IT

C ++에서 제한 키워드는 무엇을 의미합니까?

lottoking 2020. 5. 20. 08:12
반응형

C ++에서 제한 키워드는 무엇을 의미합니까?


나는 항상 확실하지 않았다. C ++에서 restrict 키워드는 무엇을 의미 하는가?

함수에 주어진 둘 이상의 포인터가 겹치지 않는다는 것을 의미합니까? 그게 무슨 뜻입니까?


Christer Ericson은 자신의 논문 인 Memory Optimization 에서 restrict아직 C ++ 표준의 일부는 아니지만 많은 컴파일러에서 지원하고 있으며 가능한 경우 사용을 권장한다고 말합니다.

키워드 제한

! 1999 ANSI / ISO C 표준에 새로 추가

! C ++ 표준은 아니지만 많은 C ++ 컴파일러에서 지원

! 힌트 만이므로 아무 것도 할 수 없으며 여전히 준수하고 있습니다.

제한 규정 포인터 (또는 참조) ...

! ... 기본적으로 컴파일러는 포인터의 범위에 대해 포인터의 대상이 해당 포인터를 통해 액세스 할 수 있습니다 (포인터에서 복사 된 포인터).

이를 지원하는 C ++ 컴파일러에서는 아마도 C에서와 동일하게 작동해야합니다.

자세한 내용은이 SO 게시물을 참조하십시오 : C99 '제한'키워드의 현실적인 사용법?

에릭슨의 논문을 훑어 보려면 30 분이 걸립니다. 재미 있고 가치가 있습니다.

편집하다

또한 IBM의 AIX C / C ++ 컴파일러가 __restrict__keyword 키워드를 지원 한다는 것을 알았습니다 .

g ++은 다음 프로그램이 g ++에서 깔끔하게 컴파일되므로 이것을 지원하는 것 같습니다.

#include <stdio.h>

int foo(int * __restrict__ a, int * __restrict__ b) {
    return *a + *b;
}

int main(void) {
    int a = 1, b = 1, c;

    c = foo(&a, &b);

    printf("c == %d\n", c);

    return 0;
}

나는 또한 사용에 관한 좋은 기사를 발견했다 restrict.

제한 키워드 이해하기

편집 2

C ++ 프로그램에서 제한 사용에 대해 구체적으로 설명하는 기사를 살펴 보았습니다.

적중 상점 및 __restrict 키워드

또한 Microsoft Visual C ++ __restrict키워드를 지원합니다 .


다른 사람들이 말했듯이, C ++ 14의 의미가 없다면__restrict__ C99와 동일한 GCC 확장을 고려하십시오 restrict.

C99

restrict두 포인터가 겹치는 메모리 영역을 가리킬 수 없다고 말합니다. 가장 일반적인 사용법은 함수 인수입니다.

이것은 함수 호출 방법을 제한하지만 더 많은 컴파일 최적화를 허용합니다.

발신자가 restrict계약을 따르지 않으면 정의되지 않은 동작입니다.

C99 N1256 초안 6.7.3 / 7 "형식 한정자"말한다 :

제한 규정 자 (레지스터 저장 클래스와 같은)의 의도 된 사용은 최적화를 촉진하는 것이며, 규정을 준수하는 프로그램을 구성하는 모든 사전 처리 변환 단위에서 규정 자의 모든 인스턴스를 삭제해도 의미가 변경되지 않습니다 (즉, 관찰 가능한 동작).

그리고 6.7.3.1 "제한의 공식적 정의"는 세부 사항을 제공한다.

가능한 최적화

위키 백과의 예 입니다 매우 조명.

하나의 조립 명령을 저장할 수있는 방법을 명확하게 보여줍니다 .

제한없이 :

void f(int *a, int *b, int *x) {
  *a += *x;
  *b += *x;
}

의사 어셈블리 :

load R1 ← *x    ; Load the value of x pointer
load R2 ← *a    ; Load the value of a pointer
add R2 += R1    ; Perform Addition
set R2 → *a     ; Update the value of a pointer
; Similarly for b, note that x is loaded twice,
; because a may be equal to x.
load R1 ← *x
load R2 ← *b
add R2 += R1
set R2 → *b

제한으로 :

void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x);

의사 어셈블리 :

load R1 ← *x
load R2 ← *a
add R2 += R1
set R2 → *a
; Note that x is not reloaded,
; because the compiler knows it is unchanged
; load R1 ← *x
load R2 ← *b
add R2 += R1
set R2 → *b

GCC가 실제로합니까?

g++ 4.8 리눅스 x86-64 :

g++ -g -std=gnu++98 -O0 -c main.cpp
objdump -S main.o

로도 -O0동일합니다.

-O3:

