GCC 32 位 arm 内联汇编约束,用于原子加载/存储寄存器对 [重复]

问题描述 投票:0回答:1

在 32 位 ARM 汇编中有几个指令可用于原子加载和存储一对寄存器:

  • ldaexd 和 stlexd(对于具有获取-释放内存顺序的 ARMv8 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和Rt2)有一些要求:

  • “Rt 必须是偶数寄存器,而不是 LR”
  • “Rt2 必须是 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 arm 内联汇编约束能够以某种方式描述自动寄存器映射的依赖寄存器对,如果这是单个指令所需要的。

我的问题是,对两个传输寄存器的要求怎么描述为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]

gcc arm atomic inline-assembly
1个回答
3
投票

对于此类未记录甚至未记录的内容,您可以“窥视引擎盖下”并查看 GCC 内部如何在 config/arm/sync.md 中描述这些指令.

事实证明,绑定一个 DImode(64 位)操作数足以得到奇偶寄存器对。在 C 中,您可以绑定一个

uint64_t
变量并使用
H
修饰符拼出第二个寄存器(GCC 端没有记录 Arm 的修饰符,但是 LLVM 记录了它们):

uint64_t f(uint64_t *p)
{
    uint64_t r;
    asm volatile("ldaexd %0, %H0, [%1]"
                 : "=r"(r)
                 : "r"(p)
                 : "memory");
    return r;
}
© www.soinside.com 2019 - 2024. All rights reserved.