2017-01-15 7 views
1

unsigned char의 배열에서 1의 수를 계산하기 위해 현재 내장형 popcnt을 사용하려고합니다.gcc 인라인 asm이 컴파일되지 않았습니다.

나는 보통 __builtin_popcount으로 작동하는 기능을 가지고 있었지만 좀 더 공격적인 속도 요구 사항으로 인라인 asm 접근 방식을 사용하기로 결정했습니다.

size_t popcnt_manual(unsigned char *bytes, size_t len) { 
    size_t i, cnt = 0; 
    for(i = 0; i < len; i++) { 
     __asm__(
       "popcnt %0, %0 \n\t" 
       "add %0, %1 \n\t" 
       : "+r" (cnt) 
       : "r" (bytes[i])); 
    } 

    return cnt; 
} 

그리고 컴파일러는

접미사 또는이 잘못 피연산자 코드에서 구문 오류를 제외하고

답변

2

를 추가 말하는 유지 (" "r" ->: "r"), 문제는 일치하지 않는 매개 변수입니다 . -S에서 출력을 보면

: 이것은 당신이 기대하는 것입니다, cnt 이후

add rax, r8b 

은 size_t로하고 bytes[i]는 바이트이다. 추가를하면 크기가 동일해야합니다.

또한 인라인 asm 대신 builtins를 사용할 것을 제안 할 수 있습니까? 이 문제는 (다른 많은 것들도 마찬가지입니다) 피합니다.


먼저 레지스터에을 저장하지 않고 popcnt에서 결과를 추가 할 수있는 방법이 있습니까?

음. 그것은 사실 전혀 다른 질문입니다. 당신이 물어 본 오류는 단일 add 명령에서 바이트와 size_t를 섞어서 발생했습니다. 그것은 수행하여 해결할 수 있습니다 : 나는 (? 내 카르마 포인트를 획득하는 방법) 새로운 질문을 계속 추가하는 것이 좋습니다 안

__asm__(
      "popcnt %0, %0 \n\t" 
      "add %0, %1 \n\t" 
      : "+r" (cnt) 
      : "r" ((size_t)bytes[i])); 

하지만, 해당 웹 사이트에서 찾고, 코드는 그는 덤비는 것 같다

uint32_t builtin_popcnt_unrolled_errata(const uint64_t* buf, int len) { 
    assert(len % 4 == 0); 
    int cnt[4]; 
    for (int i = 0; i < 4; ++i) { 
    cnt[i] = 0; 
    } 

    for (int i = 0; i < len; i+=4) { 
    cnt[0] += __builtin_popcountll(buf[i]); 
    cnt[1] += __builtin_popcountll(buf[i+1]); 
    cnt[2] += __builtin_popcountll(buf[i+2]); 
    cnt[3] += __builtin_popcountll(buf[i+3]); 
    } 
    return cnt[0] + cnt[1] + cnt[2] + cnt[3]; 
} 

그는 popcnt의 'false dependency'문제를 피하기 위해 명시 적으로 cnt [x]를 사용합니다.

, GCC 6.1을 사용하고 -m64 -O3 -march=native -mtune=native 컴파일 I 출력으로 이것을보고 있어요 "레지스터에 떨어져 저장"

.L14: 
     popcnt r11, QWORD PTR [rcx] 
     add  rcx, 32 
     add  edx, r11d 
     popcnt r11, QWORD PTR -24[rcx] 
     add  eax, r11d 
     popcnt r11, QWORD PTR -16[rcx] 
     add  r10d, r11d 
     popcnt r11, QWORD PTR -8[rcx] 
     add  r9d, r11d 
     cmp  rcx, r8 
     jne  .L14 

당신이 언급하는?

+0

내가 builtins로 시작했지만 더 빠른 것을 원했습니다. popcnt의 결과를 레지스터에 저장하지 않고 추가 할 수있는 방법이 있습니까? https://danluu.com/assembly-intrinsics/ –

+0

답변을 주셔서 감사합니다. 나는 단지 블로그 포스트가 말하려고했던 것과 혼동되어 있었음에 틀림 없다. 여기에 당신의 업장 지점이 있습니다 :) –

+0

블로그에는 날짜가 없지만 4.8.2를 사용하여 작성했습니다. 오래 전 이었으므로 상황이 바뀔 수도 있습니다. 이것은 인라인 대신 빌트인을 사용하는 것이 권장되는 또 다른 이유입니다. 내장 함수는 시간이 지남에 따라 향상 될 수 있지만 인라인으로 작성하면 작성한 내용 만 얻을 수 있습니다. BTW, 성능이 중요하다면, 64 비트 popcnt를 사용하는 것은 아마도 8 비트 반복보다 빠릅니다. len을 확인하고 이상한 크기를 처리해야하지만 시간을두고 시도해야합니다. –