2014-04-10 13 views
0

我想讓編譯器通過參數化我的C代碼中的內聯彙編來自動選擇寄存器,但是我遇到了一些麻煩。誰能告訴我發生了什麼問題?如果我使用我已註釋掉的代碼(強制與%xmm0有關),它將編譯並獲得預期結果。但是,如果我離開它註釋掉作爲寫到這裏,我得到的編譯器錯誤:嘗試在gcc中使用(SSE4)blendvpd和行內彙編

/tmp/ccJxmSbm.s: Assembler messages: 
/tmp/ccJxmSbm.s:81: Error: the first operand of `blendvpd' must be `%xmm0' 

另外,如果我什麼都不做除了去掉printf語句,代碼塊編譯成功過。所以它與移動參數有關,爲printf調用做準備。我已經明確地加入了應該強制使用%xmm0的「Yz」約束,但它看起來並沒有被尊重。

這裏是有問題的代碼:

#include <stdio.h> 

const unsigned long long myConst[2] = {0x0000000000000000,0xffffffffffffffff}; 
const unsigned long long myConst2[2] = {0x0000000000000000,0x1111111111111111}; 
const unsigned long long myConst3[2] = {0xabcdef,0x0000000000000000}; 

#define ASSIGN_CONST128(val, const) \ 
    val = *((__uint128_t *)const); 

int main(void) 
{ 
    register __uint128_t regVal1 /* asm("%xmm0") */ ; 
    register __uint128_t regVal2; 
    register __uint128_t regVal3; 
    ASSIGN_CONST128(regVal1, myConst); 
    ASSIGN_CONST128(regVal2, myConst2); 
    ASSIGN_CONST128(regVal3, myConst3); 

    asm("blendvpd %[mask], %[val1], %[val2]" : 
     [val2] "+x" (regVal3) : 
     [mask] "Yz" (regVal1), 
     [val1] "x" (regVal2)); 

    printf("REGVAL1: %016llx%016llx (original=%016llx%016llx)\n" 
      "REGVAL2: %016llx%016llx (original=%016llx%016llx)\n" 
      "REGVAL3: %016llx%016llx (original=%016llx%016llx)\n", 
    (unsigned long long)(regVal1>>64), (unsigned long long)regVal1, 
    myConst[1], myConst[0], 
    (unsigned long long)(regVal2>>64), (unsigned long long)regVal2, 
    myConst2[1], myConst2[0], 
    (unsigned long long)(regVal3>>64), (unsigned long long)regVal3, 
    myConst3[1], myConst3[0]); 

    // Expected result: 
    // REGVAL1: ffffffffffffffff0000000000000000 (original=ffffffffffffffff0000000000000000) 
    // REGVAL2: 11111111111111110000000000000000 (original=11111111111111110000000000000000) 
    // REGVAL3: 1111111111111111abcdef (original=0000000000000000abcdef) 
} 

我明白任何想法。

+1

'__uint128_t'與'__m128d'不一樣。僅供參考,'icc'在此代碼上崩潰,'clang'拒絕編譯。 –

+0

我的純粹無知。當我更改爲__m128i(實際上需要整數變體,如果它有所不同),我開始注意到編譯器手持多少。似乎所有與這種類型的對象的交互現在都必須在彙編中完成。不一定是問題,但我很難弄清楚。 – Marty

+0

所以,現在我製作了兩個「無符號長整型」臨時變量,並使用movlpd/movhpd將xmmX寄存器內容移入它們。然後我可以對「unsigned long long」變量執行printf。 – Marty

回答

2

爲什麼不只是使用相關的內在?

regVal3 = _mm_blendv_pd (regVal1, regVal2, regVal3); 

正如其他人指出,regVal1regVal2regVal3都應該被聲明爲__m128d

+0

再次,大多是無知。這是我第一次使用C語言嵌入彙編。我希望儘量減少或更直接地控制應用程序中的內存何時被觸及,所以它看起來像asm()結構中的約束條件允許的那樣。內在因素是否提供相同的控制水平? – Marty

+0

看起來像我的GCC版本不支持SSE4.1,所以我不能使用這種內在。您的版本看起來像英特爾內在。我發現GCC使用'__v2df'參數並被稱爲'__builtin_ia32_blendvpd'。 – Marty

+0

通常,低層指令內在('__builtin_ia32_blendvpd')被封裝在更高層次的內在('_mm_blendv_pd')中,例如,在'': '__STATIC_INLINE __m128d __attribute __((__ always_inline__)) _mm_blendv_pd(__m128d __X,__m128d __Y,__m128d __M) { 回報(__m128d)__builtin_ia32_blendvpd((__v2df)__ X, \t \t \t \t \t(__v2df) __Y, \t \t \t \t \t(__v2df)__ M); }' –