Issue #3049 - Rename and wire loongarch64 baseline JIT backend

This commit is contained in:
Basilisk-Dev 2026-04-23 19:09:10 -04:00 committed by wuggy
commit 36b9acb8a5
38 changed files with 15074 additions and 65 deletions

View file

@ -385,7 +385,7 @@ struct BaselineStackBuilder
return virtualPointerAtStackOffset(priorOffset);
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
defined(JS_CODEGEN_X64)
defined(JS_CODEGEN_LOONGARCH64) || defined(JS_CODEGEN_X64)
// On X64, ARM, ARM64, and MIPS, the frame pointer save location depends on
// the caller of the rectifier frame.
BufferPointer<RectifierFrameLayout> priorFrame =

View file

@ -15,6 +15,8 @@
# include "jit/arm/BaselineCompiler-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/BaselineCompiler-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/loongarch64/BaselineCompiler-loongarch64.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/BaselineCompiler-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -19,6 +19,8 @@
# include "jit/arm/CodeGenerator-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/CodeGenerator-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/none/CodeGenerator-none.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/CodeGenerator-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -64,6 +64,7 @@ extern "C" void sync_instruction_memory(caddr_t v, u_int len);
#if defined(__linux__) && \
(defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)) && \
!defined(JS_CODEGEN_LOONGARCH64) && \
(!defined(JS_SIMULATOR_MIPS32) && !defined(JS_SIMULATOR_MIPS64))
#include <sys/cachectl.h>
#endif
@ -220,6 +221,12 @@ class ExecutableAllocator
{
js::jit::Simulator::FlushICache(code, size);
}
#elif defined(JS_CODEGEN_LOONGARCH64)
static void cacheFlush(void* code, size_t size)
{
intptr_t end = reinterpret_cast<intptr_t>(code) + size;
__builtin___clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(end));
}
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
static void cacheFlush(void* code, size_t size)
{

View file

@ -162,7 +162,7 @@ static inline bool
IsIonEnabled(JSContext* cx)
{
// The ARM64 Ion engine is not yet implemented.
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_LOONGARCH64)
return false;
#else
return cx->options().ion() &&

View file

@ -10,6 +10,8 @@
# include "jit/arm/Assembler-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/Assembler-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/loongarch64/Assembler-loongarch64.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/Assembler-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -1927,6 +1927,8 @@ LAllocation::toRegister() const
# include "jit/mips64/LIR-mips64.h"
# endif
# include "jit/mips-shared/LIR-mips-shared.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/none/LIR-none.h"
#elif defined(JS_CODEGEN_NONE)
# include "jit/none/LIR-none.h"
#else

View file

@ -14,6 +14,8 @@
# include "jit/arm/LOpcodes-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/LOpcodes-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/none/LOpcodes-none.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/LOpcodes-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -18,6 +18,8 @@
# include "jit/arm/Lowering-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/Lowering-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/none/Lowering-none.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/Lowering-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -18,6 +18,8 @@
# include "jit/arm/MacroAssembler-arm-inl.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/MacroAssembler-arm64-inl.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/loongarch64/MacroAssembler-loongarch64-inl.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/MacroAssembler-mips32-inl.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -19,6 +19,8 @@
# include "jit/arm/MacroAssembler-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/MacroAssembler-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/loongarch64/MacroAssembler-loongarch64.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/MacroAssembler-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)
@ -66,8 +68,8 @@ using mozilla::FloatingPoint;
// architectures on each method declaration, such as PER_ARCH and
// PER_SHARED_ARCH.
# define ALL_ARCH mips32, mips64, arm, arm64, x86, x64
# define ALL_SHARED_ARCH arm, arm64, x86_shared, mips_shared
# define ALL_ARCH mips32, mips64, loongarch64, arm, arm64, x86, x64
# define ALL_SHARED_ARCH arm, arm64, loongarch64, x86_shared, mips_shared
// * How this macro works:
//
@ -110,6 +112,7 @@ using mozilla::FloatingPoint;
# define DEFINED_ON_x86_shared
# define DEFINED_ON_arm
# define DEFINED_ON_arm64
# define DEFINED_ON_loongarch64
# define DEFINED_ON_mips32
# define DEFINED_ON_mips64
# define DEFINED_ON_mips_shared
@ -132,6 +135,9 @@ using mozilla::FloatingPoint;
#elif defined(JS_CODEGEN_ARM64)
# undef DEFINED_ON_arm64
# define DEFINED_ON_arm64 define
#elif defined(JS_CODEGEN_LOONGARCH64)
# undef DEFINED_ON_loongarch64
# define DEFINED_ON_loongarch64 define
#elif defined(JS_CODEGEN_MIPS32)
# undef DEFINED_ON_mips32
# define DEFINED_ON_mips32 define
@ -419,13 +425,13 @@ class MacroAssembler : public MacroAssemblerSpecific
// Stack manipulation functions.
void PushRegsInMask(LiveRegisterSet set)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
void PushRegsInMask(LiveGeneralRegisterSet set);
void PopRegsInMask(LiveRegisterSet set);
void PopRegsInMask(LiveGeneralRegisterSet set);
void PopRegsInMaskIgnore(LiveRegisterSet set, LiveRegisterSet ignore)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
void Push(const Operand op) DEFINED_ON(x86_shared);
void Push(Register reg) PER_SHARED_ARCH;
@ -497,8 +503,8 @@ class MacroAssembler : public MacroAssemblerSpecific
void callAndPushReturnAddress(Register reg) DEFINED_ON(x86_shared);
void callAndPushReturnAddress(Label* label) DEFINED_ON(x86_shared);
void pushReturnAddress() DEFINED_ON(mips_shared, arm, arm64);
void popReturnAddress() DEFINED_ON(mips_shared, arm, arm64);
void pushReturnAddress() DEFINED_ON(mips_shared, loongarch64, arm, arm64);
void popReturnAddress() DEFINED_ON(mips_shared, loongarch64, arm, arm64);
public:
// ===============================================================
@ -741,9 +747,9 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void xorPtr(Register src, Register dest) PER_ARCH;
inline void xorPtr(Imm32 imm, Register dest) PER_ARCH;
inline void and64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64);
inline void or64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64);
inline void xor64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64);
inline void and64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
inline void or64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
inline void xor64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
// ===============================================================
// Arithmetic functions
@ -759,14 +765,14 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void addPtr(Imm32 imm, Register src, Register dest) DEFINED_ON(arm64);
inline void addPtr(ImmWord imm, Register dest) PER_ARCH;
inline void addPtr(ImmPtr imm, Register dest);
inline void addPtr(Imm32 imm, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64);
inline void addPtr(Imm32 imm, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64);
inline void addPtr(Imm32 imm, const AbsoluteAddress& dest) DEFINED_ON(x86, x64);
inline void addPtr(const Address& src, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64);
inline void addPtr(const Address& src, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64);
inline void add64(Register64 src, Register64 dest) PER_ARCH;
inline void add64(Imm32 imm, Register64 dest) PER_ARCH;
inline void add64(Imm64 imm, Register64 dest) DEFINED_ON(x86, x64, arm, mips32, mips64);
inline void add64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64);
inline void add64(Imm64 imm, Register64 dest) DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
inline void add64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
inline void addFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
@ -778,14 +784,14 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void sub32(Imm32 imm, Register dest) PER_SHARED_ARCH;
inline void subPtr(Register src, Register dest) PER_ARCH;
inline void subPtr(Register src, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64);
inline void subPtr(Register src, const Address& dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64);
inline void subPtr(Imm32 imm, Register dest) PER_ARCH;
inline void subPtr(ImmWord imm, Register dest) DEFINED_ON(x64);
inline void subPtr(const Address& addr, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64);
inline void subPtr(const Address& addr, Register dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64);
inline void sub64(Register64 src, Register64 dest) PER_ARCH;
inline void sub64(Imm64 imm, Register64 dest) DEFINED_ON(x86, x64, arm, mips32, mips64);
inline void sub64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64);
inline void sub64(Imm64 imm, Register64 dest) DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
inline void sub64(const Operand& src, Register64 dest) DEFINED_ON(x64, mips64, loongarch64);
inline void subFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
@ -798,10 +804,10 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void mul64(const Operand& src, const Register64& dest) DEFINED_ON(x64);
inline void mul64(const Operand& src, const Register64& dest, const Register temp)
DEFINED_ON(x64, mips64);
DEFINED_ON(x64, mips64, loongarch64);
inline void mul64(Imm64 imm, const Register64& dest) PER_ARCH;
inline void mul64(Imm64 imm, const Register64& dest, const Register temp)
DEFINED_ON(x86, x64, arm, mips32, mips64);
DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
inline void mul64(const Register64& src, const Register64& dest, const Register temp)
PER_ARCH;
@ -810,7 +816,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void mulFloat32(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
inline void mulDouble(FloatRegister src, FloatRegister dest) PER_SHARED_ARCH;
inline void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64);
inline void mulDoublePtr(ImmPtr imm, Register temp, FloatRegister dest) DEFINED_ON(mips_shared, arm, arm64, x86, x64, loongarch64);
// Perform an integer division, returning the integer part rounded toward zero.
// rhs must not be zero, and the division must not overflow.
@ -835,7 +841,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void dec32(RegisterOrInt32Constant* key);
inline void neg32(Register reg) PER_SHARED_ARCH;
inline void neg64(Register64 reg) DEFINED_ON(x86, x64, arm, mips32, mips64);
inline void neg64(Register64 reg) DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
inline void negateFloat(FloatRegister reg) PER_SHARED_ARCH;
@ -899,7 +905,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64);
inline void rotateLeft64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64);
inline void rotateLeft64(Imm32 count, Register64 input, Register64 dest, Register temp)
DEFINED_ON(x86, x64, arm, mips32, mips64);
DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
inline void rotateLeft64(Register count, Register64 input, Register64 dest, Register temp)
PER_ARCH;
@ -908,7 +914,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void rotateRight64(Imm32 count, Register64 input, Register64 dest) DEFINED_ON(x64);
inline void rotateRight64(Register count, Register64 input, Register64 dest) DEFINED_ON(x64);
inline void rotateRight64(Imm32 count, Register64 input, Register64 dest, Register temp)
DEFINED_ON(x86, x64, arm, mips32, mips64);
DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
inline void rotateRight64(Register count, Register64 input, Register64 dest, Register temp)
PER_ARCH;
@ -934,7 +940,7 @@ class MacroAssembler : public MacroAssemblerSpecific
template <typename T1, typename T2>
inline void cmp32Set(Condition cond, T1 lhs, T2 rhs, Register dest)
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64);
template <typename T1, typename T2>
inline void cmpPtrSet(Condition cond, T1 lhs, T2 rhs, Register dest)
@ -956,9 +962,9 @@ class MacroAssembler : public MacroAssemblerSpecific
Label* label);
inline void branch32(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
inline void branch32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
inline void branch32(Condition cond, const BaseIndex& lhs, Register rhs, Label* label)
DEFINED_ON(x86_shared);
@ -968,7 +974,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branch32(Condition cond, const Operand& lhs, Imm32 rhs, Label* label) DEFINED_ON(x86_shared);
inline void branch32(Condition cond, wasm::SymbolicAddress lhs, Imm32 rhs, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
// The supported condition are Equal, NotEqual, LessThan(orEqual), GreaterThan(orEqual),
// Below(orEqual) and Above(orEqual).
@ -977,7 +983,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branch64(Condition cond, Register64 lhs, Imm64 val, Label* success,
Label* fail = nullptr) PER_ARCH;
inline void branch64(Condition cond, Register64 lhs, Register64 rhs, Label* success,
Label* fail = nullptr) DEFINED_ON(x86, x64, arm, mips32, mips64);
Label* fail = nullptr) DEFINED_ON(x86, x64, arm, mips32, mips64, loongarch64);
// On x86 and x64 NotEqual and Equal conditions are allowed for the branch64 variants
// with Address as lhs. On others only the NotEqual condition.
inline void branch64(Condition cond, const Address& lhs, Imm64 val, Label* label) PER_ARCH;
@ -1001,12 +1007,12 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchPtr(Condition cond, const Address& lhs, ImmWord rhs, Label* label) PER_SHARED_ARCH;
inline void branchPtr(Condition cond, const AbsoluteAddress& lhs, Register rhs, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
inline void branchPtr(Condition cond, const AbsoluteAddress& lhs, ImmWord rhs, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
inline void branchPtr(Condition cond, wasm::SymbolicAddress lhs, Register rhs, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
template <typename T>
inline CodeOffsetJump branchPtrWithPatch(Condition cond, Register lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH;
@ -1014,7 +1020,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline CodeOffsetJump branchPtrWithPatch(Condition cond, Address lhs, T rhs, RepatchLabel* label) PER_SHARED_ARCH;
void branchPtrInNurseryChunk(Condition cond, Register ptr, Register temp, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
void branchPtrInNurseryChunk(Condition cond, const Address& address, Register temp, Label* label)
DEFINED_ON(x86);
void branchValueIsNurseryObject(Condition cond, const Address& address, Register temp, Label* label) PER_ARCH;
@ -1032,9 +1038,9 @@ class MacroAssembler : public MacroAssemblerSpecific
// which isn't implemented on all architectures.
// E.g. the x64 variants will do this only in the int64_t range.
inline void branchTruncateFloat32MaybeModUint32(FloatRegister src, Register dest, Label* fail)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
inline void branchTruncateDoubleMaybeModUint32(FloatRegister src, Register dest, Label* fail)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
// Truncate a double/float32 to intptr and when it doesn't fit jump to the failure label.
inline void branchTruncateFloat32ToPtr(FloatRegister src, Register dest, Label* fail)
@ -1044,9 +1050,9 @@ class MacroAssembler : public MacroAssemblerSpecific
// Truncate a double/float32 to int32 and when it doesn't fit jump to the failure label.
inline void branchTruncateFloat32ToInt32(FloatRegister src, Register dest, Label* fail)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
inline void branchTruncateDoubleToInt32(FloatRegister src, Register dest, Label* fail)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
inline void branchDouble(DoubleCondition cond, FloatRegister lhs, FloatRegister rhs,
Label* label) PER_SHARED_ARCH;
@ -1069,7 +1075,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTest32(Condition cond, Register lhs, Imm32 rhs, L label) PER_SHARED_ARCH;
inline void branchTest32(Condition cond, const Address& lhs, Imm32 rhh, Label* label) PER_SHARED_ARCH;
inline void branchTest32(Condition cond, const AbsoluteAddress& lhs, Imm32 rhs, Label* label)
DEFINED_ON(arm, arm64, mips_shared, x86, x64);
DEFINED_ON(arm, arm64, mips_shared, x86, x64, loongarch64);
template <class L>
inline void branchTestPtr(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH;
@ -1132,7 +1138,7 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTestUndefined(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestInt32(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestDouble(Condition cond, Register tag, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestNumber(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestBoolean(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
inline void branchTestString(Condition cond, Register tag, Label* label) PER_SHARED_ARCH;
@ -1150,60 +1156,60 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void branchTestUndefined(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestUndefined(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestUndefined(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestInt32(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestInt32(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestInt32(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestDouble(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestDouble(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestDouble(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestNumber(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestBoolean(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestBoolean(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestBoolean(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestString(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestString(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestSymbol(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestSymbol(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestBigInt(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestBigInt(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestNull(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestNull(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestNull(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
// Clobbers the ScratchReg on x64.
inline void branchTestObject(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestObject(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestObject(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestGCThing(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestGCThing(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
inline void branchTestPrimitive(Condition cond, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestMagic(Condition cond, const Address& address, Label* label) PER_SHARED_ARCH;
inline void branchTestMagic(Condition cond, const BaseIndex& address, Label* label) PER_SHARED_ARCH;
template <class L>
inline void branchTestMagic(Condition cond, const ValueOperand& value, L label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestMagic(Condition cond, const Address& valaddr, JSWhyMagic why, Label* label) PER_ARCH;
@ -1216,13 +1222,13 @@ class MacroAssembler : public MacroAssemblerSpecific
// Checks if given Value is evaluated to true or false in a condition.
// The type of the value should match the type of the method.
inline void branchTestInt32Truthy(bool truthy, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestDoubleTruthy(bool truthy, FloatRegister reg, Label* label) PER_SHARED_ARCH;
inline void branchTestBooleanTruthy(bool truthy, const ValueOperand& value, Label* label) PER_ARCH;
inline void branchTestStringTruthy(bool truthy, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
inline void branchTestBigIntTruthy(bool truthy, const ValueOperand& value, Label* label)
DEFINED_ON(arm, arm64, mips32, mips64, x86_shared);
DEFINED_ON(arm, arm64, mips32, mips64, loongarch64, x86_shared);
private:
@ -1294,9 +1300,9 @@ class MacroAssembler : public MacroAssemblerSpecific
// ========================================================================
// Memory access primitives.
inline void storeUncanonicalizedDouble(FloatRegister src, const Address& dest)
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64);
inline void storeUncanonicalizedDouble(FloatRegister src, const BaseIndex& dest)
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64);
inline void storeUncanonicalizedDouble(FloatRegister src, const Operand& dest)
DEFINED_ON(x86_shared);
@ -1304,9 +1310,9 @@ class MacroAssembler : public MacroAssemblerSpecific
inline void storeDouble(FloatRegister src, const T& dest);
inline void storeUncanonicalizedFloat32(FloatRegister src, const Address& dest)
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64);
inline void storeUncanonicalizedFloat32(FloatRegister src, const BaseIndex& dest)
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64);
DEFINED_ON(x86_shared, arm, arm64, mips32, mips64, loongarch64);
inline void storeUncanonicalizedFloat32(FloatRegister src, const Operand& dest)
DEFINED_ON(x86_shared);
@ -1747,7 +1753,7 @@ class MacroAssembler : public MacroAssemblerSpecific
template <typename T> inline void addToStackPtr(T t);
template <typename T> inline void addStackPtrTo(T t);
void subFromStackPtr(Imm32 imm32) DEFINED_ON(mips32, mips64, arm, x86, x64);
void subFromStackPtr(Imm32 imm32) DEFINED_ON(mips32, mips64, loongarch64, arm, x86, x64);
void subFromStackPtr(Register reg);
template <typename T>

View file

@ -12,6 +12,8 @@
# include "jit/arm/MoveEmitter-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/MoveEmitter-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/mips64/MoveEmitter-mips64.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/MoveEmitter-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -15,6 +15,8 @@
# include "jit/arm/Architecture-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/Architecture-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/loongarch64/Architecture-loongarch64.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/Architecture-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -14,6 +14,8 @@
# include "jit/arm/SharedICHelpers-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/SharedICHelpers-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/loongarch64/SharedICHelpers-loongarch64.h"
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
#include "jit/mips-shared/SharedICHelpers-mips-shared.h"
#elif defined(JS_CODEGEN_NONE)

View file

@ -14,6 +14,8 @@
# include "jit/arm/SharedICRegisters-arm.h"
#elif defined(JS_CODEGEN_ARM64)
# include "jit/arm64/SharedICRegisters-arm64.h"
#elif defined(JS_CODEGEN_LOONGARCH64)
# include "jit/loongarch64/SharedICRegisters-loongarch64.h"
#elif defined(JS_CODEGEN_MIPS32)
# include "jit/mips32/SharedICRegisters-mips32.h"
#elif defined(JS_CODEGEN_MIPS64)

View file

@ -0,0 +1,98 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/loongarch64/Architecture-loongarch64.h"
#include <cstring>
#ifdef JS_SIMULATOR
# include "jit/loongarch64/Simulator-loongarch64.h"
#endif
#include "jit/RegisterSets.h"
namespace js {
namespace jit {
Registers::Code Registers::FromName(const char* name) {
for (size_t i = 0; i < TotalPhys; i++) {
if (strcmp(GetName(i), name) == 0) {
return Code(i);
}
}
return Invalid;
}
FloatRegisters::Code FloatRegisters::FromName(const char* name) {
for (size_t i = 0; i < TotalPhys; i++) {
if (strcmp(GetName(i), name) == 0) {
return Code(i);
}
}
return Invalid;
}
FloatRegisterSet FloatRegister::ReduceSetForPush(const FloatRegisterSet& s) {
#ifdef ENABLE_WASM_SIMD
# error "Needs more careful logic if SIMD is enabled"
#endif
LiveFloatRegisterSet ret;
for (FloatRegisterIterator iter(s); iter.more(); ++iter) {
ret.addUnchecked(FromCode((*iter).encoding()));
}
return ret.set();
}
uint32_t FloatRegister::GetSizeInBytes(const FloatRegisterSet& s) {
#ifdef ENABLE_WASM_SIMD
# error "Needs more careful logic if SIMD is enabled"
#endif
return s.size() * sizeof(double);
}
uint32_t FloatRegister::GetPushSizeInBytes(const FloatRegisterSet& s) {
#ifdef ENABLE_WASM_SIMD
# error "Needs more careful logic if SIMD is enabled"
#endif
return s.size() * sizeof(double);
}
uint32_t FloatRegister::getRegisterDumpOffsetInBytes() {
#ifdef ENABLE_WASM_SIMD
# error "Needs more careful logic if SIMD is enabled"
#endif
return encoding() * sizeof(double);
}
bool CPUFlagsHaveBeenComputed() {
// TODO(loongarch64): Add CPU flags support.
return true;
}
uint32_t GetLOONGARCH64Flags() { return 0; }
void FlushICache(void* code, size_t size, bool codeIsThreadLocal) {
#if defined(JS_SIMULATOR)
js::jit::SimulatorProcess::FlushICache(code, size);
#elif defined(__GNUC__)
intptr_t end = reinterpret_cast<intptr_t>(code) + size;
__builtin___clear_cache(reinterpret_cast<char*>(code),
reinterpret_cast<char*>(end));
#else
_flush_cache(reinterpret_cast<char*>(code), size, BCACHE);
#endif
}
} // namespace jit
} // namespace js

View file

@ -0,0 +1,510 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_loongarch64_Architecture_loongarch64_h
#define jit_loongarch64_Architecture_loongarch64_h
#include "mozilla/MathAlgorithms.h"
#include <algorithm>
#include <limits.h>
#include <stdint.h>
#include "js/Utility.h"
namespace js {
namespace jit {
// LoongArch64 has 32 64-bit integer registers, r0 though r31.
// The program counter is not accessible as a register.
//
// SIMD and scalar floating-point registers share a register bank.
// Floating-point registers are f0 through f31.
// 128 bit SIMD registers are vr0 through vr31.
// e.g., f0 is the bottom 64 bits of vr0.
// LoongArch64 INT Register Convention:
// Name Alias Usage
// $r0 $zero Constant zero
// $r1 $ra Return address
// $r2 $tp TLS
// $r3 $sp Stack pointer
// $r4-$r11 $a0-$a7 Argument registers
// $r4-$r5 $v0-$v1 Return values
// $r12-$r20 $t0-$t8 Temporary registers
// $r21 $x Reserved
// $r22 $fp Frame pointer
// $r23-$r31 $s0-$s8 Callee-saved registers
// LoongArch64 FP Register Convention:
// Name Alias Usage
// $f0-$f7 $fa0-$fa7 Argument registers
// $f0-$f1 $fv0-$fv1 Return values
// $f8-f23 $ft0-$ft15 Temporary registers
// $f24-$f31 $fs0-$fs7 Callee-saved registers
class Registers {
public:
enum RegisterID {
r0 = 0,
r1,
r2,
r3,
r4,
r5,
r6,
r7,
r8,
r9,
r10,
r11,
r12,
r13,
r14,
r15,
r16,
r17,
r18,
r19,
r20,
r21,
r22,
r23,
r24,
r25,
r26,
r27,
r28,
r29,
r30,
r31,
zero = r0,
ra = r1,
tp = r2,
sp = r3,
a0 = r4,
a1 = r5,
a2 = r6,
a3 = r7,
a4 = r8,
a5 = r9,
a6 = r10,
a7 = r11,
t0 = r12,
t1 = r13,
t2 = r14,
t3 = r15,
t4 = r16,
t5 = r17,
t6 = r18,
t7 = r19,
t8 = r20,
rx = r21,
fp = r22,
s0 = r23,
s1 = r24,
s2 = r25,
s3 = r26,
s4 = r27,
s5 = r28,
s6 = r29,
s7 = r30,
s8 = r31,
invalid_reg,
};
typedef uint8_t Code;
typedef RegisterID Encoding;
typedef uint32_t SetType;
static const Encoding StackPointer = sp;
static const Encoding Invalid = invalid_reg;
// Content spilled during bailouts.
union RegisterContent {
uintptr_t r;
};
static uint32_t SetSize(SetType x) {
static_assert(sizeof(SetType) == 4, "SetType must be 32 bits");
return mozilla::CountPopulation32(x);
}
static uint32_t FirstBit(SetType x) {
return mozilla::CountTrailingZeroes32(x);
}
static uint32_t LastBit(SetType x) {
return 31 - mozilla::CountLeadingZeroes32(x);
}
static const char* GetName(uint32_t code) {
static const char* const Names[] = {
"zero", "ra", "tp", "sp", "a0", "a1", "a2", "a3", "a4", "a5", "a6",
"a7", "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", "t8", "rx",
"fp", "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8"};
static_assert(Total == sizeof(Names) / sizeof(Names[0]),
"Table is the correct size");
if ((code & 31) >= TotalPhys) {
return "invalid";
}
return Names[code & 31];
}
static Code FromName(const char* name);
static const uint32_t Total = 32;
static const uint32_t TotalPhys = 32;
static const uint32_t Allocatable =
23; // No named special-function registers.
static const SetType AllMask = 0xFFFFFFFF;
static const SetType NoneMask = 0x0;
static const SetType ArgRegMask =
(1 << Registers::a0) | (1 << Registers::a1) | (1 << Registers::a2) |
(1 << Registers::a3) | (1 << Registers::a4) | (1 << Registers::a5) |
(1 << Registers::a6) | (1 << Registers::a7);
static const SetType VolatileMask =
(1 << Registers::a0) | (1 << Registers::a1) | (1 << Registers::a2) |
(1 << Registers::a3) | (1 << Registers::a4) | (1 << Registers::a5) |
(1 << Registers::a6) | (1 << Registers::a7) | (1 << Registers::t0) |
(1 << Registers::t1) | (1 << Registers::t2) | (1 << Registers::t3) |
(1 << Registers::t4) | (1 << Registers::t5) | (1 << Registers::t6);
// We use this constant to save registers when entering functions. This
// is why $ra is added here even though it is not "Non Volatile".
static const SetType NonVolatileMask =
(1 << Registers::ra) | (1 << Registers::fp) | (1 << Registers::s0) |
(1 << Registers::s1) | (1 << Registers::s2) | (1 << Registers::s3) |
(1 << Registers::s4) | (1 << Registers::s5) | (1 << Registers::s6) |
(1 << Registers::s7) | (1 << Registers::s8);
static const SetType SingleByteRegs = VolatileMask | NonVolatileMask;
static const SetType NonAllocatableMask =
(1 << Registers::zero) | // Always be zero.
(1 << Registers::t7) | // First scratch register.
(1 << Registers::t8) | // Second scratch register.
(1 << Registers::rx) | // Reserved Register.
(1 << Registers::ra) | (1 << Registers::tp) | (1 << Registers::sp);
static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
static const SetType WrapperMask = VolatileMask;
// Registers returned from a JS -> JS call.
static const SetType JSCallMask = (1 << Registers::a2);
// Registers returned from a JS -> C call.
static const SetType CallMask = (1 << Registers::a0);
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
};
// Smallest integer type that can hold a register bitmask.
typedef uint32_t PackedRegisterMask;
template <typename T>
class TypedRegisterSet;
class FloatRegisters {
public:
enum FPRegisterID {
f0 = 0,
f1,
f2,
f3,
f4,
f5,
f6,
f7,
f8,
f9,
f10,
f11,
f12,
f13,
f14,
f15,
f16,
f17,
f18,
f19,
f20,
f21,
f22,
f23, // Scratch register.
f24,
f25,
f26,
f27,
f28,
f29,
f30,
f31,
};
// Eight bits: (invalid << 7) | (kind << 5) | encoding
typedef uint8_t Code;
typedef FPRegisterID Encoding;
typedef uint64_t SetType;
enum Kind : uint8_t { Double, Single, NumTypes };
static constexpr Code Invalid = 0x80;
static const char* GetName(uint32_t code) {
static const char* const Names[] = {
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31"};
static_assert(TotalPhys == sizeof(Names) / sizeof(Names[0]),
"Table is the correct size");
if ((code & 31) >= TotalPhys) {
return "invalid";
}
return Names[code & 31];
}
static Code FromName(const char* name);
static const uint32_t TotalPhys = 32;
static const uint32_t Total = TotalPhys * NumTypes;
static const uint32_t Allocatable = 31; // Without f23, the scratch register.
static_assert(sizeof(SetType) * 8 >= Total,
"SetType should be large enough to enumerate all registers.");
// Magic values which are used to duplicate a mask of physical register for
// a specific type of register. A multiplication is used to copy and shift
// the bits of the physical register mask.
static const SetType SpreadSingle = SetType(1)
<< (uint32_t(Single) * TotalPhys);
static const SetType SpreadDouble = SetType(1)
<< (uint32_t(Double) * TotalPhys);
static const SetType Spread = SpreadSingle | SpreadDouble;
static const SetType AllPhysMask = ((SetType(1) << TotalPhys) - 1);
static const SetType AllMask = AllPhysMask * Spread;
static const SetType AllSingleMask = AllPhysMask * SpreadSingle;
static const SetType AllDoubleMask = AllPhysMask * SpreadDouble;
static const SetType NoneMask = SetType(0);
// TODO(loongarch64): Much less than ARM64 here.
static const SetType NonVolatileMask =
SetType((1 << FloatRegisters::f24) | (1 << FloatRegisters::f25) |
(1 << FloatRegisters::f26) | (1 << FloatRegisters::f27) |
(1 << FloatRegisters::f28) | (1 << FloatRegisters::f29) |
(1 << FloatRegisters::f30) | (1 << FloatRegisters::f31)) *
Spread;
static const SetType VolatileMask = AllMask & ~NonVolatileMask;
static const SetType WrapperMask = VolatileMask;
// f23 is the scratch register.
static const SetType NonAllocatableMask =
(SetType(1) << FloatRegisters::f23) * Spread;
static const SetType TempMask = VolatileMask & ~NonAllocatableMask;
static const SetType AllocatableMask = AllMask & ~NonAllocatableMask;
// Content spilled during bailouts.
union RegisterContent {
float s;
double d;
};
static constexpr Encoding encoding(Code c) {
// assert() not available in constexpr function.
// assert(c < Total);
return Encoding(c & 31);
}
static constexpr Kind kind(Code c) {
// assert() not available in constexpr function.
// assert(c < Total && ((c >> 5) & 3) < NumTypes);
return Kind((c >> 5) & 3);
}
static constexpr Code fromParts(uint32_t encoding, uint32_t kind,
uint32_t invalid) {
return Code((invalid << 7) | (kind << 5) | encoding);
}
};
static const uint32_t SpillSlotSize =
std::max(sizeof(Registers::RegisterContent),
sizeof(FloatRegisters::RegisterContent));
static const uint32_t ION_FRAME_SLACK_SIZE = 24;
static const uint32_t ShadowStackSpace = 0;
static const uint32_t SizeOfReturnAddressAfterCall = 0;
// When our only strategy for far jumps is to encode the offset directly, and
// not insert any jump islands during assembly for even further jumps, then the
// architecture restricts us to -2^27 .. 2^27-4, to fit into a signed 28-bit
// value. We further reduce this range to allow the far-jump inserting code to
// have some breathing room.
static const uint32_t JumpImmediateRange = ((1 << 27) - (20 * 1024 * 1024));
struct FloatRegister {
typedef FloatRegisters Codes;
typedef Codes::Code Code;
typedef Codes::Encoding Encoding;
typedef Codes::SetType SetType;
static uint32_t SetSize(SetType x) {
static_assert(sizeof(SetType) == 8, "SetType must be 64 bits");
x |= x >> FloatRegisters::TotalPhys;
x &= FloatRegisters::AllPhysMask;
return mozilla::CountPopulation32(x);
}
static uint32_t FirstBit(SetType x) {
static_assert(sizeof(SetType) == 8, "SetType");
return mozilla::CountTrailingZeroes64(x);
}
static uint32_t LastBit(SetType x) {
static_assert(sizeof(SetType) == 8, "SetType");
return 63 - mozilla::CountLeadingZeroes64(x);
}
private:
// These fields only hold valid values: an invalid register is always
// represented as a valid encoding and kind with the invalid_ bit set.
uint8_t encoding_; // 32 encodings
uint8_t kind_; // Double, Single; more later
bool invalid_;
typedef Codes::Kind Kind;
public:
union RegisterContent {
float s;
double d;
};
constexpr FloatRegister(Encoding encoding, Kind kind)
: encoding_(encoding), kind_(kind), invalid_(false) {
// assert(uint32_t(encoding) < Codes::TotalPhys);
}
explicit constexpr FloatRegister(uint32_t code)
: encoding_(FloatRegisters::encoding(code)),
kind_(FloatRegisters::kind(code)),
invalid_(false) {}
constexpr FloatRegister()
: encoding_(0), kind_(FloatRegisters::Double), invalid_(true) {}
static FloatRegister FromCode(uint32_t i) {
MOZ_ASSERT(i < Codes::Total);
return FloatRegister(FloatRegisters::encoding(i), FloatRegisters::kind(i));
}
bool isSingle() const {
MOZ_ASSERT(!invalid_);
return kind_ == FloatRegisters::Single;
}
bool isDouble() const {
MOZ_ASSERT(!invalid_);
return kind_ == FloatRegisters::Double;
}
bool isSimd128() const {
MOZ_ASSERT(!invalid_);
return false;
}
bool isInvalid() const { return invalid_; }
FloatRegister asSingle() const {
MOZ_ASSERT(!invalid_);
return FloatRegister(Encoding(encoding_), FloatRegisters::Single);
}
FloatRegister asDouble() const {
MOZ_ASSERT(!invalid_);
return FloatRegister(Encoding(encoding_), FloatRegisters::Double);
}
FloatRegister asSimd128() const { MOZ_CRASH(); }
constexpr uint32_t size() const {
MOZ_ASSERT(!invalid_);
if (kind_ == FloatRegisters::Double) {
return sizeof(double);
}
MOZ_ASSERT(kind_ == FloatRegisters::Single);
return sizeof(float);
}
constexpr Code code() const {
// assert(!invalid_);
return Codes::fromParts(encoding_, kind_, invalid_);
}
constexpr Encoding encoding() const {
MOZ_ASSERT(!invalid_);
return Encoding(encoding_);
}
const char* name() const { return FloatRegisters::GetName(uint32_t(encoding_)); }
bool volatile_() const {
MOZ_ASSERT(!invalid_);
return !!((SetType(1) << code()) & FloatRegisters::VolatileMask);
}
constexpr bool operator!=(FloatRegister other) const {
return code() != other.code();
}
constexpr bool operator==(FloatRegister other) const {
return code() == other.code();
}
bool aliases(FloatRegister other) const {
return other.encoding_ == encoding_;
}
// Ensure that two floating point registers' types are equivalent.
bool equiv(FloatRegister other) const {
MOZ_ASSERT(!invalid_);
return kind_ == other.kind_;
}
uint32_t numAliased() const { return Codes::NumTypes; }
uint32_t numAlignedAliased() const { return numAliased(); }
void aliased(uint32_t aliasIdx, FloatRegister* ret) const {
MOZ_ASSERT(!invalid_);
MOZ_ASSERT(aliasIdx < numAliased());
*ret = FloatRegister(Encoding(encoding_),
Kind((aliasIdx + kind_) % numAliased()));
}
void alignedAliased(uint32_t aliasIdx, FloatRegister* ret) const {
MOZ_ASSERT(aliasIdx < numAliased());
aliased(aliasIdx, ret);
}
SetType alignedOrDominatedAliasedSet() const {
return Codes::Spread << encoding_;
}
static Code FromName(const char* name) { return FloatRegisters::FromName(name); }
static TypedRegisterSet<FloatRegister> ReduceSetForPush(
const TypedRegisterSet<FloatRegister>& s);
static uint32_t GetSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
static uint32_t GetPushSizeInBytes(const TypedRegisterSet<FloatRegister>& s);
uint32_t getRegisterDumpOffsetInBytes();
};
// LoongArch doesn't have double registers that cannot be treated as float32.
inline bool hasUnaliasedDouble() { return false; }
// LoongArch doesn't have double registers that alias multiple floats.
inline bool hasMultiAlias() { return false; }
uint32_t GetLOONGARCH64Flags();
} // namespace jit
} // namespace js
#endif /* jit_loongarch64_Architecture_loongarch64_h */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,27 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/loongarch64/Bailouts-loongarch64.h"
#include "jscntxt.h"
#include "jscompartment.h"
using namespace js;
using namespace js::jit;
BailoutFrameInfo::BailoutFrameInfo(const JitActivationIterator& activations,
BailoutStack* bailout)
: machine_(bailout->machineState())
{
uint8_t* sp = bailout->parentStackPointer();
framePointer_ = sp + bailout->frameSize();
topFrameSize_ = framePointer_ - sp;
JSScript* script = ScriptFromCalleeToken(((JitFrameLayout*) framePointer_)->calleeToken());
topIonScript_ = script->ionScript();
attachOnJitActivation(activations);
snapshotOffset_ = bailout->snapshotOffset();
}

View file

@ -0,0 +1,43 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_loongarch64_Bailouts_loongarch64_h
#define jit_loongarch64_Bailouts_loongarch64_h
#include "jit/Bailouts.h"
#include "jit/JitCompartment.h"
namespace js {
namespace jit {
class BailoutStack
{
RegisterDump::FPUArray fpregs_;
RegisterDump::GPRArray regs_;
uintptr_t frameSize_;
uintptr_t snapshotOffset_;
public:
MachineState machineState() {
return MachineState::FromBailout(regs_, fpregs_);
}
uint32_t snapshotOffset() const {
return snapshotOffset_;
}
uint32_t frameSize() const {
return frameSize_;
}
uint8_t* parentStackPointer() {
return (uint8_t*)this + sizeof(BailoutStack);
}
static size_t offsetOfFrameSize() {
return offsetof(BailoutStack, frameSize_);
}
};
} // namespace jit
} // namespace js
#endif /* jit_loongarch64_Bailouts_loongarch64_h */

View file

@ -0,0 +1,15 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/loongarch64/BaselineCompiler-loongarch64.h"
using namespace js;
using namespace js::jit;
BaselineCompilerLOONGARCH64::BaselineCompilerLOONGARCH64(JSContext* cx, TempAllocator& alloc,
JSScript* script)
: BaselineCompilerMIPSShared(cx, alloc, script)
{
}

View file

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_loongarch64_BaselineCompiler_loongarch64_h
#define jit_loongarch64_BaselineCompiler_loongarch64_h
#include "jit/mips-shared/BaselineCompiler-mips-shared.h"
namespace js {
namespace jit {
class BaselineCompilerLOONGARCH64 : public BaselineCompilerMIPSShared
{
protected:
BaselineCompilerLOONGARCH64(JSContext* cx, TempAllocator& alloc, JSScript* script);
};
typedef BaselineCompilerLOONGARCH64 BaselineCompilerSpecific;
} // namespace jit
} // namespace js
#endif /* jit_loongarch64_BaselineCompiler_loongarch64_h */

View file

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jit/BaselineCompiler.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/Linker.h"
#include "jit/SharedICHelpers.h"
using namespace js;
using namespace js::jit;
namespace js {
namespace jit {
// ICCompare_Int32
bool
ICCompare_Int32::Compiler::generateStubCode(MacroAssembler& masm)
{
// Guard that R0 is an integer and R1 is an integer.
Label failure;
Label conditionTrue;
masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
// Compare payload regs of R0 and R1.
masm.unboxInt32(R0, ExtractTemp0);
masm.unboxInt32(R1, ExtractTemp1);
Assembler::Condition cond = JSOpToCondition(op, /* signed = */true);
masm.ma_cmp_set(R0.valueReg(), ExtractTemp0, ExtractTemp1, cond);
masm.tagValue(JSVAL_TYPE_BOOLEAN, R0.valueReg(), R0);
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
} // namespace jit
} // namespace js

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,190 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "jsiter.h"
#include "jit/BaselineCompiler.h"
#include "jit/BaselineIC.h"
#include "jit/BaselineJIT.h"
#include "jit/Linker.h"
#include "jit/SharedICHelpers.h"
#include "jsboolinlines.h"
using namespace js;
using namespace js::jit;
namespace js {
namespace jit {
// ICBinaryArith_Int32
bool
ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
{
// Guard that R0 is an integer and R1 is an integer.
Label failure;
masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
masm.branchTestInt32(Assembler::NotEqual, R1, &failure);
// Add R0 and R1. Don't need to explicitly unbox, just use R2's valueReg.
Register scratchReg = R2.valueReg();
Label goodMul, divTest1, divTest2;
switch(op_) {
case JSOP_ADD:
masm.unboxInt32(R0, ExtractTemp0);
masm.unboxInt32(R1, ExtractTemp1);
masm.ma_addTestOverflow(scratchReg, ExtractTemp0, ExtractTemp1, &failure);
masm.boxValue(JSVAL_TYPE_INT32, scratchReg, R0.valueReg());
break;
case JSOP_SUB:
masm.unboxInt32(R0, ExtractTemp0);
masm.unboxInt32(R1, ExtractTemp1);
masm.ma_subTestOverflow(scratchReg, ExtractTemp0, ExtractTemp1, &failure);
masm.boxValue(JSVAL_TYPE_INT32, scratchReg, R0.valueReg());
break;
case JSOP_MUL: {
masm.unboxInt32(R0, ExtractTemp0);
masm.unboxInt32(R1, ExtractTemp1);
masm.ma_mul_branch_overflow(scratchReg, ExtractTemp0, ExtractTemp1, &failure);
masm.ma_b(scratchReg, Imm32(0), &goodMul, Assembler::NotEqual, ShortJump);
// Result is -0 if operands have different signs.
masm.as_xor(t8, ExtractTemp0, ExtractTemp1);
masm.ma_b(t8, Imm32(0), &failure, Assembler::LessThan, ShortJump);
masm.bind(&goodMul);
masm.boxValue(JSVAL_TYPE_INT32, scratchReg, R0.valueReg());
break;
}
case JSOP_DIV:
case JSOP_MOD: {
masm.unboxInt32(R0, ExtractTemp0);
masm.unboxInt32(R1, ExtractTemp1);
// Check for INT_MIN / -1, it results in a double.
masm.ma_b(ExtractTemp0, Imm32(INT_MIN), &divTest1, Assembler::NotEqual, ShortJump);
masm.ma_b(ExtractTemp1, Imm32(-1), &failure, Assembler::Equal, ShortJump);
masm.bind(&divTest1);
// Check for division by zero
masm.ma_b(ExtractTemp1, Imm32(0), &failure, Assembler::Equal, ShortJump);
// Check for 0 / X with X < 0 (results in -0).
masm.ma_b(ExtractTemp0, Imm32(0), &divTest2, Assembler::NotEqual, ShortJump);
masm.ma_b(ExtractTemp1, Imm32(0), &failure, Assembler::LessThan, ShortJump);
masm.bind(&divTest2);
masm.as_div(ExtractTemp0, ExtractTemp1);
if (op_ == JSOP_DIV) {
// Result is a double if the remainder != 0.
masm.as_mfhi(scratchReg);
masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::NotEqual, ShortJump);
masm.as_mflo(scratchReg);
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
} else {
Label done;
// If X % Y == 0 and X < 0, the result is -0.
masm.as_mfhi(scratchReg);
masm.ma_b(scratchReg, Imm32(0), &done, Assembler::NotEqual, ShortJump);
masm.ma_b(ExtractTemp0, Imm32(0), &failure, Assembler::LessThan, ShortJump);
masm.bind(&done);
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
}
break;
}
case JSOP_BITOR:
masm.as_or(R0.valueReg() , R0.valueReg(), R1.valueReg());
break;
case JSOP_BITXOR:
masm.as_xor(scratchReg, R0.valueReg(), R1.valueReg());
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
break;
case JSOP_BITAND:
masm.as_and(R0.valueReg() , R0.valueReg(), R1.valueReg());
break;
case JSOP_LSH:
masm.unboxInt32(R0, ExtractTemp0);
masm.unboxInt32(R1, ExtractTemp1);
// MIPS will only use 5 lowest bits in R1 as shift offset.
masm.ma_sll(scratchReg, ExtractTemp0, ExtractTemp1);
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
break;
case JSOP_RSH:
masm.unboxInt32(R0, ExtractTemp0);
masm.unboxInt32(R1, ExtractTemp1);
masm.ma_sra(scratchReg, ExtractTemp0, ExtractTemp1);
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
break;
case JSOP_URSH:
masm.unboxInt32(R0, ExtractTemp0);
masm.unboxInt32(R1, ExtractTemp1);
masm.ma_srl(scratchReg, ExtractTemp0, ExtractTemp1);
if (allowDouble_) {
Label toUint;
masm.ma_b(scratchReg, Imm32(0), &toUint, Assembler::LessThan, ShortJump);
// Move result and box for return.
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
EmitReturnFromIC(masm);
masm.bind(&toUint);
masm.convertUInt32ToDouble(scratchReg, FloatReg1);
masm.boxDouble(FloatReg1, R0);
} else {
masm.ma_b(scratchReg, Imm32(0), &failure, Assembler::LessThan, ShortJump);
// Move result for return.
masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
}
break;
default:
MOZ_CRASH("Unhandled op for BinaryArith_Int32.");
}
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
bool
ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler& masm)
{
Label failure;
masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
switch (op) {
case JSOP_BITNOT:
masm.not32(R0.valueReg());
masm.tagValue(JSVAL_TYPE_INT32, R0.valueReg(), R0);
break;
case JSOP_NEG:
masm.unboxInt32(R0, ExtractTemp0);
// Guard against 0 and MIN_INT, both result in a double.
masm.branchTest32(Assembler::Zero, ExtractTemp0, Imm32(INT32_MAX), &failure);
masm.neg32(ExtractTemp0);
masm.tagValue(JSVAL_TYPE_INT32, ExtractTemp0, R0);
break;
default:
MOZ_CRASH("Unexpected op");
return false;
}
EmitReturnFromIC(masm);
masm.bind(&failure);
EmitStubGuardFailure(masm);
return true;
}
} // namespace jit
} // namespace js

View file

@ -0,0 +1,381 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_loongarch64_SharedICHelpers_loongarch64_h
#define jit_loongarch64_SharedICHelpers_loongarch64_h
#include "jit/BaselineFrame.h"
#include "jit/BaselineIC.h"
#include "jit/MacroAssembler.h"
#include "jit/SharedICRegisters.h"
namespace js {
namespace jit {
// Distance from sp to the top Value inside an IC stub (no return address on
// the stack on LoongArch).
static const size_t ICStackValueOffset = 0;
inline void
EmitRestoreTailCallReg(MacroAssembler& masm)
{
// No-op on LoongArch because ra register is always holding the return address.
}
inline void
EmitRepushTailCallReg(MacroAssembler& masm)
{
// No-op on LoongArch because ra register is always holding the return address.
}
inline void
EmitCallIC(CodeOffset* patchOffset, MacroAssembler& masm)
{
// Move ICEntry offset into ICStubReg.
CodeOffset offset = masm.movWithPatch(ImmWord(-1), ICStubReg);
*patchOffset = offset;
// Load stub pointer into ICStubReg.
masm.loadPtr(Address(ICStubReg, ICEntry::offsetOfFirstStub()), ICStubReg);
// Load stubcode pointer from BaselineStubEntry.
// R2 won't be active when we call ICs, so we can use it as scratch.
masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
// Call the stubcode via a direct jump-and-link
masm.call(R2.scratchReg());
}
inline void
EmitEnterTypeMonitorIC(MacroAssembler& masm,
size_t monitorStubOffset = ICMonitoredStub::offsetOfFirstMonitorStub())
{
// This is expected to be called from within an IC, when ICStubReg
// is properly initialized to point to the stub.
masm.loadPtr(Address(ICStubReg, (uint32_t) monitorStubOffset), ICStubReg);
// Load stubcode pointer from BaselineStubEntry.
// R2 won't be active when we call ICs, so we can use it.
masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
// Jump to the stubcode.
masm.branch(R2.scratchReg());
}
inline void
EmitReturnFromIC(MacroAssembler& masm)
{
masm.branch(ra);
}
inline void
EmitChangeICReturnAddress(MacroAssembler& masm, Register reg)
{
masm.movePtr(reg, ra);
}
inline void
EmitBaselineTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t argSize)
{
Register scratch = R2.scratchReg();
// Compute frame size.
masm.movePtr(BaselineFrameReg, scratch);
masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), scratch);
masm.subPtr(BaselineStackReg, scratch);
// Store frame size without VMFunction arguments for GC marking.
masm.subPtr(Imm32(argSize), scratch);
masm.store32(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
masm.addPtr(Imm32(argSize), scratch);
// Push frame descriptor and perform the tail call.
// ICTailCallReg (ra) already contains the return address (as we
// keep it there through the stub calls), but the VMWrapper code being
// called expects the return address to also be pushed on the stack.
MOZ_ASSERT(ICTailCallReg == ra);
masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS, ExitFrameLayout::Size());
masm.subPtr(Imm32(sizeof(CommonFrameLayout)), StackPointer);
masm.storePtr(scratch, Address(StackPointer, CommonFrameLayout::offsetOfDescriptor()));
masm.storePtr(ra, Address(StackPointer, CommonFrameLayout::offsetOfReturnAddress()));
masm.branch(target);
}
inline void
EmitIonTailCallVM(JitCode* target, MacroAssembler& masm, uint32_t stackSize)
{
Register scratch = R2.scratchReg();
masm.loadPtr(Address(sp, stackSize), scratch);
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), scratch);
masm.addPtr(Imm32(stackSize + JitStubFrameLayout::Size() - sizeof(intptr_t)), scratch);
// Push frame descriptor and perform the tail call.
MOZ_ASSERT(ICTailCallReg == ra);
masm.makeFrameDescriptor(scratch, JitFrame_IonJS, ExitFrameLayout::Size());
masm.push(scratch);
masm.push(ICTailCallReg);
masm.branch(target);
}
inline void
EmitBaselineCreateStubFrameDescriptor(MacroAssembler& masm, Register reg, uint32_t headerSize)
{
// Compute stub frame size. We have to add two pointers: the stub reg and
// previous frame pointer pushed by EmitEnterStubFrame.
masm.movePtr(BaselineFrameReg, reg);
masm.addPtr(Imm32(sizeof(intptr_t) * 2), reg);
masm.subPtr(BaselineStackReg, reg);
masm.makeFrameDescriptor(reg, JitFrame_BaselineStub, headerSize);
}
inline void
EmitBaselineCallVM(JitCode* target, MacroAssembler& masm)
{
Register scratch = R2.scratchReg();
EmitBaselineCreateStubFrameDescriptor(masm, scratch, ExitFrameLayout::Size());
masm.push(scratch);
masm.call(target);
}
inline void
EmitIonCallVM(JitCode* target, size_t stackSlots, MacroAssembler& masm)
{
uint32_t descriptor = MakeFrameDescriptor(masm.framePushed(), JitFrame_IonStub,
ExitFrameLayout::Size());
masm.Push(Imm32(descriptor));
masm.callJit(target);
// Remove rest of the frame left on the stack. We remove the return address
// which is implicitly popped when returning.
size_t framePop = sizeof(ExitFrameLayout) - sizeof(void*);
// Pop arguments from framePushed.
masm.implicitPop(stackSlots * sizeof(void*) + framePop);
}
struct BaselineStubFrame {
uintptr_t savedFrame;
uintptr_t savedStub;
uintptr_t returnAddress;
uintptr_t descriptor;
};
static const uint32_t STUB_FRAME_SIZE = sizeof(BaselineStubFrame);
static const uint32_t STUB_FRAME_SAVED_STUB_OFFSET = offsetof(BaselineStubFrame, savedStub);
inline void
EmitBaselineEnterStubFrame(MacroAssembler& masm, Register scratch)
{
MOZ_ASSERT(scratch != ICTailCallReg);
// Compute frame size.
masm.movePtr(BaselineFrameReg, scratch);
masm.addPtr(Imm32(BaselineFrame::FramePointerOffset), scratch);
masm.subPtr(BaselineStackReg, scratch);
masm.store32(scratch, Address(BaselineFrameReg, BaselineFrame::reverseOffsetOfFrameSize()));
// Note: when making changes here, don't forget to update
// BaselineStubFrame if needed.
// Push frame descriptor and return address.
masm.makeFrameDescriptor(scratch, JitFrame_BaselineJS, BaselineStubFrameLayout::Size());
masm.subPtr(Imm32(STUB_FRAME_SIZE), StackPointer);
masm.storePtr(scratch, Address(StackPointer, offsetof(BaselineStubFrame, descriptor)));
masm.storePtr(ICTailCallReg, Address(StackPointer,
offsetof(BaselineStubFrame, returnAddress)));
// Save old frame pointer, stack pointer and stub reg.
masm.storePtr(ICStubReg, Address(StackPointer,
offsetof(BaselineStubFrame, savedStub)));
masm.storePtr(BaselineFrameReg, Address(StackPointer,
offsetof(BaselineStubFrame, savedFrame)));
masm.movePtr(BaselineStackReg, BaselineFrameReg);
// Stack should remain aligned.
masm.assertStackAlignment(sizeof(Value), 0);
}
inline void
EmitIonEnterStubFrame(MacroAssembler& masm, Register scratch)
{
MOZ_ASSERT(ICTailCallReg == ra);
// In LoongArch the ra register contains the return address,
// but in jit frames we expect it to be on the stack. As a result
// push the link register (which is actually part of the previous frame.
// Therefore using push instead of Push).
masm.push(ICTailCallReg);
masm.Push(ICStubReg);
}
inline void
EmitBaselineLeaveStubFrame(MacroAssembler& masm, bool calledIntoIon = false)
{
// Ion frames do not save and restore the frame pointer. If we called
// into Ion, we have to restore the stack pointer from the frame descriptor.
// If we performed a VM call, the descriptor has been popped already so
// in that case we use the frame pointer.
if (calledIntoIon) {
masm.pop(ScratchRegister);
masm.rshiftPtr(Imm32(FRAMESIZE_SHIFT), ScratchRegister);
masm.addPtr(ScratchRegister, BaselineStackReg);
} else {
masm.movePtr(BaselineFrameReg, BaselineStackReg);
}
masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedFrame)),
BaselineFrameReg);
masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, savedStub)),
ICStubReg);
// Load the return address.
masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, returnAddress)),
ICTailCallReg);
// Discard the frame descriptor.
masm.loadPtr(Address(StackPointer, offsetof(BaselineStubFrame, descriptor)), ScratchRegister);
masm.addPtr(Imm32(STUB_FRAME_SIZE), StackPointer);
}
inline void
EmitIonLeaveStubFrame(MacroAssembler& masm)
{
masm.Pop(ICStubReg);
masm.pop(ICTailCallReg); // See EmitIonEnterStubFrame for explanation on pop/Pop.
}
inline void
EmitStowICValues(MacroAssembler& masm, int values)
{
MOZ_ASSERT(values >= 0 && values <= 2);
switch(values) {
case 1:
// Stow R0
masm.Push(R0);
break;
case 2:
// Stow R0 and R1
masm.Push(R0);
masm.Push(R1);
}
}
inline void
EmitUnstowICValues(MacroAssembler& masm, int values, bool discard = false)
{
MOZ_ASSERT(values >= 0 && values <= 2);
switch(values) {
case 1:
// Unstow R0.
if (discard)
masm.addPtr(Imm32(sizeof(Value)), BaselineStackReg);
else
masm.popValue(R0);
break;
case 2:
// Unstow R0 and R1.
if (discard) {
masm.addPtr(Imm32(sizeof(Value) * 2), BaselineStackReg);
} else {
masm.popValue(R1);
masm.popValue(R0);
}
break;
}
masm.adjustFrame(-values * sizeof(Value));
}
inline void
EmitCallTypeUpdateIC(MacroAssembler& masm, JitCode* code, uint32_t objectOffset)
{
// R0 contains the value that needs to be typechecked.
// The object we're updating is a boxed Value on the stack, at offset
// objectOffset from $sp, excluding the return address.
// Save the current ICStubReg to stack, as well as the TailCallReg,
// since on LoongArch, the $ra is live.
masm.subPtr(Imm32(2 * sizeof(intptr_t)), StackPointer);
masm.storePtr(ICStubReg, Address(StackPointer, sizeof(intptr_t)));
masm.storePtr(ICTailCallReg, Address(StackPointer, 0));
// This is expected to be called from within an IC, when ICStubReg
// is properly initialized to point to the stub.
masm.loadPtr(Address(ICStubReg, ICUpdatedStub::offsetOfFirstUpdateStub()),
ICStubReg);
// Load stubcode pointer from ICStubReg into ICTailCallReg.
masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
// Call the stubcode.
masm.call(R2.scratchReg());
// Restore the old stub reg and tailcall reg.
masm.loadPtr(Address(StackPointer, 0), ICTailCallReg);
masm.loadPtr(Address(StackPointer, sizeof(intptr_t)), ICStubReg);
masm.addPtr(Imm32(2 * sizeof(intptr_t)), StackPointer);
// The update IC will store 0 or 1 in R1.scratchReg() reflecting if the
// value in R0 type-checked properly or not.
Label success;
masm.ma_b(R1.scratchReg(), Imm32(1), &success, Assembler::Equal, ShortJump);
// If the IC failed, then call the update fallback function.
EmitBaselineEnterStubFrame(masm, R1.scratchReg());
masm.loadValue(Address(BaselineStackReg, STUB_FRAME_SIZE + objectOffset), R1);
masm.Push(R0);
masm.Push(R1);
masm.Push(ICStubReg);
// Load previous frame pointer, push BaselineFrame*.
masm.loadPtr(Address(BaselineFrameReg, 0), R0.scratchReg());
masm.pushBaselineFramePtr(R0.scratchReg(), R0.scratchReg());
EmitBaselineCallVM(code, masm);
EmitBaselineLeaveStubFrame(masm);
// Success at end.
masm.bind(&success);
}
template <typename AddrType>
inline void
EmitPreBarrier(MacroAssembler& masm, const AddrType& addr, MIRType type)
{
// On LoongArch, $ra is clobbered by patchableCallPreBarrier. Save it first.
masm.push(ra);
masm.patchableCallPreBarrier(addr, type);
masm.pop(ra);
}
inline void
EmitStubGuardFailure(MacroAssembler& masm)
{
// NOTE: This routine assumes that the stub guard code left the stack in
// the same state it was in when it was entered.
// BaselineStubEntry points to the current stub.
// Load next stub into ICStubReg
masm.loadPtr(Address(ICStubReg, ICStub::offsetOfNext()), ICStubReg);
// Load stubcode pointer from BaselineStubEntry into scratch register.
masm.loadPtr(Address(ICStubReg, ICStub::offsetOfStubCode()), R2.scratchReg());
// Return address is already loaded, just jump to the next stubcode.
MOZ_ASSERT(ICTailCallReg == ra);
masm.branch(R2.scratchReg());
}
} // namespace jit
} // namespace js
#endif /* jit_loongarch64_SharedICHelpers_loongarch64_h */

View file

@ -0,0 +1,53 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
* vim: set ts=8 sts=2 et sw=2 tw=80:
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef jit_loongarch64_SharedICRegisters_loongarch64_h
#define jit_loongarch64_SharedICRegisters_loongarch64_h
#include "jit/loongarch64/Assembler-loongarch64.h"
#include "jit/Registers.h"
#include "jit/RegisterSets.h"
namespace js {
namespace jit {
// Must be a callee-saved register for preservation around generateEnterJIT().
static constexpr Register BaselineFrameReg = s0;
static constexpr Register BaselineStackReg = sp;
// ValueOperands R0, R1, and R2.
// R0 == JSReturnReg, and R2 uses registers not preserved across calls. R1 value
// should be preserved across calls.
static constexpr ValueOperand R0(a2);
static constexpr ValueOperand R1(s1);
static constexpr ValueOperand R2(a0);
// ICTailCallReg and ICStubReg
// These use registers that are not preserved across calls.
static constexpr Register ICTailCallReg = ra;
static constexpr Register ICStubReg = t0;
// ExtractTemps must be callee-save registers:
// ICSetProp_Native::Compiler::generateStubCode() stores the object
// in ExtractTemp0, but then calls callTypeUpdateIC(), which clobbers
// caller-save registers.
static constexpr Register ExtractTemp0 = s7;
static constexpr Register ExtractTemp1 = s8;
// Note that ICTailCallReg is actually just the link register.
// In LoongArch code emission, we do not clobber ICTailCallReg since we keep
// the return address for calls there.
// FloatReg0 must be equal to ReturnFloatReg.
static constexpr FloatRegister FloatReg0 = f0;
static constexpr FloatRegister FloatReg1 = f1;
static constexpr FloatRegister FloatReg2 = f2;
static constexpr FloatRegister FloatReg3 = f3;
} // namespace jit
} // namespace js
#endif /* jit_loongarch64_SharedICRegisters_loongarch64_h */

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,8 @@
#include "wasm/WasmTypes.h"
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64) || \
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \
defined(JS_CODEGEN_LOONGARCH64)
// Push return addresses callee-side.
# define JS_USE_LINK_REGISTER
#endif

View file

@ -301,7 +301,7 @@ LIRGeneratorShared::defineSinCos(LInstructionHelper<2, Ops, Temps> *lir, MDefini
#elif defined(JS_CODEGEN_ARM64)
lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE,
LFloatReg(FloatRegister(FloatRegisters::d1, FloatRegisters::Double))));
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64)
lir->setDef(1, LDefinition(vreg + VREG_INCREMENT, LDefinition::DOUBLE, LFloatReg(f2)));
#elif defined(JS_CODEGEN_NONE)
MOZ_CRASH();

View file

@ -443,7 +443,7 @@ PodSet(T* aDst, const T& aSrc, size_t aNElem)
# define JS_SWEPT_CODE_PATTERN 0xED // IN instruction, crashes in user mode.
#elif defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
# define JS_SWEPT_CODE_PATTERN 0xA3 // undefined instruction
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || defined(JS_CODEGEN_LOONGARCH64)
# define JS_SWEPT_CODE_PATTERN 0x01 // undefined instruction
#else
# error "JS_SWEPT_CODE_PATTERN not defined for this platform"

View file

@ -524,6 +524,24 @@ elif CONFIG['JS_CODEGEN_ARM64']:
'jit/arm64/vixl/MozSimulator-vixl.cpp',
'jit/arm64/vixl/Simulator-vixl.cpp'
]
elif CONFIG['JS_CODEGEN_LOONGARCH64']:
jit_ioncheck1_deunified_sources += [
'jit/mips-shared/Bailouts-mips-shared.cpp',
'jit/mips-shared/BaselineCompiler-mips-shared.cpp',
'jit/mips-shared/BaselineIC-mips-shared.cpp',
'jit/mips-shared/MoveEmitter-mips-shared.cpp',
]
jit_ioncheck2_deunified_sources += [
'jit/loongarch64/Architecture-loongarch64.cpp',
'jit/loongarch64/Assembler-loongarch64.cpp',
'jit/loongarch64/Bailouts-loongarch64.cpp',
'jit/loongarch64/BaselineCompiler-loongarch64.cpp',
'jit/loongarch64/BaselineIC-loongarch64.cpp',
'jit/loongarch64/MacroAssembler-loongarch64.cpp',
'jit/mips64/MoveEmitter-mips64.cpp',
'jit/loongarch64/SharedIC-loongarch64.cpp',
'jit/loongarch64/Trampoline-loongarch64.cpp',
]
elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']:
jit_ioncheck1_deunified_sources += [
'jit/mips-shared/Architecture-mips-shared.cpp',

View file

@ -976,6 +976,10 @@ arm*-*)
ENABLE_ION=1
AC_DEFINE(JS_CPU_ARM)
;;
loongarch64*-*)
ENABLE_ION=1
AC_DEFINE(JS_CPU_LOONGARCH64)
;;
sparc-*)
dnl ENABLE_ION=0
AC_DEFINE(JS_CPU_SPARC)
@ -1781,6 +1785,9 @@ elif test "$CPU_ARCH" = "arm"; then
dnl ARM platforms may trap on unaligned accesses; catch the signal and
dnl recover.
elif test "$CPU_ARCH" = "loongarch64"; then
AC_DEFINE(JS_CODEGEN_LOONGARCH64)
JS_CODEGEN_LOONGARCH64=1
elif test "$CPU_ARCH" = "mips" || test "$CPU_ARCH" = "mips32" || test "$CPU_ARCH" = "mips64"; then
if test ! "$HAVE_64BIT_BUILD"; then
AC_DEFINE(JS_CODEGEN_MIPS32)
@ -1798,6 +1805,7 @@ AC_SUBST(JS_SIMULATOR_MIPS32)
AC_SUBST(JS_SIMULATOR_MIPS64)
AC_SUBST(JS_CODEGEN_ARM)
AC_SUBST(JS_CODEGEN_ARM64)
AC_SUBST(JS_CODEGEN_LOONGARCH64)
AC_SUBST(JS_CODEGEN_MIPS32)
AC_SUBST(JS_CODEGEN_MIPS64)
AC_SUBST(JS_CODEGEN_X86)

View file

@ -66,7 +66,7 @@ wasm::HasCompilerSupport(ExclusiveContext* cx)
return false;
#endif
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64)
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_ARM64) || defined(JS_CODEGEN_LOONGARCH64)
return false;
#else
return true;

View file

@ -392,7 +392,7 @@ struct macos_aarch64_context {
# define PC_sig(p) R15_sig(p)
#elif defined(__aarch64__)
# define PC_sig(p) EPC_sig(p)
#elif defined(JS_CPU_MIPS)
#elif defined(JS_CPU_MIPS) || defined(JS_CPU_LOONGARCH64)
# define PC_sig(p) EPC_sig(p)
#endif