Определить опцию -xarch в препроцессоре?
Я использую Sun Studio 12.4 и 12.5 на Solaris 11. У нас есть исходный файл, который обеспечивает прямую реализацию CRC32 на C / C++ или оптимизированную версию CRC32 с использованием встроенных функций Intel. Во время выполнения указатель функции заполняется правильной реализацией.
Тестирование на сервере x86 с двумя Xeon производит следующее, потому что мы делаем пути к коду доступными на основе версий компилятора. В SunCC 12.1 добавлена поддержка SSE4 (если я правильно проанализировал матрицу), поэтому мы пытаемся включить его, когда __SUNPRO_CC >= 0x5100
,
"crc.cpp", line 311: ube: error: _mm_crc32_u8 intrinsic requires at least -xarch=sse4_2.
SunCC не определяет обычные GCC определяет, как __SSE4_1__
а также __SSE4_2__
, Кроме того, SunCC, по-видимому, не предоставляет встроенные функции, такие как MS VC++, где версия компилятора указывает на поддержку.
Похоже, что SunCC включает функции, основанные на -xarch
варианты, но мне не ясно, как обнаружить его в препроцессоре. Кроме того, используя -xarch
устанавливает некоторые биты, которые вызывают сбой программы на процессорах нижнего уровня (что-то вроде "минимальной" платформы).
У меня два вопроса.
- как я могу обнаружить
-xarch
вариант в препроцессоре? - как отключить
-xarch
биты, чтобы программа могла работать на процессорах нижнего уровня?
Ниже приведен фрагмент дампа макроса с -xarch=aes
, Обратите внимание, что ничего не указывает на доступные функции.
$ /opt/solarisstudio12.4/bin/CC -native -m64 -xarch=aes -xdumpmacros -E /dev/null 2>&1 | /usr/gnu/bin/sort --ignore-case
#1 "/dev/null"
#define __alignof__ __alignof
#define __amd64 1
#define __amd64__ 1
#define __ARRAYNEW 1
#define __asm asm
#define __asm__ asm
#define __attribute __attribute__
#define __builtin_constant_p __oracle_builtin_constant_p
#define __builtin_fpclassify __oracle_builtin_fpclassify
#define __builtin_huge_val __oracle_builtin_huge_val
#define __builtin_huge_valf __oracle_builtin_huge_valf
#define __builtin_huge_vall __oracle_builtin_huge_vall
#define __builtin_infinity __oracle_builtin_infinity
#define __builtin_isfinite __oracle_builtin_isfinite
#define __builtin_isgreater __oracle_builtin_isgreater
#define __builtin_isgreaterequal __oracle_builtin_isgreaterequal
#define __builtin_isinf __oracle_builtin_isinf
#define __builtin_isless __oracle_builtin_isless
#define __builtin_islessequal __oracle_builtin_islessequal
#define __builtin_islessgreater __oracle_builtin_islessgreater
#define __builtin_isnan __oracle_builtin_isnan
#define __builtin_isnormal __oracle_builtin_isnormal
#define __builtin_isunordered __oracle_builtin_isunordered
#define __builtin_nan __oracle_builtin_nan
#define __builtin_signbit __oracle_builtin_signbit
#define __BUILTIN_VA_STRUCT 1
#define __cplusplus 199711L
#define __DATE__ "Jul 11 2016"
#define __FILE__
#define __has_attribute(x) __oracle_has_attribute(x)
#define __has_nothrow_assign(x) __oracle_has_nothrow_assign(x)
#define __has_nothrow_constructor(x) __oracle_has_nothrow_constructor(x)
#define __has_nothrow_copy(x) __oracle_has_nothrow_copy(x)
#define __has_trivial_assign(x) __oracle_has_trivial_assign(x)
#define __has_trivial_constructor(x) __oracle_has_trivial_constructor(x)
#define __has_trivial_copy(x) __oracle_has_trivial_copy(x)
#define __has_trivial_destructor(x) __oracle_has_trivial_destructor(x)
#define __has_virtual_destructor(x) __oracle_has_virtual_destructor(x)
#define __is_abstract(x) __oracle_is_abstract(x)
#define __is_base_of(x,y) __oracle_is_base_of(x,y)
#define __is_class(x) __oracle_is_class(x)
#define __is_empty(x) __oracle_is_empty(x)
#define __is_enum(x) __oracle_is_enum(x)
#define __is_final(x) __oracle_is_final(x)
#define __is_literal_type(x) __oracle_is_literal_type(x)
#define __is_pod(x) __oracle_is_pod(x)
#define __is_polymorphic(x) __oracle_is_polymorphic(x)
#define __is_standard_layout(x) __oracle_is_standard_layout(x)
#define __is_trivial(x) __oracle_is_trivial(x)
#define __is_union(x) __oracle_is_union(x)
#define __LINE__
#define __LP64__ 1
#define __PRAGMA_REDEFINE_EXTNAME 1
#define __STDC__ 0
#define __sun 1
#define __SUN_PREFETCH 1
#define __SunOS 1
#define __SunOS_5_11 1
#define __SUNPRO_CC 0x5130
#define __SUNPRO_CC_COMPAT 5
#define __SVR4 1
#define __TIME__ "20:58:00"
#define __underlying_type(x) __oracle_underlying_type(x)
#define __unix 1
#define __volatile volatile
#define __volatile__ volatile
#define __x86_64 1
#define __x86_64__ 1
#define _BOOL 1
#define _LARGEFILE64_SOURCE 1
#define _LP64 1
#define _SIGNEDCHAR_ 1
#define _TEMPLATE_NO_EXTDEF 1
#define _WCHAR_T
#define sun 1
#define unix 1
3 ответа
На ваш второй вопрос:
как отключить биты -xarch, чтобы программа могла работать на процессорах нижнего уровня?
См. Главу 7 Обработка возможностей Руководства по компоновщикам и библиотекам:
https://docs.oracle.com/cd/E53394_01/html/E54813/index.html
Здесь показано, как доставить несколько экземпляров одной и той же функции, помеченных битами возможностей. Компоновщик времени выполнения определит, какая функция используется, основываясь на сообщенных возможностях.
Если вы действительно хотите управлять битами возможностей самостоятельно, см. Главу 9 Mapfiles в отдельном разделе Директива CAPABILITY. Это показывает, как удалить возможности из сгенерированного объекта.
Я считаю, что для вас в конкретной ситуации (вторая часть) единственный простой способ сделать то, что вы хотите, это: скомпилировать с явно установленным "-xarch=sse4.2" (это позволяет компилятору расширять встроенные функции SSE4.2) и затем удалите биты HWCAP до вашей минимальной архитектуры (это делает вашу программу работоспособной на оборудовании до SSE4.2).
Для извлечения HWCAP см.: https://docs.oracle.com/cd/E23823_01/html/816-5165/elfedit-1.html
(Пример 2 Удаление бита аппаратных возможностей)
Во-первых, вы не хотите удалять флаги набора команд из ваших скомпилированных двоичных файлов. Когда вы компилируете с -xarch=NNNN
вариант, компиляция будет использовать эти инструкции. Если вы попытаетесь запустить на "более низком" процессоре, который не реализует инструкции из архитектуры, которую вы предоставили в -xarch
аргумент, ваш двоичный код имеет хорошие шансы не работать.
Из Руководства пользователя Solaris Studio 12.4: C:
1.3 Проверка двоичной совместимости
В системах Solaris, начиная с Solaris Studio 11, двоичные файлы программ, скомпилированные с помощью компиляторов Oracle Solaris Studio, отмечены аппаратными флагами архитектуры, указывающими наборы команд, принятые скомпилированным двоичным файлом. Во время выполнения эти флажки маркеров проверяются, чтобы убедиться, что двоичный файл может работать на оборудовании, на котором он пытается выполнить.
Запуск программ, которые не содержат этих аппаратных флагов архитектуры на платформах, на которых не включены соответствующие функции или расширения набора команд, может привести к ошибкам сегментации или неправильным результатам без каких-либо явных предупреждений.
Также обратите внимание на упоминание функций, а также наборов инструкций. По моему опыту работы с документацией по Solaris, этого небольшого отступления достаточно для предупреждения о том, что
Я не знаю какого-либо способа обнаружить доступный набор команд через препроцессор. Вы можете получить помощь на форуме Oracle для Solaris Studio по адресу https://community.oracle.com/community/server_%26_storage_systems/application_development_in_c__c%2B%2B__and_fortran/developer_studio_c_c%2B%2B_fortran_compilers
Я подозреваю, что даже там вы не найдете способ использовать препроцессор. Обычный способ предоставления конкретных реализаций для платформы и набора команд в Solaris - через определенные общие объекты. Из руководства Solaris Linker и библиотек:
Набор инструкций для определенных общих объектов
Динамический токен
$ISALIST
расширяется во время выполнения для отражения собственных наборов команд, выполняемых на этой платформе, как показано утилитойisalist(1)
,Любое имя строки, включающее
$ISALIST
токен эффективно дублируется в несколько строк. Каждой строке назначается один из доступных наборов команд. Этот токен доступен только для спецификаций фильтра или пути выполнения....
Или приложение с аналогичными зависимостями выполняется на
MMX
сконфигурированоPentium Pro
:$ ldd -ls prog ..... find object=libbar.so.1; required by ./libfoo.so.1 search path=/opt/ISV/lib/$ISALIST (RPATH from file ./libfoo.so.1) trying path=/opt/ISV/lib/pentium_pro+mmx/libbar.so.1 trying path=/opt/ISV/lib/pentium_pro/libbar.so.1 trying path=/opt/ISV/lib/pentium+mmx/libbar.so.1 trying path=/opt/ISV/lib/pentium/libbar.so.1 trying path=/opt/ISV/lib/i486/libbar.so.1 trying path=/opt/ISV/lib/i386/libbar.so.1 trying path=/opt/ISV/lib/i86/libbar.so.1
Обратите внимание, как поиск в библиотеке начинается с "самой высокой" библиотеки, определенной для набора команд, и переходит в "более низкие" библиотеки. Это позволяет размещать несколько общих объектов, определенных для набора команд, от "самого быстрого" до "самого медленного". libc.so
в Solaris это обеспечивает платформо-зависимые версии библиотечных функций, таких как memcpy()
,