Нужно ли создавать несколько исполняемых файлов для целевых наборов команд?

Предположим, у меня есть программа для выполнения операций AES.

Некоторые продвинутые процессоры имеют набор команд AES-NI, а другие - нет.

Должен ли я скомпилировать мою программу в два исполняемых файла: A_with_aes_ni.exe и B_without_aes_ni.exe?

2 ответа

Решение

То, что вы хотите, называется диспетчером ЦП. Агнер Фог имеет 10 страниц текста по этому вопросу в третьей главе "Создание критического кода в нескольких версиях для разных наборов инструкций" своего руководства по оптимизации C++. Он обсуждает это как с GCC, так и с ICC.

Вам нужен только один исполняемый файл, но вам нужно скомпилировать два разных объектных файла с включенной AES и без нее. Затем диспетчер определяет, какой набор инструкций доступен, и выбирает путь кода на основании этого.

Я пытался сделать это с диспетчером процессора MSVC2010 для Visual Studio для AVX и SSE, но безуспешно. Я подозреваю, что мог бы заставить это работать теперь все же.

Редактировать: в векторном классе Агнера Фога у него есть файл dispatch_example.cpp а также instrset_detech.cpp который должен иметь большую часть того, что нужно сделать диспетчеру. Вам все еще нужно выяснить, как определить, есть ли у процессора AES. Вам нужно увеличить файл intrset_detect.cpp. Согласно википедии, когда вы читаете CPUID, бит 23 в регистре ECX устанавливается, если у CPU есть AES. В Википедии также есть примеры кода для чтения CPUID (помимо instrset_detech.cpp - еще один хороший пример на https://github.com/Mysticial/Flops в файле cpuid.c)

Один из способов сделать это в Solaris - это иметь библиотеки аппаратных возможностей, которые динамически загружаются компоновщиком во время выполнения.

Другой вариант - сначала загрузить обработчик прерываний для недопустимых инструкций, а затем проверить нужные инструкции на машинном языке. Если вы попали в ловушку, то вы знаете, что не можете использовать оптимизированную версию и должны загружать неоптимизированную (или менее оптимизированную).

Хотя мне нравится предложение Эндрю выше, я думаю, что безопаснее проверить конкретные инструкции, которые вам нужны. Таким образом, вам не нужно постоянно обновлять приложение для более новых выходных данных CPUID.

Отредактировано, чтобы добавить: я понимаю, что должен был привести пример. Для libc Solaris на платформе x64 мы предоставляем hw-оптимизированные версии библиотеки - три для 32-битных, одна для 64-битных. Мы можем увидеть различия, запустив elfdump -Hна интересующий файл:

s11u1:jmcp $ elfdump -H /usr/lib/libc/libc_hwcap1.so.1 

Capabilities Section:  .SUNW_cap

 Object Capabilities:
     index  tag               value
       [0]  CA_SUNW_HW_1     0x86d  [ SSE MMX CMOV SEP CX8 FPU ]

 Symbol Capabilities:
     index  tag               value
       [2]  CA_SUNW_ID       hrt
       [3]  CA_SUNW_HW_1     0x40002  [ TSCP TSC ]

  Symbols:
     index    value      size      type bind oth ver shndx          name
       [1]  0x000f306c 0x00000225  FUNC LOCL  D    0 .text          gettimeofday%hrt
       [2]  0x000f2efc 0x00000165  FUNC LOCL  D    0 .text          gethrtime%hrt

Capabilities Chain Section:  .SUNW_capchain

 Capabilities family: gettimeofday
  chainndx  symndx      name
         1  [702]       gettimeofday
         2  [1]         gettimeofday%hrt

 Capabilities family: gethrtime
  chainndx  symndx      name
         4  [1939]      gethrtime
         5  [2]         gethrtime%hrt

s11u1:jmcp $ elfdump -H /usr/lib/libc/libc_hwcap2.so.1 

Capabilities Section:  .SUNW_cap

 Object Capabilities:
     index  tag               value
       [0]  CA_SUNW_HW_1     0x1875  [ SSE2 SSE MMX CMOV AMD_SYSC CX8 FPU ]

 Symbol Capabilities:
     index  tag               value
       [2]  CA_SUNW_ID       hrt
       [3]  CA_SUNW_HW_1     0x40002  [ TSCP TSC ]

  Symbols:
     index    value      size      type bind oth ver shndx          name
       [1]  0x000f253c 0x00000225  FUNC LOCL  D    0 .text              gettimeofday%hrt
       [2]  0x000f23cc 0x00000165  FUNC LOCL  D    0 .text          gethrtime%hrt

Capabilities Chain Section:  .SUNW_capchain

 Capabilities family: gettimeofday
  chainndx  symndx      name
         1  [702]       gettimeofday
         2  [1]         gettimeofday%hrt

 Capabilities family: gethrtime
  chainndx  symndx      name
         4  [1939]      gethrtime
         5  [2]         gethrtime%hrt

Угадайте, что из перечисленного выше для систем AMD, а что для Intel?

У компоновщика Solaris есть умения загружать правильную библиотеку hwcap во время выполнения перед вызовом _init() вашего процесса.

Другие вопросы по тегам