关于 arch/arm64/include/asm/atomic.h 的功能atomic_add问题



我对基于 Linux 内核的 C 编码风格非常陌生。我试图理解"arch/arm64/include/asm/atomic.h"文件中"atomic_add"函数的以下实现(此处第 112-124 行)。

static inline void atomic_add(int i, atomic_t *v)
{ 
unsigned long tmp;
int result;
asm volatile("// atomic_addn"
"1: ldxr    %w0, %2n"
"   add %w0, %w0, %w3n"
"   stxr    %w1, %w0, %2n"
"   cbnz    %w1, 1b"
: "=&r" (result), "=&r" (tmp), "+Q" (v->counter)
: "Ir" (I));
}

请帮助我理解以下问题。

%
  1. w0 或 %w3 是什么意思?我知道 %2 指的是计数器值。

  2. %w0 是指(结果)变量还是通用寄存器?

  3. 约束字符串"Ir"是否代表"立即寄存器"?

  1. w是一个模板修饰符。 它使内联asm包含寄存器的32位名称(w0等),而不是默认的64位名称(x0)。 请参阅David Wohlferd链接的文档。 您也可以尝试一下,并注意,如果您写入%0而不是%w0,则生成的指令使用64位x寄存器。 这不是您想要的,因为这些应该是 32 位加载和存储。

  2. 双。 与GCC样式的扩展asm一样,%w0引用内联asm的操作数编号0(如前所述,使用其32位名称的w修饰符)。 这是用"=&r" (result)声明的那个. 由于约束是r的,这个操作数将被分配一个通用寄存器,并且所有在asm代码中提及%0(分别为%w0)都将替换为该寄存器的名称。 在上面的 Godbolt 示例中,编译器选择了x9(分别为w9)。

    (result)意味着在 asm 语句之后,编译器应该获取w9中剩余的任何内容并将其存储在变量result中。 它可以将存储到内存,或者mov到用于result的任何寄存器,或者它可以在该变量本身中分配result。 幸运的是,优化器应该选择后者;由于resultasm之后不用于任何东西,它不应该对该寄存器做任何进一步的事情。 因此,实际上,带有之后不使用的变量的输出操作数是一种告诉编译器"请选择一个我可以用作暂存器的寄存器"的方法。

  3. 这是两个约束,Ir。 GCC 记录了约束:简单且特定于机器,当给出多个约束时,编译器可以选择满足其中任何一个约束。

    I要求一个适合在 AArch64add指令中使用的即时值,即可选择移动 12 位的 12 位零扩展数,这是一个编译时常量。 如您所知,r要求通用寄存器。 因此,如果您编写atomic_add(1, &c)atomic_add(1+1+1, &c)atomic_add(4095, &c)atomic_add(4096, &c)中的任何一个,则asm语句的第二行将作为即时add指令发出,您的常量直接编码到指令中:add w9, w9, #1等等。 但是如果你写atomic_add(4097, &c)atomic_add(my_variable, &c),编译器会在asm之前生成额外的代码,将适当的值加载到某个寄存器(比如w13)中,并在你的asm中发出add w9, w9, w13。 这使编译器尽可能生成更高效的即时add,同时通常仍能获得正确的代码。

相关内容

  • 没有找到相关文章

最新更新