2014-04-10 4 views
0

컴파일러가 내 C 코드에서 인라인 어셈블리를 매개 변수화하여 레지스터를 자동으로 선택하도록하고 싶습니다.하지만 몇 가지 문제가 있습니다. 누구가 잘못 될지 말해 줄 수 있습니까? 내가 주석 처리 한 코드를 사용하면 (% xmm0과의 제휴를 강요 함) 컴파일하여 예상 결과를 얻습니다.(SSE4) gcc에서 인라인 어셈블리로 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

그래서 이제는 두 개의 "부호없는 long long"임시 변수를 만들고 movlpd/movhpd를 사용하여 xmmX 레지스터 내용을 이동시킵니다. 그리고 나서 "unsigned long long"변수에 대해 printf를 할 수 있습니다. – Marty

답변

2

관련 내장 함수를 사용하지 않는 이유는 무엇입니까? 다른 사람이 언급 한 것처럼

regVal3 = _mm_blendv_pd (regVal1, regVal2, regVal3); 

regVal1, regVal2regVal3 모든 __m128d로 선언되어야한다.

+0

다시, 대부분 무지. C에서 어셈블리를 임베딩하는 데 처음으로 작업 한 적이 있습니다. 응용 프로그램에서 메모리를 직접 만지면되는 것을 최소화하거나 직접 제어하고 싶었 기 때문에 asm() 구문의 제약이이를 허용하는 것처럼 보였습니다. 내장 함수는 동일한 수준의 제어를 제공합니까? – Marty

+0

내 버전의 GCC는 SSE4.1을 지원하지 않으므로이 내장 함수를 사용할 수 없습니다. 위 버전은 Intel 내장 제품과 같습니다. 나는 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); }' –