【问题标题】:How can I make a compiler choose flag-updating ARM instructions?如何让编译器选择标志更新 ARM 指令?
【发布时间】:2018-11-08 14:58:56
【问题描述】:

我试图在我的代码进行算术运算时使用 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。

【问题讨论】:

  • 这种做法是非常错误的。现代编译器不是机械的汇编生成机器。你不能指望他们会根据源代码编写汇编指令,然后你可以进去插入额外的指令。
  • “代码需要在各种平台上运行” ...好吧,有些CPU根本没有标志...只是说...

标签: c assembly arm flags


【解决方案1】:

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

【讨论】:

  • 不幸的是,我不能将加法指令放入 asm 语句中,因为 getFlags() 函数旨在用于几种不同的算术运算。我想我可以为每种类型的操作创建一个单独的函数,尽管我希望不必这样;我想让平台特定的代码尽可能小。
  • 想要写你必须在(真正的)汇编中完成。
  • @superbowl 恐怕这是你必须做的;每个算术运算一个函数。您也许可以使用预处理器来减少为此必须做的工作量。如果你愿意,我可以为你写一个例子。
【解决方案2】:

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

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

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

【讨论】:

  • 这看起来很有希望。我试试看。
猜你喜欢
  • 2012-07-05
  • 2015-04-04
  • 1970-01-01
  • 2015-08-22
  • 1970-01-01
  • 1970-01-01
  • 2020-12-14
  • 1970-01-01
  • 2020-03-15
相关资源
最近更新 更多