summaryrefslogtreecommitdiff
path: root/chapter12/src
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2024-07-25 23:46:39 +0300
committerDibyendu Majumdar <dibyendumajumdar@users.noreply.github.com>2024-08-05 23:28:33 +0100
commit799ba3a8d2603a51fc5b860f7845e72e6af61c38 (patch)
tree628fb922e02c3940bda7bbf02da8b86ffca5f637 /chapter12/src
parente325c3ad27aa12df9f2edfb1988e9c1270a88eea (diff)
downloadSimple-799ba3a8d2603a51fc5b860f7845e72e6af61c38.tar.gz
Simple-799ba3a8d2603a51fc5b860f7845e72e6af61c38.zip
Float bugs
Fix bug infinite loop finding. Fix inf loops before printing graph. Missing float unary negate . Generator makes float exprs Fix missing dep in LCA finding
Diffstat (limited to 'chapter12/src')
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java8
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/IterPeeps.java2
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/Parser.java4
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java6
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/CFGNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/LoopNode.java9
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java36
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java1
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/MultiNode.java8
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java4
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/Node.java1
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java2
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java4
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java2
-rw-r--r--chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java2
-rw-r--r--chapter12/src/test/java/com/seaofnodes/simple/Chapter11Test.java6
-rw-r--r--chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java20
-rw-r--r--chapter12/src/test/java/com/seaofnodes/simple/FuzzerWrap.java1
-rw-r--r--chapter12/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java7
-rw-r--r--chapter12/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java23
20 files changed, 113 insertions, 42 deletions
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java b/chapter12/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java
index 054a489c..4e0a31d5 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java
@@ -10,7 +10,6 @@ public abstract class GlobalCodeMotion {
// Node.use(0) is always a block tail (either IfNode or head of the
// following block). There are no unreachable infinite loops.
public static void buildCFG( StopNode stop ) {
- fixLoops(stop);
schedEarly();
Parser.SCHEDULED = true;
schedLate(Parser.START);
@@ -20,7 +19,7 @@ public abstract class GlobalCodeMotion {
// Backwards walk on the CFG only, looking for unreachable code - which has
// to be an infinite loop. Insert a bogus never-taken exit to Stop, so the
// loop becomes reachable. Also, set loop nesting depth
- private static void fixLoops(StopNode stop) {
+ static void fixLoops(StopNode stop) {
// Backwards walk from Stop, looking for unreachable code
BitSet visit = new BitSet();
HashSet<CFGNode> unreach = new HashSet<>();
@@ -148,7 +147,7 @@ public abstract class GlobalCodeMotion {
assert early != null;
CFGNode lca = null;
for( Node use : n._outputs )
- lca = use_block(n,use, late).idom(lca);
+ lca = use_block(n,use, late)._idom(lca,null);
// Loads may need anti-dependencies, raising their LCA
if( n instanceof LoadNode load )
@@ -214,6 +213,7 @@ public abstract class GlobalCodeMotion {
break;
case LoadNode ld: break; // Loads do not cause anti-deps on other loads
case ReturnNode ret: break; // Load must already be ahead of Return
+ case NeverNode never: break;
default: throw Utils.TODO();
}
}
@@ -226,7 +226,7 @@ public abstract class GlobalCodeMotion {
for( ; stblk != defblk.idom(); stblk = stblk.idom() ) {
// Store and Load overlap, need anti-dependence
if( stblk._anti==load._nid ) {
- lca = stblk.idom(lca); // Raise Loads LCA
+ lca = stblk._idom(lca,null); // Raise Loads LCA
if( lca == stblk && st != null && Utils.find(st._inputs,load) == -1 ) // And if something moved,
st.addDef(load); // Add anti-dep as well
return lca; // Cap this stores' anti-dep to here
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/IterPeeps.java b/chapter12/src/main/java/com/seaofnodes/simple/IterPeeps.java
index b2b76777..121d0233 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/IterPeeps.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/IterPeeps.java
@@ -92,6 +92,8 @@ public abstract class IterPeeps {
n.kill(); // Just plain dead
}
+ // Break infinite loops, forcing a Never-branch to exit
+ GlobalCodeMotion.fixLoops(stop);
if( show )
System.out.println(new GraphVisualizer().generateDotOutput(stop,null,null));
GlobalCodeMotion.buildCFG(stop);
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/Parser.java b/chapter12/src/main/java/com/seaofnodes/simple/Parser.java
index 4c62226b..cc1fb0df 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/Parser.java
@@ -429,6 +429,8 @@ public class Parser {
throw error("Undefined name '" + name + "'");
_scope.update(name,expr);
}
+ if( expr._type instanceof TypeInteger && t instanceof TypeFloat )
+ expr = expr.widen();
if( !expr._type.isa(t) )
throw error("Type " + expr._type.str() + " is not of declared type " + t.str());
return expr;
@@ -564,7 +566,7 @@ public class Parser {
* @return a unary expression {@link Node}, never {@code null}
*/
private Node parseUnary() {
- if (match("-")) return new MinusNode(parseUnary()).peephole();
+ if (match("-")) return new MinusNode(parseUnary()).widen().peephole();
if (match("!")) return new NotNode(parseUnary()).peephole();
return parsePostfix(parsePrimary());
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index 4454a5ad..b9faeb32 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -76,8 +76,8 @@ abstract public class BoolNode extends Node {
public static class LT extends BoolNode { public LT(Node lhs, Node rhs) { super(lhs,rhs); } String op() { return "<" ; } boolean doOp(long lhs, long rhs) { return lhs < rhs; } Node copy(Node lhs, Node rhs) { return new LT(lhs,rhs); } BoolNode copyF() { return new LTF(null,null); }}
public static class LE extends BoolNode { public LE(Node lhs, Node rhs) { super(lhs,rhs); } String op() { return "<="; } boolean doOp(long lhs, long rhs) { return lhs <= rhs; } Node copy(Node lhs, Node rhs) { return new LE(lhs,rhs); } BoolNode copyF() { return new LEF(null,null); } }
- public static class EQF extends BoolNode { public EQF(Node lhs, Node rhs) { super(lhs,rhs); } String op() { return "=="; } boolean doOp(double lhs, double rhs) { return lhs == rhs; } }
- public static class LTF extends BoolNode { public LTF(Node lhs, Node rhs) { super(lhs,rhs); } String op() { return "<" ; } boolean doOp(double lhs, double rhs) { return lhs < rhs; } }
- public static class LEF extends BoolNode { public LEF(Node lhs, Node rhs) { super(lhs,rhs); } String op() { return "<="; } boolean doOp(double lhs, double rhs) { return lhs <= rhs; } }
+ public static class EQF extends EQ { public EQF(Node lhs, Node rhs) { super(lhs,rhs); } boolean doOp(double lhs, double rhs) { return lhs == rhs; } }
+ public static class LTF extends LT { public LTF(Node lhs, Node rhs) { super(lhs,rhs); } boolean doOp(double lhs, double rhs) { return lhs < rhs; } }
+ public static class LEF extends LE { public LEF(Node lhs, Node rhs) { super(lhs,rhs); } boolean doOp(double lhs, double rhs) { return lhs <= rhs; } }
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/CFGNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/CFGNode.java
index b605071b..07ba0fa4 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/CFGNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/CFGNode.java
@@ -52,16 +52,17 @@ public abstract class CFGNode extends Node {
public int idepth() { return _idepth==0 ? (_idepth=idom().idepth()+1) : _idepth; }
// Return the immediate dominator of this Node and compute dom tree depth.
- public CFGNode idom() { return cfg(0); }
+ public CFGNode idom(Node dep) { return cfg(0); }
+ public final CFGNode idom() { return idom(null); }
// Return the LCA of two idoms
- public CFGNode idom(CFGNode rhs) {
+ public CFGNode _idom(CFGNode rhs, Node dep) {
if( rhs==null ) return this;
CFGNode lhs = this;
while( lhs != rhs ) {
var comp = lhs.idepth() - rhs.idepth();
- if( comp >= 0 ) lhs = lhs.idom();
- if( comp <= 0 ) rhs = rhs.idom();
+ if( comp >= 0 ) lhs = ((CFGNode)lhs.addDep(dep)).idom();
+ if( comp <= 0 ) rhs = ((CFGNode)rhs.addDep(dep)).idom();
}
return lhs;
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/LoopNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/LoopNode.java
index c662dee6..22862cb9 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/LoopNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/LoopNode.java
@@ -30,7 +30,7 @@ public class LoopNode extends RegionNode {
// Bypass Region idom, same as the default idom() using use in(1) instead of in(0)
@Override public int idepth() { return _idepth==0 ? (_idepth=idom().idepth()+1) : _idepth; }
// Bypass Region idom, same as the default idom() using use in(1) instead of in(0)
- @Override public CFGNode idom() { return entry(); }
+ @Override public CFGNode idom(Node dep) { return entry(); }
@Override public int loopDepth() {
if( _loopDepth!=0 ) return _loopDepth; // Was already set
@@ -60,8 +60,11 @@ public class LoopNode extends RegionNode {
// directly on the If) we found our exit.
CFGNode x = back();
while( x != this ) {
- if( x instanceof CProjNode exit )
- return; // Found an exit, not an infinite loop
+ if( x instanceof CProjNode exit && exit.in(0) instanceof IfNode iff ) {
+ Node other = iff.cproj(1-exit._idx);
+ if( !(other.out(0) instanceof LoopNode loop) || loop.entry()==exit )
+ return; // Found an exit, not an infinite loop
+ }
x = x.idom();
}
// Found a no-exit loop. Insert an exit
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
new file mode 100644
index 00000000..0853729d
--- /dev/null
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/MinusFNode.java
@@ -0,0 +1,36 @@
+package com.seaofnodes.simple.node;
+
+import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.type.TypeFloat;
+
+import java.util.BitSet;
+
+public class MinusFNode extends Node {
+ public MinusFNode(Node in) { super(null, in); }
+
+ @Override public String label() { return "MinusF"; }
+
+ @Override public String glabel() { return "-"; }
+
+ @Override
+ StringBuilder _print1(StringBuilder sb, BitSet visited) {
+ in(1)._print0(sb.append("(-"), visited);
+ return sb.append(")");
+ }
+
+ @Override
+ public Type compute() {
+ if (in(1)._type instanceof TypeFloat i0)
+ return i0.isConstant() ? TypeFloat.constant(-i0.value()) : i0;
+ return TypeFloat.TOP.meet(in(1)._type);
+ }
+
+ @Override
+ public Node idealize() {
+ // -(-x) is x
+ if( in(1) instanceof MinusFNode minus )
+ return minus.in(1);
+
+ return null;
+ }
+}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java
index 9b687613..ae8e9e1b 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/MinusNode.java
@@ -33,4 +33,5 @@ public class MinusNode extends Node {
return null;
}
+ @Override Node copyF() { return new MinusFNode(null); }
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/MultiNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/MultiNode.java
index 379e140d..ac9c0045 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/MultiNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/MultiNode.java
@@ -9,4 +9,12 @@ public interface MultiNode extends OutNode {
return prj;
return null;
}
+
+ // Find a projection by index
+ default CProjNode cproj( int idx ) {
+ for( Node out : outs() )
+ if( out instanceof CProjNode prj && prj._idx==idx )
+ return prj;
+ return null;
+ }
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java
index f50d3503..e77ed653 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/NeverNode.java
@@ -3,6 +3,8 @@ package com.seaofnodes.simple.node;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.type.TypeInteger;
import com.seaofnodes.simple.type.Type;
+import com.seaofnodes.simple.type.TypeTuple;
+
import java.util.BitSet;
// "Never true" for infinite loop exits
@@ -13,7 +15,7 @@ public class NeverNode extends IfNode {
@Override StringBuilder _print1(StringBuilder sb, BitSet visited) { return sb.append("Never"); }
- @Override public Type compute() { return TypeInteger.BOT; }
+ @Override public Type compute() { return TypeTuple.IF_BOTH; }
@Override public Node idealize() { return null; }
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter12/src/main/java/com/seaofnodes/simple/node/Node.java
index 3af49dbf..03b3d5e0 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/Node.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/Node.java
@@ -1,7 +1,6 @@
package com.seaofnodes.simple.node;
import com.seaofnodes.simple.IRPrinter;
-import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.IterPeeps;
import com.seaofnodes.simple.Utils;
import com.seaofnodes.simple.type.Type;
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index a07dc140..535db980 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -100,7 +100,7 @@ public class PhiNode extends Node {
if( in(2)._type == in(2)._type.makeInit() ) nullx = 2;
if( nullx != -1 ) {
Node val = in(3-nullx);
- if( region().idom() instanceof IfNode iff && iff.pred().addDep(this)==val ) {
+ if( region().idom(this) instanceof IfNode iff && iff.pred().addDep(this)==val ) {
// Must walk the idom on the null side to make sure we hit False.
CFGNode idom = (CFGNode)region().in(nullx);
while( idom.in(0) != iff ) idom = idom.idom();
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java
index dcc7ccef..d5105614 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/RegionNode.java
@@ -99,12 +99,12 @@ public class RegionNode extends CFGNode {
return _idepth=d;
}
- @Override public CFGNode idom() {
+ @Override public CFGNode idom(Node dep) {
CFGNode lca = null;
// Walk the LHS & RHS idom trees in parallel until they match, or either fails.
// Because this does not cache, it can be linear in the size of the program.
for( int i=1; i<nIns(); i++ )
- lca = cfg(i).idom(lca);
+ lca = cfg(i)._idom(lca,dep);
return lca;
}
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java
index 62fc8a6b..5f205ffd 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/StartNode.java
@@ -75,7 +75,7 @@ public class StartNode extends CFGNode implements MultiNode {
// No immediate dominator, and idepth==0
@Override public int idepth() { return 0; }
- @Override public CFGNode idom() { return null; }
+ @Override public CFGNode idom(Node dep) { return null; }
@Override void _walkUnreach( BitSet visit, HashSet<CFGNode> unreach ) { }
diff --git a/chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java b/chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java
index 94b2ad6d..ab567bae 100644
--- a/chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java
+++ b/chapter12/src/main/java/com/seaofnodes/simple/node/StopNode.java
@@ -59,7 +59,7 @@ public class StopNode extends CFGNode {
d = Math.max(d,((CFGNode)n).idepth()+1);
return _idepth=d;
}
- @Override public CFGNode idom() { return null; }
+ @Override public CFGNode idom(Node dep) { return null; }
@Override public int loopDepth() { return (_loopDepth=1); }
diff --git a/chapter12/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter12/src/test/java/com/seaofnodes/simple/Chapter11Test.java
index 9b05d66c..6c1f7938 100644
--- a/chapter12/src/test/java/com/seaofnodes/simple/Chapter11Test.java
+++ b/chapter12/src/test/java/com/seaofnodes/simple/Chapter11Test.java
@@ -292,7 +292,7 @@ else {
}
""");
StopNode stop = parser.parse(false).iterate(false);
- assertEquals("Stop[ return 9; return 0; return 0; ]", stop.toString());
+ assertEquals("Stop[ return 9; return 0; return 0; return 0; return 0; ]", stop.toString());
}
@@ -433,8 +433,8 @@ while( -arg )
while(1)
arg = arg+ptr.v;
""");
- StopNode stop = parser.parse(false).iterate(false);
- assertEquals("return 0;", stop.toString());
+ StopNode stop = parser.parse(false).iterate(true);
+ assertEquals("Stop[ return 0; return 0; ]", stop.toString());
}
@Test
diff --git a/chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java
index bfd6c309..af8fdfe9 100644
--- a/chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java
+++ b/chapter12/src/test/java/com/seaofnodes/simple/Chapter12Test.java
@@ -6,15 +6,27 @@ import org.junit.Test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
public class Chapter12Test {
@Test
+ public void testJig() {
+ Parser parser = new Parser(
+"""
+return 3.14;
+""");
+ StopNode stop = parser.parse(false).iterate(false);
+ assertEquals("return 3.14;", stop.toString());
+ assertEquals(3.14, Evaluator.evaluate(stop, 0));
+ }
+
+ @Test
public void testFloat() {
Parser parser = new Parser(
"""
return 3.14;
""");
- StopNode stop = parser.parse(false).iterate(true);
+ StopNode stop = parser.parse(false).iterate(false);
assertEquals("return 3.14;", stop.toString());
assertEquals(3.14, Evaluator.evaluate(stop, 0));
}
@@ -31,7 +43,7 @@ while( 1 ) {
}
return guess;
""");
- StopNode stop = parser.parse(false).iterate(true);
+ StopNode stop = parser.parse(false).iterate(false);
assertEquals("return Phi(Loop9,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0));", stop.toString());
assertEquals(3.0, Evaluator.evaluate(stop, 9));
assertEquals(1.414213562373095, Evaluator.evaluate(stop, 2));
@@ -44,8 +56,8 @@ return guess;
flt x = arg;
return x+1==x;
""");
- StopNode stop = parser.parse(false).iterate(true);
- assertEquals("return (((flt)arg+1.0)==ToFloat);", stop.toString());
+ StopNode stop = parser.parse(false).iterate(false);
+ assertEquals("return ((flt)arg==(ToFloat+1.0));", stop.toString());
assertEquals(0L, Evaluator.evaluate(stop, 1));
}
diff --git a/chapter12/src/test/java/com/seaofnodes/simple/FuzzerWrap.java b/chapter12/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
index 699711fc..efd76481 100644
--- a/chapter12/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
+++ b/chapter12/src/test/java/com/seaofnodes/simple/FuzzerWrap.java
@@ -14,7 +14,6 @@ import static org.junit.Assert.assertTrue;
*/
public class FuzzerWrap {
- @Ignore
@Test
public void fuzzPeeps() {
var fuzzer = new Fuzzer();
diff --git a/chapter12/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter12/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
index 09bda290..ab5c9bbd 100644
--- a/chapter12/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
+++ b/chapter12/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java
@@ -135,15 +135,16 @@ public class Evaluator {
case ConstantNode cons -> cons(cons);
case AddNode add -> vall(add.in(1)) + vall(add.in(2));
case AddFNode add -> vald(add.in(1)) + vald(add.in(2));
- case BoolNode.EQ eq -> Objects.equals(val(eq.in(1)), val(eq.in(2))) ? 1L : 0L;
- case BoolNode.LE le -> vall(le.in(1)) <= vall(le.in(2)) ? 1L : 0L;
- case BoolNode.LT lt -> vall(lt.in(1)) < vall(lt.in(2)) ? 1L : 0L;
case BoolNode.EQF eq -> Objects.equals(val(eq.in(1)), val(eq.in(2))) ? 1L : 0L;
case BoolNode.LEF le -> vald(le.in(1)) <= vald(le.in(2)) ? 1L : 0L;
case BoolNode.LTF lt -> vald(lt.in(1)) < vald(lt.in(2)) ? 1L : 0L;
+ case BoolNode.EQ eq -> Objects.equals(val(eq.in(1)), val(eq.in(2))) ? 1L : 0L;
+ case BoolNode.LE le -> vall(le.in(1)) <= vall(le.in(2)) ? 1L : 0L;
+ case BoolNode.LT lt -> vall(lt.in(1)) < vall(lt.in(2)) ? 1L : 0L;
case DivNode div -> div(div);
case DivFNode div -> div(div);
case MinusNode minus -> -vall(minus.in(1));
+ case MinusFNode minus -> -vald(minus.in(1));
case MulNode mul -> vall(mul.in(1)) * vall(mul.in(2));
case MulFNode mul -> vald(mul.in(1)) * vald(mul.in(2));
case NotNode not -> isTrue(val(not.in(1))) ? 0L : 1L;
diff --git a/chapter12/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java b/chapter12/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
index 155063ab..053be297 100644
--- a/chapter12/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
+++ b/chapter12/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
@@ -90,6 +90,7 @@ public class ScriptGenerator {
}
private static final Type TYPE_INT = new Type("int");
+ private static final Type TYPE_FLT = new Type("flt");
private static class Variable {
@@ -343,7 +344,9 @@ public class ScriptGenerator {
* @return A random type
*/
private Type getType() {
- if (structs.isEmpty() || random.nextBoolean()) return TYPE_INT;
+ int t = random.nextInt(10);
+ if( t<5 || structs.isEmpty() ) return TYPE_INT;
+ if( t<7 ) return TYPE_FLT;
var idx = random.nextInt(structs.size());
TypeStruct struct = structs.get(idx);
if (random.nextBoolean()) return struct.nullable;
@@ -415,7 +418,7 @@ public class ScriptGenerator {
indentation += INDENTATION;
for (int i=0; i<fields.length; i++) {
var fieldName = getRandomName();
- var type = generateInvalid() ? getType() : TYPE_INT;
+ var type = generateInvalid() ? getType() : (random.nextBoolean() ? TYPE_INT : TYPE_FLT);
printIndentation().append(type.name).append(" ").append(fieldName).append(";\n");
fields[i] = new TypeStruct.Field(fieldName.toString(), type);
}
@@ -679,16 +682,16 @@ public class ScriptGenerator {
*/
public void genExpression(Type type) {
if (generateInvalid()) type = getType();
- if (type != TYPE_INT) {
+ if (type != TYPE_INT && type != TYPE_FLT) {
genUnary(type);
return;
}
var num = randLog(MAX_BINARY_EXPRESSIONS_PER_EXPRESSION);
while(num-->0) {
- genUnary(TYPE_INT);
+ genUnary(type);
sb.append(BINARY_OP[random.nextInt(BINARY_OP.length)]);
}
- genUnary(TYPE_INT);
+ genUnary(type);
}
/**
@@ -696,7 +699,7 @@ public class ScriptGenerator {
*/
public void genUnary(Type type) {
if (generateInvalid()) type = getType();
- if (type != TYPE_INT) {
+ if (type != TYPE_INT && type != TYPE_FLT) {
genSuffix(type);
return;
}
@@ -704,7 +707,7 @@ public class ScriptGenerator {
while(num-->0) {
sb.append(UNARY_OP[random.nextInt(UNARY_OP.length)]);
}
- genSuffix(TYPE_INT);
+ genSuffix(type);
}
/**
@@ -712,7 +715,7 @@ public class ScriptGenerator {
*/
public void genSuffix(Type type) {
if (generateInvalid()) type = getType();
- if (type == TYPE_INT && random.nextBoolean()) {
+ if ((type == TYPE_INT || type == TYPE_FLT) && random.nextBoolean()) {
var t = getType();
if (generateInvalid()) {
var field = getRandomName();
@@ -721,7 +724,7 @@ public class ScriptGenerator {
return;
} else if (t instanceof TypeStruct s && s.fields.length > 0) {
var field = s.fields[random.nextInt(s.fields.length)];
- if (field.type == TYPE_INT) {
+ if (field.type == TYPE_INT || field.type == TYPE_FLT) {
genPrimary(t);
sb.append(".").append(field.name);
return;
@@ -762,6 +765,8 @@ public class ScriptGenerator {
case 1 -> sb.append("false");
default -> sb.append(random.nextInt(1<<(rand-2)));
}
+ } else if (type == TYPE_FLT) {
+ sb.append(random.nextFloat());
} else if (type instanceof TypeNullable n) {
if (random.nextBoolean()) {
sb.append("null");