[assembly] 32 비트 레지스터의 x86-64 명령어가 전체 64 비트 레지스터의 위쪽 부분을 0으로 만드는 이유는 무엇입니까?

에서 인텔 설명서의 x86-64에 투어 , 본인은

아마도 가장 놀라운 사실은 같은 명령어가 MOV EAX, EBX상위 32 비트 RAX레지스터 를 자동으로 제로화 한다는 것입니다 .

동일한 소스에서 인용 된 인텔 문서 (3.4.1.1 수동 기본 아키텍처의 64 비트 모드에서 범용 레지스터)는 다음과 같이 알려줍니다.

  • 64 비트 피연산자는 대상 범용 레지스터에서 64 비트 결과를 생성합니다.
  • 32 비트 피연산자는 대상 범용 레지스터에서 64 비트 결과로 0 확장 된 32 비트 결과를 생성합니다.
  • 8 비트 및 16 비트 피연산자는 8 비트 또는 16 비트 결과를 생성합니다. 대상 범용 레지스터의 상위 56 비트 또는 48 비트 (각각)는 연산에 의해 수정되지 않습니다. 8 비트 또는 16 비트 연산의 결과가 64 비트 주소 계산 용인 경우 레지스터를 전체 64 비트로 명시 적으로 부호 확장합니다.

x86-32 및 x86-64 어셈블리에서 다음과 같은 16 비트 명령어

mov ax, bx

eax의 상위 단어가 0이되는 이런 종류의 “이상한”동작을 표시하지 마십시오.

따라서이 행동이 도입 된 이유는 무엇입니까? 언뜻보기에는 비논리적으로 보입니다 (하지만 x86-32 어셈블리의 단점에 익숙하기 때문일 수 있습니다).



답변

나는 AMD가 아니거나 그들에게 말하고 있지는 않지만 같은 방식으로했을 것입니다. 상위 절반을 0으로 설정해도 이전 값에 대한 종속성이 생성되지 않으므로 CPU가 기다려야합니다. 레지스터 이름 바꾸기 가 그런 식으로 일을하지 않은 경우 메커니즘은 본질적으로 패배 할 것이다.

이렇게하면 항상 종속성을 명시 적으로 중단하지 않고도 64 비트 모드에서 32 비트 값을 사용하여 빠른 코드를 작성할 수 있습니다. 이 동작이 없으면 64 비트 모드의 모든 32 비트 명령어는 상위 부분이 거의 사용되지 않더라도 이전에 일어난 일을 기다려야합니다. ( int64 비트를 만들면 캐시 공간과 메모리 대역폭이 낭비됩니다. x86-64는 32 비트 및 64 비트 피연산자 크기를 가장 효율적으로 지원합니다. )

8 비트 및 16 비트 피연산자 크기의 동작은 이상합니다. 의존성 광기는 현재 16 비트 명령어를 피하는 이유 중 하나입니다. x86-64는 8 비트의 경우 8086, 16 비트의 경우 386에서이를 상속했으며 8 비트 및 16 비트 레지스터가 32 비트 모드에서와 동일한 방식으로 64 비트 모드에서 작동하도록 결정했습니다.


GCC가 부분 레지스터를 사용하지 않는 이유 도 참조하십시오 . 실제 CPU에서 8 비트 및 16 비트 부분 레지스터에 대한 쓰기 (및 전체 레지스터의 후속 읽기)를 처리하는 방법에 대한 실제 세부 정보를 참조하십시오.


답변

단순히 명령어와 명령어 세트의 공간을 절약합니다. 기존 (32 비트) 명령어를 사용하여 작은 즉치 값을 64 비트 레지스터로 이동할 수 있습니다.

또한 재사용 MOV RAX, 42MOV EAX, 42수있는 경우에 대해 8 바이트 값을 인코딩하지 않아도됩니다 .

이 최적화는 8 비트 및 16 비트 작업에 대해 중요하지 않으며 (더 작기 때문에) 규칙을 변경하면 이전 코드도 손상됩니다.


답변

0이 64 비트로 확장되지 않으면에서 읽는 명령어 raxrax피연산자 (에 쓰는 eax명령어와 그 rax앞에 쓰는 명령어)에 대해 2 개의 종속성을 갖게됩니다. 즉, 1) ROB에 대한 항목이 있어야합니다. 단일 피연산자에 대한 다중 종속성, 이는 ROB가 더 많은 로직과 트랜지스터를 필요로하고 더 많은 공간을 차지하며 실행하는 데 오래 걸릴 수있는 불필요한 두 번째 종속성을 기다리면 실행 속도가 느려짐을 의미합니다. 또는 2), 16 비트 명령에서 발생한다고 생각하는 것은 할당 단계가 아마도 중단 될 것입니다 (즉, RAT에 ax쓰기에 대한 활성 할당이 있고 eax읽기가 나타나면 ax쓰기가 중단 될 때까지 중단됨).

mov rdx, 1
mov rax, 6
imul rax, rdx
mov rbx, rax
mov eax, 7 //retires before add rax, 6
mov rdx, rax // has to wait for both imul rax, rdx and mov eax, 7 to finish before dispatch to the execution units, even though the higher order bits are identical anyway

제로 확장이 아닌 경우의 유일한 이점은 더 높은 순서의 비트 rax가 포함 되도록하는 것 입니다. 예를 들어 원래 0xffffffffffffffff를 포함하는 경우 결과는 0xffffffff00000007이되지만 ISA가 이러한 비용으로이 보장을 수행 할 이유가 거의 없습니다. 제로 확장의 이점이 실제로 더 많이 필요할 가능성이 높으므로 추가 코드 줄이 절약 mov rax, 0됩니다. 항상 제로가 64 비트로 확장 될 것입니다 보장함으로써, 컴파일러에있는 동안 마음이 공리와 함께 작업 할 수 있습니다 mov rdx, rax, rax단지 그것을 실행 유닛을 확보, 빠른 실행을 시작하고 은퇴 할 수 있음을 의미, 그 하나의 종속 기다려야합니다. 또한 REX 바이트 없이도 xor eax, eax제로화 와 같은보다 효율적인 제로 관용구를 허용합니다 rax.


답변