2016-07-12 30 views
2

我在Solaris 11上使用Sun Studio 12.4和12.5。我們有一個源文件,它提供了CRC32的直接C/C++實現或使用Intel內核的CRC32的優化版本。在運行時,函數指針被填充正確的實現。在預處理器中檢測-xarch選項?

使用雙至強處理器的x86服務器上的測試正在生成以下內容,因爲我們正在根據編譯器版本提供可用的代碼路徑。 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章映射文件,特別是CAPABILITY指令。 這顯示瞭如何從生成的對象中移除功能。

+0

由於約翰。我們在運行時保護我們的代碼路徑,所以我們通常只需要編譯器就可以使ASM或內部可用。也就是說,爲SSE2構建,我們可以處理其餘部分,如優化的SSE3和SSE4實現。例如,參見[crc.cpp](http://github.com/weidai11/cryptopp/blob/master/crc.cpp)和[blake2.cpp](http://github.com/weidai11/cryptopp/)斑點/主/ blake2.cpp)。 – jww

+0

我假定你引用的守衛是像HasSSE2()和HasSSE4()這樣的函數。如果這些運行時檢查硬件功能,那麼您只需在Studio中編譯選項-Mmapfile即可。 mapfile將包含CAPABILITY條目,如「HW - = SSE2」。屏蔽在提供故障預置功能的功能最低的系統上運行所需的每個功能。 –

+0

謝謝約翰。有太多我必須瞭解Solaris。多年來,這是一個紅頭髮的小孩,只有C/C++實現。作爲一種學習練習,我想讓它成爲一流的公民,因此它具有所有的速度優勢。 (Sun Studio 12.1及更高版本,這是第一個使用GCC內聯彙編的程序)。 – jww

1

首先,您不想從編譯的二進制文件中刪除指令集標誌。當您使用-xarch=NNNN選項進行編譯時,編譯將使用這些指令。如果您嘗試在「較低」的處理器上運行,而該處理器沒有實現您在-xarch參數中提供的體系結構中的指令,則您的二進制文件很有可能無法正常工作。

Solaris Studio 12.4: C User's Guide

1.3二進制兼容性驗證

在Solaris系統上,從Solaris Studio的11開始,從Oracle Solaris Studio編譯器編譯的程序二進制 標有 架構的硬件指示由編譯的二進制文件所假設的指令集的標誌 。在運行時,檢查這些標記標記爲 ,驗證二進制文件是否可以在其試圖執行的硬件上運行。

運行不包含在未與相應功能或 指令集擴展啓用可能會導致段故障或 沒有任何明確的警告消息出現的不正確的結果,這些平臺架構的硬件標誌 程序。

另請注意提及的功能以及指令集。根據我對Solaris文檔的經驗,這一點不足以足以警告,可能有更多的警告,我可能不知道通過預處理器檢測可用指令集的任何方法。您可能能夠在Oracle Studio for 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 and Libraries Guide

指令集特定的共享庫

動態令牌$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 

注庫搜索如何與「最高」指令集專用庫開始,並轉移到「較低」的圖書館。這允許定位多個指令集特定的共享對象,從「最快特定」到「最慢通用」。 Solaris上的libc.so是否可以提供庫函數的平臺特定版本,如memcpy()

2

我相信對於你特定的情況(它的第二部分),你想做的唯一簡單的方法是:編譯時明確設置「-xarch = sse4.2」(這允許編譯器擴展SSE4 .2內部函數),然後將HWCAP位剝離到最小的體系結構(這使您的程序可以在SSE4.2之前的硬件上運行)。

對於汽提HWCAP看到: https://docs.oracle.com/cd/E23823_01/html/816-5165/elfedit-1.html

(實施例2卸下硬件能力位)

+0

用'-xarch = sse4.2'編譯允許編譯器使用SSE4.2內部函數。稍後剝離SSE4.2 HWCAP位可能會導致使用這些內部函數的二進制文件,然後無法在不支持SSE4.2的硬件上運行。你不會編譯64位二進制文​​件,修改ELF頭文件作爲32位二進制文​​件讀取,並期望它在32位硬件上運行,對嗎? –

+0

topic-starter提到他們有運行時警衛,根據運行的應用程序的HW來選擇適當的實現。我知道一般情況下HWCAP是什麼。但這種情況很特殊。有可能是編譯器爲代碼的非內在部分發出非SSE2的情況。這需要檢查。 P.S. ELF32和ELF64是ELF本身的屬性(類型更精確),而不是HWCAP部分的某些值。所以,你在這裏過度疲勞。 – Anton

+0

*主題啓動者提到他們有選擇合適實現的時間後衛,具體取決於應用程序運行的硬件。*我不清楚提供的運行時保護示例是否保證可以保護使用的編譯代碼特定的指令集,如SSE2。從提供的例子看來,編譯器外部的代碼*也可以使用這些指令集進行編譯,所以刪除HWCAP位意味着沒有實現特定功能的硬件可能仍然會遇到需要它的指令。 –