2013-01-21 2 views
43

잠금없는 데이터 구조와 타이밍 코드를 구현할 때 컴파일러의 최적화를 억제해야 할 때가 있습니다. 일반적으로 사람들은 asm volatile을 사용하여 클로버 목록에 memory을 표시하지만 가끔씩 asm volatile 또는 평범한 asm 메모리 만 볼 수도 있습니다.asm, asm 휘발성 메모리 및 clobbering 메모리의 차이점

이 두 가지 진술은 코드 생성시 어떤 영향을 미칩니 까? (특히 GCC에서는 이식성이 떨어지기 때문에)? ..

asm (""); // presumably this has no effect on code generation 
asm volatile (""); 
asm ("" ::: "memory"); 
asm volatile ("" ::: "memory"); 
+0

사람이 너무 가까운 주변까지 덤비는 것 같다 metal :-) (그리고 어딘가에 @Mysticial은 엄청나게 상세한 답변을 타이프하고있다.) –

답변

39

"Extended Asm" page in the GCC documentation를 참조 생성합니다.

당신은 asm 후 키워드 volatile를 작성하여 삭제되는 것을 asm 명령을 방지 할 수 있습니다. [...] volatile 키워드는 지침에 중요한 부작용이 있음을 나타냅니다. GCC는 도달 할 수있는 경우 volatile asm을 삭제하지 않습니다. 모든 출력 피연산자없이

asm 명령은 휘발성 asm 지시와 동일하게 취급된다.귀하의 예

없음은 출력 피연산자를 지정하지 않았습니다, 그래서 asmasm volatile 형태가 동일하게 작동했다 : (이 도달 할 수없는 것으로 판명되지 않는 한)이 삭제되지 않을 수 있습니다 코드에 포인트를 만듭니다.

아무 것도하지 않는 것과 같지 않습니다. 코드 생성을 변경하는 더미 asm의 예는 this question을 참조하십시오.이 예에서 루프 1000 회 반복되는 코드는 루프의 16 회 반복을 한 번에 계산하는 코드로 벡터화됩니다. 루프 내부에 asm이 있으면 최적화가 불가능합니다 (asm에 1000 번 도달해야 함). 이 GCC는 보관하지하게됩니다

:

"memory" 소지품은 GCC는 어떤 메모리를 읽거나 asm 블록에 의해 기록 된 임의 수 있음을 가정, 그래서 그것을 통해로드 또는 저장을 재정렬에서 컴파일러를 방지 할 수 있습니다 어셈블러 명령어에서 레지스터에 캐시 된 메모리 값이며 해당 메모리에 대한 저장 또는로드를 최적화하지 않습니다.

(즉하지만, 다른 CPU에 대한로드 및 저장을 재정렬에서 CPU를 방지하지 않습니다. 당신이 그것에 대해 실제 메모리 장벽 지침이 필요)

+0

이것은 사실 매우 흥미 롭습니다. gcc가 출력없이 'asm'블록을 휘발성 메모리로 취급한다는 사실을 깨닫지 못해서 제 지식에 커다란 차이가있었습니다. – jleahy

+0

그래서 변수 (volatile 또는 asm)에서 사용되는 컨텍스트에 상관없이 'volatile'= 성능 저하가 발생합니다. 'goto' 키워드로 파일을 만드십시오 - 절대적으로 필요한 경우에만 사용하십시오. – etherice

8

asm ("") 아무것도하지 않는다 (또는 적어도, 아무것도 안 것

asm volatile ("") 않습니다 아무것도

asm ("" ::: "memory") :

그냥 참조를 위해 이러한 흥미로운 변화입니다 간단한 컴파일러 울타리입니다.

asm volatile ("" ::: "memory") AFAIK는 동일합니다. 이전과 같습니다. volatile 키워드는이 어셈블리 블록을 이동할 수 없다는 것을 컴파일러에 알립니다. 예를 들어, 컴파일러가 모든 호출에서 입력 값이 동일하다고 판단하면 루프에서 벗어날 수 있습니다. 나는 어떤 조건 하에서 컴파일러가 배치를 최적화하려고 어셈블리에 대해 충분히 이해한다고 결정할지는 모르겠지만 volatile 키워드는 완전히 억제합니다. 즉, 컴파일러가 입력 또는 출력이 선언되지 않은 asm 문을 이동하려고 시도하면 매우 놀랄 것입니다.

덧붙여 말하면 volatile은 출력 값이 사용되지 않는다고 결정하면 컴파일러가 식을 삭제하지 못하게합니다. 이것은 출력 값이있는 경우에만 발생할 수 있으므로 asm ("" ::: "memory")에는 적용되지 않습니다.

+6

Matthew Slattery의 대답은 'asm 휘발성 ("") "은 ​​아무 것도하지 않는 것과 같지 않다는 것을 지적한다. 컴파일러 최적화에 큰 영향을 미친다. asm 휘발성 (""::: "메모리")'를 컴파일러 펜스 (fence)로 사용하는 것과 동일한 성능 영향이 적용됩니다. – etherice

+0

컴파일러가 어셈블리 언어를 이해하지 못합니다! – curiousguy

+1

@curiousguy 아니요.하지만 'asm'블록이 입/출력을 선언했을 때 컴파일러에게 알려주는 레지스터와 의존 할 레지스터를 알려줍니다. 따라서 컴파일러는 특정 계산을 섞을 수 있습니다. 입력/출력에 영향을 미치지 않습니다. –

1

Visual Studio 2010은 Kevin Ballard의 답변을 완벽하게 마무리하기 위해 _ReadBarrier(), _WriteBarrier() 및 _ReadWriteBarrier()를 제공합니다 (VS2010에서는 64 비트 응용 프로그램의 인라인 어셈블리를 허용하지 않습니다).

이들은 명령어를 생성하지는 않지만 컴파일러의 동작에 영향을줍니다. 좋은 예는 here

메모리 배리어()가 lock or DWORD PTR [rsp], 0