Master the fundamental concepts of optimizations through this focused micro-challenge.
You have read the whole brief, and the concepts above stay free on every task. Writing and running the code needs a plan.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksBasic blocks are straight-line code with single entry and exit. Analyses partition the CFG into blocks, then compute properties per block: predecessors, successors, dominators, loop membership. LLVM's LoopInfo and GCC's loop passes depend on this foundation.
For each block: list of instructions, predecessor and successor sets, whether it is a loop header, whether it dominates its successors' join nodes.
cLoading…
Production compilers embed this step inside a longer pipeline. GCC flows through cpp, cc1, assembly, and ld; Clang uses the driver, Sema, LLVM IR passes, and a target backend. LLVM bitcode, JVM bytecode, and WASM are other familiar IRs at the same layer. The exercise isolates one pass so you can test it alone before chaining it to the next stage.
You will implement basic block analysis on your CFG. This exercise requires identifying blocks, computing predecessor and successor lists, and preparing data structures for loop and dominance analyses.
Go beyond splitting code into basic blocks: compute global liveness over the control-flow graph, which variables are live on entry to and exit from every block, with the classic iterative data-flow algorithm. This is the analysis register allocators and dead-store elimination run on real, branching code.
TAC with labels and jumps: x = a, x = a OP b, L:, goto L, if a goto L, ifFalse a goto L, print a, return a. Operands are names or integer literals.
return; a conditional jump has two successors, goto one, return none; otherwise control falls through to the next block. Blocks are B0, B1, ….use(B): variables read before any write to them in Bdef(B): variables written in Bout(B) = ⋃ in(S) over successors S, then in(B) = use(B) ∪ (out(B) − def(B)).
All sets start empty. Count passes, including the final one that changes nothing.cLoading…
Variables inside a set are listed in order of first appearance in the program (reading each instruction left to right), separated by single spaces.
Input:
cLoading…
Output:
cLoading…
use, def, in and out.Hidden tests cover nested loops, a variable that is never live, and an unreachable block (liveness still flows backward into it from its successor).