gcc - ARM、VFP、浮点、惰性上下文切换
问题描述
我正在为 ARM 处理器(Cortex-A9)编写操作系统。
我正在尝试实现浮点寄存器的惰性上下文切换。这背后的想法是浮点扩展最初是为线程禁用的,因此不需要在任务切换上保存浮点上下文。
当线程尝试使用浮点指令时,它会触发异常。操作系统然后启用浮点扩展,并且知道在下一次上下文切换中必须为该线程保存浮点上下文。然后重新执行浮点指令。
我的问题是,即使在 c 代码中没有使用浮点运算,编译器也会生成浮点指令。这是在 c 中不使用浮点的函数的反汇编示例:
10002f5c <rmtcpy_from>:
10002f5c: e1a0c00d mov ip, sp
10002f60: e92ddff0 push {r4, r5, r6, r7, r8, r9, sl, fp, ip, lr, pc}
10002f64: e24cb004 sub fp, ip, #4
10002f68: ed2d8b02 vpush {d8}
...
10002f80: ee082a10 vmov s16, r2
...
10002fe0: ee180a10 vmov r0, s16
...
1000308c: ecbc8b02 vldmia ip!, {d8}
...
当我有很多这样的功能时,懒惰的上下文切换就没有意义了。
有谁知道如何告诉编译器只有在 c 代码中有浮点运算时才应该生成浮点指令?
我使用 gcc 9.2.0。浮点选项是:-mhard-float -mfloat-abi=hard -mfpu=vfp
这是一个示例 c 函数(不可用,只是一个演示):
void func(char *a1, char *a2, char *a3);
int bar_1[1], foo_1, foo_2;
void fpu_test() {
int oldest_idx = -1;
while (1) {
int *oldest = (int *)0;
int idx = oldest_idx;
for (int i = 0; i < 3; i++) {
if (++idx >= 3)
idx = 0;
int *lec = &bar_1[idx];
if (*lec) {
if (*lec - *oldest < 0) {
oldest = lec;
oldest_idx = idx;
}
}
}
if (oldest) {
foo_1++;
if (foo_2)
func("1", "2", "3");
}
}
}
gcc命令行:
$HOME/devel/opt/cross-musl/bin/arm-linux-musleabihf-gcc -O2 -march=armv7-a -mtune=cortex-a9 -mhard-float -mfloat-abi=hard -mfpu=vfp -Wa,-ahlms=fpu_test.lst -mapcs-frame -c fpu_test.c -o fpu_test.o
汇编器列表:
...
35 0000 0DC0A0E1 mov ip, sp
36 0004 003000E3 movw r3, #:lower16:foo_2
37 0008 F0DF2DE9 push {r4, r5, r6, r7, r8, r9, r10, fp, ip, lr, pc}
38 000c 006000E3 movw r6, #:lower16:foo_1
39 0010 003040E3 movt r3, #:upper16:foo_2
40 0014 04B04CE2 sub fp, ip, #4
41 0018 006040E3 movt r6, #:upper16:foo_1
42 001c 004000E3 movw r4, #:lower16:bar_1
43 0020 028B2DED vpush.64 {d8} <=== this is the problem
...
解决方案
GCC 有一个命令行开关,-mgeneral-regs-only
. . 使用命令行开关时,您可能需要将有意使用浮点寄存器或运算的代码分离到单独的源文件中,以便在没有该开关的情况下对其进行编译。
从 GCC 9.3(可能是 9?)开始,对于 ARM 目标,这可用作函数属性:
void MyFunction(char *MyParameter) __attribute__ ((general-regs-only));
将属性放在声明之后是较旧的语法,并且需要非定义声明。测试表明 GCC 现在在声明符之前接受一个属性,并且可以与定义一起使用:
void __attribute__ ((general-regs-only)) MyFunction(char *MyParameter)
{...}
您也可以使用 来否定该属性__attribute__ ((nogeneral-regs-only))
,尽管我没有看到此文档。
这也可以用pragma来控制。
和开关中也有+nofp
选项,但我认为这是您想要的。-march
-mcpu
-mgeneral-regs-only
推荐阅读
- c# - 如何将数据从 WCF 服务推送到控制台应用程序?
- pocketsphinx-android - 带有阿拉伯模型的 Pocketsphinx android 演示不能作为 pc 模型工作
- javascript - 上传文件时超出重试限制
- javascript - 看起来我的 javascript 中断了我的 css
- angular - router.navigate 中的 {skipLocationChange : true} 不起作用;改变状态
- c# - 没有 APIController 属性的版本化 API Explorer
- javascript - 如何从 ES6 JavaScript 类实例中获取源代码位置?
- java - Javafx Google 按高度和经度映射标记
- c - 我们可以减去 NULL 指针吗?
- javascript - Angular6:无法访问获取异步数据的模板中的 js 变量