Генерировать и оптимизировать код FP / SIMD в ядре Linux для файлов, содержащих kernel_fpu_begin ()? - PullRequest
0 голосов
/ 30 апреля 2020

Я знаю, что запрещено использовать любой тип кода с плавающей точкой в ​​ядре, и мы никогда не должны использовать какой-либо флаг G CC, который мог бы генерировать инструкции FP / SIMD, но как насчет некоторого исходного кода (особенно arch/x86/crypto/*) который использует kernel_fpu_begin() и kernel_fpu_end()?

Пример 1 , пример 2 .

У меня есть древний Intel Core 2 Duo Процессор, который я использую для своего 64-битного Linux ядра и в основном Makefile Я использую следующие C флаги:

# Target specific Flags
KBUILD_CFLAGS   += \
           -m64 \
           -march=core2 \
           -mtune=core2 \
           -mfpmath=sse \
           -msoft-float \
           -mno-fp-ret-in-387 \
           -mno-mmx \
           -mno-sse \
           -mno-sse2 \
           -mno-sse3 \
           -mno-ssse3

# FPU Flags
FPU_CFLAGS := $(KBUILD_CFLAGS) \
           -mhard-float \
           -mfp-ret-in-387 \
           -mmmx \
           -msse \
           -msse2 \
           -msse3 \
           -mssse3 \
           -ftree-vectorize

и в файлах, где присутствует kernel_fpu_begin(), я передаю FPU_CFLAGS в их Makefiles примерно так:

CFLAGS_sha512_ssse3_glue.o := $(FPU_CFLAGS)

Это правильно и будет ли оптимизировать код FP / SIMD? Или это не нужно, и эта реализация может даже нарушить состояние FPU / SIMD?

1 Ответ

2 голосов
/ 30 апреля 2020

Это правильно

Нет, абсолютно не делайте этого. Эти опции сообщают G CC, что он может использовать инструкции SIMD / FP где угодно в этом модуле компиляции, включая до kernel_fpu_begin() или после kernel_fpu_end(), или в функциях, которые никогда не вызывают kernel_fpu_begin().

, например, он может генерировать нагрузку movdqu или сохранить для копирования 16 байтов структуры и поврежденное состояние регистра XMM в пространстве пользователя до того, как kernel_fpu_begin сохранит его.

и оптимизирует FP / SIMD-код?

Нет, код ядра, использующий kernel_fpu_begin(), также использует встроенный asm для запуска инструкций SIMD. Это будет выдавать инструкции SIMD без никакой помощи от компилятора.

Или теоретически некоторый код ядра может использовать атрибут функции, такой как __attribute__((target("sse2"))), или что-то подобное для вспомогательной функции, вызываемой изнутри. kernel_fpu_begin() / end блок. Но я думаю, что Linux предпочитает встроенный asm вместо этого плюс встроенную или автоматическую векторизацию.

Ядро не потрудится включить вызовы kernel_fpu_begin() / end, если оно получит нулевую выгоду из него . Кстати, вы можете разобрать соответствующие модули ядра .ko и увидеть, что они на самом деле содержат SIMD-инструкции, которые используют регистры XMM. Используйте objdump -drwC -Mintel foo.ko

...