Welcome to XCODX Online Compiler
Quick Start:
Ctrl+Enter Run code
Ctrl+S Save / Download
Ctrl+L Clear output
Select a language and start coding.
Welcome to XCODX Online Compiler
Quick Start:
Ctrl+Enter Run code
Ctrl+S Save / Download
Ctrl+L Clear output
Select a language and start coding.
LLVM IR is the intermediate representation at the heart of modern compilation: Clang, Rust, Swift, Julia, and dozens of other compilers lower source code into this typed, SSA-form assembly-like language before optimizing and emitting machine code. Reading and writing IR by hand is a standard exercise in compiler construction courses and the fastest way to understand what optimization passes actually do. Recent LLVM releases use opaque pointers (the ptr type), a change worth knowing when older tutorials show typed pointers like i8*. On this page your module is executed directly through LLVM's JIT tooling in a real terminal, so you can hand-craft functions and immediately watch calls, branches, and printf output happen.
; A hand-written LLVM IR module
@.hello = private constant [18 x i8] c"Hello from LLVM!\0A\00"
@.fmt = private constant [15 x i8] c"square(%d)=%d\0A\00"
declare i32 @printf(ptr, ...)
define i32 @square(i32 %x) {
entry:
%r = mul nsw i32 %x, %x
ret i32 %r
}
define i32 @main() {
entry:
%c0 = call i32 (ptr, ...) @printf(ptr @.hello)
br label %loop
loop:
%i = phi i32 [ 1, %entry ], [ %next, %loop ]
%sq = call i32 @square(i32 %i)
%c1 = call i32 (ptr, ...) @printf(ptr @.fmt, i32 %i, i32 %sq)
%next = add nsw i32 %i, 1
%done = icmp sgt i32 %next, 4
br i1 %done, label %exit, label %loop
exit:
ret i32 0
}
Hand-written IR is bread and butter in university compiler courses, where assignments ask students to lower expressions, implement phi nodes for loops, or predict what mem2reg and constant folding will produce. Compiler engineers use a quick IR scratchpad to minimize bug reproductions before filing LLVM issues, and language designers prototyping a new frontend verify that their intended lowering is valid. It also helps performance-minded developers decode the output of clang -emit-llvm or rustc --emit=llvm-ir when investigating why a hot function did or did not vectorize.
Yes, by declaring and calling C library functions: declare i32 @getchar() or scanf via a varargs declaration, then call them like any IR function. Because the terminal is attached live, a blocking getchar call waits for your keystroke. Most hand-written learning modules stick to printf output, but interactive input works when you need it.
Use ptr. LLVM completed its migration to opaque pointers, and releases from version 17 onward reject typed pointer syntax entirely. If you are following an older textbook or blog post showing i8* and getelementptr with pointee types, mechanically replacing pointer types with ptr and adjusting getelementptr's explicit type argument brings examples up to date.
The module is executed with LLVM's JIT-based tooling, which verifies the IR, compiles it in memory, and runs the result natively, so semantic errors like type mismatches or malformed phi nodes surface as verifier messages before anything executes. This mirrors exactly how course autograders and LLVM's own lli tool treat handwritten modules.
main.llplain text — no highlighter ships for this language@getchar / @scanf@.str = private unnamed_addr constant [15 x i8] c"Hello, World!\0A\00"
declare i32 @printf(i8*, ...)
define i32 @main() {
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str, i32 0, i32 0))
ret i32 0
}