Issue #3049 - Wire up loongarch64 SpiderMonkey baseline backend

This commit is contained in:
Basilisk-Dev 2026-04-23 23:41:12 -04:00 committed by wuggy
commit feb29eaff0
11 changed files with 122 additions and 14 deletions

View file

@ -20,7 +20,7 @@
using namespace js;
#if defined(__loongarch64)
#if defined(__loongarch64) && !defined(JS_CODEGEN_LOONGARCH64)
namespace js {
namespace jit {

View file

@ -2224,6 +2224,51 @@ void Assembler::TraceJumpRelocations(JSTracer* trc, JitCode* code,
}
}
static void TraceBufferDataRelocations(JSTracer* trc,
LOONGBufferWithExecutableCopy* buffer,
CompactBufferReader& reader);
void Assembler::trace(JSTracer* trc) {
for (size_t i = 0; i < jumps_.length(); i++) {
RelativePatch& rp = jumps_[i];
if (rp.kind == Relocation::JITCODE) {
JitCode* code = JitCode::FromExecutable((uint8_t*)rp.target);
TraceManuallyBarrieredEdge(trc, &code, "masmrel32");
MOZ_ASSERT(code == JitCode::FromExecutable((uint8_t*)rp.target));
}
}
if (dataRelocations_.length()) {
CompactBufferReader reader(dataRelocations_);
TraceBufferDataRelocations(trc, &m_buffer, reader);
}
}
static void TraceOneDataRelocation(JSTracer* trc, Instruction* inst) {
void* ptr = (void*)Assembler::ExtractLoad64Value(inst);
void* prior = ptr;
// Data relocations can be for Values or for raw pointers. If a Value is
// zero-tagged, we can trace it as if it were a raw pointer. If a Value
// is not zero-tagged, we have to interpret it as a Value to ensure that the
// tag bits are masked off to recover the actual pointer.
uintptr_t word = reinterpret_cast<uintptr_t>(ptr);
if (word >> JSVAL_TAG_SHIFT) {
// This relocation is a Value with a non-zero tag.
Value v = Value::fromRawBits(word);
TraceManuallyBarrieredEdge(trc, &v, "jit-masm-value");
ptr = (void*)v.bitsAsPunboxPointer();
} else {
// This relocation is a raw pointer or a Value with a zero tag.
// No barrier needed since these are constants.
TraceManuallyBarrieredGenericPointerEdge(
trc, reinterpret_cast<gc::Cell**>(&ptr), "jit-masm-ptr");
}
if (ptr != prior) {
Assembler::UpdateLoad64Value(inst, uint64_t(ptr));
}
}
static void TraceOneDataRelocation(JSTracer* trc,
mozilla::Maybe<AutoWritableJitCode>& awjc,
JitCode* code, Instruction* inst) {
@ -2255,6 +2300,15 @@ static void TraceOneDataRelocation(JSTracer* trc,
}
}
static void TraceBufferDataRelocations(JSTracer* trc,
LOONGBufferWithExecutableCopy* buffer,
CompactBufferReader& reader) {
while (reader.more()) {
BufferOffset bo(reader.readUnsigned());
TraceOneDataRelocation(trc, buffer->getInst(bo));
}
}
/* static */
void Assembler::TraceDataRelocations(JSTracer* trc, JitCode* code,
CompactBufferReader& reader) {
@ -2465,6 +2519,10 @@ void Assembler::PatchDataWithValueCheck(CodeLocationLabel label,
Assembler::UpdateLoad64Value(inst, uint64_t(newValue.value));
}
void Assembler::PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm) {
Assembler::UpdateLoad64Value((Instruction*)code, uint64_t(imm.value));
}
uint64_t Assembler::ExtractInstructionImmediate(uint8_t* code) {
InstImm* inst = (InstImm*)code;
return Assembler::ExtractLoad64Value(inst);

View file

@ -215,6 +215,12 @@ static constexpr Register WasmJitEntryReturnScratch = t1;
static constexpr uint32_t ABIStackAlignment = 16;
static constexpr uint32_t CodeAlignment = 16;
// This boolean indicates whether we support SIMD instructions flavoured for
// this architecture or not. Rather than a method in the LIRGenerator, it is
// here such that it is accessible from the entire codebase. Once full support
// for SIMD is reached on all tier-1 platforms, this constant can be deleted.
static constexpr bool SupportsSimd = false;
static constexpr uint32_t JitStackAlignment = 16;
static constexpr uint32_t JitStackValueAlignment =
@ -821,6 +827,19 @@ class LOONGBufferWithExecutableCopy : public LOONGBuffer {
}
}
bool appendBuffer(const LOONGBufferWithExecutableCopy& other) {
if (this->oom() || other.oom()) {
return false;
}
for (Slice* cur = other.head; cur != nullptr; cur = cur->getNext()) {
if (!appendRawCode(cur->instructions.begin(), cur->length())) {
return false;
}
}
return !this->oom();
}
bool appendRawCode(const uint8_t* code, size_t numBytes) {
if (this->oom()) {
return false;
@ -1800,6 +1819,9 @@ class Assembler : public AssemblerLOONGARCH64 {
public:
Assembler() : AssemblerLOONGARCH64() {}
// MacroAssemblers hold onto gcthings, so they are traced by the GC.
void trace(JSTracer* trc);
static uintptr_t GetPointer(uint8_t*);
using AssemblerLOONGARCH64::bind;
@ -1840,6 +1862,7 @@ class Assembler : public AssemblerLOONGARCH64 {
PatchedImmPtr newValue,
PatchedImmPtr expectedValue);
static void PatchInstructionImmediate(uint8_t* code, PatchedImmPtr imm);
static uint64_t ExtractInstructionImmediate(uint8_t* code);
static void ToggleCall(CodeLocationLabel inst_, bool enabled);

View file

@ -394,6 +394,18 @@ class MacroAssemblerLOONGARCH64Compat : public MacroAssemblerLOONGARCH64 {
MacroAssemblerLOONGARCH64Compat() {}
struct AutoPrepareForPatching {
explicit AutoPrepareForPatching(MacroAssemblerLOONGARCH64Compat&) {}
};
bool asmMergeWith(const MacroAssemblerLOONGARCH64Compat& other) {
if (!AssemblerShared::asmMergeWith(size(), other))
return false;
return m_buffer.appendBuffer(other.m_buffer);
}
size_t labelToPatchOffset(CodeOffset label) { return label.offset(); }
void convertBoolToInt32(Register src, Register dest) {
ma_and(dest, src, Imm32(0xff));
};
@ -502,6 +514,11 @@ class MacroAssemblerLOONGARCH64Compat : public MacroAssemblerLOONGARCH64 {
void push(FloatRegister reg) { ma_push(reg); }
void pop(Register reg) { ma_pop(reg); }
void pop(FloatRegister reg) { ma_pop(reg); }
void pop(const Address& address) {
ScratchRegisterScope scratch(asMasm());
ma_pop(scratch);
storePtr(scratch, address);
}
// Emit a branch that can be toggled to a non-operation. On LOONGARCH64 we use
// "andi" instruction to toggle the branch.

View file

@ -1620,7 +1620,8 @@ CodeGeneratorShared::getJumpLabelForBranch(MBasicBlock* block)
}
// This function is not used for MIPS/MIPS64. MIPS has branchToBlock.
#if !defined(JS_CODEGEN_MIPS32) && !defined(JS_CODEGEN_MIPS64)
#if !defined(JS_CODEGEN_MIPS32) && !defined(JS_CODEGEN_MIPS64) && \
!defined(JS_CODEGEN_LOONGARCH64)
void
CodeGeneratorShared::jumpToBlock(MBasicBlock* mir, Assembler::Condition cond)
{

View file

@ -349,7 +349,6 @@ main_deunified_sources = [
'vm/WeakMapPtr.cpp',
'vm/Xdr.cpp',
'wasm/AsmJS.cpp',
'wasm/WasmBaselineCompile.cpp',
'wasm/WasmBinaryFormat.cpp',
'wasm/WasmBinaryIterator.cpp',
'wasm/WasmBinaryToAST.cpp',
@ -361,7 +360,6 @@ main_deunified_sources = [
'wasm/WasmFrameIterator.cpp',
'wasm/WasmGenerator.cpp',
'wasm/WasmInstance.cpp',
'wasm/WasmIonCompile.cpp',
'wasm/WasmJS.cpp',
'wasm/WasmModule.cpp',
'wasm/WasmSignalHandlers.cpp',
@ -372,6 +370,12 @@ main_deunified_sources = [
'wasm/WasmTypes.cpp'
]
if not CONFIG['JS_CODEGEN_LOONGARCH64']:
SOURCES += [
'wasm/WasmBaselineCompile.cpp',
'wasm/WasmIonCompile.cpp',
]
# jsarray.cpp and jsatom.cpp cannot be built in unified mode because
# xpcshell is broken during packaging when compiled with gcc-4.8.2
# builtin/RegExp.cpp cannot be built in unified mode because it is built
@ -427,7 +431,7 @@ if CONFIG['ENABLE_TRACE_LOGGING']:
jit_ioncheck1_deunified_sources = []
jit_ioncheck2_deunified_sources = []
jit_ioncheck3_deunified_sources = []
if not CONFIG['ENABLE_ION']:
if CONFIG['JS_CODEGEN_NONE']:
jit_ioncheck1_deunified_sources += [
'jit/none/Trampoline-none.cpp'
]
@ -538,9 +542,9 @@ elif CONFIG['JS_CODEGEN_LOONGARCH64']:
'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',
'jit/mips64/MoveEmitter-mips64.cpp',
]
elif CONFIG['JS_CODEGEN_MIPS32'] or CONFIG['JS_CODEGEN_MIPS64']:
jit_ioncheck1_deunified_sources += [

View file

@ -1728,7 +1728,7 @@ if test -n "$JS_SIMULATOR"; then
esac
fi
if test -z "$ENABLE_ION"; then
if test -z "$ENABLE_ION" && test "$CPU_ARCH" != "loongarch64"; then
AC_DEFINE(JS_CODEGEN_NONE)
JS_CODEGEN_NONE=1
elif test "$JS_SIMULATOR" = arm; then

View file

@ -242,7 +242,7 @@ static const unsigned PushedRetAddr = 8;
static const unsigned PushedFP = 32;
static const unsigned StoredFP = 36;
static const unsigned PostStorePrePopFP = 4;
#elif defined(JS_CODEGEN_NONE)
#elif defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_LOONGARCH64)
# if defined(DEBUG)
static const unsigned PushedRetAddr = 0;
static const unsigned PostStorePrePopFP = 0;
@ -826,7 +826,7 @@ wasm::ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled)
BOffImm16 calleeOffset;
callerInsn->extractImm16(&calleeOffset);
void* callee = calleeOffset.getDest(reinterpret_cast<Instruction*>(caller));
#elif defined(JS_CODEGEN_NONE)
#elif defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_LOONGARCH64)
MOZ_CRASH();
void* callee = nullptr;
#else
@ -853,7 +853,7 @@ wasm::ToggleProfiling(const Code& code, const CallSite& callSite, bool enabled)
MOZ_CRASH();
#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64)
new (caller) InstImm(op_regimm, zero, rt_bgezal, BOffImm16(to - caller));
#elif defined(JS_CODEGEN_NONE)
#elif defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_LOONGARCH64)
MOZ_CRASH();
#else
# error "Missing architecture"

View file

@ -399,7 +399,7 @@ struct macos_aarch64_context {
static uint8_t**
ContextToPC(CONTEXT* context)
{
#ifdef JS_CODEGEN_NONE
#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_LOONGARCH64)
MOZ_CRASH();
#else
return reinterpret_cast<uint8_t**>(&PC_sig(context));

View file

@ -83,7 +83,7 @@ static const LiveRegisterSet NonVolatileRegs =
static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) +
NonVolatileRegs.fpus().getPushSizeInBytes() +
sizeof(double);
#elif defined(JS_CODEGEN_NONE)
#elif defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_LOONGARCH64)
static const unsigned FramePushedAfterSave = 0;
#else
static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t)
@ -586,6 +586,10 @@ static const unsigned SavedTlsReg = sizeof(void*);
ProfilingOffsets
wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* throwLabel)
{
#if defined(JS_CODEGEN_LOONGARCH64)
MOZ_CRASH("wasm import JIT exits are unsupported on loongarch64");
return ProfilingOffsets();
#else
masm.setFramePushed(0);
// JIT calls use the following stack layout (sp grows to the left):
@ -808,6 +812,7 @@ wasm::GenerateImportJitExit(MacroAssembler& masm, const FuncImport& fi, Label* t
offsets.end = masm.currentOffset();
return offsets;
#endif
}
// Generate a stub that calls into ReportTrap with the right trap reason.
@ -1049,7 +1054,7 @@ wasm::GenerateInterruptExit(MacroAssembler& masm, Label* throwLabel)
masm.ret();
#elif defined(JS_CODEGEN_ARM64)
MOZ_CRASH();
#elif defined (JS_CODEGEN_NONE)
#elif defined (JS_CODEGEN_NONE) || defined(JS_CODEGEN_LOONGARCH64)
MOZ_CRASH();
#else
# error "Unknown architecture!"

View file

@ -399,7 +399,7 @@ GetCPUID()
#elif defined(JS_CODEGEN_MIPS64)
MOZ_ASSERT(jit::GetMIPSFlags() <= (UINT32_MAX >> ARCH_BITS));
return MIPS64 | (jit::GetMIPSFlags() << ARCH_BITS);
#elif defined(JS_CODEGEN_NONE)
#elif defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_LOONGARCH64)
return 0;
#else
# error "unknown architecture"