Why should I know this?

LLVM] phi 간략 살펴보기 본문

LLVM-STUDY

LLVM] phi 간략 살펴보기

die4taoam 2022. 9. 17. 14:17

 

LLVM IR 중에 PHI 라는 것이 종종 보인다.

PREDS와 PHI 는 처음 LLVM 을 접하게 된다면 생소한 개념이라 약간 헤깔린다.
phi 관련 내용은 wiki 에 자세히 나와있으니 참고하시고

(https://en.wikipedia.org/wiki/Static_single-assignment_form)

 

몇 가지 핵심만 요약정리 해보자.

 

1. 일단 이름부터

왜 phi 인가하면 기호가 진짜 phi 이다 = called a Φ (Phi) function

 

2. phi 의 정의

preds가 명목상 모든 연관 노드라고 하면, phi 는 특별하게 연관된 노드이다.

구체적으로 이전 노드에 의존적인 관계에 있는 노드이다.

  %retval = phi i32 [%a, %btrue], [%b, %bfalse]

위의 phi 예에서 %btrue 에서 온 경우 %a가 %bfalse 에서 온 경우 %b의 값이 %retval에 대입된다.

 

 

 

3. phi 는 왜 필요한가?
(참조 : https://mapping-high-level-constructs-to-llvm-ir.readthedocs.io/en/latest/control-structures/ssa-phi.html)

다음 코드를 통해 phi 가 어떻게 활용되는지 확인해보자.

 

int max(int a, int b) {
  if (a > b) {
    return a;
  } else {
    return b;
  }
}

int max_phi(int a, int b) {
  return (a > b) ? a : b;
}

번역된 IR 코드를 보면 btrue, bfalse 분기에서 true 때는 a가 false 때는 b가 각각 retval에 대입되지만

retval는 end: block에서 다시 한번 로드된 후 리턴된다. 이것은 SSA의 특징 때문이다.

 

이럴 때 phi를 사용하면 최적화가 가능하다.

define i32 @max(i32 %a, i32 %b) {
entry:
  %0 = icmp sgt i32 %a, %b
  br i1 %0, label %btrue, label %bfalse

btrue:                                      ; preds = %2
  br label %end

bfalse:                                     ; preds = %2
  br label %end

end:                                     ; preds = %btrue, %bfalse
  %retval = phi i32 [%a, %btrue], [%b, %bfalse]
  ret i32 %retval
}

 

예에서 다뤘듯, 다음 구문에서 %btrue에서 온 경우 %a가, %bfalse에서 온 경우 %b가 %retval에 대입된다.

  %retval = phi i32 [%a, %btrue], [%b, %bfalse]

 

 

4. phi 코드가 기계어로 번역된다면

-O[1~3]의 경우

max:                                    # @max
# %bb.0:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    %edi, -8(%rbp)
        movl    %esi, -4(%rbp)
        movl    -8(%rbp), %eax
        cmpl    -4(%rbp), %eax
        jle     .LBB0_2
# %bb.1:
        movl    -8(%rbp), %eax
        movl    %eax, -12(%rbp)
        jmp     .LBB0_3
.LBB0_2:
        movl    -4(%rbp), %eax
        movl    %eax, -12(%rbp)
.LBB0_3:
        movl    -12(%rbp), %eax
        popq    %rbp
        retq
max_phi:                                # @max_phi
# %bb.0:
        pushq   %rbp
        movq    %rsp, %rbp
        movl    %edi, -8(%rbp)
        movl    %esi, -4(%rbp)
        movl    -8(%rbp), %eax
        cmpl    -4(%rbp), %eax
        jle     .LBB1_2
# %bb.1:
        movl    -8(%rbp), %eax
        jmp     .LBB1_3
.LBB1_2:
        movl    -4(%rbp), %eax
.LBB1_3:
        popq    %rbp
        retq

최적화 옵션을 줬을 때 생성되는 기계어에서 차이를 볼 수있다.

 

구체적으로
1. 값을 로드 후 저장하고
2. 마지막에 저장된 값을 꺼내 리턴하는 

두 부분이 사라지고 

%eax 레지스터에 값을 세팅한 채로 리턴하는 것을 볼 수 있다.

 

이것이 PHI 구문의 효용이다.

 

'LLVM-STUDY' 카테고리의 다른 글

LoopLatch  (0) 2023.02.26
LLVM Optimization study - LoopFlatten  (0) 2023.02.23
LLVM 기반 TOOL을 제작할 때 라이브러리 링킹하는 법  (0) 2022.09.27
LLVM compile option  (0) 2022.03.21
LLVM tutor] implements CFI  (0) 2021.04.12
Comments