summaryrefslogtreecommitdiff
path: root/chapter22/src
diff options
context:
space:
mode:
authorCliff Click <cliffc@acm.org>2025-04-29 21:52:24 -0700
committerCliff Click <cliffc@acm.org>2025-04-29 21:52:24 -0700
commitd85354f39d267e1840edeebf1e6e81b90985d3a8 (patch)
tree0f308aa6b333762d7aad5fa8a3ca0a5f809d5eeb /chapter22/src
parent6eb2979c1ac89e04b583dc687efe2012aa65d9ba (diff)
downloadSimple-d85354f39d267e1840edeebf1e6e81b90985d3a8.tar.gz
Simple-d85354f39d267e1840edeebf1e6e81b90985d3a8.zip
Drop a false start for adding clazz fields.
GLB does not widen primitives in memory. Missing float-cmp-copy
Diffstat (limited to 'chapter22/src')
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/Parser.java133
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/Var.java17
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java21
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java4
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java4
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java55
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/Field.java4
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/Type.java5
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypeFloat.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypeInteger.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypeMem.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypeNil.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypePtr.java2
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java10
-rw-r--r--chapter22/src/main/java/com/seaofnodes/simple/type/TypeTuple.java5
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java4
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Chapter17Test.java8
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java2
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/Eval2.java3
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/TypeTest.java16
-rw-r--r--chapter22/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java2
24 files changed, 124 insertions, 185 deletions
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
index ebc7cdc5..bbf841c8 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/Parser.java
@@ -81,11 +81,31 @@ public class Parser {
ScopeNode _breakScope; // Merge all the while-breaks here
FunNode _fun; // Current function being parsed
- // Mapping from a primitive name to a Type. The string name matches
+ // Mapping from a type name to a Type. The string name matches
// `type.str()` call. No TypeMemPtrs are in here, because Simple does not
// have C-style '*ptr' references.
- public static final HashMap<String, Type> PRIMS =
- new HashMap<>() {{
+ public static HashMap<String, Type> TYPES = defaultTypes();
+
+ // Mapping from a type name to the constructor for a Type.
+ public final HashMap<String, StructNode> INITS;
+
+
+ public Parser(CodeGen code, TypeInteger arg) {
+ _code = code;
+ _scope = new ScopeNode();
+ _continueScope = _breakScope = null;
+ ZERO = con(TypeInteger.ZERO).keep();
+ NIL = con(Type.NIL).keep();
+ XCTRL= new XCtrlNode().peephole().keep();
+ TYPES = defaultTypes();
+ INITS = new HashMap<>();
+ }
+
+ @Override
+ public String toString() { return _lexer.toString(); }
+
+ public static HashMap<String, Type> defaultTypes() {
+ return new HashMap<>() {{
put("bool",TypeInteger.U1 );
put("byte",TypeInteger.U8 );
put("f32" ,TypeFloat .F32);
@@ -103,25 +123,8 @@ public class Parser {
put("val" ,Type.TOP); // Marker type, indicates type inference
put("var" ,Type.BOTTOM); // Marker type, indicates type inference
}};
-
-
- // Mapping from a type name to the constructor for a Type.
- public final HashMap<String, StructNode> INITS;
-
-
- public Parser(CodeGen code, TypeInteger arg) {
- _code = code;
- _scope = new ScopeNode();
- _continueScope = _breakScope = null;
- ZERO = con(TypeInteger.ZERO).keep();
- NIL = con(Type.NIL).keep();
- XCTRL= new XCtrlNode().peephole().keep();
- INITS = new HashMap<>();
}
- @Override
- public String toString() { return _lexer.toString(); }
-
// Debugging utility to find a Node by index
public Node f(int nid) { return _code.f(nid); }
@@ -217,7 +220,7 @@ public class Parser {
// Pre-call the function from Start, with worse-case arguments. This
// represents all the future, yet-to-be-parsed functions calls and
// external calls.
- _scope.push(ScopeNode.Kind.Function,null);
+ _scope.push(ScopeNode.Kind.Function);
ctrl(fun); // Scope control from function
// Private mem alias tracking per function
MemMergeNode mem = new MemMergeNode(true);
@@ -276,7 +279,7 @@ public class Parser {
*/
private Node parseBlock(ScopeNode.Kind kind) {
// Enter a new scope
- _scope.push(kind,null);
+ _scope.push(kind);
Node last = ZERO;
while (!peek('}') && !_lexer.isEOF())
last = parseStatement();
@@ -343,7 +346,7 @@ public class Parser {
// }
// }
require("(");
- _scope.push(ScopeNode.Kind.Block,null); // Scope for the index variables
+ _scope.push(ScopeNode.Kind.Block); // Scope for the index variables
if( !match(";") ) // Can be empty init "for(;test;next) body"
parseDeclarationStatement(); // Non-empty init
Node rez = parseLooping(true);
@@ -677,17 +680,9 @@ public class Parser {
* exprAsgn = var '=' exprAsgn | expr
*/
private Node parseDeclarationStatement() {
- int old = pos();
Type t = type();
if( t == null )
return require(parseAsgn(),";");
- // Ambiguous leading type then doing a type/class static field lookup.
- // "T var" - declare a variable of type T
- // "T.fld" - lookup field "fld" in type T
- if( peek('.') ) {
- pos(old);
- return require(parseAsgn(),";");
- }
// now parse var['=' asgnexpr] in a loop
Node n = parseDeclaration(t);
@@ -727,7 +722,7 @@ public class Parser {
if( expr._type==Type.NIL )
throw error("a not-null/non-zero expression");
t = expr._type;
- if( !xfinal ) t = t.glb(); // Widen if not final
+ if( !xfinal ) t = t.glb(false); // Widen if not final
}
// expr is a constant function
if( t instanceof TypeFunPtr && expr._type instanceof TypeFunPtr tfp && tfp.isConstant() ) {
@@ -739,7 +734,7 @@ public class Parser {
// Need an expression to infer the type.
// Also, if not-null then need an initializing expression.
// Allowed in a class def, because type/init will happen in the constructor.
- if( (inferType || (t instanceof TypeNil tn && !tn.nullable() )) && !_scope.inDeclarationQ() )
+ if( (inferType || (t instanceof TypeNil tn && !tn.nullable() )) && !_scope.inConstructor() )
throw errorSyntax("=expression");
// Initial value for uninitialized struct fields.
expr = switch( t ) {
@@ -784,7 +779,7 @@ public class Parser {
String typeName = requireId();
// A Block scope parse, and inspect the scope afterward for fields.
- _scope.push(ScopeNode.Kind.DeclarationQ,typeName);
+ _scope.push(ScopeNode.Kind.Constructor);
require("{");
while (!peek('}') && !_lexer.isEOF())
parseStatement().isKill();
@@ -792,43 +787,24 @@ public class Parser {
// Grab the declarations and build fields and a Struct
int lexlen = _scope._lexSize.last();
int varlen = _scope._vars._len;
- StructNode inst = new StructNode();
- StructNode clz = new StructNode();
- Ary<Field> fs = new Ary<>(Field.class); // Struct fields
- Ary<Field> cs = new Ary<>(Field.class); // Class fields
+ StructNode s = new StructNode();
+ Ary<Field> fs = new Ary<>(Field.class);
for( int i=lexlen; i<varlen; i++ ) {
Var v = _scope.var(i);
if( v.isFRef() ) continue; // Promote to outer scope, not defined here
- var flds = v._final && v.type().isConstant() ? cs : fs;
- var stru = v._final && v.type().isConstant() ? clz : inst;
- // Declare field, gather field init
- flds.push(Field.make(v._name,v.type(),_code.getALIAS(),v._final));
- stru.addDef(_scope.in(i));
+ s.addDef(_scope.in(i)); // Keep the program code to generate instance
+ fs.push(Field.make(v._name,v.type(),_code.getALIAS(),v._final));
}
- TypeStruct ts = inst._ts = TypeStruct.make(typeName, fs.asAry());
- //PRIMS.put(typeName, TypeMemPtr.make(ts));
- INITS.put(typeName,inst.peephole().keep());
+ // Save instance default constructor
+ TypeStruct ts = s._ts = TypeStruct.make(typeName, fs.asAry());
+ TYPES.put(typeName, TypeMemPtr.make(ts));
+ INITS.put(typeName,s.peephole().keep());
- //String clzName = typeName + ".clz"; // Class name
- //PRIMS.put(clzName, TypeMemPtr.make(TypeStruct.make(clzName, cs.asAry())));
// Done with struct/block scope
require("}");
require(";");
_scope.pop();
- // Make a pointer to the class fields
-
- // ISSUE: LOOKUP EXPECTS TO FIND INSTANCE FIELDS FOR 'NEW' OR TYPE DECLS:
- // Vector2D v = ...;
- // Type for 'v' includes fields 'x,y'.
- // Whereas: Vector2D.PI lookups up via the class struct.
- // So e.g. add a hidden " decl" field that gets the instance fields.
- cs.push(Field.make(" decl",TypeMemPtr.make(ts),-1,true));
-
- TypeMemPtr tclz = TypeMemPtr.make(TypeStruct.make(typeName, cs.asAry()));
- ConstantNode nclz = con(tclz);
- // Define the constant clazz fields
- _scope.define(typeName,tclz, true, nclz, true, loc());
- return nclz;
+ return ZERO;
}
@@ -847,15 +823,14 @@ public class Parser {
String tname = _lexer.matchId();
if( tname==null ) return null;
- // Convert the type name to a type, either user instance type or a primitive.
- Type t0 = _scope.lookupInstance(tname);
- if( t0 == null ) t0 = PRIMS.get(tname);
+ // Convert the type name to a type.
+ Type t0 = TYPES.get(tname);
// No new types as keywords
if( t0 == null && KEYWORDS.contains(tname) )
return posT(old1);
if( t0 == Type.BOTTOM || t0 == Type.TOP ) return t0; // var/val type inference
// Still no type found? Assume forward reference
- Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.makeFRef(tname)) : t0; // Null: assume a forward ref type
+ Type t1 = t0 == null ? TypeMemPtr.make(TypeStruct.makeFRef(tname)) :t0; // Null: assume a forward ref type
// Nest arrays and '?' as needed
Type t2 = t1;
while( true ) {
@@ -881,7 +856,7 @@ public class Parser {
return posT(old1); // Reset lexer to reparse
pos(old2); // Reset lexer to reparse
// Yes a forward ref, so declare it
- _scope.define(tname, t1, true, XCTRL, true, null);
+ TYPES.put(tname,t1);
// Return the (array, final) type
return t2;
}
@@ -891,15 +866,14 @@ public class Parser {
if( t instanceof TypeMemPtr tmp && tmp.notNull() )
throw error("Arrays of reference types must always be nullable");
String tname = "["+t.str()+"]";
- Type ta = PRIMS.get(tname);
+ Type ta = TYPES.get(tname);
if( ta != null ) return (TypeMemPtr)ta;
// Need make an array type.
TypeStruct ts = TypeStruct.makeAry(TypeInteger.U32,_code.getALIAS(),t,_code.getALIAS());
assert ts.str().equals(tname);
TypeMemPtr tary = TypeMemPtr.make(ts);
- //PRIMS.put(tname,tary);
- //return tary;
- throw Utils.TODO();
+ TYPES.put(tname,tary);
+ return tary;
}
// A function type is `{ type... -> type }` or `{ type }`.
@@ -1217,7 +1191,7 @@ public class Parser {
if( hasConstructor ) {
idx = _scope.nIns();
// Push a scope, and pre-assign all struct fields.
- _scope.push(ScopeNode.Kind.Block,null);
+ _scope.push(ScopeNode.Kind.Block);
Lexer loc = loc();
for( int i=0; i<fs.length; i++ )
_scope.define(fs[i]._fname, fs[i]._type, fs[i]._final, s.in(i)._type==Type.TOP ? con(Type.BOTTOM) : s.in(i), loc);
@@ -1318,22 +1292,15 @@ public class Parser {
// Find the field from the Type. Lookup in the base object field names.
TypeStruct base = ptr._obj;
- if( base.isFRef() ) {
- //ptr = _scope.lookupInstance(base._name);
- //base = ptr._obj;
- throw Utils.TODO();
- }
+ assert !base.isFRef();
int fidx = base.find(name);
- if( fidx == -1 ) { // No such field!
- throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
- // TODO: ch22 allow class field lookups
- }
+ if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'");
// Get field type and layout offset from base type and field index fidx
Field f = base._fields[fidx]; // Field from field index
Type tf = f._type;
if( tf instanceof TypeMemPtr ftmp && ftmp.isFRef() )
- tf = ftmp.makeFrom(((TypeMemPtr)(PRIMS.get(ftmp._obj._name)))._obj);
+ tf = ftmp.makeFrom(((TypeMemPtr)(TYPES.get(ftmp._obj._name)))._obj);
// Field offset; fixed for structs, computed for arrays
Node off = (name.equals("[]") // If field is an array body
@@ -1439,7 +1406,7 @@ public class Parser {
if( expr._type == Type.NIL )
throw error("Calling a null function pointer");
if( !(expr instanceof FRefNode) && !expr._type.isa(TypeFunPtr.BOT) )
- throw error("Expected a function but got "+expr._type.glb().str());
+ throw error("Expected a function but got "+expr._type.glb(false).str());
expr.keep(); // Keep while parsing args
Ary<Node> args = new Ary<Node>(Node.class);
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/Var.java b/chapter22/src/main/java/com/seaofnodes/simple/Var.java
index 154b99f4..cf549cd6 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/Var.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/Var.java
@@ -15,31 +15,24 @@ public class Var {
private Type _type; // Declared type
public boolean _final; // Final field
public boolean _fref; // Forward ref
- public final boolean _clz; // Is a Simple clazz
public Parser.Lexer _loc; // Source location
public Var(int idx, String name, Type type, boolean xfinal, Parser.Lexer loc ) {
- this(idx,name,type,xfinal,loc,false,false);
+ this(idx,name,type,xfinal,loc,false);
}
- public Var(int idx, String name, Type type, boolean xfinal, Parser.Lexer loc, boolean clz, boolean fref) {
+ public Var(int idx, String name, Type type, boolean xfinal, Parser.Lexer loc, boolean fref) {
_idx = idx;
_name = name;
_type = type;
_final = xfinal;
_fref = fref;
- _clz = clz;
_loc = loc;
}
public Type type() {
if( !_type.isFRef() ) return _type;
// Update self to no longer use the forward ref type
- //Type def = Parser.TYPES.get(((TypeMemPtr)_type)._obj._name);
- //return (_type=_type.meet(def));
- throw Utils.TODO();
- }
- public Type lazyGLB() {
- Type t = type();
- return t instanceof TypeMemPtr ? t : t.glb();
+ Type def = Parser.TYPES.get(((TypeMemPtr)_type)._obj._name);
+ return (_type=_type.meet(def));
}
// Forward reference variables (not types) must be BOTTOM and
@@ -55,6 +48,6 @@ public class Var {
}
@Override public String toString() {
- return _type.toString()+(_final ? " ": " !")+(_clz?"@":"")+_name;
+ return _type.toString()+(_final ? " ": " !")+_name;
}
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java
index fd6448a2..301e1517 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/BoolNode.java
@@ -130,9 +130,24 @@ abstract public class BoolNode extends Node {
Node copyF() { return new LEF(null,null); }
}
- 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 boolean isFloat() { return true; } }
- 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 boolean isFloat() { return true; } }
- public static class LEF extends LE { public LEF(Node lhs, Node rhs) { super(lhs,rhs); } boolean doOp(double lhs, double rhs) { return lhs <= rhs; } public boolean isFloat() { return true; } }
+ public static class EQF extends EQ {
+ public EQF(Node lhs, Node rhs) { super(lhs,rhs); }
+ @Override boolean doOp(double lhs, double rhs) { return lhs == rhs; }
+ @Override public boolean isFloat() { return true; }
+ @Override Node copy(Node lhs, Node rhs) { return new EQF(lhs,rhs); }
+ }
+ public static class LTF extends LT {
+ public LTF(Node lhs, Node rhs) { super(lhs,rhs); }
+ @Override boolean doOp(double lhs, double rhs) { return lhs < rhs; }
+ @Override public boolean isFloat() { return true; }
+ @Override Node copy(Node lhs, Node rhs) { return new LTF(lhs,rhs); }
+ }
+ public static class LEF extends LE {
+ public LEF(Node lhs, Node rhs) { super(lhs,rhs); }
+ @Override boolean doOp(double lhs, double rhs) { return lhs <= rhs; }
+ @Override public boolean isFloat() { return true; }
+ @Override Node copy(Node lhs, Node rhs) { return new LEF(lhs,rhs); }
+ }
// Unsigned less that, for range checks. Not directly user writable.
public static class ULT extends BoolNode {
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
index 32c25a8b..5b923bf0 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java
@@ -122,7 +122,7 @@ public class MemMergeNode extends Node {
// by alias as it will trigger a phi creation
Node lhs = this._mem(i,null);
Node rhs = that._mem(i,null);
- alias(i, new PhiNode(Parser.memName(i), lhs._type.glb().meet(rhs._type.glb()), r, lhs, rhs).peephole());
+ alias(i, new PhiNode(Parser.memName(i), lhs._type.glb(true).meet(rhs._type.glb(true)), r, lhs, rhs).peephole());
}
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java
index 384dbace..c1a5a524 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/MulNode.java
@@ -80,8 +80,8 @@ public class MulNode extends Node {
@Override Node copyF() { return new MulFNode(null,null); }
@Override public Parser.ParseException err() {
if( in(1)._type.isHigh() || in(2)._type.isHigh() ) return null;
- if( !(in(1)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(1)._type.glb(),null);
- if( !(in(2)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(2)._type.glb(),null);
+ if( !(in(1)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(1)._type.glb(false),null);
+ if( !(in(2)._type instanceof TypeInteger) ) return Parser.error("Cannot '"+label()+"' " + in(2)._type.glb(false),null);
return null;
}
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java
index e6f9cae7..79251839 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/PhiNode.java
@@ -54,7 +54,7 @@ public class PhiNode extends Node {
// During parsing Phis have to be computed type pessimistically.
if( r.inProgress() ) return _declaredType;
// Set type to local top of the starting type
- Type t = _declaredType.glb().dual();//Type.TOP;
+ Type t = _declaredType.glb(false).dual();//Type.TOP;
for (int i = 1; i < nIns(); i++)
// If the region's control input is live, add this as a dependency
// to the control because we can be peeped should it become dead.
@@ -148,7 +148,7 @@ public class PhiNode extends Node {
if( in(i).in(j) != x )
{ needsPhi=true; break; }
if( needsPhi ) {
- x = new PhiNode(_label,op.in(j)._type.glb());
+ x = new PhiNode(_label,op.in(j)._type.glb(false));
x.addDef(region());
for( int i=1; i<nIns(); i++ )
x.addDef(in(i).in(j));
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
index eda29915..3127e491 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/node/ScopeNode.java
@@ -28,12 +28,9 @@ public class ScopeNode extends MemMergeNode {
// Lexical scope is typed:
// - Block scope - basic block scoping
// - Constructor - struct type is defined, and here we give values to all fields
- // - Declaration - struct is declared, final constant fields defined
// - Function - out-of-scope lookups restricted to final constants
- public enum Kind { Block, Constructor, DeclarationQ, Function };
+ public enum Kind { Block, Constructor, Function };
public final Ary<Kind> _kinds;
- // Each Constructor scope is named, allowing for nested Type names
- public final Ary<String> _tnamesQ;
// Extra guards; tested predicates and casted results
private final Ary<Node> _guards;
@@ -44,7 +41,6 @@ public class ScopeNode extends MemMergeNode {
_vars = new Ary<>(Var .class);
_lexSize= new Ary<>(Integer.class);
_kinds = new Ary<>(Kind .class);
- _tnamesQ = new Ary<>(String .class);
_guards = new Ary<>(Node .class);
}
@@ -93,21 +89,18 @@ public class ScopeNode extends MemMergeNode {
public <N extends Node> N ctrl(N n) { return setDef(0,n); }
public Node mem(Node n) { return setDef(1,n); }
- public void push(Kind kind, String tnameQ) {
- assert _lexSize._len==_kinds._len && _lexSize._len==_tnamesQ._len;
- assert !(kind==Kind.DeclarationQ && tnameQ==null);
+ public void push( Kind kind ) {
+ assert _lexSize._len==_kinds._len;
_lexSize.push(_vars.size());
_kinds .push(kind);
- _tnamesQ .push(tnameQ);
}
// Pop a lexical scope
public void pop() {
- assert _lexSize._len==_kinds._len && _lexSize._len==_tnamesQ._len;
+ assert _lexSize._len==_kinds._len;
promote(); // Promote forward references to the next outer scope
int n = _lexSize.pop();
_kinds.pop();
- _tnamesQ.pop();
popUntil(n); // Pop off inputs going out of scope
_vars.setLen(n); // Pop off variables going out of scope
}
@@ -132,14 +125,6 @@ public class ScopeNode extends MemMergeNode {
public boolean inConstructor() { return _kinds.last() == Kind.Constructor; }
- public boolean inDeclarationQ() { return _kinds.last() == Kind.DeclarationQ; }
- // Nearest enclosing declaration scope name
- public String declNameQ() {
- for( int i=_lexSize._len-1; i>=0; i-- )
- if( _kinds.at(i)==Kind.DeclarationQ )
- return _tnamesQ.at(i);
- return null;
- }
// Is v outside any current function scope?
public boolean outOfFunction( Var v ) {
@@ -153,9 +138,9 @@ public class ScopeNode extends MemMergeNode {
// Find name in reverse, return an index into _vars or -1. Linear scan
// instead of hashtable, but probably doesn't matter until the scan
// typically hits many dozens of variables.
- public int find( String name, boolean clz ) {
+ public int find( String name ) {
for( int i=_vars.size()-1; i>=0; i-- )
- if( var(i)._name.equals(name) && var(i)._clz==clz )
+ if( var(i)._name.equals(name) )
return i;
return -1;
}
@@ -164,9 +149,6 @@ public class ScopeNode extends MemMergeNode {
* Create a new variable name in the current scope
*/
public boolean define( String name, Type declaredType, boolean xfinal, Node init, Parser.Lexer loc ) {
- return define(name,declaredType,xfinal,init,false,loc);
- }
- public boolean define( String name, Type declaredType, boolean xfinal, Node init, boolean clz, Parser.Lexer loc ) {
assert _lexSize.isEmpty() || name.charAt(0)!='$' ; // Later scopes do not define memory
if( _lexSize._len > 0 )
for( int i=_vars.size()-1; i>=_lexSize.last(); i-- ) {
@@ -179,7 +161,7 @@ public class ScopeNode extends MemMergeNode {
setDef(n._idx,fref.addDef(init)); // Set FRef to defined; tell parser also
}
}
- Var v = new Var(nIns(),name,declaredType,xfinal,loc,clz,init==Parser.XCTRL);
+ Var v = new Var(nIns(),name,declaredType,xfinal,loc,init==Parser.XCTRL);
_vars.add(v);
// Creating a forward reference
if( init==Parser.XCTRL )
@@ -201,35 +183,19 @@ public class ScopeNode extends MemMergeNode {
* @return null if not found, or the implementing Node
*/
public Var lookup( String name ) {
- int idx = find(name,false);
+ int idx = find(name);
// -1 is missed in all scopes, not found
return idx == -1 ? null : update(var(idx),null);
}
/**
- * Lookup a type name and return the instance TypeMemPtr
- *
- * @param name of Type
- * @return null if not found, or *instance* TypeMemPtr
- */
- public TypeMemPtr lookupInstance( String name ) {
- int idx = find(name,true);
- // -1 is missed in all scopes, not found
- if( idx == -1 ) return null;
- // Class types are always TMPs
- TypeMemPtr clz = (TypeMemPtr)var(idx).type();
- // Instance types are always TMPs
- return (TypeMemPtr)(clz._obj.field(" decl")._type);
- }
-
- /**
* Redefine an existing name
*
* @param name Name being redefined
* @param n The node to bind to the name
*/
public void update( String name, Node n ) {
- int idx = find(name,false);
+ int idx = find(name);
assert idx>=0;
update(var(idx),n);
}
@@ -245,7 +211,7 @@ public class ScopeNode extends MemMergeNode {
// Set real Phi in the loop head
// The phi takes its one input (no backedge yet) from a recursive
// lookup, which might have insert a Phi in every loop nest.
- : loop.setDef(v._idx,new PhiNode(v._name, v.lazyGLB(), loop.ctrl(), loop.in(loop.update(v,null)._idx),null).peephole());
+ : loop.setDef(v._idx,new PhiNode(v._name, v.type(), loop.ctrl(), loop.in(loop.update(v,null)._idx),null).peephole());
setDef(v._idx,old);
}
assert !v._final || st==null;
@@ -276,7 +242,6 @@ public class ScopeNode extends MemMergeNode {
dup._vars .addAll(_vars );
dup._lexSize.addAll(_lexSize);
dup._kinds .addAll(_kinds );
- dup._tnamesQ .addAll(_tnamesQ );
dup._guards .addAll(_guards );
// The dup'd guards all need dup'd keepers, to keep proper accounting
// when later removing all guards
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/Field.java b/chapter22/src/main/java/com/seaofnodes/simple/type/Field.java
index ffa9d2a6..bd67735a 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/Field.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/Field.java
@@ -51,8 +51,8 @@ public class Field extends Type {
@Override
public Field dual() { return make(_fname,_type.dual(),_alias,!_final); }
- @Override public Field glb() {
- Type glb = _type.glb();
+ @Override public Field glb(boolean mem) {
+ Type glb = _type.glb(mem);
return (glb==_type && _final) ? this : make(_fname,glb,_alias,true);
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/Type.java b/chapter22/src/main/java/com/seaofnodes/simple/type/Type.java
index 6df4e7ab..38414dcf 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/Type.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/Type.java
@@ -200,8 +200,9 @@ public class Type {
// Make a zero version of this type, 0 for integers and null for pointers.
public Type makeZero() { return Type.NIL; }
- /** Compute greatest lower bound in the lattice */
- public Type glb() { return Type.BOTTOM; }
+ /** Compute greatest lower bound in the lattice. If values are in memory,
+ * ints and floats cannot widen. */
+ public Type glb(boolean mem) { return Type.BOTTOM; }
// Is forward-reference
public boolean isFRef() { return false; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeFloat.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
index aa205149..a0940f8b 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeFloat.java
@@ -81,7 +81,7 @@ public class TypeFloat extends Type {
}
@Override public Type makeZero() { return FZERO; }
- @Override public Type glb() { return F64; }
+ @Override public Type glb(boolean mem) { return mem ? (isHigh() ? dual() : this) : F64; }
@Override
int hash() { return (int)(Double.hashCode(_con) ^ _sz ^ (1<<17)); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
index bd64bd81..abfcf1e3 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java
@@ -59,7 +59,7 @@ public class TypeFunPtr extends TypeNil {
// RHS is NIL; do not deep-dual when crossing the centerline
@Override public Type meet0() { return _nil==3 ? this : make((byte)3,_sig,_ret,_fidxs); }
- @Override public TypeFunPtr glb() { return make((byte)3,_sig,_ret,-1L); }
+ @Override public TypeFunPtr glb(boolean mem) { return make((byte)3,_sig,_ret,-1L); }
@Override public boolean isHigh () { return _nil <= 1 || (_nil==2 && _fidxs==0); }
@Override public boolean isConstant() { return (_nil==2 && Long.bitCount(_fidxs)==1) || (_nil==3 && _fidxs==0); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
index cccb85a5..9f017fd1 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeInteger.java
@@ -119,7 +119,7 @@ public class TypeInteger extends Type {
return this;
}
@Override public Type makeZero() { return ZERO; }
- @Override public TypeInteger glb() { return BOT; }
+ @Override public Type glb(boolean mem) { return mem ? (isHigh() ? dual() : this) : BOT; }
@Override int hash() { return Utils.fold(_min) * Utils.fold(_max); }
@Override public boolean eq( Type t ) {
TypeInteger i = (TypeInteger)t; // Contract
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMem.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMem.java
index 9ed4c7a8..9be4908b 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMem.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMem.java
@@ -50,7 +50,7 @@ public class TypeMem extends Type {
}
@Override public boolean isHigh() { return _t.isHigh(); }
- @Override public Type glb() { return make(_alias,_t.glb()); }
+ @Override public Type glb(boolean mem) { return make(_alias,_t.glb(true)); }
@Override int hash() { return 9876543 + _alias + _t.hashCode(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
index 284bf581..67ed65a9 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java
@@ -73,7 +73,7 @@ public class TypeMemPtr extends TypeNil {
throw Utils.TODO(); // return _obj.shallowISA(that._obj);
}
- @Override public TypeMemPtr glb() { return make((byte)3,_obj.glb()); }
+ @Override public TypeMemPtr glb(boolean mem) { return make((byte)3,_obj.glb(true)); }
// Is forward-reference
@Override public boolean isFRef() { return _obj.isFRef(); }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeNil.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeNil.java
index aee623ba..3902c40b 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeNil.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeNil.java
@@ -48,7 +48,7 @@ public abstract class TypeNil extends Type {
@Override public boolean isConstant () { return false; }
@Override public boolean isHighOrConst() { return isHigh() || isConstant(); }
- @Override public Type glb() { return Type.NIL; }
+ @Override public Type glb(boolean mem) { return Type.NIL; }
public boolean notNull() { return _nil==1 || _nil==2; }
public boolean nullable() { return _nil==3; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypePtr.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypePtr.java
index e9091c25..d9de5cd7 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypePtr.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypePtr.java
@@ -45,7 +45,7 @@ public class TypePtr extends TypeNil {
// 0->xscalar, 1->nscalar, 2->nscalar, 3->scalar
@Override Type meetX() { return _nil==0 ? XNIL : (_nil==3 ? PTR : NPTR); }
- @Override public TypePtr glb() { return PTR; }
+ @Override public TypePtr glb(boolean mem) { return PTR; }
private static final String[] STRS = new String[]{"~ptr","~nptr","nptr","ptr"};
@Override public String str() { return STRS[_nil]; }
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
index e981b5dc..13105d20 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeStruct.java
@@ -129,18 +129,18 @@ public class TypeStruct extends Type {
}
// Keeps the same struct, but lower-bounds all fields.
- @Override public TypeStruct glb() {
- if( _glb() ) return this;
+ @Override public TypeStruct glb(boolean mem) {
+ if( _glb(mem) ) return this;
// Need to glb each field
Field[] flds = new Field[_fields.length];
for( int i=0; i<_fields.length; i++ )
- flds[i] = _fields[i].glb();
+ flds[i] = _fields[i].glb(mem);
return make(_name,flds);
}
- private boolean _glb() {
+ private boolean _glb(boolean mem) {
if( _fields!=null )
for( Field f : _fields )
- if( f.glb() != f )
+ if( f.glb(mem) != f )
return false;
return true;
}
diff --git a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeTuple.java b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
index d3b19b52..c9f88efa 100644
--- a/chapter22/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
+++ b/chapter22/src/main/java/com/seaofnodes/simple/type/TypeTuple.java
@@ -48,11 +48,10 @@ public class TypeTuple extends Type {
return make(ts);
}
- @Override
- public Type glb() {
+ @Override public Type glb(boolean mem) {
Type[] ts = new Type[_types.length];
for( int i=0; i<_types.length; i++ )
- ts[i] = _types[i].glb();
+ ts[i] = _types[i].glb(mem);
return make(ts);
}
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java
index 930624e5..58bb4148 100644
--- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java
+++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter16Test.java
@@ -128,7 +128,7 @@ p.x++;
return p;
""");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test
@@ -140,7 +140,7 @@ p.x++;
return p;
""");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter17Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter17Test.java
index 78515083..bdeb645c 100644
--- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter17Test.java
+++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter17Test.java
@@ -172,13 +172,13 @@ return s.x;
@Test public void testVar6() {
CodeGen code = new CodeGen("struct S{int x;}; S s=new S; s.x++; return s.x; // Error initializer so x is immutable ");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test public void testVar7() {
CodeGen code = new CodeGen("struct S{int x;}; S s=new S{x=3;}; s.x++; return s.x; // Error initializer so x is immutable ");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test public void testVar8() {
@@ -198,7 +198,7 @@ return s.x;
@Test public void testVar10() {
CodeGen code = new CodeGen("struct S{int x;}; val s=new S; s.x++; return s.x; // Error, has val so x is immutable ");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test public void testVar11() {
@@ -216,7 +216,7 @@ val xfoo = foo; // Throw away mutability
xfoo.bar.x++; // Error, cannot mutate through xfoo
""");
try { code.parse().opto().typeCheck(); fail(); }
- catch( Exception e ) { assertEquals("Cannot modify final field 'x'",e.getMessage()); }
+ catch( Exception e ) { assertEquals("Cannot reassign final 'x'",e.getMessage()); }
}
@Test public void testVar12() {
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java
index dccf00bc..6bec499e 100644
--- a/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java
+++ b/chapter22/src/test/java/com/seaofnodes/simple/Chapter22Test.java
@@ -28,7 +28,7 @@ public class Chapter22Test {
assertEquals(stop, code._stop.toString());
}
- @Test
+ @Test @Ignore
public void testCoRecur() {
String src = """
struct A { B? b; C? c; i64 ax; val az = x*2; };
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java b/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java
index 38da6898..ecea97dd 100644
--- a/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java
+++ b/chapter22/src/test/java/com/seaofnodes/simple/Eval2.java
@@ -407,8 +407,7 @@ public abstract class Eval2 {
// Since never can close the type cycle, without cyclic types, have
// to handle FRefs even here
if( tmp.isFRef() )
- //tmp = tmp.makeFrom(((TypeMemPtr)Parser.TYPES.get(tmp._obj._name))._obj);
- throw Utils.TODO();
+ tmp = tmp.makeFrom(((TypeMemPtr)Parser.TYPES.get(tmp._obj._name))._obj);
Object[] xs = (Object[])x; // Array of fields
if( tmp._obj.isAry() ) {
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/TypeTest.java b/chapter22/src/test/java/com/seaofnodes/simple/TypeTest.java
index d94f5b5a..660f984a 100644
--- a/chapter22/src/test/java/com/seaofnodes/simple/TypeTest.java
+++ b/chapter22/src/test/java/com/seaofnodes/simple/TypeTest.java
@@ -20,9 +20,9 @@ public class TypeTest {
TypeStruct s2 = TypeStruct.make("s2", new Field[]{
Field.make("a", TypeInteger.BOT,-3, false),
Field.make("b", TypeInteger.BOT,-4, false) });
- Assert.assertEquals(s1.makeRO(), s1.glb());
+ Assert.assertEquals(s1.makeRO(), s1.glb(false));
Assert.assertNotEquals(s1, s1.dual());
- Assert.assertEquals(s1.makeRO(), s1.dual().glb());
+ Assert.assertEquals(s1.makeRO(), s1.dual().glb(false));
TypeMem m1 = TypeMem.make(1,TypeNil.NIL);
TypeMem m2 = TypeMem.make(2,TypeInteger.U16);
@@ -38,9 +38,9 @@ public class TypeTest {
Assert.assertEquals(TypeMem.make(0,Type.BOTTOM), m1.meet(m3));
Assert.assertEquals(TypeMem .BOT, m3.meet(m4));
- Assert.assertEquals(TypeMem.make(1,Type.BOTTOM), m1.glb());
+ Assert.assertEquals(TypeMem.make(1,Type.BOTTOM), m1.glb(false));
Assert.assertEquals(TypeMem.make(1,Type.XNIL), m1.dual());
- Assert.assertEquals(m4.dual(), m4.glb().dual());
+ Assert.assertEquals(m4.dual(), m4.glb(false).dual());
TypeMemPtr ptr1 = TypeMemPtr.make(s1);
Assert.assertEquals(s1, ptr1._obj);
@@ -55,13 +55,13 @@ public class TypeTest {
Assert.assertEquals(s2, ptr2nil._obj);
Assert.assertNotEquals(ptr1, ptr2);
- Assert.assertNotEquals(ptr1, ptr1.glb());
- Assert.assertEquals(ptr1nil.makeRO(), ptr1.glb());
+ Assert.assertNotEquals(ptr1, ptr1.glb(false));
+ Assert.assertEquals(ptr1nil.makeRO(), ptr1.glb(false));
Assert.assertEquals(ptr1, ptr1.dual().dual());
- Assert.assertEquals(ptr1.glb().makeRO(), ptr1.dual().glb());
+ Assert.assertEquals(ptr1.glb(false).makeRO(), ptr1.dual().glb(false));
Assert.assertEquals(TypeMemPtr.makeNullable(TypeStruct.BOT), ptr1.meet(ptr2nil));
- Assert.assertEquals(ptr1.glb(), ptr1.meet(TypeNil.NIL).makeRO());
+ Assert.assertEquals(ptr1.glb(false), ptr1.meet(TypeNil.NIL).makeRO());
TypeMemPtr TOP = TypeMemPtr.TOP;
TypeMemPtr BOT = TypeMemPtr.makeNullable(TypeStruct.BOT);
diff --git a/chapter22/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java b/chapter22/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
index c9f7d801..4f86d0be 100644
--- a/chapter22/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
+++ b/chapter22/src/test/java/com/seaofnodes/simple/fuzzer/ScriptGenerator.java
@@ -97,7 +97,7 @@ public class ScriptGenerator {
private static final List<TypeInt> INTTYPES = new ArrayList<>();
static {
- for( var e : Parser.PRIMS.entrySet() ) {
+ for( var e : Parser.TYPES.entrySet() ) {
if( e.getValue() instanceof TypeInteger ) {
INTTYPES.add(new TypeInt(e.getKey()));
}