4 คะแนน โดย GN⁺ 2026-01-13 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • วิเคราะห์อย่างรอบด้านถึง ข้อจำกัดเชิงโครงสร้างและหนี้ทางเทคนิคของโครงการ LLVM พร้อมชี้จุดที่ควรได้รับการปรับปรุงอย่างเป็นรูปธรรม
  • นำเสนอคอขวดในการดำเนินโครงการโอเพนซอร์สขนาดใหญ่ เช่น การรีวิวไม่เพียงพอ, ความไม่เสถียรของ API, เวลา build และ compile, ความไม่เสถียรของ CI
  • ปัญหาด้าน การออกแบบ IR ครอบคลุมการจัดการค่า undef, การเข้ารหัสเงื่อนไขจำกัด, ความหมายของ floating point และความไม่สมบูรณ์ของสเปก
  • ชี้ปัญหาเชิงโครงสร้างระยะยาว เช่น ความต่างกันของ backend, ความสับสนในการจัดการ ABI, ความล่าช้าในการย้ายไปใช้ GlobalISel และ pass manager
  • แทนที่จะมองสถานะของ LLVM ในแง่ลบ บทความนี้เสนอให้มองเป็น โอกาสสำหรับการปรับปรุงอย่างต่อเนื่องและการขยายการมีส่วนร่วม

ปัญหาเชิงโครงสร้างหลัก

  • การขาดแคลนศักยภาพด้านการรีวิว ถูกชี้ว่าเป็นคอขวดที่ใหญ่ที่สุด

    • มีผู้เขียนโค้ดจำนวนมาก แต่มีผู้รีวิวน้อย ทำให้เกิดกรณีที่มีการ merge การเปลี่ยนแปลงที่ยังไม่ได้รับการตรวจสอบอย่างเพียงพอ
    • ด้วยโครงสร้างที่ให้ผู้เขียนเป็นผู้รับผิดชอบในการขอรีวิว ผู้มีส่วนร่วมหน้าใหม่จึงหาผู้รีวิวที่เหมาะสมได้ยาก
    • มีการกล่าวถึงการนำ ระบบมอบหมาย PR อัตโนมัติ ของ Rust มาใช้เป็นแนวทางปรับปรุง
  • การเปลี่ยนแปลง API และ IR บ่อยครั้ง (Churn) สร้างภาระให้ผู้ใช้

    • C API ค่อนข้างเสถียร แต่ C++ API เปลี่ยนแปลงบ่อย ทำให้ต้นทุนในการดูแลรักษา frontend และ backend สูงขึ้น
    • ด้วยแนวคิด “Upstream or GTFO” โค้ดที่ไม่ได้แชร์ขึ้น upstream จึงไม่ถูกนำมาพิจารณาในการตัดสินใจ
  • ปัญหา เวลา build ที่มากเกินไป

    • LLVM ประกอบด้วยโค้ด C++ มากกว่า 2.5 ล้านบรรทัด ทำให้ใช้เวลา build นานมาก และในการ build แบบ debug การใช้หน่วยความจำและดิสก์จะเพิ่มสูงขึ้นอย่างมาก
    • มีการพูดถึงแนวทางปรับปรุง เช่น precompiled headers (PCH), การ build แบบ dylib เป็นค่าเริ่มต้น, การทำ daemon ให้กับการทดสอบ
  • CI ไม่เสถียร

    • แม้จะมี buildbot มากกว่า 200 ตัวทดสอบในสภาพแวดล้อมหลากหลาย แต่ก็ไม่สามารถรักษา “สถานะสีเขียว” ได้ตลอดเวลา
    • ปัญหา flaky tests และปัญหาของ buildbot ทำให้สัญญาณเตือนถูกกลบ จนตรวจจับข้อผิดพลาดจริงได้ยาก
    • การนำ pre-test สำหรับ PR เข้ามาช่วยปรับปรุงได้บางส่วน แต่ยังไม่แก้ปัญหาที่รากฐาน
  • การทดสอบแบบ end-to-end มีไม่เพียงพอ

    • แม้ unit test ของการเพิ่มประสิทธิภาพแต่ละส่วนจะทำได้ดี แต่แทบไม่มีการทดสอบทั้ง pipeline หรือการทดสอบการเชื่อมต่อกับ backend แบบครบวงจร
    • แม้จะมี llvm-test-suite อยู่แล้ว แต่ก็ยังครอบคลุมการผสมกันของการดำเนินการพื้นฐานและชนิดข้อมูลได้ไม่เพียงพอ

