c - 如何在 GCC 的内联汇编中指定一个特定的寄存器来分配 C 表达式的结果?
问题描述
我想a0
使用 GCC 将 C 表达式的结果存储到 RISC-V 程序中的寄存器中(为了下面的示例,假设有一个volatile int val = 42
或类似的)。mv
在显式调用指令时,我可以使用内联汇编来完成此操作:
asm ("mv a0, %0\n\t" :: "r" ((val == 0) ? 1 : val) : "a0");
但是,如果结果已经在正确的寄存器“中”计算出来,则移动将是不必要的。我已经尝试过使用文档register
中描述的变量的各种事情,但失败了。例如,以下内容被完全优化掉:
register volatile int res asm("a0") = (val == 0) ? 1 : val;
与“空” asm 语句相同:
register int res asm("a0") = (val == 0) ? 1 : val;
asm volatile ( "" /* just store */ : "=r" (res) );
有一个更好的方法吗?我忽略了什么吗?
解决方案
你很接近,但"=r"(res)
告诉编译器旧值res
已经死了,所以它没有在任何地方实现它。
register ... asm("regname")
本地变量仅在用作扩展语句的操作数时才能保证做任何事情。asm
如果asm
语句本身是asm volatile
,则即使其输入未使用,也无法对其进行优化。(不要做register ... asm
变量volatile
;那没用。)
因此,要强制编译器在其中实现表达式的结果a0
(例如,对于由于某种原因您想要部分破坏优化的微基准,否则https://gcc.gnu.org/wiki/DontUseInlineAsm):
register int res asm("a0") = (val == 0) ? 1 : val;
// then read that reg var, forcing the compiler to actually materialize it
asm volatile("# just a comment, input picked %0" : : "r"(res));
这可以移植到支持 GNU C 内联汇编的其他编译器,包括 clang。
Godbolt 上的演示(我调整了 asm 模板以在注释前使用 nop,因此编译器 - 资源管理器注释过滤器不会删除它。空的模板字符串不会改变任何东西;那只是为了确认编译器“知道“它放在什么寄存器res
中。)
void foo(int dummy, int val) {
register int res asm("a3") = (val == 0) ? 1 : val;
asm volatile("nop # just a comment, input picked %0" : : "r"(res));
}
我选择a3
了一个void
函数来确保 GCC 没有理由碰巧选择那个寄存器,甚至根本没有实现res
;我不退货。
# RISC-V gcc 10.2 -O3
foo:
mv a3,a1
bne a1,zero,.L2
li a3,1
.L2:
nop # just a comment, input picked a3
# if we had returned res, we'd have mv a0,a3 here
ret
请注意,此asm
语句没有输出操作数,也没有破坏器,因此编译器知道它对任何寄存器或内存都没有影响。
如果我使用"=r"(res)
了 ,那将告诉编译器 的原始值res
已死,因此在 asm 语句执行并生成任何新值之前,无需在该寄存器中实现它。就像你写过res = rand();
什么一样,res
如果没有人读过它,甚至不需要计算以前的值。
"+r"(res)
会告诉编译器 asm 指令读取该寄存器,然后在那里写入一个新值。例如,您可以使用它来隐藏优化器中的常量,因此编译器必须假设res
在 this 之后的使用是一个完全未知的运行时变量,即使您使用过register int res asm("a0") = 1;
弄错了,没有asm()
int bar(int dummy, int val) {
register int res asm("a3") = (val == 0) ? 1 : val;
return res;
}
,a0
恰好“工作”只是因为 a0 是返回值寄存器,我们正在返回res
(以阻止它优化)。
bar: # same computation, but without using a3
mv a0,a1
bne a1,zero,.L5
li a0,1
.L5:
ret
如果我不这样做return res
,它将完全优化未使用变量的计算。 volatile register int res asm("a3")
不能改变这一点。
推荐阅读
- excel - VBA使用密码提示取消保护所有工作表,但只有一次
- android - Facebook登录不起作用:错误:Android
- django - 如何在 django html 表中显示数据库中的所有数据
- php - 当您可以在邮件中发送令牌时,为什么要在标题中发送令牌?
- reactjs - 以反应钩子形式验证?
- python - 我需要有关将路径输入到 mySQL 表中的帮助(来自 python 代码)
- awk - Bash Extract first number of a three digit version
- output - 这个流程图的输出是什么?
- javascript - 如何将深层嵌套对象的属性之和移动或计算到对象数组的顶层
- azure - 自托管 Azure DevOps 代理卷映射