diff --git a/ykrt/src/compile/jitc_yk/codegen/x64/mod.rs b/ykrt/src/compile/jitc_yk/codegen/x64/mod.rs index 6a2efe048..03bdab919 100644 --- a/ykrt/src/compile/jitc_yk/codegen/x64/mod.rs +++ b/ykrt/src/compile/jitc_yk/codegen/x64/mod.rs @@ -1803,7 +1803,7 @@ impl<'a> Assemble<'a> { match bit_size { 0 => unreachable!(), 32 => dynasm!(self.asm; cmp Rd(lhs_reg.code()), rhs), - 1..=64 => { + 8 | 16 | 64 => { if pred.signed() { self.sign_extend_to_reg64(lhs_reg, u8::try_from(bit_size).unwrap()); } else { @@ -1819,7 +1819,7 @@ impl<'a> Assemble<'a> { match bit_size { 0 => unreachable!(), 32 => dynasm!(self.asm; cmp Rd(lhs_reg.code()), Rd(rhs_reg.code())), - 1..=64 => { + 8 | 16 | 64 => { if pred.signed() { self.sign_extend_to_reg64(lhs_reg, u8::try_from(bit_size).unwrap()); self.sign_extend_to_reg64(rhs_reg, u8::try_from(bit_size).unwrap()); @@ -1829,7 +1829,7 @@ impl<'a> Assemble<'a> { } dynasm!(self.asm; cmp Rq(lhs_reg.code()), Rq(rhs_reg.code())); } - _ => todo!(), + _ => todo!("{bit_size}"), } } @@ -2492,8 +2492,16 @@ impl<'a> Assemble<'a> { RegConstraint::Input(inst.falseval(self.m)), ], ); - dynasm!(self.asm ; cmp Rb(cond_reg.code()), 0); - dynasm!(self.asm ; cmove Rq(true_reg.code()), Rq(false_reg.code())); + debug_assert_eq!( + self.m + .type_(inst.cond(self.m).tyidx(self.m)) + .bit_size() + .unwrap(), + 1 + ); + + dynasm!(self.asm ; bt Rq(cond_reg.code()), 0); + dynasm!(self.asm ; cmovnc Rq(true_reg.code()), Rq(false_reg.code())); } fn guard_to_deopt(&mut self, inst: &jit_ir::GuardInst) -> DynamicLabel { @@ -2580,15 +2588,15 @@ impl<'a> Assemble<'a> { fn cg_guard(&mut self, iidx: jit_ir::InstIdx, inst: &jit_ir::GuardInst) { let fail_label = self.guard_to_deopt(inst); let cond = inst.cond(self.m); - // ICmp instructions evaluate to a one-byte zero/one value. - debug_assert_eq!(cond.byte_size(self.m), 1); let [reg] = self .ra .assign_gp_regs(&mut self.asm, iidx, [RegConstraint::Input(cond)]); - dynasm!(self.asm - ; cmp Rb(reg.code()), inst.expect() as i8 // `as` intentional. - ; jne =>fail_label - ); + dynasm!(self.asm ; bt Rq(reg.code()), 0); + if inst.expect() { + dynasm!(self.asm ; jnb =>fail_label); + } else { + dynasm!(self.asm ; jb =>fail_label); + } } } @@ -4000,19 +4008,16 @@ mod tests { entry: %0: i16 = param 0 %1: i32 = param 1 - %2: i63 = param 2 - header_start [%0, %1, %2] - %4: i1 = eq %0, %0 - %5: i1 = eq %1, %1 - %6: i1 = eq %2, %2 + header_start [%0, %1] + %3: i1 = eq %0, %0 + %4: i1 = eq %1, %1 + black_box %3 black_box %4 - black_box %5 - black_box %6 - header_end [%0, %1, %2] + header_end [%0, %1] ", " ... - ; %4: i1 = eq %0, %0 + ; %3: i1 = eq %0, %0 ...... ...... movzx r.64.a, r.16.a @@ -4020,20 +4025,12 @@ mod tests { cmp r.64.a, r.64.b setz r.8._ ... - ; %5: i1 = eq %1, %1 + ; %4: i1 = eq %1, %1 ...... ...... cmp r.32.c, r.32.d setz r.8._ - ; %6: i1 = eq %2, %2 - ...... - ...... - shl r.64.e, 0x01 - shr r.64.e, 0x01 - shl r.64.f, 0x01 - shr r.64.f, 0x01 - cmp r.64.e, r.64.f - setz r.8._ + ; black_box %3 ... ", false, @@ -4136,8 +4133,8 @@ mod tests { ... ; guard true, %0, [] ; ... movzx r.64._, byte ptr ... - cmp r.8.b, 0x01 - jnz 0x... + bt r.64._, 0x00 + jnb 0x... ... ; deopt id for guard 0 push rsi @@ -4166,8 +4163,8 @@ mod tests { ... ; guard false, %0, [] ; ... movzx r.64._, byte ptr ... - cmp r.8.b, 0x00 - jnz 0x... + bt r.64._, 0x00 + jb 0x... ... ; deopt id for guard 0 push rsi @@ -4199,8 +4196,8 @@ mod tests { ... ; guard false, %0, [0:%0_0: %0, 0:%0_1: 10i8, 0:%0_2: 32i8, 0:%0_3: 42i8] ; trace_gidx 0 safepoint_id 0 movzx r.64._, byte ptr ... - cmp r.8.b, 0x00 - jnz 0x... + bt r.64._, 0x00 + jb 0x... ... ; deopt id for guard 0 push rsi @@ -4280,8 +4277,8 @@ mod tests { cmp r.64.x, 0x03 setz bl ; guard true, %1, [] ; ... - cmp bl, 0x01 - jnz 0x... + bt r.64._, 0x00 + jnb 0x... ; %3: i8 = sext %1 shl rbx, 0x3f sar rbx, 0x3f @@ -4433,7 +4430,7 @@ mod tests { codegen_and_test( " entry: - %0: i32 = param 0 + %0: i1 = param 0 %1: i32 = %0 ? 1i32 : 2i32 black_box %1 ", @@ -4442,8 +4439,8 @@ mod tests { ; %1: i32 = %0 ? 1i32 : 2i32 mov r.64.x, 0x01 mov r.64.y, 0x02 - cmp r.8.z, 0x00 - cmovz r.64.x, r.64.y + bt r.64.z, 0x00 + cmovnb r.64.x, r.64.y ... ", false, diff --git a/ykrt/src/compile/jitc_yk/jit_ir/well_formed.rs b/ykrt/src/compile/jitc_yk/jit_ir/well_formed.rs index ce84a3595..251183497 100644 --- a/ykrt/src/compile/jitc_yk/jit_ir/well_formed.rs +++ b/ykrt/src/compile/jitc_yk/jit_ir/well_formed.rs @@ -154,6 +154,23 @@ impl Module { ); } } + Inst::Select(x) => { + let Ty::Integer(bitsize) = self.type_(x.cond(self).tyidx(self)) else { + panic!(); + }; + if *bitsize != 1 { + panic!( + "Instruction at position {iidx} trying to select on a non-i1\n {}", + self.inst(iidx).display(self, iidx) + ); + } + if x.trueval(self).tyidx(self) != x.falseval(self).tyidx(self) { + panic!( + "Instruction at position {iidx} has incompatible true/false types\n {}", + self.inst(iidx).display(self, iidx) + ); + } + } Inst::SExt(x) => { let Ty::Integer(val_bitsize) = self.type_(x.val(self).tyidx(self)) else { panic!(); @@ -395,6 +412,30 @@ mod tests { ); } + #[test] + #[should_panic(expected = "Instruction at position 1 trying to select on a non-i1")] + fn select_bad_width() { + Module::from_str( + " + entry: + %0: i32 = param 0 + %1: i32 = %0 ? 1i32 : 2i32 + ", + ); + } + + #[test] + #[should_panic(expected = "Instruction at position 1 has incompatible true/false types")] + fn select_incompatible_types() { + Module::from_str( + " + entry: + %0: i1 = param 0 + %1: i32 = %0 ? 1i16 : 2i32 + ", + ); + } + #[test] #[should_panic( expected = "Instruction at position 1 trying to sign extend from an equal-or-larger-than integer type"