ปัญหาด้าน backend และประสิทธิภาพ

  • ความต่างกันระหว่าง backend

    • แม้ส่วนกลางจะถูกรวมเป็นหนึ่งเดียว แต่ backend ของแต่ละ target ยังมีการแก้ไขแยกกันจำนวนมาก ทำให้ ความซ้ำซ้อนและการแตกแขนงเพิ่มขึ้น
    • มีแนวโน้มจะเพิ่ม hook เฉพาะ target แทนการทำ optimization ส่วนกลางร่วมกัน
  • เวลา compile

    • ช้าสำหรับ JIT และภาษาที่สร้าง IR ขนาดใหญ่ เช่น Rust และ C++
    • การ build ด้วย -O0 ช้าเป็นพิเศษ และมีการเสนอว่า TPDE backend เป็นทางเลือกที่เร็วกว่าได้ถึง 10–20 เท่า
  • ขาดการติดตามประสิทธิภาพ

    • ไม่มี โครงสร้างพื้นฐานอย่างเป็นทางการสำหรับติดตามประสิทธิภาพ runtime
    • ระบบ LNT มีประสิทธิผลต่ำ เนื่องจากปัญหาความไม่เสถียรในการทำงาน, UX และข้อมูลที่ไม่เพียงพอ

ปัญหาการออกแบบ IR

  • ความซับซ้อนในการจัดการค่า undef

    • เนื่องจากอาจมีค่าต่างกันได้ในแต่ละครั้งที่ถูกใช้งาน จึงก่อให้เกิดข้อผิดพลาดระหว่าง optimization
    • ในอนาคตอาจถูกแทนที่ด้วย ค่า poison แต่การจัดการ poison ในหน่วยความจำยังไม่สมบูรณ์
  • สเปกไม่สมบูรณ์และไม่สอดคล้องกัน

    • มีกรณีการทำงานผิดพลาดเก่าที่ยังไม่ได้รับการแก้ไขอยู่
    • ยังมีโจทย์ด้านการออกแบบที่ยาก เช่น โมเดล provenance
    • เพื่อแก้ปัญหานี้ จึงมีการตั้ง working group ด้านสเปกอย่างเป็นทางการ ขึ้นมา
  • ขาดความสม่ำเสมอในการเข้ารหัสเงื่อนไขจำกัด

    • มีหลายวิธีปะปนกัน เช่น poison flags, metadata, attributes, assumes
    • ส่งผลเสียต่อ optimization ทั้งจากการสูญเสียข้อมูลหรือการเก็บข้อมูลมากเกินไป
  • ปัญหาความหมายของ floating point (FP)

    • เกิดความไม่สอดคล้องในกรณีของ signaling NaN, สภาพแวดล้อมที่ไม่เป็นมาตรฐาน, การจัดการ denormal, ความละเอียดเกินของ x87
    • มีการแยกจัดการด้วย constrained FP intrinsic ทำให้ความซับซ้อนเพิ่มขึ้น

ปัญหาทางเทคนิคอื่น ๆ

  • ความล่าช้าในการย้ายระบบบางส่วน

    • pass manager ใหม่ ถูกใช้ถึงแค่ขั้นกลางเท่านั้น ส่วน backend ยังใช้ของเก่าอยู่
    • GlobalISel ผ่านมา 10 ปีแล้วยังไม่สามารถย้ายได้สมบูรณ์ และยังอยู่ร่วมกับ SDAG
  • ความสับสนในการจัดการ ABI และ calling convention

    • การแยกความรับผิดชอบระหว่าง frontend และ backend ยังไม่ชัดเจน และเอกสารก็ไม่เพียงพอ
    • กำลังมีการพัฒนา ไลบรารี ABI และ implementation ต้นแบบ
    • ยังมีปัญหาที่ ABI เปลี่ยนไปตามการเปิดใช้ฟีเจอร์ของ target
  • ความไม่สอดคล้องในการจัดการ built-in functions และ libcalls

    • TargetLibraryInfo และ RuntimeLibcalls แยกจากกัน ทำให้ขาดความสม่ำเสมอ
    • ไม่สามารถรับรู้ความพร้อมใช้งานตามชนิดของ runtime library (เช่น libgcc, compiler-rt) ได้
    • ขาดจุดสำหรับปรับแต่งโดย runtime ภายนอก เช่น Rust
  • โครงสร้าง Context / Module ที่ไม่มีประสิทธิภาพ

    • type และ constant อยู่ใน Context ส่วน function และ global อยู่ใน Module
    • ทำให้เข้าถึง data layout ไม่ได้ จึงไม่สะดวกต่อสิ่งอย่าง constant folding
    • ไม่สามารถลิงก์ข้าม context ได้ และควรทำให้โครงสร้างเรียบง่ายกว่านี้
  • แรงกดดันต่อรีจิสเตอร์จาก LICM (loop-invariant code motion)

    • มีการ hoist โดยไม่มี cost model
    • backend ก็ไม่ sink กลับลงมาอีก ทำให้ จำนวน spill และ reload เพิ่มขึ้น

