Week 2 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 2 spec.
How to use this
Run python tools/test.py --compiler PATH --week 2 -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.
| test | kind | what it checks | bugs known to fail it |
|---|---|---|---|
render/alloc_read_before_write | render | reading an alloc before any store sees zeros | C alloc not zeroed C rank-1 store one elem final version not followed |
render/alloc_scratch | render | a local alloc holds an intermediate, and it starts as zeros | final version not followed |
render/alloc_two_distinct | render | two same-size allocs are separate arrays | C alloc not zeroed C rank-1 store one elem allocs share storage final version not followed |
render/asserts_ignored | render | render ignores asserts and statements the outputs don't need | final version not followed |
render/bool_ops | render | bool xor, where on bools, and bool to i32 | C where swapped final version not followed |
render/call_inlined | render | calls render inline: the body runs on loaded args | C rank-1 store one elem final version not followed |
render/call_nested_closed | render | a nested call's body keeps its own param 0 when inlined | final version not followed top-down inline enters bodies |
render/casts_to_i32_and_bool | render | f32 to i32 truncates, and anything to bool is != 0, nan included | C cast to i32 rounds C rank-1 store one elem final version not followed |
render/copy_scalar | render | the smallest kernel: one load, one store | final version not followed |
render/dynamic_offset_bool | render | a bool-derived offset picks one of two elements | final version not followed |
render/dynamic_offset_store | render | store at a masked loaded offset | final version not followed |
render/f32_chain | render | a longer f32 chain where every intermediate rounds | final version not followed |
render/f32_exact_literals | render | f32 constants need every digit: 1/3 and the largest finite f32 must come out exact | C float literals 6 digits C rank-1 store one elem final version not followed |
render/f32_from_i32_cast | render | i32 to f32 rounds to nearest even, and bool to f32 is 0 or 1 | C cast to i32 rounds final version not followed |
render/f32_max | render | max with nan on either side and both signed-zero orders | C max ignores -0.0 C max ignores nan final version not followed |
render/f32_recip | render | recip of zeros, infinities and a value that rounds | final version not followed |
render/f32_rounding | render | every f32 op rounds; -ffp-contract=off keeps a*b+c from fusing | final version not followed |
render/f32_signed_zero | render | -0.0 survives where it should and doesn't where it shouldn't | final version not followed |
render/f32_specials | render | nan and inf arithmetic | final version not followed |
render/f32_where_cmplt | render | cmplt with nan is false, and where picks a branch | C cmplt as <= C where swapped final version not followed |
render/i32_add_wrap | render | i32 add wraps, and in C that has to go through uint32_t | C plain signed add final version not followed |
render/i32_div_mod_intmin | render | INT_MIN / -1 and INT_MIN % -1 are UB in C; the kernel must not trap | C div without -1 guard C mod without -1 guard final version not followed |
render/i32_div_mod_trunc | render | C division truncates toward zero, and mod takes the dividend's sign | final version not followed |
render/i32_max_cmp_xor | render | max, xor and a cmplt-driven where on i32 edges | C where swapped final version not followed |
render/i32_mul_wrap | render | i32 mul wraps without UB | C plain signed add final version not followed |
render/i32_shl_wrap | render | shl into the sign bit and past it | C plain signed add final version not followed |
render/load_whole_index | render | load a whole buffer and index it | C rank-1 store one elem final version not followed |
render/mixed_dtypes | render | three buffers of different dtypes in one kernel | final version not followed loads not before stores |
render/nested_view_offsets | render | shrink of shrink: offsets add in the C too | C nested offsets lost C rank-1 load no offset C rank-1 store one elem final version not followed |
render/old_version_late_use | render | an old-version load whose value is used two stores later | final version not followed loads not before stores |
render/rank1_copy | render | load a [3] view and store it into another buffer's [3] view | C rank-1 load no offset C rank-1 store one elem final version not followed |
render/rmw_chain | render | three increments of the same element | C plain signed add final version not followed |
render/special_data_copy | render | special float data copies through bit for bit | C rank-1 store one elem final version not followed |
render/stack_index_dynamic | render | index a stack with a loaded index | C rank-1 store one elem final version not followed |
render/store_whole_buffer | render | store a rank-1 value into a whole buffer | C rank-1 store one elem final version not followed |
render/swap_schedule | render | swap: the second store uses a load of the original version, so loads must be scheduled first | final version not followed loads not before stores |
render/unwritten_buffer | render | a buffer the kernel never writes keeps its data | final version not followed |
run/alloc_distinct | run: pass | two allocs of the same size are different memory | alloc not zeroed evaluates everything |
run/alloc_scratch | run: pass | alloc is local scratch that starts as zeros | alloc not zeroed evaluates everything |
run/bounds_bool_offset | run: pass | a bool cast to i32 is in [0, 1], so it can index a 2-element buffer | evaluates everything load ignores the offset |
run/bounds_const_arith_offset | run: pass | constant arithmetic offsets have exact bounds | evaluates everything load ignores the offset |
run/bounds_last_window | run: pass | a [k] view that ends exactly at the end is in bounds | evaluates everything load ignores the offset |
run/bounds_masked_offset | run: pass | a loaded index masked with max and mod is provably in [0, 3] | evaluates everything load ignores the offset |
run/buf_bool | run: pass | bool buffers hold true/false | evaluates everything load ignores the offset xor bool is equality |
run/buf_chain3 | run: pass | three stores in a row, each into the previous version | evaluates everything |
run/buf_data_load | run: pass | data= gives a buffer its initial contents, and a scalar view loads one element | evaluates everything load ignores the offset |
run/buf_f32_rounding | run: pass | f32 data rounds like f32 literals, and stays f32 through memory | evaluates everything f32 consts not rounded f32 ops not rounded load ignores the offset |
run/buf_old_version | run: pass | a load of the old version still sees the old value, even if written after the store in the file | evaluates everything load ignores the offset |
run/buf_rmw | run: pass | read, modify, write back | evaluates everything |
run/buf_store_after | run: pass | after names the version with the store applied | evaluates everything load ignores the offset |
run/buf_versions_differ | run: pass | every version keeps its own contents | evaluates everything |
run/buf_zeros | run: pass | without data=, a buffer starts as zeros of its dtype | evaluates everything |
run/copy_between_buffers | run: pass | load from one buffer, store into another | evaluates everything load ignores the offset rank-1 store writes one |
run/err_after_not_store | run: invalid | the second operand of after must be a store | none recorded |
run/err_after_on_view | run: invalid | after takes a whole buffer version, not a view | none recorded |
run/err_after_stale_version | run: invalid | after names an older version of the right buffer: still wrong | after version unchecked |
run/err_after_wrong_version | run: invalid | after must name the version the store writes into | after version unchecked |
run/err_alloc_slot | run: invalid | alloc has no slot: it isn't an input | unknown attributes ignored |
run/err_bounds_mask_too_wide | run: invalid | masking to [0, 4] doesn't fit a scalar view in a 4-element buffer | bounds off by one bounds unchecked |
run/err_bounds_mod_negative | run: invalid | mod alone keeps the sign, so the offset could be negative | bounds allow negative bounds unchecked mod bounds ignore sign |
run/err_bounds_negative | run: invalid | negative offsets are out of bounds | bounds allow negative bounds unchecked |
run/err_bounds_nested | run: invalid | a nested view must fit its parent view, not just the buffer | bounds off by one bounds unchecked nested view vs storage |
run/err_bounds_past_end | run: invalid | elements 3 and 4 of a 4-element buffer: 4 is past the end | bounds off by one bounds unchecked |
run/err_bounds_raw_loaded | run: invalid | a raw loaded index could be anything, so the view can't be proven in bounds | bounds unchecked |
run/err_bounds_scalar_at_n | run: invalid | element 4 of a 4-element buffer doesn't exist | bounds off by one bounds unchecked |
run/err_bounds_unused | run: invalid | bounds are checked statically, even for a view nothing uses | bounds unchecked |
run/err_buffer_no_dtype | run: invalid | a buffer needs dtype= | none recorded |
run/err_buffer_no_slot | run: invalid | buffer needs slot= | none recorded |
run/err_buffer_size_zero | run: invalid | a buffer has at least one element | none recorded |
run/err_data_dtype | run: invalid | data values must be literals of the buffer's dtype | data dtype unchecked |
run/err_data_length | run: invalid | data= must give exactly n values | data length unchecked |
run/err_duplicate_slot | run: invalid | slots are unique | duplicate slots ok |
run/err_duplicate_slot_identical | run: invalid | two identical buffer statements are still two buffers sharing a slot | duplicate slots ok identical buffers merge |
run/err_load_value | run: invalid | load reads memory, not a value | none recorded |
run/err_mem_alu_operand | run: invalid | memory isn't a value: load it first | none recorded |
run/err_mem_assert | run: invalid | assert compares values, not memory | memory as ALU operand ok |
run/err_mem_call_arg | run: invalid | memory can't be passed to a call | none recorded |
run/err_mem_in_call_body | run: invalid | memory can't be used inside a call body | memory in call body ok |
run/err_mem_stack | run: invalid | memory can't be stacked | memory as ALU operand ok |
run/err_offset_f32 | run: invalid | offsets are i32 | none recorded |
run/err_old_version_needed_late | run: invalid | the offset of a load from the old version depends on the new version: no order works | loads not before stores no ordering cycle check |
run/err_shrink_no_shape | run: invalid | shrink needs shape= | none recorded |
run/err_store_dtype | run: invalid | the stored value must have the view's dtype | store type unchecked |
run/err_store_into_value | run: invalid | store writes into memory, not into a value | none recorded |
run/err_store_shape | run: invalid | the stored value must have the view's shape | store type unchecked |
run/err_two_stores_one_version | run: invalid | two stores into the same version are unordered | two stores per version |
run/err_two_stores_unsequenced_second | run: invalid | a second store into a version is invalid even if only one is sequenced | none recorded |
run/err_unsequenced_store | run: invalid | a store no after sequences has no effect, so it's an error | unsequenced store ok |
run/err_view_alu_operand | run: invalid | a view isn't a value either | memory as ALU operand ok |
run/fail_memory_assert | run: assert_fail | a failing assert on a loaded value | evaluates everything |
run/load_after_values_in_call | run: pass | loaded values (not memory) can be call args | evaluates everything |
run/loaded_div_zero | run: invalid | a runtime error in a value an assert depends on: dividing by a loaded zero | div by zero returns 0 |
run/special_float_data | run: pass | data can hold nan, inf, -inf and -0.0 | -0.0 != 0.0 in assert NaN != NaN in assert evaluates everything load ignores the offset recip 0 ignores sign |
run/swap | run: pass | swap two elements: both loads read the original version | evaluates everything load ignores the offset loads not before stores |
run/unread_store_ok | run: pass | a sequenced store that no assert reads is fine | evaluates everything |
run/view_rank1_load | run: pass | shape=[k] views k elements starting at the offset | evaluates everything load ignores the offset |
run/view_rank1_store | run: pass | store a rank-1 value into a [k] view | evaluates everything rank-1 store writes one |
run/view_shrink_of_shrink | run: pass | offsets add: shrink 1 then shrink 2 lands on element 3 | evaluates everything load ignores the offset shrink offsets don't add |
run/view_shrink_of_shrink_store | run: pass | a store through a nested view writes the right element | evaluates everything shrink offsets don't add |
run/view_whole_load_index | run: pass | load a whole buffer, then index the rank-1 value | evaluates everything |