컴파일러가 로컬 휘발성을 일정하게 접을 수 있습니까?


25

이 간단한 코드를 고려하십시오.

void g();

void foo()
{
    volatile bool x = false;
    if (x)
        g();
}

https://godbolt.org/z/I2kBY7

에 대한 잠재적 호출을 최적화 gcc하거나 clang최적화 하지는 않습니다 g. 이것은 내 이해에 맞습니다 : 추상 기계는 volatile변수가 언제든지 (하드웨어 매핑 등으로 인해) 변경 될 수 있다고 가정해야 하므로 false초기화에 if검사 를 지속적으로 접는 것은 잘못 될 것입니다.

그러나 MSVC는 g전체 호출을 제거합니다 (읽기와 쓰기를 유지함 volatile). 이 표준 준수 동작입니까?


배경 : 때때로 디버깅 출력을 즉시 켜고 끌 수 있도록 이러한 종류의 구성을 사용합니다. 컴파일러는 항상 메모리에서 값을 읽어야하므로 디버깅 중에 변수 / 메모리를 변경하면 그에 따라 제어 흐름이 수정되어야합니다 . MSVC 출력은 값을 다시 읽지 만 값을 무시합니다 (아마도 일정한 폴딩 및 / 또는 데드 코드 제거로 인해). 물론 내 의도를 상실합니다.


편집 :

  • 읽기와 쓰기의 제거는 volatile여기서 논의됩니다 : 컴파일러가 로컬 휘발성 변수를 최적화 할 수 있습니까? (나단 감사합니다!). 나는 읽고 쓰는 것이 반드시 일어나야 한다는 표준이 풍부하다고 생각합니다 . 그러나이 논의는 컴파일러가 읽기 결과 를 당연한 것으로 받아들이고이를 기반으로 최적화 하는 것이 합법적인지 여부는 다루지 않습니다 . 나는 이것이 표준에 미달 / 미지정 이라고 가정 하지만 누군가 나를 잘못 입증하면 기쁠 것입니다.

  • 물론 x문제를 회피하기 위해 로컬이 아닌 변수를 만들 수 있습니다 . 이 질문은 호기심에서 벗어납니다.


3
이것은 나에게 명백한 컴파일러 버그처럼 보입니다.
Sam Varshavchik

1
내가 아는 한 이것은 as 규칙에 따라 합법적입니다. 컴파일러는 객체가 일시적이지만 상태를 수정할 방법이 없어서 접을 수 있음을 증명할 수 있습니다. 나는 대답에 넣을만큼 확신하지 못하지만 그것이 옳다고 생각합니다.
NathanOliver

3
그러나 디버거가 변수를 수정할 수 있다는 OP의 주장은 합리적이라고 생각합니다. 누군가가 MSVC에 버그 보고서를 제출해야 할 수도 있습니다.
Brian

2
@curiousguy 결과를 버리거나 정확한 값을 가정하더라도 여전히 읽습니다.
중복 제거기

2
흥미롭게도 x64에서만 가능합니다. 는 x86 버전은 여전히 g ()를 호출 godbolt.org/z/nc3Y-f을
제리 예레미야에게

답변:


2

MSVC 동작을 설명하기 위해 [intro.execution] (단락 번호가 다름)을 사용할 수 있다고 생각합니다.

자동 저장 기간이있는 각 개체의 인스턴스는 해당 블록의 각 항목과 연결됩니다. 이러한 객체는 존재하며 블록을 실행하는 동안과 블록이 일시 중단 된 동안 마지막으로 저장된 값을 유지합니다 .

이 표준은 휘발성 glvalue를 통한 판독의 제거를 허용하지 않지만 위의 단락은 값을 예측할 수있는 것으로 해석 될 수 있습니다 false.


C 표준 (N1570 6.2.4 / 2) 인 BTW는

개체가 존재하고 주소가 일정하며 수명 기간 동안 마지막으로 저장된 값을 유지합니다. 34


34) 휘발성 개체의 경우 프로그램에서 마지막 저장소를 명시 적으로 지정할 필요는 없습니다.

C 메모리 / 객체 모델에서 자동 저장 시간을 가진 객체에 명시 적이 지 않은 저장소가있을 수 있는지 확실하지 않습니다.


컴파일러가 대상 플랫폼
MM

1
따라서 이것이 사실이라면 로컬 휘발성 객체는 (적어도 MSVC에서) 완전히 무의미합니까? volatile최적화 목적으로 무시되는 경우 추가하면 구매 (불필요한 읽기 / 쓰기 제외)가 있습니까?
Max Langhof

