在 ARM64 架构(也称为 AArch64)中,函数调用约定定义了寄存器如何用于传递参数和返回值。这些约定有助于实现高效的函数调用和返回。在 ARM64 的汇编中,寄存器传参遵循以下约定:
参数传递寄存器
x0 - x7: 这 8 个寄存器用于传递函数的前 8 个参数(对于整数类型的参数)。如果函数有更多的参数,这些额外的参数会通过栈传递。
- x0 用于第一个参数
- x1 用于第二个参数
- x2 用于第三个参数
- x3 用于第四个参数
- x4 用于第五个参数
- x5 用于第六个参数
- x6 用于第七个参数
- x7 用于第八个参数
v0 - v7: 对于浮点数和 SIMD(单指令多数据)参数,这 8 个寄存器用于传递前 8 个浮点数参数(每个寄存器可以存储一个 64 位的浮点数,或者一组 128 位的 SIMD 数据)。
返回值
x0: 用于返回整数类型的结果(例如,int、long、pointer 等)。
v0: 用于返回浮点数或 SIMD 类型的结果(例如,float、double、__m128 等)。
阅读汇编代码时需要注意上述约定。
学完后实习一下:https://godbolt.org/z/zWjbo9183
仅仅是用了 restrict,性能可以提升非常大:
source:here
C++代码:
struct AvgState {
uint64_t numerator{0};
uint64_t denominator{0};
double divide() { return numerator / denominator; }
};
void addBatch(size_t batch_size, AggregateDataPtr __restrict state, Column *args) __attribute__((noinline)) {
for (size_t i = 0; i < batch_size; ++i) {
data(state).numerator += args[0].data()[i];
++(data(state).denominator);
}
}
对应汇编代码:
IAggregate<AvgAggregator>::addBatch(unsigned long, char*, Column*) [clone .isra.0]:
cbz x0, .L7 <= x0 是第一个参数,batch_size,cbz(compare and branch on zero),batch_size 是 0 的话直接返回
ldr x2, [x2] <= x2 是第三个参数 args,args[0] 地址等于 x2, args[0].data() 地址也等于 x2, args, args[0].data()[0]地址也等于