Skip to content

Commit 709d4fe

Browse files
committed
Budget overlapping Lua inline results
1 parent 98f62cf commit 709d4fe

2 files changed

Lines changed: 89 additions & 1 deletion

File tree

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/translation/imoptimizer/ImInliner.java

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,21 @@ public void visit(ImVarAccess access) {
506506
});
507507
}
508508

509+
private static int statementExpressionResultSlots(ImStmt statement) {
510+
int[] result = {0};
511+
statement.accept(new ImStmt.DefaultVisitor() {
512+
@Override
513+
public void visit(ImStatementExpr expression) {
514+
super.visit(expression);
515+
ImType type = expression.getExpr().attrTyp();
516+
if (!(type instanceof ImVoid)) {
517+
result[0] += ImHelper.flattenedJassArity(type);
518+
}
519+
}
520+
});
521+
return result[0];
522+
}
523+
509524
private LuaPressure pressureOf(Iterable<ImVar> variables) {
510525
LuaPressure result = new LuaPressure();
511526
for (ImVar variable : variables) {
@@ -646,7 +661,15 @@ private LuaPressure pressureAt(Element element) {
646661
java.util.Set<ImVar> active = Collections.newSetFromMap(new IdentityHashMap<>());
647662
active.addAll(live.toJavaSet());
648663
collectReadLocals(statement, active);
649-
return pressureOf(active);
664+
LuaPressure pressure = pressureOf(active);
665+
int stagedResults = statementExpressionResultSlots(statement);
666+
if (stagedResults > 0) {
667+
// Flattening stages each already-inlined sibling result until the
668+
// surrounding expression consumes it. The pre-inline liveness map
669+
// cannot contain those future backend temporaries yet.
670+
pressure.add("statement-expression-results", stagedResults);
671+
}
672+
return pressure;
650673
}
651674
}
652675
current = current.getParent();

de.peeeq.wurstscript/src/test/java/tests/wurstscript/tests/OptimizerTests.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,6 +1686,71 @@ public void luaArithmeticHelperRetryReusesSequentialSlots() {
16861686
"sequential helper sites should share the same peak allocation slots");
16871687
}
16881688

1689+
@Test
1690+
public void luaArithmeticHelperRetryBudgetsOverlappingArgumentResults() {
1691+
WurstModel model = Ast.WurstModel();
1692+
ImTranslator translator = new ImTranslator(model, false,
1693+
new RunArgs().with("-lua", "-localOptimizations"));
1694+
ImProg prog = translator.getImProg();
1695+
ImVar helperA = JassIm.ImVar(model, TypesHelper.imInt(), "a", false);
1696+
ImVar helperB = JassIm.ImVar(model, TypesHelper.imInt(), "b", false);
1697+
ImFunction helper = JassIm.ImFunction(model, "__wurst_modInt", JassIm.ImTypeVars(),
1698+
JassIm.ImVars(helperA, helperB), TypesHelper.imInt(), JassIm.ImVars(),
1699+
JassIm.ImStmts(JassIm.ImReturn(model, JassIm.ImVarAccess(helperA))),
1700+
Collections.emptyList());
1701+
translator.luaModIntFunc = helper;
1702+
1703+
ImVars callerParameters = JassIm.ImVars();
1704+
for (int i = 0; i < 187; i++) {
1705+
callerParameters.add(JassIm.ImVar(model, TypesHelper.imInt(), "p" + i, false));
1706+
}
1707+
ImVars fiveParameters = JassIm.ImVars();
1708+
ImExprs overlappingArguments = JassIm.ImExprs();
1709+
for (int i = 0; i < 5; i++) {
1710+
fiveParameters.add(JassIm.ImVar(model, TypesHelper.imInt(), "arg" + i, false));
1711+
overlappingArguments.add(JassIm.ImFunctionCall(model, helper, JassIm.ImTypeArguments(),
1712+
JassIm.ImExprs(JassIm.ImVarAccess(callerParameters.get(i)), JassIm.ImIntVal(3)),
1713+
false, de.peeeq.wurstscript.translation.imtranslation.CallType.NORMAL));
1714+
}
1715+
ImFunction takesFive = JassIm.ImFunction(model, "takesFive", JassIm.ImTypeVars(), fiveParameters,
1716+
JassIm.ImVoid(), JassIm.ImVars(), JassIm.ImStmts(), Collections.emptyList());
1717+
ImVars keepAliveParameters = JassIm.ImVars();
1718+
ImExprs keepAliveArguments = JassIm.ImExprs();
1719+
for (int i = 0; i < callerParameters.size(); i++) {
1720+
keepAliveParameters.add(JassIm.ImVar(model, TypesHelper.imInt(), "value" + i, false));
1721+
keepAliveArguments.add(JassIm.ImVarAccess(callerParameters.get(i)));
1722+
}
1723+
ImFunction keepAlive = JassIm.ImFunction(model, "keepAlive", JassIm.ImTypeVars(),
1724+
keepAliveParameters, JassIm.ImVoid(), JassIm.ImVars(), JassIm.ImStmts(),
1725+
Collections.emptyList());
1726+
ImFunction caller = JassIm.ImFunction(model, "caller", JassIm.ImTypeVars(), callerParameters,
1727+
JassIm.ImVoid(), JassIm.ImVars(), JassIm.ImStmts(
1728+
JassIm.ImFunctionCall(model, takesFive, JassIm.ImTypeArguments(), overlappingArguments,
1729+
false, de.peeeq.wurstscript.translation.imtranslation.CallType.NORMAL),
1730+
JassIm.ImFunctionCall(model, keepAlive, JassIm.ImTypeArguments(), keepAliveArguments,
1731+
false, de.peeeq.wurstscript.translation.imtranslation.CallType.NORMAL)),
1732+
Collections.emptyList());
1733+
prog.getFunctions().add(helper);
1734+
prog.getFunctions().add(takesFive);
1735+
prog.getFunctions().add(keepAlive);
1736+
prog.getFunctions().add(caller);
1737+
1738+
int changed = new ImInliner(translator).inlineLuaDivModHelpersWithinLocalBudget();
1739+
assertTrue(changed < 5,
1740+
"overlapping argument results must stop helper inlining at the register budget");
1741+
int[] remaining = {0};
1742+
caller.getBody().accept(new ImStmts.DefaultVisitor() {
1743+
@Override
1744+
public void visit(ImFunctionCall call) {
1745+
super.visit(call);
1746+
if (call.getFunc() == helper) {
1747+
remaining[0]++;
1748+
}
1749+
}
1750+
});
1751+
assertTrue(remaining[0] > 0, "some overlapping helper calls must remain after the budget is reached");
1752+
}
1753+
16891754
@Test
16901755
public void luaArithmeticHelperRetryPreservesLocalPlayerAllocationClasses() {
16911756
WurstModel model = Ast.WurstModel();

0 commit comments

Comments
 (0)