Implement opt_and and opt_or

This commit is contained in:
Takashi Kokubun 2023-02-13 23:05:56 -08:00
parent 67cc53214c
commit bc50b0475a
Notes: git 2023-03-06 07:30:03 +00:00
4 changed files with 118 additions and 5 deletions

View file

@ -121,6 +121,16 @@ module RubyVM::MJIT
mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg], mod_rm: ModRM[mod: Mod11, reg: 4, rm: dst_reg],
imm: imm8(src_imm), imm: imm8(src_imm),
) )
# AND r64, r/m64 (Mod 01: [reg]+disp8)
in [Symbol => dst_reg, [Symbol => src_reg, Integer => src_disp]] if r64?(dst_reg) && r64?(src_reg) && imm8?(src_disp)
# REX.W + 23 /r
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
insn(
prefix: REX_W,
opcode: 0x23,
mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
disp: imm8(src_disp),
)
else else
raise NotImplementedError, "and: not-implemented operands: #{dst.inspect}, #{src.inspect}" raise NotImplementedError, "and: not-implemented operands: #{dst.inspect}, #{src.inspect}"
end end
@ -545,6 +555,23 @@ module RubyVM::MJIT
end end
end end
def or(dst, src)
case [dst, src]
# OR r64, r/m64 (Mod 01: [reg]+disp8)
in [Symbol => dst_reg, [Symbol => src_reg, Integer => src_disp]] if r64?(dst_reg) && r64?(src_reg) && imm8?(src_disp)
# REX.W + 0B /r
# RM: Operand 1: ModRM:reg (r, w), Operand 2: ModRM:r/m (r)
insn(
prefix: REX_W,
opcode: 0x0b,
mod_rm: ModRM[mod: Mod01, reg: dst_reg, rm: src_reg],
disp: imm8(src_disp),
)
else
raise NotImplementedError, "or: not-implemented operands: #{dst.inspect}, #{src.inspect}"
end
end
def push(src) def push(src)
case src case src
# PUSH r64 # PUSH r64

View file

@ -23,7 +23,7 @@ module RubyVM::MJIT
asm.incr_counter(:mjit_insns_count) asm.incr_counter(:mjit_insns_count)
asm.comment("Insn: #{insn.name}") asm.comment("Insn: #{insn.name}")
# 36/101 # 38/101
case insn.name case insn.name
when :nop then nop(jit, ctx, asm) when :nop then nop(jit, ctx, asm)
# getlocal # getlocal
@ -105,8 +105,8 @@ module RubyVM::MJIT
when :opt_gt then opt_gt(jit, ctx, asm) when :opt_gt then opt_gt(jit, ctx, asm)
when :opt_ge then opt_ge(jit, ctx, asm) when :opt_ge then opt_ge(jit, ctx, asm)
when :opt_ltlt then opt_ltlt(jit, ctx, asm) when :opt_ltlt then opt_ltlt(jit, ctx, asm)
# opt_and when :opt_and then opt_and(jit, ctx, asm)
# opt_or when :opt_or then opt_or(jit, ctx, asm)
when :opt_aref then opt_aref(jit, ctx, asm) when :opt_aref then opt_aref(jit, ctx, asm)
# opt_aset # opt_aset
# opt_aset_with # opt_aset_with
@ -648,8 +648,84 @@ module RubyVM::MJIT
opt_send_without_block(jit, ctx, asm) opt_send_without_block(jit, ctx, asm)
end end
# opt_and # @param jit [RubyVM::MJIT::JITState]
# opt_or # @param ctx [RubyVM::MJIT::Context]
# @param asm [RubyVM::MJIT::Assembler]
def opt_and(jit, ctx, asm)
unless jit.at_current_insn?
defer_compilation(jit, ctx, asm)
return EndBlock
end
if two_fixnums_on_stack?(jit)
# Create a side-exit to fall back to the interpreter
# Note: we generate the side-exit before popping operands from the stack
side_exit = side_exit(jit, ctx)
unless Invariants.assume_bop_not_redefined(jit, C.INTEGER_REDEFINED_OP_FLAG, C.BOP_AND)
return CantCompile
end
# Check that both operands are fixnums
guard_two_fixnums(jit, ctx, asm, side_exit)
# Get the operands and destination from the stack
arg1 = ctx.stack_pop(1)
arg0 = ctx.stack_pop(1)
asm.comment('bitwise and')
asm.mov(:rax, arg0)
asm.and(:rax, arg1)
# Push the return value onto the stack
dst = ctx.stack_push
asm.mov(dst, :rax)
KeepCompiling
else
opt_send_without_block(jit, ctx, asm)
end
end
# @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context]
# @param asm [RubyVM::MJIT::Assembler]
def opt_or(jit, ctx, asm)
unless jit.at_current_insn?
defer_compilation(jit, ctx, asm)
return EndBlock
end
if two_fixnums_on_stack?(jit)
# Create a side-exit to fall back to the interpreter
# Note: we generate the side-exit before popping operands from the stack
side_exit = side_exit(jit, ctx)
unless Invariants.assume_bop_not_redefined(jit, C.INTEGER_REDEFINED_OP_FLAG, C.BOP_OR)
return CantCompile
end
# Check that both operands are fixnums
guard_two_fixnums(jit, ctx, asm, side_exit)
# Get the operands and destination from the stack
asm.comment('bitwise or')
arg1 = ctx.stack_pop(1)
arg0 = ctx.stack_pop(1)
# Do the bitwise or arg0 | arg1
asm.mov(:rax, arg0)
asm.or(:rax, arg1)
# Push the return value onto the stack
dst = ctx.stack_push
asm.mov(dst, :rax)
KeepCompiling
else
opt_send_without_block(jit, ctx, asm)
end
end
# @param jit [RubyVM::MJIT::JITState] # @param jit [RubyVM::MJIT::JITState]
# @param ctx [RubyVM::MJIT::Context] # @param ctx [RubyVM::MJIT::Context]

