mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 08:47:34 +00:00
LibJS/JIT: Add helper for generating combined i32 & double fastpaths
Co-authored-by: Stephan Vedder <vedder@mbits.info>
This commit is contained in:
parent
578912aa6c
commit
d91b376393
3 changed files with 115 additions and 0 deletions
|
@ -954,6 +954,17 @@ struct X86_64Assembler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void convert_i32_to_double(Operand dst, Operand src)
|
||||||
|
{
|
||||||
|
VERIFY(dst.type == Operand::Type::FReg);
|
||||||
|
VERIFY(src.is_register_or_memory());
|
||||||
|
|
||||||
|
emit8(0xf2);
|
||||||
|
emit8(0x0f);
|
||||||
|
emit8(0x2a);
|
||||||
|
emit_modrm_rm(dst, src);
|
||||||
|
}
|
||||||
|
|
||||||
void native_call(
|
void native_call(
|
||||||
u64 callee,
|
u64 callee,
|
||||||
Vector<Operand> const& preserved_registers = {},
|
Vector<Operand> const& preserved_registers = {},
|
||||||
|
|
|
@ -348,6 +348,102 @@ void Compiler::branch_if_both_int32(Assembler::Reg lhs, Assembler::Reg rhs, Code
|
||||||
not_int32_case.link(m_assembler);
|
not_int32_case.link(m_assembler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Compiler::jump_if_not_double(Assembler::Reg reg, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label& label)
|
||||||
|
{
|
||||||
|
Assembler::Label is_double {};
|
||||||
|
// if (reg == nan) goto is_double
|
||||||
|
m_assembler.jump_if(
|
||||||
|
Assembler::Operand::Register(reg),
|
||||||
|
Assembler::Condition::EqualTo,
|
||||||
|
Assembler::Operand::Register(nan),
|
||||||
|
is_double);
|
||||||
|
// temp = reg
|
||||||
|
m_assembler.mov(Assembler::Operand::Register(temp), Assembler::Operand::Register(reg));
|
||||||
|
// if (temp & CANON_NAN_BITS == CANON_NAN_BITS) goto label
|
||||||
|
m_assembler.bitwise_and(
|
||||||
|
Assembler::Operand::Register(temp),
|
||||||
|
Assembler::Operand::Register(nan));
|
||||||
|
m_assembler.jump_if(
|
||||||
|
Assembler::Operand::Register(temp),
|
||||||
|
Assembler::Condition::EqualTo,
|
||||||
|
Assembler::Operand::Register(nan),
|
||||||
|
label);
|
||||||
|
is_double.link(m_assembler);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compiler::convert_to_double(Assembler::Reg dst, Assembler::Reg src, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label& not_number)
|
||||||
|
{
|
||||||
|
Assembler::Label is_i32;
|
||||||
|
Assembler::Label end;
|
||||||
|
jump_if_int32(src, is_i32);
|
||||||
|
jump_if_not_double(src, nan, temp, not_number);
|
||||||
|
m_assembler.mov(
|
||||||
|
Assembler::Operand::FloatRegister(dst),
|
||||||
|
Assembler::Operand::Register(src));
|
||||||
|
m_assembler.jump(end);
|
||||||
|
is_i32.link(m_assembler);
|
||||||
|
m_assembler.convert_i32_to_double(
|
||||||
|
Assembler::Operand::FloatRegister(dst),
|
||||||
|
Assembler::Operand::Register(src));
|
||||||
|
end.link(m_assembler);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename CodegenI32, typename CodegenDouble, typename CodegenValue>
|
||||||
|
void Compiler::branch_if_both_numbers(Assembler::Reg lhs, Assembler::Reg rhs, CodegenI32 codegen_i32, CodegenDouble codegen_double, CodegenValue codegen_value)
|
||||||
|
{
|
||||||
|
Assembler::Label end {};
|
||||||
|
Assembler::Label slow_case {};
|
||||||
|
|
||||||
|
// The only case where we can take the int32 fastpath
|
||||||
|
branch_if_both_int32(lhs, rhs, [&] {
|
||||||
|
// use GPR0 to preserve lhs for the slow case
|
||||||
|
m_assembler.mov32(
|
||||||
|
Assembler::Operand::Register(GPR0),
|
||||||
|
Assembler::Operand::Register(lhs));
|
||||||
|
store_accumulator(codegen_i32(GPR0, rhs, slow_case));
|
||||||
|
|
||||||
|
// accumulator |= SHIFTED_INT32_TAG;
|
||||||
|
m_assembler.mov(
|
||||||
|
Assembler::Operand::Register(GPR0),
|
||||||
|
Assembler::Operand::Imm(SHIFTED_INT32_TAG));
|
||||||
|
m_assembler.bitwise_or(
|
||||||
|
Assembler::Operand::Register(CACHED_ACCUMULATOR),
|
||||||
|
Assembler::Operand::Register(GPR0));
|
||||||
|
m_assembler.jump(end);
|
||||||
|
});
|
||||||
|
|
||||||
|
// accumulator = op_double(lhs.to_double(), rhs.to_double()) [if not numeric goto slow_case]
|
||||||
|
auto temp_register = GPR0;
|
||||||
|
auto nan_register = GPR1;
|
||||||
|
m_assembler.mov(Assembler::Operand::Register(nan_register), Assembler::Operand::Imm(CANON_NAN_BITS));
|
||||||
|
convert_to_double(FPR0, ARG1, nan_register, temp_register, slow_case);
|
||||||
|
convert_to_double(FPR1, ARG2, nan_register, temp_register, slow_case);
|
||||||
|
auto result_fp_register = codegen_double(FPR0, FPR1);
|
||||||
|
// if result != result then result = nan (canonical)
|
||||||
|
Assembler::Label nan_case;
|
||||||
|
m_assembler.jump_if(
|
||||||
|
Assembler::Operand::FloatRegister(result_fp_register),
|
||||||
|
Assembler::Condition::Unordered,
|
||||||
|
Assembler::Operand::FloatRegister(result_fp_register),
|
||||||
|
nan_case);
|
||||||
|
m_assembler.mov(
|
||||||
|
Assembler::Operand::Register(CACHED_ACCUMULATOR),
|
||||||
|
Assembler::Operand::FloatRegister(result_fp_register));
|
||||||
|
m_assembler.jump(end);
|
||||||
|
nan_case.link(m_assembler);
|
||||||
|
m_assembler.mov(
|
||||||
|
Assembler::Operand::Register(CACHED_ACCUMULATOR),
|
||||||
|
Assembler::Operand::Register(nan_register));
|
||||||
|
m_assembler.jump(end);
|
||||||
|
|
||||||
|
slow_case.link(m_assembler);
|
||||||
|
|
||||||
|
// accumulator = TRY(op_value(lhs, rhs))
|
||||||
|
store_accumulator(codegen_value(lhs, rhs));
|
||||||
|
check_exception();
|
||||||
|
end.link(m_assembler);
|
||||||
|
}
|
||||||
|
|
||||||
void Compiler::compile_increment(Bytecode::Op::Increment const&)
|
void Compiler::compile_increment(Bytecode::Op::Increment const&)
|
||||||
{
|
{
|
||||||
load_accumulator(ARG1);
|
load_accumulator(ARG1);
|
||||||
|
|
|
@ -34,6 +34,8 @@ private:
|
||||||
static constexpr auto ARG3 = Assembler::Reg::RCX;
|
static constexpr auto ARG3 = Assembler::Reg::RCX;
|
||||||
static constexpr auto ARG4 = Assembler::Reg::R8;
|
static constexpr auto ARG4 = Assembler::Reg::R8;
|
||||||
static constexpr auto ARG5 = Assembler::Reg::R9;
|
static constexpr auto ARG5 = Assembler::Reg::R9;
|
||||||
|
static constexpr auto FPR0 = Assembler::Reg::XMM0;
|
||||||
|
static constexpr auto FPR1 = Assembler::Reg::XMM1;
|
||||||
static constexpr auto RET = Assembler::Reg::RAX;
|
static constexpr auto RET = Assembler::Reg::RAX;
|
||||||
static constexpr auto STACK_POINTER = Assembler::Reg::RSP;
|
static constexpr auto STACK_POINTER = Assembler::Reg::RSP;
|
||||||
static constexpr auto REGISTER_ARRAY_BASE = Assembler::Reg::RBX;
|
static constexpr auto REGISTER_ARRAY_BASE = Assembler::Reg::RBX;
|
||||||
|
@ -186,10 +188,16 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void extract_object_pointer(Assembler::Reg dst_object, Assembler::Reg src_value);
|
void extract_object_pointer(Assembler::Reg dst_object, Assembler::Reg src_value);
|
||||||
|
void convert_to_double(Assembler::Reg dst, Assembler::Reg src, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label& not_number);
|
||||||
|
|
||||||
template<typename Codegen>
|
template<typename Codegen>
|
||||||
void branch_if_both_int32(Assembler::Reg, Assembler::Reg, Codegen);
|
void branch_if_both_int32(Assembler::Reg, Assembler::Reg, Codegen);
|
||||||
|
|
||||||
|
void jump_if_not_double(Assembler::Reg reg, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label&);
|
||||||
|
|
||||||
|
template<typename CodegenI32, typename CodegenDouble, typename CodegenValue>
|
||||||
|
void branch_if_both_numbers(Assembler::Reg lhs, Assembler::Reg rhs, CodegenI32, CodegenDouble, CodegenValue);
|
||||||
|
|
||||||
explicit Compiler(Bytecode::Executable& bytecode_executable)
|
explicit Compiler(Bytecode::Executable& bytecode_executable)
|
||||||
: m_bytecode_executable(bytecode_executable)
|
: m_bytecode_executable(bytecode_executable)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue