sum1이라는 함수가 있다. a와 b 2개의 수가 주어졌을 때 a부터 b까지의 합을 계산하여 반환한다.

int sum1(int a, int b) {
	int sum = 0;
	for (int i = a; i <= b; i++)
		sum += i;
	return sum;
}

sum1에서 루프를 도는 코드는 다음과 같이 컴파일이 된다(-O2 옵션).

_loop:
01 f8                 add    eax,edi
83 c7 01              add    edi,0x1 ; loop variable 값을 1 증가시킨다.
39 f7                 cmp    edi,esi
75 f7                 jne    _loop



sum5라는 함수가 있다. 위의 sum1 함수와 비슷하지지만 루프 안에서 i를 사용하지 않고 “i * 5”를 사용한다.

int sum5(int a, int b) {
	int sum = 0;
	for (int i = a; i <= b; i++)
		sum += i * 5; // i 값의 5배를 더한다.
	return sum;
}

sum5에서 루프를 도는 코드는 다음과 같다(-O2 옵션). 루프 안에서 “i * 5” 연산을 하는 것이 아니라(mul이라는 op code의 사용을 하지 않음) loop variable 자체에 5를 더해서 처리해 버린다.

_loop:
41 01 c0     add    r8d,eax ; mul op code를 사용하지 않고
83 c0 05     add    eax,0x5 ; loop variable 값을 5 증가시킨다.
39 d0        cmp    eax,edx
75 f6        jne    _loop:



루프를 돌면서 배열(혹은 포인터)에 있는 값들을 참조하기 위해서는 “a[i]” 혹은 “*a” 와 같은 코드를 사용할 수 있다. 아래 2개의 함수를 보자.

int sum_index(int a[], int n) {
	int sum = 0;
	for (int i = 0; i < n; i++)
		sum += a[i]; // 요거!!!
	return sum;
}

int sum_pointer(int* a, int n) {
	int sum = 0;
	for (int i = 0; i < n; i++) {
		sum += *a; // 요거!!!
		a++;
	}
	return sum;
}

sum_index 및 sum_pointer 내부에 있는 코드는 Debug 모드에서 다음과 같이 컴파일된다.

sum += a[i];
8b 45 f8                 mov    eax,DWORD PTR [rbp-0x8]
48 98                    cdqe
48 8d 14 85 00 00 00 00  lea    rdx,[rax*4+0x0] ; 곱하기 4(int의 크기)가 이루어진다.
48 8b 45 e8              mov    rax,QWORD PTR [rbp-0x18]
48 01 d0                 add    rax,rdx
8b 00                    mov    eax,DWORD PTR [rax]
01 45 fc                 add    DWORD PTR [rbp-0x4],eax

sum += *a;
48 8b 45 e8           mov    rax,QWORD PTR [rbp-0x18]
8b 00                 mov    eax,DWORD PTR [rax] ; 근냥 포인터. 곱하기가 없다.
01 45 fc              add    DWORD PTR [rbp-0x4],eax

그런데 Release 모드(-O2)에서는 sum_index와 sum_pointer 함수의 루프를 도는 코드는 비슷하게 컴파일된다(인덱스 값의 곱하기가 없이).

_loop:
			sum += a[i];
03 07           add    eax,DWORD PTR [rdi]
			for (int i = 0; i < n; i++)
48 83 c7 04     add    rdi,0x4 ; 1이 아닌 4를 더한다.
48 39 d7        cmp    rdi,rdx
75 f5           jne    _loop

_loop:
			sum += *a;
03 07           add    eax,DWORD PTR [rdi]
			a++; ; 포인터 변수 값에 4를 더한다.
48 83 c7 04     add    rdi,0x4
		for (int i = 0; i < n; i++) {
48 39 d7        cmp    rdi,rdx
75 f5           jne    _loop



결론 : 일반적으로 “a[i]”를 사용하는 것보다 “*a” 를 사용하는 것이 속도면에서 좋다고 알려져 있으나, 최적화를 거치게 되면 코드의 결과가 비슷해 지는 것을 알 수 있다.

code download