LLVM에는 매우 이상한 설명 이 포함 된 파이 명령어가 있습니다.
‘phi’명령어는 함수를 나타내는 SSA 그래프에서 φ 노드를 구현하는 데 사용됩니다.
일반적으로 분기를 구현하는 데 사용됩니다. 올바르게 이해했다면 종속성 분석을 가능하게해야하며 경우에 따라 불필요한로드를 피하는 데 도움이 될 수 있습니다. 그러나 정확히 무엇을하는지 이해하기는 여전히 어렵습니다.
Kaleidoscope 예제 는 사례에 대해 꽤 잘 설명합니다 if
. 그러나 같은 논리 연산을 구현하는 방법이 명확하지 않다 &&
와 ||
. 온라인 llvm 컴파일러에 다음을 입력하면 :
void main1(bool r, bool y) {
bool l = y || r;
}
마지막 몇 줄은 완전히 혼란 스럽습니다.
; <label>:10 ; preds = %7, %0
%11 = phi i1 [ true, %0 ], [ %9, %7 ]
%12 = zext i1 %11 to i8
파이 노드가 사용할 수있는 결과를 생성하는 것처럼 보입니다. 그리고 나는 파이 노드가 값이 오는 경로를 정의한다는 인상을 받았습니다.
누군가 Phi 노드가 무엇이며 어떻게 구현하는지 설명 할 ||
수 있습니까?
답변
파이 노드는 현재 블록의 전임자에 따라 값을 선택하는 데 사용되는 명령어입니다 ( 전체 계층 구조를 보려면 여기 를 참조하십시오. 상속되는 클래스 중 하나 인 값으로도 사용됨).
LLVM 코드의 SSA (정적 단일 할당) 스타일의 구조로 인해 Phi 노드가 필요합니다 (예 : 다음 C ++ 함수).
void m(bool r, bool y){
bool l = y || r ;
}
다음 IR로 변환됩니다. (만들어진 clang -c -emit-llvm file.c -o out.bc
후를 통해 봅니다 llvm-dis
)
define void @_Z1mbb(i1 zeroext %r, i1 zeroext %y) nounwind {
entry:
%r.addr = alloca i8, align 1
%y.addr = alloca i8, align 1
%l = alloca i8, align 1
%frombool = zext i1 %r to i8
store i8 %frombool, i8* %r.addr, align 1
%frombool1 = zext i1 %y to i8
store i8 %frombool1, i8* %y.addr, align 1
%0 = load i8* %y.addr, align 1
%tobool = trunc i8 %0 to i1
br i1 %tobool, label %lor.end, label %lor.rhs
lor.rhs: ; preds = %entry
%1 = load i8* %r.addr, align 1
%tobool2 = trunc i8 %1 to i1
br label %lor.end
lor.end: ; preds = %lor.rhs, %entry
%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]
%frombool3 = zext i1 %2 to i8
store i8 %frombool3, i8* %l, align 1
ret void
}
그래서 여기서 무슨 일이 일어나나요? 변수 bool l
가 0 또는 1 일 수 있는 C ++ 코드와 달리 LLVM IR에서는 한 번 정의해야합니다 . 그래서 우리 %tobool
는 참 인지 확인한 다음 lor.end
또는로 이동 lor.rhs
합니다.
에서 lor.end
우리는 마지막의 값이 || 운영자. 진입 블록에서 도착했다면 그것은 사실입니다. 그렇지 않으면 %tobool2
– 의 값과 같 으며 다음 IR 라인에서 얻은 결과입니다.
%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]
답변
파이를 전혀 사용할 필요가 없습니다. 임시 변수를 많이 만드십시오. LLVM 최적화 패스는 임시 변수 최적화를 처리하고 자동으로 phi 노드를 사용합니다.
예를 들어 이렇게하려면 다음을 수행하십시오.
x = 4;
if (something) x = x + 2;
print(x);
이를 위해 (의사 코드에서) phi 노드를 사용할 수 있습니다.
- x1에 4를 할당
- if (! something) 분기가 4
- 2를 더하여 x1에서 x2 계산
- x1 및 x2에서 x3 파이 할당
- x3로 전화 인쇄
그러나 phi 노드없이 (의사 코드에서) 할 수 있습니다.
- x라는 스택에 지역 변수 할당
- 임시 x1 값 4에로드
- x1을 x에 저장
- if (! something) 분기가 8
- x를 임시 x2에로드
- 임시 x3에 4와 x2 추가
- x3을 x에 저장
- x를 임시 x4에로드
- x4로 전화 인쇄
llvm으로 최적화 패스를 실행하면이 두 번째 코드가 첫 번째 코드에 최적화됩니다.