[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
This commit is contained in:
Ujjwal Sharma
2019-09-26 21:59:56 +05:30
committed by Benjamin Bouvier
parent 19444649e7
commit c062f12d7c
5 changed files with 504 additions and 0 deletions

View File

@@ -5,6 +5,7 @@ use crate::cdsl::xform::{TransformGroupBuilder, TransformGroups};
use crate::shared::immediates::Immediates; use crate::shared::immediates::Immediates;
use crate::shared::types::Float::{F32, F64}; use crate::shared::types::Float::{F32, F64};
use crate::shared::types::Int::{I128, I16, I32, I64, I8}; 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 { pub(crate) fn define(insts: &InstructionGroup, imm: &Immediates) -> TransformGroups {
let mut narrow = TransformGroupBuilder::new( 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. // Widen instructions with one input operand.
for &op in &[bnot, popcnt] { for &op in &[bnot, popcnt] {
for &int_ty in &[I8, I16] { for &int_ty in &[I8, I16] {

View File

@@ -96,6 +96,32 @@ impl CondCode for IntCC {
} }
impl 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. /// Get the corresponding string condition code for the IntCC object.
pub fn to_static_str(self) -> &'static str { pub fn to_static_str(self) -> &'static str {
use self::IntCC::*; use self::IntCC::*;

View File

@@ -672,3 +672,67 @@ fn narrow_iconst(
unimplemented!("missing encoding or legalization for iconst.{:?}", ty); 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),
}
}

View File

@@ -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

View File

@@ -25,3 +25,301 @@ ebb0(v1: i64, v2: i64):
; nextln: v10 = iconcat $v10_lsb, $v10_msb ; nextln: v10 = iconcat $v10_lsb, $v10_msb
return v10 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
}