2016-10-19 9 views
5

아마도 이것은 모두 미세하지만 나노 합성에 관한 것이 아니지만 주제가 저에게 흥미 롭습니다. 긴 모드에서 비 고유 등록 크기를 사용할 때 벌칙이 있는지 알고 싶습니다.Long 모드에서 64/32 비트 레지스터를 사용할 때 페널티가있을 수 있습니까?

다양한 소스에서 eax 대신 ax과 같은 부분 레지스터 업데이트로 인해 eflags이 멈추고 성능이 저하 될 수 있음을 알게되었습니다. 그러나 긴 모드에 대해서는 잘 모르겠습니다. 어떤 레지스터 크기가이 프로세서 작동 모드에서 기본으로 간주됩니까? x86-64는 여전히 x86 아키텍처의 확장이므로 32 비트는 여전히 기본이라고 생각합니다. 아니면 내가 틀렸어?

sub eax, r14d 

또는

sub rax, r14 

같은 예를 들어

, 지침은 같은 크기를 가지고 있지만, 그 중 하나를 사용하는 경우 어떤 처벌이있을 수있다? 아래와 같은 연속 명령어로 레지스터 크기를 혼합 할 때 불이익을받을 수 있습니까? 연속 명령어의 32 비트 및 64 비트 레지스터 크기를 혼합 할 때

sub ecx, eax 
sub r14, rax 
+0

16 비트 액세스에는 페널티가 있습니다. 32 비트 레지스터를 사용하고 r8-r15를 피하는 것이 좋으며 사실 코드 크기가 더 작아지는 경우가 많습니다. –

+4

32 비트 레지스터에 쓰면 자동으로 상위 32 비트가 지워 지므로 부분 업데이트 문제가 발생하지 않습니다. – Jester

+0

EFLAGS 레지스터는 최신 프로세서에서 많이 가상화됩니다. 모든 레지스터와 마찬가지입니다. 필연적으로, 너무 많은 명령어가이를 수정하고 슈퍼 스칼라 실행의 주요 댐퍼입니다. 코드에서 누락 된 것은 실제로 레지스터를 사용하는 명령어입니다. 따라서 프로세서가 연동하여 게시 한 코드를 멈추게 할 강력한 이유가 없습니다. 그것이 어떻게 작동 할 수 있는지/어떻게 작동 할 수 있는지에 대한 누군가의 견해를 결코 가져 본 적이 없다. 어셈블리 코드를 작성하는 유일한 포인트는 C 컴파일러보다 더 빨리 작성하는 것입니다. 법안. –

답변

8

어떤 처벌이있을 수있다 (높은 DWORD 가정하면 모든 경우에 제로)?

No, writing to a 32-bit register always zero-extends to the full register이므로 x86-64는 32 비트 및 64 비트 명령어에 대한 부분 레지스터 페널티를 방지합니다.

따라서 32 비트가 여전히 기본이라고 생각합니다.

예, 대부분의 명령어 (other than PUSH/POP)의 경우 기본 피연산자 크기는 32 비트입니다. 64 비트에는 W 비트가 1로 설정된 REX 접두어가 필요합니다. 따라서 코드 크기의 이유로 32 비트를 선호합니다. 이것이 컴파일러가 정적 데이터의 주소에 mov r32, imm32을 사용하는 이유입니다 (기본 코드 모델은 코드 및 정적 데이터 주소가 가상 주소 공간의 낮은 2GiB에 있어야하기 때문입니다).

AMD의 디자인 선택이었습니다. 그들은 다른 방법을 선택할 수 있었고 32 비트 피연산자 크기를 얻으려면 접두어가 필요했습니다. 긴 모드는 별도의 모드이므로 x86-64 기계 코드는 x86-32 기계 코드와 다를 수 있습니다. AMD는 차이를 최소화하여 디코더에서 최대한 많은 트랜지스터를 공유 할 수 있도록했습니다. 결론은 정확하지만, 당신의 추론은 완전히 가짜입니다. (대신 EAX 도끼 등)


부분 레지스터 업데이트 EFLAGS 스톨을 야기하고 성능을 저하시킬 수있다.

부분 플래그 스톨은 부분 레지스터 스톨과 별개입니다. 그들은 내부적으로 비슷하게 처리됩니다 (EFLAGS의 개별적으로 이름이 변경된 부분은 수정 된 AX가 EAX의 수정되지 않은 상위 ​​바이트와 병합되어야 함과 동일하게 병합되어야합니다). 하지만 하나는 다른 원인이되지 않습니다.

# partial-reg stall 
setcc al   # leaves the upper 3 (or 7) bytes unmodified 
add  edx, eax  # reads full EAX. Older CPUs stall while merging 

Zeroing EAX ahead of the flag-setting and setcc with xor eax,eax avoids the partial-register penalty entirely. (Core2/Nehalem은 이전 CPU보다 더 적은 사이클로 작동하지만 병합 작업을 삽입하는 동안 2 또는 3c에서는 여전히 정지합니다.Sandybridge는 병합 작업을 삽입하는 동안 전혀 멈추지 않습니다.)

(다른 CPU의 부분 등록 처벌 요약 : Why doesn't GCC use partial registers?, 기본적으로 똑같은 말).

AMD는 나중에 전체 레지스터를 읽을 때 부분 레지스터 스톨을 겪지 않지만 부분 레지스터 쓰기 및 읽기는 전체 레지스터에 대해 가짜 종속성을 갖습니다.

인텔 하 스웰/스카이 레이크 (어쩌면 Ivybridge)을 (AMD CPU는. 인텔 P4 및 Silvermont/나이트의 방문이 같은 방법입니다. 처음에 별도로 하위 레지스터의 이름을 변경하지 마십시오) 별도로 al 이름을 변경하지 않는 rax 모두이므로 low8/low16 레지스터를 병합 할 필요가 없습니다. 그러나 setcc al은 이전 값에 대해 잘못된 종속성이 있습니다. 그들은 여전히 ​​이름을 변경하고 ah을 병합합니다. (Details on HSW/SKL partial-reg performance는.)


# partial flag stall when reading a flag that didn't come from 
# the last instruction to write any flags. 
clc 
# edi and esi = one-past-the-end of dst and src 
# ecx = -count 
bigInt_add: 
    mov eax, [esi+ecx*4] 
    adc [edi+ecx*4], eax # reads CF, partial flag stall on 2nd and later iterations 
    inc ecx    # writes all flags except CF 
    jl bitInt_add   # loop upwards towards zero 

은 샌디 브리지 대 인텔 사전 샌디 브리지에 대한 부분 플래그 문제에 대한 자세한 설명은 this Q&A를 참조하십시오.


Agner Fog's microarch pdf 참조, 그리고이 모든에 대한 자세한 내용은 태그 위키에서 다른 링크.

+0

대단히 감사합니다 –