Week 3 test guide

A test failed and you don't know why? Find it here: what it checks, and the plausible bugs that are known to fail it. Then read the matching part of the week 3 spec.

How to use this

Run python tools/test.py --compiler PATH --week 3 -v, copy the failing test's name, and search below. "Bugs known to fail it" lists mistakes that were planted in the reference compiler and caught by this test, so one of them is a good first guess. It's not a complete list, and the debugging guide covers what to do when none fit.

testkindwhat it checksbugs known to fail it
render/r_bounds_from_rangesrenderrender version of run/bounds_from_rangesend doesn't close its range
render loop starts at 1
stores under ends unsequenced
values hoisted to outer loops
render/r_computed_boundrenderrender version of run/computed_boundend doesn't close its range
stores under ends unsequenced
render/r_conv1d_i32_pad2renderpadding 2 on i32end doesn't close its range
loads never move into loops
render loop starts at 1
stores under ends unsequenced
values hoisted to outer loops
render/r_conv1d_paddedrendera padded conv1d with masked tapsloads never move into loops
render loop starts at 1
render loop uses <=
values hoisted to outer loops
render/r_conv1d_validrendera valid conv1dloads never move into loops
render/r_conv2d_i32renderan i32 conv2drender loop uses <=
render/r_conv2d_validrendera valid conv2drender loop uses <=
render/r_dynamic_triprendera trip count loaded from memory: the index is masked with mod so the view is provablenone recorded
render/r_gemm_1x5x1rendera dot productnone recorded
render/r_gemm_2x3x2renderlooped matmul in Cnone recorded
render/r_gemm_3x1x4renderan outer product (K = 1)none recorded
render/r_gemm_4x3x5rendera non-square matmulnone recorded
render/r_gemm_f32_roundingrenderf32 accumulation order is exact: products of thirdsnone recorded
render/r_gemm_i32_wraprenderi32 matmul wraps through uint32_t inside loopsnone recorded
render/r_in_loop_after_chainrenderrender version of run/in_loop_after_chainnone recorded
render/r_loop_carried_loadrenderrender version of run/loop_carried_loadnone recorded
render/r_loop_invariant_valuerenderrender version of run/loop_invariant_valuenone recorded
render/r_mixed_dtypes_looprenderone loop writes f32, i32 and bool buffersnone recorded
render/r_multi_effect_endrenderrender version of run/multi_effect_endnone recorded
render/r_negative_triprenderrender version of run/negative_tripnone recorded
render/r_negzero_datarenderdata=[-0.0 0.0] round-trips through a loop: recip of each lands in the output as -inf, infnone recorded
render/r_old_version_after_looprenderrender version of run/old_version_after_loopnone recorded
render/r_prefix_f32renderan f32 running totalnone recorded
render/r_prefix_sumrendera running totalnone recorded
render/r_reduce_max_nanrendera max accumulator meets nannone recorded
render/r_reduce_max_negzerorendermax over -0.0 valuesnone recorded
render/r_reduce_product_wraprenderan i32 product accumulator wrapsnone recorded
render/r_reduce_sum_orderrender1e8 + 1 + -1e8 + 1 sums to 1.0 in f32none recorded
render/r_rowsumrenderrow sumsnone recorded
render/r_skip_middle_rangerenderrender version of run/skip_middle_rangenesting demands every range
render/r_split_use_across_assertsrenderrender must place the load where the whole program says, even though render ignores the assert that pins itloads follow their deepest use
placement sees only the roots
render/r_split_use_loadrenderrender version of run/split_use_loadnone recorded
render/r_three_deeprenderthree nested loops writing a 2x3x2 index cubenone recorded
render/r_transpose_3x4rendertransposenone recorded
render/r_transpose_f32renderf32 transpose keeps -0.0 and nannone recorded
render/r_wrap_in_looprenderadding 2^30 four times wraps through INT_MIN back to 0none recorded
render/r_zero_triprenderrender version of run/zero_tripnone recorded
run/bounds_from_rangesrun: passi*4 + k with i < 3 and k < 4 is provably inside 12 elementsloop runs one extra time
run/computed_boundrun: passa range bound can be any i32 with no open rangesloop runs one extra time
run/conv1d_i32_padded2run: passpadding of 2 on i32loop runs one extra time
run/conv1d_paddedrun: passa padded convolution masks out-of-range taps with where, after clamping the index into a provable rangenone recorded
run/conv1d_validrun: passa valid 1-d convolution: output o sums x[o+k]*w[k]none recorded
run/conv2d_validrun: passa valid 2-d convolution: four nested loopsnone recorded
run/err_after_loop_stale_versionrun: invalidafter names %o, but the loop stores into %o0, the version after the reset: the versions would forknone recorded
run/err_after_wrong_memory_looprun: invalidafter names memory the loop never stores intoafter-on-loop skips memory check
run/err_assert_closed_rangerun: invalidan assert can't read a range even when the range's loop is closed elsewhereasserts may read open ranges
run/err_assert_open_rangerun: invalidan assert can't depend on an open rangenone recorded
run/err_call_open_rangerun: invalida call can't take an argument that depends on an open rangecalls may take open-range args
run/err_end_last_not_rangerun: invalidthe last operand of end must be a rangenone recorded
run/err_end_unused_rangerun: invalidend closes a range its effect doesn't usenone recorded
run/err_end_unused_range_closedrun: invalidend over j repeats a store that doesn't use j. Otherwise j is well formed, so only the 'end must use its range' rule rejects itend need not use its range
run/err_end_value_not_effectrun: invalidend repeats effects, not valuesend accepts values
run/err_loop_never_closedrun: invalida store inside a loop that no end closesunclosed loops allowed
run/err_loop_store_unsequencedrun: invalidthe end runs the store, but no after sequences the loopnone recorded
run/err_memory_in_call_body_looprun: invalida call body can't read memory, even when called from a loopnone recorded
run/err_range_bound_dependsrun: invalida range's bound can't depend on another range (no triangular loops in week 3)bounds may depend on ranges
run/err_range_f32_boundrun: invalida range bound is an i32none recorded
run/err_range_overrunrun: invalidrange 4 indexes a 3-element buffer: offset in [0, 3] can't be proven insiderange interval is [0, 0]
range interval one too tight
run/err_range_two_endsrun: invalida range is closed by exactly one enda range may close twice
run/err_range_value_escapesrun: invalida value that depends on a range can't leak into an assert outside the loopasserts may read open ranges
run/err_two_stores_one_version_looprun: invalidtwo stores into the same version inside one loop body are unorderednone recorded
run/err_wrong_striderun: invalidi*3 + k with k < 4 overruns a 6-element buffer at i=1, k=3range interval is [0, 0]
range interval one too tight
run/gemm_1xKrun: passa 1xK @ Kx1 matmul is a dot productnone recorded
run/gemm_2x3x2run: passmatmul by hand: three loops, an accumulator reset once per output elementnone recorded
run/gemm_Kx1_outerrun: passKx1 @ 1xN with K=1 inner loop is an outer productnone recorded
run/gemm_i32_wraprun: passi32 matmul wraps inside the loopnone recorded
run/gemm_nonsquarerun: pass3x4 @ 4x2none recorded
run/in_loop_after_chainrun: passtwo stores into one element in one iteration: the second reads the first through an after inside the loopnone recorded
run/loop_assert_failrun: assert_failthe loop writes squares, but the assert expects the wrong last valuenone recorded
run/loop_carried_loadrun: passa load whose only use is inside a loop that stores into its version is reloaded every iteration: 10, 11, 12, 13none recorded
run/loop_invariant_valuerun: passa value with no range dependence is the same in every iterationnone recorded
run/loop_runtime_errorrun: invalida division by zero inside a loop an assert depends on is a runtime errornone recorded
run/multi_effect_endrun: passone end can repeat several stores into different buffersnone recorded
run/negative_triprun: passa negative bound also runs zero timeszero-trip loops run once
run/negzero_a_plusrun: passa buffer of +0.0 (parsed before negzero_b_minus, with the same names)none recorded
run/negzero_b_minusrun: passdata=[-0.0] must survive even if an identical buffer of +0.0 was built earlier: recip tells them apartnone recorded
run/old_version_after_looprun: passa load of the pre-loop version, used after the loop, still sees the old contentsnone recorded
run/pinned_load_outsiderun: passthe load's first use (x + 1) doesn't depend on the range, so both run once before the loop: every iteration writes 11none recorded
run/prefix_sumrun: passa running total: two stores per iteration into two different memories, one endloop runs backwards
run/prefix_sum_wraprun: passa running total that wrapsloop runs backwards
run/reduce_max_nanrun: passa max accumulator that meets nan stays nannone recorded
run/reduce_max_plainrun: passa max accumulatornone recorded
run/reduce_product_wraprun: passa product accumulator wraps in i32none recorded
run/reduce_sum_f32_orderrun: passthe sum runs in increasing k: 1e8 + 1 + -1e8 + 1 is 1.0 in f32, not 2.0loop runs backwards
run/rowsum_3x4run: passrow sums: one accumulator per row, reset by a store that depends on the rownone recorded
run/skip_middle_rangerun: passan inner loop inside two loops can ignore the middle range, and it just rerunsnesting demands every range
run/split_use_across_assertsrun: passwhere a load runs depends on every use in the program: the second assert uses %x outside the loop, so the loop sees the pre-loop 10 every time, even while checking the first assert aloneloads follow their deepest use
placement sees only the roots
run/split_use_loadrun: passa load with uses inside and outside the loop runs once, before it: every iteration writes 10 + 1none recorded
run/transpose_2x3run: passtranspose: read row-major, write column-majornone recorded
run/zero_triprun: passrange 0 runs zero times: the buffer keeps its datazero-trip loops run once