Skip to content

Commit 94c4f32

Browse files
committed
add RealRealMixed rewrites and tests
1 parent b96882c commit 94c4f32

2 files changed

Lines changed: 1000 additions & 582 deletions

File tree

de.peeeq.wurstscript/src/main/java/de/peeeq/wurstscript/intermediatelang/optimizer/SimpleRewrites.java

Lines changed: 160 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,18 @@ public class SimpleRewrites implements OptimizerPass {
1818
private int totalRewrites = 0;
1919
private final boolean showRewrites = false;
2020

21+
private static boolean isNumberLiteral(ImExpr e) {
22+
return e instanceof ImIntVal || e instanceof ImRealVal;
23+
}
24+
25+
private static float asFloat(ImExpr e) {
26+
if (e instanceof ImRealVal) {
27+
return Float.parseFloat(((ImRealVal) e).getValR());
28+
} else {
29+
return ((ImIntVal) e).getValI();
30+
}
31+
}
32+
2133
@Override
2234
public int optimize(ImTranslator trans) {
2335
ImProg prog = trans.getImProg();
@@ -178,10 +190,31 @@ private void optimizeOpCall(ImOperatorCall opc) {
178190
} else if (right instanceof ImBoolVal) {
179191
boolean b2 = ((ImBoolVal) right).getValB();
180192
wasViable = replaceBoolTerm(opc, left, b2);
181-
} else if (left instanceof ImIntVal && right instanceof ImIntVal) {
182-
wasViable = optimizeIntInt(opc, wasViable, (ImIntVal) left, (ImIntVal) right);
183-
} else if (left instanceof ImRealVal && right instanceof ImRealVal) {
184-
wasViable = optimizeRealReal(opc, wasViable, (ImRealVal) left, (ImRealVal) right);
193+
} else if (isNumberLiteral(left) && isNumberLiteral(right)) {
194+
// If any side is real (or the op is a real op), fold as real; otherwise fold as int.
195+
boolean foldAsReal =
196+
(left instanceof ImRealVal) ||
197+
(right instanceof ImRealVal) ||
198+
opc.getOp() == WurstOperator.DIV_REAL ||
199+
opc.getOp() == WurstOperator.MOD_REAL;
200+
201+
if (foldAsReal) {
202+
wasViable = optimizeRealRealMixed(opc, wasViable, left, right);
203+
} else if (left instanceof ImIntVal && right instanceof ImIntVal) {
204+
wasViable = optimizeIntInt(opc, wasViable, (ImIntVal) left, (ImIntVal) right);
205+
} else {
206+
wasViable = false; // unknown numeric combo
207+
}
208+
} else if (left instanceof ImStringVal) {
209+
// Fold "" + expr => expr
210+
if (opc.getOp() == WurstOperator.PLUS
211+
&& ((ImStringVal) left).getValS().isEmpty()) {
212+
right.setParent(null);
213+
opc.replaceBy(right);
214+
wasViable = true;
215+
} else {
216+
wasViable = false;
217+
}
185218
} else if (right instanceof ImStringVal) {
186219
if (left instanceof ImStringVal) {
187220
wasViable = optimizeStringString(opc, (ImStringVal) left, (ImStringVal) right);
@@ -201,13 +234,11 @@ private void optimizeOpCall(ImOperatorCall opc) {
201234
else {
202235
ImExpr expr = opc.getArguments().get(0);
203236
if (opc.getOp() == WurstOperator.UNARY_MINUS && expr instanceof ImIntVal) {
204-
ImIntVal imIntVal = (ImIntVal) expr;
205-
if (imIntVal.getValI() <= 0) {
206-
int inverseVal = imIntVal.getValI() * -1;
207-
ImIntVal newVal = JassIm.ImIntVal(inverseVal);
208-
opc.replaceBy(newVal);
237+
int v = ((ImIntVal) expr).getValI();
238+
if (v != Integer.MIN_VALUE && v <= 0) {
239+
opc.replaceBy(JassIm.ImIntVal(-v));
240+
wasViable = false;
209241
}
210-
wasViable = false;
211242
} else if (expr instanceof ImBoolVal) {
212243
boolean b1 = ((ImBoolVal) expr).getValB();
213244
boolean result;
@@ -241,7 +272,7 @@ private void optimizeOpCall(ImOperatorCall opc) {
241272
List<ImExpr> args = inner.getArguments().removeAll();
242273
ImExprs imExprs = JassIm.ImExprs();
243274
args.forEach((e) ->
244-
imExprs.add(JassIm.ImOperatorCall(WurstOperator.NOT, JassIm.ImExprs(e.copy()))));
275+
imExprs.add(JassIm.ImOperatorCall(WurstOperator.NOT, JassIm.ImExprs(e.copy()))));
245276

246277
ImOperatorCall opCall = JassIm.ImOperatorCall(oppositeOperator(inner.getOp()), imExprs);
247278
opc.replaceBy(opCall);
@@ -263,6 +294,89 @@ private void optimizeOpCall(ImOperatorCall opc) {
263294

264295
}
265296

297+
private boolean optimizeRealRealMixed(ImOperatorCall opc, boolean wasViable, ImExpr left, ImExpr right) {
298+
float f1 = asFloat(left);
299+
float f2 = asFloat(right);
300+
boolean isConditional = false;
301+
boolean isArithmetic = false;
302+
boolean result = false;
303+
float resultVal = 0f;
304+
305+
switch (opc.getOp()) {
306+
case GREATER:
307+
result = f1 > f2;
308+
isConditional = true;
309+
break;
310+
case GREATER_EQ:
311+
result = f1 >= f2;
312+
isConditional = true;
313+
break;
314+
case LESS:
315+
result = f1 < f2;
316+
isConditional = true;
317+
break;
318+
case LESS_EQ:
319+
result = f1 <= f2;
320+
isConditional = true;
321+
break;
322+
case EQ:
323+
result = f1 == f2;
324+
isConditional = true;
325+
break;
326+
case NOTEQ:
327+
result = f1 != f2;
328+
isConditional = true;
329+
break;
330+
331+
case PLUS:
332+
resultVal = f1 + f2;
333+
isArithmetic = true;
334+
break;
335+
case MINUS:
336+
resultVal = f1 - f2;
337+
isArithmetic = true;
338+
break;
339+
case MULT:
340+
resultVal = f1 * f2;
341+
isArithmetic = true;
342+
break;
343+
case MOD_REAL:
344+
if (f2 != 0f) {
345+
resultVal = f1 % f2;
346+
isArithmetic = true;
347+
}
348+
break;
349+
case DIV_INT:
350+
case DIV_REAL:
351+
if (f2 != 0f) {
352+
resultVal = f1 / f2;
353+
isArithmetic = true;
354+
}
355+
break;
356+
357+
default:
358+
return false;
359+
}
360+
361+
if (isConditional) {
362+
opc.replaceBy(JassIm.ImBoolVal(result));
363+
return true;
364+
} else if (isArithmetic) {
365+
String s = floatToStringWithDecimalDigits(resultVal, 4);
366+
if (Float.parseFloat(s) != resultVal) {
367+
s = floatToStringWithDecimalDigits(resultVal, 9);
368+
if (Float.parseFloat(s) != resultVal) {
369+
return false;
370+
}
371+
}
372+
opc.replaceBy(JassIm.ImRealVal(s));
373+
return true;
374+
} else {
375+
return false;
376+
}
377+
}
378+
379+
266380
private boolean optimizeStringString(ImOperatorCall opc, ImStringVal left, ImStringVal right) {
267381
String f1 = left.getValS();
268382
String f2 = right.getValS();
@@ -417,28 +531,52 @@ private boolean optimizeIntInt(ImOperatorCall opc, boolean wasViable, ImIntVal l
417531
isArithmetic = true;
418532
}
419533
break;
420-
case MOD_REAL:
534+
case MOD_REAL: {
421535
float f1 = i1;
422536
float f2 = i2;
423-
if (f2 != 0) {
537+
if (f2 != 0f) {
424538
float resultF = f1 % f2;
425-
opc.replaceBy(JassIm.ImRealVal(String.valueOf(resultF)));
539+
String s = floatToStringWithDecimalDigits(resultF, 4);
540+
if (Float.parseFloat(s) != resultF) {
541+
s = floatToStringWithDecimalDigits(resultF, 9);
542+
if (Float.parseFloat(s) != resultF) {
543+
wasViable = false;
544+
break;
545+
}
546+
}
547+
opc.replaceBy(JassIm.ImRealVal(s));
548+
// keep wasViable as-is (true) so the caller counts this rewrite
549+
} else {
550+
wasViable = false; // don’t fold div-by-zero
426551
}
427552
break;
553+
}
554+
case DIV_REAL: {
555+
float f1 = i1;
556+
float f2 = i2;
557+
if (f2 != 0f) {
558+
float resultF = f1 / f2;
559+
String s = floatToStringWithDecimalDigits(resultF, 4);
560+
if (Float.parseFloat(s) != resultF) {
561+
s = floatToStringWithDecimalDigits(resultF, 9);
562+
if (Float.parseFloat(s) != resultF) {
563+
wasViable = false;
564+
break;
565+
}
566+
}
567+
opc.replaceBy(JassIm.ImRealVal(s));
568+
// keep wasViable as-is (true) so the caller counts this rewrite
569+
} else {
570+
wasViable = false; // don’t fold div-by-zero
571+
}
572+
break;
573+
}
428574
case DIV_INT:
429575
if (i2 != 0) {
430576
resultVal = i1 / i2;
431577
isArithmetic = true;
432578
}
433579
break;
434-
case DIV_REAL:
435-
float f3 = i1;
436-
float f4 = i2;
437-
if (f4 != 0) {
438-
float resultF = f3 / f4;
439-
opc.replaceBy(JassIm.ImRealVal(String.valueOf(resultF)));
440-
}
441-
break;
442580
default:
443581
result = false;
444582
isConditional = false;

0 commit comments

Comments
 (0)