สรุป

  • ปัญหาที่ยกมาทั้งหมดเป็น โจทย์เชิงโครงสร้างที่เกิดจากระดับความ成熟และขนาดของ LLVM และถูกนำเสนอในฐานะ โอกาสในการยกระดับคุณภาพของโครงการและประสบการณ์ของผู้มีส่วนร่วม
  • ในบางด้าน เช่น การเพิ่มประสิทธิภาพการ build, ไลบรารี ABI, การติดตามประสิทธิภาพ มีการปรับปรุงที่กำลังดำเนินอยู่แล้ว
  • โดยรวมแล้ว LLVM ยังทรงพลังมาก แต่ การรีแฟกเตอร์อย่างต่อเนื่องและการจัดระเบียบสเปกยังเป็นสิ่งจำเป็น

1 ความคิดเห็น

 
GN⁺ 2026-01-13
ความคิดเห็นจาก Hacker News
  • บทความทั้งชิ้นเรียบเรียงมาอย่างดี เลยรู้สึกเห็นด้วยมาก
    ช่วงนี้ ความเสถียรของ LLVM IR สูงขึ้นมากพอสมควร ผมรีเบส Fil-C จาก LLVM 17 ไปเป็น 20 ได้ภายในวันเดียว
    ในโปรเจ็กต์อื่นก็เคยคง pass เดียวกันไว้ข้าม LLVM หลายเวอร์ชัน และแทบไม่มีปัญหาใหญ่
    แต่ แรงกดดันต่อรีจิสเตอร์ของ LICM รุนแรงมากเป็นพิเศษกับซอร์สที่ไม่ใช่ C/C++ ปัญหาดูเหมือนจะไม่ใช่ตัว LICM เองเท่าไร แต่เป็นเรื่องที่ต้องทำให้ regalloc เรียนรู้การ rematerialize ให้ดีขึ้น

    • regalloc รู้จัก rematerialize อยู่แล้ว เพียงแต่แบ็กเอนด์มีแค่ มุมมองเฉพาะที่ มากกว่าตัว optimizer เลยย้อนการตัดสินใจแย่ ๆ ที่ LICM สร้างไว้ได้ยาก
    • มี rematerialize pass อยู่แล้ว ไม่จำเป็นต้องผูกมันเข้ากับ register allocation ก็ได้ LLVM regalloc เองก็ไม่ได้สมบูรณ์แบบแต่แรกอยู่แล้ว
      ถ้าเปิดตัวเลือกให้มากขึ้นเพื่อให้ผู้พัฒนาฟรอนต์เอนด์ benchmark การตั้งค่าหลายแบบและเลือกค่าที่ดีที่สุดได้ ก็น่าจะดี
    • ผมไม่ใช่ผู้เชี่ยวชาญ LLVM แต่ตอนที่เคยจับมันเมื่อก่อน IR ให้ความรู้สึกเหมือนเป็น ชุดคำศัพท์ร่วม ของหลายภาษา มากกว่าจะเป็นภาษาหนึ่งภาษา
      เครื่องมือและคอมโพเนนต์แต่ละตัวต่างก็มีกฎของตัวเอง การเกิดความต่างกันระหว่างเวอร์ชันเลยดูเป็นเรื่องธรรมชาติ เลยสงสัยว่าหรือผมจะเข้าใจผิด
  • ผมเคยขอให้ผู้ดูแล compiler-rt เปลี่ยน boolean แค่ตัวเดียวเพื่อจะ build LLVM 18 บน macOS แต่ issue กลับถูกล็อกเป็น “heated” และยังไม่ถูกแก้มา 4 ปีแล้ว
    ถึงอย่างนั้นผมก็ยังรัก LLVM อยู่ดี clang-tidy, ASAN, UBSAN, LSAN, MSAN, TSAN ยอดเยี่ยมมาก
    ผมคิดว่าการเขียนโค้ด C/C++ โดยไม่ใช้ clang-tidy เป็นการตัดสินใจที่ผิด
    แต่ -fbounds-safety มีเฉพาะใน AppleClang ส่วน MSAN/LSAN มีเฉพาะใน LLVM Clang Xcode ก็ไม่มี clang-tidy, clang-format และ llvm-symbolizer ด้วย
    สุดท้ายบน macOS เลยต้อง build Darwin LLVM มาใช้เอง
    ฝั่ง Linux ก็ยังสับสน RHEL ไม่ให้ libcxx แต่ Fedora ให้ อย่างไรก็ตาม ไม่มีดิสโทรไหนมี libcxx ที่ instrumented สำหรับ MSAN
    Fedora มาใกล้มากแล้วแต่ก็ยังต้อง build compiler-rt เองอยู่ดี

    • มีคนแนะนำให้ลองใช้ Gentoo ดู พร้อมอ้างถึง Gentoo LLVM wiki
    • ยังมีคนถามว่า Chimera Linux หรือ Mandriva ไม่ได้ทำให้ LLVM ใช้งานได้ดีเป็นค่าเริ่มต้นหรือ Chimera ค่อนข้าง LLVM native มาก
  • หลังจากตามการถกเถียงเกี่ยวกับ LLVM ช่วงหลัง ๆ ก็ยิ่งรู้สึกว่าจำเป็นต้องมี ชุดทดสอบแบบรันได้ที่เริ่มจาก LLVM IR โดยตรง ไม่ใช่จาก C
    ถ้าลองทำแบ็กเอนด์เองจะพบว่าเอกสารเกี่ยวกับ SelectionDAG หรือ GlobalISel มีไม่พอ และความหมายของ operation ก็ไม่ชัด ทำให้ implement ผิดได้ง่าย

  • C API ให้ความรู้สึกเหมือนเป็นสิ่งที่ถูกละเลยใน LLVM หลายตัวเลือกและ opt pass ไม่ได้ถูกเปิดออกมา

    • นี่เป็นเพราะ พลังในการแสดงออกของ C++ API ย้ายมาเป็นอินเทอร์เฟซสไตล์ C ได้ยาก
      นักพัฒนาส่วนใหญ่ใช้ C++ API โดยตรงกันอยู่แล้ว C API เลยถูกดันไปเป็นเรื่องรอง และสุดท้ายก็กลายเป็น พลเมืองชั้นสอง
  • การรีวิวโค้ดไม่ได้ให้รางวัลตอบแทนแบบทันที คนเลยไม่ค่อยอยากทำ
    ถ้าให้เครดิตการมีส่วนร่วมกับการรีวิวด้วย ก็น่าจะช่วยสร้างแรงจูงใจได้

    • ในบริษัทก็เจอปัญหาคล้ายกัน บริษัทของผมเอา คุณภาพและปริมาณของการรีวิว เข้าไปอยู่ในเกณฑ์ประเมิน แต่ก็ยังสร้างแรงจูงใจได้ไม่พอ
  • เมื่อ 6 ปีก่อน ผม build LLVM บ่อย ๆ บนโน้ตบุ๊ก Dell 9360 แรม 8GB ถ้าลด parallelism ตอนลิงก์ลงก็ยังทำได้ภายในข้อจำกัดด้านหน่วยความจำ
    ตอนนี้ก็ยังสงสัยว่าแรม 8GB ยัง build ได้อยู่ไหม

    • ถ้าปิดการ build แบบขนานและเตรียม swap ไว้สักไม่กี่ GB ก็ยังทำได้ แต่ต้องปรับ linker setting flags
    • บน M1 Mac นั้น LLVM compile เสร็จภายในไม่ถึงหนึ่งชั่วโมงในทุกการตั้งค่าการ build
  • ช่วงแรก ๆ ของ LLVM จุดเด่นคือ ความเร็วในการคอมไพล์ที่เร็วกกว่า GCC
    ตอนนี้ผ่านมา 23 ปีของ LLVM แล้ว ก็สงสัยว่าจะมีอะไรใหม่โผล่มาอีกไหม

    • ช่วงหลังมีคนทำ โปรเจ็กต์ TPDE ที่ทำให้แบ็กเอนด์ -O0 ของ LLVM เร็วขึ้น 10~20 เท่า แต่ไม่ค่อยได้รับความสนใจ
      และก็ยังมีทางเลือกอย่าง Cranelift ที่ไม่ใช้ LLVM IR (Cranelift GitHub)
    • ถึงอย่างนั้น LLVM ก็ยังยอดเยี่ยมมากสำหรับการคอมไพล์ C/C++ แม้จะไม่สมบูรณ์แบบ แต่ถ้าจะทำของที่ใกล้เคียงกันได้ก็ต้องใช้ ความพยายามระดับหลายหมื่นชั่วโมงคน
  • การจัดการ ABI และ calling convention คือความเจ็บปวดที่สุด
    ในฟรอนต์เอนด์ของคอมไพเลอร์ต้องจัดการการส่งอาร์กิวเมนต์เอง และบางครั้งถึงขั้นต้อง คำนวณจำนวนรีจิสเตอร์ เอง

  • ในบทความบอกว่า “ฟรอนต์เอนด์ได้รับการปกป้องด้วย C API ที่เสถียร” แต่ในความเป็นจริงไม่ใช่แบบนั้น
    บาง API เสถียร แต่ส่วนอย่าง Orc เปลี่ยนบ่อย

    • Orc C API นั้น มีกฎต่างจาก C API ตัวอื่น (ซอร์ส Orc.h)
  • ดูเหมือน LLVM จะ แทบไม่มีระบบรีวิว issue เลย รายงานบั๊กที่ผมส่งไปก็ยังค้างอยู่หลายปี