test regalloc ; Test the spiler on an ISA with few registers. ; RV32E has 16 registers, where: ; - %x0 is hardwired to zero. ; - %x1 is the return address. ; - %x2 is the stack pointer. ; - %x3 is the global pointer. ; - %x4 is the thread pointer. ; - %x10-%x15 are function arguments. ; ; regex: V=v\d+ ; regex: WS=\s+ target riscv32 enable_e ; In straight-line code, the first value defined is spilled. ; That is in order: ; 1. The argument v1. ; 2. The link register. ; 3. The first computed value, v2 function %pyramid(i32) -> i32 { ; check: ss0 = spill_slot 4 ; check: ss1 = spill_slot 4 ; check: ss2 = spill_slot 4 ; not: spill_slot ebb0(v1: i32): ; check: ebb0($(rv1=$V): i32 [%x10], $(rlink=$V): i32 [%x1]) ; check: ,ss0]$WS v1 = spill $rv1 ; nextln: ,ss1]$WS $(link=$V) = spill $rlink ; not: spill v2 = iadd_imm v1, 12 ; check: $(r1v2=$V) = iadd_imm ; nextln: ,ss2]$WS v2 = spill $r1v2 ; not: spill v3 = iadd_imm v2, 12 v4 = iadd_imm v3, 12 v5 = iadd_imm v4, 12 v6 = iadd_imm v5, 12 v7 = iadd_imm v6, 12 v8 = iadd_imm v7, 12 v9 = iadd_imm v8, 12 v10 = iadd_imm v9, 12 v11 = iadd_imm v10, 12 v12 = iadd_imm v11, 12 v13 = iadd_imm v12, 12 v14 = iadd_imm v13, 12 v33 = iadd v13, v14 ; check: iadd v13 v32 = iadd v33, v12 v31 = iadd v32, v11 v30 = iadd v31, v10 v29 = iadd v30, v9 v28 = iadd v29, v8 v27 = iadd v28, v7 v26 = iadd v27, v6 v25 = iadd v26, v5 v24 = iadd v25, v4 v23 = iadd v24, v3 v22 = iadd v23, v2 ; check: $(r2v2=$V) = fill v2 ; check: v22 = iadd v23, $r2v2 v21 = iadd v22, v1 ; check: $(r2v1=$V) = fill v1 ; check: v21 = iadd v22, $r2v1 ; check: $(rlink2=$V) = fill $link return v21 ; check: return v21, $rlink2 } ; All values live across a call must be spilled function %across_call(i32) { fn0 = %foo(i32) ebb0(v1: i32): ; check: v1 = spill call fn0(v1) ; check: call fn0 call fn0(v1) ; check: fill v1 ; check: call fn0 return } ; The same value used for two function arguments. function %doubleuse(i32) { fn0 = %xx(i32, i32) ebb0(v0: i32): ; check: $(c=$V) = copy v0 call fn0(v0, v0) ; check: call fn0(v0, $c) return } ; The same value used as indirect callee and argument. function %doubleuse_icall1(i32) { sig0 = (i32) system_v ebb0(v0: i32): ; not:copy call_indirect sig0, v0(v0) return } ; The same value used as indirect callee and two arguments. function %doubleuse_icall2(i32) { sig0 = (i32, i32) system_v ebb0(v0: i32): ; check: $(c=$V) = copy v0 call_indirect sig0, v0(v0, v0) ; check: call_indirect sig0, v0(v0, $c) return } ; Two arguments on the stack. function %stackargs(i32, i32, i32, i32, i32, i32, i32, i32) -> i32 { ; check: ss0 = incoming_arg 4 ; check: ss1 = incoming_arg 4, offset 4 ; not: incoming_arg ebb0(v0: i32, v1: i32, v2: i32, v3: i32, v4: i32, v5: i32, v6: i32, v7: i32): ; unordered: fill v6 ; unordered: fill v7 v10 = iadd v6, v7 return v10 } ; More EBB arguments than registers. function %ebbargs(i32) -> i32 { ebb0(v1: i32): ; check: v1 = spill v2 = iconst.i32 1 jump ebb1(v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2) ebb1(v10: i32, v11: i32, v12: i32, v13: i32, v14: i32, v15: i32, v16: i32, v17: i32, v18: i32, v19: i32, v20: i32, v21: i32): v22 = iadd v10, v11 v23 = iadd v22, v12 v24 = iadd v23, v13 v25 = iadd v24, v14 v26 = iadd v25, v15 v27 = iadd v26, v16 v28 = iadd v27, v17 v29 = iadd v28, v18 v30 = iadd v29, v19 v31 = iadd v30, v20 v32 = iadd v31, v21 v33 = iadd v32, v1 return v33 } ; Spilling an EBB argument to make room for a branch operand. function %brargs(i32) -> i32 { ebb0(v1: i32): ; check: v1 = spill v2 = iconst.i32 1 brnz v1, ebb1(v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2, v2) return v1 ebb1(v10: i32, v11: i32, v12: i32, v13: i32, v14: i32, v15: i32, v16: i32, v17: i32, v18: i32, v19: i32, v20: i32, v21: i32): v22 = iadd v10, v11 v23 = iadd v22, v12 v24 = iadd v23, v13 v25 = iadd v24, v14 v26 = iadd v25, v15 v27 = iadd v26, v16 v28 = iadd v27, v17 v29 = iadd v28, v18 v30 = iadd v29, v19 v31 = iadd v30, v20 v32 = iadd v31, v21 v33 = iadd v32, v1 return v33 } ; In straight-line code, the first value defined is spilled. ; That is in order: ; 1. The argument v1. ; 2. The link register. ; 3. The first computed value, v2 function %use_spilled_value(i32) -> i32 { ; check: ss0 = spill_slot 4 ; check: ss1 = spill_slot 4 ; check: ss2 = spill_slot 4 ebb0(v1: i32): ; check: ebb0($(rv1=$V): i32 [%x10], $(rlink=$V): i32 [%x1]) ; check: ,ss0]$WS v1 = spill $rv1 ; nextln: ,ss1]$WS $(link=$V) = spill $rlink ; not: spill v2 = iadd_imm v1, 12 ; check: $(r1v2=$V) = iadd_imm ; nextln: ,ss2]$WS v2 = spill $r1v2 v3 = iadd_imm v2, 12 v4 = iadd_imm v3, 12 v5 = iadd_imm v4, 12 v6 = iadd_imm v5, 12 v7 = iadd_imm v6, 12 v8 = iadd_imm v7, 12 v9 = iadd_imm v8, 12 v10 = iadd_imm v9, 12 v11 = iadd_imm v10, 12 v12 = iadd_imm v11, 12 v13 = iadd_imm v12, 12 v14 = iadd_imm v13, 12 ; Here we have maximum register pressure, and v2 has been spilled. ; What happens if we use it? v33 = iadd v2, v14 v32 = iadd v33, v12 v31 = iadd v32, v11 v30 = iadd v31, v10 v29 = iadd v30, v9 v28 = iadd v29, v8 v27 = iadd v28, v7 v26 = iadd v27, v6 v25 = iadd v26, v5 v24 = iadd v25, v4 v23 = iadd v24, v3 v22 = iadd v23, v2 v21 = iadd v22, v1 v20 = iadd v21, v13 v19 = iadd v20, v2 return v21 }