1
Fork 0
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:
Simon Wanner 2023-11-10 09:03:15 +01:00 committed by Andreas Kling
parent 578912aa6c
commit d91b376393
3 changed files with 115 additions and 0 deletions

View file

@ -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(
u64 callee,
Vector<Operand> const& preserved_registers = {},

View file

@ -348,6 +348,102 @@ void Compiler::branch_if_both_int32(Assembler::Reg lhs, Assembler::Reg rhs, Code
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&)
{
load_accumulator(ARG1);

View file

@ -34,6 +34,8 @@ private:
static constexpr auto ARG3 = Assembler::Reg::RCX;
static constexpr auto ARG4 = Assembler::Reg::R8;
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 STACK_POINTER = Assembler::Reg::RSP;
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 convert_to_double(Assembler::Reg dst, Assembler::Reg src, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label& not_number);
template<typename 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)
: m_bytecode_executable(bytecode_executable)
{