คำสั่ง PHI ทำอะไรได้บ้างและจะใช้อย่างไรใน LLVM


91

LLVM มีคำสั่งphiพร้อมคำอธิบายที่ค่อนข้างแปลก:

คำสั่ง '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 node จะสร้างผลลัพธ์ที่สามารถใช้ได้ และฉันรู้สึกประทับใจที่ phi node เพียงแค่กำหนดค่าของเส้นทางที่จะมา

มีใครสามารถอธิบายได้ว่าโหนด Phi คืออะไรและจะนำไปใช้||อย่างไร


1
phiโหนดเป็นวิธีการแก้ปัญหาในคอมไพเลอร์ที่จะแปลง IR ลง "คงที่ได้รับมอบหมายเดียว" แบบฟอร์ม เพื่อให้เข้าใจวิธีแก้ปัญหาได้ดีขึ้นฉันขอแนะนำให้เข้าใจปัญหาให้ดีขึ้น ดังนั้นฉันจะเรียกคุณว่า " โหนทำไมphi "
Vraj Pandya

คำตอบ:


77

phi node คือคำสั่งที่ใช้ในการเลือกค่าโดยขึ้นอยู่กับรุ่นก่อนของบล็อกปัจจุบัน (ดูที่นี่เพื่อดูลำดับชั้นแบบเต็ม - ยังใช้เป็นค่าซึ่งเป็นหนึ่งในคลาสที่สืบทอดมา)

โหนด Phi มีความจำเป็นเนื่องจากโครงสร้างของรูปแบบ SSA (การกำหนดเดี่ยวแบบคงที่) ของรหัส LLVM - ตัวอย่างเช่นฟังก์ชัน 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
}

แล้วเกิดอะไรขึ้นที่นี่? ซึ่งแตกต่างจากรหัส C ++ ที่ตัวแปรbool lอาจเป็น 0 หรือ 1 ใน LLVM IR ก็จะต้องมีการกำหนดครั้งเดียว ดังนั้นเราจึงตรวจสอบว่า%toboolเป็นความจริงแล้วข้ามไปหรือlor.endlor.rhs

ในlor.endที่สุดเราก็มีค่าของ || ตัวดำเนินการ ถ้าเรามาจากบล็อกทางเข้า - มันก็จริง มิฉะนั้นจะเท่ากับค่าของ%tobool2- และนั่นคือสิ่งที่เราได้รับจากบรรทัด IR ต่อไปนี้:

%2 = phi i1 [ true, %entry ], [ %tobool2, %lor.rhs ]

6
TL; DR φ node คือนิพจน์ด้านท้าย อาจมีคนโต้แย้งว่าไม่มีเงื่อนไข แต่จริงๆแล้วเมื่อแปลงเป็นรหัสสุดท้ายคุณไม่สามารถระบุได้ว่าอาร์กิวเมนต์ใดใช้งานได้จริงดังนั้นจึงต้องมีเงื่อนไขด้วย
Hi-Angel

31

คุณไม่จำเป็นต้องใช้ phi เลย เพียงสร้างตัวแปรชั่วคราวจำนวนมาก LLVM optimization pass จะดูแลการเพิ่มประสิทธิภาพตัวแปรชั่วคราวและจะใช้ phi node สำหรับสิ่งนั้นโดยอัตโนมัติ

ตัวอย่างเช่นหากคุณต้องการทำสิ่งนี้:

x = 4;
if (something) x = x + 2;
print(x);

คุณสามารถใช้ phi node สำหรับสิ่งนั้น (ใน pseudocode):

  1. กำหนด 4 ถึง x1
  2. ถ้า (! something) แยกเป็น 4
  3. คำนวณ x2 จาก x1 โดยการเพิ่ม 2
  4. กำหนด x3 phi จาก x1 และ x2
  5. โทรพิมพ์ด้วย x3

แต่คุณสามารถทำได้โดยไม่ต้อง phi node (ใน pseudocode):

  1. จัดสรรตัวแปรโลคัลบนสแต็กที่เรียกว่า x
  2. โหลดลงในค่า temp x1 4
  3. เก็บ x1 ถึง x
  4. ถ้า (! something) สาขาเป็น 8
  5. โหลด x เป็นอุณหภูมิ x2
  6. เพิ่ม x2 ด้วย 4 ถึง temp x3
  7. เก็บ x3 ถึง x
  8. โหลด x เป็น temp x4
  9. โทรพิมพ์ด้วย x4

โดยการเรียกใช้การเพิ่มประสิทธิภาพผ่านด้วย llvm รหัสที่สองนี้จะได้รับการปรับให้เหมาะกับรหัสแรก


4
จากสิ่งที่ฉันได้อ่านดูเหมือนจะมีข้อ จำกัด บางประการที่ควรคำนึงถึงที่นี่ mem2regคือผ่านการเพิ่มประสิทธิภาพในคำถามและก็มีข้อ จำกัด บางอย่างที่จะชี้ให้เห็นในตัวอย่าง Kaleidoscope ดูเหมือนว่านี่เป็นวิธีที่ดีที่สุดในการจัดการปัญหาและ Clang ใช้
Matthew Sanders
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.