Function arguments that don't fit in registers are passed on the stack. Create "incoming_arg" stack slots representing the stack arguments, and assign them to the value arguments during spilling.
124 lines
3.0 KiB
Plaintext
124 lines
3.0 KiB
Plaintext
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+
|
|
|
|
isa riscv 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, $(rlink=$V): i32)
|
|
; 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 = function %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 = function %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 = signature(i32)
|
|
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 = signature(i32, i32)
|
|
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
|
|
}
|