1
@MaxLanghof 완전히 무의미한 것과 당신이 원하거나 기대하는 효과가없는 것에는 차이가 있습니다.
중복 제거기

1
@MaxLanghof 부동 소수점 계산의 중간 결과는 때때로 정밀 문제를 일으키는 80 비트 레지스터로 승격됩니다. 나는 이것이 gcc-ism이라고 생각하며 휘발성과 같은 모든 이중을 선언함으로써 피할 수 있습니다. 참조 : gcc.gnu.org/bugzilla/show_bug.cgi?id=323
ForeverLearning

1
@philipxy PS 내 답변보기 액세스가 구현 정의되어 있음을 알고 있습니다. 문제는 액세스에 대한 것이 아니라 (객체가 액세스되는) 값의 예측입니다.
Language Lawyer

2

TL; DR 컴파일러는 각각의 휘발성 액세스에 대해 원하는 것을 수행 할 수 있습니다. 그러나이 문서는 사용자에게 알려야합니다. ""휘발성 glvalue를 통한 액세스의 의미론은 구현 정의되어 있습니다. "


이 표준은 구현이 " 'as-if'규칙"에 따라 존중해야하는 "휘발성 액세스"및 기타 "관찰 가능한 행동"( "부작용"을 통해 달성 됨) 시퀀스를 프로그램에 정의합니다.

그러나 표준은 (내 볼드체 강조)라고 말합니다.

초안 작성, 프로그래밍 언어 표준 C ++
문서 번호 : N4659
날짜 : 2017-03-21

§ 10.1.7.1 cv 한정자

5 휘발성 glvalue 통한 액세스의 시맨틱이 구현 정의된다. […]

대화 형 장치 (대담한 강조)와 마찬가지로 :

4.6 프로그램 실행

5 잘 구성된 프로그램을 실행하는 적합한 구현은 동일한 프로그램과 동일한 입력으로 추상 기계의 해당 인스턴스의 가능한 실행 중 하나와 동일한 관찰 가능한 동작을 생성해야합니다. [...]

7 적합한 구현에 대한 최소 요구 사항은 다음과 같습니다.

(7.1) — 휘발성 glvalue를 통한 액세스는 추상 머신의 규칙에 따라 엄격하게 평가됩니다.
(7.2) — 프로그램 종료시 파일에 기록 된 모든 데이터는 추상 의미론에 따라 프로그램을 실행했을 때 가능한 결과 중 하나와 동일해야합니다.
(7.3) — 대화식 장치의 입력 및 출력 역학은 프로그램이 입력을 대기하기 전에 실제로 출력을 프롬프트하는 방식으로 발생해야합니다. 대화 형 장치를 구성하는 것은 구현 정의입니다.

이를 총괄적으로 프로그램 의 관찰 가능한 동작 이라고합니다. [...]

(어쨌든 프로그램에 대해 생성되는 특정 코드는 표준에 의해 지정되지 않았습니다.)

따라서 표준에 따르면 휘발성 액세스는 추상 기계 부작용의 추상 시퀀스 및 결과적으로 일부 코드 (정의)가 정의 할 수있는 관찰 가능한 동작에서 벗어날 수는 없지만 객체 코드 또는 실제 세계에 아무것도 반영 될 수는 없습니다. 컴파일러 문서 에서 휘발성 액세스를 구성하는 내용을 알려주지 않는 한 동작 . 대화 형 장치를위한 Ditto

당신은 휘발성 마주 마주에 관심이 있다면 추상 기계 부작용 및 / 또는 결과의 관찰 행동의 추상적 인 시퀀스 일부 코드 (아마도)을 정의는 다음 이렇게 말한다 . 그러나 해당 객체 코드가 생성 되는 것에 관심이 있다면 컴파일러 및 컴파일 컨텍스트에서 해석해야합니다 .

일반적으로 사람들은 휘발성 액세스의 경우 추상 기계 평가 / 읽기가 구현 된 읽기를 발생시키고 추상 기계 할당 / 쓰기가 구현 된 쓰기를 유발한다고 잘못 생각합니다. 구현 문서가 없다는 믿음에 대한 근거는 없습니다. 구현이 실제로 "유연한 액세스"에 따라 무언가 를 수행한다고 말하면 사람들은 무언가 특정 객체 코드의 생성을 기대할 수 있습니다.


