data영역 메모리에 데이터를 저장하고 나서 메모리에 저장된 데이터를 가져오기 위해 그 메모리 위치를 label로 표시할 수 있다.
이때, 문자열로된 label로부터 실제 메모리 주소값을 가져오는 명령어가 set 이다.
.data
i_m: .word 4
j_m: .word 9
k_m: .word 3
위 코드에서는 data 영역에 4바이트 크기의 메모리 공간 3개에 각각 4, 9, 3을 저장하고, 각 메모리 주소를 i_m, j_m, k_m 으로 표시하였다.
이때 i_m, j_m, k_m 이 가리키는 메모리 주소는 아래와 같이 가져올 수 있다.
set i_m, %o0
위 코드는 i_m의 주소값을 가져와서 %o0 레지스터에 저장하는 코드이다.
한편, 지난 지연주기 최적화 글에서 set은 nop에 바로 넣을 수 없다고 하였다.
set은 명령어 2개가 합쳐진 합성 명령어이기 때문이다.
그렇다면 왜 set 명령어는 2개 명령어로 합칠 수 밖에 없었을까?
그 전에 왜 set을 사용해야 하는지부터 고민해보자.
SPARC 프로세서가 다루는 '명령어' 의 크기, '데이터' 의 크기는 모두 32bit ( = 4byte) 이다.
명령어는 그 포맷 구조상 상수 필드가 13bit로 제한되어 있어, 피연산자로 주소값을 모두 저장할 수 없다.
메모리 주소값도 결국 프로세서가 처리하는 '데이터' 이기 때문에 32bit 사이즈이기 때문이다.
그 동안 -4096 ~ 4095 범위의 상수만 처리할 수 있었던 이유도, 부호비트 1개, 데이터비트 12개로 상수를 13비트로 표현할 수 있었기 때문이다.
즉, 32bit 메모리 주소 데이터 전체를 명령어 하나에서 온전히 가져다 쓰지 못하기 때문에,
메모리의 주소값 4byte를 레지스터에 저장해두고, 그 레지스터의 값을 활용해 메모리에 접근해왔던 것이다.
결국 이 메모리 주소값 자체를 레지스터에 저장할 별도 명령어가 필요해 set 명령어가 등장했는데, 이 set도 결국 명령어인지라 OP 코드 같이 다른 잡다한 기본 명령어 필수 포맷을 저장할 공간이 필요하여 32bit 를 피연산자로 받을 수 없다.
그래서 명령어를 2번 실행하여 메모리 주소값을 나눠 저장하게 되는데, 이때 사용하는 명령어가 sethi 와 or 명령어이다.
sethi 명령어도 명령어이므로, OP 코드 같이 다른 잡다한 기본 명령어 필수 포맷을 저장할 공간이 필요하다.
이를 위해 10개 비트를 사용하고 있어 레지스터로 저장할 메모리 주소를 담을 공간이 총 22비트어치 남는다.
sethi 는 이름 그대로, 이 22비트의 데이터를 레지스터의 32bit 공간중 상위 22개 비트에 저장한다.
sethi 0x30cfcf0032 >> 10, %l0
sethi 는 다음과 같이 사용되는데, 이는 저 32bit 메모리를 오른쪽으로 10번 밀어 하위 10개 비트를 버린다.
(위에 0이 10개 채워지는데) 이는 무시되며, 남은 22개 비트를 %l0의 상위 22개 비트에 저장한다.
그 다음 or 명령어가 실행되는데, 이는 나머지 하위 10개비트를 아까 %l0에 그대로 다시 저장하여 합치는 과정이다.
or %l0, 0x30cf0034 & 0x3ff, %l0
0x3ff 는 하위비트 10개가 모두 1이고 나머지는 모두 0인 32bit를 나타낸다.
어떤 값과 이 값을 and 연산하므로 하위 10개 비트만 남기고 다 버리게 된다.
이 값을 기존 %l0 과 or 연산으로 하여 다시 %l0에 넣는다는 것은 하위 10개비트를 저장한다는 것과 같다.
즉, 정리하면
1. sethi 로 저장할 메모리 주소의 상위 22개 비트를 먼저 저장하고
2. or 연산자로 저장할 메모리 주소의 나머지 하위 10개 비트를 저장한다.
이제 set 명령어의 구조와 작동 방식을 이해하였으므로, 지연주기 최적화를 할 수 있다.
set str, %o0
call printf
nop
이런 코드가 있다고 해보자.
set을 nop 위치로 보내는 것이 불가능한 것은 이해할 수 있다.
그렇다면 이제 이를 아래와 같이 최적화할 수 있다.
sethi %hi(str), %o0
call printf
or %o0, %lo(str), %o0
%hi, %lo 는 주어진 라벨이 가리키는 주소값의 상위 22비트, 하위 22비트를 각각 가리킨다.
'CS > 어셈블리' 카테고리의 다른 글
[SPARC] 25. Stack Frame (0) | 2023.11.17 |
---|---|
[SPARC] 24. SPARC 메모리 맵 정리 ( + bss 영역) (0) | 2023.11.16 |
[SPARC] 22. 정적 메모리와 경계정렬 (0) | 2023.10.20 |
[SPARC] 21. 메모리 (0) | 2023.10.19 |
[SPARC] 20. switch - case 구현하기 (0) | 2023.10.18 |