Issue #3049 - Support more LoongArch minimal JIT branch ops

This commit is contained in:
Basilisk-Dev 2026-04-23 03:31:22 -04:00 • committed by wuggy
commit 43a6d946f8
2 changed files with 180 additions and 0 deletions

View file

@ -192,6 +192,70 @@ function sumRange(n) {
return total;
}
function coalesceArg(a) {
return a ?? 9;
}
function coalesceLocal() {
var x;
return x ?? 5;
}
function coalesceNull() {
return null ?? 5;
}
function sparseSwitchValue(a) {
var out = -1;
switch (a) {
case 1:
out = 10;
break;
case 4:
out = 40;
break;
default:
out = 99;
break;
}
return out;
}
function denseSwitchValue(a) {
var out = -1;
switch (a) {
case 0:
out = 7;
break;
case 1:
out = 8;
break;
case 2:
out = 9;
break;
default:
out = 11;
break;
}
return out;
}
function groupedSwitchValue(a) {
var out = 0;
switch (a) {
case 0:
case 1:
out = 10;
break;
case 3:
out = 30;
default:
out = out + 1;
break;
}
return out;
}
for (var i = 0; i < 100; i++) {
assertEq(add(i, i + 1), (i + i + 1));
assertEq(withLocal(i, 7), i + 7);
@ -272,6 +336,21 @@ assertEq(chooseOrder(2, 3), true);
assertEq(chooseOrder(3, 2), false);
assertEq(sumRange(0), 0);
assertEq(sumRange(5), 10);
assertEq(coalesceArg(0), 0);
assertEq(coalesceArg(7), 7);
assertEq(coalesceLocal(), 5);
assertEq(coalesceNull(), 5);
assertEq(sparseSwitchValue(1), 10);
assertEq(sparseSwitchValue(4), 40);
assertEq(sparseSwitchValue(2), 99);
assertEq(denseSwitchValue(0), 7);
assertEq(denseSwitchValue(1), 8);
assertEq(denseSwitchValue(2), 9);
assertEq(denseSwitchValue(5), 11);
assertEq(groupedSwitchValue(0), 10);
assertEq(groupedSwitchValue(1), 10);
assertEq(groupedSwitchValue(3), 31);
assertEq(groupedSwitchValue(5), 1);
(function testPropertyWrappers() {
function getX(obj) { return obj.x; }

View file

@ -854,7 +854,22 @@ class MinimalLoongArchCompiler
case JSOP_LOOPENTRY:
case JSOP_JUMPTARGET:
case JSOP_NOP:
case JSOP_CONDSWITCH:
break;
case JSOP_COALESCE: {
if (!stackDepth_)
return false;
MinimalValueKind kind = stack_[stackDepth_ - 1].kind;
if (kind == MinimalValueKind::Null || kind == MinimalValueKind::Undefined)
break;
uint32_t target = uint32_t(int32_t(pcOffset) + GET_JUMP_OFFSET(pc));
if (!recordTargetState(target))
return false;
if (!emitBranch(BranchKind::Always, zero, target))
return false;
reachable_ = false;
break;
}
case JSOP_OR:
case JSOP_AND: {
if (!stackDepth_)
@ -867,6 +882,87 @@ class MinimalLoongArchCompiler
return false;
break;
}
case JSOP_CASE: {
StackValue rhs;
StackValue lhs;
if (!pop(&rhs) || !pop(&lhs))
return false;
uint32_t target = uint32_t(int32_t(pcOffset) + GET_JUMP_OFFSET(pc));
if (lhs.kind != rhs.kind) {
stack_[stackDepth_++] = lhs;
break;
}
if (!recordTargetState(target))
return false;
if (lhs.kind == MinimalValueKind::Null || lhs.kind == MinimalValueKind::Undefined) {
if (!emitBranch(BranchKind::Always, zero, target))
return false;
reachable_ = false;
break;
}
if (!emitEq(lhs.reg, rhs.reg, WideScratch, false))
return false;
if (!emitBranch(BranchKind::IfTrue, WideScratch, target))
return false;
stack_[stackDepth_++] = lhs;
break;
}
case JSOP_TABLESWITCH: {
StackValue input;
if (!pop(&input))
return false;
if (input.kind != MinimalValueKind::Int32)
return false;
uint32_t defaultTarget = uint32_t(int32_t(pcOffset) + GET_JUMP_OFFSET(pc));
if (!recordTargetState(defaultTarget))
return false;
jsbytecode* tablePc = pc + JUMP_OFFSET_LEN;
int32_t low = GET_JUMP_OFFSET(tablePc);
tablePc += JUMP_OFFSET_LEN;
int32_t high = GET_JUMP_OFFSET(tablePc);
tablePc += JUMP_OFFSET_LEN;
if (high < low)
return false;
if (!emitLoadImm32(NarrowScratch, low))
return false;
if (!emitCompare(JSOP_LT, input.reg, NarrowScratch, WideScratch))
return false;
if (!emitBranch(BranchKind::IfTrue, WideScratch, defaultTarget))
return false;
if (!emitLoadImm32(NarrowScratch, high))
return false;
if (!emitCompare(JSOP_GT, input.reg, NarrowScratch, WideScratch))
return false;
if (!emitBranch(BranchKind::IfTrue, WideScratch, defaultTarget))
return false;
uint32_t caseCount = uint32_t(high - low + 1);
for (uint32_t i = 0; i < caseCount; i++) {
int32_t rel = GET_JUMP_OFFSET(tablePc);
tablePc += JUMP_OFFSET_LEN;
if (!rel)
continue;
uint32_t target = uint32_t(int32_t(pcOffset) + rel);
if (!recordTargetState(target))
return false;
if (!emitLoadImm32(NarrowScratch, low + int32_t(i)))
return false;
if (!emitEq(input.reg, NarrowScratch, WideScratch, false))
return false;
if (!emitBranch(BranchKind::IfTrue, WideScratch, target))
return false;
}
if (!emitBranch(BranchKind::Always, zero, defaultTarget))
return false;
reachable_ = false;
break;
}
case JSOP_ADD:
case JSOP_SUB:
case JSOP_MUL:
@ -1031,7 +1127,12 @@ class MinimalLoongArchCompiler
return false;
stack_[stackDepth_ - 1].kind = MinimalValueKind::Int32;
break;
case JSOP_DEFAULT:
case JSOP_GOTO: {
if (!stackDepth_ && op == JSOP_DEFAULT)
return false;
if (op == JSOP_DEFAULT)
stackDepth_--;
uint32_t target = uint32_t(int32_t(pcOffset) + GET_JUMP_OFFSET(pc));
if (!recordTargetState(target))
return false;