我正在为ARM处理器(Cortex-A9)编写操作系统。
我试图实现浮点寄存器的惰性上下文切换。这背后的思路是,对于一个线程,浮点扩展最初是禁用的,因此在任务切换时无需保存浮点上下文。
当一个线程尝试使用浮点指令时,它会触发异常。然后操作系统启用浮点扩展,并知道必须在下一次上下文切换中保存该线程的浮点上下文。然后重新执行浮点指令。
我的问题是,即使在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
...