View file

@ -329,6 +329,10 @@ module RubyVM::MJIT # :nodoc: all
Primitive.cexpr! %q{ UINT2NUM(ARRAY_REDEFINED_OP_FLAG) } Primitive.cexpr! %q{ UINT2NUM(ARRAY_REDEFINED_OP_FLAG) }
end end
def C.BOP_AND
Primitive.cexpr! %q{ UINT2NUM(BOP_AND) }
end
def C.BOP_AREF def C.BOP_AREF
Primitive.cexpr! %q{ UINT2NUM(BOP_AREF) } Primitive.cexpr! %q{ UINT2NUM(BOP_AREF) }
end end
@ -357,6 +361,10 @@ module RubyVM::MJIT # :nodoc: all
Primitive.cexpr! %q{ UINT2NUM(BOP_MOD) } Primitive.cexpr! %q{ UINT2NUM(BOP_MOD) }
end end
def C.BOP_OR
Primitive.cexpr! %q{ UINT2NUM(BOP_OR) }
end
def C.BOP_PLUS def C.BOP_PLUS
Primitive.cexpr! %q{ UINT2NUM(BOP_PLUS) } Primitive.cexpr! %q{ UINT2NUM(BOP_PLUS) }
end end

View file

@ -348,6 +348,7 @@ generator = BindingGenerator.new(
VM_ENV_DATA_INDEX_SPECVAL VM_ENV_DATA_INDEX_SPECVAL
], ],
UINT: %w[ UINT: %w[
BOP_AND
BOP_AREF BOP_AREF
BOP_GE BOP_GE
BOP_GT BOP_GT
@ -355,6 +356,7 @@ generator = BindingGenerator.new(
BOP_LT BOP_LT
BOP_MINUS BOP_MINUS
BOP_MOD BOP_MOD
BOP_OR
BOP_PLUS BOP_PLUS
ARRAY_REDEFINED_OP_FLAG ARRAY_REDEFINED_OP_FLAG
HASH_REDEFINED_OP_FLAG HASH_REDEFINED_OP_FLAG