如何让编译器选择标志更新 ARM 指令?

How can I make a compiler choose flag-updating ARM instructions?

我正在尝试在我的代码执行算术运算时使用 CPSR 标志,而不是使用一系列 if 语句来检查溢出、进位等,以便拥有更小、更快的代码。一个简单的例子就是这个加法运算:

int16_t a = 0x5000;
int16_t b = 0x4000;
int16_t result = a+b;
uint32_t flags = getFlags();

代码需要在各种平台上 运行,因此 getFlags() 是代码中唯一允许包含特定于体系结构的程序集的部分。

inline uint32_t getFlags() {
    uint32_t flags = 0;
    asm (“mrs %0, cpsr”
        : “=r” (flags)
        :
        : );
    return flags;
}

问题是编译器无法知道本例中的加法运算应该设置标志,因此它生成的指令类似于:

ldrsh r3, [r0]
ldrsh r4, [r1]
add r3, r3, r4
strh r3, [r2]
mrs r3, cpsr

为了让 CPSR 包含任何有用的东西,我需要编译器使用添加而不是添加(s 后缀 = 更新 CPSR)。有什么我可以更改我的 C 代码或可能导致它选择标志更新指令的编译器选项吗?我可以使用 GCC 或 Clang。

这种代码无法以有用的方式工作,因为编译器可以随意重新排列代码。甚至不能保证添加是 mrs 指令运行之前的最后一个标志更新指令。如果你想做对,把标志设置加法和 mrs 指令放在一个 asm 语句中。

您无法指定编译器将使用哪些指令。这种方法是徒劳的,并且与编译器执行的关键优化功能不兼容。

您可以通过使用GCC and Clang 都支持的编译器内置函数来获得可移植的溢出检查。例如,__builtin_add_overflow(a, b, &c)a+b 存储在 c 中,如果发生溢出,则 returns 为真。 (而且是泛型的,abc可以是任意整数类型,是否溢出只取决于a和[=14的取值=] 和 c 的类型。)

您可以预期此类内置函数将参与优化,包括在合适的情况下使用标志更新指令。 (GCC 文档明确说明了这一点。)