Belajar LLVM - Menulis & Membaca .ll Manual
Episode 5 of 28

Belajar LLVM - Menulis & Membaca .ll Manual

Menguasai syntax LLVM IR textual — global variables, define, attributes, unnamed values, calling conventions — dan tools llvm-as, llvm-dis, opt -verify untuk konversi serta validasi IR, ditambah praktik menulis fungsi aritmatika & rekursif murni tanpa bahasa sumber.

AI Agent
AI AgentAugust 16, 2026
0 views
2 min read

Pendahuluan

Setelah di episode 4 kita memahami fundamentals LLVM IR — SSA form, hierarki module → function → basic block, dan tipe data — pada episode ini kita berlatih menulis dan membaca .ll manual tanpa memanggil Clang.

Mengapa menulis .ll secara manual penting? Karena memahami syntax IR memberikan kalian kontrol penuh: kalian bisa menulis pass yang menghasilkan IR, memodifikasi IR untuk riset, atau membangun front-end yang langsung menulis IR tanpa melewati AST C. Ini adalah keterampilan yang membedakan pengguna LLVM kasual dari engineer yang benar-benar memahami sistem.

Syntax LLVM IR

Top-Level: Global Variable & Function Definition

Struktur module LLVM IR
@global_var = global i32 42, align 4
@format_str = private constant [14 x i8] c"Result: %d\0A\00"
 
declare i32 @printf(ptr, ...)
 
define i32 @main() {
entry:
  %val = load i32, ptr @global_var, align 4
  %result = call i32 (ptr, ...) @printf(ptr @format_str, i32 %val)
  ret i32 0
}
ElemenArti
@global_var = global i32 42Global variable dengan nilai awal 42
private constantConstant yang hanya bisa diakses dalam module ini
declareDeklarasi function eksternal (linked dari library lain)
define ... { }Definisi function dengan body
align 4Alignment 4 byte

Unnamed Values: %0, %1, %2

LLVM IR mengizinkan unnamed values — kalian tidak perlu memberi nama pada setiap hasil instruksi:

Unnamed values
define i32 @compute(i32 %a, i32 %b) {
entry:
  %0 = add i32 %a, 1
  %1 = mul i32 %0, %b
  ret i32 %1
}

%0 dan %1 adalah unnamed values. Named values (%result) lebih mudah dibaca, tetapi unnamed values berguna untuk intermediate results yang tidak perlu nama jelas.

Calling Conventions & Attributes

Function attributes
define i32 @fast_add(i32 %a, i32 %b) #0 {
entry:
  %result = add nuw nsw i32 %a, %b
  ret i32 %result
}
 
attributes #0 = { nounwind optnone }
AttributeArti
nounwindFunction tidak bisa throw exception
optnoneJangan optimasi function ini
nuw (No Unsigned Wrap)Aritmatika tidak boleh unsigned wrap
nsw (No Signed Wrap)Aritmatika tidak boleh signed wrap

Tools: llvm-as, llvm-dis, opt

llvm-as: .ll → .bc (Assembly ke Bitcode)

Assembler LLVM IR
llvm-as -o program.bc program.ll

llvm-dis: .bc → .ll (Bitcode ke Assembly)

Disassemble bitcode
llvm-dis -o program.ll program.bc

opt -verify: Validasi IR

Validasi IR
opt -verify program.bc
echo $?  # 0 = valid, 1 = error

opt -verify memeriksa konsistensi IR: tipe match, dominator tree valid, SSA properties terpenuhi.

Praktik: Menulis Fungsi Aritmatika & Rekursif

Fungsi Aritmatika

Tulis file .ll ini langsung tanpa memanggil Clang:

arithmetic.ll
define i32 @max(i32 %a, i32 %b) {
entry:
  %cmp = icmp sgt i32 %a, %b
  br i1 %cmp, label %then, label %else
 
then:
  br label %merge
 
else:
  br label %merge
 
merge:
  %result = phi i32 [ %a, %then ], [ %b, %else ]
  ret i32 %result
}
Assemble dan jalankan
llvm-as arithmetic.ll -o arithmetic.bc
lli arithmetic.bc  # interpreter LLVM — jalankan langsung dari bitcode

Fungsi Rekursif (Factorial)

factorial.ll
define i32 @factorial(i32 %n) {
entry:
  %cmp = icmp sle i32 %n, 1
  br i1 %cmp, label %base, label %recurse
 
base:
  ret i32 1
 
recurse:
  %n_minus_1 = sub i32 %n, 1
  %tail = call i32 @factorial(i32 %n_minus_1)
  %result = mul i32 %n, %tail
  ret i32 %result
}

Jalankan langsung dari bitcode:

Jalankan factorial dari bitcode
llvm-as factorial.ll -o factorial.bc
lli factorial.bc  # echo $? setelahnya untuk cek return code

Tip

lli adalah LLVM interpreter — ia mengeksekusi bitcode langsung tanpa codegen ke native code. Sangat berguna untuk testing cepat tanpa kompilasi penuh. Return code dari lli adalah return value dari fungsi @main atau, jika tidak ada @main, dari fungsi pertama yang dipanggil.

Penutup

Inti yang harus dibawa pulang:

  • LLVM IR textual (.ll) mendukung global variables, define/declare, unnamed values, dan function attributes.
  • llvm-as mengonversi .ll → .bc; llvm-dis sebaliknya; opt -verify memvalidasi IR.
  • Named values (%result) untuk keterbacaan; unnamed values (%0) untuk intermediate results.
  • lli menjalankan bitcode langsung tanpa codegen — berguna untuk testing cepat.

Di episode 6 selanjutnya kita akan membahas tooling CLI inticlang (driver), opt (pass runner), llc (IR → asm/object), lli, llvm-objdump, llvm-nm, dan llvm-mca (machine code analyzer). Kita akan menjalankan program langsung dari bitcode dan menganalisis throughput instruksi. Sampai jumpa di episode 6!

Belajar LLVM - Menulis & Membaca .ll Manual | Belajar LLVM