From 813e153d44f1e2adb7fde3b6c78a83cdd0130805 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Wed, 18 Dec 2024 15:37:39 -0800 Subject: [PATCH] pulley: Add branch-with-compare-against-immediate This commit adds a large number of new `br_if_x*` instructions which compare with an immediate instead of comparing two registers. This is pretty common in wasm/compiled code where, for example, loop upper bounds are often constants. This helps compress code slightly while fusing more instructions together. The main cost of this is that the number of opcodes added here is quite large. Like with previous immediate-taking opcodes both 8 and 32-bit variants of immediates are added for all comparisons. Additionally unlike the previous set of branch-and-compare instructions it's required to add instructions for `>` and `>=` because the operands cannot be swapped to invert the condition, further increasing the number of opcodes added. This is a mild size reduction on `spidermonkey.cwasm` from 29M to 28M but it's mostly expected to be a performance win for interpreted loops. --- .../codegen/src/isa/pulley_shared/inst.isle | 22 ++ .../src/isa/pulley_shared/inst/args.rs | 194 +++++++++++++++++- .../codegen/src/isa/pulley_shared/lower.isle | 88 ++++++++ .../filetests/isa/pulley32/brif.clif | 123 +++++++++++ .../filetests/isa/pulley32/trap.clif | 24 +-- .../filetests/isa/pulley64/trap.clif | 24 +-- pulley/src/interp.rs | 104 ++++++++++ pulley/src/lib.rs | 82 ++++++++ tests/disas/pulley/epoch-simple.wat | 2 +- tests/disas/pulley/memory-inbounds.wat | 52 +++-- 10 files changed, 653 insertions(+), 62 deletions(-) diff --git a/cranelift/codegen/src/isa/pulley_shared/inst.isle b/cranelift/codegen/src/isa/pulley_shared/inst.isle index a27d421abd7a..0da137f4aaed 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst.isle +++ b/cranelift/codegen/src/isa/pulley_shared/inst.isle @@ -109,6 +109,17 @@ (IfXult32 (src1 XReg) (src2 XReg)) (IfXulteq32 (src1 XReg) (src2 XReg)) + (IfXeq32I32 (src1 XReg) (src2 i32)) + (IfXneq32I32 (src1 XReg) (src2 i32)) + (IfXslt32I32 (src1 XReg) (src2 i32)) + (IfXslteq32I32 (src1 XReg) (src2 i32)) + (IfXult32I32 (src1 XReg) (src2 u32)) + (IfXulteq32I32 (src1 XReg) (src2 u32)) + (IfXsgt32I32 (src1 XReg) (src2 i32)) + (IfXsgteq32I32 (src1 XReg) (src2 i32)) + (IfXugt32I32 (src1 XReg) (src2 u32)) + (IfXugteq32I32 (src1 XReg) (src2 u32)) + ;; Conditionals for comparing two 64-bit registers. (IfXeq64 (src1 XReg) (src2 XReg)) (IfXneq64 (src1 XReg) (src2 XReg)) @@ -116,6 +127,17 @@ (IfXslteq64 (src1 XReg) (src2 XReg)) (IfXult64 (src1 XReg) (src2 XReg)) (IfXulteq64 (src1 XReg) (src2 XReg)) + + (IfXeq64I32 (src1 XReg) (src2 i32)) + (IfXneq64I32 (src1 XReg) (src2 i32)) + (IfXslt64I32 (src1 XReg) (src2 i32)) + (IfXslteq64I32 (src1 XReg) (src2 i32)) + (IfXult64I32 (src1 XReg) (src2 u32)) + (IfXulteq64I32 (src1 XReg) (src2 u32)) + (IfXsgt64I32 (src1 XReg) (src2 i32)) + (IfXsgteq64I32 (src1 XReg) (src2 i32)) + (IfXugt64I32 (src1 XReg) (src2 u32)) + (IfXugteq64I32 (src1 XReg) (src2 u32)) ) ) diff --git a/cranelift/codegen/src/isa/pulley_shared/inst/args.rs b/cranelift/codegen/src/isa/pulley_shared/inst/args.rs index d28ae9c9d1dc..cb7496336341 100644 --- a/cranelift/codegen/src/isa/pulley_shared/inst/args.rs +++ b/cranelift/codegen/src/isa/pulley_shared/inst/args.rs @@ -255,6 +255,34 @@ impl Cond { collector.reg_use(src1); collector.reg_use(src2); } + + Cond::IfXeq32I32 { src1, src2 } + | Cond::IfXneq32I32 { src1, src2 } + | Cond::IfXslt32I32 { src1, src2 } + | Cond::IfXslteq32I32 { src1, src2 } + | Cond::IfXsgt32I32 { src1, src2 } + | Cond::IfXsgteq32I32 { src1, src2 } + | Cond::IfXeq64I32 { src1, src2 } + | Cond::IfXneq64I32 { src1, src2 } + | Cond::IfXslt64I32 { src1, src2 } + | Cond::IfXslteq64I32 { src1, src2 } + | Cond::IfXsgt64I32 { src1, src2 } + | Cond::IfXsgteq64I32 { src1, src2 } => { + collector.reg_use(src1); + let _: &mut i32 = src2; + } + + Cond::IfXult32I32 { src1, src2 } + | Cond::IfXulteq32I32 { src1, src2 } + | Cond::IfXugt32I32 { src1, src2 } + | Cond::IfXugteq32I32 { src1, src2 } + | Cond::IfXult64I32 { src1, src2 } + | Cond::IfXulteq64I32 { src1, src2 } + | Cond::IfXugt64I32 { src1, src2 } + | Cond::IfXugteq64I32 { src1, src2 } => { + collector.reg_use(src1); + let _: &mut u32 = src2; + } } } @@ -263,7 +291,7 @@ impl Cond { /// Note that the offset encoded to jump by is filled in as 0 and it's /// assumed `MachBuffer` will come back and clean it up. pub fn encode(&self, sink: &mut impl Extend) { - match self { + match *self { Cond::If32 { reg } => encode::br_if32(sink, reg, 0), Cond::IfNot32 { reg } => encode::br_if_not32(sink, reg, 0), Cond::IfXeq32 { src1, src2 } => encode::br_if_xeq32(sink, src1, src2, 0), @@ -278,6 +306,88 @@ impl Cond { Cond::IfXslteq64 { src1, src2 } => encode::br_if_xslteq64(sink, src1, src2, 0), Cond::IfXult64 { src1, src2 } => encode::br_if_xult64(sink, src1, src2, 0), Cond::IfXulteq64 { src1, src2 } => encode::br_if_xulteq64(sink, src1, src2, 0), + + Cond::IfXeq32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xeq32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xeq32_i32(sink, src1, src2, 0), + }, + Cond::IfXneq32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xneq32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xneq32_i32(sink, src1, src2, 0), + }, + Cond::IfXslt32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xslt32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xslt32_i32(sink, src1, src2, 0), + }, + Cond::IfXslteq32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xslteq32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xslteq32_i32(sink, src1, src2, 0), + }, + Cond::IfXsgt32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xsgt32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xsgt32_i32(sink, src1, src2, 0), + }, + Cond::IfXsgteq32I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xsgteq32_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xsgteq32_i32(sink, src1, src2, 0), + }, + Cond::IfXult32I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xult32_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xult32_u32(sink, src1, src2, 0), + }, + Cond::IfXulteq32I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xulteq32_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xulteq32_u32(sink, src1, src2, 0), + }, + Cond::IfXugt32I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xugt32_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xugt32_u32(sink, src1, src2, 0), + }, + Cond::IfXugteq32I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xugteq32_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xugteq32_u32(sink, src1, src2, 0), + }, + + Cond::IfXeq64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xeq64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xeq64_i32(sink, src1, src2, 0), + }, + Cond::IfXneq64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xneq64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xneq64_i32(sink, src1, src2, 0), + }, + Cond::IfXslt64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xslt64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xslt64_i32(sink, src1, src2, 0), + }, + Cond::IfXslteq64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xslteq64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xslteq64_i32(sink, src1, src2, 0), + }, + Cond::IfXsgt64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xsgt64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xsgt64_i32(sink, src1, src2, 0), + }, + Cond::IfXsgteq64I32 { src1, src2 } => match i8::try_from(src2) { + Ok(src2) => encode::br_if_xsgteq64_i8(sink, src1, src2, 0), + Err(_) => encode::br_if_xsgteq64_i32(sink, src1, src2, 0), + }, + Cond::IfXult64I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xult64_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xult64_u32(sink, src1, src2, 0), + }, + Cond::IfXulteq64I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xulteq64_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xulteq64_u32(sink, src1, src2, 0), + }, + Cond::IfXugt64I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xugt64_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xugt64_u32(sink, src1, src2, 0), + }, + Cond::IfXugteq64I32 { src1, src2 } => match u8::try_from(src2) { + Ok(src2) => encode::br_if_xugteq64_u8(sink, src1, src2, 0), + Err(_) => encode::br_if_xugteq64_u32(sink, src1, src2, 0), + }, } } @@ -325,6 +435,28 @@ impl Cond { src1: src2, src2: src1, }, + + Cond::IfXeq32I32 { src1, src2 } => Cond::IfXneq32I32 { src1, src2 }, + Cond::IfXneq32I32 { src1, src2 } => Cond::IfXeq32I32 { src1, src2 }, + Cond::IfXslt32I32 { src1, src2 } => Cond::IfXsgteq32I32 { src1, src2 }, + Cond::IfXslteq32I32 { src1, src2 } => Cond::IfXsgt32I32 { src1, src2 }, + Cond::IfXult32I32 { src1, src2 } => Cond::IfXugteq32I32 { src1, src2 }, + Cond::IfXulteq32I32 { src1, src2 } => Cond::IfXugt32I32 { src1, src2 }, + Cond::IfXsgt32I32 { src1, src2 } => Cond::IfXslteq32I32 { src1, src2 }, + Cond::IfXsgteq32I32 { src1, src2 } => Cond::IfXslt32I32 { src1, src2 }, + Cond::IfXugt32I32 { src1, src2 } => Cond::IfXulteq32I32 { src1, src2 }, + Cond::IfXugteq32I32 { src1, src2 } => Cond::IfXult32I32 { src1, src2 }, + + Cond::IfXeq64I32 { src1, src2 } => Cond::IfXneq64I32 { src1, src2 }, + Cond::IfXneq64I32 { src1, src2 } => Cond::IfXeq64I32 { src1, src2 }, + Cond::IfXslt64I32 { src1, src2 } => Cond::IfXsgteq64I32 { src1, src2 }, + Cond::IfXslteq64I32 { src1, src2 } => Cond::IfXsgt64I32 { src1, src2 }, + Cond::IfXult64I32 { src1, src2 } => Cond::IfXugteq64I32 { src1, src2 }, + Cond::IfXulteq64I32 { src1, src2 } => Cond::IfXugt64I32 { src1, src2 }, + Cond::IfXsgt64I32 { src1, src2 } => Cond::IfXslteq64I32 { src1, src2 }, + Cond::IfXsgteq64I32 { src1, src2 } => Cond::IfXslt64I32 { src1, src2 }, + Cond::IfXugt64I32 { src1, src2 } => Cond::IfXulteq64I32 { src1, src2 }, + Cond::IfXugteq64I32 { src1, src2 } => Cond::IfXult64I32 { src1, src2 }, } } } @@ -370,6 +502,66 @@ impl fmt::Display for Cond { Cond::IfXulteq64 { src1, src2 } => { write!(f, "if_xulteq64 {}, {}", reg_name(**src1), reg_name(**src2)) } + Cond::IfXeq32I32 { src1, src2 } => { + write!(f, "if_xeq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXneq32I32 { src1, src2 } => { + write!(f, "if_xneq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXslt32I32 { src1, src2 } => { + write!(f, "if_xslt32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXslteq32I32 { src1, src2 } => { + write!(f, "if_xslteq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXsgt32I32 { src1, src2 } => { + write!(f, "if_xsgt32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXsgteq32I32 { src1, src2 } => { + write!(f, "if_xsgteq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXult32I32 { src1, src2 } => { + write!(f, "if_xult32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXulteq32I32 { src1, src2 } => { + write!(f, "if_xulteq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXugt32I32 { src1, src2 } => { + write!(f, "if_xugt32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXugteq32I32 { src1, src2 } => { + write!(f, "if_xugteq32_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXeq64I32 { src1, src2 } => { + write!(f, "if_xeq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXneq64I32 { src1, src2 } => { + write!(f, "if_xneq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXslt64I32 { src1, src2 } => { + write!(f, "if_xslt64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXslteq64I32 { src1, src2 } => { + write!(f, "if_xslteq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXsgt64I32 { src1, src2 } => { + write!(f, "if_xsgt64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXsgteq64I32 { src1, src2 } => { + write!(f, "if_xsgteq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXult64I32 { src1, src2 } => { + write!(f, "if_xult64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXulteq64I32 { src1, src2 } => { + write!(f, "if_xulteq64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXugt64I32 { src1, src2 } => { + write!(f, "if_xugt64_i32 {}, {src2}", reg_name(**src1)) + } + Cond::IfXugteq64I32 { src1, src2 } => { + write!(f, "if_xugteq64_i32 {}, {src2}", reg_name(**src1)) + } } } } diff --git a/cranelift/codegen/src/isa/pulley_shared/lower.isle b/cranelift/codegen/src/isa/pulley_shared/lower.isle index 5b14f38fc01b..03bacddc78ed 100644 --- a/cranelift/codegen/src/isa/pulley_shared/lower.isle +++ b/cranelift/codegen/src/isa/pulley_shared/lower.isle @@ -35,6 +35,27 @@ (rule (lower_cond_icmp32 (IntCC.UnsignedGreaterThan) a b) (Cond.IfXult32 b a)) (rule (lower_cond_icmp32 (IntCC.UnsignedGreaterThanOrEqual) a b) (Cond.IfXulteq32 b a)) +(rule 1 (lower_cond_icmp32 (IntCC.Equal) a (i32_from_iconst b)) + (Cond.IfXeq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.NotEqual) a (i32_from_iconst b)) + (Cond.IfXneq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.SignedLessThan) a (i32_from_iconst b)) + (Cond.IfXslt32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.SignedLessThanOrEqual) a (i32_from_iconst b)) + (Cond.IfXslteq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.SignedGreaterThan) a (i32_from_iconst b)) + (Cond.IfXsgt32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.SignedGreaterThanOrEqual) a (i32_from_iconst b)) + (Cond.IfXsgteq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.UnsignedLessThan) a (u32_from_iconst b)) + (Cond.IfXult32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.UnsignedLessThanOrEqual) a (u32_from_iconst b)) + (Cond.IfXulteq32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.UnsignedGreaterThan) a (u32_from_iconst b)) + (Cond.IfXugt32I32 a b)) +(rule 1 (lower_cond_icmp32 (IntCC.UnsignedGreaterThanOrEqual) a (u32_from_iconst b)) + (Cond.IfXugteq32I32 a b)) + (decl lower_cond_icmp64 (IntCC Value Value) Cond) (rule (lower_cond_icmp64 (IntCC.Equal) a b) (Cond.IfXeq64 a b)) (rule (lower_cond_icmp64 (IntCC.NotEqual) a b) (Cond.IfXneq64 a b)) @@ -48,6 +69,27 @@ (rule (lower_cond_icmp64 (IntCC.UnsignedGreaterThan) a b) (Cond.IfXult64 b a)) (rule (lower_cond_icmp64 (IntCC.UnsignedGreaterThanOrEqual) a b) (Cond.IfXulteq64 b a)) +(rule 1 (lower_cond_icmp64 (IntCC.Equal) a (i32_from_iconst b)) + (Cond.IfXeq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.NotEqual) a (i32_from_iconst b)) + (Cond.IfXneq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.SignedLessThan) a (i32_from_iconst b)) + (Cond.IfXslt64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.SignedLessThanOrEqual) a (i32_from_iconst b)) + (Cond.IfXslteq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.SignedGreaterThan) a (i32_from_iconst b)) + (Cond.IfXsgt64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.SignedGreaterThanOrEqual) a (i32_from_iconst b)) + (Cond.IfXsgteq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.UnsignedLessThan) a (u32_from_iconst b)) + (Cond.IfXult64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.UnsignedLessThanOrEqual) a (u32_from_iconst b)) + (Cond.IfXulteq64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.UnsignedGreaterThan) a (u32_from_iconst b)) + (Cond.IfXugt64I32 a b)) +(rule 1 (lower_cond_icmp64 (IntCC.UnsignedGreaterThanOrEqual) a (u32_from_iconst b)) + (Cond.IfXugteq64I32 a b)) + ;; The main control-flow-lowering term: takes a control-flow instruction and ;; target(s) and emits the necessary instructions. (decl partial lower_branch (Inst MachLabelSlice) Unit) @@ -880,6 +922,52 @@ (rule (emit_cond (Cond.IfXult64 src1 src2)) (pulley_xult64 src1 src2)) (rule (emit_cond (Cond.IfXulteq64 src1 src2)) (pulley_xulteq64 src1 src2)) +(rule (emit_cond (Cond.IfXeq32I32 src1 src2)) + (pulley_xeq32 src1 (imm $I32 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXneq32I32 src1 src2)) + (pulley_xneq32 src1 (imm $I32 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXslt32I32 src1 src2)) + (pulley_xslt32 src1 (imm $I32 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXslteq32I32 src1 src2)) + (pulley_xslteq32 src1 (imm $I32 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXult32I32 src1 src2)) + (pulley_xult32 src1 (imm $I32 (u32_as_u64 src2)))) +(rule (emit_cond (Cond.IfXulteq32I32 src1 src2)) + (pulley_xulteq32 src1 (imm $I32 (u32_as_u64 src2)))) + +;; Note the operand swaps here +(rule (emit_cond (Cond.IfXsgt32I32 src1 src2)) + (pulley_xslteq32 (imm $I32 (i64_as_u64 (i32_as_i64 src2))) src1)) +(rule (emit_cond (Cond.IfXsgteq32I32 src1 src2)) + (pulley_xslt32 (imm $I32 (i64_as_u64 (i32_as_i64 src2))) src1)) +(rule (emit_cond (Cond.IfXugt32I32 src1 src2)) + (pulley_xulteq32 (imm $I32 (u32_as_u64 src2)) src1)) +(rule (emit_cond (Cond.IfXugteq32I32 src1 src2)) + (pulley_xult32 (imm $I32 (u32_as_u64 src2)) src1)) + +(rule (emit_cond (Cond.IfXeq64I32 src1 src2)) + (pulley_xeq64 src1 (imm $I64 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXneq64I32 src1 src2)) + (pulley_xneq64 src1 (imm $I64 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXslt64I32 src1 src2)) + (pulley_xslt64 src1 (imm $I64 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXslteq64I32 src1 src2)) + (pulley_xslteq64 src1 (imm $I64 (i64_as_u64 (i32_as_i64 src2))))) +(rule (emit_cond (Cond.IfXult64I32 src1 src2)) + (pulley_xult64 src1 (imm $I64 (u32_as_u64 src2)))) +(rule (emit_cond (Cond.IfXulteq64I32 src1 src2)) + (pulley_xulteq64 src1 (imm $I64 (u32_as_u64 src2)))) + +;; Note the operand swaps here +(rule (emit_cond (Cond.IfXsgt64I32 src1 src2)) + (pulley_xslteq64 (imm $I64 (i64_as_u64 (i32_as_i64 src2))) src1)) +(rule (emit_cond (Cond.IfXsgteq64I32 src1 src2)) + (pulley_xslt64 (imm $I64 (i64_as_u64 (i32_as_i64 src2))) src1)) +(rule (emit_cond (Cond.IfXugt64I32 src1 src2)) + (pulley_xulteq64 (imm $I64 (u32_as_u64 src2)) src1)) +(rule (emit_cond (Cond.IfXugteq64I32 src1 src2)) + (pulley_xult64 (imm $I64 (u32_as_u64 src2)) src1)) + ;;;; Rules for `bitcast` ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (rule (lower (has_type $F32 (bitcast _flags val @ (value_type $I32)))) diff --git a/cranelift/filetests/filetests/isa/pulley32/brif.clif b/cranelift/filetests/filetests/isa/pulley32/brif.clif index b7c86f7513c1..f342c34b08ea 100644 --- a/cranelift/filetests/filetests/isa/pulley32/brif.clif +++ b/cranelift/filetests/filetests/isa/pulley32/brif.clif @@ -267,3 +267,126 @@ block2: ; xconst8 x0, 1 ; ret +function %brif_icmp_i32_imm(i32) -> i8 { +block0(v0: i32): + v2 = icmp_imm slt v0, 10 + brif v2, block1, block2 + +block1: + v3 = iconst.i8 1 + return v3 + +block2: + v4 = iconst.i8 0 + return v4 +} + +; VCode: +; block0: +; br_if_xslt32_i32 x0, 10, label2; jump label1 +; block1: +; xconst8 x0, 0 +; ret +; block2: +; xconst8 x0, 1 +; ret +; +; Disassembled: +; br_if_xslt32_i8 x0, 10, 0xb // target = 0xb +; xconst8 x0, 0 +; ret +; xconst8 x0, 1 +; ret + +function %brif_icmp_i32_imm_big(i32) -> i8 { +block0(v0: i32): + v2 = icmp_imm slt v0, 88888 + brif v2, block1, block2 + +block1: + v3 = iconst.i8 1 + return v3 + +block2: + v4 = iconst.i8 0 + return v4 +} + +; VCode: +; block0: +; br_if_xslt32_i32 x0, 88888, label2; jump label1 +; block1: +; xconst8 x0, 0 +; ret +; block2: +; xconst8 x0, 1 +; ret +; +; Disassembled: +; br_if_xslt32_i32 x0, 88888, 0xe // target = 0xe +; xconst8 x0, 0 +; ret +; xconst8 x0, 1 +; ret + +function %brif_icmp_i64_imm(i64) -> i8 { +block0(v0: i64): + v2 = icmp_imm slt v0, 10 + brif v2, block1, block2 + +block1: + v3 = iconst.i8 1 + return v3 + +block2: + v4 = iconst.i8 0 + return v4 +} + +; VCode: +; block0: +; br_if_xslt64_i32 x0, 10, label2; jump label1 +; block1: +; xconst8 x0, 0 +; ret +; block2: +; xconst8 x0, 1 +; ret +; +; Disassembled: +; br_if_xslt64_i8 x0, 10, 0xb // target = 0xb +; xconst8 x0, 0 +; ret +; xconst8 x0, 1 +; ret + +function %brif_icmp_i64_imm_big(i64) -> i8 { +block0(v0: i64): + v2 = icmp_imm slt v0, 88888 + brif v2, block1, block2 + +block1: + v3 = iconst.i8 1 + return v3 + +block2: + v4 = iconst.i8 0 + return v4 +} + +; VCode: +; block0: +; br_if_xslt64_i32 x0, 88888, label2; jump label1 +; block1: +; xconst8 x0, 0 +; ret +; block2: +; xconst8 x0, 1 +; ret +; +; Disassembled: +; br_if_xslt64_i32 x0, 88888, 0xe // target = 0xe +; xconst8 x0, 0 +; ret +; xconst8 x0, 1 +; ret diff --git a/cranelift/filetests/filetests/isa/pulley32/trap.clif b/cranelift/filetests/filetests/isa/pulley32/trap.clif index f11b1f2de43e..7bd7ba27fbae 100644 --- a/cranelift/filetests/filetests/isa/pulley32/trap.clif +++ b/cranelift/filetests/filetests/isa/pulley32/trap.clif @@ -23,13 +23,11 @@ block0(v0: i64): ; VCode: ; block0: -; xconst8 x2, 42 -; trap_if_xeq64 x0, x2 // code = TrapCode(1) +; trap_if_xeq64_i32 x0, 42 // code = TrapCode(1) ; ret ; ; Disassembled: -; xconst8 x2, 42 -; br_if_xeq64 x0, x2, 0x8 // target = 0xb +; br_if_xeq64_i8 x0, 42, 0x8 // target = 0x8 ; ret ; trap @@ -43,13 +41,11 @@ block0(v0: i64): ; VCode: ; block0: -; xconst8 x2, 42 -; trap_if_xneq64 x0, x2 // code = TrapCode(1) +; trap_if_xneq64_i32 x0, 42 // code = TrapCode(1) ; ret ; ; Disassembled: -; xconst8 x2, 42 -; br_if_xneq64 x0, x2, 0x8 // target = 0xb +; br_if_xneq64_i8 x0, 42, 0x8 // target = 0x8 ; ret ; trap @@ -63,13 +59,11 @@ block0(v0: i64): ; VCode: ; block0: -; xconst8 x2, 42 -; trap_if_xeq64 x0, x2 // code = TrapCode(1) +; trap_if_xeq64_i32 x0, 42 // code = TrapCode(1) ; ret ; ; Disassembled: -; xconst8 x2, 42 -; br_if_xeq64 x0, x2, 0x8 // target = 0xb +; br_if_xeq64_i8 x0, 42, 0x8 // target = 0x8 ; ret ; trap @@ -83,13 +77,11 @@ block0(v0: i64): ; VCode: ; block0: -; xconst8 x2, 42 -; trap_if_xneq64 x0, x2 // code = TrapCode(1) +; trap_if_xneq64_i32 x0, 42 // code = TrapCode(1) ; ret ; ; Disassembled: -; xconst8 x2, 42 -; br_if_xneq64 x0, x2, 0x8 // target = 0xb +; br_if_xneq64_i8 x0, 42, 0x8 // target = 0x8 ; ret ; trap diff --git a/cranelift/filetests/filetests/isa/pulley64/trap.clif b/cranelift/filetests/filetests/isa/pulley64/trap.clif index e343de871480..d38ac59dd9f1 100644 --- a/cranelift/filetests/filetests/isa/pulley64/trap.clif +++ b/cranelift/filetests/filetests/isa/pulley64/trap.clif @@ -23,13 +23,11 @@ block0(v0: i64): ; VCode: ; block0: -; xconst8 x2, 42 -; trap_if_xeq64 x0, x2 // code = TrapCode(1) +; trap_if_xeq64_i32 x0, 42 // code = TrapCode(1) ; ret ; ; Disassembled: -; xconst8 x2, 42 -; br_if_xeq64 x0, x2, 0x8 // target = 0xb +; br_if_xeq64_i8 x0, 42, 0x8 // target = 0x8 ; ret ; trap @@ -43,13 +41,11 @@ block0(v0: i64): ; VCode: ; block0: -; xconst8 x2, 42 -; trap_if_xneq64 x0, x2 // code = TrapCode(1) +; trap_if_xneq64_i32 x0, 42 // code = TrapCode(1) ; ret ; ; Disassembled: -; xconst8 x2, 42 -; br_if_xneq64 x0, x2, 0x8 // target = 0xb +; br_if_xneq64_i8 x0, 42, 0x8 // target = 0x8 ; ret ; trap @@ -63,13 +59,11 @@ block0(v0: i64): ; VCode: ; block0: -; xconst8 x2, 42 -; trap_if_xeq64 x0, x2 // code = TrapCode(1) +; trap_if_xeq64_i32 x0, 42 // code = TrapCode(1) ; ret ; ; Disassembled: -; xconst8 x2, 42 -; br_if_xeq64 x0, x2, 0x8 // target = 0xb +; br_if_xeq64_i8 x0, 42, 0x8 // target = 0x8 ; ret ; trap @@ -83,13 +77,11 @@ block0(v0: i64): ; VCode: ; block0: -; xconst8 x2, 42 -; trap_if_xneq64 x0, x2 // code = TrapCode(1) +; trap_if_xneq64_i32 x0, 42 // code = TrapCode(1) ; ret ; ; Disassembled: -; xconst8 x2, 42 -; br_if_xneq64 x0, x2, 0x8 // target = 0xb +; br_if_xneq64_i8 x0, 42, 0x8 // target = 0x8 ; ret ; trap diff --git a/pulley/src/interp.rs b/pulley/src/interp.rs index b87ad44a3eac..fe32ea75d6ac 100644 --- a/pulley/src/interp.rs +++ b/pulley/src/interp.rs @@ -1024,6 +1024,22 @@ fn simple_push_pop() { } } +macro_rules! br_if_imm { + ($( + fn $snake:ident(&mut self, a: XReg, b: $imm:ident, offset: PcRelOffset) + = $camel:ident / $op:tt / $get:ident; + )*) => {$( + fn $snake(&mut self, a: XReg, b: $imm, offset: PcRelOffset) -> ControlFlow { + let a = self.state[a].$get(); + if a $op b.into() { + self.pc_rel_jump::(offset) + } else { + ControlFlow::Continue(()) + } + } + )*}; +} + impl OpVisitor for Interpreter<'_> { type BytecodeStream = UnsafeBytecodeStream; type Return = ControlFlow; @@ -1211,6 +1227,94 @@ impl OpVisitor for Interpreter<'_> { } } + br_if_imm! { + fn br_if_xeq32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXeq32I8 / == / get_i32; + fn br_if_xeq32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXeq32I32 / == / get_i32; + fn br_if_xneq32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXneq32I8 / != / get_i32; + fn br_if_xneq32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXneq32I32 / != / get_i32; + + fn br_if_xslt32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXslt32I8 / < / get_i32; + fn br_if_xslt32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXslt32I32 / < / get_i32; + fn br_if_xsgt32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXsgt32I8 / > / get_i32; + fn br_if_xsgt32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXsgt32I32 / > / get_i32; + fn br_if_xslteq32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXslteq32I8 / <= / get_i32; + fn br_if_xslteq32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXslteq32I32 / <= / get_i32; + fn br_if_xsgteq32_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXsgteq32I8 / >= / get_i32; + fn br_if_xsgteq32_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXsgteq32I32 / >= / get_i32; + + fn br_if_xult32_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset) + = BrIfXult32U8 / < / get_u32; + fn br_if_xult32_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset) + = BrIfXult32U32 / < / get_u32; + fn br_if_xugt32_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset) + = BrIfXugt32U8 / > / get_u32; + fn br_if_xugt32_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset) + = BrIfXugt32U32 / > / get_u32; + fn br_if_xulteq32_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset) + = BrIfXulteq32U8 / <= / get_u32; + fn br_if_xulteq32_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset) + = BrIfXulteq32U32 / <= / get_u32; + fn br_if_xugteq32_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset) + = BrIfXugteq32U8 / >= / get_u32; + fn br_if_xugteq32_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset) + = BrIfXugteq32U32 / >= / get_u32; + + fn br_if_xeq64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXeq64I8 / == / get_i64; + fn br_if_xeq64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXeq64I32 / == / get_i64; + fn br_if_xneq64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXneq64I8 / != / get_i64; + fn br_if_xneq64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXneq64I32 / != / get_i64; + + fn br_if_xslt64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXslt64I8 / < / get_i64; + fn br_if_xslt64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXslt64I32 / < / get_i64; + fn br_if_xsgt64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXsgt64I8 / > / get_i64; + fn br_if_xsgt64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXsgt64I32 / > / get_i64; + fn br_if_xslteq64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXslteq64I8 / <= / get_i64; + fn br_if_xslteq64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXslteq64I32 / <= / get_i64; + fn br_if_xsgteq64_i8(&mut self, a: XReg, b: i8, offset: PcRelOffset) + = BrIfXsgteq64I8 / >= / get_i64; + fn br_if_xsgteq64_i32(&mut self, a: XReg, b: i32, offset: PcRelOffset) + = BrIfXsgteq64I32 / >= / get_i64; + + fn br_if_xult64_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset) + = BrIfXult64U8 / < / get_u64; + fn br_if_xult64_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset) + = BrIfXult64U32 / < / get_u64; + fn br_if_xugt64_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset) + = BrIfXugt64U8 / > / get_u64; + fn br_if_xugt64_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset) + = BrIfXugt64U32 / > / get_u64; + fn br_if_xulteq64_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset) + = BrIfXulteq64U8 / <= / get_u64; + fn br_if_xulteq64_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset) + = BrIfXulteq64U32 / <= / get_u64; + fn br_if_xugteq64_u8(&mut self, a: XReg, b: u8, offset: PcRelOffset) + = BrIfXugteq64U8 / >= / get_u64; + fn br_if_xugteq64_u32(&mut self, a: XReg, b: u32, offset: PcRelOffset) + = BrIfXugteq64U32 / >= / get_u64; + } + fn xmov(&mut self, dst: XReg, src: XReg) -> ControlFlow { let val = self.state[src]; self.state[dst] = val; diff --git a/pulley/src/lib.rs b/pulley/src/lib.rs index 37fb02c78ddf..f87388f2f59c 100644 --- a/pulley/src/lib.rs +++ b/pulley/src/lib.rs @@ -138,6 +138,88 @@ macro_rules! for_each_op { /// Branch if unsigned `a <= b`. br_if_xulteq64 = BrIfXulteq64 { a: XReg, b: XReg, offset: PcRelOffset }; + /// Branch if `a == b`. + br_if_xeq32_i8 = BrIfXeq32I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if `a == b`. + br_if_xeq32_i32 = BrIfXeq32I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if `a != `b. + br_if_xneq32_i8 = BrIfXneq32I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if `a != `b. + br_if_xneq32_i32 = BrIfXneq32I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if signed `a < b`. + br_if_xslt32_i8 = BrIfXslt32I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if signed `a < b`. + br_if_xslt32_i32 = BrIfXslt32I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if signed `a > b`. + br_if_xsgt32_i8 = BrIfXsgt32I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if signed `a > b`. + br_if_xsgt32_i32 = BrIfXsgt32I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if signed `a <= b`. + br_if_xslteq32_i8 = BrIfXslteq32I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if signed `a <= b`. + br_if_xslteq32_i32 = BrIfXslteq32I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if signed `a >= b`. + br_if_xsgteq32_i8 = BrIfXsgteq32I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if signed `a >= b`. + br_if_xsgteq32_i32 = BrIfXsgteq32I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if unsigned `a < b`. + br_if_xult32_u8 = BrIfXult32U8 { a: XReg, b: u8, offset: PcRelOffset }; + /// Branch if unsigned `a < b`. + br_if_xult32_u32 = BrIfXult32U32 { a: XReg, b: u32, offset: PcRelOffset }; + /// Branch if unsigned `a <= b`. + br_if_xulteq32_u8 = BrIfXulteq32U8 { a: XReg, b: u8, offset: PcRelOffset }; + /// Branch if unsigned `a <= b`. + br_if_xulteq32_u32 = BrIfXulteq32U32 { a: XReg, b: u32, offset: PcRelOffset }; + /// Branch if unsigned `a > b`. + br_if_xugt32_u8 = BrIfXugt32U8 { a: XReg, b: u8, offset: PcRelOffset }; + /// Branch if unsigned `a > b`. + br_if_xugt32_u32 = BrIfXugt32U32 { a: XReg, b: u32, offset: PcRelOffset }; + /// Branch if unsigned `a >= b`. + br_if_xugteq32_u8 = BrIfXugteq32U8 { a: XReg, b: u8, offset: PcRelOffset }; + /// Branch if unsigned `a >= b`. + br_if_xugteq32_u32 = BrIfXugteq32U32 { a: XReg, b: u32, offset: PcRelOffset }; + + /// Branch if `a == b`. + br_if_xeq64_i8 = BrIfXeq64I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if `a == b`. + br_if_xeq64_i32 = BrIfXeq64I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if `a != `b. + br_if_xneq64_i8 = BrIfXneq64I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if `a != `b. + br_if_xneq64_i32 = BrIfXneq64I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if signed `a < b`. + br_if_xslt64_i8 = BrIfXslt64I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if signed `a < b`. + br_if_xslt64_i32 = BrIfXslt64I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if signed `a > b`. + br_if_xsgt64_i8 = BrIfXsgt64I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if signed `a > b`. + br_if_xsgt64_i32 = BrIfXsgt64I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if signed `a <= b`. + br_if_xslteq64_i8 = BrIfXslteq64I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if signed `a <= b`. + br_if_xslteq64_i32 = BrIfXslteq64I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if signed `a >= b`. + br_if_xsgteq64_i8 = BrIfXsgteq64I8 { a: XReg, b: i8, offset: PcRelOffset }; + /// Branch if signed `a >= b`. + br_if_xsgteq64_i32 = BrIfXsgteq64I32 { a: XReg, b: i32, offset: PcRelOffset }; + /// Branch if unsigned `a < b`. + br_if_xult64_u8 = BrIfXult64U8 { a: XReg, b: u8, offset: PcRelOffset }; + /// Branch if unsigned `a < b`. + br_if_xult64_u32 = BrIfXult64U32 { a: XReg, b: u32, offset: PcRelOffset }; + /// Branch if unsigned `a <= b`. + br_if_xulteq64_u8 = BrIfXulteq64U8 { a: XReg, b: u8, offset: PcRelOffset }; + /// Branch if unsigned `a <= b`. + br_if_xulteq64_u32 = BrIfXulteq64U32 { a: XReg, b: u32, offset: PcRelOffset }; + /// Branch if unsigned `a > b`. + br_if_xugt64_u8 = BrIfXugt64U8 { a: XReg, b: u8, offset: PcRelOffset }; + /// Branch if unsigned `a > b`. + br_if_xugt64_u32 = BrIfXugt64U32 { a: XReg, b: u32, offset: PcRelOffset }; + /// Branch if unsigned `a >= b`. + br_if_xugteq64_u8 = BrIfXugteq64U8 { a: XReg, b: u8, offset: PcRelOffset }; + /// Branch if unsigned `a >= b`. + br_if_xugteq64_u32 = BrIfXugteq64U32 { a: XReg, b: u32, offset: PcRelOffset }; + /// Branch to the label indicated by `low32(idx)`. /// /// After this instruction are `amt` instances of `PcRelOffset` diff --git a/tests/disas/pulley/epoch-simple.wat b/tests/disas/pulley/epoch-simple.wat index 763aaad534aa..0c2adb5fede5 100644 --- a/tests/disas/pulley/epoch-simple.wat +++ b/tests/disas/pulley/epoch-simple.wat @@ -14,5 +14,5 @@ ;; br_if_xulteq64 x6, x7, 0x9 // target = 0x1a ;; 18: pop_frame ;; ret -;; 1a: call 0xa4 // target = 0xbe +;; 1a: call 0xa1 // target = 0xbb ;; 1f: jump 0xfffffffffffffff9 // target = 0x18 diff --git a/tests/disas/pulley/memory-inbounds.wat b/tests/disas/pulley/memory-inbounds.wat index f4a7d6fbffa2..3b5f021d2014 100644 --- a/tests/disas/pulley/memory-inbounds.wat +++ b/tests/disas/pulley/memory-inbounds.wat @@ -48,15 +48,14 @@ ;; ;; wasm[0]::function[4]::offset_just_bad: ;; push_frame -;; xload64le_offset8 x6, x0, 104 -;; xsub64_u8 x6, x6, 4 -;; xconst32 x7, 65533 -;; br_if_xult64 x6, x7, 0x14 // target = 0x23 -;; 16: xload64le_offset8 x7, x0, 96 -;; xload32le_offset32 x0, x7, 65533 +;; xload64le_offset8 x5, x0, 104 +;; xsub64_u8 x5, x5, 4 +;; br_if_xult64_u32 x5, 65533, 0x17 // target = 0x20 +;; 13: xload64le_offset8 x6, x0, 96 +;; xload32le_offset32 x0, x6, 65533 ;; pop_frame ;; ret -;; 23: trap +;; 20: trap ;; ;; wasm[0]::function[5]::offset_just_ok_v2: ;; push_frame @@ -67,27 +66,25 @@ ;; ;; wasm[0]::function[6]::offset_just_bad_v2: ;; push_frame -;; xload64le_offset8 x6, x0, 104 -;; xsub64_u32 x6, x6, 65536 -;; xconst8 x7, 0 -;; br_if_xeq64 x6, x7, 0x14 // target = 0x23 -;; 16: xload64le_offset8 x7, x0, 96 -;; xload32le_offset32 x0, x7, 65533 +;; xload64le_offset8 x5, x0, 104 +;; xsub64_u32 x5, x5, 65536 +;; br_if_xeq64_i8 x5, 0, 0x14 // target = 0x20 +;; 13: xload64le_offset8 x6, x0, 96 +;; xload32le_offset32 x0, x6, 65533 ;; pop_frame ;; ret -;; 23: trap +;; 20: trap ;; ;; wasm[0]::function[7]::maybe_inbounds: ;; push_frame -;; xload64le_offset8 x6, x0, 104 -;; xsub64_u8 x6, x6, 4 -;; xconst32 x7, 131068 -;; br_if_xult64 x6, x7, 0x14 // target = 0x23 -;; 16: xload64le_offset8 x7, x0, 96 -;; xload32le_offset32 x0, x7, 131068 +;; xload64le_offset8 x5, x0, 104 +;; xsub64_u8 x5, x5, 4 +;; br_if_xult64_u32 x5, 131068, 0x17 // target = 0x20 +;; 13: xload64le_offset8 x6, x0, 96 +;; xload32le_offset32 x0, x6, 131068 ;; pop_frame ;; ret -;; 23: trap +;; 20: trap ;; ;; wasm[0]::function[8]::maybe_inbounds_v2: ;; push_frame @@ -104,15 +101,14 @@ ;; ;; wasm[0]::function[9]::never_inbounds: ;; push_frame -;; xload64le_offset8 x6, x0, 104 -;; xsub64_u8 x6, x6, 4 -;; xconst32 x7, 131069 -;; br_if_xult64 x6, x7, 0x14 // target = 0x23 -;; 16: xload64le_offset8 x7, x0, 96 -;; xload32le_offset32 x0, x7, 131069 +;; xload64le_offset8 x5, x0, 104 +;; xsub64_u8 x5, x5, 4 +;; br_if_xult64_u32 x5, 131069, 0x17 // target = 0x20 +;; 13: xload64le_offset8 x6, x0, 96 +;; xload32le_offset32 x0, x6, 131069 ;; pop_frame ;; ret -;; 23: trap +;; 20: trap ;; ;; wasm[0]::function[10]::never_inbounds_v2: ;; push_frame