1
" 이것은 내가 언급 한 모든 부작용이 작동하지 않는 기계를 생각해 내면 모든 프로그램을 작동하지 않도록 컴파일하여 합법적 인 C ++ 구현을 갖습니다 . " 물론 우리는 추상 기계 부작용이 tautologically 추상적이기 때문에 실제로 관찰 가능한 효과에 관심이 있습니다. 여기에는 부작용에 대한 기본 개념이 필요하며, "휘발성 액세스는 명시 적 메모리 액세스 명령으로 이어집니다"가 표준의 일부가 아니기 때문에 그 이유 중 하나라고 생각합니다. 추상적 의미론 대신 코드를 원한다면 " 여전히 +1입니다.
Max Langhof

예, 구현 품질이 관련이 있습니다. 그럼에도 불구하고 파일에 쓰는 것 외에 "관찰 가능"[sic]은 구현에 따라 정의됩니다. 중단 점을 설정하고 특정 실제 메모리에 액세스하고 추상 휘발성 읽기 및 쓰기에서 '휘발성'을 무시한 경우 컴파일러 작성자가 적절한 코드를 출력하도록해야합니다 . PS C ++에서 "부작용"은 그 자체로 observabke 동작에 사용되지 않으며, 하위 표현식의 부분 순서 평가를 설명하는 데 사용됩니다.
philipxy

[sic]을 설명해 주시겠습니까? 어떤 출처를 인용하고 있으며 실수는 무엇입니까?
Max Langhof

Resic 나는 단지 구현이 말하는 것처럼 추상 기계 관찰 가능은 실제 관찰 가능하다는 것을 의미합니다.
philipxy

1
구현에서 대화 형 장치와 같은 것은 없다고 주장 할 수 있으므로 모든 프로그램이 무엇이든 할 수 있으며 여전히 올바른 것입니까? (참고 : 대화 형 장치에 대한 귀하의 강조는 이해가되지 않습니다.)
curiousguy

-1

수표를 건너 뛰는 것이 합법적이라고 생각합니다.

모두가 인용하는 단락

34) 휘발성 개체의 경우 프로그램에서 마지막 저장소를 명시 적으로 지정할 필요가 없습니다.

구현시 이러한 스토어가 언제든 또는 모든 휘발성 변수에 대해 가능하다고 가정해야 함을 의미하지는 않습니다. 구현은 가능한 상점을 알고 있습니다. 예를 들어, 이러한 암시 적 쓰기는 디바이스 레지스터에 매핑 된 휘발성 변수에 대해서만 발생하고 이러한 매핑은 외부 연결이있는 변수에만 가능하다고 가정하는 것이 전적으로 합리적입니다. 또는 구현은 그러한 쓰기가 워드 크기, 워드 정렬 메모리 위치에만 영향을 미친다고 가정 할 수있다.

MSVC의 행동은 버그라고 생각합니다. 통화를 최적화 할 실제적인 이유는 없습니다. 이러한 최적화는 준수 할 수 있지만 불필요하게 악합니다.


왜 악한 지 설명 할 수 있습니까? 코드 쇼에서 함수는 문자 그대로 호출 될 수 없습니다.
David Schwartz

@DavidSchwartz 로컬 휘발성 변수의 의미를 지정한 후에 만 ​​위의 인용 된 단락을 참조하십시오. 자체 표준 노트 volatile예정되어 값이 구현 수단의 알 수없는에 의해 변경할 수있는에 대한 힌트가 될 수 있습니다.
Max Langhof

@MaxLanghof 구현이 알 수없는 것을 올바르게 처리 할 수있는 방법은 없습니다. 실제로 유용한 플랫폼은 volatile플랫폼 및 해당 사양 이외의 플랫폼에서 사용할 수 있고 사용할 수없는 것을 지정하는 것 입니다.
David Schwartz

@DavidSchwartz 물론 그것은 추상 기계의 의미론 (특히, 읽기 및 쓰기)을 따름으로써 가능합니다. 올바르게 최적화하지 못할 수도 있습니다. 이것이 표준의 핵심입니다. 이제는 참고 사항이므로 규범 적이 지 않으며, 우리가 말했듯이 구현은 그에 따르는 것을 지정할 수 있습니다 volatile. 내 요점은 코드 자체 (C ++ 표준 / 추상 기계에 따라) g를 통해 호출 할 수 있는지 여부를 결정할 수 없다는 것입니다.
Max Langhof

@DavidSchwartz 암시적인 쓰기가 없으면 코드에서 나오지 않기 때문에 코드에는 이와 같은 내용이 표시되지 않습니다.
n. '대명사'm.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.