Theory test — Chapter 22¶
53 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 22 # interactive
./course quiz template 22 -o answers/ch22.yaml # or fill in a file ...
./course quiz grade 22 # ... and grade it
interference-edges · set · 1 pt · 01-the-problemThe running example of Lesson 22.1 (a phi operand from P is used at the end of P):
B0: a = arg
jmp B1
B1: i = phi B0:0 B2:i2
s = phi B0:a B2:s2
c = lt i 10
br c B2 B3
B2: t = mul s i
u = add t a
s2 = xor u i
i2 = add i 1
jmp B1
B3: r = add s a
ret r
Which values interfere with s (Definition 22.1.5)?
dead-def-interferes · single · 1 pt · 01-the-problemIn x = add y z the value x is never used. Which statement is true under Definition
22.1.5?
xinterferes with nothing, because it is never livexinterferes with every value live just after the instruction, because the instruction still writes its registerxinterferes withyandzonlyxinterferes with every value in the function
subreg-alias · single · 1 pt · 01-the-problemOn x86-64, eax is the low half of rax. How does LLVM decide that a value in eax and a
value in rax conflict?
- They are in the same register class
- They share a register unit (TargetRegisterInfo::regunits), and interference is checked per unit
- The coalescer merges them before allocation
- They never conflict: sub-registers are allocated separately
maxlive-classes · mapping · 1 pt · 01-the-problemValues are either i64 (class GPR) or f64 (class FPR):
a:i64 = arg
b:f64 = arg
c:f64 = fmul b b
d:i64 = add a a
e:f64 = fadd c b
f:i64 = fptosi e
g:i64 = add f d
ret g
Give MaxLive per class (Definition 22.1.7, over the definition points of Definition 22.1.4).
GPR, FPRcaller-saved-crossing · set · 1 pt · 01-the-problemB0: x = arg
y = arg
z = mul x y
w = add x 1
call z
v = add w y
ret v
call z clobbers the caller-saved registers. Which values must be spilled or placed in a
callee-saved register (SPEC R4: live across the call and not defined by it)?
regmask-meaning · single · 1 pt · 01-the-problemWhat does a register-mask operand on a call in LLVM MIR express?
- The registers the callee reads as arguments
- The registers preserved by the call; every other register is clobbered
- The registers the allocator may not use anywhere in the function
- The registers that hold the return value
belady-trace · sequence · 1 pt · 02-local-allocationReference string c a b d c b a d c a, K = 2 registers, initially empty. Apply Belady's
MIN (evict the value used furthest in the future; never again = infinitely far). Give the
evicted values in order.
belady-loads · number · 1 pt · 02-local-allocationSame string c a b d c b a d c a, K = 2. How many loads (misses) does MIN need?
fast-backward · text · 1 pt · 02-local-allocationFind it in LLVM: in llvm/lib/CodeGen/RegAllocFast.cpp (llvmorg-23.1.2), which member
function of RegAllocFastImpl allocates one basic block, walking it backwards?
fast-spill-cost · number · 1 pt · 02-local-allocationIn the lab, ch22-regalloc running.ll --function=run --method=local --gpr=3 --metrics
reports the weighted spill cost of local allocation on the running example
(loads and stores weighted by 10^loop depth). What is it?
chaitin-simplify-order · sequence · 1 pt · 03-graph-coloringThe running example's interference graph (Lesson 22.1): edges a–c, a–i, a–i2, a–s, a–s2,
a–t, a–u, c–i, c–s, i–s, i–s2, i–t, i–u, i2–s2; r is isolated. With k = 4, simplify by
repeatedly removing the alphabetically first node of degree < 4 (order: a < c < i < i2
< r < s < s2 < t < u). Give the removal order.
chaitin-spill-choice · text · 1 pt · 03-graph-coloringSame graph with k = 3 and spill costs a 13, i 50, s 21, c/t/u/s2/i2 20, r 2. When
simplification is stuck, Chaitin spills the node with the smallest cost/degree. Which
value is spilled?
simplify-lemma · single · 1 pt · 03-graph-coloringWhy may a node of degree < k be removed during simplification?
- Because it cannot interfere with a spilled node
- Because whatever colours its fewer than k neighbours get, one of the k colours is left for it
- Because nodes of low degree are always cheap to spill
- Because the graph is chordal
briggs-square · mapping · 1 pt · 03-graph-coloringThe square a–b–c–d–a with k = 2. How many values does each allocator actually spill?
Chaitin, Briggsbriggs-never-worse · single · 1 pt · 03-graph-coloringWhy does optimistic colouring never spill more values than Chaitin's allocator on the same graph and costs?
- It uses a better spill metric
- It simplifies in the same order and only postpones the spill decision to select, where a potential spill may still find a colour
- It coalesces more moves
- It colours in dominance order
aggressive-harm · single · 1 pt · 04-coalescingWhat can go wrong when two non-interfering move-related nodes are merged without a test?
- The program computes a different result
- The merged node may have k or more significant neighbours, so a k-colourable graph can become uncolourable and values get spilled
- The copy is executed twice
- Nothing; merging only removes edges
aggressive-llvm · single · 1 pt · 04-coalescingLLVM's RegisterCoalescer coalesces aggressively before allocation. What keeps this from
causing many spills?
- It uses the George test
- Greedy's live-range splitting can split a merged interval again where pressure is high
- It only coalesces copies inside loops
- RegAllocFast runs afterwards
briggs-verdict · mapping · 1 pt · 04-coalescingRunning-example graph (edges as in chaitin-simplify-order). Does the Briggs test
(Definition 22.4.3: the merged node has fewer than k neighbours of degree ≥ k) accept the
move pairs below? Answer yes or no, for k = 3 and for k = 4.
i-i2/k3, s-s2/k3, i-i2/k4, s-s2/k4george-verdict · mapping · 1 pt · 04-coalescingSame graph, k = 3. The George test merges x into y if every neighbour of x interferes with
y or has degree < k (Definition 22.4.5). Answer yes or no.
i2 into i, i into i2, s2 into s, s into s2irc-freeze · single · 1 pt · 04-coalescingWhat does the freeze step of iterated register coalescing do?
- Spills a move-related node
- Gives up coalescing the moves of a low-degree move-related node, so it can be simplified
- Merges all remaining moves aggressively
- Fixes the colours of pre-coloured nodes
irc-moves-k4 · mapping · 1 pt · 04-coalescingRun IRC on the running example with k = 4 (moves: i–i2 and s–s2 from the back-edge phis,
s–a from the entry edge). How does each move end: coalesced, constrained or frozen?
i-i2, s-s2, s-als-spill-running · text · 1 pt · 05-linear-scanPoletto–Sarkar on the running example's hulls a [1,20], i [5,16], s [5,20], c [7,8],
t [11,12], u [13,14], s2 [15,19], i2 [17,19], r [21,22] with K = 3. Intervals with the same
start are handled alphabetically, and when several intervals end furthest, the
alphabetically last one is spilled. Which value is spilled?
ls-no-spill-depth · number · 1 pt · 05-linear-scanWith the same hulls, what is the smallest K for which Poletto–Sarkar spills nothing?
ls-hull-false-conflict · single · 1 pt · 05-linear-scanA value x is live in [2, 6] and [30, 34] (a hole in between); y is live in [10, 20].
What does hull-based linear scan conclude, and which technique avoids it?
- No conflict; nothing to avoid
- A false conflict (hull [2, 34] contains [10, 20]); binpacking into lifetime holes (Traub et al.) lets y use x's register
- A real conflict, so y must be spilled
- A conflict that only coalescing can remove
second-chance-meaning · single · 1 pt · 05-linear-scanIn second-chance binpacking, what is the "second chance"?
- A spilled value is reloaded into a register at its next use and may stay there, instead of living in memory for the rest of its life
- The allocator runs twice
- Every interval is tried with two registers
- A value that fails colouring is retried with linear scan
wm-free-until · mapping · 1 pt · 05-linear-scanWimmer–Mössenböck TryAllocateFreeReg for the interval current = [10, 25] (no holes),
with freeUntil r0 = 12, r1 = 20, r2 = 8. Which register does it take, and before which
position is it split?
register, splitwm-blocked-choice · single · 1 pt · 05-linear-scanIn AllocateBlockedReg (Wimmer–Mössenböck), which register is chosen when all are occupied?
- The register whose occupant has the lowest spill cost
- The register whose next use (by the intervals holding it) is furthest away
- The register with the lowest number
- A callee-saved register
wf-loop-extension · single · 1 pt · 05-linear-scanIn Wimmer–Franz's one-pass interval building on SSA, what happens to a value that is live
at the start of a loop header when the header is processed?
- Its range is extended over the whole contiguous loop, up to the loop's last block
- It is spilled
- The loop is processed a second time
- It is split at the loop header
wf-order · single · 1 pt · 05-linear-scanWhich block order does Wimmer–Franz interval building require?
- Any order
- Every block after its dominator, and the blocks of each loop contiguous
- Postorder
- Blocks sorted by frequency
ssa-chordal-why · single · 1 pt · 06-ssa-based-allocationWhy is the interference graph of a strict SSA program chordal?
- Because SSA programs have no loops
- Because interfering values are ordered by dominance of their definitions, and the reversed dominance order of definitions is a perfect elimination order
- Because phis are removed before allocation
- Because every value has one use
ssa-color-trace · mapping · 1 pt · 06-ssa-based-allocationColour the running example (program in interference-edges) with Algorithm 22.6.6 and
K = 4: blocks in dominator-tree preorder B0, B1, B2, B3; at block entry live-in colours are
taken; phis then each result get the lowest free colour, after releasing the colours of
operands used for the last time at that instruction. Give every value's colour.
a, i, s, c, t, u, s2, i2, rdecoupled-spill-choice · single · 1 pt · 06-ssa-based-allocationWhat does "decoupled" mean in SSA-based allocation?
- Spilling and coalescing run on different threads
- Spilling first reduces the pressure to at most K at every point; colouring then never spills (Theorem 22.6.7)
- Each class is allocated separately
- Spill code is placed after colouring
maxlive-after-spill · set · 1 pt · 06-ssa-based-allocationThe running example has MaxLive 4. Spilling which single value (spill-everywhere, reloads
through a scratch register outside the K) brings MaxLive down to 3?
phi-permutation · number · 1 pt · 06-ssa-based-allocationAfter SSA colouring, the phis of a block require the parallel copy (r0, r1, r2) ← (r1, r2,
r0) on an edge. With one free scratch register, how many moves are needed?
ssa-input-allocator · single · 1 pt · 06-ssa-based-allocationWhich production allocator takes SSA with block parameters as input and emits the phi (block-parameter) moves itself?
- LLVM's greedy allocator
- Cranelift's regalloc2
- GCC's IRA
- HotSpot C2
pbqp-rii-cost · mapping · 1 pt · 07-pbqp-and-ilpPBQP with two choices per node (0, 1). Node u has cost vector (1, 3) and exactly two
neighbours v and w with C_uv = [[∞, 0], [0, ∞]] (u and v interfere) and
C_uw = [[0, 2], [2, 0]] (a copy costing 2 if u and w differ). RII removes u and adds to the
v–w matrix Δ(j, k) = min over i of c_u(i) + C_uv(i, j) + C_uw(i, k). Give Δ.
v0-w0, v0-w1, v1-w0, v1-w1pbqp-ri-exact · single · 1 pt · 07-pbqp-and-ilpWhy is the RI reduction (a node of degree 1) exact?
- Because degree-1 nodes are always spilled
- Because the node's best choice depends only on its neighbour's choice, so folding min over its choices into the neighbour's vector loses nothing
- Because the solver backtracks
- Because the graph is chordal
ilp-constraint · single · 1 pt · 07-pbqp-and-ilpIn the 0-1 ILP of Definition 22.7.6, which constraint forbids two interfering values u, v in the same register r?
- x_{u,r} + x_{v,r} ≤ 1
- x_{u,r} = x_{v,r}
- s_u + s_v ≥ 1
- d_{uv} ≥ x_{u,r} − x_{v,r}
ilp-objective-running · number · 1 pt · 07-pbqp-and-ilpThe ILP of Definition 22.7.6 for the running example with K = 3: spill costs from Lesson
22.3 (a 13, i 50, s 21, others 20, r 2), affinities i–i2 and s–s2 with weight 10 and s–a
with weight 1. What is the optimal objective value HiGHS reports?
appel-george-split · single · 1 pt · 07-pbqp-and-ilpHow do Appel and George make optimal spilling practical?
- They solve colouring by ILP and spill heuristically
- They decide optimally by ILP where each value is in a register or in memory (at most K in registers at each point), then assign registers by coalescing heuristics
- They use PBQP
- They restrict the problem to straight-line code
greedy-stage-order · sequence · 1 pt · 08-llvm-greedyOrder the live-range stages of LLVM's greedy allocator (LiveRangeStage) from first to
last: RS_Spill, RS_New, RS_Split2, RS_Done, RS_Assign, RS_Split.
greedy-cascade · single · 1 pt · 08-llvm-greedyInterval A (cascade 3, weight 8) wants a register held by B (cascade 3, weight 5). May A evict B?
- Yes, because A's weight is higher
- No: an interval may only evict intervals with a strictly lower cascade
- Yes, if B is a spill product
- Only at -O0
find-evict-advisor · text · 1 pt · 08-llvm-greedyFind it in LLVM: which source file in llvm/lib/CodeGen/ (llvmorg-23.1.2) defines
DefaultEvictionAdvisor::canEvictInterferenceBasedOnCost, the rule of Definition 22.8.1?
split-kinds · single · 1 pt · 08-llvm-greedyFor a global live range (spanning several blocks) in stage RS_Split, which split does greedy try first?
- Instruction split
- Region split, using SpillPlacement over edge bundles
- Local split
- Spill everywhere
find-spill-placement · text · 1 pt · 08-llvm-greedyFind it in LLVM: which source file in llvm/lib/CodeGen/ implements the Hopfield-network
analysis that greedy's region splitting uses to decide in which edge bundles a value
should be in a register?
rewriter-identity · single · 1 pt · 08-llvm-greedyAfter allocation, $rax = COPY $rax appears. What does VirtRegRewriter do with it?
- Keeps it for debugging
- Deletes it (or turns it into a KILL when it carries extra liveness information)
- Turns it into a spill
- Asks the allocator to reassign
mcp-forward · single · 1 pt · 08-llvm-greedyAfter allocation, $rcx = COPY $rax is followed by $rdx = ADD64rr $rdx, $rcx and $rcx
is dead afterwards; $rax is not redefined in between. What can MachineCopyPropagation do?
- Nothing: copies are never touched after allocation
- Forward $rax into the ADD's operand and delete the now dead copy
- Replace the ADD by a copy
- Move the copy before the previous definition of $rax
spill-weight-running · number · 1 pt · 09-spilling-and-rematerializationIn the running example with f(B) = 10^loop depth, s has UD = 21 and live segments of
total length 5 slots (two slots per instruction, so 25 instructions = 50 slots). Compute
w(s) = UD / (|s| + 50) to three decimals (Definition 22.9.1, α = 1).
loop-frequency · number · 1 pt · 09-spilling-and-rematerializationA loop is entered from the function entry with probability 3/4, and its back edge is taken
with probability 7/8. What is the relative frequency f(B) of the loop body (per execution of
the entry block)?
remat-when · multi · 1 pt · 09-spilling-and-rematerializationA spilled value x has a use at point p. In which cases may x be recomputed at p
instead of reloaded (Definition 22.9.4, Theorem 22.9.6)?
x = const 42x = add y 4, and y is live at p with the same value it had at x's definitionx = load qfrom memory that a store may modify between x's definition and px = call randx = lea @global
find-remat · text · 1 pt · 09-spilling-and-rematerializationFind it in LLVM: which member function of InlineSpiller (llvm/lib/CodeGen/InlineSpiller.cpp,
llvmorg-23.1.2) tries to rematerialize a spilled value before one instruction instead of
reloading it?
hoist-dp · set · 1 pt · 09-spilling-and-rematerializationDominator tree (block: frequency): r: 1 with children X: 0.8 and Y: 0.2; X has children
X1: 0.3, X2: 0.5, X3: 0.1. The spilled value is defined in r and the initial stores are in
X1, X2 and Y; every block is a candidate. Run Algorithm 22.9.9 with LLVM's margin μ = 0.9
(hoist into n when the subtree's store cost > μ · f(n) if it has several stores, > f(n) if
one). In which blocks are the stores at the end?
go-spill-sink · single · 1 pt · 09-spilling-and-rematerializationIn Go's placeSpills, a value y defined before a loop is restored only in a call block
inside the loop. Where is its spill placed?
- In the call block, next to the restore
- Right after y's definition, because the search does not move a spill into a deeper loop
- At the function entry
- In every predecessor of the call block