Skip to content

Commit 009ce6c

Browse files
committed
fix removing 1 / 0
1 parent f419f6b commit 009ce6c

2 files changed

Lines changed: 39 additions & 0 deletions

File tree

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.google.common.collect.Lists;
44
import de.peeeq.wurstio.TimeTaker;
5+
import de.peeeq.wurstscript.WurstOperator;
56
import de.peeeq.wurstscript.WLogger;
67
import de.peeeq.wurstscript.intermediatelang.optimizer.BranchMerger;
78
import de.peeeq.wurstscript.intermediatelang.optimizer.ConstantAndCopyPropagation;
@@ -201,10 +202,34 @@ private List<ImExpr> collectSideEffects(ImExpr expr, SideEffectAnalyzer analyzer
201202
if (expr == null) {
202203
return Collections.emptyList();
203204
}
205+
if (mayTrapAtRuntime(expr)) {
206+
return Collections.singletonList(expr);
207+
}
204208
if (analyzer.hasObservableSideEffects(expr, func -> func.isNative()
205209
&& UselessFunctionCallsRemover.isFunctionWithoutSideEffect(func.getName()))) {
206210
return Collections.singletonList(expr);
207211
}
208212
return Collections.emptyList();
209213
}
214+
215+
private boolean mayTrapAtRuntime(Element elem) {
216+
if (elem instanceof ImOperatorCall) {
217+
ImOperatorCall opCall = (ImOperatorCall) elem;
218+
WurstOperator op = opCall.getOp();
219+
if ((op == WurstOperator.DIV_INT || op == WurstOperator.MOD_INT) && opCall.getArguments().size() >= 2) {
220+
ImExpr denominator = opCall.getArguments().get(1);
221+
// Preserve integer div/mod unless denominator is provably non-zero.
222+
if (!(denominator instanceof ImIntVal) || ((ImIntVal) denominator).getValI() == 0) {
223+
return true;
224+
}
225+
}
226+
}
227+
for (int i = 0; i < elem.size(); i++) {
228+
Element child = elem.get(i);
229+
if (mayTrapAtRuntime(child)) {
230+
return true;
231+
}
232+
}
233+
return false;
234+
}
210235
}

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

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,20 @@ public void test_unused_func_remover2() throws IOException {
599599
assertTrue(compiledAndOptimized.contains("I2S"), "I2S should not be removed");
600600
}
601601

602+
@Test
603+
public void deadStoreKeepsPotentialDivisionTrap() throws IOException {
604+
test().executeProg(false).lines(
605+
"package test",
606+
" @extern native I2S(int i) returns string",
607+
" native getY() returns int",
608+
" init",
609+
" int y = getY()",
610+
" string x = I2S(1 div y)",
611+
"endpackage");
612+
String compiledNoOpt = Files.toString(new File("test-output/OptimizerTests_deadStoreKeepsPotentialDivisionTrap_no_opts.j"), Charsets.UTF_8);
613+
assertTrue(compiledNoOpt.contains("1 /"), "potential division trap should be preserved");
614+
}
615+
602616
@Test
603617
public void test_unreachableCodeRemover() throws IOException {
604618
test().withStdLib().lines(

0 commit comments

Comments
 (0)