From 683173c33b8094350a238d91b930b5afc2e97b42 Mon Sep 17 00:00:00 2001 From: Basilisk-Dev Date: Fri, 24 Apr 2026 15:58:49 -0400 Subject: [PATCH] Issue #3049 - Add loongarch64 wasm backend build support --- .../jit/loongarch64/Assembler-loongarch64.h | 18 +++++- .../MacroAssembler-loongarch64-inl.h | 18 ++++-- .../MacroAssembler-loongarch64.cpp | 13 ++-- .../loongarch64/MacroAssembler-loongarch64.h | 64 +++++++++++++++---- js/src/moz.build | 5 ++ js/src/wasm/WasmFrameIterator.cpp | 12 +++- js/src/wasm/WasmSignalHandlers.cpp | 7 +- js/src/wasm/WasmStubs.cpp | 23 +------ js/src/wasm/WasmTypes.cpp | 6 +- 9 files changed, 113 insertions(+), 53 deletions(-) diff --git a/js/src/jit/loongarch64/Assembler-loongarch64.h b/js/src/jit/loongarch64/Assembler-loongarch64.h index 3a3c2bc050..81b7929f2b 100644 --- a/js/src/jit/loongarch64/Assembler-loongarch64.h +++ b/js/src/jit/loongarch64/Assembler-loongarch64.h @@ -1839,9 +1839,21 @@ class Assembler : public AssemblerLOONGARCH64 { static void Bind(uint8_t* rawCode, CodeLabel label); void bind(RepatchLabel* label); void bindLater(Label* label, wasm::TrapDesc target) { - (void)label; - (void)target; - MOZ_CRASH("wasm trap patching is not supported on loongarch64 yet"); + if (label->used()) { + int32_t next; + + BufferOffset b(label); + do { + Instruction* inst = editSrc(b); + + append(wasm::TrapSite(target, b.getOffset())); + next = inst[1].encode(); + inst[1].makeNop(); + + b = BufferOffset(next); + } while (next != LabelBase::INVALID_OFFSET); + } + label->reset(); } void processCodeLabels(uint8_t* rawCode); diff --git a/js/src/jit/loongarch64/MacroAssembler-loongarch64-inl.h b/js/src/jit/loongarch64/MacroAssembler-loongarch64-inl.h index d4d83d0daa..64e06ffbb6 100644 --- a/js/src/jit/loongarch64/MacroAssembler-loongarch64-inl.h +++ b/js/src/jit/loongarch64/MacroAssembler-loongarch64-inl.h @@ -1436,16 +1436,20 @@ void MacroAssembler::clampIntToUint8(Register reg) { template void MacroAssembler::wasmBoundsCheck(Condition cond, Register index, L label) { - (void)cond; - (void)index; - (void)label; - MOZ_CRASH("wasm bounds checks are not supported on loongarch64 yet"); + BufferOffset bo = ma_BoundsCheck(ScratchRegister); + append(wasm::BoundsCheck(bo.getOffset())); + ma_b(index, ScratchRegister, label, cond); } void MacroAssembler::wasmPatchBoundsCheck(uint8_t* patchAt, uint32_t limit) { - (void)patchAt; - (void)limit; - MOZ_CRASH("wasm bounds checks are not supported on loongarch64 yet"); + InstImm* i0 = reinterpret_cast(patchAt); + InstImm* i1 = reinterpret_cast(i0->next()); + + *i0 = InstImm(op_lu12i_w, int32_t((limit >> 12) & 0xfffff), + Register::FromCode(i0->extractRD()), false); + *i1 = InstImm(op_ori, int32_t(limit & 0xfff), + Register::FromCode(i1->extractRJ()), + Register::FromCode(i1->extractRD()), 12); } void MacroAssembler::memoryBarrier(MemoryBarrierBits barrier) { diff --git a/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp b/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp index c065dbd0df..938783b93a 100644 --- a/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp +++ b/js/src/jit/loongarch64/MacroAssembler-loongarch64.cpp @@ -2469,18 +2469,19 @@ void MacroAssembler::repatchFarJump(uint8_t* code, uint32_t farJumpOffset, } CodeOffset MacroAssembler::nopPatchableToNearJump() { - MOZ_CRASH("wasm patchable jumps are not supported on loongarch64"); + CodeOffset offset(currentOffset()); + as_nop(); + return offset; } void MacroAssembler::patchNopToNearJump(uint8_t* jump, uint8_t* target) { - (void)jump; - (void)target; - MOZ_CRASH("wasm patchable jumps are not supported on loongarch64"); + MOZ_ASSERT(reinterpret_cast(jump)->is()); + new (jump) InstJump(op_b, JOffImm26(target - jump)); } void MacroAssembler::patchNearJumpToNop(uint8_t* jump) { - (void)jump; - MOZ_CRASH("wasm patchable jumps are not supported on loongarch64"); + MOZ_ASSERT(reinterpret_cast(jump)->is()); + new (jump) InstNOP(); } void MacroAssembler::call(wasm::SymbolicAddress target) { diff --git a/js/src/jit/loongarch64/MacroAssembler-loongarch64.h b/js/src/jit/loongarch64/MacroAssembler-loongarch64.h index 160dd70274..31ed3777d3 100644 --- a/js/src/jit/loongarch64/MacroAssembler-loongarch64.h +++ b/js/src/jit/loongarch64/MacroAssembler-loongarch64.h @@ -116,6 +116,27 @@ class MacroAssemblerLOONGARCH64 : public Assembler { Label* overflow); void ma_add32TestOverflow(Register rd, Register rj, Imm32 imm, Label* overflow); + template + void ma_add32TestOverflow(Register rd, Register rj, Register rk, + L overflow) { + ScratchRegisterScope scratch(asMasm()); + as_add_d(scratch, rj, rk); + as_add_w(rd, rj, rk); + ma_b(rd, Register(scratch), overflow, Assembler::NotEqual); + } + template + void ma_add32TestOverflow(Register rd, Register rj, Imm32 imm, L overflow) { + if (is_intN(imm.value, 12)) { + ScratchRegisterScope scratch(asMasm()); + as_addi_d(scratch, rj, imm.value); + as_addi_w(rd, rj, imm.value); + ma_b(rd, scratch, overflow, Assembler::NotEqual); + } else { + SecondScratchRegisterScope scratch2(asMasm()); + ma_li(scratch2, imm); + ma_add32TestOverflow(rd, rj, scratch2, overflow); + } + } void ma_addPtrTestOverflow(Register rd, Register rj, Register rk, Label* overflow); void ma_addPtrTestOverflow(Register rd, Register rj, Imm32 imm, @@ -257,6 +278,25 @@ class MacroAssemblerLOONGARCH64 : public Assembler { Label* overflow); void ma_add32TestCarry(Condition cond, Register rd, Register rj, Imm32 imm, Label* overflow); + template + void ma_add32TestCarry(Condition cond, Register rd, Register rj, Register rk, + L overflow) { + MOZ_ASSERT(cond == Assembler::CarrySet || cond == Assembler::CarryClear); + MOZ_ASSERT_IF(rd == rj, rk != rd); + ScratchRegisterScope scratch(asMasm()); + as_add_w(rd, rj, rk); + as_sltu(scratch, rd, rd == rj ? rk : rj); + ma_b(Register(scratch), Register(scratch), overflow, + cond == Assembler::CarrySet ? Assembler::NonZero : Assembler::Zero); + } + template + void ma_add32TestCarry(Condition cond, Register rd, Register rj, Imm32 imm, + L overflow) { + SecondScratchRegisterScope scratch2(asMasm()); + MOZ_ASSERT(rj != scratch2); + ma_li(scratch2, imm); + ma_add32TestCarry(cond, rd, rj, scratch2, overflow); + } // subtract void ma_sub_w(Register rd, Register rj, Imm32 imm); @@ -376,18 +416,15 @@ class MacroAssemblerLOONGARCH64 : public Assembler { template void ma_b(Register lhs, const T& rhs, wasm::TrapDesc target, Condition c, JumpKind jumpKind = LongJump) { - (void)lhs; - (void)rhs; - (void)target; - (void)c; - (void)jumpKind; - MOZ_CRASH("wasm trap branches are not supported on loongarch64 yet"); + Label label; + ma_b(lhs, rhs, &label, c, jumpKind); + bindLater(&label, target); } void ma_b(wasm::TrapDesc target, JumpKind jumpKind = LongJump) { - (void)target; - (void)jumpKind; - MOZ_CRASH("wasm trap jumps are not supported on loongarch64 yet"); + Label label; + ma_b(&label, jumpKind); + bindLater(&label, target); } void ma_b(Label* l, JumpKind jumpKind = LongJump); @@ -1306,12 +1343,13 @@ class MacroAssemblerLOONGARCH64Compat : public MacroAssemblerLOONGARCH64 { static void calculateAlignedStackPointer(void** stackPointer); void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { - (void)globalDataOffset; - (void)dest; - MOZ_CRASH("wasm globals are not supported on loongarch64 yet"); + loadPtr(Address(GlobalReg, globalDataOffset - WasmGlobalRegBias), dest); } void loadWasmPinnedRegsFromTls() { - MOZ_CRASH("wasm pinned registers are not supported on loongarch64 yet"); + loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, memoryBase)), HeapReg); + loadPtr(Address(WasmTlsReg, offsetof(wasm::TlsData, globalData)), + GlobalReg); + ma_add_d(GlobalReg, GlobalReg, Imm32(WasmGlobalRegBias)); } void cmpPtrSet(Assembler::Condition cond, Address lhs, ImmPtr rhs, diff --git a/js/src/moz.build b/js/src/moz.build index 2a95733396..2fec5af526 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -375,6 +375,11 @@ if not CONFIG['JS_CODEGEN_LOONGARCH64']: 'wasm/WasmBaselineCompile.cpp', 'wasm/WasmIonCompile.cpp', ] +else: + 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 diff --git a/js/src/wasm/WasmFrameIterator.cpp b/js/src/wasm/WasmFrameIterator.cpp index 4538e46bbd..e65c9c1fe3 100644 --- a/js/src/wasm/WasmFrameIterator.cpp +++ b/js/src/wasm/WasmFrameIterator.cpp @@ -242,7 +242,14 @@ 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) || defined(JS_CODEGEN_LOONGARCH64) +#elif defined(JS_CODEGEN_LOONGARCH64) +static const unsigned PushedRetAddr = 8; +static const unsigned PushedFP = 36; +static const unsigned StoredFP = 40; +# if defined(DEBUG) +static const unsigned PostStorePrePopFP = 0; +# endif +#elif defined(JS_CODEGEN_NONE) # if defined(DEBUG) static const unsigned PushedRetAddr = 0; static const unsigned PostStorePrePopFP = 0; @@ -258,7 +265,8 @@ PushRetAddr(MacroAssembler& masm) { #if defined(JS_CODEGEN_ARM) masm.push(lr); -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) masm.push(ra); #else // The x86/x64 call instruction pushes the return address. diff --git a/js/src/wasm/WasmSignalHandlers.cpp b/js/src/wasm/WasmSignalHandlers.cpp index aaeaf59b3c..704223069c 100644 --- a/js/src/wasm/WasmSignalHandlers.cpp +++ b/js/src/wasm/WasmSignalHandlers.cpp @@ -172,6 +172,11 @@ class AutoSetHandlingSegFault # define RSP_sig(p) ((p)->uc_mcontext.gregs[29]) # define RFP_sig(p) ((p)->uc_mcontext.gregs[30]) # endif +# if defined(__linux__) && defined(__loongarch__) +# define EPC_sig(p) ((p)->uc_mcontext.__pc) +# define RSP_sig(p) ((p)->uc_mcontext.__gregs[3]) +# define RFP_sig(p) ((p)->uc_mcontext.__gregs[22]) +# endif #elif defined(__NetBSD__) # define XMM_sig(p,i) (((struct fxsave64*)(p)->uc_mcontext.__fpregs)->fx_xmm[i]) # define EIP_sig(p) ((p)->uc_mcontext.__gregs[_REG_EIP]) @@ -399,7 +404,7 @@ struct macos_aarch64_context { static uint8_t** ContextToPC(CONTEXT* context) { -#if defined(JS_CODEGEN_NONE) || defined(JS_CODEGEN_LOONGARCH64) +#if defined(JS_CODEGEN_NONE) MOZ_CRASH(); #else return reinterpret_cast(&PC_sig(context)); diff --git a/js/src/wasm/WasmStubs.cpp b/js/src/wasm/WasmStubs.cpp index 40704c93dd..c6d66a2947 100644 --- a/js/src/wasm/WasmStubs.cpp +++ b/js/src/wasm/WasmStubs.cpp @@ -84,7 +84,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) || defined(JS_CODEGEN_LOONGARCH64) +#elif defined(JS_CODEGEN_NONE) static const unsigned FramePushedAfterSave = 0; #else static const unsigned FramePushedAfterSave = NonVolatileRegs.gprs().size() * sizeof(intptr_t) @@ -107,7 +107,8 @@ wasm::GenerateEntry(MacroAssembler& masm, const FuncExport& fe) // Save the return address if it wasn't already saved by the call insn. #if defined(JS_CODEGEN_ARM) masm.push(lr); -#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) +#elif defined(JS_CODEGEN_MIPS32) || defined(JS_CODEGEN_MIPS64) || \ + defined(JS_CODEGEN_LOONGARCH64) masm.push(ra); #endif @@ -1099,21 +1100,3 @@ wasm::GenerateThrowStub(MacroAssembler& masm, Label* throwLabel) offsets.end = masm.currentOffset(); return offsets; } - -#if defined(JS_CODEGEN_LOONGARCH64) - -bool -js::wasm::BaselineCanCompile(const FunctionGenerator* fg) -{ - (void)fg; - return false; -} - -bool -js::wasm::CompileFunction(IonCompileTask* task) -{ - (void)task; - return false; -} - -#endif diff --git a/js/src/wasm/WasmTypes.cpp b/js/src/wasm/WasmTypes.cpp index f92609b84f..a36e4fe17e 100644 --- a/js/src/wasm/WasmTypes.cpp +++ b/js/src/wasm/WasmTypes.cpp @@ -379,6 +379,7 @@ GetCPUID() ARM = 0x3, MIPS = 0x4, MIPS64 = 0x5, + LOONGARCH64 = 0x6, ARCH_BITS = 3 }; @@ -399,7 +400,10 @@ 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) || defined(JS_CODEGEN_LOONGARCH64) +#elif defined(JS_CODEGEN_LOONGARCH64) + MOZ_ASSERT(jit::GetLOONGARCH64Flags() <= (UINT32_MAX >> ARCH_BITS)); + return LOONGARCH64 | (jit::GetLOONGARCH64Flags() << ARCH_BITS); +#elif defined(JS_CODEGEN_NONE) return 0; #else # error "unknown architecture"