From 17ae6edd8ef73059cf35d8c27364deaee3f1d737 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 3 Nov 2023 08:35:07 +0100 Subject: [PATCH] LibJS+LibJIT: Add fast path for Int32 - Int32 --- Userland/Libraries/LibJIT/Assembler.h | 25 ++++++++++++++ Userland/Libraries/LibJS/JIT/Compiler.cpp | 42 +++++++++++++++++++++++ Userland/Libraries/LibJS/JIT/Compiler.h | 1 - 3 files changed, 67 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJIT/Assembler.h b/Userland/Libraries/LibJIT/Assembler.h index f068528513..e59a8507c3 100644 --- a/Userland/Libraries/LibJIT/Assembler.h +++ b/Userland/Libraries/LibJIT/Assembler.h @@ -664,6 +664,31 @@ struct Assembler { } } + void sub32(Operand dst, Operand src, Optional overflow_label) + { + if (dst.is_register_or_memory() && src.type == Operand::Type::Reg) { + emit_rex_for_mr(dst, src, REX_W::No); + emit8(0x29); + emit_modrm_mr(dst, src); + } else if (dst.is_register_or_memory() && src.type == Operand::Type::Imm && src.fits_in_i8()) { + emit_rex_for_slash(dst, REX_W::No); + emit8(0x83); + emit_modrm_slash(5, dst); + emit8(src.offset_or_immediate); + } else if (dst.is_register_or_memory() && src.type == Operand::Type::Imm && src.fits_in_i32()) { + emit_rex_for_slash(dst, REX_W::No); + emit8(0x81); + emit_modrm_slash(5, dst); + emit32(src.offset_or_immediate); + } else { + VERIFY_NOT_REACHED(); + } + + if (overflow_label.has_value()) { + jump_if(Condition::Overflow, *overflow_label); + } + } + // NOTE: It's up to the caller of this function to preserve registers as needed. void native_call(void* callee, Vector const& stack_arguments = {}) { diff --git a/Userland/Libraries/LibJS/JIT/Compiler.cpp b/Userland/Libraries/LibJS/JIT/Compiler.cpp index b89acba56b..0f3bf2250b 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.cpp +++ b/Userland/Libraries/LibJS/JIT/Compiler.cpp @@ -536,6 +536,48 @@ void Compiler::compile_add(Bytecode::Op::Add const& op) end.link(m_assembler); } +static Value cxx_sub(VM& vm, Value lhs, Value rhs) +{ + return TRY_OR_SET_EXCEPTION(sub(vm, lhs, rhs)); +} + +void Compiler::compile_sub(Bytecode::Op::Sub const& op) +{ + load_vm_register(ARG1, op.lhs()); + load_accumulator(ARG2); + + Assembler::Label end {}; + Assembler::Label slow_case {}; + + branch_if_both_int32(ARG1, ARG2, [&] { + // GPR0 = ARG1 + ARG2 (32-bit) + // if (overflow) goto slow_case; + m_assembler.mov( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(ARG1)); + m_assembler.sub32( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(ARG2), + slow_case); + + // accumulator = GPR0 | SHIFTED_INT32_TAG; + m_assembler.mov( + Assembler::Operand::Register(GPR1), + Assembler::Operand::Imm(SHIFTED_INT32_TAG)); + m_assembler.bitwise_or( + Assembler::Operand::Register(GPR0), + Assembler::Operand::Register(GPR1)); + store_accumulator(GPR0); + m_assembler.jump(end); + }); + + slow_case.link(m_assembler); + native_call((void*)cxx_sub); + store_accumulator(RET); + check_exception(); + end.link(m_assembler); +} + static Value cxx_less_than(VM& vm, Value lhs, Value rhs) { return TRY_OR_SET_EXCEPTION(less_than(vm, lhs, rhs)); diff --git a/Userland/Libraries/LibJS/JIT/Compiler.h b/Userland/Libraries/LibJS/JIT/Compiler.h index d6119c8a57..ebf5f3b8e8 100644 --- a/Userland/Libraries/LibJS/JIT/Compiler.h +++ b/Userland/Libraries/LibJS/JIT/Compiler.h @@ -41,7 +41,6 @@ private: # endif # define JS_ENUMERATE_COMMON_BINARY_OPS_WITHOUT_FAST_PATH(O) \ - O(Sub, sub) \ O(Mul, mul) \ O(Div, div) \ O(Exp, exp) \