Add a "colocated" flag to symbol references. (#298)

This adds a "colocated" flag to function and symbolic global variables which
indicates that they are defined along with the current function, so they can
use PC-relative addressing.

This also changes the function decl syntax; the name now always precedes the
signature, and the "function" keyword is no longer included.
This commit is contained in:
Dan Gohman
2018-04-13 15:00:09 -07:00
committed by GitHub
parent 645fa3e858
commit 0e57f3d0ea
46 changed files with 312 additions and 164 deletions

View File

@@ -4,7 +4,7 @@ isa riscv
function %RV32I(i32 link [%x1]) -> i32 link [%x1] {
sig0 = ()
fn0 = function %foo()
fn0 = %foo()
ebb0(v9999: i32):
[-,%x10] v1 = iconst.i32 1

View File

@@ -17,8 +17,8 @@ ebb0(v0: i64):
}
function %split_call_arg(i32) {
fn1 = function %foo(i64)
fn2 = function %foo(i32, i64)
fn1 = %foo(i64)
fn2 = %foo(i32, i64)
ebb0(v0: i32):
v1 = uextend.i64 v0
call fn1(v1)
@@ -30,7 +30,7 @@ ebb0(v0: i32):
}
function %split_ret_val() {
fn1 = function %foo() -> i64
fn1 = %foo() -> i64
ebb0:
v1 = call fn1()
; check: ebb0($(link=$V): i32):
@@ -45,7 +45,7 @@ ebb1(v10: i64):
; First return value is fine, second one is expanded.
function %split_ret_val2() {
fn1 = function %foo() -> i32, i64
fn1 = %foo() -> i32, i64
ebb0:
v1, v2 = call fn1()
; check: ebb0($(link=$V): i32):
@@ -70,7 +70,7 @@ ebb0(v1: i8, v2: i8, v3: i8):
; Function produces single return value, still need to copy.
function %ext_ret_val() {
fn1 = function %foo() -> i8 sext
fn1 = %foo() -> i8 sext
ebb0:
v1 = call fn1()
; check: ebb0($V: i32):
@@ -124,7 +124,7 @@ ebb0(v0: i32, v1: f32x2):
; Call a function that takes arguments on the stack.
function %stack_args(i32) {
; check: $(ss0=$SS) = outgoing_arg 4
fn1 = function %foo(i64, i64, i64, i64, i32)
fn1 = %foo(i64, i64, i64, i64, i32)
ebb0(v0: i32):
v1 = iconst.i64 1
call fn1(v1, v1, v1, v1, v0)

View File

@@ -27,9 +27,9 @@ function %parse_encoding(i32 [%x5]) -> i32 [%x10] {
; check: sig5 = () -> f32 [0] system_v
; function + signature
fn0 = function %bar(i32 [%x10]) -> b1 [%x10] system_v
fn0 = %bar(i32 [%x10]) -> b1 [%x10] system_v
; check: sig6 = (i32 [%x10]) -> b1 [%x10] system_v
; nextln: fn0 = sig6 %bar
; nextln: fn0 = %bar sig6
ebb0(v0: i32):
return v0

View File

@@ -2,7 +2,7 @@ test verifier
isa riscv
function %RV32I(i32 link [%x1]) -> i32 link [%x1] {
fn0 = function %foo()
fn0 = %foo()
ebb0(v9999: i32):
; iconst.i32 needs legalizing, so it should throw a
@@ -11,7 +11,7 @@ ebb0(v9999: i32):
}
function %RV32I(i32 link [%x1]) -> i32 link [%x1] {
fn0 = function %foo()
fn0 = %foo()
ebb0(v9999: i32):
v1 = iconst.i32 1

View File

@@ -21,7 +21,7 @@ ebb0:
function %pass_stack_int64(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64 vmctx) spiderwasm {
sig0 = (i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64 vmctx) spiderwasm
fn0 = sig0 u0:0
fn0 = u0:0 sig0
ebb0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64, v6: i64, v7: i64, v8: i64, v9: i64, v10: i64, v11: i64, v12: i64, v13: i64, v14: i64, v15: i64, v16: i64, v17: i64, v18: i64, v19: i64, v20: i64):
call fn0(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20)

View File

@@ -12,7 +12,7 @@ isa x86 haswell
; Tests from binary32.cton affected by allones_funcaddrs.
function %I32() {
sig0 = ()
fn0 = function %foo()
fn0 = %foo()
ebb0:

View File

@@ -13,7 +13,7 @@ isa x86 haswell
; Tests from binary64.cton affected by allones_funcaddrs.
function %I64() {
sig0 = ()
fn0 = function %foo()
fn0 = %foo()
ebb0:

View File

@@ -10,7 +10,7 @@ isa x86 haswell
function %I32() {
sig0 = ()
fn0 = function %foo()
fn0 = %foo()
gv0 = globalsym %some_gv

View File

@@ -13,9 +13,11 @@ isa x86 haswell
; Tests for i64 instructions.
function %I64() {
sig0 = ()
fn0 = function %foo()
fn0 = %foo()
fn1 = colocated %bar()
gv0 = globalsym %some_gv
gv1 = globalsym colocated %some_gv
; Use incoming_arg stack slots because they won't be relocated by the frame
; layout.
@@ -29,6 +31,9 @@ ebb0:
; asm: call foo@PLT
call fn0() ; bin: e8 PLTRel4(%foo-4) 00000000
; asm: call foo
call fn1() ; bin: e8 PCRel4(%bar-4) 00000000
; asm: mov 0x0(%rip), %rax
[-,%rax] v0 = func_addr.i64 fn0 ; bin: 48 8b 05 GOTPCRel4(%foo-4) 00000000
; asm: mov 0x0(%rip), %rsi
@@ -50,5 +55,12 @@ ebb0:
; asm: mov 0x0(%rip), %r10
[-,%r10] v5 = globalsym_addr.i64 gv0 ; bin: 4c 8b 15 GOTPCRel4(%some_gv-4) 00000000
; asm: lea 0x0(%rip), %rcx
[-,%rcx] v6 = globalsym_addr.i64 gv1 ; bin: 48 8d 0d PCRel4(%some_gv-4) 00000000
; asm: lea 0x0(%rip), %rsi
[-,%rsi] v7 = globalsym_addr.i64 gv1 ; bin: 48 8d 35 PCRel4(%some_gv-4) 00000000
; asm: lea 0x0(%rip), %r10
[-,%r10] v8 = globalsym_addr.i64 gv1 ; bin: 4c 8d 15 PCRel4(%some_gv-4) 00000000
return
}

View File

@@ -12,7 +12,7 @@ isa x86 haswell
; Tests for i64 instructions.
function %I64() {
sig0 = ()
fn0 = function %foo()
fn0 = %foo()
gv0 = globalsym %some_gv
@@ -473,12 +473,6 @@ ebb0:
; asm: movzbq %dl, %rsi
[-,%rsi] v351 = bint.i64 v301 ; bin: 0f b6 f2
; TODO: x86-64 can't encode a direct call to an arbitrary 64-bit address in
; a single instruction. When we add a concept of colocated definitions, this
; test can be re-enabled.
; disabled: asm: call foo
; disabled: call fn0() ; bin: e8 PCRel4(%foo-4) 00000000
; asm: movabsq $0, %rcx
[-,%rcx] v400 = func_addr.i64 fn0 ; bin: 48 b9 Abs8(%foo) 0000000000000000
; asm: movabsq $0, %rsi
@@ -713,7 +707,7 @@ ebb0:
; be done by an instruction shrinking pass.
function %I32() {
sig0 = ()
fn0 = function %foo()
fn0 = %foo()
ss0 = incoming_arg 8, offset 0
ss1 = incoming_arg 1024, offset -1024

View File

@@ -12,5 +12,5 @@ ebb0(v0: f32):
}
; check: function %floor(f32 [%xmm0]) -> f32 [%xmm0] system_v {
; check: sig0 = (f32) -> f32 system_v
; check: fn0 = sig0 %FloorF32
; check: fn0 = %FloorF32 sig0
; check: v1 = call fn0(v0)

View File

@@ -45,7 +45,7 @@ ebb0:
; A function performing a call.
function %call() {
fn0 = function %foo()
fn0 = %foo()
ebb0:
call fn0()
@@ -55,7 +55,7 @@ ebb0:
; check: function %call(i64 fp [%rbp]) -> i64 fp [%rbp] system_v {
; nextln: ss0 = incoming_arg 16, offset -16
; nextln: sig0 = () system_v
; nextln: fn0 = sig0 %foo
; nextln: fn0 = %foo sig0
; nextln:
; nextln: ebb0(v0: i64 [%rbp]):
; nextln: x86_push v0

View File

@@ -26,22 +26,22 @@ ebb1:
function %signatures() {
sig10 = ()
sig11 = (i32, f64) -> i32, b1 spiderwasm
fn5 = sig11 %foo
fn8 = function %bar(i32) -> b1
fn5 = %foo sig11
fn8 = %bar(i32) -> b1
}
; sameln: function %signatures() system_v {
; check: sig10 = () system_v
; check: sig11 = (i32, f64) -> i32, b1 spiderwasm
; check: sig12 = (i32) -> b1 system_v
; not: fn0
; check: fn5 = sig11 %foo
; check: fn8 = sig12 %bar
; check: fn5 = %foo sig11
; check: fn8 = %bar sig12
; check: }
function %direct() {
fn0 = function %none()
fn1 = function %one() -> i32
fn2 = function %two() -> i32, f32
fn0 = %none()
fn1 = %one() -> i32
fn2 = %two() -> i32, f32
ebb0:
call fn0()
@@ -72,7 +72,7 @@ ebb0(v0: i64):
function %long_call() {
sig0 = ()
fn0 = sig0 %none
fn0 = %none sig0
ebb0:
v0 = func_addr.i32 fn0

View File

@@ -53,7 +53,7 @@ ebb1(v10: i32):
; Pass an EBB argument as a function argument.
function %callebb(i32, i32) -> i32 {
fn0 = function %foo(i32) -> i32
fn0 = %foo(i32) -> i32
ebb0(v1: i32, v2: i32):
brnz v1, ebb1(v1)
@@ -66,7 +66,7 @@ ebb1(v10: i32):
; Pass an EBB argument as a jump argument.
function %jumpebb(i32, i32) -> i32 {
fn0 = function %foo(i32) -> i32
fn0 = %foo(i32) -> i32
ebb0(v1: i32, v2: i32):
brnz v1, ebb1(v1, v2)

View File

@@ -11,9 +11,9 @@ function %pr207(i64 vmctx, i32, i32) -> i32 system_v {
sig0 = (i64 vmctx, i32, i32) -> i32 system_v
sig1 = (i64 vmctx, i32, i32, i32) -> i32 system_v
sig2 = (i64 vmctx, i32, i32, i32) -> i32 system_v
fn0 = sig0 u0:2
fn1 = sig1 u0:0
fn2 = sig2 u0:1
fn0 = u0:2 sig0
fn1 = u0:0 sig1
fn2 = u0:1 sig2
ebb0(v0: i64, v1: i32, v2: i32):
v3 = iconst.i32 0
@@ -1038,7 +1038,7 @@ function %musl(f64 [%xmm0], i64 vmctx [%rdi]) -> f64 [%xmm0] system_v {
gv0 = vmctx
heap0 = static gv0, min 0, bound 0x0001_0000_0000, guard 0x8000_0000
sig0 = (f64 [%xmm0], i32 [%rdi], i64 vmctx [%rsi]) -> f64 [%xmm0] system_v
fn0 = sig0 u0:517
fn0 = u0:517 sig0
ebb0(v0: f64, v1: i64):
v3 = iconst.i64 0

View File

@@ -16,8 +16,8 @@ function %pr208(i64 vmctx [%rdi]) system_v {
heap0 = static gv0, min 0, bound 0x5000, guard 0x0040_0000
sig0 = (i64 vmctx [%rdi]) -> i32 [%rax] system_v
sig1 = (i64 vmctx [%rdi], i32 [%rsi]) system_v
fn0 = sig0 u0:1
fn1 = sig1 u0:3
fn0 = u0:1 sig0
fn1 = u0:3 sig1
ebb0(v0: i64):
v1 = iconst.i32 0

View File

@@ -5,7 +5,7 @@ isa riscv enable_e
; Check that we can handle a function return value that got spilled.
function %spill_return() -> i32 {
fn0 = function %foo() -> i32 system_v
fn0 = %foo() -> i32 system_v
ebb0:
v0 = call fn0()

View File

@@ -70,7 +70,7 @@ ebb0(v1: i32):
; All values live across a call must be spilled
function %across_call(i32) {
fn0 = function %foo(i32)
fn0 = %foo(i32)
ebb0(v1: i32):
; check: v1 = spill
call fn0(v1)
@@ -83,7 +83,7 @@ ebb0(v1: i32):
; The same value used for two function arguments.
function %doubleuse(i32) {
fn0 = function %xx(i32, i32)
fn0 = %xx(i32, i32)
ebb0(v0: i32):
; check: $(c=$V) = copy v0
call fn0(v0, v0)

View File

@@ -42,14 +42,14 @@ function %type_mismatch_controlling_variable() {
}
function %fn_call_too_few_args() {
fn2 = function %great_fn(i32, f32)
fn2 = %great_fn(i32, f32)
ebb0:
call fn2() ; error: mismatched argument count, got 0, expected 2
return
}
function %fn_call_too_many_args() {
fn5 = function %best_fn()
fn5 = %best_fn()
ebb0:
v0 = iconst.i64 56
v1 = f32const 0.0