From c062f12d7ccc86ee30cb3ca47b425d9f44911da1 Mon Sep 17 00:00:00 2001 From: Ujjwal Sharma Date: Thu, 26 Sep 2019 21:59:56 +0530 Subject: [PATCH] [codegen] legalize icmp for 64 and 128 bit operands Add legalizations for icmp and icmp_imm for i64 and i128 operands for the narrow legalization set, allowing 32-bit ISAs (like x86-32) to compare 64-bit integers and all ISAs to compare 128-bit integers. Fixes: https://github.com/bnjbvr/cranelift-x86/issues/2 --- cranelift/codegen/meta/src/shared/legalize.rs | 64 ++++ cranelift/codegen/shared/src/condcodes.rs | 26 ++ cranelift/codegen/src/legalizer/mod.rs | 64 ++++ .../filetests/isa/x86/icmp-i128.clif | 52 +++ .../filetests/isa/x86/legalize-i64.clif | 298 ++++++++++++++++++ 5 files changed, 504 insertions(+) create mode 100644 cranelift/filetests/filetests/isa/x86/icmp-i128.clif diff --git a/cranelift/codegen/meta/src/shared/legalize.rs b/cranelift/codegen/meta/src/shared/legalize.rs index 7ac4e8af13..bf046f5ddd 100644 --- a/cranelift/codegen/meta/src/shared/legalize.rs +++ b/cranelift/codegen/meta/src/shared/legalize.rs @@ -5,6 +5,7 @@ use crate::cdsl::xform::{TransformGroupBuilder, TransformGroups}; use crate::shared::immediates::Immediates; use crate::shared::types::Float::{F32, F64}; use crate::shared::types::Int::{I128, I16, I32, I64, I8}; +use cranelift_codegen_shared::condcodes::{CondCode, IntCC}; pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGroups { let mut narrow = TransformGroupBuilder::new( @@ -272,6 +273,69 @@ pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGro ], ); + // TODO(ryzokuken): benchmark this and decide if branching is a faster + // approach than evaluating boolean expressions. + + narrow.custom_legalize(icmp_imm, "narrow_icmp_imm"); + + let intcc_eq = Literal::enumerator_for(&imm.intcc, "eq"); + let intcc_ne = Literal::enumerator_for(&imm.intcc, "ne"); + for &(int_ty, int_ty_half) in &[(I64, I32), (I128, I64)] { + narrow.legalize( + def!(b = icmp.int_ty(intcc_eq, x, y)), + vec![ + def!((xl, xh) = isplit(x)), + def!((yl, yh) = isplit(y)), + def!(b1 = icmp.int_ty_half(intcc_eq, xl, yl)), + def!(b2 = icmp.int_ty_half(intcc_eq, xh, yh)), + def!(b = band(b1, b2)), + ], + ); + + narrow.legalize( + def!(b = icmp.int_ty(intcc_ne, x, y)), + vec![ + def!((xl, xh) = isplit(x)), + def!((yl, yh) = isplit(y)), + def!(b1 = icmp.int_ty_half(intcc_ne, xl, yl)), + def!(b2 = icmp.int_ty_half(intcc_ne, xh, yh)), + def!(b = bor(b1, b2)), + ], + ); + + use IntCC::*; + for cc in &[ + SignedGreaterThan, + SignedGreaterThanOrEqual, + SignedLessThan, + SignedLessThanOrEqual, + UnsignedGreaterThan, + UnsignedGreaterThanOrEqual, + UnsignedLessThan, + UnsignedLessThanOrEqual, + ] { + let intcc_cc = Literal::enumerator_for(&imm.intcc, cc.to_static_str()); + let cc1 = Literal::enumerator_for(&imm.intcc, cc.without_equal().to_static_str()); + let cc2 = + Literal::enumerator_for(&imm.intcc, cc.inverse().without_equal().to_static_str()); + let cc3 = Literal::enumerator_for(&imm.intcc, cc.unsigned().to_static_str()); + narrow.legalize( + def!(b = icmp.int_ty(intcc_cc, x, y)), + vec![ + def!((xl, xh) = isplit(x)), + def!((yl, yh) = isplit(y)), + // X = cc1 || (!cc2 && cc3) + def!(b1 = icmp.int_ty_half(cc1, xh, yh)), + def!(b2 = icmp.int_ty_half(cc2, xh, yh)), + def!(b3 = icmp.int_ty_half(cc3, xl, yl)), + def!(c1 = bnot(b2)), + def!(c2 = band(c1, b3)), + def!(b = bor(b1, c2)), + ], + ); + } + } + // Widen instructions with one input operand. for &op in &[bnot, popcnt] { for &int_ty in &[I8, I16] { diff --git a/cranelift/codegen/shared/src/condcodes.rs b/cranelift/codegen/shared/src/condcodes.rs index d151c49466..03ae865ce4 100644 --- a/cranelift/codegen/shared/src/condcodes.rs +++ b/cranelift/codegen/shared/src/condcodes.rs @@ -96,6 +96,32 @@ impl CondCode for IntCC { } impl IntCC { + /// Get the corresponding IntCC with the equal component removed. + /// For conditions without a zero component, this is a no-op. + pub fn without_equal(self) -> Self { + use self::IntCC::*; + match self { + SignedGreaterThan | SignedGreaterThanOrEqual => SignedGreaterThan, + SignedLessThan | SignedLessThanOrEqual => SignedLessThan, + UnsignedGreaterThan | UnsignedGreaterThanOrEqual => UnsignedGreaterThan, + UnsignedLessThan | UnsignedLessThanOrEqual => UnsignedLessThan, + _ => self, + } + } + + /// Get the corresponding IntCC with the signed component removed. + /// For conditions without a signed component, this is a no-op. + pub fn unsigned(self) -> Self { + use self::IntCC::*; + match self { + SignedGreaterThan | UnsignedGreaterThan => UnsignedGreaterThan, + SignedGreaterThanOrEqual | UnsignedGreaterThanOrEqual => UnsignedGreaterThanOrEqual, + SignedLessThan | UnsignedLessThan => UnsignedLessThan, + SignedLessThanOrEqual | UnsignedLessThanOrEqual => UnsignedLessThanOrEqual, + _ => self, + } + } + /// Get the corresponding string condition code for the IntCC object. pub fn to_static_str(self) -> &'static str { use self::IntCC::*; diff --git a/cranelift/codegen/src/legalizer/mod.rs b/cranelift/codegen/src/legalizer/mod.rs index b406506f48..b0fdac9ea9 100644 --- a/cranelift/codegen/src/legalizer/mod.rs +++ b/cranelift/codegen/src/legalizer/mod.rs @@ -672,3 +672,67 @@ fn narrow_iconst( unimplemented!("missing encoding or legalization for iconst.{:?}", ty); } + +fn narrow_icmp_imm( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + _isa: &dyn TargetIsa, +) { + use crate::ir::condcodes::{CondCode, IntCC}; + + let (arg, cond, imm): (ir::Value, IntCC, i64) = match func.dfg[inst] { + ir::InstructionData::IntCompareImm { + opcode: ir::Opcode::IcmpImm, + arg, + cond, + imm, + } => (arg, cond, imm.into()), + _ => panic!("unexpected instruction in narrow_icmp_imm"), + }; + + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + + let ty = pos.func.dfg.ctrl_typevar(inst); + let ty_half = ty.half_width().unwrap(); + + let imm_low = pos + .ins() + .iconst(ty_half, imm & (1u128 << ty_half.bits() - 1) as i64); + let imm_high = pos + .ins() + .iconst(ty_half, imm.wrapping_shr(ty_half.bits().into())); + let (arg_low, arg_high) = pos.ins().isplit(arg); + + match cond { + IntCC::Equal => { + let res_low = pos.ins().icmp(cond, arg_low, imm_low); + let res_high = pos.ins().icmp(cond, arg_high, imm_high); + pos.func.dfg.replace(inst).band(res_low, res_high); + } + IntCC::NotEqual => { + let res_low = pos.ins().icmp(cond, arg_low, imm_low); + let res_high = pos.ins().icmp(cond, arg_high, imm_high); + pos.func.dfg.replace(inst).bor(res_low, res_high); + } + IntCC::SignedGreaterThan + | IntCC::SignedGreaterThanOrEqual + | IntCC::SignedLessThan + | IntCC::SignedLessThanOrEqual + | IntCC::UnsignedGreaterThan + | IntCC::UnsignedGreaterThanOrEqual + | IntCC::UnsignedLessThan + | IntCC::UnsignedLessThanOrEqual => { + let b1 = pos.ins().icmp(cond.without_equal(), arg_high, imm_high); + let b2 = pos + .ins() + .icmp(cond.inverse().without_equal(), arg_high, imm_high); + let b3 = pos.ins().icmp(cond.unsigned(), arg_low, imm_low); + let c1 = pos.ins().bnot(b2); + let c2 = pos.ins().band(c1, b3); + pos.func.dfg.replace(inst).bor(b1, c2); + } + _ => unimplemented!("missing legalization for condition {:?}", cond), + } +} diff --git a/cranelift/filetests/filetests/isa/x86/icmp-i128.clif b/cranelift/filetests/filetests/isa/x86/icmp-i128.clif new file mode 100644 index 0000000000..8816d22d69 --- /dev/null +++ b/cranelift/filetests/filetests/isa/x86/icmp-i128.clif @@ -0,0 +1,52 @@ +test run +target x86_64 haswell + +function %test_icmp_eq_i128() -> b1 { +ebb0: + v11 = iconst.i64 0x0 + v12 = iconst.i64 0x0 + v1 = iconcat v11, v12 + v21 = iconst.i64 0x0 + v22 = iconst.i64 0x0 + v2 = iconcat v21, v22 + v10 = icmp.i128 eq v1, v2 + return v10 +} + +; run + +function %test_icmp_imm_eq_i128() -> b1 { +ebb0: + v11 = iconst.i64 0x0 + v12 = iconst.i64 0x0 + v1 = iconcat v11, v12 + v10 = icmp_imm.i128 eq v1, 0x0 + return v10 +} + +; run + +function %test_icmp_ne_i128() -> b1 { +ebb0: + v11 = iconst.i64 0x0 + v12 = iconst.i64 0x0 + v1 = iconcat v11, v12 + v21 = iconst.i64 0x0 + v22 = iconst.i64 0x1 + v2 = iconcat v21, v22 + v10 = icmp.i128 ne v1, v2 + return v10 +} + +; run + +function %test_icmp_imm_ne_i128() -> b1 { +ebb0: + v11 = iconst.i64 0x0 + v12 = iconst.i64 0x0 + v1 = iconcat v11, v12 + v10 = icmp_imm.i128 ne v1, 0x1 + return v10 +} + +; run diff --git a/cranelift/filetests/filetests/isa/x86/legalize-i64.clif b/cranelift/filetests/filetests/isa/x86/legalize-i64.clif index 8ae88f736e..2723bd69b8 100644 --- a/cranelift/filetests/filetests/isa/x86/legalize-i64.clif +++ b/cranelift/filetests/filetests/isa/x86/legalize-i64.clif @@ -25,3 +25,301 @@ ebb0(v1: i64, v2: i64): ; nextln: v10 = iconcat $v10_lsb, $v10_msb return v10 } + +function %icmp_eq(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp eq v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(v10_lsb=$V) = icmp eq $v1_lsb, $v2_lsb + ; nextln: $(v10_msb=$V) = icmp eq $v1_msb, $v2_msb + ; nextln: v10 = band $v10_lsb, $v10_msb + return v10 +} + +function %icmp_imm_eq(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm eq v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(v10_lsb=$V) = icmp eq $v1_lsb, $v2_lsb + ; nextln: $(v10_msb=$V) = icmp eq $v1_msb, $v2_msb + ; nextln: v10 = band $v10_lsb, $v10_msb + return v10 +} + +function %icmp_ne(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp ne v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(v10_lsb=$V) = icmp ne $v1_lsb, $v2_lsb + ; nextln: $(v10_msb=$V) = icmp ne $v1_msb, $v2_msb + ; nextln: v10 = bor $v10_lsb, $v10_msb + return v10 +} + +function %icmp_imm_ne(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm ne v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(v10_lsb=$V) = icmp ne $v1_lsb, $v2_lsb + ; nextln: $(v10_msb=$V) = icmp ne $v1_msb, $v2_msb + ; nextln: v10 = bor $v10_lsb, $v10_msb + return v10 +} + +function %icmp_sgt(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp sgt v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(b1=$V) = icmp sgt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp slt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ugt $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_imm_sgt(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm sgt v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(b1=$V) = icmp sgt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp slt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ugt $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_sge(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp sge v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(b1=$V) = icmp sgt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp slt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp uge $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_imm_sge(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm sge v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(b1=$V) = icmp sgt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp slt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp uge $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_slt(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp slt v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(b1=$V) = icmp slt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp sgt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ult $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_imm_slt(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm slt v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(b1=$V) = icmp slt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp sgt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ult $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_sle(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp sle v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(b1=$V) = icmp slt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp sgt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ule $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_imm_sle(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm sle v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(b1=$V) = icmp slt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp sgt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ule $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_ugt(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp ugt v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(b1=$V) = icmp ugt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp ult $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ugt $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_imm_ugt(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm ugt v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(b1=$V) = icmp ugt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp ult $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ugt $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_uge(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp uge v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(b1=$V) = icmp ugt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp ult $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp uge $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_imm_uge(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm uge v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(b1=$V) = icmp ugt $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp ult $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp uge $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_ult(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp ult v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(b1=$V) = icmp ult $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp ugt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ult $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_imm_ult(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm ult v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(b1=$V) = icmp ult $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp ugt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ult $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_ule(i64, i64) -> b1 { +ebb0(v1: i64, v2: i64): + v10 = icmp ule v1, v2 + ; check: v1 = iconcat $(v1_lsb=$V), $(v1_msb=$V) + ; nextln: v2 = iconcat $(v2_lsb=$V), $(v2_msb=$V) + ; nextln: $(b1=$V) = icmp ult $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp ugt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ule $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +} + +function %icmp_imm_ule(i64) -> b1 { +ebb0(v1: i64): + v10 = icmp_imm ule v1, 0 + ; check: $(v1_lsb=$V) -> $(v1_lsb_a=$V) + ; nextln: $(v1_msb=$V) -> $(v1_msb_a=$V) + ; nextln: v1 = iconcat $(v1_lsb_a=$V), $(v1_msb_a=$V) + ; nextln: $(v2_lsb=$V) = iconst.i32 0 + ; nextln: $(v2_msb=$V) = iconst.i32 0 + ; nextln: $(b1=$V) = icmp ult $v1_msb, $v2_msb + ; nextln: $(b2=$V) = icmp ugt $v1_msb, $v2_msb + ; nextln: $(b3=$V) = icmp ule $v1_lsb, $v2_lsb + ; nextln: $(c1=$V) = bnot $b2 + ; nextln: $(c2=$V) = band $c1, $b3 + ; nextln: v10 = bor $b1, $c2 + return v10 +}