이 코드 스 니펫에서 16 비트 레지스터가 BSR 명령에 사용되는 이유는 무엇입니까?
-
10-07-2019 - |
문제
~ 안에 이 하드 코어 기사 기능이 있습니다 find_maskwidth()
기본적으로 표현하는 데 필요한 비트 수를 감지합니다. itemCount
명령 값 :
unsigned int find_maskwidth( unsigned int itemCount )
{
unsigned int maskWidth, count = itemCount;
__asm {
mov eax, count
mov ecx, 0
mov maskWidth, ecx
dec eax
bsr cx, ax
jz next
inc cx
mov maskWidth, ecx
next:
}
return maskWidth;
}
문제는 그들이 사용하는 이유입니다 ax
그리고 cx
대신 등록 eax
그리고 ecx
?
해결책
나는 그들이 16 비트 이하의 필드만을 다룰 것으로 기대한다고 생각할 수있다. 패키지의 코어 또는 논리 프로세서 수와 같은 것을보고하는 데 사용할 수있는 비트 수를 결정하는 데 사용되기 때문에 65535 이상으로 넘쳐나 기 전에 시간이 오래 걸릴 것입니다.
나는 누군가가보다 일반적인 목적으로 루틴을 사용하기로 결정하지 않기를 바랍니다.
그리고 FYI- X86 어셈블리로 떨어지지 않고 이와 같은 일을하고 싶다면 (기사의 목적에 대해서는 포트가 불가능하다고 생각하지만), 비트 twiddling 핵 페이지 당신은 덮었습니까?
다른 팁
원래 데이터의 너비는 16 비트에 불과한 것 같습니다. CX는 약간의 숫자를 얻고 있기 때문에 어쨌든 아주 적은 수보다 클 수있을 가능성이 없습니다.
한 레벨에서 16 비트 및 32 비트 IA32의 Opcodes는 접두사 바이트를 제외하고는 동일하므로 어떤 모드에 따라 All-32 또는 All-16 비트 지침을 발행하는 것이 더 효율적입니다. 당신은 들어 왔습니다. 그게 당신이 질문을 한 이유라고 생각합니다 ...
이 코드가 실제로 쓰여지지 않았다는 사실을 감안할 때 (예를 들어 코드를 혼란스럽게하는 것 외에도 마스크 폭과 카운트 변수가 전혀 필요하지 않음) 또 다른 "나쁜 것"임을 확신 할 수 있다고 생각합니다. 이 코드에서.
일상은 기본적으로 ItemCount의 이진 (베이스 2) 로그를 결정합니다.
ItemCount> 2^16 인 경우 완전히 잘못된 값을 제공합니다. 그것은 포화되지 않거나 무언가가 아니며, 단지 명백한 잘못입니다. 입력 매개 변수는 "부호없는 int"이므로 더 잘못된 것입니다. 따라서 더 많은 65536 코어에서 작동을 멈출 것입니다.
내 생각에, 인텔의 누군가가 실제로 16 비트로 거슬러 올라가는 정말 고대 코드를 파고 실제로 이해하지 않고 사용했으며 65536이 영원히 충분히 충분하기 때문에 640k 메모리가 영원히 충분하거나 두 개가되기 때문입니다. -기지 연도는 시간이 끝날 때까지 충분합니다.
이 코드의 저자는 아마도 그가 무엇을하고 있는지 알지 못했을 것입니다 :-). 이 지침의 16 비트 버전은 더 길고 빠르지 않습니다. 실제로, 그들은 아마도 ECX를 사용하는 다음 명령어에서 부분 레지스터 스톨을 일으킬 것입니다 (예 : MOV).
또한 DEC는 출력이 0 일 때 ZF를 이미 설정하므로 점프는 1 월 (DEC 이후)에 하나의 명령을 안전하게 이동할 수 있습니다. 코드를 약간 단순화 할 수 있습니다.
이것이 제가이 코드 스 니펫을 작성하는 방법입니다.
mov eax, [count]
xor ecx, ecx
dec eax
jz next
bsr ecx, eax
inc ecx
next:
mov [maskWidth], ecx
또한, 여기서 조립에 대한 동기 부여는 BSR 명령을 사용하는 것으로 보이며, 이는 C 언어 나 라이브러리에 해당하지 않습니다. 이 목적을 위해 컴파일러 별 고유 기능을 사용하여 어셈블리를 사용하지 않을 수 있습니다. 이것들은 본질적으로 포송 할 수 없지만 인라인 어셈블리도 아닙니다.
GCC에서 동등한 기능은 다음과 같습니다.
unsigned int find_maskwidth(unsigned int itemCount)
{
if(itemCount <= 1)
return 0;
else
return 32 - __builtin_clz(itemCount - 1);
}
훨씬 더 읽기 쉬운가요?