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

时间:2018-11-08 14:58:56

标签: c assembly arm flags

当我的代码执行算术运算时,我尝试使用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包含有用的内容,我需要编译器使用添加而不是添加(后缀=更新CPSR)。我可以在C代码或编译器选项中进行某些更改,以使其选择标志更新指令吗?我可以使用GCC或Clang。

2 个答案:

答案 0 :(得分:5)

这种代码无法以有用的方式工作,因为编译器可以随意重新排列代码。甚至不能保证加法是mrs指令运行前的最后一个标志更新指令。如果您想解决这个问题,请将标记设置附加项和mrs指令放在一个asm语句中。

答案 1 :(得分:4)

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

您可以使用GCCClang都支持的编译器内置函数来获得可移植溢出检查。例如,__builtin_add_overflow(a, b, &c)a+b存储在c中,如果发生溢出,则返回true。 (并且它是类型通用的; abc可以是任何整数类型。是否发生溢出仅取决于a和{{1 }}和b的类型。)

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