void f(int *a, int *b, int *x) {
    *a += *x;
   0:   8b 02                   mov    (%rdx),%eax
   2:   01 07                   add    %eax,(%rdi)
    *b += *x;
   4:   8b 02                   mov    (%rdx),%eax
   6:   01 06                   add    %eax,(%rsi)  

void fr(int *__restrict__ a, int *__restrict__ b, int *__restrict__ x) {
    *a += *x;
  10:   8b 02                   mov    (%rdx),%eax
  12:   01 07                   add    %eax,(%rdi)
    *b += *x;
  14:   01 06                   add    %eax,(%rsi) 

시작하지 않은 경우 호출 규칙 은 다음과 같습니다.

  • rdi = 첫 번째 매개 변수
  • rsi = 두 번째 매개 변수
  • rdx = 세번째 매개 변수

GCC 출력은 Wiki 기사보다 훨씬 명확했습니다. 4 가지 명령어와 3 개의 명령어.

배열

So far we have single instruction savings, but if pointer represent arrays to be looped over, a common use case, then a bunch of instructions could be saved, as mentioned by supercat and michael.

Consider for example:

void f(char *restrict p1, char *restrict p2, size_t size) {
     for (size_t i = 0; i < size; i++) {
         p1[i] = 4;
         p2[i] = 9;
     }
 }

Because of restrict, a smart compiler (or human), could optimize that to:

memset(p1, 4, size);
memset(p2, 9, size);

Which is potentially much more efficient as it may be assembly optimized on a decent libc implementation (like glibc) Is it better to use std::memcpy() or std::copy() in terms to performance?, possibly with SIMD instructions.

Without, restrict, this optimization could not be done, e.g. consider:

char p1[4];
char *p2 = &p1[1];
f(p1, p2, 3);

Then for version makes:

p1 == {4, 4, 4, 9}

while the memset version makes:

p1 == {4, 9, 9, 9}

Does GCC really do it?

GCC 5.2.1.Linux x86-64 Ubuntu 15.10:

gcc -g -std=c99 -O0 -c main.c
objdump -dr main.o

With -O0, both are the same.

With -O3:

  • with restrict:

    3f0:   48 85 d2                test   %rdx,%rdx
    3f3:   74 33                   je     428 <fr+0x38>
    3f5:   55                      push   %rbp
    3f6:   53                      push   %rbx
    3f7:   48 89 f5                mov    %rsi,%rbp
    3fa:   be 04 00 00 00          mov    $0x4,%esi
    3ff:   48 89 d3                mov    %rdx,%rbx
    402:   48 83 ec 08             sub    $0x8,%rsp
    406:   e8 00 00 00 00          callq  40b <fr+0x1b>
                            407: R_X86_64_PC32      memset-0x4
    40b:   48 83 c4 08             add    $0x8,%rsp
    40f:   48 89 da                mov    %rbx,%rdx
    412:   48 89 ef                mov    %rbp,%rdi
    415:   5b                      pop    %rbx
    416:   5d                      pop    %rbp
    417:   be 09 00 00 00          mov    $0x9,%esi
    41c:   e9 00 00 00 00          jmpq   421 <fr+0x31>
                            41d: R_X86_64_PC32      memset-0x4
    421:   0f 1f 80 00 00 00 00    nopl   0x0(%rax)
    428:   f3 c3                   repz retq
    

    Two memset calls as expected.

  • without restrict: no stdlib calls, just a 16 iteration wide loop unrolling which I do not intend to reproduce here :-)

I haven't had the patience to benchmark them, but I believe that the restrict version will be faster.

Strict aliasing rule

The restrict keyword only affects pointers of compatible types (e.g. two int*) because the strict aliasing rules says that aliasing incompatible types is undefined behavior by default, and so compilers can assume it does not happen and optimize away.

See: What is the strict aliasing rule?

Does it work for references?

According to the GCC docs it does: https://gcc.gnu.org/onlinedocs/gcc-5.1.0/gcc/Restricted-Pointers.html with syntax:

int &__restrict__ rref

There is even a version for this of member functions:

void T::fn () __restrict__

Nothing. It was added to the C99 standard.


This is the original proposal to add this keyword. As dirkgently pointed out though, this is a C99 feature; it has nothing to do with C++.


There's no such keyword in C++. List of C++ keywords can be found in section 2.11/1 of C++ language standard. restrict is a keyword in C99 version of C language and not in C++.


Since header files from some C libraries use the keyword, the C++ language will have to do something about it.. at the minimum, ignoring the keyword, so we don't have to #define the keyword to a blank macro to suppress the keyword.

참고URL : https://stackoverflow.com/questions/776283/what-does-the-restrict-keyword-mean-in-c

반응형