Merge branch 'master' into master
This commit is contained in:
@@ -31,7 +31,7 @@ clap = "2.32.0"
|
|||||||
serde = "1.0.8"
|
serde = "1.0.8"
|
||||||
term = "0.5.1"
|
term = "0.5.1"
|
||||||
capstone = { version = "0.5.0", optional = true }
|
capstone = { version = "0.5.0", optional = true }
|
||||||
wabt = { version = "0.5", optional = true }
|
wabt = { version = "0.6", optional = true }
|
||||||
target-lexicon = "0.0.3"
|
target-lexicon = "0.0.3"
|
||||||
pretty_env_logger = "0.2.4"
|
pretty_env_logger = "0.2.4"
|
||||||
file-per-thread-logger = "0.1.1"
|
file-per-thread-logger = "0.1.1"
|
||||||
|
|||||||
36
cranelift/filetests/isa/x86/legalize-byte-ops-i8.clif
Normal file
36
cranelift/filetests/isa/x86/legalize-byte-ops-i8.clif
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
test compile
|
||||||
|
target x86_64
|
||||||
|
|
||||||
|
; regex: V=v\d+
|
||||||
|
|
||||||
|
function u0:0(i8, i8) fast {
|
||||||
|
fn0 = %black_box(i8)
|
||||||
|
ss0 = explicit_slot 1 ; black box
|
||||||
|
|
||||||
|
ebb0(v0: i8, v1: i8):
|
||||||
|
v99 = stack_addr.i64 ss0
|
||||||
|
|
||||||
|
; check: istore8 $(V), $(V)
|
||||||
|
|
||||||
|
v2 = band v0, v1
|
||||||
|
store v2, v99
|
||||||
|
v3 = bor v0, v1
|
||||||
|
store v3, v99
|
||||||
|
v4 = bxor v0, v1
|
||||||
|
store v4, v99
|
||||||
|
v5 = bnot v0
|
||||||
|
store v5, v99
|
||||||
|
v6 = band_not v0, v1
|
||||||
|
store v6, v99
|
||||||
|
v7 = bor_not v0, v1
|
||||||
|
store v7, v99
|
||||||
|
v8 = bxor_not v0, v1
|
||||||
|
store v8, v99
|
||||||
|
v9 = band_imm v0, 42
|
||||||
|
store v9, v99
|
||||||
|
v10 = bor_imm v0, 42
|
||||||
|
store v10, v99
|
||||||
|
v11 = bxor_imm v0, 42
|
||||||
|
store v11, v99
|
||||||
|
return
|
||||||
|
}
|
||||||
19
cranelift/filetests/isa/x86/legalize-icmp-i8.clif
Normal file
19
cranelift/filetests/isa/x86/legalize-icmp-i8.clif
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
test compile
|
||||||
|
target x86_64
|
||||||
|
|
||||||
|
; regex: V=v\d+
|
||||||
|
|
||||||
|
function u0:0(i8, i8) -> i8 fast {
|
||||||
|
ebb0(v0: i8, v1: i8):
|
||||||
|
v2 = icmp_imm sle v0, 0
|
||||||
|
; check: $(e1=$V) = sextend.i32 v0
|
||||||
|
; nextln: v2 = icmp_imm sle $e1, 0
|
||||||
|
v3 = bint.i8 v2
|
||||||
|
v4 = icmp eq v0, v1
|
||||||
|
; check: $(e2=$V) = uextend.i32 v0
|
||||||
|
; nextln: $(e3=$V) = uextend.i32 v1
|
||||||
|
; nextln: v4 = icmp eq $e2, $e3
|
||||||
|
v5 = bint.i8 v4
|
||||||
|
v6 = iadd v3, v5
|
||||||
|
return v6
|
||||||
|
}
|
||||||
24
cranelift/filetests/isa/x86/legalize-shlr-i8.clif
Normal file
24
cranelift/filetests/isa/x86/legalize-shlr-i8.clif
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
test compile
|
||||||
|
target x86_64
|
||||||
|
|
||||||
|
; regex: V=v\d+
|
||||||
|
|
||||||
|
function u0:0(i8, i8) -> i8 fast {
|
||||||
|
ebb0(v0: i8, v1: i8):
|
||||||
|
v2 = ishl v0, v1
|
||||||
|
; check: $(e1=$V) = uextend.i32 v0
|
||||||
|
; check: $(r1=$V) = ishl $e1, v1
|
||||||
|
; check v2 = ireduce.i8 $r1
|
||||||
|
v3 = ushr v0, v1
|
||||||
|
; check: $(e2=$V) = uextend.i32 v0
|
||||||
|
; check: $(r2=$V) = ushr $e2, v1
|
||||||
|
; check v2 = ireduce.i8 $r2
|
||||||
|
v4 = sshr v0, v1
|
||||||
|
; check: $(e3=$V) = sextend.i32 v0
|
||||||
|
; check: $(r3=$V) = sshr $e3, v1
|
||||||
|
; check v2 = ireduce.i8 $r3
|
||||||
|
|
||||||
|
v5 = iadd v2, v3
|
||||||
|
v6 = iadd v4, v5
|
||||||
|
return v6
|
||||||
|
}
|
||||||
15
cranelift/filetests/isa/x86/legalize-urem-i8.clif
Normal file
15
cranelift/filetests/isa/x86/legalize-urem-i8.clif
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
test compile
|
||||||
|
target x86_64
|
||||||
|
|
||||||
|
; regex: V=v\d+
|
||||||
|
|
||||||
|
function u0:0(i8, i8) -> i8 fast {
|
||||||
|
ebb0(v0: i8, v1: i8):
|
||||||
|
v2 = urem v0, v1
|
||||||
|
; check: $(a=$V) = uextend.i32 v0
|
||||||
|
; nextln: $(b=$V) = uextend.i32 v1
|
||||||
|
; nextln: $(c=$V) = iconst.i32 0
|
||||||
|
; nextln: $(V), $(r=$V) = x86_udivmodx $a, $c, $b
|
||||||
|
; nextln: v2 = ireduce.i8 $r
|
||||||
|
return v2
|
||||||
|
}
|
||||||
@@ -6,68 +6,125 @@ ebb0(v0: i8):
|
|||||||
v1 = bitrev.i8 v0
|
v1 = bitrev.i8 v0
|
||||||
return v1
|
return v1
|
||||||
}
|
}
|
||||||
; check: v2 = band_imm v0, 170
|
; check: v16 = uextend.i32 v0
|
||||||
; check: v3 = ushr_imm v2, 1
|
; check: v17 = band_imm v16, 170
|
||||||
; check: v4 = band_imm v0, 85
|
; check: v2 = ireduce.i8 v17
|
||||||
; check: v5 = ishl_imm v4, 1
|
; check: v18 = uextend.i32 v2
|
||||||
; check: v16 = uextend.i32 v3
|
; check: v19 = ushr_imm v18, 1
|
||||||
; check: v17 = uextend.i32 v5
|
; check: v3 = ireduce.i8 v19
|
||||||
; check: v18 = bor v16, v17
|
; check: v20 = uextend.i32 v0
|
||||||
; check: v6 = ireduce.i8 v18
|
; check: v21 = band_imm v20, 85
|
||||||
; check: v7 = band_imm v6, 204
|
; check: v4 = ireduce.i8 v21
|
||||||
; check: v8 = ushr_imm v7, 2
|
; check: v22 = uextend.i32 v4
|
||||||
; check: v9 = band_imm v6, 51
|
; check: v23 = ishl_imm v22, 1
|
||||||
; check: v10 = ushr_imm v9, 2
|
; check: v5 = ireduce.i8 v23
|
||||||
; check: v19 = uextend.i32 v8
|
; check: v24 = uextend.i32 v3
|
||||||
; check: v20 = uextend.i32 v10
|
; check: v25 = uextend.i32 v5
|
||||||
; check: v21 = bor v19, v20
|
; check: v26 = bor v24, v25
|
||||||
; check: v11 = ireduce.i8 v21
|
; check: v6 = ireduce.i8 v26
|
||||||
; check: v12 = band_imm v11, 240
|
; check: v27 = uextend.i32 v6
|
||||||
; check: v13 = ushr_imm v12, 4
|
; check: v28 = band_imm v27, 204
|
||||||
; check: v14 = band_imm v11, 15
|
; check: v7 = ireduce.i8 v28
|
||||||
; check: v15 = ishl_imm v14, 4
|
; check: v29 = uextend.i32 v7
|
||||||
; check: v22 = uextend.i32 v13
|
; check: v30 = ushr_imm v29, 2
|
||||||
; check: v23 = uextend.i32 v15
|
; check: v8 = ireduce.i8 v30
|
||||||
; check: v24 = bor v22, v23
|
; check: v31 = uextend.i32 v6
|
||||||
; check: v1 = ireduce.i8 v24
|
; check: v32 = band_imm v31, 51
|
||||||
|
; check: v9 = ireduce.i8 v32
|
||||||
|
; check: v33 = uextend.i32 v9
|
||||||
|
; check: v34 = ushr_imm v33, 2
|
||||||
|
; check: v10 = ireduce.i8 v34
|
||||||
|
; check: v35 = uextend.i32 v8
|
||||||
|
; check: v36 = uextend.i32 v10
|
||||||
|
; check: v37 = bor v35, v36
|
||||||
|
; check: v11 = ireduce.i8 v37
|
||||||
|
; check: v38 = uextend.i32 v11
|
||||||
|
; check: v39 = band_imm v38, 240
|
||||||
|
; check: v12 = ireduce.i8 v39
|
||||||
|
; check: v40 = uextend.i32 v12
|
||||||
|
; check: v41 = ushr_imm v40, 4
|
||||||
|
; check: v13 = ireduce.i8 v41
|
||||||
|
; check: v42 = uextend.i32 v11
|
||||||
|
; check: v43 = band_imm v42, 15
|
||||||
|
; check: v14 = ireduce.i8 v43
|
||||||
|
; check: v44 = uextend.i32 v14
|
||||||
|
; check: v45 = ishl_imm v44, 4
|
||||||
|
; check: v15 = ireduce.i8 v45
|
||||||
|
; check: v46 = uextend.i32 v13
|
||||||
|
; check: v47 = uextend.i32 v15
|
||||||
|
; check: v48 = bor v46, v47
|
||||||
|
; check: v1 = ireduce.i8 v48
|
||||||
|
; check: return v1
|
||||||
|
|
||||||
function %reverse_bits_16(i16) -> i16 {
|
function %reverse_bits_16(i16) -> i16 {
|
||||||
ebb0(v0: i16):
|
ebb0(v0: i16):
|
||||||
v1 = bitrev.i16 v0
|
v1 = bitrev.i16 v0
|
||||||
return v1
|
return v1
|
||||||
}
|
}
|
||||||
; check: v2 = band_imm v0, 0xaaaa
|
; check: v21 = uextend.i32 v0
|
||||||
; check: v3 = ushr_imm v2, 1
|
; check: v22 = band_imm v21, 0xaaaa
|
||||||
; check: v4 = band_imm v0, 0x5555
|
; check: v2 = ireduce.i16 v22
|
||||||
; check: v5 = ishl_imm v4, 1
|
; check: v23 = uextend.i32 v2
|
||||||
; check: v21 = uextend.i32 v3
|
; check: v24 = ushr_imm v23, 1
|
||||||
; check: v22 = uextend.i32 v5
|
; check: v3 = ireduce.i16 v24
|
||||||
; check: v23 = bor v21, v22
|
; check: v25 = uextend.i32 v0
|
||||||
; check: v6 = ireduce.i16 v23
|
; check: v26 = band_imm v25, 0x5555
|
||||||
; check: v7 = band_imm v6, 0xcccc
|
; check: v4 = ireduce.i16 v26
|
||||||
; check: v8 = ushr_imm v7, 2
|
; check: v27 = uextend.i32 v4
|
||||||
; check: v9 = band_imm v6, 0x3333
|
; check: v28 = ishl_imm v27, 1
|
||||||
; check: v10 = ushr_imm v9, 2
|
; check: v5 = ireduce.i16 v28
|
||||||
; check: v24 = uextend.i32 v8
|
; check: v29 = uextend.i32 v3
|
||||||
; check: v25 = uextend.i32 v10
|
; check: v30 = uextend.i32 v5
|
||||||
; check: v26 = bor v24, v25
|
; check: v31 = bor v29, v30
|
||||||
; check: v11 = ireduce.i16 v26
|
; check: v6 = ireduce.i16 v31
|
||||||
; check: v12 = band_imm v11, 0xf0f0
|
; check: v32 = uextend.i32 v6
|
||||||
; check: v13 = ushr_imm v12, 4
|
; check: v33 = band_imm v32, 0xcccc
|
||||||
; check: v14 = band_imm v11, 3855
|
; check: v7 = ireduce.i16 v33
|
||||||
; check: v15 = ishl_imm v14, 4
|
; check: v34 = uextend.i32 v7
|
||||||
; check: v27 = uextend.i32 v13
|
; check: v35 = ushr_imm v34, 2
|
||||||
; check: v28 = uextend.i32 v15
|
; check: v8 = ireduce.i16 v35
|
||||||
; check: v29 = bor v27, v28
|
; check: v36 = uextend.i32 v6
|
||||||
; check: v16 = ireduce.i16 v29
|
; check: v37 = band_imm v36, 0x3333
|
||||||
; check: v17 = band_imm v16, 0xff00
|
; check: v9 = ireduce.i16 v37
|
||||||
; check: v18 = ushr_imm v17, 8
|
; check: v38 = uextend.i32 v9
|
||||||
; check: v19 = band_imm v16, 255
|
; check: v39 = ushr_imm v38, 2
|
||||||
; check: v20 = ishl_imm v19, 8
|
; check: v10 = ireduce.i16 v39
|
||||||
; check: v30 = uextend.i32 v18
|
; check: v40 = uextend.i32 v8
|
||||||
; check: v31 = uextend.i32 v20
|
; check: v41 = uextend.i32 v10
|
||||||
; check: v32 = bor v30, v31
|
; check: v42 = bor v40, v41
|
||||||
; check: v1 = ireduce.i16 v32
|
; check: v11 = ireduce.i16 v42
|
||||||
|
; check: v43 = uextend.i32 v11
|
||||||
|
; check: v44 = band_imm v43, 0xf0f0
|
||||||
|
; check: v12 = ireduce.i16 v44
|
||||||
|
; check: v45 = uextend.i32 v12
|
||||||
|
; check: v46 = ushr_imm v45, 4
|
||||||
|
; check: v13 = ireduce.i16 v46
|
||||||
|
; check: v47 = uextend.i32 v11
|
||||||
|
; check: v48 = band_imm v47, 3855
|
||||||
|
; check: v14 = ireduce.i16 v48
|
||||||
|
; check: v49 = uextend.i32 v14
|
||||||
|
; check: v50 = ishl_imm v49, 4
|
||||||
|
; check: v15 = ireduce.i16 v50
|
||||||
|
; check: v51 = uextend.i32 v13
|
||||||
|
; check: v52 = uextend.i32 v15
|
||||||
|
; check: v53 = bor v51, v52
|
||||||
|
; check: v16 = ireduce.i16 v53
|
||||||
|
; check: v54 = uextend.i32 v16
|
||||||
|
; check: v55 = band_imm v54, 0xff00
|
||||||
|
; check: v17 = ireduce.i16 v55
|
||||||
|
; check: v56 = uextend.i32 v17
|
||||||
|
; check: v57 = ushr_imm v56, 8
|
||||||
|
; check: v18 = ireduce.i16 v57
|
||||||
|
; check: v58 = uextend.i32 v16
|
||||||
|
; check: v59 = band_imm v58, 255
|
||||||
|
; check: v19 = ireduce.i16 v59
|
||||||
|
; check: v60 = uextend.i32 v19
|
||||||
|
; check: v61 = ishl_imm v60, 8
|
||||||
|
; check: v20 = ireduce.i16 v61
|
||||||
|
; check: v62 = uextend.i32 v18
|
||||||
|
; check: v63 = uextend.i32 v20
|
||||||
|
; check: v64 = bor v62, v63
|
||||||
|
; check: v1 = ireduce.i16 v64
|
||||||
; check: return v1
|
; check: return v1
|
||||||
|
|
||||||
function %reverse_bits_32(i32) -> i32 {
|
function %reverse_bits_32(i32) -> i32 {
|
||||||
|
|||||||
@@ -217,7 +217,7 @@ fn main() {
|
|||||||
rest_cmd.is_present("verbose"),
|
rest_cmd.is_present("verbose"),
|
||||||
&get_vec(rest_cmd.values_of("pass")),
|
&get_vec(rest_cmd.values_of("pass")),
|
||||||
target_val,
|
target_val,
|
||||||
&rest_cmd.value_of("single-file").unwrap().to_string(),
|
rest_cmd.value_of("single-file").unwrap(),
|
||||||
).map(|_time| ())
|
).map(|_time| ())
|
||||||
}
|
}
|
||||||
("print-cfg", Some(rest_cmd)) => {
|
("print-cfg", Some(rest_cmd)) => {
|
||||||
@@ -264,7 +264,7 @@ fn main() {
|
|||||||
|
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
_ => Err(format!("Invalid subcommand.")),
|
_ => Err("Invalid subcommand.".to_owned()),
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(mut msg) = res_util {
|
if let Err(mut msg) = res_util {
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ from .instructions import bitrev
|
|||||||
from cdsl.ast import Var
|
from cdsl.ast import Var
|
||||||
from cdsl.xform import Rtl, XFormGroup
|
from cdsl.xform import Rtl, XFormGroup
|
||||||
|
|
||||||
|
try:
|
||||||
|
from typing import TYPE_CHECKING # noqa
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from cdsl.instructions import Instruction # noqa
|
||||||
|
except ImportError:
|
||||||
|
TYPE_CHECKING = False
|
||||||
|
|
||||||
|
|
||||||
narrow = XFormGroup('narrow', """
|
narrow = XFormGroup('narrow', """
|
||||||
Legalize instructions by narrowing.
|
Legalize instructions by narrowing.
|
||||||
@@ -89,6 +96,7 @@ expand.custom_legalize(insts.stack_store, 'expand_stack_store')
|
|||||||
|
|
||||||
x = Var('x')
|
x = Var('x')
|
||||||
y = Var('y')
|
y = Var('y')
|
||||||
|
z = Var('z')
|
||||||
a = Var('a')
|
a = Var('a')
|
||||||
a1 = Var('a1')
|
a1 = Var('a1')
|
||||||
a2 = Var('a2')
|
a2 = Var('a2')
|
||||||
@@ -174,6 +182,92 @@ narrow.legalize(
|
|||||||
a << iconcat(al, ah)
|
a << iconcat(al, ah)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
def widen_one_arg(signed, op):
|
||||||
|
# type: (bool, Instruction) -> None
|
||||||
|
for int_ty in [types.i8, types.i16]:
|
||||||
|
if signed:
|
||||||
|
widen.legalize(
|
||||||
|
a << op.bind(int_ty)(b),
|
||||||
|
Rtl(
|
||||||
|
x << sextend.i32(b),
|
||||||
|
z << op.i32(x),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
widen.legalize(
|
||||||
|
a << op.bind(int_ty)(b),
|
||||||
|
Rtl(
|
||||||
|
x << uextend.i32(b),
|
||||||
|
z << op.i32(x),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
def widen_two_arg(signed, op):
|
||||||
|
# type: (bool, Instruction) -> None
|
||||||
|
for int_ty in [types.i8, types.i16]:
|
||||||
|
if signed:
|
||||||
|
widen.legalize(
|
||||||
|
a << op.bind(int_ty)(b, c),
|
||||||
|
Rtl(
|
||||||
|
x << sextend.i32(b),
|
||||||
|
y << sextend.i32(c),
|
||||||
|
z << op.i32(x, y),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
widen.legalize(
|
||||||
|
a << op.bind(int_ty)(b, c),
|
||||||
|
Rtl(
|
||||||
|
x << uextend.i32(b),
|
||||||
|
y << uextend.i32(c),
|
||||||
|
z << op.i32(x, y),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
def widen_imm(signed, op):
|
||||||
|
# type: (bool, Instruction) -> None
|
||||||
|
for int_ty in [types.i8, types.i16]:
|
||||||
|
if signed:
|
||||||
|
widen.legalize(
|
||||||
|
a << op.bind(int_ty)(b, c),
|
||||||
|
Rtl(
|
||||||
|
x << sextend.i32(b),
|
||||||
|
z << op.i32(x, c),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
else:
|
||||||
|
widen.legalize(
|
||||||
|
a << op.bind(int_ty)(b, c),
|
||||||
|
Rtl(
|
||||||
|
x << uextend.i32(b),
|
||||||
|
z << op.i32(x, c),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
|
for binop in [iadd, isub, imul, udiv, urem]:
|
||||||
|
widen_two_arg(False, binop)
|
||||||
|
|
||||||
|
widen_two_arg(True, sdiv)
|
||||||
|
|
||||||
|
widen_one_arg(False, bnot)
|
||||||
|
|
||||||
|
for binop in [iadd_imm, imul_imm, udiv_imm, urem_imm]:
|
||||||
|
widen_imm(False, binop)
|
||||||
|
|
||||||
|
for binop in [sdiv_imm, srem_imm]:
|
||||||
|
widen_imm(True, binop)
|
||||||
|
|
||||||
|
# bit ops
|
||||||
|
for binop in [band, bor, bxor, band_not, bor_not, bxor_not]:
|
||||||
|
widen_two_arg(False, binop)
|
||||||
|
|
||||||
|
for binop in [band_imm, bor_imm, bxor_imm]:
|
||||||
|
widen_imm(False, binop)
|
||||||
|
|
||||||
for int_ty in [types.i8, types.i16]:
|
for int_ty in [types.i8, types.i16]:
|
||||||
widen.legalize(
|
widen.legalize(
|
||||||
a << iconst.bind(int_ty)(b),
|
a << iconst.bind(int_ty)(b),
|
||||||
@@ -210,63 +304,6 @@ widen.legalize(
|
|||||||
a << ireduce(b)
|
a << ireduce(b)
|
||||||
))
|
))
|
||||||
|
|
||||||
for binop in [iadd, isub, imul, udiv, band, bor, bxor]:
|
|
||||||
for int_ty in [types.i8, types.i16]:
|
|
||||||
widen.legalize(
|
|
||||||
a << binop.bind(int_ty)(x, y),
|
|
||||||
Rtl(
|
|
||||||
b << uextend.i32(x),
|
|
||||||
c << uextend.i32(y),
|
|
||||||
d << binop(b, c),
|
|
||||||
a << ireduce(d)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for binop in [sdiv]:
|
|
||||||
for int_ty in [types.i8, types.i16]:
|
|
||||||
widen.legalize(
|
|
||||||
a << binop.bind(int_ty)(x, y),
|
|
||||||
Rtl(
|
|
||||||
b << sextend.i32(x),
|
|
||||||
c << sextend.i32(y),
|
|
||||||
d << binop(b, c),
|
|
||||||
a << ireduce(d)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for unop in [bnot]:
|
|
||||||
for int_ty in [types.i8, types.i16]:
|
|
||||||
widen.legalize(
|
|
||||||
a << unop.bind(int_ty)(x),
|
|
||||||
Rtl(
|
|
||||||
b << sextend.i32(x),
|
|
||||||
d << unop(b),
|
|
||||||
a << ireduce(d)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for binop in [iadd_imm, imul_imm, udiv_imm]:
|
|
||||||
for int_ty in [types.i8, types.i16]:
|
|
||||||
widen.legalize(
|
|
||||||
a << binop.bind(int_ty)(x, y),
|
|
||||||
Rtl(
|
|
||||||
b << uextend.i32(x),
|
|
||||||
c << binop(b, y),
|
|
||||||
a << ireduce(c)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for binop in [sdiv_imm]:
|
|
||||||
for int_ty in [types.i8, types.i16]:
|
|
||||||
widen.legalize(
|
|
||||||
a << binop.bind(int_ty)(x, y),
|
|
||||||
Rtl(
|
|
||||||
b << sextend.i32(x),
|
|
||||||
c << binop(b, y),
|
|
||||||
a << ireduce(c)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for int_ty in [types.i8, types.i16]:
|
for int_ty in [types.i8, types.i16]:
|
||||||
widen.legalize(
|
widen.legalize(
|
||||||
br_table.bind(int_ty)(x, y),
|
br_table.bind(int_ty)(x, y),
|
||||||
@@ -285,6 +322,72 @@ for int_ty in [types.i8, types.i16]:
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for int_ty in [types.i8, types.i16]:
|
||||||
|
for op in [ushr_imm, ishl_imm]:
|
||||||
|
widen.legalize(
|
||||||
|
a << op.bind(int_ty)(b, c),
|
||||||
|
Rtl(
|
||||||
|
x << uextend.i32(b),
|
||||||
|
z << op.i32(x, c),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
|
||||||
|
widen.legalize(
|
||||||
|
a << ishl.bind(int_ty)(b, c),
|
||||||
|
Rtl(
|
||||||
|
x << uextend.i32(b),
|
||||||
|
z << ishl.i32(x, c),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
|
||||||
|
widen.legalize(
|
||||||
|
a << ushr.bind(int_ty)(b, c),
|
||||||
|
Rtl(
|
||||||
|
x << uextend.i32(b),
|
||||||
|
z << ushr.i32(x, c),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
|
||||||
|
widen.legalize(
|
||||||
|
a << sshr.bind(int_ty)(b, c),
|
||||||
|
Rtl(
|
||||||
|
x << sextend.i32(b),
|
||||||
|
z << sshr.i32(x, c),
|
||||||
|
a << ireduce.bind(int_ty)(z)
|
||||||
|
))
|
||||||
|
|
||||||
|
for w_cc in [
|
||||||
|
intcc.eq, intcc.ne, intcc.ugt, intcc.ult, intcc.uge, intcc.ule
|
||||||
|
]:
|
||||||
|
widen.legalize(
|
||||||
|
a << insts.icmp_imm.bind(int_ty)(w_cc, b, c),
|
||||||
|
Rtl(
|
||||||
|
x << uextend.i32(b),
|
||||||
|
a << insts.icmp_imm(w_cc, x, c)
|
||||||
|
))
|
||||||
|
widen.legalize(
|
||||||
|
a << insts.icmp.bind(int_ty)(w_cc, b, c),
|
||||||
|
Rtl(
|
||||||
|
x << uextend.i32(b),
|
||||||
|
y << uextend.i32(c),
|
||||||
|
a << insts.icmp.i32(w_cc, x, y)
|
||||||
|
))
|
||||||
|
for w_cc in [intcc.sgt, intcc.slt, intcc.sge, intcc.sle]:
|
||||||
|
widen.legalize(
|
||||||
|
a << insts.icmp_imm.bind(int_ty)(w_cc, b, c),
|
||||||
|
Rtl(
|
||||||
|
x << sextend.i32(b),
|
||||||
|
a << insts.icmp_imm(w_cc, x, c)
|
||||||
|
))
|
||||||
|
widen.legalize(
|
||||||
|
a << insts.icmp.bind(int_ty)(w_cc, b, c),
|
||||||
|
Rtl(
|
||||||
|
x << sextend.i32(b),
|
||||||
|
y << sextend.i32(c),
|
||||||
|
a << insts.icmp(w_cc, x, y)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
# Expand integer operations with carry for RISC architectures that don't have
|
# Expand integer operations with carry for RISC architectures that don't have
|
||||||
# the flags.
|
# the flags.
|
||||||
expand.legalize(
|
expand.legalize(
|
||||||
|
|||||||
@@ -244,7 +244,7 @@ class FieldPredicate(object):
|
|||||||
"""
|
"""
|
||||||
# Prepend `field` to the predicate function arguments.
|
# Prepend `field` to the predicate function arguments.
|
||||||
args = (self.field.rust_name(),) + tuple(map(str, self.args))
|
args = (self.field.rust_name(),) + tuple(map(str, self.args))
|
||||||
return 'predicates::{}({})'.format(self.function, ', '.join(args))
|
return '::predicates::{}({})'.format(self.function, ', '.join(args))
|
||||||
|
|
||||||
|
|
||||||
class IsEqual(FieldPredicate):
|
class IsEqual(FieldPredicate):
|
||||||
|
|||||||
@@ -165,19 +165,18 @@ fn valid_valuedata(data: &ValueData) -> bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Iterator for Values<'a> {
|
impl<'a> Iterator for Values<'a> {
|
||||||
type Item = Value;
|
type Item = Value;
|
||||||
|
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
return self
|
self.inner
|
||||||
.inner
|
|
||||||
.by_ref()
|
.by_ref()
|
||||||
.filter(|kv| valid_valuedata(kv.1))
|
.filter(|kv| valid_valuedata(kv.1))
|
||||||
.next()
|
.next()
|
||||||
.map(|kv| kv.0);
|
.map(|kv| kv.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ use isa;
|
|||||||
use isa::constraints::*;
|
use isa::constraints::*;
|
||||||
use isa::enc_tables::*;
|
use isa::enc_tables::*;
|
||||||
use isa::encoding::RecipeSizing;
|
use isa::encoding::RecipeSizing;
|
||||||
use predicates;
|
|
||||||
|
|
||||||
// Include the generated encoding tables:
|
// Include the generated encoding tables:
|
||||||
// - `LEVEL1_RV32`
|
// - `LEVEL1_RV32`
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ use isa;
|
|||||||
use isa::constraints::*;
|
use isa::constraints::*;
|
||||||
use isa::enc_tables::*;
|
use isa::enc_tables::*;
|
||||||
use isa::encoding::RecipeSizing;
|
use isa::encoding::RecipeSizing;
|
||||||
use predicates;
|
|
||||||
|
|
||||||
include!(concat!(env!("OUT_DIR"), "/encoding-x86.rs"));
|
include!(concat!(env!("OUT_DIR"), "/encoding-x86.rs"));
|
||||||
include!(concat!(env!("OUT_DIR"), "/legalize-x86.rs"));
|
include!(concat!(env!("OUT_DIR"), "/legalize-x86.rs"));
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ pub fn run(verbose: bool, files: &[String]) -> TestResult {
|
|||||||
///
|
///
|
||||||
/// Directories are scanned recursively for test cases ending in `.clif`.
|
/// Directories are scanned recursively for test cases ending in `.clif`.
|
||||||
///
|
///
|
||||||
pub fn run_passes(verbose: bool, passes: &[String], target: &str, file: &String) -> TestResult {
|
pub fn run_passes(verbose: bool, passes: &[String], target: &str, file: &str) -> TestResult {
|
||||||
let mut runner = TestRunner::new(verbose);
|
let mut runner = TestRunner::new(verbose);
|
||||||
|
|
||||||
let path = Path::new(file);
|
let path = Path::new(file);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ readme = "README.md"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
cranelift-codegen = { path = "../codegen", version = "0.22.0", default-features = false }
|
cranelift-codegen = { path = "../codegen", version = "0.22.0", default-features = false }
|
||||||
target-lexicon = { version = "0.0.3", default-features = false }
|
target-lexicon = { version = "0.0.3", default-features = false }
|
||||||
|
log = { version = "0.4.4", default-features = false, features = ["release_max_level_warn"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -179,12 +179,16 @@
|
|||||||
extern crate cranelift_codegen;
|
extern crate cranelift_codegen;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
extern crate target_lexicon;
|
extern crate target_lexicon;
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
pub use frontend::{FunctionBuilder, FunctionBuilderContext};
|
pub use frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
|
pub use switch::Switch;
|
||||||
pub use variable::Variable;
|
pub use variable::Variable;
|
||||||
|
|
||||||
mod frontend;
|
mod frontend;
|
||||||
mod ssa;
|
mod ssa;
|
||||||
|
mod switch;
|
||||||
mod variable;
|
mod variable;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
|
|||||||
350
lib/frontend/src/switch.rs
Normal file
350
lib/frontend/src/switch.rs
Normal file
@@ -0,0 +1,350 @@
|
|||||||
|
use cranelift_codegen::ir::condcodes::IntCC;
|
||||||
|
use cranelift_codegen::ir::*;
|
||||||
|
use frontend::FunctionBuilder;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
type EntryIndex = u64;
|
||||||
|
|
||||||
|
/// Unlike with `br_table`, `Switch` cases may be sparse or non-0-based.
|
||||||
|
/// They emit efficient code using branches, jump tables, or a combination of both.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Switch {
|
||||||
|
cases: HashMap<EntryIndex, Ebb>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Switch {
|
||||||
|
/// Create a new empty switch
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Switch {
|
||||||
|
cases: HashMap::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a switch entry
|
||||||
|
pub fn set_entry(&mut self, index: EntryIndex, ebb: Ebb) {
|
||||||
|
let prev = self.cases.insert(index, ebb);
|
||||||
|
assert!(
|
||||||
|
prev.is_none(),
|
||||||
|
"Tried to set the same entry {} twice",
|
||||||
|
index
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn collect_contiguous_case_ranges(self) -> Vec<(EntryIndex, Vec<Ebb>)> {
|
||||||
|
debug!("build_contiguous_case_ranges before: {:#?}", self.cases);
|
||||||
|
let mut cases = self.cases.into_iter().collect::<Vec<(_, _)>>();
|
||||||
|
cases.sort_by_key(|&(index, _)| index);
|
||||||
|
|
||||||
|
let mut contiguous_case_ranges: Vec<(EntryIndex, Vec<Ebb>)> = vec![];
|
||||||
|
let mut last_index = None;
|
||||||
|
for (index, ebb) in cases {
|
||||||
|
match last_index {
|
||||||
|
None => contiguous_case_ranges.push((index, vec![])),
|
||||||
|
Some(last_index) => {
|
||||||
|
if index > last_index + 1 {
|
||||||
|
contiguous_case_ranges.push((index, vec![]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contiguous_case_ranges.last_mut().unwrap().1.push(ebb);
|
||||||
|
last_index = Some(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
debug!(
|
||||||
|
"build_contiguous_case_ranges after: {:#?}",
|
||||||
|
contiguous_case_ranges
|
||||||
|
);
|
||||||
|
|
||||||
|
contiguous_case_ranges
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_search_tree(
|
||||||
|
bx: &mut FunctionBuilder,
|
||||||
|
val: Value,
|
||||||
|
otherwise: Ebb,
|
||||||
|
contiguous_case_ranges: Vec<(EntryIndex, Vec<Ebb>)>,
|
||||||
|
) -> Vec<(EntryIndex, Ebb, Vec<Ebb>)> {
|
||||||
|
let mut cases_and_jt_ebbs = Vec::new();
|
||||||
|
|
||||||
|
// Avoid allocation in the common case
|
||||||
|
if contiguous_case_ranges.len() <= 3 {
|
||||||
|
Self::build_search_branches(
|
||||||
|
bx,
|
||||||
|
val,
|
||||||
|
otherwise,
|
||||||
|
contiguous_case_ranges,
|
||||||
|
&mut cases_and_jt_ebbs,
|
||||||
|
);
|
||||||
|
return cases_and_jt_ebbs;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut stack: Vec<(Option<Ebb>, Vec<(EntryIndex, Vec<Ebb>)>)> = Vec::new();
|
||||||
|
stack.push((None, contiguous_case_ranges));
|
||||||
|
|
||||||
|
while let Some((ebb, contiguous_case_ranges)) = stack.pop() {
|
||||||
|
if let Some(ebb) = ebb {
|
||||||
|
bx.switch_to_block(ebb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if contiguous_case_ranges.len() <= 3 {
|
||||||
|
Self::build_search_branches(
|
||||||
|
bx,
|
||||||
|
val,
|
||||||
|
otherwise,
|
||||||
|
contiguous_case_ranges,
|
||||||
|
&mut cases_and_jt_ebbs,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let split_point = contiguous_case_ranges.len() / 2;
|
||||||
|
let mut left = contiguous_case_ranges;
|
||||||
|
let right = left.split_off(split_point);
|
||||||
|
|
||||||
|
let left_ebb = bx.create_ebb();
|
||||||
|
let right_ebb = bx.create_ebb();
|
||||||
|
|
||||||
|
let should_take_right_side =
|
||||||
|
bx.ins()
|
||||||
|
.icmp_imm(IntCC::UnsignedGreaterThanOrEqual, val, right[0].0 as i64);
|
||||||
|
bx.ins().brnz(should_take_right_side, right_ebb, &[]);
|
||||||
|
bx.ins().jump(left_ebb, &[]);
|
||||||
|
|
||||||
|
stack.push((Some(left_ebb), left));
|
||||||
|
stack.push((Some(right_ebb), right));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cases_and_jt_ebbs
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_search_branches(
|
||||||
|
bx: &mut FunctionBuilder,
|
||||||
|
val: Value,
|
||||||
|
otherwise: Ebb,
|
||||||
|
contiguous_case_ranges: Vec<(EntryIndex, Vec<Ebb>)>,
|
||||||
|
cases_and_jt_ebbs: &mut Vec<(EntryIndex, Ebb, Vec<Ebb>)>,
|
||||||
|
) {
|
||||||
|
for (first_index, ebbs) in contiguous_case_ranges.into_iter().rev() {
|
||||||
|
if ebbs.len() == 1 {
|
||||||
|
let is_good_val = bx.ins().icmp_imm(IntCC::Equal, val, first_index as i64);
|
||||||
|
bx.ins().brnz(is_good_val, ebbs[0], &[]);
|
||||||
|
} else {
|
||||||
|
let jt_ebb = bx.create_ebb();
|
||||||
|
let is_good_val =
|
||||||
|
bx.ins()
|
||||||
|
.icmp_imm(IntCC::UnsignedGreaterThanOrEqual, val, first_index as i64);
|
||||||
|
bx.ins().brnz(is_good_val, jt_ebb, &[]);
|
||||||
|
cases_and_jt_ebbs.push((first_index, jt_ebb, ebbs));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bx.ins().jump(otherwise, &[]);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_jump_tables(
|
||||||
|
bx: &mut FunctionBuilder,
|
||||||
|
val: Value,
|
||||||
|
otherwise: Ebb,
|
||||||
|
cases_and_jt_ebbs: Vec<(EntryIndex, Ebb, Vec<Ebb>)>,
|
||||||
|
) {
|
||||||
|
for (first_index, jt_ebb, ebbs) in cases_and_jt_ebbs.into_iter().rev() {
|
||||||
|
let mut jt_data = JumpTableData::new();
|
||||||
|
for ebb in ebbs {
|
||||||
|
jt_data.push_entry(ebb);
|
||||||
|
}
|
||||||
|
let jump_table = bx.create_jump_table(jt_data);
|
||||||
|
|
||||||
|
bx.switch_to_block(jt_ebb);
|
||||||
|
let discr = bx.ins().iadd_imm(val, (first_index as i64).wrapping_neg());
|
||||||
|
bx.ins().br_table(discr, jump_table);
|
||||||
|
bx.ins().jump(otherwise, &[]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build the switch
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * The function builder to emit to
|
||||||
|
/// * The value to switch on
|
||||||
|
/// * The default ebb
|
||||||
|
pub fn emit(self, bx: &mut FunctionBuilder, val: Value, otherwise: Ebb) {
|
||||||
|
// FIXME icmp(_imm) doesn't have encodings for i8 and i16 on x86(_64) yet
|
||||||
|
let val = match bx.func.dfg.value_type(val) {
|
||||||
|
types::I8 | types::I16 => bx.ins().uextend(types::I32, val),
|
||||||
|
_ => val,
|
||||||
|
};
|
||||||
|
|
||||||
|
let contiguous_case_ranges = self.collect_contiguous_case_ranges();
|
||||||
|
let cases_and_jt_ebbs = Self::build_search_tree(bx, val, otherwise, contiguous_case_ranges);
|
||||||
|
Self::build_jump_tables(bx, val, otherwise, cases_and_jt_ebbs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use cranelift_codegen::ir::Function;
|
||||||
|
use frontend::FunctionBuilderContext;
|
||||||
|
|
||||||
|
macro_rules! setup {
|
||||||
|
($default:expr, [$($index:expr,)*]) => {{
|
||||||
|
let mut func = Function::new();
|
||||||
|
let mut func_ctx = FunctionBuilderContext::new();
|
||||||
|
{
|
||||||
|
let mut bx = FunctionBuilder::new(&mut func, &mut func_ctx);
|
||||||
|
let ebb = bx.create_ebb();
|
||||||
|
bx.switch_to_block(ebb);
|
||||||
|
let val = bx.ins().iconst(types::I8, 0);
|
||||||
|
let mut switch = Switch::new();
|
||||||
|
$(
|
||||||
|
let ebb = bx.create_ebb();
|
||||||
|
switch.set_entry($index, ebb);
|
||||||
|
)*
|
||||||
|
switch.emit(&mut bx, val, Ebb::with_number($default).unwrap());
|
||||||
|
}
|
||||||
|
func
|
||||||
|
.to_string()
|
||||||
|
.trim_left_matches("function u0:0() fast {\n")
|
||||||
|
.trim_right_matches("\n}\n")
|
||||||
|
.to_string()
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_zero() {
|
||||||
|
let func = setup!(0, [0,]);
|
||||||
|
assert_eq!(
|
||||||
|
func,
|
||||||
|
"ebb0:
|
||||||
|
v0 = iconst.i8 0
|
||||||
|
v1 = uextend.i32 v0
|
||||||
|
v2 = icmp_imm eq v1, 0
|
||||||
|
brnz v2, ebb1
|
||||||
|
jump ebb0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_single() {
|
||||||
|
let func = setup!(0, [1,]);
|
||||||
|
assert_eq!(
|
||||||
|
func,
|
||||||
|
"ebb0:
|
||||||
|
v0 = iconst.i8 0
|
||||||
|
v1 = uextend.i32 v0
|
||||||
|
v2 = icmp_imm eq v1, 1
|
||||||
|
brnz v2, ebb1
|
||||||
|
jump ebb0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_bool() {
|
||||||
|
let func = setup!(0, [0, 1,]);
|
||||||
|
assert_eq!(
|
||||||
|
func,
|
||||||
|
" jt0 = jump_table ebb1, ebb2
|
||||||
|
|
||||||
|
ebb0:
|
||||||
|
v0 = iconst.i8 0
|
||||||
|
v1 = uextend.i32 v0
|
||||||
|
v2 = icmp_imm uge v1, 0
|
||||||
|
brnz v2, ebb3
|
||||||
|
jump ebb0
|
||||||
|
|
||||||
|
ebb3:
|
||||||
|
v3 = iadd_imm.i32 v1, 0
|
||||||
|
br_table v3, jt0
|
||||||
|
jump ebb0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_two_gap() {
|
||||||
|
let func = setup!(0, [0, 2,]);
|
||||||
|
assert_eq!(
|
||||||
|
func,
|
||||||
|
"ebb0:
|
||||||
|
v0 = iconst.i8 0
|
||||||
|
v1 = uextend.i32 v0
|
||||||
|
v2 = icmp_imm eq v1, 2
|
||||||
|
brnz v2, ebb2
|
||||||
|
v3 = icmp_imm eq v1, 0
|
||||||
|
brnz v3, ebb1
|
||||||
|
jump ebb0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_many() {
|
||||||
|
let func = setup!(0, [0, 1, 5, 7, 10, 11, 12,]);
|
||||||
|
assert_eq!(
|
||||||
|
func,
|
||||||
|
" jt0 = jump_table ebb1, ebb2
|
||||||
|
jt1 = jump_table ebb5, ebb6, ebb7
|
||||||
|
|
||||||
|
ebb0:
|
||||||
|
v0 = iconst.i8 0
|
||||||
|
v1 = uextend.i32 v0
|
||||||
|
v2 = icmp_imm uge v1, 7
|
||||||
|
brnz v2, ebb9
|
||||||
|
jump ebb8
|
||||||
|
|
||||||
|
ebb9:
|
||||||
|
v3 = icmp_imm.i32 uge v1, 10
|
||||||
|
brnz v3, ebb10
|
||||||
|
v4 = icmp_imm.i32 eq v1, 7
|
||||||
|
brnz v4, ebb4
|
||||||
|
jump ebb0
|
||||||
|
|
||||||
|
ebb8:
|
||||||
|
v5 = icmp_imm.i32 eq v1, 5
|
||||||
|
brnz v5, ebb3
|
||||||
|
v6 = icmp_imm.i32 uge v1, 0
|
||||||
|
brnz v6, ebb11
|
||||||
|
jump ebb0
|
||||||
|
|
||||||
|
ebb11:
|
||||||
|
v7 = iadd_imm.i32 v1, 0
|
||||||
|
br_table v7, jt0
|
||||||
|
jump ebb0
|
||||||
|
|
||||||
|
ebb10:
|
||||||
|
v8 = iadd_imm.i32 v1, -10
|
||||||
|
br_table v8, jt1
|
||||||
|
jump ebb0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_min_index_value() {
|
||||||
|
let func = setup!(0, [::std::i64::MIN as u64, 1,]);
|
||||||
|
assert_eq!(
|
||||||
|
func,
|
||||||
|
"ebb0:
|
||||||
|
v0 = iconst.i8 0
|
||||||
|
v1 = uextend.i32 v0
|
||||||
|
v2 = icmp_imm eq v1, 0x8000_0000_0000_0000
|
||||||
|
brnz v2, ebb1
|
||||||
|
v3 = icmp_imm eq v1, 1
|
||||||
|
brnz v3, ebb2
|
||||||
|
jump ebb0"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn switch_max_index_value() {
|
||||||
|
let func = setup!(0, [::std::i64::MAX as u64, 1,]);
|
||||||
|
assert_eq!(
|
||||||
|
func,
|
||||||
|
"ebb0:
|
||||||
|
v0 = iconst.i8 0
|
||||||
|
v1 = uextend.i32 v0
|
||||||
|
v2 = icmp_imm eq v1, 0x7fff_ffff_ffff_ffff
|
||||||
|
brnz v2, ebb1
|
||||||
|
v3 = icmp_imm eq v1, 1
|
||||||
|
brnz v3, ebb2
|
||||||
|
jump ebb0"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,7 +21,7 @@ target-lexicon = { version = "0.0.3", default-features = false }
|
|||||||
log = { version = "0.4.4", default-features = false, features = ["release_max_level_warn"] }
|
log = { version = "0.4.4", default-features = false, features = ["release_max_level_warn"] }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wabt = "0.5.0"
|
wabt = "0.6.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
Reference in New Issue
Block a user