_man(C99) restrict 포인터
2022. 3. 13. 15:30ㆍ카테고리 없음
restrict 키워드
컴파일을 할 때 최적화를 위해서 사용하는 키워드이다.
어떤 방식으로 최적화 되는지 알아보기 위해 간단한 함수 두개를 비교해보자.
간단한 함수 작성
void increase(int *a, int *b, int *x)
{
*a += *x;
*b += *x;
}
void restrict_increase(int *restrict a, int *restrict b, int *restrict x)
{
*a += *x;
*b += *x;
}
포인터를 받아서 x만큼 더하는 간단한 함수이다. restrict를 사용했을 때 어셈블리어에 어떤 변화가 생겼을까?
obj 파일 분석
void increase(int *a, int *b, int *x)
{
*a += *x;
restrict.o[0x4] <+4>: mov eax, dword ptr [rdx]
restrict.o[0x6] <+6>: add dword ptr [rdi], eax
*b += *x;
restrict.o[0x8] <+8>: mov eax, dword ptr [rdx]
restrict.o[0xa] <+10>: add dword ptr [rsi], eax
}
void restrict_increase(int *restrict a, int *restrict b, int *restrict x)
{
*a += *x;
restrict.o[0x14] <+4>: mov eax, dword ptr [rdx]
restrict.o[0x16] <+6>: add dword ptr [rdi], eax
*b += *x;
restrict.o[0x18] <+8>: add dword ptr [rsi], eax
}
increase 함수는 a에 x를 더하기 위해서 x가 가리키는 주소를 레지스터에 복사하고, a에 더하고 있다. b도 마찬가지이다.
restrict_increase 함수는 a에서는 위와 같은 방식으로 작동하나, b에서는 레지스터에 다시 복사하지 않고 값을 재사용하여 b에 더하는 것을 볼 수 있다.
x의 주소값에 참조할 수 있는 방법이 x를 이용하는 방법밖에 없다고 알려주었으므로 중간에 메모리에 변화를 주는 연산을 해도 x에서 다시 값을 읽어올 필요가 없어진다. 따라서 restrict_increase 함수에서는 x주소에서 값을 받아오는 mov 연산을 빼고 기존의 값을 재사용 하는 것을 볼 수 있다.
excutable 파일 분석
void increase(int *a, int *b, int *x)
{
restrict[0x100003f44] <+4>: mov qword ptr [rbp - 0x8], rdi
restrict[0x100003f48] <+8>: mov qword ptr [rbp - 0x10], rsi
restrict[0x100003f4c] <+12>: mov qword ptr [rbp - 0x18], rdx
*a += *x;
restrict[0x100003f50] <+16>: mov rax, qword ptr [rbp - 0x18]
restrict[0x100003f54] <+20>: mov ecx, dword ptr [rax]
restrict[0x100003f56] <+22>: mov rax, qword ptr [rbp - 0x8]
restrict[0x100003f5a] <+26>: add ecx, dword ptr [rax]
restrict[0x100003f5c] <+28>: mov dword ptr [rax], ecx
*b += *x;
restrict[0x100003f5e] <+30>: mov rax, qword ptr [rbp - 0x18]
restrict[0x100003f62] <+34>: mov ecx, dword ptr [rax]
restrict[0x100003f64] <+36>: mov rax, qword ptr [rbp - 0x10]
restrict[0x100003f68] <+40>: add ecx, dword ptr [rax]
restrict[0x100003f6a] <+42>: mov dword ptr [rax], ecx
}
void restrict_increase(int *restrict a, int *restrict b, int *restrict x)
{
restrict[0x100003f74] <+4>: mov qword ptr [rbp - 0x8], rdi
restrict[0x100003f78] <+8>: mov qword ptr [rbp - 0x10], rsi
restrict[0x100003f7c] <+12>: mov qword ptr [rbp - 0x18], rdx
*a += *x;
restrict[0x100003f80] <+16>: mov rax, qword ptr [rbp - 0x18]
restrict[0x100003f84] <+20>: mov ecx, dword ptr [rax]
restrict[0x100003f86] <+22>: mov rax, qword ptr [rbp - 0x8]
restrict[0x100003f8a] <+26>: add ecx, dword ptr [rax]
restrict[0x100003f8c] <+28>: mov dword ptr [rax], ecx
*b += *x;
restrict[0x100003f8e] <+30>: mov rax, qword ptr [rbp - 0x18]
restrict[0x100003f92] <+34>: mov ecx, dword ptr [rax]
restrict[0x100003f94] <+36>: mov rax, qword ptr [rbp - 0x10]
restrict[0x100003f98] <+40>: add ecx, dword ptr [rax]
restrict[0x100003f9a] <+42>: mov dword ptr [rax], ecx
}
obj 파일에서는 최적화 되어 operation이 준 것을 볼 수 있었는데, 막상 executable 파일을 뜯어보니 x가 가리키는 주소를 b가 더해질 때도 복사를 한번 더 하고 있다.
왜 이런 차이가 있는지는 아직 모르겠다.