Issue #3049 - Allow more LoongArch minimal JIT arguments

This commit is contained in:
Basilisk-Dev 2026-04-23 03:36:42 -04:00 • committed by wuggy
commit 2198d41700
2 changed files with 58 additions and 21 deletions

View file

@ -8,6 +8,15 @@ function withLocal(a, b) {
return d + 1; return d + 1;
} }
function addEight(a, b, c, d, e, f, g, h) {
return a + b + c + d + e + f + g + h;
}
function assignSixthArg(a, b, c, d, e, f) {
f = a + e;
return f;
}
function overflow(a, b) { function overflow(a, b) {
return a + b; return a + b;
} }
@ -259,8 +268,12 @@ function groupedSwitchValue(a) {
for (var i = 0; i < 100; i++) { for (var i = 0; i < 100; i++) {
assertEq(add(i, i + 1), (i + i + 1)); assertEq(add(i, i + 1), (i + i + 1));
assertEq(withLocal(i, 7), i + 7); assertEq(withLocal(i, 7), i + 7);
assertEq(addEight(i, 1, 2, 3, 4, 5, 6, 7), i + 28);
} }
assertEq(assignSixthArg(2, 0, 0, 0, 5, 99), 7);
assertEq(assignSixthArg(-3, 0, 0, 0, 8, 11), 5);
assertEq(overflow(2147483647, 1), 2147483648); assertEq(overflow(2147483647, 1), 2147483648);
assertEq(unsupported(2, 3), 5.5); assertEq(unsupported(2, 3), 5.5);
assertEq(largeResult(7), 307); assertEq(largeResult(7), 307);

View file

@ -48,8 +48,10 @@ enum LoongArchReg : uint8_t {
t8 = 20 t8 = 20
}; };
static constexpr LoongArchReg ArgRegs[] = { a0, a1 }; static constexpr size_t MaxArgCount = 16;
static constexpr LoongArchReg LocalRegs[] = { a3, a4, a5, a6, a7 }; static constexpr LoongArchReg ArgsPointerReg = a0;
static constexpr LoongArchReg ResultPointerReg = a1;
static constexpr LoongArchReg LocalRegs[] = { a2, a3, a4, a5, a6, a7 };
static constexpr LoongArchReg StackRegs[] = { t0, t1, t2, t3, t4, t5, t6 }; static constexpr LoongArchReg StackRegs[] = { t0, t1, t2, t3, t4, t5, t6 };
static constexpr LoongArchReg WideScratch = t7; static constexpr LoongArchReg WideScratch = t7;
static constexpr LoongArchReg NarrowScratch = t8; static constexpr LoongArchReg NarrowScratch = t8;
@ -76,7 +78,7 @@ IsNumericKind(MinimalValueKind kind)
return kind == MinimalValueKind::Int32 || kind == MinimalValueKind::Boolean; return kind == MinimalValueKind::Int32 || kind == MinimalValueKind::Boolean;
} }
using TinyLoongArchJitCode = bool (*)(int32_t arg0, int32_t arg1, MinimalJitResult* out); using TinyLoongArchJitCode = bool (*)(int32_t* args, MinimalJitResult* out);
enum MinimalFastPathKind : uint8_t { enum MinimalFastPathKind : uint8_t {
MinimalFastPathUninitialized = 0, MinimalFastPathUninitialized = 0,
@ -185,7 +187,7 @@ struct ControlFlowState
size_t stackDepth; size_t stackDepth;
LoongArchReg stackRegs[mozilla::ArrayLength(StackRegs)]; LoongArchReg stackRegs[mozilla::ArrayLength(StackRegs)];
MinimalValueKind stackKinds[mozilla::ArrayLength(StackRegs)]; MinimalValueKind stackKinds[mozilla::ArrayLength(StackRegs)];
MinimalValueKind argKinds[mozilla::ArrayLength(ArgRegs)]; MinimalValueKind argKinds[MaxArgCount];
MinimalValueKind localKinds[mozilla::ArrayLength(LocalRegs)]; MinimalValueKind localKinds[mozilla::ArrayLength(LocalRegs)];
ControlFlowState() ControlFlowState()
@ -208,7 +210,7 @@ class MinimalLoongArchCompiler
size_t failPatches_[128]; size_t failPatches_[128];
size_t failPatchCount_; size_t failPatchCount_;
StackValue stack_[mozilla::ArrayLength(StackRegs)]; StackValue stack_[mozilla::ArrayLength(StackRegs)];
MinimalValueKind argKinds_[mozilla::ArrayLength(ArgRegs)]; MinimalValueKind argKinds_[MaxArgCount];
MinimalValueKind localKinds_[mozilla::ArrayLength(LocalRegs)]; MinimalValueKind localKinds_[mozilla::ArrayLength(LocalRegs)];
size_t stackDepth_; size_t stackDepth_;
bool reachable_; bool reachable_;
@ -230,7 +232,7 @@ class MinimalLoongArchCompiler
stack_[i].reg = state.stackRegs[i]; stack_[i].reg = state.stackRegs[i];
stack_[i].kind = state.stackKinds[i]; stack_[i].kind = state.stackKinds[i];
} }
for (size_t i = 0; i < mozilla::ArrayLength(argKinds_); i++) for (size_t i = 0; i < MaxArgCount; i++)
argKinds_[i] = state.argKinds[i]; argKinds_[i] = state.argKinds[i];
for (size_t i = 0; i < mozilla::ArrayLength(localKinds_); i++) for (size_t i = 0; i < mozilla::ArrayLength(localKinds_); i++)
localKinds_[i] = state.localKinds[i]; localKinds_[i] = state.localKinds[i];
@ -247,7 +249,7 @@ class MinimalLoongArchCompiler
return false; return false;
} }
} }
for (size_t i = 0; i < mozilla::ArrayLength(argKinds_); i++) { for (size_t i = 0; i < MaxArgCount; i++) {
if (argKinds_[i] != state.argKinds[i]) if (argKinds_[i] != state.argKinds[i])
return false; return false;
} }
@ -265,7 +267,7 @@ class MinimalLoongArchCompiler
state->stackRegs[i] = stack_[i].reg; state->stackRegs[i] = stack_[i].reg;
state->stackKinds[i] = stack_[i].kind; state->stackKinds[i] = stack_[i].kind;
} }
for (size_t i = 0; i < mozilla::ArrayLength(argKinds_); i++) for (size_t i = 0; i < MaxArgCount; i++)
state->argKinds[i] = argKinds_[i]; state->argKinds[i] = argKinds_[i];
for (size_t i = 0; i < mozilla::ArrayLength(localKinds_); i++) for (size_t i = 0; i < mozilla::ArrayLength(localKinds_); i++)
state->localKinds[i] = localKinds_[i]; state->localKinds[i] = localKinds_[i];
@ -323,6 +325,19 @@ class MinimalLoongArchCompiler
return emit(EncodeUnsignedImm12(0x03c00000, dst, src, imm)); return emit(EncodeUnsignedImm12(0x03c00000, dst, src, imm));
} }
bool emitLoadWord(LoongArchReg dst, LoongArchReg base, uint32_t offset) {
return emit(EncodeUnsignedImm12(0x28800000, dst, base, offset));
}
bool emitStoreWord(LoongArchReg src, LoongArchReg base, uint32_t offset) {
return emit(EncodeUnsignedImm12(0x29800000, src, base, offset));
}
bool emitLoadArg(LoongArchReg dst, uint32_t slot) {
MOZ_ASSERT(slot < MaxArgCount);
return emitLoadWord(dst, ArgsPointerReg, slot * sizeof(int32_t));
}
bool emitSltui(LoongArchReg dst, LoongArchReg src, uint32_t imm) { bool emitSltui(LoongArchReg dst, LoongArchReg src, uint32_t imm) {
return emit(EncodeUnsignedImm12(0x02400000, dst, src, imm)); return emit(EncodeUnsignedImm12(0x02400000, dst, src, imm));
} }
@ -542,11 +557,11 @@ class MinimalLoongArchCompiler
} }
bool emitReturn(const StackValue& result) { bool emitReturn(const StackValue& result) {
if (!emit(EncodeUnsignedImm12(0x29800000, result.reg, a2, 0))) if (!emitStoreWord(result.reg, ResultPointerReg, 0))
return false; return false;
if (!emitLoadImm32(NarrowScratch, int32_t(result.kind))) if (!emitLoadImm32(NarrowScratch, int32_t(result.kind)))
return false; return false;
if (!emit(EncodeUnsignedImm12(0x29800000, NarrowScratch, a2, sizeof(uint32_t)))) if (!emitStoreWord(NarrowScratch, ResultPointerReg, sizeof(uint32_t)))
return false; return false;
if (!emit(EncodeImm12(0x02800000, a0, zero, 1))) if (!emit(EncodeImm12(0x02800000, a0, zero, 1)))
return false; return false;
@ -643,14 +658,14 @@ class MinimalLoongArchCompiler
bool emitStoreArg(uint32_t slot) { bool emitStoreArg(uint32_t slot) {
if (slot >= script_->numArgs() || !stackDepth_) if (slot >= script_->numArgs() || !stackDepth_)
return false; return false;
if (!emitMove(ArgRegs[slot], stack_[stackDepth_ - 1].reg)) if (!emitStoreWord(stack_[stackDepth_ - 1].reg, ArgsPointerReg, slot * sizeof(int32_t)))
return false; return false;
argKinds_[slot] = stack_[stackDepth_ - 1].kind; argKinds_[slot] = stack_[stackDepth_ - 1].kind;
return true; return true;
} }
bool supportedScriptShape() const { bool supportedScriptShape() const {
return script_->numArgs() <= 2 && return script_->numArgs() <= MaxArgCount &&
script_->nfixed() <= mozilla::ArrayLength(LocalRegs) && script_->nfixed() <= mozilla::ArrayLength(LocalRegs) &&
!script_->isAsync() && !script_->isAsync() &&
!script_->isStarGenerator() && !script_->isStarGenerator() &&
@ -701,7 +716,9 @@ class MinimalLoongArchCompiler
reachable_(true), reachable_(true),
sawReturn_(false) sawReturn_(false)
{ {
for (size_t i = 0; i < mozilla::ArrayLength(argKinds_); i++) for (size_t i = 0; i < MaxArgCount; i++)
argKinds_[i] = MinimalValueKind::Undefined;
for (size_t i = 0; i < script_->numArgs(); i++)
argKinds_[i] = MinimalValueKind::Int32; argKinds_[i] = MinimalValueKind::Int32;
for (size_t i = 0; i < mozilla::ArrayLength(localKinds_); i++) for (size_t i = 0; i < mozilla::ArrayLength(localKinds_); i++)
localKinds_[i] = MinimalValueKind::Undefined; localKinds_[i] = MinimalValueKind::Undefined;
@ -738,8 +755,12 @@ class MinimalLoongArchCompiler
uint32_t arg = GET_ARGNO(pc); uint32_t arg = GET_ARGNO(pc);
if (arg >= script_->numArgs()) if (arg >= script_->numArgs())
return false; return false;
if (!pushTempFromReg(ArgRegs[arg], argKinds_[arg])) if (stackDepth_ >= mozilla::ArrayLength(StackRegs))
return false; return false;
LoongArchReg dst = allocStackReg();
if (!emitLoadArg(dst, arg))
return false;
stack_[stackDepth_++] = { dst, argKinds_[arg] };
break; break;
} }
case JSOP_SETARG: case JSOP_SETARG:
@ -853,6 +874,7 @@ class MinimalLoongArchCompiler
case JSOP_CHECKLEXICAL: case JSOP_CHECKLEXICAL:
case JSOP_LOOPENTRY: case JSOP_LOOPENTRY:
case JSOP_JUMPTARGET: case JSOP_JUMPTARGET:
case JSOP_LINENO:
case JSOP_NOP: case JSOP_NOP:
case JSOP_CONDSWITCH: case JSOP_CONDSWITCH:
break; break;
@ -1201,7 +1223,7 @@ class MinimalLoongArchCompiler
static bool static bool
CanUseMinimalJit(JSScript* script, const CallArgs& args) CanUseMinimalJit(JSScript* script, const CallArgs& args)
{ {
if (!script || script->numArgs() > 2) if (!script || script->numArgs() > MaxArgCount)
return false; return false;
if (args.length() < script->numArgs()) if (args.length() < script->numArgs())
@ -1435,9 +1457,10 @@ TryCallLoongArchMinimalJit(JSContext* cx, HandleFunction fun, const CallArgs& ar
return true; return true;
MinimalJitResult result = { 0, MinimalValueKind::Int32 }; MinimalJitResult result = { 0, MinimalValueKind::Int32 };
int32_t arg0 = script->numArgs() >= 1 ? args[0].toInt32() : 0; int32_t argPayloads[MaxArgCount] = { 0 };
int32_t arg1 = script->numArgs() >= 2 ? args[1].toInt32() : 0; for (uint32_t i = 0; i < script->numArgs(); i++)
if (!fn(arg0, arg1, &result)) argPayloads[i] = args[i].toInt32();
if (!fn(argPayloads, &result))
return true; return true;
args.rval().set(MinimalJitResultToValue(result)); args.rval().set(MinimalJitResultToValue(result));
@ -1468,9 +1491,10 @@ TryEnterLoongArchMinimalJit(JSContext* cx, RunState& state)
return false; return false;
MinimalJitResult result = { 0, MinimalValueKind::Int32 }; MinimalJitResult result = { 0, MinimalValueKind::Int32 };
int32_t arg0 = state.script()->numArgs() >= 1 ? invoke.args()[0].toInt32() : 0; int32_t argPayloads[MaxArgCount] = { 0 };
int32_t arg1 = state.script()->numArgs() >= 2 ? invoke.args()[1].toInt32() : 0; for (uint32_t i = 0; i < state.script()->numArgs(); i++)
if (!fn(arg0, arg1, &result)) argPayloads[i] = invoke.args()[i].toInt32();
if (!fn(argPayloads, &result))
return false; return false;
state.setReturnValue(MinimalJitResultToValue(result)); state.setReturnValue(MinimalJitResultToValue(result));