เหตุใด LLVM จึงจัดสรรตัวแปรซ้ำซ้อน


9

นี่คือไฟล์ C อย่างง่ายที่มีนิยาม enum และmainฟังก์ชั่น:

enum days {MON, TUE, WED, THU};

int main() {
    enum days d;
    d = WED;
    return 0;
}

มัน transpiles เพื่อ LLVM IR ต่อไปนี้:

define dso_local i32 @main() #0 {
  %1 = alloca i32, align 4
  %2 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  store i32 2, i32* %2, align 4
  ret i32 0
}

%2เห็นได้ชัดว่าเป็นdตัวแปรซึ่งได้รับ 2 กำหนดให้กับมัน อะไรคือสิ่งที่%1ตรงกับถ้าศูนย์ส่งคืนโดยตรง?


1
คุณใช้ธงอะไรในการสร้าง IR นี้
arrowd

@arrowd ฉันติดตั้งชุด LLVM ที่เสถียรล่าสุดแล้วและวิ่งclang-9 -S -emit-llvm simple.c
macleginn

1
ฉันคิดว่ามันมีบางอย่างเกี่ยวกับการเริ่มต้นก่อนmain( godbolt.org/z/kEtS-s ) ลิงก์แสดงวิธีการแมปประกอบกับแหล่งที่มา
Pradeep Kumar

2
@PradeepKumar: แน่นอนถ้าคุณเปลี่ยนชื่อของฟังก์ชั่นเป็นอย่างอื่นนอกจากmainตัวแปรพิเศษลึกลับจะหายไป ที่น่าสนใจก็จะหายไปถ้าคุณไม่ใช้returnคำสั่งทั้งหมด (ซึ่งถูกต้องตามกฎหมายmainใน C และเทียบเท่าreturn 0;)
Nate Eldredge

1
@magicginn: ฉันไม่แน่ใจ หากคุณประกาศmainตามที่int main(int argc, char **argv)เห็นargcและargvคัดลอกลงในสแต็ก แต่ตัวแปรศูนย์ลึกลับยังคงมีอยู่นอกเหนือจากพวกเขา
Nate Eldredge

คำตอบ:


3

นี้%1ลงทะเบียนถูกสร้างขึ้นโดยเสียงดังกราวที่จะจัดการกับงบการกลับมาในหลายฟังก์ชั่น ลองนึกภาพคุณมีฟังก์ชั่นในการคำนวณแฟคทอเรียลของจำนวนเต็ม แทนที่จะเขียนแบบนี้

int factorial(int n){
    int result;
    if(n < 2)
      result = 1;
    else{
      result = n * factorial(n-1);
    }
    return result;
}

คุณอาจจะทำเช่นนี้

int factorial(int n){
    if(n < 2)
      return 1;
    return n * factorial(n-1);
}

ทำไม? เพราะเสียงดังกราวจะแทรกresultตัวแปรที่เก็บค่าตอบแทนสำหรับคุณ เย้. นั่นคือจุดประสงค์ที่แน่นอนของสิ่ง%1นั้น ดู ir สำหรับรหัสรุ่นที่ปรับเปลี่ยนเล็กน้อยของคุณ

แก้ไขรหัส

enum days {MON, TUE, WED, THU};

int main() {
    enum days d;
    d = WED;
    if(d) return 1;
    return 0;
}

IR,

define dso_local i32 @main() #0 !dbg !15 {
    %1 = alloca i32, align 4
    %2 = alloca i32, align 4
    store i32 0, i32* %1, align 4
    store i32 2, i32* %2, align 4, !dbg !22
    %3 = load i32, i32* %2, align 4, !dbg !23
    %4 = icmp ne i32 %3, 0, !dbg !23
    br i1 %4, label %5, label %6, !dbg !25

 5:                                                ; preds = %0
   store i32 1, i32* %1, align 4, !dbg !26
   br label %7, !dbg !26

 6:                                                ; preds = %0
  store i32 0, i32* %1, align 4, !dbg !27
  br label %7, !dbg !27

 7:                                                ; preds = %6, %5
  %8 = load i32, i32* %1, align 4, !dbg !28
  ret i32 %8, !dbg !28
}

