Arm 프로세서 내부에서 성능을 최적화하기 위해 종종 어셈블리 명령어의 순서를 바꿔 실행한다고 설명했습니다. 이런 동작을 수행하기 전에 먼저 각 명령어 간에 의존성이 있는지 체크합니다. 명령어 간 의존성이 있다면 명령어의 순서를 지켜 실행합니다.

다음 어셈블리 명령어를 보면서 어드레스 의존성에 대해 배워 봅시다.
 

그림 17.2 의존성이 있는 로드(LDR) 명령어의 예시

위 코드는 2개의 로드 명령어로 구성돼 있습니다. 

먼저 01번째 줄을 봅시다. X1 레지스터가 0x30000을 담고 있고 0x30000 주소에 0x10000이 있다고 가정합시다. 01번째 줄은 X1 레지스터가 담고 있는 주소에 있는 데이터를 X0 레지스터에 로딩하는 동작입니다. 이어서 02번째 줄은 X0 레지스터의 값에서 8을 더한 결과(주소)에 있는 값을 X2 레지스터에 로딩합니다. 

01번째 줄 명령어를 실행한 결과, X0이 0x10000이면 02번째 줄은 0x10008 주소에 있는 데이터를 X2 레지스터에 로딩합니다. 02번째 줄은 다음과 같이 실행된다고 볼 수 있습니다.

X2 = *(0x10000 + 0x8);

이번에는 다른 예를 들까요? 01번째 줄 명령어의 실행 결과 X0이 0x20000이면 02 번째 줄은 어떻게 실행될까요? 02번째 줄은 0x20008 주소에 있는 데이터를 X2 레지스터에 로딩합니다. 이를 다음과 같은 수식으로 나타낼 수 있습니다. 

X2 = *(0x20000 + 0x8);

앞의 두 가지 예시에서 든 명령어의 공통점은 다음과 같은 의사 코드로 표현할 수 있습니다. 

X2 = *(0x0 + 0x8);

“X2 레지스터의 값은 X0 레지스터에 따라 결정된다”라고 해석할 수 있습니다. 

앞에서 소개한 두 가지 패턴의 명령어에서 한 가지 기억할 점은 "01번째 줄 명령어의 실행 결과가 02번째 줄에 영향을 미친다."라는 것입니다. 여기서 X0 레지스터의 값에 따라 02번째 줄의 실행 결과에 영향을 미치니 “01번째와 02번째 줄 명령어 사이에 의존성이 있다”라고 볼 수 있습니다. 이를 어드레스 의존성(address dependence) 혹은 레지스터 의존성(register dependence)이라고 하며, 다음 그림과 같이 표현할 수 있습니다.

 

그림 17.3 어드레스 의존성

만약 의존성이 있는 01번째 줄과 02번째 줄 명령어의 실행 순서를 바꾸면 어떻게 동작할까요? 명령어가 실행되면 예측할 수 없는 이상한 값이 레지스터에 저장될 가능성이 높아 오동작을 유발할 것입니다. 따라서 명령어 사이에 의존성이 있으면 Arm 프로세서 내부에서 메모리에 액세스하는 순서를 바꾸지 않습니다.

+ Recent posts