4

내가 좋아하는 예를 들어 기능이있는 경우 : 인라인 함수를 호출C++ 컴파일러가 할당 중복을 제거합니까?

void func1(float a, float b, float c) 
{ 
    setA(a); 
    setB(b); 
    setC(c);           
} 

다음 "m_isValid = false"를 중복 또는 컴파일러에 대한

inline void setA(float a){ m_a = a; m_isValid = false; } 
inline void setB(float b){ m_b = b; m_isValid = false; } 
inline void setC(float c){ m_c = c; m_isValid = false; } 

내가 관심을 가져야는 최적화하여 그들을 제거?

+1

나는 그것을 매우 의심한다. 어쨌든 작업에 소요되는 시간은 최소화되어 있습니다. "최적화"대신에 그대로 두는 것이 좋습니다. (조기 최적화는 모든 악의 근원입니다.) – SJuan76

+0

인라인으로도 코드가 순차적으로 보이지만 , 값은 여전히 ​​다른 스레드에 의해 동시에 수정되어 이러한 최적화를 상당히 나쁜 것으로 만들 수 있습니다. – SirDarius

+0

반대로, 컴파일러는 그 할당을 여러 번 반복 할 것입니다. 이와 같은 함수는 일반적으로 두 개의 CPU 명령어 만 필요하기 때문에 거의 항상 인라인됩니다. 그건 중요하지 않아 코드가 더 빨라졌습니다 *. –

답변

6

괜찮은 컴파일러는이 특별한 경우이를 제거해야합니다. 전체 컴파일 예에 완료

struct Foo { 
    float m_a, m_b, m_c; 
    bool m_isValid; 

    void setA(float a){ m_a = a; m_isValid = false; } 
    void setB(float b){ m_b = b; m_isValid = false; } 
    void setC(float c){ m_c = c; m_isValid = false; } 

    void func1(float a, float b, float c); 
}; 

Foo f; 

void func1(float a, float b, float c) 
{ 
    f.setA(a); 
    f.setB(b); 
    f.setC(c); 
} 

그램 ++이 경우 컴파일에 func1는 사실 동안 프로그램의 경우를 설계하는 방법에 대한 눈을 밖으로 유지해야한다는 것을

_Z5func1fff: 
.LFB3: 
    .cfi_startproc 
    movl 4(%esp), %eax  ;; loads a 
    movb $0, f+12   ;; clears m_isValid 
    movl %eax, f   ;; stores m_a 
    movl 8(%esp), %eax  ;; loads b 
    movl %eax, f+4   ;; stores m_b 
    movl 12(%esp), %eax ;; loads c 
    movl %eax, f+8   ;; stores m_c 
    ret 
    .cfi_endproc 

참고 성능이 문제가되는 경우, 이러한 종류의 마이크로 레벨 최적화는 코드가 실제로 시간을 잃는 위치를 측정 한 후 끝까지 완료하는 것이 가장 좋습니다.

+0

Visual Studio 2012 Ultimate에서이 작업을 수행하는 방법에 대한 아이디어가 있습니까? 해체 창에 액세스 할 수 없습니다. – plasmacel

+0

이 최적화는 인라인되는'set [ABC]'에 의존하지만, 차례로 정의가 동일한 TU에 있거나 LTO가 사용되어야합니다. – delnan

+0

TU와 LTO는 무엇을 의미합니까? – plasmacel

8

예, 일반적으로 Dead Store Elimination (읽기 =로드 및 쓰기 = 컴파일러 용어로 저장)이라고합니다.

일반적으로 쓸모없는 작업은 컴파일러가 최적화하여 사용자 (사용자)가 언어로 설정된 경계 내에서이를 알아 채지 못함을 증명할 수 있습니다.

이 일반적으로 제한됩니다 특히 죽은 스토어 제거를위한

:

  • 하나의 함수의 몸은 불투명 함수 호출을 개입하지 않고
  • (단, 인라인은 여기에 있습니다)

몇 가지 예 :

struct Foo { int a; int b; }; 

void opaque(Foo& x); // opaque, aka unknown definition 

Foo foo() { 
    Foo x{1, 2}; 
    x.a = 3; 
    return x; // provably returns {3, 2} 
       // thus equivalent to Foo foo() { return {3, 2}; } 
} 

Foo bar() { 
    Foo x{1, 2}; 
    opaque(x); // may use x.a, so need to leave it at '1' for now 
    x.a = 3; 
    return x; 
} 

Foo baz() { 
    Foo x{1, 2}; 
    opaque(x); 
    x.a = 1; // x.a may have been changed, cannot be optimized 
    return x; 
} 

컴파일러가 변수가 두 저장소 작업 사이에서 읽히지 않는다는 것을 증명할 수있는 한 동일한 값을 연속적으로 저장하거나 중요하지 않습니다. 따라서 첫 번째 안전하게 제거 할 수 있습니다.

특별한 경우 : C++의 사양에 따라 volatile에 대한로드/저장을 최적화 할 수 없습니다. 이는 하드웨어와의 상호 작용을 허용하기 위해 volatile이 지정 되었기 때문에 컴파일러는 하드웨어가 프로그램의 배후 변수를 읽거나 쓸지 여부를 선험적으로 알 수 없기 때문입니다.

또 다른 특별한 경우 : 최적화 목적으로 멀티 스레드 프로그램에서 사용되는 메모리 동기화 작업 (펜스, 장벽 등)은 이러한 종류의 최적화를 막을 수 있습니다. volatile의 경우와 매우 비슷하기 때문에 동기화는 다른 스레드가이 스레드 뒤에서 변수를 수정했을 수 있음을 의미합니다.

마지막으로 모든 최적화와 마찬가지로 효율성은 문맥 지식에 크게 달려 있습니다.opaque이 읽지 않거나 x.a에 쓰지 않는다고 증명되면 컴파일러가 opaque의 정의를 검사 할 수있는 경우 입증 할 수있는 저장소가 있으므로 일부 저장소는 일반적으로 인라인 및 상수 전파에 의존합니다.

+0

+1 적어도 불투명 한 답변 :-) – TemplateRex

0

대부분의 최신 컴파일러 (최적화 옵션이 활성화되어 있어야 함)로 작성해야합니다.

관련 문제