ตอนนี้คุณเห็นไหมว่า%1การทำให้ตัวเองมีประโยชน์ฮะ? ตามที่คนอื่น ๆ ได้ชี้ให้เห็นสำหรับฟังก์ชั่นที่มีคำสั่ง return เพียงคำเดียวตัวแปรนี้อาจถูกปล้นโดยการส่งผ่านที่เหมาะสมที่สุดของ llvm


1

ทำไมเรื่องนี้ - ปัญหาแท้จริงคืออะไร

ฉันคิดว่าคำตอบที่ลึกกว่าที่คุณกำลังมองหาอาจเป็น: สถาปัตยกรรมของ LLVM นั้นมีพื้นฐานมาจากส่วนหน้าที่ค่อนข้างเรียบง่ายและหลายรอบ ส่วนหน้าจะต้องสร้างรหัสที่ถูกต้อง แต่ก็ไม่จำเป็นต้องเป็นรหัสที่ดี พวกเขาสามารถทำสิ่งที่ง่ายที่สุดที่ได้ผล

ในกรณีนี้เสียงดังกราวสร้างคำแนะนำสองสามข้อที่ไม่ควรใช้กับสิ่งใด โดยทั่วไปไม่ใช่ปัญหาเพราะบางส่วนของ LLVM จะกำจัดคำแนะนำที่ฟุ่มเฟือย เสียงดังกราวเชื่อมั่นว่าจะเกิดขึ้น เสียงดังกราวไม่จำเป็นต้องหลีกเลี่ยงการปล่อยรหัสตาย การนำไปใช้อาจมุ่งเน้นไปที่ความถูกต้องความเรียบง่ายความสามารถในการทดสอบและอื่น ๆ


1

เพราะเสียงดังดังกราวจะทำด้วยการวิเคราะห์ไวยากรณ์ แต่ LLVM ไม่ได้เริ่มต้นด้วยการเพิ่มประสิทธิภาพ

ส่วนหน้าของเสียงดังกราวได้สร้าง IR (การเป็นตัวแทนระดับกลาง) และไม่ใช่รหัสเครื่อง ตัวแปรเหล่านั้นคือ SSAs (Single Static Assignments); พวกเขายังไม่ได้ผูกมัดกับการลงทะเบียนและหลังจากการปรับให้เหมาะสมแล้วจะไม่เป็นเพราะซ้ำซ้อน

รหัสนั้นเป็นการแสดงถึงแหล่งที่มาที่แท้จริง มันเป็นสิ่งที่ส่งเสียงดังกราวด์เพื่อ LLVM สำหรับการเพิ่มประสิทธิภาพ โดยทั่วไป LLVM เริ่มต้นด้วยสิ่งนั้นและปรับให้เหมาะสมจากที่นั่น แท้จริงแล้วสำหรับรุ่น 10 และ x86_64 ในที่สุดllc -O2จะสร้าง:

main: # @main
  xor eax, eax
  ret

ฉันเข้าใจกระบวนการในระดับนี้ ฉันอยากรู้ว่าทำไม IR นี้จึงถูกสร้างขึ้นเพื่อเริ่มต้นด้วย
macleginn

คุณอาจจะคิดว่าคอมไพเลอร์เป็นบัตรเดียว มีท่อส่งของเริ่มต้นด้วยส่วนหน้าของ Clang ซึ่งสร้าง IR มันไม่ได้สร้าง IR ต้นฉบับเดิมซึ่งแทนที่จะมีคนร้องขอด้วย clang -emit-llvm -S file.cpp เสียงดังกราวจริง ๆ แล้วสร้าง bitcode ที่เป็นอนุกรมไบนารีของ IR LLVM มีโครงสร้างเป็นหลายรอบแต่ละการถ่ายและการปรับ IR ให้เหมาะสม LLVM pass แรกใช้ IR จาก Clang ใช้ IR เพราะคุณสามารถแทนที่ Clang ด้วย Fortran FE เพื่อสนับสนุนภาษาอื่นด้วยเครื่องมือเพิ่มประสิทธิภาพ + ตัวสร้างรหัสเดียวกัน
Olsonist
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.