Skip to content

Restricting Pointer Aliasing

제한된 (Restricting) 포인터 에일리어스 (Pointer Alias) 관한 내용.

Pointer Aliasing

포인터 에일리어스(Pointer Alias)는 두 개 이상의 포인터 변수가 같은 메모리 위치를 담고 있을 때 그 포인터들을 에일리어스(alias)라고 부른다.

컴파일러 입장에선 모든 포인터 변수가 서로의 에일리어스 일 수도 있다 생각하는 것이 안전하다.

// 포인터 에일리어스 발생 가능성이 높은 코드:
void any_func( int* a, int* b )
{
  *b = *b + *a;
  *a = *a + 2;
}

포인터 a, b가 에일리어스 상태가 아니라면 a의 값은 한 번만 로딩되면 된다. 에일리어스일 경우에는 포인터 b가 지칭하는 값에 대한 수정이 a가 지칭하는 값에 대한 수정일 수 있으므로 a의 값이 두 번 로딩되어야 한다.

// 포인터 에일리어싱이 가능한 코드:
void func( int* a, int* b )
{
  (*a)++;
  (*b)++;
}

위 코드가 컴파일 되면 아래와 같이 된다.

; 포인터 에일리어스가 가능한 상태에서 컴파일된 코드
ld [$o0], %o5 ! Load *a
add %o5, %o5 ! Increment
st %05, [%o0] ! Store *a // 첫 번째 변수 저장
ld [%01], %o4 ! Load *b // 두 번째 변수 읽어들임
add $o4, 1, $o3 ! Increment
st %o3, [%o1] ! Store *b

포인터 에일리어싱 때문에 포인터 변수 b가 가리키는 주소에서 값을 읽기(load) 전에 포인터 변수 a가 가리키는 주소에 값을 써야한다(store). 다음은 포인터 에일리어싱이 없는 경우이다.

// 포인터 에일리어싱 문제가 없는 코드
void func( int* a )
{
  a[0]++;
  a[1]++;
}

위 코드가 컴파일 되면 이와 같이 된다.

;포인터 에일리어싱 없이 컴파일된 코드
ld [%o0], %o5 ! Load a[0]
ld [%o0+4], %o4 !Load a[1] // 두 번째 변수를 load
add %o5, 1, %o5 ! Increment 
st %o5, [%o0] ! Store a[0] // 첫 번째 변수 저장
add %o4, 1, %o3 ! Increment
st %o3, [%o1] ! Store a[1]

두 메모리 작업에 에일리어싱이 없다는 사실을 컴파일러가 알 수 있으므로, 명령어 순서를 바꿔 메모리 읽기를 앞으로 당겨 메모리 접근 지연의 영향을 줄일 수 있다.

restrict 키워드

restrict 키워드는 출력값으로 쓰이는 포인터(destination!)는 인자로 같은 요소를 가리키지 않을 것이란걸 컴파일러에게 알려주는 것으로,

컴파일러는 이 통지를 믿고 최적화 과정을 수행하게 된다. 이 키워드는 C에서는 표준이지만 C++에선 표준이 아니다.

Restricted Pointers

As with the C front end, G++ understands the C99 feature of restricted pointers, specified with the __restrict__, or __restrict type qualifier. Because you cannot compile C++ by specifying the -std=c99 language flag, restrict is not a keyword in C++.

In addition to allowing restricted pointers, you can specify restricted references, which indicate that the reference is not aliased in the local context.

void fn (int *__restrict__ rptr, int &__restrict__ rref)
{
  /* … */
}

In the body of fn, rptr points to an unaliased integer and rref refers to a (different) unaliased integer.

You may also specify whether a member function’s this pointer is unaliased by using __restrict__ as a member function qualifier.

void T::fn () __restrict__
{
  /* … */
}

Within the body of T::fn, this has the effective definition T *__restrict__ const this. Notice that the interpretation of a __restrict__ member function qualifier is different to that of const or volatile qualifier, in that it is applied to the pointer rather than the object. This is consistent with other compilers that implement restricted pointers.

As with all outermost parameter qualifiers, __restrict__ is ignored in function definition matching. This means you only need to specify __restrict__ in a function definition, rather than in a function prototype as well.

See also

Favorite site