Theory test — Chapter 9¶
67 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 9 # interactive
./course quiz template 9 -o answers/ch09.yaml # or fill in a file ...
./course quiz grade 9 # ... and grade it
module-components · set · 1 pt · 01-modules-globals-functionsA module, in full:
target triple = "x86_64-unknown-linux-gnu"
%struct.P = type { i32, i32 }
@g = global i32 0
@s = private unnamed_addr constant [3 x i8] c"hi\00"
@a = alias i32, ptr @g
$grp = comdat any
declare i32 @puts(ptr)
define i32 @main() {
%r = call i32 @puts(ptr @s)
ret i32 %r
}
!llvm.ident = !{!0}
!0 = !{!"hand-written"}
Give the set of global values \(\mathcal{GV}(M)\) of Definition 9.1.1, i.e. the names
in the module's symbol table. Write the names without the @ sigil.
find-undefined-global · text · 1 pt · 01-modules-globals-functionsFind where LLVM does it (Lesson 9.1 §7, llvm/lib/AsmParser/LLParser.cpp). A module
contains call void @nope() in a function body, and @nope is neither declared nor
defined anywhere in the module. Which error message does llvm-as print (quote it without
the file position)?
linkage-resolution · mapping · 1 pt · 01-modules-globals-functionsThree modules are linked in the order m1, m2, m3 (llvm-link m1.ll m2.ll m3.ll),
and a function in m1 loads from all four names, so nothing is dropped as unused.
| name | m1.ll | m2.ll | m3.ll |
|---|---|---|---|
@x | weak global i32 1 | linkonce global i32 2 | external global i32 (declaration) |
@y | common global [2 x i32] zeroinitializer | common global [4 x i32] zeroinitializer | weak global i32 6 |
@z | external global i32 (declaration) | available_externally global i32 3 | linkonce_odr global i32 3 |
@w | global i32 4 (external definition) | weak global i32 5 | common global i32 0 |
Run Algorithm 9.1.4 for each name. Which module's definition does the linked module
keep? Answer x: m1 style.
x, y, z, wlinkage-discardable · set · 1 pt · 01-modules-globals-functionsSix functions, all dso_local, each with a body:
| function | linkage |
|---|---|
f1 | weak |
f2 | linkonce_odr |
f3 | internal |
f4 | external |
f5 | linkonce |
f6 | available_externally |
Which of them may the optimizer both inline into a caller and delete once no
call is left? (Use Definition 9.1.2.)
find-discardable · set · 1 pt · 01-modules-globals-functionsFind where LLVM does it (Lesson 9.1 §7). In llvm/include/llvm/IR/GlobalValue.h,
GlobalValue::isDiscardableIfUnused(LinkageTypes) is a disjunction of three linkage
predicates. Give the set of linkages for which it returns true (spell them as in the
IR, e.g. linkonce_odr).
slot-numbering · mapping · 1 pt · 01-modules-globals-functionsThe parser of LLVM 23 accepts this text (the entry block has no label):
define i32 @f(i32, i32 %y) {
%3 = add i32 %0, %y
%cmp = icmp sgt i32 %3, 0
br i1 %cmp, label %7, label %done
7:
%9 = mul i32 %3, 2
br label %done
done:
%12 = phi i32 [ %3, %1 ], [ %9, %7 ]
ret i32 %12
}
llvm-as | llvm-dis prints it again with Algorithm 9.1.7. Which number does each of the
following get in the printed text? Answer %3: %N style (for the block, 7: N).
%3, 7, %9, %12ssa-def-count · number · 1 pt · 01-modules-globals-functionsA C fragment (all variables are int locals; a, b, c are parameters):
int x = a + b;
x = x * 2;
if (c) x = x - 1;
return x;
After clang -O0 and mem2reg (minimal SSA), how many distinct SSA values stand for
the C variable x, counting phis?
signless-integers · set · 1 pt · 02-type-system-and-data-layoutOperations on i8 values, without flags. For which of them is the result bit pattern
the same whether the operands are read as unsigned or as two's-complement signed numbers
— i.e. which need no signed/unsigned twin?
add, mul, udiv, shl, lshr, xor, icmp ult, trunc to i4, zext to i16
opaque-pointer-consequence · single · 1 pt · 02-type-system-and-data-layoutdefine double @pun(ptr %p) {
%i = load i64, ptr %p
%d = load double, ptr %p
ret double %d
}
What does LLVM 23 say about this function?
- It is rejected:
%pwas first used as a pointer toi64, so loading adoublethrough it needs abitcast. - It is valid: a
ptrhas no pointee type, and eachloadnames the type it reads. - It is valid only if
%pis declaredptr addrspace(0)explicitly. - It is valid, and the type-based alias analysis concludes from the two load types that the loads cannot alias.
struct-layout-x86 · mapping · 1 pt · 02-type-system-and-data-layoutOn x86-64 (target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"):
%T = type { i16, i64, i8, <4 x float>, i8 }
Give the byte offset of each field (f0 … f4), the struct's alloc size (size) and
its ABI alignment (align).
f0, f1, f2, f3, f4, size, alignliteral-vs-identified · number · 1 pt · 02-type-system-and-data-layoutA module declares
%A = type { i32, ptr }
%B = type { i32, ptr }
and its functions use, among others, the types { i32, ptr } (in two different
functions), <{ i32, ptr }> and %A. How many distinct struct type objects does the
context hold for these (Definition 9.2.3 and Algorithm 9.2.4)?
scalable-size · number · 1 pt · 02-type-system-and-data-layoutAn Arm SVE machine has 384-bit vector registers, so vscale = 3 for the whole run.
How many bytes does store <vscale x 2 x double> %v, ptr %p write?
vector-alloc · mapping · 1 pt · 02-type-system-and-data-layoutOn x86-64 (no v96 entry in the data layout), give for <3 x i32> its store size
(store), ABI alignment (align) and alloc size (alloc) in bytes, and the offset of
the vector field in { i8, <3 x i32> } (field).
store, align, alloc, fieldtoken-phi · multi · 1 pt · 02-type-system-and-data-layoutWhich of these are rejected by LLVM 23 (by the parser or by the verifier)?
%t = phi token [ %t1, %entry ], [ %t1, %a ]define void @f(label %l) { ret void }define token @g() { ret token none }define void @h(target("spirv.Image", float, 1, 0, 0, 0, 0, 0, 0) %img) { ret void }%t = select i1 %c, token %t1, token %t1%t = call token @llvm.experimental.convergence.entry()in aconvergentfunction
find-token-check · text · 1 pt · 02-type-system-and-data-layoutFind where LLVM does it (Lesson 9.2 §7). In llvm/lib/IR/Verifier.cpp, the check
that rejects token-typed phis prints "PHI nodes cannot have token type!". In which
Verifier::visit… member function is it?
datalayout-i686 · mapping · 1 pt · 02-type-system-and-data-layoutOn 32-bit x86 Linux the data layout is
"e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128".
%R = type { i16, double, i32, i64 }
Give the byte offsets of the double (d), the i32 (i) and the i64 (q), and
the alloc size of %R (size).
d, i, q, sizedatalayout-default-i64 · mapping · 1 pt · 02-type-system-and-data-layoutWhat is the alloc size in bytes of { i32, i64 } under the empty data layout
(target datalayout absent, all defaults of Definition 9.2.5), and under the x86-64
layout (which contains i64:64)? Answer empty: N and x86_64: N.
empty, x86_64switch-successors · mapping · 1 pt · 03-control-flow-and-ssaentry:
switch i8 %c, label %d [ i8 1, label %a
i8 2, label %b
i8 3, label %a
i8 4, label %d ]
Blocks a, b and d each start with a phi and have no predecessor other than
entry. How many entries ([ v, %entry ] pairs) must each of the three phis have for
the verifier to accept the function?
a, b, dinvoke-normal-edge · set · 1 pt · 03-control-flow-and-ssaentry:
%call = invoke i32 @r(i32 %x) to label %cont unwind label %lpad
cont:
br label %join
lpad:
%lp = landingpad { ptr, i32 } cleanup
br label %join
join:
%p = phi i32 [ %call, %cont ], [ 0, %lpad ]
ret i32 %p
In which of the blocks entry, cont, lpad, join may a non-phi instruction
(say %u = add i32 %call, 1, placed before the block's terminator) use %call?
find-switch-table · text · 1 pt · 03-control-flow-and-ssaFind where LLVM does it (Lesson 9.3 §7). simplifySwitchLookup in
llvm/lib/Transforms/Utils/SimplifyCFG.cpp turns
switch (op) { case 0: return 10; case 1: return 20; case 7: return 30; default: __builtin_unreachable(); }
into a constant table indexed by op. What does the table hold at the indices 2–6,
which no case lists? (One word.)
phi-parallel · mapping · 1 pt · 03-control-flow-and-ssaloop:
%x = phi i32 [ 1, %entry ], [ %y, %loop ]
%y = phi i32 [ 2, %entry ], [ %x, %loop ]
%z = phi i32 [ 0, %entry ], [ %s, %loop ]
%s = add i32 %x, %z
...
br i1 %again, label %loop, label %done
Give the values of %x, %y and %z at the start of the third execution of
loop (the first comes from entry).
x, y, zselect-poison · mapping · 1 pt · 03-control-flow-and-ssaWith %x = add i32 5, 0, what does each select evaluate to? Answer an integer or
poison.
%r1 = select i1 true, i32 %x, i32 poison
%r2 = select i1 poison, i32 1, i32 1
%r3 = select i1 false, i32 %x, i32 poison
%r4 = select i1 true, i32 poison, i32 %x
r1, r2, r3, r4branch-to-select · multi · 1 pt · 03-control-flow-and-ssaA diamond br i1 %c, label %t, label %e joins with %r = phi [ %v, %t ], [ %w, %e ].
Arm %t contains a single instruction computing %v, arm %e just branches with
%w = %x. For which contents of %t may simplifycfg hoist it into the branching
block and replace the phi by select i1 %c, i32 %v, i32 %x (Proposition 9.3.10)?
Nothing is known about %x, %y, %n or %p.
%v = add nsw i32 %x, 1%v = sdiv i32 %x, %y%v = load i32, ptr %p(nothing known about%p)%v = udiv i32 %x, 7%v = call i32 @log_and_get()%v = shl i32 %x, %n
verifier-rule-of-error · mapping · 1 pt · 03-control-flow-and-ssaName the rule of Definition 9.3.4 (W1–W7) that each LLVM 23 message reports:
m1: "Entry block to function must not have predecessors!"m2: "PHI nodes not grouped at top of basic block!"m3: "PHINode should have one entry for each predecessor of its parent basic block!"m4: "Only PHI nodes may reference their own value!"m5: "'%c' defined with type 'i32' but expected 'i1'" (at abr i1 %c, …)m6: "Instruction does not dominate all uses!"
m1, m2, m3, m4, m5, m6dominance-use · set · 1 pt · 03-control-flow-and-ssaCFG (entry A; G has no predecessors and is unreachable):
A -> B, C
B -> D
C -> D
D -> E, F
E -> D
G -> F
%v is defined in D (not as a phi). In which blocks may a non-phi instruction use
%v without violating W6? (For D itself, assume the use comes after the definition.)
find-phi-dup-check · single · 1 pt · 03-control-flow-and-ssaFind where LLVM does it (Lesson 9.3 §7). In llvm/lib/IR/Verifier.cpp, the message
"PHI node has multiple entries for the same basic block with different incoming
values!" is emitted by visitBasicBlock. Which rule of Definition 9.3.4 does it enforce?
- W3: phis come before all other instructions.
- W4: one entry per incoming edge, and entries for the same predecessor carry the same value.
- W6: every use is dominated by its definition.
- W2: the entry block has no predecessors.
promotable-alloca · set · 1 pt · 04-memory-and-addresses@gp = global ptr null
declare void @use(ptr)
define i32 @f(i32 %x, float %y) {
entry:
%a = alloca i32
%b = alloca i32
%c = alloca i32
%d = alloca [2 x i32]
%e = alloca i32
%f = alloca ptr
%h = alloca i32
store i32 %x, ptr %a
%va = load i32, ptr %a
store i32 %x, ptr %b
call void @use(ptr %b)
store volatile i32 %x, ptr %c
%vc = load i32, ptr %c
%d1 = getelementptr [2 x i32], ptr %d, i64 0, i64 1
store i32 %x, ptr %d1
store i32 %x, ptr %e
%ve = load atomic i32, ptr %e monotonic, align 4
store ptr %f, ptr @gp
store float %y, ptr %h
%vh = load i32, ptr %h
...
Which allocas does opt -passes=mem2reg promote to SSA values? (Names without %.)
find-promotable-volatile · single · 1 pt · 04-memory-and-addressesFind where LLVM does it (Lesson 9.4 §7). In
llvm/lib/Transforms/Utils/PromoteMemoryToRegister.cpp, isAllocaPromotable walks the
users of an alloca. What does it do with a volatile load of the alloca?
- Accepts it: the volatile flag is dropped because the slot is private to the function.
- Rejects the alloca:
if (LI->isVolatile()) return false;. - Accepts it but keeps the load, turning only the other accesses into SSA values.
- Accepts it if the load is also
atomic.
hoist-plain-load · mapping · 1 pt · 04-memory-and-addressesint flag, counter; void ext(void); are globals. For each loop, may the compiler replace
the loop's repeated reads of flag by one load before the loop (Proposition 9.4.13)?
Answer yes or no.
w1:while (!flag) {}w2:while (!__atomic_load_n(&flag, __ATOMIC_ACQUIRE)) {}w3:while (!*(volatile int *)&flag) {}w4:while (!flag) { ext(); }w5:while (!flag) { counter++; }
w1, w2, w3, w4, w5seqcst-store-x86 · mapping · 1 pt · 04-memory-and-addressesllc -O1 for x86-64. Which instruction mnemonic implements each operation on
@r (write it without lock prefix or size suffix, e.g. mov)?
rel:store atomic i32 1, ptr @r releasesc:store atomic i32 1, ptr @r seq_cstacq:load atomic i32, ptr @r acquirescl:load atomic i32, ptr @r seq_cstrmw:atomicrmw add ptr @r, i32 1 seq_cst
rel, sc, acq, scl, rmwgep-offset-langref · number · 1 pt · 04-memory-and-addressesWith the LangRef's structs on x86-64 (Lesson 9.4 §3:
%struct.RT = type { i8, [10 x [20 x i32]], i8 }, alloc size 808, field 1 at 4;
%struct.ST = type { i32, double, %struct.RT }, alloc size 824, field 2 at 16),
what byte offset \(\Delta\) does Algorithm 9.4.4 give for
getelementptr %struct.ST, ptr %s, i64 -1, i32 2, i32 1, i64 9, i64 19
gep-leading-zero · multi · 1 pt · 04-memory-and-addresses%s points to a %struct.ST = type { i32, double, %struct.RT } on x86-64 (double at
offset 8). Which instructions compute the same address as the C expression &s->Y
(field 1)?
getelementptr %struct.ST, ptr %s, i32 1getelementptr %struct.ST, ptr %s, i64 0, i32 1getelementptr double, ptr %s, i64 1getelementptr %struct.ST, ptr %s, i64 1, i32 0getelementptr i8, ptr %s, i64 8
gep-canonical-form · mapping · 1 pt · 04-memory-and-addressesOn x86-64, with
%struct.E = type { i16, i32 } ; size 8
%struct.Q = type { i64, [8 x %struct.E] } ; field 1 at 8, size 72
%q = getelementptr inbounds %struct.Q, ptr %p, i64 %i, i32 1, i64 %j
opt -passes=instcombine rewrites %q into three GEPs in byte-offset form
(Algorithm 9.4.9): a scaled piece [n1 x i8] indexed by %i, a constant piece
i8 by c, and a scaled piece [n2 x i8] indexed by %j. Give n1, c and n2.
n1, c, n2gep-inbounds-null · multi · 1 pt · 04-memory-and-addressesWhich of these functions does opt -passes=instcombine fold to ret i1 false?
%q = getelementptr inbounds i8, ptr %p, i64 4·%c = icmp eq ptr %q, null%q = getelementptr i8, ptr %p, i64 4·%c = icmp eq ptr %q, null%q = getelementptr nuw i8, ptr %p, i64 %x·%c = icmp ult ptr %q, %p%q = getelementptr inbounds i8, ptr %p, i64 %x·%c = icmp eq ptr %q, null%q = getelementptr inbounds i8, ptr %p, i64 -4·%c = icmp ugt ptr %q, %p
fptosi-poison · mapping · 1 pt · 04-memory-and-addressesWhat does each cast produce? Answer an integer or poison.
a:fptosi double 3.9e9 to i32b:fptosi double -2.7 to i32c:fptoui double -0.5 to i32d:fptosi double NaN to i32
a, b, c, dtrunc-zext-roundtrip · mapping · 1 pt · 04-memory-and-addresses%x is the i8 with bit pattern 0xC8 (−56 signed, 200 unsigned).
%s = sext i8 %x to i32 and %z = zext i8 %x to i32. What does each trunc produce?
Answer the i8 result as a signed decimal, or poison.
t1:trunc nsw i32 %s to i8t2:trunc nuw i32 %s to i8t3:trunc nuw i32 %z to i8t4:trunc nsw i32 %z to i8
t1, t2, t3, t4vararg-promotion · mapping · 1 pt · 05-calls-attributes-intrinsicsint printf(const char *, ...);
void f(short s, unsigned char uc, float x, _Bool b, long l) {
printf("%hd %hhu %f %d %ld\n", s, uc, x, b, l);
}
clang for x86-64 must apply C's default argument promotions itself (Definition 9.5.2).
Which cast instruction produces each variadic argument of the call? Answer sext,
zext, fpext or none.
s, uc, x, b, lcc-mismatch · single · 1 pt · 05-calls-attributes-intrinsicsdefine fastcc i32 @callee_fast(i32 %x) { ret i32 %x }
define i32 @mismatch(i32 %x) {
%r = call i32 @callee_fast(i32 %x) ; default convention: ccc
ret i32 %r
}
What happens to @mismatch under opt -passes=instcombine?
- The verifier rejects the module: call and callee conventions must match.
- InstCombine adds
fastccto the call, because the callee is known. - InstCombine replaces the call by its unreachable marker (
store i1 true, ptr poison) and the function returnspoison. - Nothing: the mismatch is only diagnosed by
llc.
memory-effects-join · mapping · 1 pt · 05-calls-attributes-intrinsicsRun Algorithm 9.5.5 (as opt -passes=function-attrs does) on
@g = global i32 0
define void @a(ptr %p) {
store i32 0, ptr %p
ret void
}
define i32 @b() {
%v = load i32, ptr @g
ret i32 %v
}
define i32 @c(ptr %p, ptr %q) {
call void @a(ptr %q)
%v = call i32 @b()
ret i32 %v
}
define i32 @d(ptr %p) {
%x = alloca i32
store i32 1, ptr %x
call void @a(ptr %x)
%v = load i32, ptr %x
ret i32 %v
}
Give the access (none, read, write or readwrite) that the inferred memory(…)
allows to argument memory and to other memory, for b, c and d.
b.argmem, b.other, c.argmem, c.other, d.argmem, d.otherfind-memloc · set · 1 pt · 05-calls-attributes-intrinsicsFind where LLVM does it (Lesson 9.5 §7). In llvm/include/llvm/Support/ModRef.h,
list the enumerators of enum class IRMemLocation (without the First/Last helpers),
spelled as in the source.
intrinsic-mangling · mapping · 1 pt · 05-calls-attributes-intrinsicsGive the full mangled name (Definition 9.5.6) of each overloaded intrinsic call:
k1:umul.with.overflowon<4 x i16>operandsk2:memcpyfrom aptr(address space 0) to aptr addrspace(1)with ani32lengthk3:ctpopon<vscale x 2 x i64>k4:fabsondouble
k1, k2, k3, k4find-smul-overflow · single · 1 pt · 05-calls-attributes-intrinsicsFind where LLVM does it (Lesson 9.5 §7). In llvm/include/llvm/IR/Intrinsics.td,
def int_smul_with_overflow : DefaultAttrsIntrinsic<RET, PARAMS>. What is RET?
[llvm_anyint_ty, LLVMScalarOrSameVectorWidth<0, llvm_i1_ty>][llvm_i64_ty, llvm_i1_ty][LLVMMatchType<0>, LLVMMatchType<0>][llvm_anyint_ty]
tbaa-noalias · mapping · 1 pt · 06-metadata-and-representationA front end emits this scalar TBAA tree (every access tag is !{T, T, i64 0} for its
type T):
R (root)
└─ any
├─ int
│ └─ myint
└─ float
R2 (another root)
└─ o
Run Algorithm 9.6.3 on each pair of access types. Answer NoAlias or MayAlias.
q1:myintvsintq2:myintvsfloatq3:intvsfloatq4:anyvsfloatq5:ovsint
q1, q2, q3, q4, q5range-fold · mapping · 1 pt · 06-metadata-and-representationEach function loads %v = load i8, ptr %p, !range !0 with !0 = !{i8 0, i8 5} and
returns one comparison. Does opt -passes=instcombine fold the comparison? Answer
true, false or kept.
c1:icmp ult i8 %v, 10c2:icmp eq i8 %v, 7c3:icmp ult i8 %v, 3c4:icmp sgt i8 %v, -1
c1, c2, c3, c4find-tbaa-root · text · 1 pt · 06-metadata-and-representationFind where LLVM does it (Lesson 9.6 §7). In clang/lib/CodeGen/CodeGenTBAA.cpp, the
root of clang's C/C++ TBAA tree is named "Simple C/C++ TBAA". What is the name of the node
directly under it, from which every scalar C type (int, float, pointers…) descends?
loop-md-distinct · single · 1 pt · 06-metadata-and-representationclang attaches !llvm.loop !5 with !5 = distinct !{!5, !6, !7} to a loop's latch
branch. Why is the node distinct with itself as first operand?
- So that the verifier can find the loop header by following the self-reference.
- So that two loops with identical properties do not share one node: uniqued nodes with equal operands are merged, and updating one loop's properties would change the other's.
- Because metadata cycles are required for the bitcode writer to emit the node before its uses.
- To mark that the loop must be vectorized; a non-distinct node means the hints are optional.
loop-mustprogress · set · 1 pt · 06-metadata-and-representationCompiled as C11 with clang-23 -std=c11 -O0 -S -emit-llvm (ext is an external function):
void l1(int n) { for (int i = 0; i < n; i++) ext(); }
void l2(void) { while (1) ext(); }
void l3(int n) { int i = 0; do { ext(); } while (++i < n); }
void l4(void) { for (;;) ext(); }
Which functions' loops get an !llvm.loop node containing !{!"llvm.loop.mustprogress"}
(Definition 9.6.5)?
debug-records-not-instructions · mapping · 1 pt · 06-metadata-and-representationA basic block contains 5 instructions and, compiled with -g, 3 variable-location
annotations. How many elements does for (Instruction &I : BB) visit when the
annotations are LLVM 23's debug records (records), and how many when they are the old
call void @llvm.dbg.value(…) intrinsics (intrinsics)?
records, intrinsicsdebug-record-values · mapping · 1 pt · 06-metadata-and-representationIn the -O1 -g output of sum_pos (Lesson 9.6 §7, box "Debug records in the running
example"), !23 is the variable s and !24 is i. The loop block is
for.body:
%i.010 = phi i64 [ %inc, %for.body ], [ 0, %entry ]
%s.09 = phi i64 [ %spec.select, %for.body ], [ 0, %entry ]
#dbg_value(i64 %i.010, !24, !DIExpression(), !27)
#dbg_value(i64 %s.09, !23, !DIExpression(), !26)
%arrayidx = getelementptr inbounds nuw [8 x i8], ptr %a, i64 %i.010, !dbg !32
%0 = load i64, ptr %arrayidx, align 8, !dbg !32, !tbaa !34
%add = tail call i64 @llvm.smax.i64(i64 %0, i64 0), !dbg !36
%spec.select = add nuw nsw i64 %add, %s.09, !dbg !36
#dbg_value(i64 %spec.select, !23, !DIExpression(), !26)
%inc = add nuw nsw i64 %i.010, 1, !dbg !37
#dbg_value(i64 %inc, !24, !DIExpression(), !27)
...
Which SSA values does the block say hold s, and which hold i? (Names without %.)
s, ivbr-encode · mapping · 1 pt · 06-metadata-and-representationEncode the value 100 with Algorithm 9.6.7. How many chunks does vbr4 use, and what is
the first emitted chunk as an unsigned number (continuation bit included)? Same for
vbr6.
vbr4_chunks, vbr4_first, vbr6_chunks, vbr6_firstcompat-policy · multi · 1 pt · 06-metadata-and-representationWhich statements are part of LLVM's IR backwards-compatibility policy
(llvm/docs/DeveloperPolicy.md, "IR Backwards Compatibility")?
- The current LLVM version supports loading any bitcode since version 3.0.
- Textual
.llfiles written for LLVM 3.0 are guaranteed to parse with the current version. - Non-debug metadata is defined to be safe to drop, so dropping it is a valid way to upgrade it.
- Bitcode written by the current version can be read by the previous release.
- Newer releases can ignore features from older releases, but they cannot miscompile them.
ub-or-poison · mapping · 1 pt · 07-poison-undef-and-ubFor each i8 instruction with these constant operands, is the result immediate UB,
poison, or a defined value? Answer ub, poison or defined.
a:udiv i8 7, 0b:add nsw i8 127, 1c:shl i8 1, 9d:sdiv i8 -128, -1e:lshr exact i8 5, 1f:add i8 127, 1
a, b, c, d, e, fbranch-on-poison · multi · 1 pt · 07-poison-undef-and-ub%v is an i32 poison value and %c an i1 poison value. Which of these instructions
is immediate UB when executed?
br i1 %c, label %a, label %b%s = select i1 %c, i32 1, i32 2%q = udiv i32 1, %v%r = udiv i32 %v, 7call void @f(i32 noundef %v)store i32 %v, ptr %p(with%pa valid pointer)%k = icmp eq i32 %v, 0
poison-trace · mapping · 1 pt · 07-poison-undef-and-ubEvaluate with Definition 9.7.4 (Algorithm 9.7.5). Answer a number, true/false, or
poison.
%x = add i8 200, 0
%a = add nuw i8 %x, 100
%b = or disjoint i8 12, 3
%c = or disjoint i8 12, 4
%d = select i1 false, i8 %a, i8 %b
%e = mul i8 %c, 0
%f = icmp samesign ult i8 3, 5
%g = zext nneg i8 -3 to i16
a, b, c, d, e, f, gfreeze-sub · mapping · 1 pt · 07-poison-undef-and-ub%p is i8 poison. For each value, answer its number if it is the same for every
choice freeze can make, poison, or depends:
%f = freeze i8 %p
%d = sub i8 %f, %f
%f1 = freeze i8 %p
%f2 = freeze i8 %p
%e = sub i8 %f1, %f2
%g = sub i8 %p, %p
%h = and i8 %f, 0
d, e, g, hundef-twice · mapping · 1 pt · 07-poison-undef-and-ub%u is i8 undef. How many different results can each instruction produce
(Definition 9.7.6)?
add:add i8 %u, %umul:mul i8 %u, 2
add, mulundef-vs-poison · multi · 1 pt · 07-poison-undef-and-ubWhich statements about undef and poison hold in LLVM 23?
and i8 undef, 1can only be 0 or 1, whileand i8 poison, 1is poison.- Replacing a
poisonconstant byundefis a refinement. - Replacing an
undefconstant bypoisonis a refinement. sub i8 %x, %xmay be folded to 0 even if%xmay beundef.freeze i8 undefyields one fixed, arbitrary value that all its uses share.
nsw-fold · mapping · 1 pt · 07-poison-undef-and-ubIs each rewrite (on i8) a correct refinement? Answer valid or invalid.
f1:icmp sgt (add nsw %x, 1), %x→truef2:icmp ugt (add nsw %x, 1), %x→truef3:icmp ugt (add nuw %x, 1), %x→truef4:sdiv (mul nsw %x, 4), 4→%xf5:sdiv (mul %x, 4), 4→%x
f1, f2, f3, f4, f5flags-allowed · mapping · 1 pt · 07-poison-undef-and-ubAlgorithm 9.7.10 on two rewrites (i8). For each target, which flags may it keep so
that it still refines the source? Answer the allowed set as none, nuw, nsw or
both.
r1:or disjoint i8 %x, %y→add i8 %x, %yr2:mul nuw i8 %x, 2→shl i8 %x, 1
r1, r2find-propagates-poison · mapping · 1 pt · 07-poison-undef-and-ubFind where LLVM does it (Lesson 9.7 §7). In llvm/lib/Analysis/ValueTracking.cpp,
propagatesPoison(const Use &PoisonOp) says whether an instruction's result is poison
whenever the given operand is. What does it return (true/false) for:
sel_cond: the condition of aselectsel_arm: the true or false operand of aselectphi: an incoming value of aphifreeze: the operand offreezeicmp: an operand oficmpcall: an argument of a call to an ordinary (non-intrinsic) function
sel_cond, sel_arm, phi, freeze, icmp, callrefinement-direction · multi · 1 pt · 07-poison-undef-and-ubWhich transformations are correct, i.e. the result refines the original
(Definition 9.7.8)? %x, %y are arbitrary i8 values, %c an arbitrary i1.
add nsw i8 %x, %y→add i8 %x, %yadd i8 %x, %y→add nsw i8 %x, %yselect i1 %c, i8 %x, i8 %y→ a diamond that branches on%cand joins with a phi- a
poisonconstant →i8 0 freeze i8 %x→%x%x(as an operand) →freeze i8 %x
blockargs-translate · sequence · 1 pt · 08-ir-comparisonApply Algorithm 9.8.3 (phis to block arguments) to
entry:
br label %loop
loop:
%a = phi i64 [ 0, %entry ], [ %b, %loop ]
%b = phi i64 [ 1, %entry ], [ %sum, %loop ]
%k = phi i64 [ %n, %entry ], [ %k1, %loop ]
%sum = add i64 %a, %b
%k1 = sub i64 %k, 1
%c = icmp eq i64 %k1, 0
br i1 %c, label %exit, label %loop
loop gets the parameters (a, b, k) in phi order. Which arguments does the back edge
loop → loop pass, in order? (Names without %.)
ir-coordinates · mapping · 1 pt · 08-ir-comparisonDefinition 9.8.1's merges coordinate: how does each IR combine values that reach a
join from different paths? Answer phi, blockargs (block parameters/arguments) or
locals (assignments to mutable locals, including Wasm's locals and operand stack).
llvm, gimple, sil, mir, clif, wasm, pir
llvm, gimple, sil, mir, clif, wasm, pirgimple-phi · single · 1 pt · 08-ir-comparisonGCC's -fdump-tree-optimized for sum_pos (Lesson 9.8 §7) contains, at the top of
<bb 4>, the line # s_15 = PHI <s_5(6), 0(3)>. What do (6) and (3) denote?
- The SSA version numbers of the two incoming values.
- The numbers of the predecessor basic blocks from which each value arrives.
- Branch probabilities in tenths.
- The source lines where
swas assigned.
mir-assert · single · 1 pt · 08-ir-comparisonrustc's MIR for sum_pos (Lesson 9.8 §7) contains
assert(move _9, "index out of bounds: the length is {} but the index is {}", copy _5, copy _8) -> [success: bb3, unwind continue];
Which statement is right?
assertis a statement that is removed in release builds (-C opt-level=2), like C'sassert.assertis a terminator: if_9is true control goes tobb3; otherwise the function panics, andunwind continuemeans the unwinding simply continues into the caller because this function has no cleanup to run.unwind continuemeans execution continues atbb3even when the check fails.- It is lowered to
llvm.assume(_9), so LLVM may assume the index is in bounds.
clif-no-poison · mapping · 1 pt · 08-ir-comparisonCranelift compiles these i32 operations (CLIF iadd, udiv, ishl, sdiv, as
translated from the Wasm instructions i32.add, i32.div_u, i32.shl, i32.div_s).
What happens? Answer the result as a signed decimal, or trap.
a: 2147483647 + 1b: 7 ÷ 0 (unsigned)c: 1 shifted left by 33d: −2147483648 ÷ −1 (signed)
a, b, c, dwasm-structured · mapping · 1 pt · 08-ir-comparison(block ;; B
(loop ;; L
...
(br_if 0 (local.get $again)) ;; x
...
(br_if 1 (local.get $done)) ;; y
...
)
(block ;; C
(br 0) ;; z
)
)
Where does each branch go (Definition 9.8.5)? Answer L-start, L-end, B-end or
C-end.
x, y, z