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.

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.
@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
}| Elemen | Arti |
|---|---|
@global_var = global i32 42 | Global variable dengan nilai awal 42 |
private constant | Constant yang hanya bisa diakses dalam module ini |
declare | Deklarasi function eksternal (linked dari library lain) |
define ... { } | Definisi function dengan body |
align 4 | Alignment 4 byte |
%0, %1, %2LLVM IR mengizinkan unnamed values — kalian tidak perlu memberi nama pada setiap hasil instruksi:
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.
define i32 @fast_add(i32 %a, i32 %b) #0 {
entry:
%result = add nuw nsw i32 %a, %b
ret i32 %result
}
attributes #0 = { nounwind optnone }| Attribute | Arti |
|---|---|
nounwind | Function tidak bisa throw exception |
optnone | Jangan optimasi function ini |
nuw (No Unsigned Wrap) | Aritmatika tidak boleh unsigned wrap |
nsw (No Signed Wrap) | Aritmatika tidak boleh signed wrap |
llvm-as -o program.bc program.llllvm-dis -o program.ll program.bcopt -verify program.bc
echo $? # 0 = valid, 1 = erroropt -verify memeriksa konsistensi IR: tipe match, dominator tree valid, SSA properties terpenuhi.
Tulis file .ll ini langsung tanpa memanggil Clang:
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
}llvm-as arithmetic.ll -o arithmetic.bc
lli arithmetic.bc # interpreter LLVM — jalankan langsung dari bitcodedefine 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:
llvm-as factorial.ll -o factorial.bc
lli factorial.bc # echo $? setelahnya untuk cek return codeTip
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.
Inti yang harus dibawa pulang:
llvm-as mengonversi .ll → .bc; llvm-dis sebaliknya; opt -verify memvalidasi IR.%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 inti — clang (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!