gcc -O3 optimize:: xmm0 зарегистрироваться?
(Я плохо говорю по-английски.. пожалуйста, поймите ТТ)
Я писал функцию vsprintf для использования моего ядра 64-битной ОС (написано на C) и проверял, хорошо ли она работает в Visual Studio и Cygwin gcc. Затем я установил ядро и запустил... но ядро не работает
Я отладил и выяснил проблему: vsprintf содержит следующий код сборки
movdqa xmm0,XMMWORD PTR [rip+0x0]
Настоящая проблема в том, что я НИКОГДА не использую плавающую точку!
Я думаю, что это была оптимизация GCC, и это кажется правильным, потому что он работает хорошо без оптимизации
Есть ли, так сказать, вариант gcc, который отключает оптимизацию с помощью регистров xmm?
2 ответа
Команды перемещения регистра XMM генерируются, потому что в System V AMD64 ABI аргументы с плавающей запятой хранятся в XMM0–XMM7.
Поскольку мы не знаем, используются ли числа с плавающей запятой, просто взглянув на функцию с переменным числом, компилятору необходимо сгенерировать инструкции для передачи значений с плавающей запятой va_list
также.
Вы могли бы использовать -mno-sse
флаг для отключения SSE. Например,
__attribute__((noinline))
void f(const char* x, ...) {
va_list va;
va_start(va, x);
vprintf(x, va);
va_end(va);
}
Без -mno-sse
флаг:
subq $0x000000d8,%rsp
testb %al,%al
movq %rsi,0x28(%rsp)
movq %rdx,0x30(%rsp)
movq %rcx,0x38(%rsp)
movq %r8,0x40(%rsp)
movq %r9,0x48(%rsp)
je 0x100000f1b
movaps %xmm0,0x50(%rsp)
movaps %xmm1,0x60(%rsp)
movaps %xmm2,0x70(%rsp)
movaps %xmm3,0x00000080(%rsp)
movaps %xmm4,0x00000090(%rsp)
movaps %xmm5,0x000000a0(%rsp)
movaps %xmm6,0x000000b0(%rsp)
movaps %xmm7,0x000000c0(%rsp)
0x100000f1b:
leaq 0x000000e0(%rsp),%rax
movl $0x00000008,0x08(%rsp)
movq %rax,0x10(%rsp)
leaq 0x08(%rsp),%rsi
leaq 0x20(%rsp),%rax
movl $0x00000030,0x0c(%rsp)
movq %rax,0x18(%rsp)
callq 0x100000f6a ; symbol stub for: _vprintf
addq $0x000000d8,%rsp
ret
С -mno-sse
флаг:
subq $0x58,%rsp
leaq 0x60(%rsp),%rax
movq %rsi,0x28(%rsp)
movq %rax,0x10(%rsp)
leaq 0x08(%rsp),%rsi
leaq 0x20(%rsp),%rax
movq %rdx,0x30(%rsp)
movq %rcx,0x38(%rsp)
movq %r8,0x40(%rsp)
movq %r9,0x48(%rsp)
movl $0x00000008,0x08(%rsp)
movq %rax,0x18(%rsp)
callq 0x100000f6a ; symbol stub for: _vprintf
addq $0x58,%rsp
ret
Вы также можете использовать target
атрибут для отключения SSE только для этой функции, например
__attribute__((noinline, target("no-sse")))
// ^^^^^^^^^^^^^^^^
void f(const char* x, ...) {
va_list va;
va_start(va, x);
vprintf(x, va);
va_end(va);
}
Но имейте в виду, что другие функции с поддержкой SSE не будут знать f
не использует SSE, и, следовательно, вызов их с числами с плавающей точкой вызовет неопределенное поведение:
int main() {
f("%g %g", 1.0, 2.0); // 1.0 and 2.0 are stored in XMM0–1
// So this will print garbage e.g. `0 6.95326e-310`
}