YJIT: Branch directly when nil? is known from types

This commit is contained in:
John Hawthorn 2022-09-08 21:51:39 -07:00
parent d319184390
commit 5e39b3b844
Notes: git 2022-09-10 12:30:03 +09:00
2 changed files with 34 additions and 18 deletions

View File

@ -3340,11 +3340,6 @@ fn gen_branchnil(
gen_check_ints(asm, side_exit); gen_check_ints(asm, side_exit);
} }
// Test if the value is Qnil
// RUBY_Qnil /* ...0000 1000 */
let val_opnd = ctx.stack_pop(1);
asm.cmp(val_opnd, Opnd::UImm(Qnil.into()));
// Get the branch target instruction offsets // Get the branch target instruction offsets
let next_idx = jit_next_insn_idx(jit) as i32; let next_idx = jit_next_insn_idx(jit) as i32;
let jump_idx = next_idx + jump_offset; let jump_idx = next_idx + jump_offset;
@ -3357,18 +3352,29 @@ fn gen_branchnil(
idx: jump_idx.try_into().unwrap(), idx: jump_idx.try_into().unwrap(),
}; };
// Generate the branch instructions let val_type = ctx.get_opnd_type(StackOpnd(0));
gen_branch( let val_opnd = ctx.stack_pop(1);
jit,
ctx, if let Some(result) = val_type.known_nil() {
asm, let target = if result { jump_block } else { next_block };
ocb, gen_direct_jump(jit, ctx, target, asm);
jump_block, } else {
ctx, // Test if the value is Qnil
Some(next_block), // RUBY_Qnil /* ...0000 1000 */
Some(ctx), asm.cmp(val_opnd, Opnd::UImm(Qnil.into()));
gen_branchnil_branch, // Generate the branch instructions
); gen_branch(
jit,
ctx,
asm,
ocb,
jump_block,
ctx,
Some(next_block),
Some(ctx),
gen_branchnil_branch,
);
}
EndBlock EndBlock
} }

View File

@ -172,7 +172,7 @@ impl Type {
} }
} }
/// Returns an Option with the exact value if it is known, otherwise None /// Returns an Option boolean representing whether the value is truthy if known, otherwise None
pub fn known_truthy(&self) -> Option<bool> { pub fn known_truthy(&self) -> Option<bool> {
match self { match self {
Type::Nil => Some(false), Type::Nil => Some(false),
@ -183,6 +183,16 @@ impl Type {
} }
} }
/// Returns an Option boolean representing whether the value is equal to nil if known, otherwise None
pub fn known_nil(&self) -> Option<bool> {
match (self, self.known_truthy()) {
(Type::Nil, _) => Some(true),
(Type::False, _) => Some(false), // Qfalse is not nil
(_, Some(true)) => Some(false), // if truthy, can't be nil
(_, _) => None // otherwise unknown
}
}
/// Compute a difference between two value types /// Compute a difference between two value types
/// Returns 0 if the two are the same /// Returns 0 if the two are the same
/// Returns > 0 if different but compatible /// Returns > 0 if different but compatible