Запись функций x86 asm переносимо (win/linux/osx), без зависимости от зависимости от yasm/nasm?
par2 имеет небольшую и довольно чистую С++-кодовую базу, которая, как я думаю, прекрасно подходит для GNU/Linux, OS X и Windows ( с MSVС++).
Я хотел бы включить версию x86-64 asm одной функции, которая занимает почти все время процессора. (рассылки с более подробными сообщениями. реализация /benchmark здесь.)
Intrinsics будет очевидным решением, но gcc не создает достаточно хороший код для получения одного байта за раз из 64-битного регистра для использования в качестве индекса в LUT. Я также мог бы потратить время, чтобы запланировать инструкции, поэтому каждая строка кэша uop содержит несколько 4-х тонов, поскольку пропускная способность uop является узким местом, даже если буфер ввода/вывода является приличным размером.
Я бы предпочел не вводить зависимость от ясности, поскольку многие люди установили gcc, но не yasm.
Есть ли способ написать функцию в asm в отдельном файле, который может собирать gcc/clang и MSVC? Цели:
- нет дополнительного программного обеспечения в качестве сборки. (без YASM).
- только одна версия каждой функции asm. (без поддержки версий MASM и AT & T того же кода.)
Системы сборки Par2cmdline - это autoconf/automake для Unix, MSVC .sln
для Windows.
Я знаю, что сборник GNU имеет директиву .intel_syntax noprefix
, но это только изменяет форматы команд, а не другие директивы ассемблера. например .align 16
против align 16
. Мой код довольно прост и мал, поэтому было бы нормально работать с различными директивами с C-препроцессором #define
s, если это может работать.
Я предполагаю, что выполнение обнаружения ЦП и установка указателя функции на основе результата не должны быть проблемой на С++, даже если я должен использовать для этого условную компиляцию #ifdef
.
Если нет решения для того, на что я надеюсь, я, вероятно, добавлю зависящую от построения зависимость от yasm и имею параметр ./configure --no-asm
, чтобы отключить ускорение asm для людей, строящих на x86 без присутствия язвы.
Мой предпочтительный план обработки различных соглашений о вызовах в Windows и Linux ABI состоял в использовании __attribute__((sysv_abi))
для моих прототипов C для моих функций asm. Тогда мне нужно написать пролог функции для SysV ABI. Есть ли у MSVC что-то вроде этого, что поставит args в regs в соответствии с SysV ABI для определенных функций? (BTW, это щекотало ошибка компилятора, поэтому будьте осторожны с этой идеей, если вы хотите, чтобы ваш код работал с текущим gcc.)
Ответы
Ответ 1
В то время как у меня нет хорошего решения по удалению зависимости от конкретного ассемблера, у меня есть предложение о том, как разрешить две разностные соглашения с 64-битными вызовами: Microsoft x64 и SysV ABI.
Самый младший значащий знаменатель - это соглашения о вызовах Microsoft x64, поскольку он может передавать только первые четыре значения по регистру. Поэтому, если вы ограничиваете себя этим и используете макросы для определения регистров, вы можете легко сделать свой код для Unix (Linux/BSD/OSX) и Windows.
Например, посмотрите в файле strcat64.asm
в Agner Fog asmlib
%IFDEF WINDOWS
%define Rpar1 rcx ; function parameter 1
%define Rpar2 rdx ; function parameter 2
%define Rpar3 r8 ; function parameter 3
%ENDIF
%IFDEF UNIX
%define Rpar1 rdi ; function parameter 1
%define Rpar2 rsi ; function parameter 2
%define Rpar3 rdx ; function parameter 3
%ENDIF
push Rpar1 ; dest
push Rpar2 ; src
call A_strlen ; length of dest
push rax ; strlen(dest)
mov Rpar1, [rsp+8] ; src
call A_strlen ; length of src
pop Rpar1 ; strlen(dest)
pop Rpar2 ; src
add Rpar1, [rsp] ; dest + strlen(dest)
lea Rpar3, [rax+1] ; strlen(src)+1
call A_memcpy ; copy
pop rax ; return dest
ret
;A_strcat ENDP
Я не думаю, что четыре регистра - это действительно ограничение, потому что, если вы пишете что-то в сборке, потому что вам нужна максимальная эффективность, в этом случае служебная нагрузка функции должна быть незначительной по сравнению с самой функцией, поэтому нажатие/значения в/из стека, если вам нужно при вызове функции, не должны влиять на производительность.