summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/Parser.java60
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java4
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java4
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java2
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java2
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java2
-rw-r--r--chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java2
-rw-r--r--chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java11
-rw-r--r--pom.xml1
9 files changed, 49 insertions, 39 deletions
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/Parser.java b/chapter16/src/main/java/com/seaofnodes/simple/Parser.java
index 626f7749..b22bcab7 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/Parser.java
@@ -873,8 +873,14 @@ public class Parser {
// Sanity check expr for being a reference
if( !(expr._type instanceof TypeMemPtr ptr) )
throw error("Expected reference but got " + expr._type.str());
- if( ptr == TypeMemPtr.TOP ) throw error("Accessing field '" + name + "' from null");
- if( ptr._obj == null ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
+
+ // Happens when parsing known dead code, which often has other typing
+ // issues. Since the code is dead, possibly due to inlining, lets not
+ // spoil the user experience with error messages.
+ if( ctrl()._type==Type.XCONTROL )
+ // Exit out via parsing the trailing expression
+ return matchOpx('=','=') ? parseExpression() : parsePostfix(con(Type.TOP));
+
// Sanity check field name for existing
TypeMemPtr tmp = (TypeMemPtr)TYPES.get(ptr._obj._name);
if( tmp == null ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
@@ -884,31 +890,25 @@ public class Parser {
// Get field type and layout offset from base type and field index fidx
Field f = base._fields[fidx]; // Field from field index
- Node off;
- if( name.equals("[]") ) { // If field is an array body
- // Array index math
- Node idx = require(parseExpression(),"]");
- off = new AddNode(con(base.aryBase()),new ShlNode(idx,con(base.aryScale())).peephole()).peephole();
- } else { // Else normal struct field
- // Hardwired field offset
- off = con(base.offset(fidx));
- }
- if( match("=") ) {
- // Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment
- if( peek('=') ) _lexer._position--;
- else {
- Node val = parseExpression();
- // Auto-truncate when storing to narrow fields
- val = zsMask(val,f._type);
- Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr, off, val, false);
- // Arrays include control, as a proxy for a safety range check.
- // Structs don't need this; they only need a NPE check which is
- // done via the type system.
- if( base.isAry() ) st.setDef(0,ctrl());
- memAlias(f._alias, st.peephole());
- return val; // "obj.a = expr" returns the expression while updating memory
- }
+ Node off = name.equals("[]") // If field is an array body
+ // Array index math
+ ? new AddNode(con(base.aryBase()),new ShlNode(require(parseExpression(),"]"),con(base.aryScale())).peephole()).peephole()
+ // Struct field offsets are hardwired
+ : con(base.offset(fidx));
+
+ // Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment
+ if( matchOpx('=','=') ) {
+ Node val = parseExpression();
+ // Auto-truncate when storing to narrow fields
+ val = zsMask(val,f._type);
+ Node st = new StoreNode(name, f._alias, f._type, memAlias(f._alias), expr, off, val, false);
+ // Arrays include control, as a proxy for a safety range check.
+ // Structs don't need this; they only need a NPE check which is
+ // done via the type system.
+ if( base.isAry() ) st.setDef(0,ctrl());
+ memAlias(f._alias, st.peephole());
+ return val; // "obj.a = expr" returns the expression while updating memory
}
Node load = new LoadNode(name, f._alias, f._type.glb(), memAlias(f._alias), expr, off);
@@ -959,6 +959,7 @@ public class Parser {
private boolean match (String syntax) { return _lexer.match (syntax); }
// Match must be "exact", not be followed by more id letters
private boolean matchx(String syntax) { return _lexer.matchx(syntax); }
+ private boolean matchOpx(char c0, char c1) { return _lexer.matchOpx(c0,c1); }
// Return true and do NOT skip if 'ch' is next
private boolean peek(char ch) { return _lexer.peek(ch); }
private boolean peekIsId() { return _lexer.peekIsId(); }
@@ -1078,6 +1079,13 @@ public class Parser {
_position -= syntax.length();
return false;
}
+ boolean matchOpx(char c0, char c1) {
+ skipWhiteSpace();
+ if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c1 )
+ return false;
+ _position++;
+ return true;
+ }
private boolean peek(char ch) {
skipWhiteSpace();
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java
index 5457ac6e..3cce89ab 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/IfNode.java
@@ -41,8 +41,8 @@ public class IfNode extends CFGNode implements MultiNode {
return TypeTuple.IF_NEITHER;
// If constant is 0 then false branch is reachable
// Else true branch is reachable
- if (t instanceof TypeInteger ti && ti.isConstant())
- return ti==TypeInteger.ZERO ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE;
+ if( t.isConstant() )
+ return t.makeInit()==t ? TypeTuple.IF_FALSE : TypeTuple.IF_TRUE;
return TypeTuple.IF_BOTH;
}
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java
index c4abed12..d15d4f83 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java
@@ -74,8 +74,8 @@ public class LoadNode extends MemOpNode {
// Pointers cannot overlap
mem = st.mem(); // Proved never equal
break;
- case PhiNode phi:
- break outer; // Assume related
+ case PhiNode phi: break outer; // Assume related
+ case ConstantNode top: break outer; // Assume shortly dead
case ProjNode mproj:
if( mproj.in(0) instanceof NewNode nnn1 ) {
if( ptr instanceof ProjNode pproj && pproj.in(0) == mproj.in(0) )
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
index 1e6d2baa..ddb1e09a 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java
@@ -27,7 +27,7 @@ public class NewNode extends Node implements MultiNode {
// Memory slices for all fields.
assert nodes[2+ i]._type instanceof TypeMem;
// Value slices for all fields.
- assert nodes[2+_len+i]._type instanceof Type;
+ assert nodes[2 + _len + i]._type != null;
}
}
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index 139e80a3..f0140ce6 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -43,7 +43,7 @@ public class PhiNode extends Node {
@Override
public Type compute() {
if( !(region() instanceof RegionNode r) )
- return region()._type==Type.XCONTROL ? Type.TOP : _type;
+ return region()._type==Type.XCONTROL ? (_type instanceof TypeMem ? TypeMem.TOP : Type.TOP) : _type;
// During parsing Phis have to be computed type pessimistically.
if( r.inProgress() ) return _declaredType;
// Set type to local top of the starting type
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java
index 48f81ddb..e4874e15 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java
@@ -13,7 +13,7 @@ public class ScopeMinNode extends Node {
/** The tracked fields are now complex enough to deserve a array-of-structs layout
*/
- public class Var {
+ public static class Var {
public final int _idx;
public final String _name;
public final Type _type;
diff --git a/chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
index 8b484235..ec059b8f 100644
--- a/chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
+++ b/chapter16/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
@@ -61,6 +61,8 @@ public class TypeMemPtr extends Type {
@Override public Type nonZero() { return VOIDPTR; }
@Override public boolean isHigh() { return this==TOP; }
+ @Override public boolean isConstant() { return this==NULLPTR; }
+ @Override public boolean isHighOrConst() { return this==TOP || this==NULLPTR; }
@Override public int log_size() { return 2; } // (1<<2)==4-byte pointers
diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java
index a31dfab3..2a33031d 100644
--- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java
+++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java
@@ -1,5 +1,6 @@
package com.seaofnodes.simple;
+import com.seaofnodes.simple.evaluator.Evaluator;
import com.seaofnodes.simple.node.StopNode;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
@@ -285,15 +286,13 @@ return ret;
@Test
public void testBug3() {
Parser parser = new Parser("""
-struct s0 {
- int f0;
-};
-if(0>=0) return new s0;
+struct s0 { int f0; };
return new s0;
int v0=null.f0;
""");
- try { parser.parse(); fail(); }
- catch( Exception e ) { assertEquals("Accessing unknown field 'f0' from 'null'", e.getMessage()); }
+ StopNode stop = parser.parse().iterate();
+ assertEquals("return s0;", stop.toString());
+ assertEquals("Obj<s0>{f0=0}", Evaluator.evaluate(stop, 0).toString());
}
@Test
diff --git a/pom.xml b/pom.xml
index 8f55db98..b59bc034 100644
--- a/pom.xml
+++ b/pom.xml
@@ -34,6 +34,7 @@
<module>chapter13</module>
<module>chapter14</module>
<module>chapter15</module>
+ <module>chapter16</module>
<module>transpile-tests</module>
</modules>