Skip to content

Commit d91b376

Browse files
skyrisingfeliwir
authored andcommitted
LibJS/JIT: Add helper for generating combined i32 & double fastpaths
Co-authored-by: Stephan Vedder <vedder@mbits.info>
1 parent 578912a commit d91b376

File tree

3 files changed

+115
-0
lines changed

3 files changed

+115
-0
lines changed

Userland/Libraries/LibJIT/X86_64/Assembler.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,17 @@ struct X86_64Assembler {
954954
}
955955
}
956956

957+
void convert_i32_to_double(Operand dst, Operand src)
958+
{
959+
VERIFY(dst.type == Operand::Type::FReg);
960+
VERIFY(src.is_register_or_memory());
961+
962+
emit8(0xf2);
963+
emit8(0x0f);
964+
emit8(0x2a);
965+
emit_modrm_rm(dst, src);
966+
}
967+
957968
void native_call(
958969
u64 callee,
959970
Vector<Operand> const& preserved_registers = {},

Userland/Libraries/LibJS/JIT/Compiler.cpp

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,102 @@ void Compiler::branch_if_both_int32(Assembler::Reg lhs, Assembler::Reg rhs, Code
348348
not_int32_case.link(m_assembler);
349349
}
350350

351+
void Compiler::jump_if_not_double(Assembler::Reg reg, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label& label)
352+
{
353+
Assembler::Label is_double {};
354+
// if (reg == nan) goto is_double
355+
m_assembler.jump_if(
356+
Assembler::Operand::Register(reg),
357+
Assembler::Condition::EqualTo,
358+
Assembler::Operand::Register(nan),
359+
is_double);
360+
// temp = reg
361+
m_assembler.mov(Assembler::Operand::Register(temp), Assembler::Operand::Register(reg));
362+
// if (temp & CANON_NAN_BITS == CANON_NAN_BITS) goto label
363+
m_assembler.bitwise_and(
364+
Assembler::Operand::Register(temp),
365+
Assembler::Operand::Register(nan));
366+
m_assembler.jump_if(
367+
Assembler::Operand::Register(temp),
368+
Assembler::Condition::EqualTo,
369+
Assembler::Operand::Register(nan),
370+
label);
371+
is_double.link(m_assembler);
372+
}
373+
374+
void Compiler::convert_to_double(Assembler::Reg dst, Assembler::Reg src, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label& not_number)
375+
{
376+
Assembler::Label is_i32;
377+
Assembler::Label end;
378+
jump_if_int32(src, is_i32);
379+
jump_if_not_double(src, nan, temp, not_number);
380+
m_assembler.mov(
381+
Assembler::Operand::FloatRegister(dst),
382+
Assembler::Operand::Register(src));
383+
m_assembler.jump(end);
384+
is_i32.link(m_assembler);
385+
m_assembler.convert_i32_to_double(
386+
Assembler::Operand::FloatRegister(dst),
387+
Assembler::Operand::Register(src));
388+
end.link(m_assembler);
389+
}
390+
391+
template<typename CodegenI32, typename CodegenDouble, typename CodegenValue>
392+
void Compiler::branch_if_both_numbers(Assembler::Reg lhs, Assembler::Reg rhs, CodegenI32 codegen_i32, CodegenDouble codegen_double, CodegenValue codegen_value)
393+
{
394+
Assembler::Label end {};
395+
Assembler::Label slow_case {};
396+
397+
// The only case where we can take the int32 fastpath
398+
branch_if_both_int32(lhs, rhs, [&] {
399+
// use GPR0 to preserve lhs for the slow case
400+
m_assembler.mov32(
401+
Assembler::Operand::Register(GPR0),
402+
Assembler::Operand::Register(lhs));
403+
store_accumulator(codegen_i32(GPR0, rhs, slow_case));
404+
405+
// accumulator |= SHIFTED_INT32_TAG;
406+
m_assembler.mov(
407+
Assembler::Operand::Register(GPR0),
408+
Assembler::Operand::Imm(SHIFTED_INT32_TAG));
409+
m_assembler.bitwise_or(
410+
Assembler::Operand::Register(CACHED_ACCUMULATOR),
411+
Assembler::Operand::Register(GPR0));
412+
m_assembler.jump(end);
413+
});
414+
415+
// accumulator = op_double(lhs.to_double(), rhs.to_double()) [if not numeric goto slow_case]
416+
auto temp_register = GPR0;
417+
auto nan_register = GPR1;
418+
m_assembler.mov(Assembler::Operand::Register(nan_register), Assembler::Operand::Imm(CANON_NAN_BITS));
419+
convert_to_double(FPR0, ARG1, nan_register, temp_register, slow_case);
420+
convert_to_double(FPR1, ARG2, nan_register, temp_register, slow_case);
421+
auto result_fp_register = codegen_double(FPR0, FPR1);
422+
// if result != result then result = nan (canonical)
423+
Assembler::Label nan_case;
424+
m_assembler.jump_if(
425+
Assembler::Operand::FloatRegister(result_fp_register),
426+
Assembler::Condition::Unordered,
427+
Assembler::Operand::FloatRegister(result_fp_register),
428+
nan_case);
429+
m_assembler.mov(
430+
Assembler::Operand::Register(CACHED_ACCUMULATOR),
431+
Assembler::Operand::FloatRegister(result_fp_register));
432+
m_assembler.jump(end);
433+
nan_case.link(m_assembler);
434+
m_assembler.mov(
435+
Assembler::Operand::Register(CACHED_ACCUMULATOR),
436+
Assembler::Operand::Register(nan_register));
437+
m_assembler.jump(end);
438+
439+
slow_case.link(m_assembler);
440+
441+
// accumulator = TRY(op_value(lhs, rhs))
442+
store_accumulator(codegen_value(lhs, rhs));
443+
check_exception();
444+
end.link(m_assembler);
445+
}
446+
351447
void Compiler::compile_increment(Bytecode::Op::Increment const&)
352448
{
353449
load_accumulator(ARG1);

Userland/Libraries/LibJS/JIT/Compiler.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ class Compiler {
3434
static constexpr auto ARG3 = Assembler::Reg::RCX;
3535
static constexpr auto ARG4 = Assembler::Reg::R8;
3636
static constexpr auto ARG5 = Assembler::Reg::R9;
37+
static constexpr auto FPR0 = Assembler::Reg::XMM0;
38+
static constexpr auto FPR1 = Assembler::Reg::XMM1;
3739
static constexpr auto RET = Assembler::Reg::RAX;
3840
static constexpr auto STACK_POINTER = Assembler::Reg::RSP;
3941
static constexpr auto REGISTER_ARRAY_BASE = Assembler::Reg::RBX;
@@ -186,10 +188,16 @@ class Compiler {
186188
}
187189

188190
void extract_object_pointer(Assembler::Reg dst_object, Assembler::Reg src_value);
191+
void convert_to_double(Assembler::Reg dst, Assembler::Reg src, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label& not_number);
189192

190193
template<typename Codegen>
191194
void branch_if_both_int32(Assembler::Reg, Assembler::Reg, Codegen);
192195

196+
void jump_if_not_double(Assembler::Reg reg, Assembler::Reg nan, Assembler::Reg temp, Assembler::Label&);
197+
198+
template<typename CodegenI32, typename CodegenDouble, typename CodegenValue>
199+
void branch_if_both_numbers(Assembler::Reg lhs, Assembler::Reg rhs, CodegenI32, CodegenDouble, CodegenValue);
200+
193201
explicit Compiler(Bytecode::Executable& bytecode_executable)
194202
: m_bytecode_executable(bytecode_executable)
195203
{

0 commit comments

Comments
 (0)