Theory test — Chapter 0¶
57 questions; you pass at 80 %. This page shows the questions only: take the test in the terminal, where every answer is graded and explained.
./course quiz 0 # interactive
./course quiz template 0 -o answers/ch00.yaml # or fill in a file ...
./course quiz grade 0 # ... and grade it
refinement-compose · single · 1 pt · 01-pipeline-shapesPasses P1: C → LLVM IR and P2: LLVM IR → LLVM IR are both correct (each output refines its
input, Definition 0.1.4). What can you conclude about the pipeline P2 ∘ P1, and why?
- Nothing, because the passes work on different languages
- It is correct, because refinement is transitive (Lemma 0.1.3, Theorem 0.1.6)
- It is correct only if P1 and P2 are deterministic
- It is correct only if neither pass sees a program with undefined behavior
refinement-ub · single · 1 pt · 01-pipeline-shapesA source program p reads an uninitialized variable, so ub ∈ Beh(p). Which target programs q
satisfy q ⪯ p?
- Only programs with the same output as p on the test inputs
- Only programs that also contain undefined behavior
- Every program
- No program, so a correct compiler must reject p
pass-manager-recompute · number · 1 pt · 01-pipeline-shapesAlgorithm 0.1.8 runs passes P1 … P6. P1, P3 and P5 request the dominator tree; P6 does not.
P1, P3, P5 and P6 preserve it; P2 and P4 do not. How many times is the dominator tree
computed?
llvm-where-o0-pipeline · text · 1 pt · 01-pipeline-shapesIn llvm/lib/Passes/PassBuilderPipelines.cpp (LLVM 23.1.2), buildPerModuleDefaultPipeline
returns early for OptimizationLevel::O0. Which PassBuilder member function does it call
then? (name only)
backpatch-trace · mapping · 1 pt · 01-pipeline-shapesAlgorithm 0.1.10 (one-pass, with backpatching) compiles
if x < 1 { y = 1; } else { y = 2; } return y;
into 11 instructions numbered 0–10: load x, push 1, lt, jz ?, push 1, store y, jmp ?, push 2, store y, load y, ret. Give the patched targets of the two jumps.
jz, jmpsingle-pass-tcc-order · single · 1 pt · 01-pipeline-shapesIn TCC's code for for (i = 0; i < n; i++) s += i; (Lesson 0.1 box) the increment i++ is
emitted before the body, and the condition jumps over it into the body. Why?
- TCC optimizes the loop by rotating it
- A single-pass compiler emits code in source order, and
i++appears before the body in the source - x86 requires increments before loop bodies
- The preprocessor reorders the for statement
query-red-green · set · 1 pt · 01-pipeline-shapesA query graph from the previous session (deps in recorded order): A = parse(F);
B = sig(f) reads A; C = body(f) reads A; D = sig(g) reads A; E = typeck(g) reads D, B;
G = codegen(f) reads C, B; H = codegen(g) reads E. The edit changes only the body of f,
so A's value changes, B's and D's recomputed values are unchanged, and C's changes.
After demanding G and H with Algorithm 0.1.12, which nodes' providers were EXECUTED?
(Input F is not a provider.)
query-early-cutoff · single · 1 pt · 01-pipeline-shapesIn the previous question, why is typeck(g) NOT re-executed although parse(F) changed?
- Because typeck(g) is an input
- Because its recorded dependencies sig(g) and sig(f) were recomputed with unchanged fingerprints, so they are green
- Because the red-green algorithm never re-executes type checking
- Because H was demanded after G
mlir-progressive · sequence · 1 pt · 01-pipeline-shapesIn Lesson 0.1's MLIR box, give the levels the sum loop passes through, from the input to
the final output. Use the tokens: cf, llvm-dialect, llvm-ir, scf.
llvm-where-scf-for · text · 1 pt · 01-pipeline-shapesIn mlir/lib/Conversion/SCFToControlFlow/SCFToControlFlow.cpp (LLVM 23.1.2), what is the
name of the rewrite-pattern struct that lowers scf.for?
tree-walk-eval-count · number · 1 pt · 02-interpretersHow many times does the tree walker of Algorithm 0.2.3 call Eval (once per expression node
visited) on the program x = 3; while x > 0 { x = x - 1; } return x;?
llvm-where-interpreter · text · 1 pt · 02-interpretersIn llvm/lib/ExecutionEngine/Interpreter/Execution.cpp (LLVM 23.1.2), which member function
of class Interpreter contains the main loop that executes instructions one after another?
bigstep-division · mapping · 1 pt · 02-interpretersUnder Tiny's semantics (Definition 0.2.2), give the values:
A = 7 / 0, B = 7 % 0, C = (-7) / 2, D = (-7) % 2, E = (-9223372036854775807 - 1) / (-1).
A, B, C, D, Estack-code-order · sequence · 1 pt · 02-interpretersGive the stack code of Algorithm 0.2.5 for (a - b) * c, instructions separated by commas
(instruction names: load, push, add, sub, mul).
stack-depth · number · 1 pt · 02-interpretersWhat is the maximum stack depth D(e) of the postorder stack code for a - (b - (c - d))?
ershov-number · number · 1 pt · 02-interpretersWhat is the Ershov number E(e) of a - (b - (c - d)) — the minimum stack depth if, at each
operator, either operand may be evaluated first?
register-count · number · 1 pt · 02-interpretersHow many three-address instructions does Algorithm 0.2.7 emit for (a + b) * (c - d * e)
(no destination register)?
register-vs-stack · single · 1 pt · 02-interpretersCompared with a stack VM for the same programs, a register VM typically…
- executes more instructions, each smaller
- executes fewer instructions, each larger (Shi et al.: ~47% fewer, code ~25% larger)
- executes the same number of instructions but predicts branches better
- needs no operands at all
dispatch-switch-misses · number · 1 pt · 02-interpretersAn interpreter executes the opcode trace A B A A B B A. Under the last-target model
(Definition 0.2.9), how many dispatches mispredict with SWITCH dispatch?
dispatch-threaded-misses · number · 1 pt · 02-interpretersSame trace A B A A B B A. How many dispatches mispredict with THREADED dispatch (each handler
has its own dispatch site; the first dispatch comes from an entry site)?
threading-kinds · mapping · 1 pt · 02-interpretersMatch each dispatch scheme to its description (Definition 0.2.8):
a = the code holds handler addresses and every handler jumps to the next one itself;
b = one indirect jump through a jump table in a loop, shared by all handlers;
c = the code holds addresses of cells that contain handler addresses;
d = the code holds opcodes, and every handler ends with a jump through the opcode table.
Keys: switch, direct, indirect, token.
switch, direct, indirect, tokenaot-o2-closed-form · single · 1 pt · 03-aot-jit-transpilersWhat happened to the loop of sum.c in clang's -O2 LLVM IR (Lesson 0.3 box)?
- It was unrolled four times
- It was vectorized
- It was replaced by a closed-form computation of the sum (scalar evolution), with no loop left
- Nothing: -O2 keeps loops unchanged
jit-breakeven · number · 1 pt · 03-aot-jit-transpilersA program runs in 0.50 ms interpreted and 0.02 ms compiled; compiling it costs 9.6 ms. After
how many runs N* = c / Δ does compiling break even?
ski-rental-ratio · number · 1 pt · 03-aot-jit-transpilersWith c = 1000 µs and Δ = 1 µs, the threshold policy compiles on call k = ⌊c/Δ⌋ + 1 = 1001.
For N = 1500 calls, what is its extra cost (above running compiled code for every call), in µs?
llvm-where-lljit · text · 1 pt · 03-aot-jit-transpilersIn llvm/lib/ExecutionEngine/Orc/LLJIT.cpp (LLVM 23.1.2), which LLJITBuilderState member
function fills in defaults (target machine, linking layer, …) before an LLJIT is constructed?
trace-guards · single · 1 pt · 03-aot-jit-transpilersWhat happens when a guard in a compiled trace fails?
- The program aborts with an error
- The trace is recompiled and restarted from the loop header
- A side exit rebuilds the interpreter state at that point and the interpreter continues from there
- The guard is ignored and the trace continues
tracing-vs-method · single · 1 pt · 03-aot-jit-transpilersWhich code shape is worst for a tracing JIT compared with a method JIT?
- A tight numeric loop with a stable path
- A loop body with many independent, unpredictable if-statements
- A function called once
- A loop that calls a small function every iteration
hotspot-tiers · mapping · 1 pt · 03-aot-jit-transpilersIn HotSpot's -XX:+PrintCompilation output, give the tier level number for:
interpreter, c1-full-profile (C1 with full profiling), c2.
interpreter, c1-full-profile, c2deopt-purpose · single · 1 pt · 03-aot-jit-transpilersWhy do optimizing JITs need deoptimization?
- To free memory used by compiled code
- To fall back to a lower tier when a speculative assumption (type, branch, callee) turns out false, without restarting the function
- To recompile at a higher optimization level
- To handle exceptions thrown by the interpreter
transpiler-es5 · multi · 1 pt · 03-aot-jit-transpilersWhich transformations did tsc --target ES5 apply to the Lesson 0.3 example?
- let/const became var
- the arrow function became a function expression
- the class became a constructor function with a prototype method
- the type annotations were kept as comments
- the loop was unrolled
transpiler-definition · single · 1 pt · 03-aot-jit-transpilersWhat distinguishes a transpiler from other compilers?
- It never checks the program for errors
- Its target is a high-level language that another compiler or interpreter processes further
- It runs at run time
- It cannot be correct in the sense of Definition 0.1.4
futamura-second · single · 1 pt · 03-aot-jit-transpilersIf mix is a specializer and int an interpreter for L, what is [mix]?
- A compiled version of int
- A compiler from L to mix's language
- A compiler generator
- An interpreter for mix
futamura-residual · text · 1 pt · 03-aot-jit-transpilersSpecialize the Lesson 0.3 stack interpreter (Algorithm 0.3.10) to the static program
ARG, PUSH 2, MUL, PUSH 1, ADD. Give the residual expression in x (write it as x*2+1 or
similar).
m-times-n · number · 1 pt · 04-retargetingFor 5 source languages and 7 target machines, how many translators does a shared-IR design need?
ir-target-dependent · single · 1 pt · 04-retargetingWhy should you not compile clang's --target=x86_64-linux-gnu LLVM IR for AArch64 with
llc -mtriple=aarch64-linux-gnu?
- llc cannot read IR produced by clang
- The IR already encodes x86-64 decisions — type sizes, data layout, ABI lowering, target CPU and features
- LLVM IR has no branches that AArch64 can execute
- It works identically; there is no reason
llvm-where-lookup-target · text · 1 pt · 04-retargetingIn llvm/include/llvm/MC/TargetRegistry.h (LLVM 23.1.2), which static member function of
TargetRegistry maps a target triple to a const Target *?
three-phase-roles · mapping · 1 pt · 04-retargetingWhich LLVM phase makes each decision? Values: front-end, optimizer, back-end.
long-size (C long is i64 vs i32); loop-rotation (moving the test to the bottom);
register-allocation; sext-w (RISC-V sign extension of 32-bit values).
long-size, loop-rotation, register-allocation, sext-wgcc-irs-order · sequence · 1 pt · 04-retargetingGive GCC's three intermediate representations in the order a function passes through them.
gimple-three-address · number · 1 pt · 04-retargetingHow many fresh temporaries does Algorithm 0.4.5 (gimplification) create for the expression (a + b) * (c - d)?
cranelift-block-params · single · 1 pt · 04-retargetingIn the CLIF of Lesson 0.4, what plays the role of LLVM's phi nodes?
- Stack slots
- Block parameters, with values passed by each branch (
jump block3(v14, v10)) - Global values (gv0, gv1)
- Nothing: CLIF is not in SSA form
cranelift-isle · single · 1 pt · 04-retargetingIn Cranelift's x64 lower.isle, two rules match iadd: iadd_base_case_32_or_64_lea with
priority −5 and a load-sinking rule with priority −4. If both match, which is used?
- The one with priority −5, because it is more general
- The one with priority −4, because higher priority is tried first
- Both, emitting two instructions
- Neither; ISLE reports an ambiguity
tdiagram-cross · text · 1 pt · 05-bootstrapping-and-trustOn an x86 host, you compile the source of C(Oak, RISCV, Oak) with the binary
C(Oak, x86, x86). Give the result as S->T in I.
tdiagram-interp · single · 1 pt · 05-bootstrapping-and-trustYou have C(C, x86, x86), the source of a bytecode VM R(BC, C), and a boot compiler
C(Oak, BC, BC) as bytecode. What must you do before the boot compiler can compile anything?
- Nothing: bytecode runs anywhere
- Compile the VM with the C compiler, obtaining R(BC, x86), so that BC becomes executable on the host
- Compile the boot compiler with the C compiler
- Rewrite the boot compiler in C
stage2-stage3 · single · 1 pt · 05-bootstrapping-and-trustIn a 3-stage bootstrap, the stage-2 and stage-3 compilers are bit-identical. What does this show?
- That the compiler source is correct
- That the stage-1 build compiled the source consistently (no miscompilation of the compiler by stage 1, and deterministic output) — but not that the source is correct or trojan-free
- That the bootstrap compiler was correct
- Nothing at all
llvm-where-bootstrap · text · 1 pt · 05-bootstrapping-and-trustAccording to llvm/docs/AdvancedBuilds.md (LLVM 23.1.2), which CMake option enables a
multi-stage (bootstrap) clang build?
trusting-trust-triggers · multi · 1 pt · 05-bootstrapping-and-trustWhich behaviors does Thompson's trojaned compiler binary have?
- When compiling login, it inserts a backdoor
- When compiling the compiler's own source, it inserts both triggers into the output
- It modifies the compiler's source file on disk
- It can be found by reading the compiler's source code
trusting-trust-stages · number · 1 pt · 05-bootstrapping-and-trustStarting from a trojaned binary b0 and the CLEAN compiler source, you build b1 = b0(src),
b2 = b1(src), b3 = b2(src). How many of b1, b2, b3 contain the trojan?
ddc-conclusion · single · 1 pt · 05-bootstrapping-and-trustDiverse double-compiling: stage1 = c_T(s_A), stage2 = stage1(s_A), and stage2 is bit-identical
to the compiler binary c_A under test. What follows?
- c_A is correct
- c_A is exactly the faithful self-compilation of s_A, so it contains no trojan absent from s_A — assuming c_T is trustworthy and compilation deterministic
- c_T contains no trojan
- s_A contains no bugs
ddc-determinism · single · 1 pt · 05-bootstrapping-and-trustWhich of these would make DDC report a mismatch even without any trojan?
- The compiler source uses DATE in its version string (and SOURCE_DATE_EPOCH is not set)
- The trusted compiler generates slower code than c_A
- The trusted compiler is from a different vendor
- Stage 1 is larger than c_A
macro-hideset · text · 1 pt · 06-toolchainWith #define X Y + 1 and #define Y X * 2, what does the preprocessor produce for X?
(tokens separated by single spaces)
phase-attribution · mapping · 1 pt · 06-toolchainWhich phase reports or produces each item? Values: preprocess, lex, parse, sema, codegen,
assemble, link, load, run.
A = "fatal error: 'missing.h' file not found"; B = "use of undeclared identifier 'y'";
C = "undefined reference to `sum'"; D = "error while loading shared libraries: libsum.so";
E = "invalid suffix 'x' on integer constant"; F = "Floating point exception" from 10 / z.
A, B, C, D, E, Freloc-value · number · 1 pt · 06-toolchainAn R_X86_64_PLT32 relocation with addend A = −4 is applied at P = 0x1157 for a symbol at
S = 0x1180. What 32-bit value does the linker write (give it in decimal)?
llvm-where-elf-writer · text · 1 pt · 06-toolchainIn llvm/lib/MC/ELFObjectWriter.cpp (LLVM 23.1.2), which type (declared with struct)
computes the symbol table and writes the section headers of an ELF object?
link-errors · single · 1 pt · 06-toolchainmain.c declares int sum(int); and calls it; you run clang main.c -o prog without sum.c.
Which component reports the error?
- The preprocessor
- The compiler's semantic analysis
- The linker, as "undefined reference to `sum'"
- The loader, at run time
loader-exit-127 · single · 1 pt · 06-toolchain./prog2 fails with "error while loading shared libraries: libsum.so: cannot open shared
object file" and exit status 127. Which statement is true?
- The program was linked incorrectly and must be recompiled
- The dynamic linker could not find a NEEDED library at startup; setting LD_LIBRARY_PATH (or a runpath) fixes it
- main returned 127
- libsum.so contains a bug
crt-order · sequence · 1 pt · 06-toolchainOrder these steps of a dynamically linked C program's life: main, _start, exit,
__libc_start_main, init_array, fini_array.
startup-sequence · single · 1 pt · 06-toolchainWhich object file provides _start for clang's default PIE executables on Linux?
- crtbeginS.o
- Scrt1.o
- crti.o
- libc.so.6