此问题已在此处有答案:
Using LDRD in GNU C inline asm? What constraints to use?(1个答案)
5天前关闭。
在32位ARM汇编中,有几条指令可用于原子加载和存储一对寄存器:
- ldaexd和stlexd(用于ARMv 8 32位,具有获取-释放内存顺序)[https://developer.arm.com/documentation/dui0802/b/A32-and-T32-Instructions/LDAEX-and-STLEX]
- ldrexd和strexd(适用于不含屏障的ARMv7)[https://developer.arm.com/documentation/dui0802/b/A32-and-T32-Instructions/LDREX-and-STREX]
这些32位指令对于选择传输寄存器对(Rt和Rt 2)具有一些要求:
- Rt必须是偶数寄存器,而不是LR
- “Rt 2必须是R(t+1)”
我已经包含了一些GCC内联汇编代码的例子(对于C/C++,下面描述的问题对于所有4条指令都是一样的)。此代码不符合要求的寄存器编号。
inline static void atomic_exclusive_load_pair_aquire(uint32_t atomic[2], uint32_t target[2])
{
asm volatile("ldaexd %0, %1, [%2]" // load-acquire exclusive register pair
: "=r"(target[0]), // first transfer register
"=r"(target[1]) // second transfer register
: "r"(&atomic[0]) // atomic base register
: "memory"); // "memory" acts as compiler r/w barrier
}
我希望GCC臂内联汇编约束以某种方式能够描述用于自动寄存器Map的依赖寄存器对,如果这是单个指令所需要的话。
我的问题是,如何将两个传输寄存器的要求描述为GCC内联汇编约束,以自动选择正确的寄存器编号?这可能吗?使用“多种替代约束”是否是一种可能的解决方案([https://gcc.gnu.org/onlinedocs/gcc/Multi-Alternative.html])?
解决方案:
正如amonakov等人所写的,解决方案是使用uint64_t作为传输类型,它使用ARM 32位上的寄存器对。取决于Thumb是否禁用,寄存器对将是偶数/奇数对。也有或多或少的未记录的内联汇编约束访问对寄存器。
inline static void atomic_exclusive_load_pair_aquire(uint32_t atomic[2], uint32_t transfer[2])
{
uint64_t pair;
asm volatile("ldaexd %Q[pair], %R[pair], [%[addr]]" // load-acquire exclusive register pair
: [pair] "=r"(pair) // transfer register pair
: [addr] "r"(&atomic[0]) // atomic base register
: "memory"); // "memory" acts as compiler r/w barrier
transfer[0] = static_cast<uint32_t>(pair);
transfer[1] = static_cast<uint32_t>(pair >> 32);
}
请在这里查看完整的解决方案和汇编代码:[https://godbolt.org/z/Mb5GYMfK5]
1条答案
按热度按时间ikfrs5lh1#
对于这些文档不足甚至没有文档的东西,您可以“窥视引擎盖下”,并查看GCC内部如何在config/arm/sync.md中描述这些指令。
事实证明,绑定一个DIMode(64位)操作数就足以获得一个奇偶寄存器对。在C中,你可以绑定一个
uint64_t
变量,并使用H
修饰符来拼写第二个寄存器(Arm的修饰符在GCC端没有记录,但LLVM记录了它们):