Skip to content

Commit cee3d5f

Browse files
committed
ZJIT: Combine two IFUNC tag guards into one
Use IntAnd + GuardBitEquals to check (block_handler & 0x3) == 0x3, matching VM_BH_IFUNC_P() in the interpreter. Add the IntAnd HIR instruction (placed next to IntOr) for bitwise AND on raw C integers.
1 parent 16e9610 commit cee3d5f

3 files changed

Lines changed: 28 additions & 25 deletions

File tree

zjit/src/codegen.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -644,6 +644,7 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
644644
Insn::FixnumAnd { left, right } => gen_fixnum_and(asm, opnd!(left), opnd!(right)),
645645
Insn::FixnumOr { left, right } => gen_fixnum_or(asm, opnd!(left), opnd!(right)),
646646
Insn::FixnumXor { left, right } => gen_fixnum_xor(asm, opnd!(left), opnd!(right)),
647+
Insn::IntAnd { left, right } => asm.and(opnd!(left), opnd!(right)),
647648
Insn::IntOr { left, right } => gen_int_or(asm, opnd!(left), opnd!(right)),
648649
&Insn::FixnumLShift { left, right, state } => {
649650
// We only create FixnumLShift when we know the shift amount statically and it's in [0,

zjit/src/hir.rs

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1072,6 +1072,7 @@ pub enum Insn {
10721072
FixnumAnd { left: InsnId, right: InsnId },
10731073
FixnumOr { left: InsnId, right: InsnId },
10741074
FixnumXor { left: InsnId, right: InsnId },
1075+
IntAnd { left: InsnId, right: InsnId },
10751076
IntOr { left: InsnId, right: InsnId },
10761077
FixnumLShift { left: InsnId, right: InsnId, state: InsnId },
10771078
FixnumRShift { left: InsnId, right: InsnId },
@@ -1275,6 +1276,7 @@ macro_rules! for_each_operand_impl {
12751276
| Insn::FixnumAnd { left, right }
12761277
| Insn::FixnumOr { left, right }
12771278
| Insn::FixnumXor { left, right }
1279+
| Insn::IntAnd { left, right }
12781280
| Insn::IntOr { left, right }
12791281
| Insn::FixnumRShift { left, right }
12801282
| Insn::IsBitEqual { left, right }
@@ -1617,6 +1619,7 @@ impl Insn {
16171619
Insn::FixnumAnd { .. } => effects::Empty,
16181620
Insn::FixnumOr { .. } => effects::Empty,
16191621
Insn::FixnumXor { .. } => effects::Empty,
1622+
Insn::IntAnd { .. } => effects::Empty,
16201623
Insn::IntOr { .. } => effects::Empty,
16211624
Insn::FixnumLShift { .. } => effects::Empty,
16221625
Insn::FixnumRShift { .. } => effects::Empty,
@@ -2006,6 +2009,7 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
20062009
Insn::FixnumAnd { left, right, .. } => { write!(f, "FixnumAnd {left}, {right}") },
20072010
Insn::FixnumOr { left, right, .. } => { write!(f, "FixnumOr {left}, {right}") },
20082011
Insn::FixnumXor { left, right, .. } => { write!(f, "FixnumXor {left}, {right}") },
2012+
Insn::IntAnd { left, right } => { write!(f, "IntAnd {left}, {right}") },
20092013
Insn::IntOr { left, right } => { write!(f, "IntOr {left}, {right}") },
20102014
Insn::FixnumLShift { left, right, .. } => { write!(f, "FixnumLShift {left}, {right}") },
20112015
Insn::FixnumRShift { left, right, .. } => { write!(f, "FixnumRShift {left}, {right}") },
@@ -2795,6 +2799,7 @@ impl Function {
27952799
&FixnumAnd { left, right } => FixnumAnd { left: find!(left), right: find!(right) },
27962800
&FixnumOr { left, right } => FixnumOr { left: find!(left), right: find!(right) },
27972801
&FixnumXor { left, right } => FixnumXor { left: find!(left), right: find!(right) },
2802+
&IntAnd { left, right } => IntAnd { left: find!(left), right: find!(right) },
27982803
&IntOr { left, right } => IntOr { left: find!(left), right: find!(right) },
27992804
&FixnumLShift { left, right, state } => FixnumLShift { left: find!(left), right: find!(right), state },
28002805
&FixnumRShift { left, right } => FixnumRShift { left: find!(left), right: find!(right) },
@@ -3057,6 +3062,7 @@ impl Function {
30573062
Insn::FixnumAnd { .. } => types::Fixnum,
30583063
Insn::FixnumOr { .. } => types::Fixnum,
30593064
Insn::FixnumXor { .. } => types::Fixnum,
3065+
Insn::IntAnd { .. } => types::CInt64,
30603066
Insn::IntOr { left, .. } => self.type_of(*left).unspecialized(),
30613067
Insn::FixnumLShift { .. } => types::Fixnum,
30623068
Insn::FixnumRShift { .. } => types::Fixnum,
@@ -6248,7 +6254,8 @@ impl Function {
62486254
Err(ValidationError::MiscValidationError(insn_id, "IsBitEqual can only compare CInt/CInt or RubyValue/RubyValue".to_string()))
62496255
}
62506256
}
6251-
Insn::IntOr { left, right } => {
6257+
Insn::IntAnd { left, right }
6258+
| Insn::IntOr { left, right } => {
62526259
// TODO: Expand this to other matching C integer sizes when we need them.
62536260
self.assert_subtype(insn_id, left, types::CInt64)?;
62546261
self.assert_subtype(insn_id, right, types::CInt64)
@@ -8161,20 +8168,13 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
81618168
return_type: types::CInt64,
81628169
});
81638170

8164-
// Guard that the block handler is an IFUNC (tag bits & 0x3 == 0x3)
8165-
// bit 0x1 must be set (iseq or ifunc)
8166-
fun.push_insn(block, Insn::GuardAnyBitSet {
8167-
val: block_handler,
8168-
mask: Const::CUInt64(0x1),
8169-
mask_name: None,
8170-
reason: SideExitReason::InvokeBlockNotIfunc,
8171-
state: exit_id,
8172-
});
8173-
// bit 0x2 must be set (ifunc specifically, not iseq)
8174-
fun.push_insn(block, Insn::GuardAnyBitSet {
8175-
val: block_handler,
8176-
mask: Const::CUInt64(0x2),
8177-
mask_name: None,
8171+
// Guard that the block handler is an IFUNC (tag bits & 0x3 == 0x3),
8172+
// matching VM_BH_IFUNC_P() in the interpreter.
8173+
let tag_mask = fun.push_insn(block, Insn::Const { val: Const::CInt64(0x3) });
8174+
let tag_bits = fun.push_insn(block, Insn::IntAnd { left: block_handler, right: tag_mask });
8175+
fun.push_insn(block, Insn::GuardBitEquals {
8176+
val: tag_bits,
8177+
expected: Const::CInt64(0x3),
81788178
reason: SideExitReason::InvokeBlockNotIfunc,
81798179
state: exit_id,
81808180
});

zjit/src/hir/opt_tests.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15102,17 +15102,19 @@ mod hir_opt_tests {
1510215102
v10:Fixnum[1] = Const Value(1)
1510315103
v12:CPtr = GetEP 0
1510415104
v13:CInt64 = LoadField v12, :_env_data_index_specval@0x1000
15105-
v14:CInt64 = GuardAnyBitSet v13, CUInt64(1)
15106-
v15:CInt64 = GuardAnyBitSet v13, CUInt64(2)
15107-
v16:BasicObject = InvokeBlockIfunc v13, v10
15108-
v20:Fixnum[2] = Const Value(2)
15109-
v22:CPtr = GetEP 0
15110-
v23:CInt64 = LoadField v22, :_env_data_index_specval@0x1000
15111-
v24:CInt64 = GuardAnyBitSet v23, CUInt64(1)
15112-
v25:CInt64 = GuardAnyBitSet v23, CUInt64(2)
15113-
v26:BasicObject = InvokeBlockIfunc v23, v20
15105+
v14:CInt64[3] = Const CInt64(3)
15106+
v15:CInt64 = IntAnd v13, v14
15107+
v16:CInt64[3] = GuardBitEquals v15, CInt64(3)
15108+
v17:BasicObject = InvokeBlockIfunc v13, v10
15109+
v21:Fixnum[2] = Const Value(2)
15110+
v23:CPtr = GetEP 0
15111+
v24:CInt64 = LoadField v23, :_env_data_index_specval@0x1000
15112+
v25:CInt64[3] = Const CInt64(3)
15113+
v26:CInt64 = IntAnd v24, v25
15114+
v27:CInt64[3] = GuardBitEquals v26, CInt64(3)
15115+
v28:BasicObject = InvokeBlockIfunc v24, v21
1511415116
CheckInterrupts
15115-
Return v26
15117+
Return v28
1511615118
");
1511715119
}
1511815120
}

0 commit comments

Comments
 (0)