From 8ecde979dee25f08bdd3360f19eeb85ead5dd2ca Mon Sep 17 00:00:00 2001 From: Cliff Click Date: Thu, 17 Oct 2024 12:18:27 -0700 Subject: Constructors working Replace ArrayList with Ary, because no "setLength" in ArrayList and "size" is private so I cannot even override. Replace Utils.find with Ary.find. Split Scope into Scope and ScopeMin (bad name). Memory edges go in ScopeMin, and it is pointed at from Scope.mem(). This lets us lazily add memory edges without interleaving them through other non-memory aliases, which was breaking all sorts of parser invariants. ScopeMin aliases are added lazily. Scope & ScopeMin now use an array-of-Var structs instead of a struct-of-arrays. --- .../src/main/java/com/seaofnodes/simple/Ary.java | 217 +++++++++++++++++ .../com/seaofnodes/simple/GlobalCodeMotion.java | 3 +- .../com/seaofnodes/simple/GraphVisualizer.java | 84 +++---- .../main/java/com/seaofnodes/simple/IterPeeps.java | 4 +- .../main/java/com/seaofnodes/simple/Parser.java | 202 ++++++++-------- .../java/com/seaofnodes/simple/node/LoadNode.java | 1 - .../java/com/seaofnodes/simple/node/NewNode.java | 10 +- .../main/java/com/seaofnodes/simple/node/Node.java | 49 ++-- .../java/com/seaofnodes/simple/node/OutNode.java | 4 +- .../com/seaofnodes/simple/node/RegionNode.java | 2 +- .../com/seaofnodes/simple/node/ReturnNode.java | 14 +- .../com/seaofnodes/simple/node/ScopeMinNode.java | 137 +++++++++++ .../java/com/seaofnodes/simple/node/ScopeNode.java | 265 ++++++++++----------- .../java/com/seaofnodes/simple/node/StartNode.java | 45 +--- .../com/seaofnodes/simple/node/StructNode.java | 17 +- .../com/seaofnodes/simple/type/TypeStruct.java | 16 +- .../java/com/seaofnodes/simple/type/TypeTuple.java | 10 +- .../java/com/seaofnodes/simple/Chapter05Test.java | 14 +- .../java/com/seaofnodes/simple/Chapter06Test.java | 10 +- .../java/com/seaofnodes/simple/Chapter07Test.java | 26 +- .../java/com/seaofnodes/simple/Chapter08Test.java | 18 +- .../java/com/seaofnodes/simple/Chapter09Test.java | 10 +- .../java/com/seaofnodes/simple/Chapter10Test.java | 14 +- .../java/com/seaofnodes/simple/Chapter11Test.java | 8 +- .../java/com/seaofnodes/simple/Chapter12Test.java | 2 +- .../java/com/seaofnodes/simple/Chapter13Test.java | 3 +- .../java/com/seaofnodes/simple/Chapter14Test.java | 2 +- .../java/com/seaofnodes/simple/Chapter15Test.java | 40 ++-- .../java/com/seaofnodes/simple/Chapter16Test.java | 27 ++- .../java/com/seaofnodes/simple/SchedulerTest.java | 4 +- .../com/seaofnodes/simple/evaluator/Evaluator.java | 24 +- .../com/seaofnodes/simple/evaluator/Scheduler.java | 2 +- 32 files changed, 826 insertions(+), 458 deletions(-) create mode 100644 chapter16/src/main/java/com/seaofnodes/simple/Ary.java create mode 100644 chapter16/src/main/java/com/seaofnodes/simple/node/ScopeMinNode.java diff --git a/chapter16/src/main/java/com/seaofnodes/simple/Ary.java b/chapter16/src/main/java/com/seaofnodes/simple/Ary.java new file mode 100644 index 00000000..8654d41e --- /dev/null +++ b/chapter16/src/main/java/com/seaofnodes/simple/Ary.java @@ -0,0 +1,217 @@ +package com.seaofnodes.simple; + +import java.lang.StringBuilder; +import java.lang.reflect.Array; +import java.util.*; + +// ArrayList with saner syntax +public class Ary extends AbstractList implements List { + public E[] _es; + public int _len; + + public Ary(E[] es) { this(es,es.length); } + public Ary(E[] es, int len) { if( es.length==0 ) es=Arrays.copyOf(es,1); _es=es; _len=len; } + @SuppressWarnings("unchecked") + public Ary(Class clazz) { this((E[]) Array.newInstance(clazz, 1),0); } + + /** @return list is empty */ + public boolean isEmpty() { return _len==0; } + /** @return active list length */ + public int len() { return _len; } + public int size() { return len(); } + + /** @param i element index + * @return element being returned; throws if OOB + * @exception AIOOBE if !(0 <= i < _len) + */ + public E get( int i ) { return at(i); } + public E at( int i ) { + range_check(i); + return _es[i]; + } + + /** @return last element */ + public E last( ) { return at(_len-1); } + + /** Add element in amortized constant time + * @param e Element to add at end of list + **/ + public E push( E e ) { + if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); + return (_es[_len++] = e); + } + /** @return remove and return last element */ + public E pop( ) { + range_check(0); + return _es[--_len]; + } + @Override public E removeLast() { return pop(); } + + + /** Add element in amortized constant time + * @param e Element to add at end of list + * @return true */ + public boolean add( E e ) { + if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); + _es[_len++] = e; + return true; + } + + ///** Slow, linear-time, element insert. Preserves order. + // * @param i index to insert at, between 0 and _len inclusive. + // * @param e Element to insert + // */ + //public void insert( int i, E e ) { + // if( i < 0 || i>_len ) + // throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len); + // if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); + // System.arraycopy(_es,i,_es,i+1,(_len++)-i); + // _es[i] = e; + //} + + /** Fast, constant-time, element removal. Does not preserve order + * @param i element to be removed + * @return element removed */ + public E del( int i ) { + range_check(i); + E tmp = _es[i]; + _es[i]=_es[--_len]; + return tmp; + } + + ///** Element removal, using '=='. Does not preserve order. + // * @param e element to be removed + // * @return element removed */ + //public E del( E e ) { + // for( int i=0; i<_len; i++ ) { + // E tmp = _es[i]; + // if( tmp==e ) { + // _es[i]=_es[--_len]; + // return tmp; + // } + // } + // return null; + //} + + /** Slow, linear-time, element removal. Preserves order. + * @param i element to be removed + * @return element removed */ + @Override public E remove( int i ) { + range_check(i); + E e = _es[i]; + System.arraycopy(_es,i+1,_es,i,(--_len)-i); + return e; + } + + /** Remove all elements */ + public void clear( ) { _len=0; } + + /** Set existing element + * @param i element to set + * @param e value to set + * @return old value + * @exception AIOOBE if !(0 <= i < _len) + */ + public E set( int i, E e ) { + range_check(i); + E old = _es[i]; + _es[i] = e; + return old; + } + + public Ary setLen( int len ) { + if( len > _len ) + while( len>= _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + _len = len; + while( _es.length > (len<<1) ) // Shrink if hugely too large + _es = Arrays.copyOf(_es,_es.length>>1); + Arrays.fill(_es,len,_es.length,null); + return this; + } + + /** @param c Collection to be added */ + public boolean addAll( Collection c ) { + if( c==null ) return false; + for( E e : c ) add(e); + return true; + } + public Ary addAll( Iterable it ) { for( E e : it ) add(e); return this; } + + /** @param es Array to be added */ + public Ary addAll( F[] es ) { + if( es==null || es.length==0 ) return this; + while( _len+es.length > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + System.arraycopy(es,0,_es,_len,es.length); + _len += es.length; + return this; + } + + /** @param c Collection to be added */ + public Ary addAll( Ary c ) { + if( c==null || c._len==0 ) return this; + while( _len+c._len > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + System.arraycopy(c._es,0,_es,_len,c._len); + _len += c._len; + return this; + } + + /** @return compact array version */ + public E[] asAry() { return Arrays.copyOf(_es,_len); } + + /** Sorts in-place + * @param c Comparator to sort by */ + public void sort_update(Comparator c ) { Arrays.sort(_es, 0, _len, c); } + + /** Find the first matching element using ==, or -1 if none. Note that + * most del calls shuffle the list, so the first element might be random. + * @param e Element to find + * @return index of first matching element, or -1 if none */ + public int find( E e ) { + for( int i=0; i<_len; i++ ) if( _es[i]==e ) return i; + return -1; + } + + + /** @return an iterator */ + @Override public Iterator iterator() { return new Iter(); } + private class Iter implements Iterator { + int _i=0; + @Override public boolean hasNext() { return _i<_len; } + @Override public E next() { return _es[_i++]; } + } + + @Override public String toString() { + StringBuilder sb = new StringBuilder().append('{'); + for( int i=0; i<_len; i++ ) { + if( i>0 ) sb.append(','); + if( _es[i] != null ) sb.append(_es[i].toString()); + } + return sb.append('}').toString(); + } + + private void range_check( int i ) { + if( i < 0 || i>=_len ) + throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len); + } + + // Note that the hashCode() and equals() are not invariant to changes in the + // underlying array. If the hashCode() is used (e.g., inserting into a + // HashMap) and the then the array changes, the hashCode() will change also. + @Override public boolean equals( Object o ) { + if( this==o ) return true; + if( !(o instanceof Ary ary) ) return false; + if( _len != ary._len ) return false; + if( _es == ary._es ) return true; + for( int i=0; i<_len; i++ ) + if( !(_es[i]==null ? (ary._es[i] == null) : _es[i].equals(ary._es[i])) ) + return false; + return true; + } + @Override public int hashCode( ) { + int sum=_len; + for( int i=0; i<_len; i++ ) + sum += _es[i]==null ? 0 : _es[i].hashCode(); + return sum; + } + +} diff --git a/chapter16/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java b/chapter16/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java index 2eac6ccc..d2bbdc1e 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/GlobalCodeMotion.java @@ -235,6 +235,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 ScopeMinNode ret: break; // Mem uses now on ScopeMin case NeverNode never: break; default: throw Utils.TODO(); } @@ -249,7 +250,7 @@ public abstract class GlobalCodeMotion { // Store and Load overlap, need anti-dependence if( stblk._anti==load._nid ) { lca = stblk._idom(lca,null); // Raise Loads LCA - if( lca == stblk && st != null && Utils.find(st._inputs,load) == -1 ) // And if something moved, + if( lca == stblk && st != null && st._inputs.find(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/chapter16/src/main/java/com/seaofnodes/simple/GraphVisualizer.java b/chapter16/src/main/java/com/seaofnodes/simple/GraphVisualizer.java index f5fa1350..9e0700d5 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/GraphVisualizer.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/GraphVisualizer.java @@ -5,6 +5,8 @@ import com.seaofnodes.simple.node.*; import java.util.*; +import static com.seaofnodes.simple.Utils.TODO; + /** * Simple visualizer that outputs GraphViz dot format. * The dot output must be saved to a file and run manually via dot to generate the SVG output. @@ -155,25 +157,26 @@ public class GraphVisualizer { private void scope( StringBuilder sb, ScopeNode scope ) { sb.append("\tnode [shape=plaintext];\n"); int level=1; - for( int idx = scope._idxs.size()-1; idx>=0; idx-- ) { - var syms = scope._idxs.get(idx); - String scopeName = makeScopeName(scope, level); - sb.append("\tsubgraph cluster_").append(scopeName).append(" {\n"); // Magic "cluster_" in the subgraph name - sb.append("\t\t").append(scopeName).append(" [label=<\n"); - sb.append("\t\t\t\n"); - // Add the scope level - int scopeLevel = scope._idxs.size()-level; - sb.append("\t\t\t"); - for(String name: syms.keySet()) - sb.append(""); - sb.append("\n"); - sb.append("\t\t\t
").append(scopeLevel).append("").append(name).append("
>];\n"); - level++; - } - // Scope clusters nest, so the graphics shows the nested scopes, so - // they are not closed as they are printed; so they just keep nesting. - // We close them all at once here. - sb.append( "\t}\n".repeat( level-1 ) ); // End all Scope clusters + //for( int idx = scope._idxs.size()-1; idx>=0; idx-- ) { + // var syms = scope._idxs.get(idx); + // String scopeName = makeScopeName(scope, level); + // sb.append("\tsubgraph cluster_").append(scopeName).append(" {\n"); // Magic "cluster_" in the subgraph name + // sb.append("\t\t").append(scopeName).append(" [label=<\n"); + // sb.append("\t\t\t\n"); + // // Add the scope level + // int scopeLevel = scope._idxs.size()-level; + // sb.append("\t\t\t"); + // for(String name: syms.keySet()) + // sb.append(""); + // sb.append("\n"); + // sb.append("\t\t\t
").append(scopeLevel).append("").append(name).append("
>];\n"); + // level++; + //} + //// Scope clusters nest, so the graphics shows the nested scopes, so + //// they are not closed as they are printed; so they just keep nesting. + //// We close them all at once here. + //sb.append( "\t}\n".repeat( level-1 ) ); // End all Scope clusters + throw TODO(); } private String makeScopeName(ScopeNode sn, int level) { return sn.uniqueName() + "_" + level; } @@ -230,27 +233,28 @@ public class GraphVisualizer { private void scopeEdges( StringBuilder sb, ScopeNode scope ) { sb.append("\tedge [style=dashed color=cornflowerblue];\n"); int level=1; - for( int i = scope._idxs.size()-1; i>=0; i-- ) { - var syms = scope._idxs.get(i); - String scopeName = makeScopeName(scope, level); - for( String name : syms.keySet() ) { - int idx = syms.get(name); - Node def = scope.in(idx); - while( def instanceof ScopeNode lazy ) - def = lazy.in(idx); - if( def==null ) continue; - sb.append("\t") - .append(scopeName).append(":") - .append('"').append(makePortName(scopeName, name)).append('"') // wrap port name with quotes because $ctrl is not valid unquoted - .append(" -> "); - if( def instanceof CProjNode proj ) { - String mname = proj.ctrl().uniqueName(); - sb.append(mname).append(":p").append(proj._idx); - } else sb.append(def.uniqueName()); - sb.append(";\n"); - } - level++; - } + //for( int i = scope._idxs.size()-1; i>=0; i-- ) { + // var syms = scope._idxs.get(i); + // String scopeName = makeScopeName(scope, level); + // for( String name : syms.keySet() ) { + // int idx = syms.get(name); + // Node def = scope.in(idx); + // while( def instanceof ScopeNode lazy ) + // def = lazy.in(idx); + // if( def==null ) continue; + // sb.append("\t") + // .append(scopeName).append(":") + // .append('"').append(makePortName(scopeName, name)).append('"') // wrap port name with quotes because $ctrl is not valid unquoted + // .append(" -> "); + // if( def instanceof CProjNode proj ) { + // String mname = proj.ctrl().uniqueName(); + // sb.append(mname).append(":p").append(proj._idx); + // } else sb.append(def.uniqueName()); + // sb.append(";\n"); + // } + // level++; + //} + throw TODO(); } /** diff --git a/chapter16/src/main/java/com/seaofnodes/simple/IterPeeps.java b/chapter16/src/main/java/com/seaofnodes/simple/IterPeeps.java index 783fc4f1..96ae350e 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/IterPeeps.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/IterPeeps.java @@ -50,7 +50,7 @@ public abstract class IterPeeps { return (N)WORK.push(n); } - public static void addAll( ArrayList ary ) { + public static void addAll( Ary ary ) { WORK.addAll(ary); } @@ -170,7 +170,7 @@ public abstract class IterPeeps { return x; } - public void addAll( ArrayList ary ) { + public void addAll( Ary ary ) { for( E n : ary ) push(n); } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/Parser.java b/chapter16/src/main/java/com/seaofnodes/simple/Parser.java index 572c170a..c77792de 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/Parser.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/Parser.java @@ -2,6 +2,7 @@ package com.seaofnodes.simple; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; +import static com.seaofnodes.simple.Utils.TODO; import java.util.*; @@ -124,7 +125,7 @@ public class Parser { _lexer = new Lexer(source); _scope = new ScopeNode(); _continueScope = _breakScope = null; - START = new StartNode(new Type[]{ Type.CONTROL, arg }); + START = new StartNode(arg); STOP = new StopNode(source); ZERO = con(0).keep(); XCTRL= new XCtrlNode().peephole().keep(); @@ -138,13 +139,10 @@ public class Parser { @Override public String toString() { return _lexer.toString(); } - String src() { return new String( _lexer._input ); } - // Debugging utility to find a Node by index public static Node find(int nid) { return START.find(nid); } private Node ctrl() { return _scope.ctrl(); } - private Node ctrl(Node n) { return _scope.ctrl(n); } public StopNode parse() { return parse(false); } @@ -152,8 +150,12 @@ public class Parser { _xScopes.push(_scope); // Enter a new scope for the initial control and arguments _scope.push(); - _scope.define(ScopeNode.CTRL, Type.CONTROL , new CProjNode(START, 0, ScopeNode.CTRL).peephole(), false); - _scope.define(ScopeNode.ARG0, TypeInteger.BOT, new ProjNode(START, 1, ScopeNode.ARG0).peephole(), false); + ScopeMinNode mem = new ScopeMinNode(); + mem.addDef(null); + _scope.define(ScopeNode.CTRL, Type.CONTROL , false, new CProjNode(START, 0, ScopeNode.CTRL).peephole()); + mem.addDef( new ProjNode(START, 1, ScopeNode.MEM0).peephole()); + _scope.define(ScopeNode.MEM0, TypeMem.TOP , false, mem .peephole()); + _scope.define(ScopeNode.ARG0, TypeInteger.BOT, false, new ProjNode(START, 2, ScopeNode.ARG0).peephole()); // Parse whole program parseBlock(); @@ -162,6 +164,9 @@ public class Parser { STOP.addReturn(new ReturnNode(ctrl(), ZERO, _scope).peephole()); _scope.pop(); _xScopes.pop(); + for( StructNode init : INITS.values() ) + init.unkeep().kill(); + INITS.clear(); if (!_lexer.isEOF()) throw error("Syntax error, unexpected " + _lexer.getAnyNextToken()); STOP.peephole(); if( show ) showGraph(); @@ -298,15 +303,15 @@ public class Parser { ctrl(XCTRL); // Kill current scope // Prune nested lexical scopes that have depth > than the loop head // We use _breakScope as a proxy for the loop head scope to obtain the depth - while( cur._idxs.size() > _breakScope._idxs.size() ) + while( cur._lexSize.size() > _breakScope._lexSize.size() ) cur.pop(); // If this is a continue then first time the target is null // So we just use the pruned current scope as the base for the // "continue" - if (toScope == null) + if( toScope == null ) return cur; // toScope is either the break scope, or a scope that was created here - assert toScope._idxs.size() <= _breakScope._idxs.size(); + assert toScope._lexSize.size() <= _breakScope._lexSize.size(); toScope.ctrl(toScope.mergeScopes(cur)); return toScope; } @@ -407,7 +412,7 @@ public class Parser { ? Type.TOP // Else takes the default : t.makeInit(); - expr = new ConstantNode(init).peephole(); + expr = con(init); } else if( !match("=") ) { // Something else _lexer._position = old; @@ -418,15 +423,15 @@ public class Parser { // Defining a new variable vs updating an old one if( !isDecl ) { // Assigning over an existing name // Lookup - Node def = _scope.lookup(name); + ScopeMinNode.Var def = _scope.lookup(name); if( def==null ) throw error("Undefined name '" + name + "'"); // TOP fields are for late-initialized fields; these have never // been written to, and this must be the final write. Other writes // need to check the final bit. - if( def._type!=Type.TOP && _scope.lookupFinal(name) ) + if( _scope.in(def._idx)._type!=Type.TOP && def._final ) throw error("Cannot reassign final '"+name+"'"); - t = _scope.lookupDeclaredType(name); + t = def._type; // Declared field type } // Auto-widen int to float @@ -443,7 +448,7 @@ public class Parser { throw error("Type " + e.str() + " is not of declared type " + t.str()); if( isDecl ) { - if( !_scope.define(name,t,expr,xfinal) ) + if( !_scope.define(name,t,xfinal,expr) ) throw error("Redefining name '" + name + "'"); } else _scope.update(name,expr); @@ -501,41 +506,29 @@ public class Parser { if( t!=null && !(t instanceof TypeMemPtr tmp && tmp._obj._fields==null) ) throw errorSyntax("struct '" + typeName + "' cannot be redefined"); - // A Block scope parse, and inspect the scope afterwards for fields. + // A Block scope parse, and inspect the scope afterward for fields. _scope.push(); require("{"); while (!peek('}') && !_lexer.isEOF()) parseStatement(); // Grab the declarations and build fields and a Struct - HashMap decls = _scope._decls.lastElement(); - HashMap idxs = _scope._idxs.lastElement(); - BitSet finals = _scope._finals; - - StructNode s = new StructNode().keep(); - Field[] fs = new Field[decls.size()]; int i=0; - for( String fname : decls.keySet() ) { - int idx = idxs.get(fname); - boolean isFinal = finals.get(idx); - Type decl = decls.get(fname); - fs[i++] = Field.make(fname,decl,ALIAS++,isFinal); - s.addDef(_scope.in(idx)); + int lexlen = _scope._lexSize.last(); + int varlen = _scope._vars._len; + StructNode s = new StructNode(); + Field[] fs = new Field[varlen-lexlen]; + for( int i=lexlen; i init=s._inputs; int idx=0; + if( hasConstructor ) { + init = _scope._inputs; + idx = _scope.nIns(); + // Push a scope, and pre-assign all struct fields. + _scope.push(); + for( int i=0; i init ) { Field[] fs = obj._fields; if( fs==null ) throw error("Unknown struct type '" + obj._name + "'"); @@ -815,36 +820,37 @@ public class Parser { Node[] ns = new Node[2+len+len]; ns[0] = ctrl(); // Control in slot 0 // Total allocated length in bytes - ns[1] = con(obj.offset(len)); + ns[1] = size; // Memory aliases for every field for( int i = 0; i < len; i++ ) ns[2 +i] = memAlias(fs[i]._alias); // Initial values for every field for( int i = 0; i < len; i++ ) - ns[2+len+i] = init.in(i+idx); + ns[2+len+i] = init.get(i+idx); Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole(); for( int i = 0; i < len; i++ ) memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole()); return new ProjNode(nnn,1,obj._name).peephole(); } + private static final Ary ALTMP = new Ary<>(Node.class); private Node newArray(TypeStruct ary, Node len) { int base = ary.aryBase (); int scale= ary.aryScale(); Node size = new AddNode(con(base),new ShlNode(len,con(scale)).peephole()).peephole(); - //Node ptr = newStruct(ary,size); + ALTMP.clear(); ALTMP.add(len); ALTMP.add(con(ary._fields[1]._type.makeInit())); + Node ptr = newStruct(ary,size,0,ALTMP); //int alias = ary._fields[0]._alias; // Length alias //memAlias(alias,new StoreNode("#",alias,TypeInteger.BOT,memAlias(alias),ptr,con( ary.offset(0) ), len.unkeep(), true ).peephole()); - //return ptr; - throw Utils.TODO(); + return ptr; } // We set up memory aliases by inserting special vars in the scope these // variables are prefixed by $ so they cannot be referenced in Simple code. // Using vars has the benefit that all the existing machinery of scoping // and phis work as expected - private Node memAlias(int alias ) { return _scope.lookup(memName(alias) ); } - private Node memAlias(int alias, Node st) { return _scope.update(memName(alias), st); } + private Node memAlias(int alias ) { return _scope.mem(alias ); } + private void memAlias(int alias, Node st) { _scope.mem(alias, st); } public static String memName(int alias) { return ("$"+alias).intern(); } /** @@ -942,13 +948,9 @@ public class Parser { * floatLiteral: [digits].[digits]?[e [digits]]? * */ - private ConstantNode parseLiteral() { - return (ConstantNode) new ConstantNode(_lexer.parseNumber()).peephole(); - } - - public static Node con( long con ) { - return new ConstantNode(TypeInteger.constant(con)).peephole(); - } + private ConstantNode parseLiteral() { return con(_lexer.parseNumber()); } + public static Node con( long con ) { return con(TypeInteger.constant(con)); } + public static ConstantNode con( Type t ) { return (ConstantNode)new ConstantNode(t).peephole(); } ////////////////////////////////// // Utilities for lexical analysis 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 bc3f4335..be6fba11 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/LoadNode.java @@ -38,7 +38,6 @@ public class LoadNode extends MemOpNode { if( mem()._type instanceof TypeMem mem && // No constant folding if ptr might null-check _declaredType != mem._t && err()==null ) { - assert mem._alias == _alias; return _declaredType.join(mem._t); } return _declaredType; 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 c65d7ca5..cb6ee464 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/NewNode.java @@ -32,7 +32,10 @@ public class NewNode extends Node implements MultiNode { } @Override public String label() { - return "new_" + (_ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str()); + return "new_"+glabel(); + } + @Override public String glabel() { + return _ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str(); } @Override @@ -43,10 +46,7 @@ public class NewNode extends Node implements MultiNode { // Find matching alias input Node findAlias(int alias) { - for( int i=0; i<_len; i++ ) - if( ((TypeMem)in(2+i)._type)._alias == alias ) - return in(2+i+_len); - throw Utils.TODO(); // Must find + return in(2+_ptr._obj.findAlias(alias)+_len); } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/Node.java b/chapter16/src/main/java/com/seaofnodes/simple/node/Node.java index e4b887a0..462a403c 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/Node.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node; +import com.seaofnodes.simple.Ary; import com.seaofnodes.simple.IRPrinter; import com.seaofnodes.simple.IterPeeps; import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; - import java.util.*; import java.util.function.Function; @@ -28,9 +28,9 @@ public abstract class Node implements OutNode { *

* Generally fixed length, ordered, nulls allowed, no unused trailing space. * Ordering is required because e.g. "a/b" is different from "b/a". - * The first input (offset 0) is often a {@link #isCFG} node. + * The first input (offset 0) is often a {@link CFGNode} node. */ - public final ArrayList _inputs; + public final Ary _inputs; /** * Outputs reference Nodes that are not null and have this Node as an @@ -41,7 +41,7 @@ public abstract class Node implements OutNode { * walked in either direction. These outputs are typically used for * efficient optimizations but otherwise have no semantics meaning. */ - public final ArrayList _outputs; + public final Ary _outputs; /** @@ -61,9 +61,9 @@ public abstract class Node implements OutNode { protected Node(Node... inputs) { _nid = UNIQUE_ID++; // allocate unique dense ID - _inputs = new ArrayList<>(); + _inputs = new Ary<>(Node.class); Collections.addAll(_inputs,inputs); - _outputs = new ArrayList<>(); + _outputs = new Ary<>(Node.class); for( Node n : _inputs ) if( n != null ) n.addUse( this ); @@ -127,7 +127,7 @@ public abstract class Node implements OutNode { */ public Node in(int i) { return _inputs.get(i); } public Node out(int i) { return _outputs.get(i); } - @Override public ArrayList outs() { return _outputs; } + @Override public Ary outs() { return _outputs; } public int nIns() { return _inputs.size(); } @@ -168,7 +168,7 @@ public abstract class Node implements OutNode { old_def.delUse(this) ) // If we removed the last use, the old def is now dead old_def.kill(); // Kill old def moveDepsToWorklist(); - // Return self for easy flow-coding + // Return new_def for easy flow-coding return new_def; } @@ -179,13 +179,20 @@ public abstract class Node implements OutNode { Node delDef(int idx) { unlock(); Node old_def = in(idx); - Utils.del(_inputs, idx); + _inputs.del(idx); if( old_def.delUse(this) ) // If we removed the last use, the old def is now dead old_def.kill(); // Kill old def old_def.moveDepsToWorklist(); return this; } + // Insert the numbered input, sliding other inputs to the right + Node insertDef(int idx, Node new_def) { + _inputs.add(idx,null); + return setDef(idx,new_def); + } + + /** * Add a new def to an existing Node. Keep the edges correct by * adding the corresponding def->use edge. @@ -210,16 +217,16 @@ public abstract class Node implements OutNode { // Return true if the output list is empty afterward. // Error is 'use' does not exist; ok for 'use' to be null. protected boolean delUse( Node use ) { - Utils.del(_outputs, Utils.find(_outputs, use)); + _outputs.del(_outputs.find(use)); return _outputs.isEmpty(); } - // Shortcut for "popping" n nodes. A "pop" is basically a + // Shortcut for "popping" until n nodes. A "pop" is basically a // setDef(last,null) followed by lowering the nIns() count. - void popN(int n) { + void popUntil(int n) { unlock(); - for( int i=0; i n ) { + Node old_def = _inputs.pop(); if( old_def != null && // If it exists and old_def.delUse(this) ) // If we removed the last use, the old def is now dead old_def.kill(); // Kill old def @@ -259,7 +266,7 @@ public abstract class Node implements OutNode { return (N)this; } // Test "keep" status - public boolean iskeep() { return Utils.find(_outputs,null) != -1; } + public boolean iskeep() { return _outputs.find(null) != -1; } // Replace self with nnn in the graph, making 'this' go dead @@ -268,7 +275,7 @@ public abstract class Node implements OutNode { while( nOuts() > 0 ) { Node n = _outputs.removeLast(); n.unlock(); - int idx = Utils.find(n._inputs, this); + int idx = n._inputs.find(this); n._inputs.set(idx,nnn); nnn.addUse(n); } @@ -451,7 +458,7 @@ public abstract class Node implements OutNode { // on a node some distance away, and if that node ever changes we should // retry the peephole. Track a set of Nodes dependent on `this`, and // revisit them if `this` changes. - ArrayList _deps; + Ary _deps; /** * Add a node to the list of dependencies. Only add it if its not an input @@ -462,10 +469,10 @@ public abstract class Node implements OutNode { // Running peepholes during the big assert cannot have side effects // like adding dependencies. if( IterPeeps.midAssert() ) return this; - if( _deps==null ) _deps = new ArrayList<>(); - if( Utils.find(_deps ,dep) != -1 ) return this; // Already on list - if( Utils.find(_inputs,dep) != -1 ) return this; // No need for deps on immediate neighbors - if( Utils.find(_outputs,dep)!= -1 ) return this; + if( _deps==null ) _deps = new Ary<>(Node.class); + if( _deps .find(dep) != -1 ) return this; // Already on list + if( _inputs .find(dep) != -1 ) return this; // No need for deps on immediate neighbors + if( _outputs.find(dep) != -1 ) return this; _deps.add(dep); return this; } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/OutNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/OutNode.java index 7e531145..dbac136b 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/OutNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/OutNode.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node; -import java.util.ArrayList; +import com.seaofnodes.simple.Ary; public interface OutNode { - ArrayList outs(); + Ary outs(); } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/RegionNode.java index bd05ce01..09a32c95 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/RegionNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/RegionNode.java @@ -68,7 +68,7 @@ public class RegionNode extends CFGNode { if( !hasPhi() && // No Phi users, just a control user in(1) instanceof CProjNode p1 && in(2) instanceof CProjNode p2 && - p1.in(0)==p2.in(0) && + p1.in(0).addDep(this)==p2.in(0).addDep(this) && p1.in(0) instanceof IfNode iff ) return iff.ctrl(); diff --git a/chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java index e12f1fef..de4eba52 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -16,17 +16,11 @@ import java.util.BitSet; public class ReturnNode extends CFGNode { public ReturnNode(Node ctrl, Node data, ScopeNode scope) { - super(ctrl, data); // Add memory slices to Return, so all memory updates are live-on-exit. - // We look up memory slices by the naming convention that they start with $. - // We could also use implicit knowledge that all memory projects are at offset >= 2 - if( scope != null ) { - String[] names = scope.reverseNames(); - for (String name: names) { - if (!name.equals("$ctrl") && name.startsWith("$")) - addDef(scope.lookup(name)); - } - } + super(ctrl, data); + if( scope!=null ) + for( int i=2; i= nIns() ) addDef(null); + return setDef(alias,st); + } + + + // Read or update from memory. + // A shared implementation allows us to create lazy phis both during + // lookups and updates; the lazy phi creation is part of chapter 8. + Node _mem( int alias, Node st ) { + // Memory projections are made lazily; if one does not exist + // then it must be START.proj(1) + Node old = alias(alias); + if( old instanceof ScopeNode loop ) { + ScopeMinNode loopmem = loop.mem(); + Node memdef = loopmem.alias(alias); + // Lazy phi! + old = memdef instanceof PhiNode phi && loop.ctrl()==phi.region() + // Loop already has a real Phi, use it + ? memdef + // 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. + : loopmem.alias(alias, new PhiNode(Parser.memName(alias), TypeMem.BOT,loop.ctrl(),loopmem._mem(alias,null),null).peephole() ); + alias(alias,old); + } + // Memory projections are made lazily; expand as needed + return st==null ? old : alias(alias,st); // Not lazy, so this is the answer + } + + + void _merge(ScopeMinNode that, RegionNode r) { + int len = Math.max(nIns(),that.nIns()); + for( int i = 2; i < len; i++) + if( alias(i) != that.alias(i) ) { // No need for redundant Phis + // If we are in lazy phi mode we need to a lookup + // by name as it will trigger a phi creation + //Var v = _vars.at(i); + Node lhs = this._mem(i,null); + Node rhs = that._mem(i,null); + alias(i, new PhiNode(Parser.memName(i), TypeMem.BOT, r, lhs, rhs).peephole()); + } + } + + // Fill in the backedge of any inserted Phis + void _endLoopMem( ScopeNode scope, ScopeMinNode back, ScopeMinNode exit ) { + for( int i=2; i> _idxs; + // All active/live variables in all nested scopes, all run together + public final Ary _vars; - /* - * Map input edge to Final bit - */ - public final BitSet _finals; + // Since of each nested lexical scope + public final Ary _lexSize; - /** - * Map variable names to declared Type - */ - public final Stack> _decls; // A new ScopeNode - public ScopeNode() { - _idxs = new Stack<>(); - _decls= new Stack<>(); - _finals = new BitSet(); - _type = Type.BOTTOM; - } + public ScopeNode() { _vars = new Ary<>(Var.class); _lexSize = new Ary<>(Integer.class); } @Override public String label() { return "Scope"; } + @Override StringBuilder _print1(StringBuilder sb, BitSet visited) { sb.append("Scope[ "); - String[] names = reverseNames(); - for( int j=0; j syms : _idxs ) - for( String name : syms.keySet() ) - names[syms.get(name)] = name; - return names; + public void push() { + _lexSize.push(_vars.size()); } - - @Override public Type compute() { return Type.BOTTOM; } - - @Override public Node idealize() { return null; } - - public void push() { _idxs.push(new HashMap<>()); _decls.push(new HashMap<>()); } public void pop() { - popN(_idxs.pop().size()); - _finals.clear(nIns()); - _decls.pop(); + int n = _lexSize.pop(); + popUntil(n); + _vars.setLen(n); + } + + // 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. + int find( String name ) { + for( int i=_vars.size()-1; i>=0; i-- ) + if( _vars.get(i)._name.equals(name) ) + return i; + return -1; } /** * Create a new variable name in the current scope */ - public boolean define( String name, Type declaredType, Node n, boolean xfinal ) { - HashMap syms = _idxs.lastElement(); - _decls.lastElement().put(name,declaredType); - if( syms.put(name,nIns()) != null ) - return false; // Double define - if( xfinal ) _finals.set(nIns()); // track finals - addDef(n); + public boolean define( String name, Type declaredType, boolean xfinal, Node init ) { + assert name.charAt(0)!='$' || _lexSize.size()==1; // Later scopes do not define memory + if( _lexSize._len > 1 ) + for( int i=_vars.size()-1; i>=_lexSize.last(); i-- ) + if( _vars.get(i)._name.equals(name) ) + return false; // Double define + _vars.add(new Var(nIns(),name,declaredType,xfinal)); + addDef(init); return true; } + // Read from memory + public Node mem( int alias ) { return mem()._mem(alias,null); } + // Write to memory + public void mem( int alias, Node st ) { mem()._mem(alias,st); } + + /** * Lookup a name in all scopes starting from most deeply nested. * * @param name Name to be looked up - * @see #update(String, Node, int) + * @return null if not found, or the implementing Node */ - public Node lookup( String name ) { return update(name,null,_idxs.size()-1); } + public Var lookup( String name ) { + int idx = find(name); + // -1 is missed in all scopes, not found + return idx == -1 ? null : _update(_vars.at(idx),null); + } + /** * If the name is present in any scope, then redefine else null * * @param name Name being redefined * @param n The node to bind to the name */ - public Node update( String name, Node n ) { return update(name,n,_idxs.size()-1); } - /** - * Both recursive lookup and update. - *

- * A shared implementation allows us to create lazy phis both during - * lookups and updates; the lazy phi creation is part of chapter 8. - * - * @param name Name whose binding is being updated or looked up - * @param n If null, do a lookup, else update binding - * @param nestingLevel The starting nesting level - * @return node being looked up, or the one that was updated - */ - private Node update( String name, Node n, int nestingLevel ) { - if( nestingLevel<0 ) return null; // Missed in all scopes, not found - var syms = _idxs.get(nestingLevel); // Get the symbol table for nesting level - var idx = syms.get(name); - if( idx == null ) return update(name,n,nestingLevel-1); // Not found in this scope, recursively look in parent scope - Node old = in(idx); + public void update( String name, Node n ) { + int idx = find(name); + assert idx>=0; + _update(_vars.at(idx),n); + } + + Var _update( ScopeNode.Var v, Node st ) { + Node old = in(v._idx); if( old instanceof ScopeNode loop ) { // Lazy Phi! - old = loop.in(idx) instanceof PhiNode phi && loop.ctrl()==phi.region() + Node def = loop.in(v._idx); + old = def instanceof PhiNode phi && loop.ctrl()==phi.region() // Loop already has a real Phi, use it - ? loop.in(idx) + ? def // 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(idx,new PhiNode(name, lookupDeclaredType(name),loop.ctrl(),loop.update(name,null,nestingLevel),null).peephole()); - setDef(idx,old); + : 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); } - return n==null ? old : setDef(idx,n); // Not lazy, so this is the answer - } - - // Return declared type for a variable - public Type lookupDeclaredType( String name ) { - for( int i=_decls.size(); i>0; i-- ) { - Type t = _decls.get(i-1).get(name); - if( t != null ) return t; - } - return null; - } - - // Return declared type for a variable - public boolean lookupFinal( String name ) { - for( int i=_idxs.size(); i>0; i-- ) { - Integer t = _idxs.get(i-1).get(name); - if( t != null ) return _finals.get(t); - } - throw Utils.TODO(); // Should not reach here + if( st!=null ) setDef(v._idx,st); // Set new value + return v; } /** @@ -198,13 +178,22 @@ public class ScopeNode extends Node { // 1) duplicate the name bindings of the ScopeNode across all stack levels // 2) Make the new ScopeNode a user of all the nodes bound // 3) Ensure that the order of defs is the same to allow easy merging - for( HashMap syms : _idxs ) - dup._idxs.push(new HashMap<>(syms)); - for( HashMap ts : _decls ) - dup._decls.push(ts); // Types don't change, just keep stacks aligned - + dup._vars.addAll(_vars); + dup._lexSize.addAll(_lexSize); dup.addDef(ctrl()); // Control input is just copied - for( int i=1; i= nIns() || in(alias)==null ? 1 : alias ); + } + + Node alias( int alias, Node st ) { + while( alias >= nIns() ) + addDef(null); + return setDef(alias,st); + } + + @Override public TypeStruct compute() { + if( _ts==null ) return TypeStruct.BOT; Field[] fs = new Field[_ts._fields.length]; for( int i=0; i ts) { ts.add(TEST); ts.add(BOT); ts.add(S1); ts.add(S2); ts.add(ARY); } + // Find field index by name public int find(String fname) { for( int i=0; i<_fields.length; i++ ) if( _fields[i]._fname.equals(fname) ) @@ -63,6 +64,15 @@ public class TypeStruct extends Type { return -1; } + // Find field index by alias + public int findAlias( int alias ) { + for( int i=0; i<_fields.length; i++ ) + if( _fields[i]._alias==alias ) + return i; + return -1; + } + + @Override Type xmeet(Type t) { TypeStruct that = (TypeStruct) t; @@ -150,10 +160,10 @@ public class TypeStruct extends Type { public StringBuilder print(StringBuilder sb) { sb.append(_name); if( _fields == null ) return sb; // Forward reference struct, just print the name - sb.append(" {\n"); + sb.append(" {"); for( Field f : _fields ) { sb.append(" ").append(f._fname).append(" :"); - f._type.print(sb).append(";\n"); + f._type.print(sb).append("; "); } return sb.append("}"); } diff --git a/chapter16/src/main/java/com/seaofnodes/simple/type/TypeTuple.java b/chapter16/src/main/java/com/seaofnodes/simple/type/TypeTuple.java index 59ddf34b..a34c64db 100644 --- a/chapter16/src/main/java/com/seaofnodes/simple/type/TypeTuple.java +++ b/chapter16/src/main/java/com/seaofnodes/simple/type/TypeTuple.java @@ -7,15 +7,17 @@ public class TypeTuple extends Type { public final Type[] _types; private TypeTuple(Type[] types) { super(TTUPLE); _types = types; } - public static TypeTuple make(Type... types) { return new TypeTuple(types).intern(); } + public static TypeTuple make(Type... types) { return new TypeTuple(types).intern(); } - private static TypeTuple TEST = make(TypeInteger.BOT,TypeMemPtr.TEST); - public static void gather(ArrayList ts) { ts.add(TEST); } + private static final TypeTuple TEST = make(TypeInteger.BOT,TypeMemPtr.TEST); + public static final TypeTuple START = make(Type.CONTROL,TypeMem.TOP,TypeInteger.BOT); + public static void gather(ArrayList ts) { ts.add(TEST); ts.add(START); } @Override Type xmeet(Type other) { TypeTuple tt = (TypeTuple)other; // contract from xmeet - assert _types.length == tt._types.length; + if( _types.length != tt._types.length ) + return BOTTOM; Type[] ts = new Type[_types.length]; for( int i=0; i<_types.length; i++ ) ts[i] = _types[i].meet(tt._types[i]); diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java index 9d154413..b5920125 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter05Test.java @@ -22,7 +22,7 @@ else { return a;"""); StopNode ret = parser.parse().iterate(); - assertEquals("return Phi(Region20,(arg+2),(arg-3));", ret.toString()); + assertEquals("return Phi(Region23,(arg+2),(arg-3));", ret.toString()); } @Test @@ -37,7 +37,7 @@ if (arg == 1) { } return c;""", TypeInteger.BOT); StopNode ret = parser.parse().iterate(); - assertEquals("return Phi(Region19,4,3);", ret.toString()); + assertEquals("return Phi(Region22,4,3);", ret.toString()); } @Test @@ -65,7 +65,7 @@ else b=a+1; return a+b;"""); StopNode ret = parser.parse().iterate(); - assertEquals("return ((arg*2)+Phi(Region23,2,3));", ret.toString()); + assertEquals("return ((arg*2)+Phi(Region26,2,3));", ret.toString()); } @Test @@ -80,7 +80,7 @@ else a=b+1; return a+b;"""); StopNode ret = parser.parse().iterate(); - assertEquals("return ((Phi(Region34,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString()); + assertEquals("return ((Phi(Region37,(arg*2),arg)+arg)+Phi(Region,4,5));", ret.toString()); } @Test @@ -100,7 +100,7 @@ else return a; """, TypeInteger.BOT); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region38,Phi(Region24,2,3),Phi(Region36,4,5));", stop.toString()); + assertEquals("return Phi(Region43,Phi(Region28,2,3),Phi(Region41,4,5));", stop.toString()); } @Test @@ -116,7 +116,7 @@ if( arg==0 ) return arg+a+b; """, TypeInteger.BOT); StopNode stop = parser.parse(); - assertEquals("return ((arg+Phi(Region17,1,0))+Phi(Region33,2,0));", stop.toString()); + assertEquals("return ((arg+Phi(Region20,1,0))+Phi(Region37,2,0));", stop.toString()); } @Test @@ -130,7 +130,7 @@ if( arg==1 ) } return a;"""); StopNode ret = parser.parse().iterate(); - assertEquals("return (arg==Phi(Region19,3,2));", ret.toString()); + assertEquals("return (arg==Phi(Region22,3,2));", ret.toString()); } @Test diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java index ae37a867..6308bdea 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter06Test.java @@ -65,7 +65,7 @@ else b=5; return b;""", TypeInteger.BOT); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region39,42,5);", stop.toString()); + assertEquals("return Phi(Region43,42,5);", stop.toString()); } @Test @@ -84,7 +84,7 @@ else b=5; return b;""", TypeInteger.BOT); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region32,2,5);", stop.toString()); + assertEquals("return Phi(Region36,2,5);", stop.toString()); } @Test @@ -144,7 +144,7 @@ else return a; """, TypeInteger.BOT); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region43,3,Phi(Region41,4,5));", stop.toString()); + assertEquals("return Phi(Region48,3,Phi(Region46,4,5));", stop.toString()); } @Test @@ -200,7 +200,7 @@ if( arg ) { return a+b; """); StopNode ret = parser.parse().iterate(); - assertEquals("return Phi(Region28,4,1);", ret.toString()); + assertEquals("return Phi(Region32,4,1);", ret.toString()); } @@ -251,7 +251,7 @@ if( arg ) { return a+b+c; """); StopNode ret = parser.parse().iterate(); - assertEquals("return (Phi(Region40,Phi(Region25,2,3),0)+Phi(Region,3,1));", ret.toString()); + assertEquals("return (Phi(Region45,Phi(Region29,2,3),0)+Phi(Region,3,1));", ret.toString()); } diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java index e6e0560b..b54c24a3 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter07Test.java @@ -18,7 +18,7 @@ public class Chapter07Test { """); Node._disablePeephole = true; StopNode stop = parser.parse(); - assertEquals("return Phi(Loop8,arg,(Phi_arg+1));", stop.toString()); + assertEquals("return Phi(Loop10,arg,(Phi_arg+1));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); Node._disablePeephole = false; } @@ -36,7 +36,7 @@ if(arg){}else{ return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region26,1,Phi(Loop15,1,(Phi_a+1)));", stop.toString()); + assertEquals("return Phi(Region31,1,Phi(Loop18,1,(Phi_a+1)));", stop.toString()); } @Test @@ -56,7 +56,7 @@ while(i < arg) { return sum; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,0,Phi(Loop22,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", stop.toString()); + assertEquals("return Phi(Loop12,0,Phi(Loop26,Phi_sum,(Phi_sum+Phi(Loop,0,(Phi_j+1)))));", stop.toString()); } @Test @@ -73,7 +73,7 @@ return b; """); Node._disablePeephole = true; StopNode stop = parser.parse(); - assertEquals("return Phi(Loop10,2,Phi(Region29,Phi_b,4));", stop.toString()); + assertEquals("return Phi(Loop12,2,Phi(Region34,Phi_b,4));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); Node._disablePeephole = false; } @@ -93,7 +93,7 @@ while(a < 10) { return b; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,2,(Phi(Region29,Phi_b,4)+1));", stop.toString()); + assertEquals("return Phi(Loop12,2,(Phi(Region34,Phi_b,4)+1));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -111,7 +111,7 @@ return a; """); Node._disablePeephole = true; StopNode stop = parser.parse(); - assertEquals("return Phi(Loop9,1,((Phi_a+1)+2));", stop.toString()); + assertEquals("return Phi(Loop11,1,((Phi_a+1)+2));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); Node._disablePeephole = false; } @@ -128,7 +128,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -142,7 +142,7 @@ return a; """); Node._disablePeephole = true; StopNode stop = parser.parse(); - assertEquals("return Phi(Loop9,1,2);", stop.toString()); + assertEquals("return Phi(Loop11,1,2);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); Node._disablePeephole = false; } @@ -156,7 +156,7 @@ while(arg) a = 2; return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,1,2);", stop.toString()); + assertEquals("return Phi(Loop11,1,2);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -173,7 +173,7 @@ return a; """); Node._disablePeephole = true; StopNode stop = parser.parse(); - assertEquals("return Phi(Loop9,1,((Phi_a+1)+2));", stop.toString()); + assertEquals("return Phi(Loop11,1,((Phi_a+1)+2));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); Node._disablePeephole = false; } @@ -190,7 +190,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop11,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -208,7 +208,7 @@ return a; """); Node._disablePeephole = true; StopNode stop = parser.parse(); - assertEquals("return Phi(Loop10,1,((Phi_a+1)+2));", stop.toString()); + assertEquals("return Phi(Loop12,1,((Phi_a+1)+2));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); Node._disablePeephole = false; } @@ -226,7 +226,7 @@ while(a < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,1,(Phi_a+3));", stop.toString()); + assertEquals("return Phi(Loop12,1,(Phi_a+3));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java index 7760ae09..8117b2d6 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter08Test.java @@ -22,8 +22,8 @@ while(arg < 10) { } return arg; """); - StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region37,Phi(Region26,Phi(Loop8,arg,(Phi_arg+1)),Add),Add);", stop.toString()); + StopNode stop = parser.parse().iterate(true); + assertEquals("return Phi(Region45,Phi(Region32,Phi(Loop10,arg,(Phi_arg+1)),Add),Add);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof RegionNode); Assert.assertEquals(5L, Evaluator.evaluate(stop, 1)); Assert.assertEquals(10L, Evaluator.evaluate(stop, 6)); @@ -46,7 +46,7 @@ while(arg < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,1,Phi(Region43,Phi_a,(Phi_a+1)));", stop.toString()); + assertEquals("return Phi(Loop11,1,Phi(Region52,Phi_a,(Phi_a+1)));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -65,7 +65,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region35,Phi(Loop8,arg,(Phi_arg+1)),Add);", stop.toString()); + assertEquals("return Phi(Region43,Phi(Loop10,arg,(Phi_arg+1)),Add);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof RegionNode); } @@ -81,7 +81,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region26,Phi(Loop8,arg,(Phi_arg+1)),Add);", stop.toString()); + assertEquals("return Phi(Region32,Phi(Loop10,arg,(Phi_arg+1)),Add);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof RegionNode); } @@ -100,7 +100,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop8,arg,(Phi_arg+1));", stop.toString()); + assertEquals("return Phi(Loop10,arg,(Phi_arg+1));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -117,7 +117,7 @@ while(arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop8,arg,(Phi_arg+1));", stop.toString()); + assertEquals("return Phi(Loop10,arg,(Phi_arg+1));", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode); } @@ -185,7 +185,7 @@ while(arg < 10) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region29,Phi(Loop9,1,(Phi_a+1)),Add);", stop.toString()); + assertEquals("return Phi(Region35,Phi(Loop11,1,(Phi_a+1)),Add);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof RegionNode); } @@ -201,7 +201,7 @@ while(1) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return (Phi(Loop9,1,Add)+1);", stop.toString()); + assertEquals("return (Phi(Loop11,1,Add)+1);", stop.toString()); assertTrue(stop.ret().ctrl() instanceof CProjNode prj && prj._idx==1 ); } diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java index 64bbf245..b1d9d6e5 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter09Test.java @@ -69,7 +69,7 @@ while (arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,arg,(Phi_arg+2));", stop.toString()); + assertEquals("return Phi(Loop11,arg,(Phi_arg+2));", stop.toString()); Assert.assertEquals(11L, Evaluator.evaluate(stop, 1)); } @@ -86,7 +86,7 @@ while (arg < 10) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop10,arg,(Phi_arg+4));", stop.toString()); + assertEquals("return Phi(Loop12,arg,(Phi_arg+4));", stop.toString()); Assert.assertEquals(13L, Evaluator.evaluate(stop, 1)); } @@ -115,7 +115,7 @@ while (arg) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop16,arg,(Phi_arg+1));", stop.toString()); + assertEquals("return Phi(Loop18,arg,(Phi_arg+1));", stop.toString()); } @Test @@ -185,7 +185,7 @@ while(arg) { return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop11,0,(-(Phi_a+3)));", stop.toString()); + assertEquals("return Phi(Loop13,0,(-(Phi_a+3)));", stop.toString()); } @Test @@ -283,7 +283,7 @@ return v1+v0; public void testFuzz8() { Parser parser = new Parser("while(arg) arg = arg - 1; return arg;"); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop8,arg,(Phi_arg-1));", stop.toString()); + assertEquals("return Phi(Loop10,arg,(Phi_arg-1));", stop.toString()); } @Test diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java index 0b3e4110..10817e04 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter10Test.java @@ -102,8 +102,8 @@ while (arg) { } return bar.a; """); - StopNode stop = parser.parse(false).iterate(); - assertEquals("return Phi(Loop15,0,(Phi_a+2));", stop.toString()); + StopNode stop = parser.parse().iterate(true); + assertEquals("return Phi(Loop16,0,(Phi_a+2));", stop.toString()); } @Test @@ -155,7 +155,7 @@ if( bar ) bar.a = 1; return bar; """); StopNode stop = parser.parse(false).iterate(); - assertEquals("return Phi(Region35,(*void)Phi(Region22,null,Bar),null);", stop.toString()); + assertEquals("return Phi(Region38,(*void)Phi(Region24,null,Bar),null);", stop.toString()); } @Test @@ -171,7 +171,7 @@ else bar.a = 1; return rez; """); StopNode stop = parser.parse(false).iterate(); - assertEquals("return Phi(Region41,4,3);", stop.toString()); + assertEquals("return Phi(Region44,4,3);", stop.toString()); } @Test @@ -244,7 +244,7 @@ while(arg) { return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop15,s0,Phi(Region39,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop16,s0,Phi(Region43,s0,Phi_ret));", stop.toString()); } @Test @@ -262,7 +262,7 @@ while(arg) { return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop19,s0,Phi(Region40,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop20,s0,Phi(Region44,s0,Phi_ret));", stop.toString()); } @@ -279,7 +279,7 @@ while(arg < 10) { return ret; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop15,s0,Phi(Region37,s0,Phi_ret));", stop.toString()); + assertEquals("return Phi(Loop16,s0,Phi(Region41,s0,Phi_ret));", stop.toString()); } @Test diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java index 90198098..a064e8e4 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter11Test.java @@ -324,7 +324,7 @@ while( prime <= arg ) { return primeCount; """); StopNode stop = parser.parse().iterate(); - assertEquals("Stop[ return 0; return Phi(Loop20,1,Phi(Region87,Phi_primeCount,Phi(Region81,(Phi_primeCount+1),Phi_primeCount))); ]", stop.toString()); + assertEquals("Stop[ return 0; return Phi(Loop23,1,Phi(Region100,Phi_primeCount,Phi(Region93,(Phi_primeCount+1),Phi_primeCount))); ]", stop.toString()); assertEquals(0L, Evaluator.evaluate(stop, 1)); // No primes 1 or below assertEquals(1L, Evaluator.evaluate(stop, 2)); // 2 assertEquals(2L, Evaluator.evaluate(stop, 3)); // 2, 3 @@ -369,7 +369,7 @@ if (arg) { return i; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region42,.f,0);", stop.toString()); + assertEquals("return Phi(Region45,.f,0);", stop.toString()); } @Test @@ -437,7 +437,7 @@ while( -arg ) while(1) arg = arg+ptr.v; """); - StopNode stop = parser.parse().iterate(); + StopNode stop = parser.parse().iterate(true); assertEquals("Stop[ return 0; return 0; ]", stop.toString()); } @@ -476,7 +476,7 @@ while(arg) { return arg; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop19,arg,Phi(Region44,.f,0));", stop.toString()); + assertEquals("return Phi(Loop20,arg,Phi(Region48,.f,0));", stop.toString()); } @Test diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java index 2a637ce6..c0f6266a 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter12Test.java @@ -43,7 +43,7 @@ while( 1 ) { return guess; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,(flt)arg,(((ToFloat/Phi_guess)+Phi_guess)/2.0));", stop.toString()); + assertEquals("return Phi(Loop11,(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)); } diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java index 750fe3d3..165d23e5 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter13Test.java @@ -2,7 +2,6 @@ package com.seaofnodes.simple; import com.seaofnodes.simple.evaluator.Evaluator; import com.seaofnodes.simple.node.StopNode; -import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -35,7 +34,7 @@ while( arg ) { return head.next.i; """); try { parser.parse().iterate(); fail(); } - catch( Exception e ) { assertEquals("Might be null accessing 'next'",e.getMessage()); } + catch( Exception e ) { assertEquals("Might be null accessing 'i'",e.getMessage()); } } @Test diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java index 674196ee..ea577c6b 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter14Test.java @@ -59,7 +59,7 @@ while( b ) b = b + 456;// Truncate return b; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Loop9,123,((Phi_b+456)&255));", stop.toString()); + assertEquals("return Phi(Loop11,123,((Phi_b+456)&255));", stop.toString()); } @Test diff --git a/chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java b/chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java index 3a379084..a9b34748 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/Chapter15Test.java @@ -4,9 +4,6 @@ import com.seaofnodes.simple.evaluator.Evaluator; import com.seaofnodes.simple.node.StopNode; import org.junit.Test; import org.junit.Ignore; - -import java.nio.charset.StandardCharsets; - import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; @@ -27,9 +24,7 @@ return 3.14; public void testCyclic() { Parser parser = new Parser( """ -struct C { - C? l; -} +struct C { C? l; }; C c = new C; c.l = c; return c; @@ -54,8 +49,8 @@ output[i] = 1; return output; """); StopNode stop = parser.parse().iterate(); - assertEquals("return u8[];", stop.toString()); - assertEquals("\u0001", Evaluator.evaluate(stop, 0).toString()); + assertEquals("return [u8];", stop.toString()); + assertEquals("Obj<[u8]>{#=1,[]=[1]}", Evaluator.evaluate(stop, 0).toString()); } @Test @@ -101,20 +96,20 @@ return a[0]; public void testBasic4() { Parser parser = new Parser( """ -struct A { int i; } +struct A { int i; }; A?[] a = new A?[2]; return a; """); StopNode stop = parser.parse().iterate(); - assertEquals("return *A?[];", stop.toString()); - assertEquals("Obj<*A?[]>{#=2,[]=[null,null]}", Evaluator.evaluate(stop, 0).toString()); + assertEquals("return [*A?];", stop.toString()); + assertEquals("Obj<[*A?]>{#=2,[]=[null,null]}", Evaluator.evaluate(stop, 0).toString()); } @Test public void testBasic5() { Parser parser = new Parser( """ -struct S { int x; flt y; } +struct S { int x; flt y; }; // A new S S s = new S; s.x=99; s.y = 3.14; @@ -135,7 +130,7 @@ else { return rez; """); StopNode stop = parser.parse().iterate(); - assertEquals("return Phi(Region118,1.2,Phi(Region115,2.3,.y));", stop.toString()); + assertEquals("return Phi(Region117,1.2,Phi(Region114,2.3,.y));", stop.toString()); assertEquals(3.14, Evaluator.evaluate(stop, 0)); } @@ -144,7 +139,7 @@ return rez; public void testBasic6() { Parser parser = new Parser( """ -struct S { int x; flt y; } +struct S { int x; flt y; }; // A new S S s = new S; s.x=99; s.y = 3.14; @@ -170,7 +165,7 @@ return rez; Parser parser = new Parser( """ // Can we define a forward-reference array? -struct Tree { Tree?[] _kids; } +struct Tree { Tree?[]? _kids; }; Tree root = new Tree; root._kids = new Tree?[2]; root._kids[0] = new Tree; @@ -178,17 +173,14 @@ return root; """); StopNode stop = parser.parse().iterate(); assertEquals("return Tree;", stop.toString()); - assertEquals("Obj{_kids=Obj<*Tree?[]>{#=2,[]=[Obj{_kids=null},null]}}", Evaluator.evaluate(stop, 0).toString()); + assertEquals("Obj{_kids=Obj<[*Tree?]>{#=2,[]=[Obj{_kids=null},null]}}", Evaluator.evaluate(stop, 0).toString()); } @Test public void testNestedStructAddMemProj() { Parser parser = new Parser( """ -struct S { - int a; - int[] b; -} +struct S { int a; int[] b; }; return 0; """); StopNode stop = parser.parse(); @@ -258,9 +250,9 @@ while( j < nprimes ) { return rez; """); StopNode stop = parser.parse().iterate(); - assertEquals("return int[];", stop.toString()); + assertEquals("return [int];", stop.toString()); Evaluator.Obj obj = (Evaluator.Obj)Evaluator.evaluate(stop, 20); - assertEquals("int[] {\n # :int;\n [] :int;\n}",obj.struct().toString()); + assertEquals("[int] { # :int; [] :int; }",obj.struct().toString()); long nprimes = (Long)obj.fields()[0]; long[] primes = new long[]{2,3,5,7,11,13,17,19}; for( int i=0; i{x=3,y=4}", Evaluator.evaluate(stop, 0).toString()); } + // Same as the Chapter13 test with the same name, but using the new + // constructor syntax + @Test + public void testLinkedList1() { + Parser parser = new Parser( +""" +struct LLI { LLI? next; int i; }; +LLI? head = null; +while( arg ) { + head = new LLI { next=head; i=arg; }; + arg = arg-1; +} +if( !head ) return 0; +LLI? next = head.next; +if( !next ) return 1; +return next.i; +"""); + StopNode stop = parser.parse().iterate(); + assertEquals("Stop[ return 0; return 1; return .i; ]", stop.toString()); + assertEquals(0L, Evaluator.evaluate(stop, 0)); + assertEquals(1L, Evaluator.evaluate(stop, 1)); + assertEquals(2L, Evaluator.evaluate(stop, 3)); + } + + } diff --git a/chapter16/src/test/java/com/seaofnodes/simple/SchedulerTest.java b/chapter16/src/test/java/com/seaofnodes/simple/SchedulerTest.java index 853999b1..168e0ed7 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/SchedulerTest.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/SchedulerTest.java @@ -41,7 +41,7 @@ return i; Parser parser = new Parser(""" struct S { int f; -} +}; S v0=new S; if(arg) v0.f=1; return v0; @@ -57,7 +57,7 @@ return v0; Parser parser = new Parser(""" struct S { int f; -} +}; S v=new S; v.f = 2; int i=new S.f; diff --git a/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java b/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java index fccec969..28896283 100644 --- a/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java +++ b/chapter16/src/test/java/com/seaofnodes/simple/evaluator/Evaluator.java @@ -192,20 +192,21 @@ public class Evaluator { if( n < 0 ) throw new NegativeArraySizeException(""+n); body = new Object[(int)n+1]; // Array body - var c = type._fields[type._fields.length-1]._type; - if (c instanceof TypeInteger) { - for (int i=0; i alloc(alloc); case CProjNode cproj -> ((Object[])val(cproj.ctrl()))[cproj._idx]; case ProjNode proj -> ((Object[])val( proj.in(0) ))[ proj._idx]; + case ScopeMinNode mem -> null; default -> throw new AssertionError("Unexpected node " + node); }; } @@ -316,8 +318,8 @@ public class Evaluator { public Object evaluate(long parameter, int loops) { if (start == null) return Status.TIMEOUT; var s = new Object[start.compute()._types.length]; - s[1] = parameter; - for(int i=2;i new Block(arr, null, -1, new Block[0]); case IfNode i -> new Block(arr, i, -1, new Block[2]); - case RegionNode r -> new Block(arr, r, Utils.find(r._inputs, prev), new Block[1]); + case RegionNode r -> new Block(arr, r, r._inputs.find(prev), new Block[1]); case ReturnNode r -> new Block(arr, r, -1, new Block[0]); default -> throw new AssertionError("Unexpected block exit node"); }); -- cgit v1.2.3