Files
wasmtime/filetests/regalloc/spill.cton
Jakob Stoklund Olesen 7f3b807597 Add a calling convention to all function signatures.
A CallConv enum on every function signature makes it possible to
generate calls to functions with different calling conventions within
the same ISA / within a single function.

The calling conventions also serve as a way of customizing Cretonne's
behavior when embedded inside a VM. As an example, the SpiderWASM
calling convention is used to compile WebAssembly functions that run
inside the SpiderMonkey virtual machine.

All function signatures must have a calling convention at the end, so
this changes the textual IL syntax.

Before:

    sig1 = signature(i32, f64) -> f64

After

    sig1 = (i32, f64) -> f64 native
    sig2 = (i32) spiderwasm

When printing functions, the signature goes after the return types:

    function %r1() -> i32, f32 spiderwasm {
    ebb1:
        ...
    }

In the parser, this calling convention is optional and defaults to
"native". This is mostly to avoid updating all the existing test cases
under filetests/. When printing a function, the calling convention is
always included, including for "native" functions.
2017-08-03 11:40:24 -07:00

197 lines
4.9 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 = (i32) native
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) native
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
}
; 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, $(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
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
}