diff options
Diffstat (limited to 'src/main/java/com/seaofnodes/simple')
209 files changed, 2353 insertions, 1154 deletions
diff --git a/src/main/java/com/seaofnodes/simple/IterPeeps.java b/src/main/java/com/seaofnodes/simple/IterPeeps.java index 66e8a4a8..9ae4231e 100644 --- a/src/main/java/com/seaofnodes/simple/IterPeeps.java +++ b/src/main/java/com/seaofnodes/simple/IterPeeps.java @@ -1,6 +1,7 @@ package com.seaofnodes.simple; import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.util.Ary; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.print.JSViewer; import java.util.Arrays; @@ -81,6 +82,7 @@ public class IterPeeps { // there's a new user), and replace in the graph. if( x != n ) { for( Node z : n. _inputs ) _work.push(z); + for( Node z : x._outputs ) _work.push(z); n.subsume(x); } } diff --git a/src/main/java/com/seaofnodes/simple/Parser.java b/src/main/java/com/seaofnodes/simple/Parser.java index 23e9ddee..1db873e0 100644 --- a/src/main/java/com/seaofnodes/simple/Parser.java +++ b/src/main/java/com/seaofnodes/simple/Parser.java @@ -4,7 +4,9 @@ import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.print.GraphVisualizer; import com.seaofnodes.simple.type.*; - +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.node.ScopeNode.Kind; import java.util.*; /** @@ -82,8 +84,7 @@ public class Parser { FunNode _fun; // Current function being parsed // 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. + // `type.str()` call. public static HashMap<String, Type> TYPES = defaultTypes(); // Mapping from a type name to the constructor for a Type. @@ -152,7 +153,7 @@ public class Parser { _xScopes.push(_scope); // Parse whole program, as-if function header "{ int arg -> body }" - parseFunctionBody(_code._main,loc(),"arg"); + parseFunctionBody( _code._main,loc(),"arg"); // Kill an empty default main. Keep only if it was explicitly defined // (programmer asked for a "main") or it has stuff (i.e. beginner @@ -188,10 +189,16 @@ public class Parser { /** * Parses a function body, assuming the header is parsed. */ - private ReturnNode parseFunctionBody(TypeFunPtr sig, Lexer loc, String... ids) { + private ReturnNode parseFunctionBody( TypeFunPtr sig, Lexer loc, String... ids) { + // If this is a method, record & restore the existing struct fields, + // which are also the struct initializers. The method might update + // mutable fields, so when the function parse is done reset back to + // pre-function-parse values. + Node[] preParse = new Node[_scope.nIns()]; + for( int i=0; i<_scope.nIns(); i++ ) + preParse[i] = _scope.in(i)==null ? null : _scope.in(i).keep(); + // Stack parser state on the local Java stack, and unstack it later - Node oldctrl = ctrl().keep(); - Node oldmem = _scope.mem().keep(); FunNode oldfun = _fun; ScopeNode breakScope = _breakScope; _breakScope = null; ScopeNode continueScope = _continueScope; _continueScope = null; @@ -206,7 +213,7 @@ public class Parser { Node rpc = new ParmNode("$rpc",0,TypeRPC.BOT,fun,con(TypeRPC.BOT)).peephole(); // Build a multi-exit return point for all function returns - RegionNode r = new RegionNode((Lexer)null,null,null).init(); + RegionNode r = new RegionNode( null,null,null).init(); assert r.inProgress(); PhiNode rmem = new PhiNode(ScopeNode.MEM0,TypeMem.BOT,r,null).init(); PhiNode rrez = new PhiNode(ScopeNode.ARG0,Type.BOTTOM,r,null).init(); @@ -215,10 +222,11 @@ public class Parser { assert ret.inProgress(); _code._stop.addDef(ret); + // 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); + _scope.push(new Kind.Func()); ctrl(fun); // Scope control from function // Private mem alias tracking per function MemMergeNode mem = new MemMergeNode(true); @@ -259,9 +267,10 @@ public class Parser { _fun = oldfun; _breakScope = breakScope; _continueScope = continueScope; - // Reset control and memory to pre-function parsing days - ctrl(oldctrl.unkeep()); - _scope.mem(oldmem.unkeep()); + + // Reset all fields to pre-parse days + for( int i=0; i<preParse.length; i++ ) + _scope.setDef(i,preParse[i]==null ? null : preParse[i].unkeep()); return ret; } @@ -275,7 +284,7 @@ public class Parser { * Does not parse the opening or closing '{}' * @return a {@link Node} or {@code null} */ - private Node parseBlock(ScopeNode.Kind kind) { + private Node parseBlock(Kind kind) { // Enter a new scope _scope.push(kind); Node last = ZERO; @@ -308,7 +317,7 @@ public class Parser { // Break ambiguity around leading function types and starting a block else if (peek('{') && !isTypeFun() ) { match("{"); - return require(parseBlock(ScopeNode.Kind.Block),"}"); + return require(parseBlock(new Kind.Block()),"}"); } // Declaration or normal assignment/expression else return parseDeclarationStatement(); @@ -344,8 +353,8 @@ public class Parser { // } // } require("("); - _scope.push(ScopeNode.Kind.Block); // Scope for the index variables - if( !match(";") ) // Can be empty init "for(;test;next) body" + _scope.push(new 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); _scope.pop(); // Exit index variable scope @@ -462,7 +471,7 @@ 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._lexSize.size() > _breakScope._lexSize.size() ) + while( cur.depth() > _breakScope.depth() ) 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 @@ -470,7 +479,7 @@ public class Parser { if( toScope == null ) return cur; // toScope is either the break scope, or a scope that was created here - assert toScope._lexSize.size() <= _breakScope._lexSize.size(); + assert toScope.depth() <= _breakScope.depth(); toScope.ctrl(toScope.mergeScopes(cur,loc()).peephole()); return toScope; } @@ -581,7 +590,7 @@ public class Parser { // Merge results RegionNode r = ctrl(tScope.mergeScopes(fScope,loc())); - Node ret = peep(new PhiNode("",lhs._type.meet(rhs._type),r,lhs.unkeep(),rhs.unkeep())); + Node ret = peep(new PhiNode("",lhs._type.meet(rhs._type).glb(false),r,lhs.unkeep(),rhs.unkeep())); // Immediately fail e.g. `arg ? 7 : ptr` ParseException err; if( !stmt && (err=ret.err()) !=null ) throw err; @@ -621,27 +630,37 @@ public class Parser { private Node parseAsgn() { int old = pos(); String name = _lexer.matchId(); + int old_pre_equals = pos(); // Just a plain expression, no assignment. // Distinguish `var==expr` from `var=expr` if( name==null || KEYWORDS.contains(name) || !matchOpx('=','=') ) { pos(old); return parseExpression(); } - // Parse assignment expression - Node expr = parseAsgn(); - - // Final variable to update + // Find variable to update Var def = _scope.lookup(name); if( def==null ) throw error("Undefined name '" + name + "'"); + // If a method var, allow nested blocks and methods, but not fcns or other structs. + // Else safety check for accessing fields out of function scope. + if( instance(def) ) { + pos(old_pre_equals); // setup for `self.name = expr` + Node self = _scope.in(_scope.lookup("self")); // Insert self reference + return parsePostfixName(self,name); + } + // TOP fields are for late-initialized fields; these have never // been written to, and this must be the final write. Other writes // outside the constructor need to check the final bit. if( _scope.in(def._idx)._type!=Type.TOP && def._final && - // Inside a constructor, final assign is OK, outside nope - !(_scope.inConstructor() && def._idx >= _scope._lexSize.last()) ) + // Inside an allocation, final assign is OK, outside nope. + // The alloc() call added the allocation scope + !(_scope.inAllocation() && def._idx >= _scope._kinds.last(-1)._lexSize) ) throw error("Cannot reassign final '"+name+"'"); + // Parse assignment expression + Node expr = parseAsgn(); + // Lift expression, based on type Node lift = liftExpr(expr.keep(), def.type(), def._final, true); // Update @@ -653,7 +672,7 @@ public class Parser { // Make finals deep; widen ints to floats; narrow wide int types. // Early error if types do not match variable. private Node liftExpr( Node expr, Type t, boolean xfinal, boolean isLoad ) { - if( expr._type instanceof TypeMemPtr tmp && tmp.isFRef() ) + if( expr._type instanceof TypeMemPtr tmp && TYPES.get(tmp._obj._name).isFRef() ) throw error("Must define forward ref "+tmp._obj._name); // Final is deep on ptrs if( xfinal && t instanceof TypeMemPtr tmp ) { @@ -662,7 +681,7 @@ public class Parser { } // Auto-widen array to i64 (cast ptr to raw int bits) if( t == TypeInteger.BOT && expr._type instanceof TypeMemPtr tmp && tmp._obj.isAry() ) - expr = peep(new AddNode(peep(new CastNode(t,ctrl(),expr)),con(tmp._obj.aryBase()))); + expr = peep(new AddNode(peep(new CastNode(t,ctrl(),expr)),off(tmp._obj,"[]"))); // Auto-widen int to float expr = widenInt( expr, t ); // Auto-narrow wide ints to narrow ints. For loads, emit code to force @@ -674,7 +693,7 @@ public class Parser { // Type is sane if( et!=Type.BOTTOM && !et.shallowISA(t) ) - throw error("Type " + et.str() + " is not of declared type " + t.str()); + expr = peep(new CastNode(t,null,expr)); return expr; } @@ -715,6 +734,7 @@ public class Parser { String name = requireId(); // Optional initializing expression follows boolean xfinal = false; + boolean fld_final = false; // Field is final, but not deeply final Node expr; if( match("=") ) { expr = isExternDecl() @@ -722,14 +742,18 @@ public class Parser { : parseAsgn(); // TOP means val and val is always final xfinal = (t==Type.TOP) || + expr instanceof ExternNode || // BOTTOM is var and var is always not-final (t!=Type.BOTTOM && // no Bang AND !hasBang && + // Locals are not-final by default + !_scope.inFunction() && // not-null (expecting null to be set to not-null) expr._type != Type.NIL && // Pointers are final by default; int/flt are not-final by default. (t instanceof TypeNil)); + // var/val, then type comes from expression if( inferType ) { if( expr._type==Type.NIL ) @@ -760,11 +784,15 @@ public class Parser { // the constructor and that's when we'll discover the type. case Type tt -> { assert tt==Type.BOTTOM; yield con(tt); } }; + // Nullable fields are set in the constructor, but remain shallow final. + // e.g. final pointer to a r/w array + if( t instanceof TypeNil tn && !tn.nullable() && !hasBang ) + fld_final = true; } // Lift expression, based on type Node lift = liftExpr(expr, t, xfinal, true); - + // Rebuild the deep RO 't', not returned from liftExpr if( xfinal && t instanceof TypeMemPtr tmp ) t = tmp.makeRO(); @@ -773,7 +801,7 @@ public class Parser { if( !lift._type.isa(t) ) lift = peep(new CastNode(t,null,lift)); // Define a new name - if( !_scope.define(name,t,xfinal,lift, loc) ) + if( !_scope.define(name,t,xfinal || fld_final,lift, loc) ) throw error("Redefining name '" + name + "'", loc); return lift; } @@ -793,30 +821,46 @@ public class Parser { String typeName = requireId(); if( old!=null ) typeName = old+"."+typeName; _nestedType = typeName; + // New declared or forward-ref type + TypeStruct ts = TYPES.get(typeName) instanceof TypeMemPtr tmp ? tmp._obj : TypeStruct.open(typeName); + TYPES.put(typeName,TypeMemPtr.make(ts)); // A Block scope parse, and inspect the scope afterward for fields. - _scope.push(ScopeNode.Kind.Constructor); + _scope.push(new Kind.Define(TypeMemPtr.make(ts))); require("{"); - while (!peek('}') && !_lexer.isEOF()) + int lexlen = _scope._kinds.last()._lexSize, nvar=lexlen; + while (!peek('}') && !_lexer.isEOF()) { parseStatement().isKill(); + while( nvar < _scope._vars._len ) { + Var v = _scope.var(nvar++); + if( !v.isFRef() ) { + ts = ts.add( Field.make( v._name, v.type(), _code.getALIAS(), v._final, v._final && _scope.in( v._idx )._type != Type.TOP ) ); + TYPES.put( typeName, TypeMemPtr.make( ts ) ); + } + } + } - // Grab the declarations and build fields and a Struct - int lexlen = _scope._lexSize.last(); + // Count struct declarations int varlen = _scope._vars._len; - 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 - s.addDef(_scope.in(i)); // Keep the program code to generate instance - fs.push(Field.make(v._name,v.type(),_code.getALIAS(),v._final)); - } + ts = ts.close(); + TYPES.put(typeName,TypeMemPtr.make(ts)); + + // Generate an initializing struct + StructNode s = new StructNode(ts); + for( int i=lexlen; i<varlen; i++ ) + if( !_scope.var(i).isFRef() ) // Promote to outer scope, not defined here + s.addDef(_scope.in(i)); // Keep the program code to generate instance + // Save instance default constructor - TypeStruct ts = s._ts = TypeStruct.make(typeName, fs.asAry()); s.setType(s.compute()); // Do not call peephole, in case the entire struct is a big plain constant - TYPES.put(typeName, TypeMemPtr.make(ts)); INITS.put(typeName,s.keep()); + // Having finalized the struct, upgrade all the 'self' pointers + for( Node n : s._inputs ) + if( n._type instanceof TypeFunPtr tfp && _code.link(tfp) instanceof FunNode fun ) + _code.addAll( fun._outputs ); + + // Done with struct/block scope _nestedType = old; require("}"); @@ -861,7 +905,7 @@ public class Parser { } // 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.open(tname)) :t0; // Null: assume a forward ref type // Nest arrays and '?' as needed Type t2 = t1; while( true ) { @@ -871,10 +915,9 @@ public class Parser { if( tmp.nullable() ) throw error("Type "+t2+" already allows null"); t2 = tmp.makeNullable(); } else if( match("[~]") ) { - TypeMemPtr tmp = typeAry(t2); - t2 = tmp.makeFrom(tmp._obj.makeRO()); + t2 = typeAry(t2,true); } else if( match("[]") ) { - t2 = typeAry(t2); + t2 = typeAry(t2,false); } else break; } @@ -896,17 +939,18 @@ public class Parser { } // Make an array type of t - private TypeMemPtr typeAry( Type t ) { + private TypeMemPtr typeAry( Type t, boolean efinal ) { if( t instanceof TypeMemPtr tmp && tmp.notNull() ) throw error("Arrays of reference types must always be nullable"); - String tname = "["+t.str()+"]"; - Type ta = TYPES.get(tname); - if( ta != null ) return (TypeMemPtr)ta; - TypeStruct ts = TypeStruct.makeAry(tname,TypeInteger.U32,_code.getALIAS(),t,_code.getALIAS()); - assert ts.str().equals(tname); - TypeMemPtr tary = TypeMemPtr.make(ts); - TYPES.put(tname,tary); - return tary; + String tname = "[]"+t.str(); + TypeMemPtr ta = (TypeMemPtr)TYPES.get(tname); + if( ta==null ) + // Remember final version + TYPES.put(tname, ta = TypeMemPtr.make( TypeStruct.makeAry(tname,TypeInteger.U32,_code.getALIAS(),t,_code.getALIAS(),true) )); + Field elem = ta._obj.field("[]"); + if( elem._final == efinal ) + return ta; + return TypeMemPtr.make( ta._obj.replace(elem.makeFrom(efinal))); } // A function type is `{ type... -> type }` or `{ type }`. @@ -916,7 +960,7 @@ public class Parser { Type t0 = type(); // Either return or first arg if( t0==null ) return posT(old); // Not a function if( match("}") ) // No-arg function { -> type } - return TypeFunPtr.make(match("?"),TypeTuple.BOT,t0); + return TypeFunPtr.make(match("?"),false,TypeFunPtr.TEMPTY,t0); Ary<Type> ts = new Ary<>(Type.class); ts.push(t0); // First argument while( true ) { @@ -924,7 +968,7 @@ public class Parser { Type ret = type(); if( ret==null || !match("}") ) return posT(old); // Not a function - return TypeFunPtr.make(match("?"),TypeTuple.make(ts.asAry()),ret); + return TypeFunPtr.make(match("?"),false,ts.asAry(),ret); } Type t1 = type(); if( t1==null ) return posT(old); // Not a function @@ -1103,14 +1147,17 @@ public class Parser { } if (match("-")) return peep(new MinusNode(parseUnary()).widen()); if (match("!")) return peep(new NotNode(parseUnary())); - return parsePostfix(parsePrimary()); + // Else be a primary expression + return parsePrimary(); } /** * Parse a primary expression: * * <pre> - * primaryExpr : integerLiteral | true | false | null | new Type | '(' expression ')' | Id['++','--'] + * primaryExpr : integerLiteral | "string" | 'char' | true | false | null | + * new Type | '(' expression ')' | Id['++','--'] | + * [static.]* Id * </pre> * @return a primary {@link Node}, never {@code null} */ @@ -1121,43 +1168,96 @@ public class Parser { if( matchx("false") ) return ZERO; if( matchx("null" ) ) return NIL; if( match ("'" ) ) return parseChar(); - if( match ("(" ) ) return require(parseAsgn(), ")"); - if( matchx("new" ) ) return alloc(); - if( match ("{" ) ) return require(func(),"}"); + if( match ("(" ) ) return parsePostfix(require(parseAsgn(), ")")); + if( matchx("new" ) ) return parsePostfix(alloc()); + if( match ("{" ) ) return parsePostfix(require(func(),"}")); // Parse static variable lookup: `type.fld` in the type namespace + // CNC: not a full type parse, just a typename parse + int pos = pos(); Type t = type(); - if( t!=null && match(".") ) { - String fld = requireId(); - TypeMemPtr tmp = ((TypeMemPtr)t); - String tname = tmp._obj._name; - StructNode init = INITS.get(tname); - int idx = tmp._obj.find(fld); - if( idx == -1 ) - throw error("Accessing unknown STATIC field"); - return init.in(idx); + if( t!=null ) { + if( peek('.') ) + return parsePostfix(con(t)); + //pos(pos); // TODO: not a `type.fld` + //return null; + throw Utils.TODO(); } // Expect an identifier now - Var n = requireLookupId(); - Node rvalue = _scope.in(n); + + // - if null, make fref, normal var handling + // - if final constant, normal var handling + // - if method var, scan skipping blocks & methods, must hit correct struct no fcns + // - if normal var, scan skipping blocks, allowing last fcn + // - NO fcns nested in methods, NO methods nested in fcns + + String id = _lexer.matchId(); + if( id == null || KEYWORDS.contains(id) ) + throw errorSyntax("an identifier or expression"); + Var var = _scope.lookup(id); + + if( var==null ) { + // If missing, assume a forward reference + _scope.define(id, FRefNode.FREF_TYPE, true, XCTRL, loc()); + var = _scope.lookup(id); + } + + // If a method var, allow nested blocks and methods, but not fcns or other structs. + // Else safety check for accessing fields out of function scope. + if( instance(var) ) { + Node self = _scope.in(_scope.lookup("self")); // Insert self reference + return parsePostfixName(self,id); + } + + // Load local value + Node rvalue = _scope.in(var); if( rvalue._type == Type.BOTTOM ) - if( rvalue instanceof FRefNode ) return rvalue; - else throw error("Cannot read uninitialized field '"+n._name+"'"); + if( rvalue instanceof FRefNode ) + return parsePostfix(rvalue); + else throw error("Cannot read uninitialized field '"+id+"'"); + // Check for assign-update, x += e0; char ch = _lexer.matchOperAssign(); - if( ch==0 ) return rvalue; - Node op = opAssign(ch,rvalue,n._final,n.type(),n._name); - _scope.update(n,op); + if( ch==0 ) // Normal primary, check for postfix updates + return parsePostfix(rvalue); + // Assign-update direct into Scope + Node op = opAssign(ch,rvalue, var.type() ); + _scope.update(var,op); return postfix(ch) ? rvalue.unkeep() : op; } + // true if instance variable lookup (var is in any number of nested blocks, + // then an instance function then inside a struct declaration). + private boolean instance(Var var ) { + // If a method var, allow nested blocks and methods, but not fcns or other structs + Kind kind = _scope.kind(var); + if( kind instanceof Kind.Define ) { + for( int i = _scope.depth()-1; i>=0 && var._idx < _scope._kinds.at(i)._lexSize; i-- ) { + Kind xkind = _scope._kinds.at(i); + if( xkind instanceof Kind.Block ) continue; + if( xkind instanceof Kind.Func ) { + if( _scope._kinds.at(i-1)==kind ) + return true; // Instance variable: lookup in a method in a decl + } + throw Utils.TODO(); + } + } else { + // If a normal var, allow any nested blocks, and a last fcn - + // but not functions further out (which involves capture). + Node def = _scope.in(var._idx); + for( int i = _scope.depth()-1; i>=0 && var._idx < _scope._kinds.at(i)._lexSize; i-- ) + if( _scope._kinds.at(i) instanceof Kind.Func && + !(def instanceof FRefNode) && !(var._final && def._type.isConstant()) ) + throw error("Variable '"+var._name+"' is out of function scope and must be a final constant"); + } + return false; + } + // Check for assign-update, "x += e0". // Returns "x + e0"; the caller assigns value. // if ch is postfix, then lhs is kept and caller will unkeep and return it. - private Node opAssign(char ch, Node lhs, boolean xfinal, Type t, String name ) { - if( xfinal ) - throw error("Cannot reassign final '"+name+"'"); + private Node opAssign( char ch, Node lhs, Type t ) { // RHS of the update. lhs.keep(); // Alive across parseAsgn Node rhs = @@ -1184,30 +1284,6 @@ public class Parser { } - // Expect an ID here. If not found, assume a forward reference function - Var requireLookupId() { - // Try in the normal variable namespace - String id = _lexer.matchId(); - if( id == null || KEYWORDS.contains(id) ) - throw errorSyntax("an identifier or expression"); - Var n = _scope.lookup(id); - // If missing, assume a forward reference - if( n==null ) { - _scope.define(id, FRefNode.FREF_TYPE, true, XCTRL, loc()); - n = _scope.lookup(id); - } else { - // Lookup worked on an out-of-function value. - if( _scope.outOfFunction(n) ) { - // No closures, so this has to be a final constant (which - // includes forward refs) - Node def = _scope.in(n._idx); - if( !(def instanceof FRefNode) && !(n._final && def._type.isConstant()) ) - throw error("Variable '"+n._name+"' is out of function scope and must be a final constant"); - } - } - return n; - } - /** Parse an allocation */ @@ -1222,7 +1298,7 @@ public class Parser { if( !(len._type instanceof TypeInteger) ) throw error("Cannot allocate an array with length "+len._type); require("]"); - TypeMemPtr tmp = typeAry(t); + TypeMemPtr tmp = typeAry(t,false); return newArray(tmp._obj,len); } @@ -1241,19 +1317,23 @@ public class Parser { if( hasConstructor ) { idx = _scope.nIns(); // Push a scope, and pre-assign all struct fields. - _scope.push(ScopeNode.Kind.Block); + _scope.push(new 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); + // An initial TOP means the field needs to be initialized. We + // store a BOT initially; any partial init will fall to BOT + // (merge BOT and the partial) and be obviously only a partial + // init. To be initialized the field needs a full clobber. + _scope.define(fs[i]._fname, fs[i]._t, fs[i]._final, s.in(i)._type==Type.TOP ? con(Type.BOTTOM) : s.in(i), loc); // Parse the constructor body - require(parseBlock(ScopeNode.Kind.Constructor),"}"); + require(parseBlock(new Kind.Alloc(tmp)),"}"); init = _scope._inputs; } // Check that all fields are initialized for( int i=idx; i<init.size(); i++ ) if( init.at(i)._type == Type.TOP || init.at(i)._type == Type.BOTTOM ) throw error("'"+tmp._obj._name+"' is not fully initialized, field '" + fs[i-idx]._fname + "' needs to be set in a constructor"); - Node ptr = newStruct(tmp._obj, con(tmp._obj.offset(fs.length)), idx, init ); + Node ptr = newStruct(tmp._obj, off(tmp._obj, " len"), idx, init ); if( hasConstructor ) _scope.pop(); return ptr; @@ -1276,18 +1356,20 @@ public class Parser { ns[1] = size; // Memory aliases for every field for( int i = 0; i < len; i++ ) - ns[2+i] = memAlias(fs[i]._alias); + if( !fs[i]._one ) + ns[2+i] = memAlias(fs[i]._alias); Node nnn = new NewNode(TypeMemPtr.make(obj), ns).peephole().keep(); for( int i = 0; i < len; i++ ) - memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole()); + if( !fs[i]._one ) + memAlias(fs[i]._alias, new ProjNode(nnn,i+2,memName(fs[i]._alias)).peephole()); Node ptr = new ProjNode(nnn.unkeep(),1,obj._name).peephole().keep(); // Initial nonzero values for every field for( int i = 0; i < len; i++ ) { Node val = init.get( i + idx ); - if( val._type != val._type.makeZero() ) { + if( !fs[i]._one && val._type != val._type.makeZero() ) { Node mem = memAlias(fs[i]._alias); - Node st = new StoreNode(loc(),fs[i]._fname,fs[i]._alias,fs[i]._type,mem,ptr,con(obj.offset(i)),val,true).peephole(); + Node st = new StoreNode(loc(),fs[i]._fname,fs[i]._alias,fs[i]._t,mem,ptr,off(obj,fs[i]._fname),val,true).peephole(); memAlias(fs[i]._alias,st); } } @@ -1297,14 +1379,14 @@ public class Parser { private static final Ary<Node> ALTMP = new Ary<>(Node.class); private Node newArray(TypeStruct ary, Node len) { - int base = ary.aryBase (); + ConFldOffNode base = off(ary, "[]"); int scale= ary.aryScale(); - Node size = peep(new AddNode(con(base),peep(new ShlNode(null,len.keep(),con(scale))))); - ALTMP.clear(); ALTMP.add(len.unkeep()); ALTMP.add(con(ary._fields[1]._type.makeZero())); + Node size = peep(new AddNode(base,peep(new ShlNode(null,len.keep(),con(scale))))); + ALTMP.clear(); ALTMP.add(len.unkeep()); ALTMP.add(con(ary._fields[1]._t.makeZero())); return newStruct(ary,size,0,ALTMP); } private Node newString(String s) { - TypeMemPtr tmp = typeAry(TypeInteger.U8); + TypeMemPtr tmp = typeAry(TypeInteger.U8,true); int lenAlias = tmp._obj.field("#" )._alias; int elemAlias = tmp._obj.field("[]")._alias; TypeConAryB con = TypeConAryB.make(s); @@ -1312,7 +1394,8 @@ public class Parser { // Make a TMP, not-null (byte)2, singleton (true) (requires text // strings are hash-interned), with a TypeStruct having a constant // array body. - TypeMemPtr str = TypeMemPtr.make((byte)2,TypeStruct.makeAry("[u8]", TypeInteger.U32, lenAlias, elem, elemAlias, true, con),true); + TypeMemPtr str = TypeMemPtr.make((byte)2,TypeStruct.makeAry("[]u8", TypeInteger.constant(s.length()), lenAlias, con, elemAlias, true),true); + assert str.isConstant(); return con(str); } @@ -1341,9 +1424,24 @@ public class Parser { if( match(".") ) name = requireId(); else if( match("#") ) name = "#"; else if( match("[") ) name = "[]"; - else if( match("(") ) return parsePostfix(require(functionCall(expr),")")); + else if( match("(") ) return parsePostfix(require(functionCall(expr,null),")")); else return expr; // No postfix + return parsePostfixName(expr,name); + } + + /** + * Parse postfix expression; this can be a field expression, an array + * lookup or a postfix operator like '#' + * + * <pre> + * expr ['++' | '--' ] // Postfix unary write operator + * expr [ [op]= expr ] // Field reference + * expr ('[' expr ']')* [ [op]= expr ] // Array reference + * </pre> + */ + private Node parsePostfixName(Node expr, String name) { + if( expr._type==Type.NIL ) throw error("Accessing unknown field '" + name + "' from 'null'"); @@ -1352,23 +1450,25 @@ public class Parser { throw error( "Expected "+(name=="#" || name=="[]" ? "array" : "reference")+" but found " + expr._type.str() ); // Find the field from the Type. Lookup in the base object field names. + TypeMemPtr ptr2 = (TypeMemPtr)TYPES.get(ptr._obj._name); + ptr = (TypeMemPtr)ptr.join(ptr2);// Upgrade to latest TYPES TypeStruct base = ptr._obj; - assert !base.isFRef(); int fidx = base.find(name); - if( fidx == -1 ) throw error("Accessing unknown field '" + name + "' from '" + ptr.str() + "'"); + 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; + Type tf = f._t; if( tf instanceof TypeMemPtr ftmp && ftmp.isFRef() ) 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 // Array index math - ? peep(new AddNode(con(base.aryBase()),peep(new ShlNode(null,require(parseAsgn(),"]"),con(base.aryScale()))))) + ? peep(new AddNode(off(base,"[]"),peep(new ShlNode(null,require(parseAsgn(),"]"),con(base.aryScale()))))) // Struct field offsets are hardwired - : con(base.offset(fidx))).keep(); + : off(base,name)).keep(); // Disambiguate "obj.fld==x" boolean test from "obj.fld=x" field assignment if( matchOpx('=','=') ) { @@ -1384,7 +1484,12 @@ public class Parser { return val.unkeep(); // "obj.a = expr" returns the expression while updating memory } - Node load = new LoadNode(loc(),name, f._alias, tf, memAlias(f._alias), expr.keep(), off); + // Keep expr for possible store update + expr.keep(); + // Load field + Node load = f._one && INITS.containsKey( base._name ) + ? INITS.get(base._name).in(base.find(name)) + : new LoadNode(loc(),name, f._alias, tf, memAlias(f._alias), expr, off); // Arrays include control, as a proxy for a safety range check // Structs don't need this; they only need a NPE check which is // done via the type system. @@ -1394,8 +1499,8 @@ public class Parser { // Check for assign-update, "ptr.fld += expr" or "ary[idx]++" char ch = _lexer.matchOperAssign(); if( ch!=0 ) { - Node op = opAssign(ch,load,f._final,tf,name); - Node st = new StoreNode(loc(), name, f._alias, tf, memAlias(f._alias), expr.unkeep(), off, op, false); + Node op = opAssign(ch,load, tf ); + Node st = new StoreNode(loc(), name, f._alias, tf, memAlias(f._alias), expr.unkeep(), off.unkeep(), op, false); // Arrays include control, as a proxy for a safety range check. // Structs don't need this; they only need a NPE check which is // done via the type system. @@ -1403,8 +1508,25 @@ public class Parser { memAlias(f._alias, peep(st)); load = postfix(ch) ? load.unkeep() : op; // And use the original loaded value as the result - } else expr.unkill(); - off.unkill(); + return load; + //throw Utils.TODO(); // NO POSTFIX AFTER STORE, JUST RETURN + } else { + off.unkill(); + // Method call: Loaded a function from a named field, AND the base + // field type is final. + if( load._type instanceof TypeFunPtr && name!="[]" && + !(load instanceof ExternNode) && + ((TypeMemPtr)TYPES.get(base._name))._obj.field(name)._final && + // And calling a function + match("(") ) { + return parsePostfix(require(functionCall(load,expr),")")); + } + + // Drop expr, keeping load alive + load.keep(); + expr.unkill(); + load.unkeep(); + } return parsePostfix(load); } @@ -1440,6 +1562,17 @@ public class Parser { private Node func() { Ary<Type> ts = new Ary<>(Type.class); Ary<String> ids = new Ary<>(String.class); + + // Defined in constructor? Add `self` argument. "static" calls still + // add a `self` they just ignore it. + if( _scope._kinds.last() instanceof Kind.Define define ) { + // Upgrade defined struct to latest fields + TypeMemPtr tmp = (TypeMemPtr)TYPES.get(define._tmp._obj._name); + ts .push(tmp); + ids.push("self"); + } + + // Parse other arguments _lexer.skipWhiteSpace(); Lexer loc = loc(); // First argument location while( true ) { @@ -1452,7 +1585,7 @@ public class Parser { } require("->"); // Make a concrete function type, with a fidx - TypeFunPtr tfp = _code.makeFun(TypeTuple.make(ts.asAry()),Type.BOTTOM); + TypeFunPtr tfp = _code.makeFun(TypeFunPtr.make(false,false,ts.asAry(),Type.BOTTOM)); ReturnNode ret = parseFunctionBody(tfp,loc,ids.asAry()); return con(ret._fun.sig()); } @@ -1463,16 +1596,18 @@ public class Parser { * ( arg* ) * </pre> */ - private Node functionCall(Node expr) { - if( expr._type == Type.NIL ) + private Node functionCall(Node fcn, Node self) { + if( fcn._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(false).str()); - expr.keep(); // Keep while parsing args + if( !(fcn instanceof FRefNode) && !fcn._type.isa(TypeFunPtr.BOT) ) + throw error("Expected a function but got "+fcn._type.glb(false).str()); + fcn.keep(); // Keep while parsing args Ary<Node> args = new Ary<>( Node.class ); args.push(null); // Space for ctrl,mem args.push(null); + if( self != null ) // Method call has a self + args.push(self); while( !peek(')') ) { Node arg = parseAsgn(); if( arg==null ) break; @@ -1482,7 +1617,7 @@ public class Parser { // Control & memory after parsing args args.set(0,ctrl().keep()); args.set(1,_scope.mem().merge().keep()); - args.push(expr); // Function pointer + args.push(fcn); // Function pointer // Unkeep them all for( Node arg : args ) arg.unkeep(); @@ -1521,8 +1656,8 @@ public class Parser { } // External linked constant private Node externDecl( String ex, Type t ) { - if( t instanceof TypeFunPtr tfp ) // Generic TFP from type parse - t = _code.makeFun(tfp._sig,tfp._ret); // Get a FIDX, becomes a constant + if( t instanceof TypeFunPtr tfp ) // Generic TFP from type parse + t = _code.makeFun(tfp); // Get a FIDX, becomes a constant return new ExternNode(t,ex).peephole(); } @@ -1537,6 +1672,7 @@ public class Parser { private ConstantNode parseLiteral() { return con(_lexer.parseNumber()); } public static Node con( long con ) { return con==0 ? ZERO : con(TypeInteger.constant(con)); } public static ConstantNode con( Type t ) { return (ConstantNode)new ConstantNode(t).peephole(); } + public static ConFldOffNode off( TypeStruct base, String fname ) { return (ConFldOffNode)(new ConFldOffNode(base._name,fname).peephole()); } public Node peep( Node n ) { // Peephole, then improve with lexically scoped guards return _scope.upcastGuard(n.peephole()); @@ -1740,6 +1876,7 @@ public class Parser { _position -= syntax.length(); return false; } + // Match these two characters in a row boolean matchOpx(char c0, char c1) { skipWhiteSpace(); if( _position+1 >= _input.length || _input[_position]!=c0 || _input[_position+1]==c1 ) @@ -1861,4 +1998,5 @@ public class Parser { //String msg = "src:"+_line_number+":"+(_position-_line_start)+" "+errorMessage; ParseException( String msg, Lexer loc ) { super(msg); _loc = loc; } } + } diff --git a/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java b/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java index e2fac779..689ceceb 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java +++ b/src/main/java/com/seaofnodes/simple/codegen/Coalesce.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; import java.util.IdentityHashMap; diff --git a/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java index adb71413..caa7ff44 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java +++ b/src/main/java/com/seaofnodes/simple/codegen/CodeGen.java @@ -1,13 +1,14 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.*; +import com.seaofnodes.simple.IterPeeps; +import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.print.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; import java.io.IOException; -import java.util.BitSet; -import java.util.HashMap; -import java.util.IdentityHashMap; +import java.util.*; @SuppressWarnings("unchecked") public class CodeGen { @@ -37,9 +38,11 @@ public class CodeGen { public final TypeInteger _arg; // --------------------------- - public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L ); } - public CodeGen( String src, TypeInteger arg, long workListSeed ) { + public CodeGen( String src ) { this(src, TypeInteger.BOT, 123L, true ); } + public CodeGen( String src, TypeInteger arg, long workListSeed, boolean reset ) { CODE = this; + if( reset ) Type.reset(); + _main = makeFun(TypeFunPtr.MAIN); _phase = null; _callingConv = null; _start = new StartNode(arg); @@ -119,18 +122,15 @@ public class CodeGen { // are structurally equal. public final HashMap<Node,Node> _gvn = new HashMap<>(); - // Compute "function indices": FIDX. - // Each new request at the same signature gets a new FIDX. - private final HashMap<TypeTuple,Integer> FIDXS = new HashMap<>(); - public TypeFunPtr makeFun( TypeTuple sig, Type ret ) { - Integer i = FIDXS.get(sig); - int fidx = i==null ? 0 : i; - FIDXS.put(sig,fidx+1); // Track count per sig + // + private int _fidx =0; + public TypeFunPtr makeFun( TypeFunPtr fun ) { + int fidx = _fidx++; assert fidx<64; // TODO: need a larger FIDX space - return TypeFunPtr.make((byte)2,sig,ret, 1L<<fidx ); + return fun.makeFrom(fidx); } // Signature for MAIN - public final TypeFunPtr _main = makeFun(TypeTuple.MAIN,Type.BOTTOM); + public final TypeFunPtr _main; // Reverse from a constant function pointer to the IR function being called public FunNode link( TypeFunPtr tfp ) { assert tfp.isConstant(); @@ -186,24 +186,44 @@ public class CodeGen { // Pessimistic peephole optimization on a worklist _iter.iterate(this); + // OPTIMISTIC PASS GOES HERE + // Not really a true optimistic pass, but look for unlinked functions. // This can be removed, which may trigger another round of pessimistic. // This is the point where we flip from a virtual Call Graph (any call // can call any function) to having a correct (but conservative) CG. + int progress = 0; + while( progress != _start.nOuts() ) { + progress = _start.nOuts(); + FunNode main = link(_main); + for( int i=0; i<_start.nOuts(); i++ ) { + Node use = _start.out(i); + if( use instanceof FunNode fun && + fun.nIns()==2 && fun.in(1)==_start && fun != main && + (fun._name==null || fun._name.startsWith("sys.")) ) { + add(fun).setDef(1,Parser.XCTRL); + addAll(fun._outputs); + i--; + } + } + _iter.iterate(this); + } - FunNode main = link(_main); + // Freeze field sizes; do struct layouts; convert field offsets into + // constants. for( int i=0; i<_start.nOuts(); i++ ) { Node use = _start.out(i); - if( use instanceof FunNode fun && - fun.nIns()==2 && fun.in(1)==_start && fun != main && - (fun._name==null || fun._name.startsWith("sys.")) ) { - add(fun).setDef(1,Parser.XCTRL); - addAll(fun._outputs); + if( use instanceof ConFldOffNode off ) { + TypeMemPtr tmp = (TypeMemPtr) Parser.TYPES.get(off._name); + off.subsume( off.asOffset(tmp._obj) ); i--; } } _iter.iterate(this); + // To help with testing, sort StopNode returns by NID + Arrays.sort(_stop._inputs._es,0,_stop.nIns(),(x,y) -> x._nid - y._nid ); + _tOpto = (int)(System.currentTimeMillis() - t0); // TODO: @@ -212,7 +232,7 @@ public class CodeGen { // loop unroll, peel, RCE, etc return this; } - public <N extends Node> N add( N n ) { return (N)_iter.add(n); } + public <N extends Node> N add( N n ) { return _iter.add(n); } public void addAll( Ary<Node> ary ) { _iter.addAll(ary); } diff --git a/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java b/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java index 0eaaae7b..8f9e2981 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java +++ b/src/main/java/com/seaofnodes/simple/codegen/ElfFile.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.codegen; import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.Encoding.BAOS; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; -import com.seaofnodes.simple.codegen.Encoding.BAOS; +import com.seaofnodes.simple.util.Ary; import java.io.*; import java.nio.ByteBuffer; import java.nio.ByteOrder; diff --git a/src/main/java/com/seaofnodes/simple/codegen/Encoding.java b/src/main/java/com/seaofnodes/simple/codegen/Encoding.java index db799b98..1065cd9f 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/Encoding.java +++ b/src/main/java/com/seaofnodes/simple/codegen/Encoding.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.print.IRPrinter; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.io.ByteArrayOutputStream; import java.util.*; @@ -45,6 +45,9 @@ public class Encoding { public int [] _opStart; // Start of opcodes, by _nid public byte[] _opLen; // Length of opcodes, by _nid + // Function headers now padded when printing + public boolean _padFunHeads; + // Big Constant relocation info. public static class Relo { public final Node _op; @@ -290,6 +293,9 @@ public class Encoding { // Fall/false into a full block, Jump/true to an empty block. if( f.nOuts()>1 && t.nOuts()==1 ) return false; if( t.nOuts()>1 && f.nOuts()==1 ) return true ; + // Jump to a merge point, assuming other things are jumping there as well + if( f.out(0) instanceof RegionNode ) return true ; + if( t.out(0) instanceof RegionNode ) return false; // Everything else equal, use pre-order return t._pre > f._pre; } @@ -397,7 +403,7 @@ public class Encoding { if( n instanceof MachNode && !(n instanceof CFGNode) ) _opStart[n._nid] += slide; } - + _padFunHeads = true; // Copy/slide the bits to make space for all the longer branches int grow = _opStart[_code._cfg.at(len-1)._nid] - oldStarts[len-1]; @@ -414,6 +420,7 @@ public class Encoding { } _bits.set(bits,bits.length); } + } @@ -492,12 +499,11 @@ public class Encoding { while( off < foff ) { bits.write(0); off++; }; // Constant array fields are special if( f._fname=="[]" ) { // Must be a constant array - ts._con.write(bits); // Write the constant array bits - off += ts._con.len(); + ((TypeConAry)f._t).write(bits); + off += ((TypeConAry)f._t).len(); } else { - int log = f._type.log_size(); - if( f._fname=="#" ) addN(log,ts._con.len(),bits); // Must be a constant array - else addN(log,f._type ,bits); + int log = f._t.log_size(); + addN(log,f._t,bits); off += 1<<log; } } diff --git a/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java b/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java index 04a119c2..520a18a3 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java +++ b/src/main/java/com/seaofnodes/simple/codegen/GlobalCodeMotion.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Ary; import com.seaofnodes.simple.IterPeeps.WorkList; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; import java.util.*; public abstract class GlobalCodeMotion { diff --git a/src/main/java/com/seaofnodes/simple/codegen/IFG.java b/src/main/java/com/seaofnodes/simple/codegen/IFG.java index fdd4e2f9..6dd6fbf1 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/IFG.java +++ b/src/main/java/com/seaofnodes/simple/codegen/IFG.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; import java.util.IdentityHashMap; diff --git a/src/main/java/com/seaofnodes/simple/codegen/LRG.java b/src/main/java/com/seaofnodes/simple/codegen/LRG.java index ec254a2e..009ddcdb 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/LRG.java +++ b/src/main/java/com/seaofnodes/simple/codegen/LRG.java @@ -1,10 +1,9 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.*; - +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.IdentityHashMap; /** A Live Range diff --git a/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java b/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java index e1e849e6..2415203d 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java +++ b/src/main/java/com/seaofnodes/simple/codegen/LinkMem.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; // In-memory linking public class LinkMem { diff --git a/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java b/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java index de4fadc4..ddf5a679 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java +++ b/src/main/java/com/seaofnodes/simple/codegen/ListScheduler.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Ary; import com.seaofnodes.simple.IterPeeps.WorkList; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; import java.util.*; public abstract class ListScheduler { diff --git a/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java b/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java index 57d0d90c..da521082 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java +++ b/src/main/java/com/seaofnodes/simple/codegen/RegAlloc.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; import com.seaofnodes.simple.node.*; import java.util.Arrays; import java.util.BitSet; @@ -398,8 +398,8 @@ public class RegAlloc { // If the minLoopDepth is less than the maxLoopDepth: for-all defs and // uses, if at minLoopDepth or lower, split after def and before use. for( Node n : _ns ) { - if( n instanceof SplitNode ) continue; // Ignoring splits; since spilling need to split in a deeper loop - if( n.isDead() ) continue; // Some Clonable went dead by other spill changes + if( n instanceof SplitNode && min!=max ) continue; // Ignoring splits; since spilling need to split in a deeper loop + if( n.isDead() ) continue; // Some Cloneable went dead by other spill changes // If this is a 2-address commutable op (e.g. AddX86, MulX86) and the rhs has only a single user, // commute the inputs... which chops the LHS live ranges' upper bound to just the RHS. if( n instanceof MachNode mach && lrg(n)==lrg && mach.twoAddress()==1 && mach.commutes() && n.in(2).nOuts()==1 ) diff --git a/src/main/java/com/seaofnodes/simple/codegen/RegMask.java b/src/main/java/com/seaofnodes/simple/codegen/RegMask.java index ec0c4e30..c7dda1da 100644 --- a/src/main/java/com/seaofnodes/simple/codegen/RegMask.java +++ b/src/main/java/com/seaofnodes/simple/codegen/RegMask.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.codegen; -import com.seaofnodes.simple.Utils; -import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; /** RegMask * A "register mask" - 1 bit set for each allowed register. In addition, diff --git a/src/main/java/com/seaofnodes/simple/node/AddNode.java b/src/main/java/com/seaofnodes/simple/node/AddNode.java index 0f472829..f1615f70 100644 --- a/src/main/java/com/seaofnodes/simple/node/AddNode.java +++ b/src/main/java/com/seaofnodes/simple/node/AddNode.java @@ -1,10 +1,7 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.type.*; -import java.util.BitSet; - import static com.seaofnodes.simple.Parser.con; public class AddNode extends ArithNode { @@ -129,7 +126,7 @@ public class AddNode extends ArithNode { for( int i=1; i<ns.length; i++ ) ns[i] = op.copy(lphi.in(i), rhs instanceof PhiNode ? rhs.in(i) : rhs).peephole(); String label = lphi._label + (rhs instanceof PhiNode rphi ? rphi._label : ""); - Node phi = new PhiNode(label,lphi._declaredType,ns).peephole(); + Node phi = new PhiNode(label,lphi._minType,ns).peephole(); // Rotate needs another op, otherwise just the phi return lhs==lphi ? phi : op.copy(lhs.in(1),phi); } @@ -151,8 +148,8 @@ public class AddNode extends ArithNode { // Ties with in a category sort by node ID. // TRUE if swapping hi and lo. static boolean spine_cmp( Node hi, Node lo, Node dep ) { - if( lo._type.isConstant() ) return false; - if( hi._type.isConstant() ) return true ; + if( lo._type.isConstant() || lo instanceof ConFldOffNode ) return false; + if( hi._type.isConstant() || hi instanceof ConFldOffNode ) return true ; if( lo instanceof PhiNode lphi && lphi.region()._type==Type.XCONTROL ) return false; if( hi instanceof PhiNode hphi && hphi.region()._type==Type.XCONTROL ) return false; diff --git a/src/main/java/com/seaofnodes/simple/node/ArithNode.java b/src/main/java/com/seaofnodes/simple/node/ArithNode.java index 3e376418..96067c8e 100644 --- a/src/main/java/com/seaofnodes/simple/node/ArithNode.java +++ b/src/main/java/com/seaofnodes/simple/node/ArithNode.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; + import java.util.BitSet; public abstract class ArithNode extends Node { @@ -56,7 +56,10 @@ public abstract class ArithNode extends Node { if( in(1) instanceof PhiNode lhs && in(2) instanceof PhiNode rhs && lhs.nIns() >= 2 && !lhs.inProgress() && - lhs.region()==rhs.region() ) { + lhs.region()==rhs.region() && + lhs.nIns()>2 && // A 1-input Phi will collapse already + // Disallow with self-looping phi; these will collapse + (lhs.in(2)!=lhs && rhs.in(2)!=rhs) ) { // Profit check: only 1 instance of `this` will remain, all the // others will fold to constants. int cnt=0; @@ -73,7 +76,7 @@ public abstract class ArithNode extends Node { : copy(lhs.in(i), rhs.in(i)).peephole(); } String label = lhs._label==rhs._label ? lhs._label : lhs._label + rhs._label; - return new PhiNode(label,lhs._declaredType,ns).peephole(); + return new PhiNode(label,lhs._minType,ns).peephole(); } } return null; diff --git a/src/main/java/com/seaofnodes/simple/node/BoolNode.java b/src/main/java/com/seaofnodes/simple/node/BoolNode.java index 301e1517..2765c308 100644 --- a/src/main/java/com/seaofnodes/simple/node/BoolNode.java +++ b/src/main/java/com/seaofnodes/simple/node/BoolNode.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; import static com.seaofnodes.simple.type.TypeInteger.*; @@ -33,7 +33,7 @@ abstract public class BoolNode extends Node { Type t2 = in(2)._type; // Exactly equals? if( t1.isHigh() || t2.isHigh() ) - return BOOL.dual(); + return (TypeInteger)BOOL.dual(); if( in(1)==in(2) ) // LT fails, both EQ and LE succeed return this instanceof LT ? FALSE : TRUE; diff --git a/src/main/java/com/seaofnodes/simple/node/CFGNode.java b/src/main/java/com/seaofnodes/simple/node/CFGNode.java index 1dddc171..b9c70e5f 100644 --- a/src/main/java/com/seaofnodes/simple/node/CFGNode.java +++ b/src/main/java/com/seaofnodes/simple/node/CFGNode.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.Ary; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; import java.util.HashMap; import java.util.HashSet; @@ -59,7 +59,7 @@ public abstract class CFGNode extends Node { // Used by the encoding / final BB layout public CFGNode uctrlSkipEmpty() { CFGNode x = this, y; - while( x.nOuts() == 1 && (y=x.uctrl())!=null ) // Skip empty blocks + while( x.nOuts() == 1 && (y=x.uctrl())!=null && !(y instanceof CallNode) ) // Skip empty blocks x = y; return x; } @@ -89,6 +89,7 @@ public abstract class CFGNode extends Node { var comp = lhs.idepth() - rhs.idepth(); if( comp >= 0 ) lhs = (dep==null ? lhs : dep.addDep(lhs)).idom(); if( comp <= 0 ) rhs = (dep==null ? rhs : dep.addDep(rhs)).idom(); + if( lhs==null || rhs==null ) return null; } return lhs; } diff --git a/src/main/java/com/seaofnodes/simple/node/CProjNode.java b/src/main/java/com/seaofnodes/simple/node/CProjNode.java index 94770f16..a6e21ea0 100644 --- a/src/main/java/com/seaofnodes/simple/node/CProjNode.java +++ b/src/main/java/com/seaofnodes/simple/node/CProjNode.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeMem; import com.seaofnodes.simple.type.TypeTuple; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; public class CProjNode extends CFGNode { diff --git a/src/main/java/com/seaofnodes/simple/node/CallEndMach.java b/src/main/java/com/seaofnodes/simple/node/CallEndMach.java index 47cab07a..d26ea33b 100644 --- a/src/main/java/com/seaofnodes/simple/node/CallEndMach.java +++ b/src/main/java/com/seaofnodes/simple/node/CallEndMach.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.util.SB; public class CallEndMach extends CallEndNode implements MachNode { public CallEndMach( CallEndNode n ) { super(n); } diff --git a/src/main/java/com/seaofnodes/simple/node/CallEndNode.java b/src/main/java/com/seaofnodes/simple/node/CallEndNode.java index cf3f337c..b75852a4 100644 --- a/src/main/java/com/seaofnodes/simple/node/CallEndNode.java +++ b/src/main/java/com/seaofnodes/simple/node/CallEndNode.java @@ -74,10 +74,10 @@ public class CallEndNode extends CFGNode implements MultiNode { assert fun.in(1) instanceof StartNode && fun.in(2)==call; // Disallow self-recursive inlining (loop unrolling by another name) CFGNode idom = call; - while( !(idom instanceof FunNode) ) + while( !(idom instanceof FunNode) && idom!=null ) idom = idom.idom(); // Inline? - if( idom != fun ) { + if( idom != fun && idom != null ) { // Trivial inline: rewrite _folding = true; // Rewrite Fun so the normal RegionNode ideal collapses @@ -105,5 +105,4 @@ public class CallEndNode extends CFGNode implements MultiNode { @Override public Node pcopy(int idx) { return _folding ? in(1).in(idx) : null; } - } diff --git a/src/main/java/com/seaofnodes/simple/node/CallNode.java b/src/main/java/com/seaofnodes/simple/node/CallNode.java index 8b243e87..ba08c87a 100644 --- a/src/main/java/com/seaofnodes/simple/node/CallNode.java +++ b/src/main/java/com/seaofnodes/simple/node/CallNode.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.IterPeeps; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; /** @@ -162,8 +162,10 @@ public class CallNode extends CFGNode { // Check for args for( int i=0; i<tfp.nargs(); i++ ) - if( !arg(i+2)._type.isa(tfp.arg(i)) ) - return Parser.error( "Argument #"+i+" isa "+arg(i+2)._type+", but must be a "+tfp.arg(i), _loc); + if( !arg(i+2)._type.isa(tfp.arg(i)) ) { + cend().addDep(arg(i+2)); // Upgrading arg type may allow inlining + return Parser.error( "Argument #" + i + " isa " + arg(i+2)._type + ", but must be a " + tfp.arg(i), _loc ); + } if( tfp.fidxs() < 0 ) throw Utils.TODO(); // Infinite unknown TFPs? Should be fairly precise CG diff --git a/src/main/java/com/seaofnodes/simple/node/CastMach.java b/src/main/java/com/seaofnodes/simple/node/CastMach.java index 92822433..e45898f5 100644 --- a/src/main/java/com/seaofnodes/simple/node/CastMach.java +++ b/src/main/java/com/seaofnodes/simple/node/CastMach.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.util.SB; /** * Cast a pointer to read-only diff --git a/src/main/java/com/seaofnodes/simple/node/CastNode.java b/src/main/java/com/seaofnodes/simple/node/CastNode.java index 8d8f0257..6dc8e9fe 100644 --- a/src/main/java/com/seaofnodes/simple/node/CastNode.java +++ b/src/main/java/com/seaofnodes/simple/node/CastNode.java @@ -1,11 +1,10 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import com.seaofnodes.simple.type.TypeMemPtr; - +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; // Upcast (join) the input to a t. Used after guard test to lift an input. @@ -40,9 +39,15 @@ public class CastNode extends Node { @Override public Type compute() { // Cast array to int - if( _t == TypeInteger.BOT && in(1)._type instanceof TypeMemPtr tmp && tmp._obj.isAry() ) + Type t1 = in(1)._type; + if( _t == TypeInteger.BOT && t1 instanceof TypeMemPtr tmp && tmp._obj.isAry() ) return _t; - return in(1)._type.join(_t); + // Freeze if the join is high but both inputs are low + Type tj = t1.join(_t); + if( tj.isHigh() && !t1.isHigh() ) + return _type==null ? _t : _type; + + return tj; } @Override @@ -64,6 +69,6 @@ public class CastNode extends Node { // Has a condition to test, so OK if( in(0) != null ) return null; // No condition to test, so this must optimize away - throw Utils.TODO(); + return Parser.error( "Type " + in(1)._type.str() + " is not of declared type " + _t.str(), null ); } } diff --git a/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java b/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java new file mode 100644 index 00000000..3e1d3c69 --- /dev/null +++ b/src/main/java/com/seaofnodes/simple/node/ConFldOffNode.java @@ -0,0 +1,43 @@ +package com.seaofnodes.simple.node; + +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.type.TypeStruct; +import com.seaofnodes.simple.util.SB; +import java.util.BitSet; + +/** + * A field offset. This becomes a constant *after* other optimizations which + * determine field sizes - some fields might be dead, or hold only zeros or + * small values. + */ + +public class ConFldOffNode extends ConstantNode { + public final String _name; // Struct name + public final String _fname; // Field name + public ConFldOffNode( String name, String fname ) { super(TypeInteger.BOT); _name = name; _fname = fname; } + + @Override public String label() { + return _fname == " len" ? "sizeof("+_name+")" : "#"+_fname; + } + @Override public String glabel() { return label(); } + @Override public String uniqueName() { return "Off_" + _nid; } + + @Override + public StringBuilder _print1(StringBuilder sb, BitSet visited) { + return sb.append(label()); + } + + // Convert field offset to an integer + public Node asOffset(TypeStruct ts) { + return new ConstantNode(TypeInteger.constant(ts.offset(_fname==" len" ? ts._fields.length : ts.find(_fname)))).peephole(); + } + + + @Override public boolean eq(Node n) { + ConFldOffNode off = (ConFldOffNode)n; // Invariant + return _name==off._name && _fname==off._fname && super.eq(n); + } + @Override int hash() { return super.hash() * _name.hashCode() * _fname.hashCode(); } +} diff --git a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java index 79f301c1..22bf03c4 100644 --- a/src/main/java/com/seaofnodes/simple/node/ConstantNode.java +++ b/src/main/java/com/seaofnodes/simple/node/ConstantNode.java @@ -1,17 +1,13 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.codegen.CodeGen; -import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; import java.util.BitSet; /** - * A Constant node represents a constant value. At present, the only constants - * that we allow are integer literals; therefore Constants contain an integer - * value. As we add other types of constants, we will refactor how we represent - * Constants. + * A Constant node represents a constant value. * <p> * Constants have no semantic inputs. However, we set Start as an input to * Constants to enable a forward graph walk. This edge carries no semantic @@ -26,8 +22,7 @@ public class ConstantNode extends Node { super(new Node[]{CodeGen.CODE._start}); _con = _type = type; } - public ConstantNode( Node con, Type t ) { super(con); _con = t; } - public ConstantNode( ConstantNode con ) { this(con,con._type); } + public ConstantNode( ConstantNode con ) { super(con); _con = con._type; } public static Node make( Type type ) { if( type==Type. CONTROL ) return new CtrlNode(); @@ -36,10 +31,8 @@ public class ConstantNode extends Node { } @Override public String label() { return "#"+_con; } - @Override public String glabel() { return _con.gprint(new SB().p("#")).toString(); } - - @Override - public String uniqueName() { return "Con_" + _nid; } + @Override public String glabel() { return "#"+_con.gprint(); } + @Override public String uniqueName() { return "Con_" + _nid; } @Override public StringBuilder _print1(StringBuilder sb, BitSet visited) { @@ -48,23 +41,12 @@ public class ConstantNode extends Node { if( fun!=null && fun._name != null ) return sb.append("{ ").append(fun._name).append("}"); } - return sb.append(_con==null ? "---" : _con.print(new SB())); + return sb.append(_con==null ? "---" : _con.toString()); } @Override public boolean isConst() { return true; } - - @Override - public Type compute() { return _con; } - - @Override - public Node idealize() { return null; } - - @Override - public boolean eq(Node n) { - ConstantNode con = (ConstantNode)n; // Contract - return _con==con._con; - } - - @Override - int hash() { return _con.hashCode(); } + @Override public Type compute() { return _con; } + @Override public Node idealize() { return null; } + @Override public boolean eq(Node n) { return _con==((ConstantNode)n)._con; } + @Override int hash() { return _con.hashCode(); } } diff --git a/src/main/java/com/seaofnodes/simple/node/ExternNode.java b/src/main/java/com/seaofnodes/simple/node/ExternNode.java index 33fc0c1e..a10bb84a 100644 --- a/src/main/java/com/seaofnodes/simple/node/ExternNode.java +++ b/src/main/java/com/seaofnodes/simple/node/ExternNode.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; import java.util.BitSet; /** @@ -16,7 +16,7 @@ public class ExternNode extends ConstantNode { public ExternNode(Type t, String ex) { super(t); _extern = ex; } @Override public String label() { return "#"+_con+":"+_extern; } - @Override public String glabel() { return _con.gprint(new SB().p("#")).p(":").p(_extern).toString(); } + @Override public String glabel() { return _con.print(new SB().p("#"), new BitSet(), true).p(":").p(_extern).toString(); } @Override public String uniqueName() { return "Extern_" + _nid; } @Override public boolean eq(Node n) { return this==n; } diff --git a/src/main/java/com/seaofnodes/simple/node/FunNode.java b/src/main/java/com/seaofnodes/simple/node/FunNode.java index 81fa627a..4bd0fd97 100644 --- a/src/main/java/com/seaofnodes/simple/node/FunNode.java +++ b/src/main/java/com/seaofnodes/simple/node/FunNode.java @@ -1,13 +1,14 @@ package com.seaofnodes.simple.node; - -import com.seaofnodes.simple.*; +import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; import com.seaofnodes.simple.type.TypeTuple; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; import static com.seaofnodes.simple.codegen.CodeGen.CODE; @@ -125,10 +126,10 @@ public class FunNode extends RegionNode { return _folding ? super.idepth() : CodeGen.CODE.iDepthAt(1); } // Bypass Region idom, always assume idom is Start - @Override public CFGNode idom(Node dep) { return _folding && nIns()==3 ? cfg(2) : cfg(1); } + @Override public CFGNode idom(Node dep) { return _folding && nIns()==3 ? cfg(2) : (nIns()>1 ? cfg(1) : null); } // Always in-progress until we run out of unknown callers - public boolean unknownCallers() { return nIns()<2 || in(1) instanceof StartNode; } + public boolean unknownCallers() { return nIns()>=2 && in(1) instanceof StartNode; } @Override public boolean inProgress() { return unknownCallers(); } diff --git a/src/main/java/com/seaofnodes/simple/node/IfNode.java b/src/main/java/com/seaofnodes/simple/node/IfNode.java index 5d90449e..c5d687e5 100644 --- a/src/main/java/com/seaofnodes/simple/node/IfNode.java +++ b/src/main/java/com/seaofnodes/simple/node/IfNode.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; public class IfNode extends CFGNode implements MultiNode { @@ -87,8 +87,8 @@ public class IfNode extends CFGNode implements MultiNode { return switch( bop ) { case "<" -> ">" ; case "<=" -> ">="; - case "==" -> "!="; - case "!=" -> "=="; + case "==" -> "=="; + case "!=" -> "!="; case ">" -> "<" ; case ">=" -> "<="; default -> throw Utils.TODO(); diff --git a/src/main/java/com/seaofnodes/simple/node/LoadNode.java b/src/main/java/com/seaofnodes/simple/node/LoadNode.java index eebe94a3..b58ea498 100644 --- a/src/main/java/com/seaofnodes/simple/node/LoadNode.java +++ b/src/main/java/com/seaofnodes/simple/node/LoadNode.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; /** @@ -33,15 +34,21 @@ public class LoadNode extends MemOpNode { @Override public Type compute() { - if( mem()._type instanceof TypeMem mem ) { - // Update declared forward ref to the actual - if( _declaredType.isFRef() && mem._t instanceof TypeMemPtr tmp && !tmp.isFRef() ) - _declaredType = tmp; - // No lifting if ptr might null-check - if( err()==null ) - return _declaredType.join(mem._t); + if( !(mem()._type instanceof TypeMem mem) ) + return _declaredType; // No memory yet? Declared type + assert !_declaredType.isFRef(); + // No lifting if ptr might null-check + if( err()!=null || !(ptr()._type instanceof TypeMemPtr tmp) ) + return _declaredType; // No pointer yet? Declared type + Type t = tmp._obj.field(_name)._t; + if( t instanceof TypeConAry ary ) { + t = ary.elem(); // TODO: if offset is known, can peek the constant } - return _declaredType; + // Lift from declared type and memory input + t = t.join(_declaredType).join(mem._t); + if( _declaredType.isFinal() ) + t = t.makeRO(); // Deep final applied + return t; } @Override @@ -49,6 +56,11 @@ public class LoadNode extends MemOpNode { Node ptr = ptr(); Node mem = mem(); + if( mem instanceof CastNode cast ) { + setDef(1,cast.in(1)); + return this; + } + // Simple Load-after-Store on same address. if( mem instanceof StoreNode st && ptr == st.ptr() && off() == st.off() ) { // Must check same object @@ -58,7 +70,11 @@ public class LoadNode extends MemOpNode { // Simple load-after-MemMerge to a known alias can bypass. Happens when inlining. if( mem instanceof MemMergeNode mem2 ) { - setDef(1,mem2.alias(_alias)); + Node memA = mem2.alias(_alias); + for( Node ld : memA._outputs ) + if( ld instanceof LoadNode ) + CodeGen.CODE.add(ld); + setDef(1,memA); return this; } @@ -111,6 +127,7 @@ public class LoadNode extends MemOpNode { default: throw Utils.TODO(); } break; + case CastNode cast: mem = cast.in(1); break; case MemMergeNode merge: mem = merge.alias(_alias); break; default: @@ -147,7 +164,7 @@ public class LoadNode extends MemOpNode { // Load a flavored zero from a New private Node zero(NewNode nnn) { TypeStruct ts = nnn._ptr._obj; - Type zero = ts._fields[ts.findAlias(_alias)]._type.makeZero(); + Type zero = ts._fields[ts.findAlias(_alias)]._t.makeZero(); return castRO(new ConstantNode(zero).peephole()); } @@ -187,7 +204,7 @@ public class LoadNode extends MemOpNode { Node px = phi.in(idx); if( px==null ) return false; if( px._type instanceof TypeMem mem && mem._t.isHighOrConst() ) return true; - if( px instanceof StoreNode st1 && ptr()==st1.ptr() && off()==st1.off() ) return true; + if( px instanceof StoreNode st1 && ptr()==addDep(st1.ptr() )&& off()==st1.off() ) return true; addDep(px); return false; } diff --git a/src/main/java/com/seaofnodes/simple/node/LoopNode.java b/src/main/java/com/seaofnodes/simple/node/LoopNode.java index ec9055dc..fc50e17f 100644 --- a/src/main/java/com/seaofnodes/simple/node/LoopNode.java +++ b/src/main/java/com/seaofnodes/simple/node/LoopNode.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; import com.seaofnodes.simple.type.TypeMem; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; import java.util.HashSet; @@ -48,7 +48,7 @@ public class LoopNode extends RegionNode { x = x.idom(); } // Found a no-exit loop. Insert an exit - NeverNode iff = new NeverNode(back()); // Ideal never-branch + NeverNode iff = (NeverNode)new NeverNode(back()).peephole(); // Ideal never-branch CProjNode t = new CProjNode(iff,0,"True" ).init(); CProjNode f = new CProjNode(iff,1,"False").init(); setDef(2,t); // True continues loop, False (never) exits loop @@ -78,17 +78,19 @@ public class LoopNode extends RegionNode { expr = new PhiNode(r,expr).init(); } // Append new Never exit - ctrl.addDef(f ); - mem .addDef(memout); - expr.addDef(top); + ctrl.keep().addDef(f ); + mem .keep().addDef(memout); + expr.keep().addDef(top); } else { - ctrl = f; - mem = memout; - expr = top; + ctrl = f .keep(); + mem = memout.keep(); + expr = top .keep(); } - ret.setDef(0,ctrl); - ret.setDef(1,mem ); - ret.setDef(2,expr); + ret.setDef(0,ctrl.unkeep()); + ret.setDef(1,mem .unkeep()); + ret.setDef(2,expr.unkeep()); + ret._type = null; // This may LIFT the Return type, from [XCtrl,mem,expr] to [Ctrl,mem,expr] + ret.setType(ret.compute()); return stop; } diff --git a/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java b/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java index b01b3308..9440a7ea 100644 --- a/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java +++ b/src/main/java/com/seaofnodes/simple/node/MachConcreteNode.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.Type; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.Utils; import java.io.ByteArrayOutputStream; import java.util.BitSet; diff --git a/src/main/java/com/seaofnodes/simple/node/MachNode.java b/src/main/java/com/seaofnodes/simple/node/MachNode.java index f63b3651..c0b3af66 100644 --- a/src/main/java/com/seaofnodes/simple/node/MachNode.java +++ b/src/main/java/com/seaofnodes/simple/node/MachNode.java @@ -2,6 +2,8 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public interface MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java index 9f2fdd16..19acc5b9 100644 --- a/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java +++ b/src/main/java/com/seaofnodes/simple/node/MemMergeNode.java @@ -67,9 +67,12 @@ public class MemMergeNode extends Node { // Fold defaults into the default boolean progress=false, allDefault=true; - for( int i=2; i<nIns(); i++ ) + for( int i=2; i<nIns(); i++ ) { + if( in(i) instanceof CastNode cast ) + { setDef(i,cast.in(1)); progress=true; } if( in(1) == in(i) ) { setDef(i,null); progress=true; } else { allDefault=false; } + } // If not merging any memory (all memory is just the default) if( allDefault ) @@ -121,7 +124,7 @@ public class MemMergeNode extends Node { // 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() ); + : loopmem.alias(alias, new PhiNode(Parser.memName(alias), TypeMem.make(alias,Type.BOTTOM),loop.ctrl(),loopmem._mem(alias,null),null).peephole() ); alias(alias,old); } // Memory projections are made lazily; expand as needed @@ -137,7 +140,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(true).meet(rhs._type.glb(true)), r, lhs, rhs).peephole()); + alias(i, new PhiNode(Parser.memName(i), lhs._type.meet(rhs._type).glb(true), r, lhs, rhs).peephole()); } } diff --git a/src/main/java/com/seaofnodes/simple/node/MemOpNode.java b/src/main/java/com/seaofnodes/simple/node/MemOpNode.java index bb84019e..ead82322 100644 --- a/src/main/java/com/seaofnodes/simple/node/MemOpNode.java +++ b/src/main/java/com/seaofnodes/simple/node/MemOpNode.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.Utils; import java.lang.StringBuilder; import java.util.BitSet; diff --git a/src/main/java/com/seaofnodes/simple/node/MinusNode.java b/src/main/java/com/seaofnodes/simple/node/MinusNode.java index 059d0d00..f26ce37e 100644 --- a/src/main/java/com/seaofnodes/simple/node/MinusNode.java +++ b/src/main/java/com/seaofnodes/simple/node/MinusNode.java @@ -2,8 +2,7 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; -import com.seaofnodes.simple.Utils; - +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; public class MinusNode extends Node { diff --git a/src/main/java/com/seaofnodes/simple/node/MultiNode.java b/src/main/java/com/seaofnodes/simple/node/MultiNode.java index 17d00881..b4d6d78e 100644 --- a/src/main/java/com/seaofnodes/simple/node/MultiNode.java +++ b/src/main/java/com/seaofnodes/simple/node/MultiNode.java @@ -1,6 +1,6 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.Ary; +import com.seaofnodes.simple.util.Ary; public interface MultiNode { diff --git a/src/main/java/com/seaofnodes/simple/node/NewNode.java b/src/main/java/com/seaofnodes/simple/node/NewNode.java index 5a8c1b6b..1785af4e 100644 --- a/src/main/java/com/seaofnodes/simple/node/NewNode.java +++ b/src/main/java/com/seaofnodes/simple/node/NewNode.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; + import java.util.BitSet; /** @@ -27,8 +27,7 @@ public class NewNode extends Node implements MultiNode { // Malloc-length in slot 1 assert nodes[1]._type instanceof TypeInteger || nodes[1]._type==Type.NIL; for( int i=0; i<_len; i++ ) - // Memory slices for all fields. - assert nodes[2+i]._type.isa(TypeMem.BOT); + assert ptr._obj._fields[i]._one || nodes[2 + i]._type.isa( TypeMem.BOT ); } public NewNode(NewNode nnn) { super(nnn); _ptr = nnn._ptr; _len = nnn._len; } @@ -37,7 +36,7 @@ public class NewNode extends Node implements MultiNode { @Override public String label() { return "new_"+glabel(); } @Override public String glabel() { - return _ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._type.str() : _ptr._obj.str(); + return _ptr._obj.isAry() ? "ary_"+_ptr._obj._fields[1]._t.str() : _ptr._obj.str(); } @Override @@ -65,17 +64,30 @@ public class NewNode extends Node implements MultiNode { ts[0] = Type.CONTROL; ts[1] = _ptr; for( int i=0; i<fs.length; i++ ) { - Type mt = in(i+2)._type; - TypeMem mem = mt==Type.TOP ? TypeMem.TOP : (TypeMem)mt; - Type tfld = mem._t.meet(mem._t.makeZero()); - Type tfld2 = tfld.join(fs[i]._type); - ts[i+2] = TypeMem.make(fs[i]._alias,tfld2); + if( _ptr._obj._fields[i]._one ) { + // Once-only fields use the declared type + ts[i+2] = _ptr._obj._fields[i]._t; + } else { + // Others take from the inputs + Type mt = in(i+2)._type; + TypeMem mem = mt==Type.TOP ? TypeMem.TOP : (TypeMem)mt; + Type tfld = mem._t.meet(mem._t.makeZero()); + Type tfld2 = tfld.join(fs[i]._t ); + ts[i+2] = TypeMem.make(fs[i]._alias,tfld2); + } } return TypeTuple.make(ts); } @Override - public Node idealize() { return null; } + public Node idealize() { + Node progress=null; + for( int i=1; i<nIns(); i++ ) { + if( in(i) instanceof CastNode cast ) + progress = setDef(i,cast.in(1)); + } + return progress == null ? null : this; + } @Override public boolean eq(Node n) { return this == n; } diff --git a/src/main/java/com/seaofnodes/simple/node/Node.java b/src/main/java/com/seaofnodes/simple/node/Node.java index eadb984a..5e5be196 100644 --- a/src/main/java/com/seaofnodes/simple/node/Node.java +++ b/src/main/java/com/seaofnodes/simple/node/Node.java @@ -1,6 +1,8 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.*; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.Utils; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.print.IRPrinter; import com.seaofnodes.simple.print.JSViewer; @@ -310,6 +312,7 @@ public abstract class Node implements Cloneable { int idx = n._inputs.find(this); n._inputs.set(idx,nnn); nnn.addUse(n); + CODE.add(n); CODE.addAll(n._outputs); } kill(); @@ -414,7 +417,7 @@ public abstract class Node implements Cloneable { // node. If peeps are disabled, still allow high Phis to collapse; // they typically come from dead Regions, and we want the Region to // collapse, which requires the Phis to die first. - if( _type.isHighOrConst() && !isConst() ) + if( !isConst() && _type.isHighOrConst() ) return ConstantNode.make(_type).peephole(); // Global Value Numbering diff --git a/src/main/java/com/seaofnodes/simple/node/NotNode.java b/src/main/java/com/seaofnodes/simple/node/NotNode.java index 0314841d..4b80e61c 100644 --- a/src/main/java/com/seaofnodes/simple/node/NotNode.java +++ b/src/main/java/com/seaofnodes/simple/node/NotNode.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; public class NotNode extends Node { @@ -20,7 +20,7 @@ public class NotNode extends Node { @Override public TypeInteger compute() { Type t0 = in(1)._type; - if( t0.isHigh() ) return TypeInteger.BOOL.dual(); + if( t0.isHigh() ) return (TypeInteger)TypeInteger.BOOL.dual(); if( t0 == Type.NIL || t0 == TypeInteger.ZERO ) return TypeInteger.TRUE; if( t0 instanceof TypeNil tn && tn.notNull() ) return TypeInteger.FALSE; if( t0 instanceof TypeInteger i && (i._min > 0 || i._max < 0) ) return TypeInteger.FALSE; diff --git a/src/main/java/com/seaofnodes/simple/node/ParmNode.java b/src/main/java/com/seaofnodes/simple/node/ParmNode.java index 32e41f54..a14a4fb9 100644 --- a/src/main/java/com/seaofnodes/simple/node/ParmNode.java +++ b/src/main/java/com/seaofnodes/simple/node/ParmNode.java @@ -1,6 +1,5 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; import java.util.BitSet; @@ -13,7 +12,7 @@ public class ParmNode extends PhiNode { super(label,declaredType,inputs); _idx = idx; } - public ParmNode(ParmNode parm) { super(parm, parm._label, parm._declaredType); _idx = parm._idx; } + public ParmNode(ParmNode parm) { super(parm, parm._label, parm._minType ); _idx = parm._idx; } @Override public String label() { return MemOpNode.mlabel(_label); } @@ -37,14 +36,8 @@ public class ParmNode extends PhiNode { } - @Override - public Node idealize() { - if( inProgress() ) return null; - return super.idealize(); - } - // Always in-progress until we run out of unknown callers - @Override public boolean inProgress() { return fun().inProgress(); } + @Override public boolean inProgress() { return in(0) instanceof FunNode fun && fun.inProgress(); } @Override public boolean eq( Node n ) { return ((ParmNode)n)._idx==_idx && super.eq(n); diff --git a/src/main/java/com/seaofnodes/simple/node/PhiNode.java b/src/main/java/com/seaofnodes/simple/node/PhiNode.java index 971b52ae..fcbacbc9 100644 --- a/src/main/java/com/seaofnodes/simple/node/PhiNode.java +++ b/src/main/java/com/seaofnodes/simple/node/PhiNode.java @@ -1,25 +1,34 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.*; +import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; public class PhiNode extends Node { public final String _label; - // The Phi type we compute must stay within the domain of the Phi. - // Example Int stays Int, Ptr stays Ptr, Control stays Control, Mem stays Mem. - final Type _declaredType; - - public PhiNode(String label, Type declaredType, Node... inputs) { super(inputs); _label = label; assert declaredType!=null; _declaredType = declaredType; } - public PhiNode(PhiNode phi, String label, Type declaredType) { super(phi); _label = label; _type = _declaredType = declaredType; } - public PhiNode(PhiNode phi) { super(phi); _label = phi._label; _declaredType = phi._declaredType; } + // The Phi type we compute must stay within the domain of the Phi. Example + // Int stays Int, Ptr stays Ptr, Control stays Control, Mem stays Mem. + Type _minType; + public PhiNode(String label, Type minType, Node... inputs) { + super(inputs); + _label = label; + assert minType!=null; + _minType = minType; + } + // Used by ParmNode + public PhiNode(PhiNode phi, String label, Type minType) { super(phi); _label = label; _type = _minType = minType; } + // Used by instruction Selection + public PhiNode(PhiNode phi) { this(phi,phi._label,phi._minType ); } + // Used by the infinite-loop exit breaker public PhiNode(RegionNode r, Node sample) { super(new Node[]{r}); _label = ""; - _declaredType = sample._type; + _minType = sample._type; while( nIns() < r.nIns() ) addDef(sample); } @@ -44,7 +53,7 @@ public class PhiNode extends Node { } public CFGNode region() { return (CFGNode)in(0); } - @Override public boolean isMem() { return _declaredType instanceof TypeMem; } + @Override public boolean isMem() { return _minType instanceof TypeMem; } @Override public boolean isPinned() { return true; } @Override @@ -52,14 +61,19 @@ public class PhiNode extends Node { if( !(region() instanceof RegionNode r) ) return region()._type==Type.XCONTROL ? (_type instanceof TypeMem ? TypeMem.TOP : Type.TOP) : _type; // During parsing Phis have to be computed type pessimistically. - if( r.inProgress() ) return _declaredType; + if( r.inProgress() ) return _minType; // Set type to local top of the starting type - Type t = _declaredType.glb(false).dual();//Type.TOP; + //Type t = _minType.dual(); + Type t = 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. - if( addDep(r.in(i))._type != Type.XCONTROL ) + if( addDep(r.in(i))._type != Type.XCONTROL ) { + if( in(i)._type==Type.BOTTOM ) + return Type.BOTTOM; t = t.meet(in(i)._type); + } + t = t.join( _minType ); return t; } @@ -67,19 +81,40 @@ public class PhiNode extends Node { public Node idealize() { if( !(region() instanceof RegionNode r ) ) return in(1); // Input has collapse to e.g. starting control. + // Can upgrade minType even while in-progress + if( _minType instanceof TypeMemPtr tmp && _minType.isFRef() ) { + TypeMemPtr tmp2 = (TypeMemPtr)CodeGen.CODE.P.TYPES.get(tmp._obj._name); + if( tmp2!=null && tmp2 != _minType ) { + _minType = tmp2; + return this; + } + } if( r.inProgress() || r.nIns()<=1 ) return null; // Input is in-progress // If we have only a single unique input, become it. Node live = singleUniqueInput(); - if (live != null) - return live; + if( live != null ) { + if( live._type.isa(_type) ) + return live; + // Keep the Phi upcast + return new CastNode(_type,null,live); + } // No bother if region is going to fold dead paths soon for( int i=1; i<nIns(); i++ ) if( r.in(i)._type == Type.XCONTROL ) return null; + // Simple Phi-after-MemMerge to a known alias can bypass. Happens when inlining. + if( _type instanceof TypeMem tmem && tmem._alias!=1 ) { + for( int i=1; i<nIns(); i++ ) + if( in(i) instanceof MemMergeNode mem ) { + setDef(i,mem.alias(tmem._alias)); + return this; + } + } + // Generic "pull down op" Node progress; if( same_op() && (progress = drop_same_op()) != null ) @@ -197,9 +232,19 @@ public class PhiNode extends Node { return in(nIns()-1) == null; } - // Never equal if inProgress + // Never equal if inProgress. + // Also, joins @Override public boolean eq( Node n ) { - return !inProgress(); + if( inProgress() ) return false; + Type min = ((PhiNode)n)._minType; + if( _minType==min ) return true; + Type mt = min.meet(_minType); + if( min!=mt && _minType!=mt ) return false; + //// Theory says these 2 Phis CAN be merged/GVNd, but I need to pick the + //// most general minType. + //_minType = ((PhiNode)n)._minType = mt; + //return true; + return false; } @Override diff --git a/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java b/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java index 86d17f9b..a35f5a1d 100644 --- a/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java +++ b/src/main/java/com/seaofnodes/simple/node/ReadOnlyMach.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.util.SB; /** * Cast a pointer to read-only diff --git a/src/main/java/com/seaofnodes/simple/node/RegionNode.java b/src/main/java/com/seaofnodes/simple/node/RegionNode.java index 8f65d0e5..6f740a47 100644 --- a/src/main/java/com/seaofnodes/simple/node/RegionNode.java +++ b/src/main/java/com/seaofnodes/simple/node/RegionNode.java @@ -45,7 +45,7 @@ public class RegionNode extends CFGNode { return in(1); // Collapse if no Phis; 1-input Phis will collapse on their own // If a CFG diamond with no merging, delete: "if( pred ) {} else {};" - if( !hasPhi() && // No Phi users, just a control user + if( !hasPhi() && nIns()>3 && // No Phi users, just a control user in(1) instanceof CProjNode p1 && in(2) instanceof CProjNode p2 && addDep(p1.in(0))==addDep(p2.in(0)) && diff --git a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java index b4173871..7971733a 100644 --- a/src/main/java/com/seaofnodes/simple/node/ReturnNode.java +++ b/src/main/java/com/seaofnodes/simple/node/ReturnNode.java @@ -1,12 +1,12 @@ package com.seaofnodes.simple.node; import com.seaofnodes.simple.Parser; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.CodeGen; -import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.codegen.Encoding; +import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; /** @@ -61,11 +61,10 @@ public class ReturnNode extends CFGNode { // Upgrade signature based on return type Type ret = expr()._type; TypeFunPtr fcn = _fun.sig(); - assert ret.isa(fcn.ret()); - if( ret != fcn.ret() ) + if( ret != fcn.ret() && ret.isa(fcn.ret()) ) _fun.setSig(fcn.makeFrom(ret)); - // If dead (cant be reached; infinite loop), kill the exit values + // If dead (cannot be reached; infinite loop), kill the exit values if( ctrl()._type==Type.XCONTROL && !(mem() instanceof ConstantNode && expr() instanceof ConstantNode) ) { Node top = new ConstantNode(Type.TOP).peephole(); @@ -100,8 +99,8 @@ public class ReturnNode extends CFGNode { // Merge path into the One True Return RegionNode r = (RegionNode)ctrl(); // Assert that the Phis are in particular outputs; not reordered or shuffled - PhiNode mem = (PhiNode)r.out(0); assert mem._declaredType == TypeMem.BOT; - PhiNode rez = (PhiNode)r.out(1); assert rez._declaredType == Type.BOTTOM; + PhiNode mem = (PhiNode)r.out(0); assert mem._minType == TypeMem.BOT; + PhiNode rez = (PhiNode)r.out(1); assert rez._minType == Type.BOTTOM; // Pop "inProgress" null off r ._inputs.pop(); mem._inputs.pop(); diff --git a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java index 3127e491..36746a81 100644 --- a/src/main/java/com/seaofnodes/simple/node/ScopeNode.java +++ b/src/main/java/com/seaofnodes/simple/node/ScopeNode.java @@ -1,8 +1,13 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.*; +import com.seaofnodes.simple.Parser; +import com.seaofnodes.simple.Var; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.AryInt; +import com.seaofnodes.simple.util.Utils; + import java.util.*; /** @@ -19,18 +24,26 @@ public class ScopeNode extends MemMergeNode { public static final String ARG0 = "arg"; public static final String MEM0 = "$mem"; - // All active/live variables in all nested scopes, all run together + // All active/live variables in all nested scopes, all run together. + // Maps 1-to-1 to the _inputs array. public final Ary<Var> _vars; - // Size of each nested lexical scope - public final Ary<Integer> _lexSize; - // Lexical scope is typed: - // - Block scope - basic block scoping - // - Constructor - struct type is defined, and here we give values to all fields - // - Function - out-of-scope lookups restricted to final constants - public enum Kind { Block, Constructor, Function }; + public static class Kind { + // Basic block scoping + public static class Block extends Kind { } + // Function scope + public static class Func extends Kind { } + // Struct definition, mapping types to fields + public static class Define extends Kind { public Define(TypeMemPtr tmp) { _tmp=tmp; } public final TypeMemPtr _tmp; } + // Struct allocation, mapping values to fields + public static class Alloc extends Kind { public Alloc (TypeMemPtr tmp) { _tmp=tmp; } public final TypeMemPtr _tmp; } + + public int _lexSize; // Number of Vars in this scope + } public final Ary<Kind> _kinds; + // Lexical scope nesting depth + public int depth() { return _kinds._len; } // Extra guards; tested predicates and casted results private final Ary<Node> _guards; @@ -38,10 +51,9 @@ public class ScopeNode extends MemMergeNode { // A new ScopeNode public ScopeNode() { super(true); - _vars = new Ary<>(Var .class); - _lexSize= new Ary<>(Integer.class); - _kinds = new Ary<>(Kind .class); - _guards = new Ary<>(Node .class); + _vars = new Ary<>(Var .class); + _kinds = new Ary<>(Kind.class); + _guards = new Ary<>(Node.class); } @Override public String label() { return "Scope"; } @@ -51,9 +63,9 @@ public class ScopeNode extends MemMergeNode { sb.append("Scope[ "); int j=1; for( int i=0; i<nIns(); i++ ) { - if( j < _lexSize._len && i == _lexSize.at(j) ) { sb.append("| "); j++; } + if( j < depth() && i == _kinds.at(j)._lexSize ) { sb.append("| "); j++; } Var v = _vars.at(i); - sb.append(v.type().print(new SB())); + sb.append(v.type()); sb.append(" "); if( v._final ) sb.append("!"); sb.append(v._name); @@ -90,17 +102,14 @@ public class ScopeNode extends MemMergeNode { public Node mem(Node n) { return setDef(1,n); } public void push( Kind kind ) { - assert _lexSize._len==_kinds._len; - _lexSize.push(_vars.size()); - _kinds .push(kind); + kind._lexSize = _vars.size(); + _kinds.push(kind); } // Pop a lexical scope public void pop() { - assert _lexSize._len==_kinds._len; promote(); // Promote forward references to the next outer scope - int n = _lexSize.pop(); - _kinds.pop(); + int n = _kinds.pop()._lexSize; popUntil(n); // Pop off inputs going out of scope _vars.setLen(n); // Pop off variables going out of scope } @@ -109,29 +118,56 @@ public class ScopeNode extends MemMergeNode { // Look for forward references in the last lexical scope and promote to the // next outer lexical scope. At the last scope declare them an error. public void promote() { - int n = _lexSize.last(); + Kind kind = _kinds.last(); + int n = kind._lexSize; for( int i=n; i<nIns(); i++ ) { Var v = var(i); if( !v.isFRef() ) continue; - if( _lexSize._len==1 ) + if( depth()==1 ) throw Parser.error("Undefined name '" + v._name + "'",v._loc); - _vars.swap(n,i); + _vars .swap(n,i); _inputs.swap(n,i); v._idx = n; - n++; - _lexSize.set(_lexSize._len-1,n); + kind._lexSize = ++n; } } - public boolean inConstructor() { return _kinds.last() == Kind.Constructor; } + public boolean inConstructor() { return _kinds.last() instanceof Kind.Define; } + public boolean inAllocation () { return _kinds.last() instanceof Kind.Alloc ; } + public boolean inFunction () { return _kinds.last() instanceof Kind.Func ; } + + public Kind kind( Var v ) { + for( int i=depth()-1; i>=0; i-- ) + if( v._idx >= _kinds.at(i)._lexSize ) + return _kinds.at(i); + throw Utils.TODO(); + } + + // Return the kind for the defining scope, or a function scope if found + // first. Block scopes means the variable can be r/w directly in the + // scope, Function scopes require final constants (no capture), and + // Constructor scopes mean an instance variable reference. + + // Walk up-lexical scope looking for defining lexical Kind. + // - Skip any amount of nested block scopes + // - Walking out of a function requires v be a final constant (for now) - + // and we can stop walking. + + // - Walking out of a method and (skipping Blocks) into the matching struct + // is OK, and this is a instance var load. + + // - Walking out of a method and into the wrong struct is an error; + // including nested structs containing (no nested classes yet) + + // Returns error, forward-ref, ok containing struct, ok containing function/block. - // Is v outside any current function scope? - public boolean outOfFunction( Var v ) { - for( int i=_lexSize._len-1; i>=0 && v._idx<_lexSize.at(i); i-- ) - if( _kinds.at(i)==Kind.Function ) - return true; - return false; + public String outOfFunction( Var v ) { + //if( v==null ) return null; // Prolly forward reference + //int i; for( i=_lexSize._len-1; i>=0 && v._idx<_lexSize.at(i); i-- ) + // if( _kinds.at(i)=="{->}" ) return "{->}"; + //return _kinds.at(i); + throw Utils.TODO(); } @@ -149,9 +185,9 @@ 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 ) { - 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-- ) { + assert _kinds.isEmpty() || name.charAt(0)!='$' ; // Later scopes do not define memory + if( depth() > 0 ) + for( int i=_vars.size()-1; i>=_kinds.last()._lexSize; i-- ) { Var n = var(i); if( n._name.equals(name) ) { if( !n.isFRef() ) return false; // Double define @@ -214,7 +250,7 @@ public class ScopeNode extends MemMergeNode { : 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; + //assert !v._final || st==null; if( st!=null ) setDef(v._idx,st); // Set new value return v; } @@ -240,7 +276,6 @@ public class ScopeNode extends MemMergeNode { // 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 dup._vars .addAll(_vars ); - dup._lexSize.addAll(_lexSize); dup._kinds .addAll(_kinds ); dup._guards .addAll(_guards ); // The dup'd guards all need dup'd keepers, to keep proper accounting diff --git a/src/main/java/com/seaofnodes/simple/node/SplitNode.java b/src/main/java/com/seaofnodes/simple/node/SplitNode.java index 3a1ed011..d061cdbd 100644 --- a/src/main/java/com/seaofnodes/simple/node/SplitNode.java +++ b/src/main/java/com/seaofnodes/simple/node/SplitNode.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; import java.util.BitSet; public abstract class SplitNode extends MachConcreteNode { diff --git a/src/main/java/com/seaofnodes/simple/node/StartNode.java b/src/main/java/com/seaofnodes/simple/node/StartNode.java index f40203b4..e3806de7 100644 --- a/src/main/java/com/seaofnodes/simple/node/StartNode.java +++ b/src/main/java/com/seaofnodes/simple/node/StartNode.java @@ -6,11 +6,11 @@ import com.seaofnodes.simple.type.*; import java.util.Arrays; import java.util.BitSet; import java.util.HashSet; -import static com.seaofnodes.simple.Utils.TODO; +import static com.seaofnodes.simple.util.Utils.TODO; /** * The Start node represents the start of the function. - * + * <p> * Start initially has 1 input (arg) from outside and the initial control. * In ch10 we also add mem aliases as structs get defined; each field in struct * adds a distinct alias to Start's tuple. @@ -19,7 +19,7 @@ public class StartNode extends LoopNode implements MultiNode { final Type _arg; - public StartNode(Type arg) { super((Parser.Lexer)null,null); _arg = arg; _type = compute(); } + public StartNode(Type arg) { super(null,null); _arg = arg; _type = compute(); } public StartNode(StartNode start) { super(start); _arg = start==null ? null : start._arg; } @Override public String label() { return "Start"; } @@ -29,13 +29,12 @@ public class StartNode extends LoopNode implements MultiNode { return sb.append(label()); } - @Override public boolean blockHead() { return true; } - @Override public CFGNode cfg0() { return null; } + @Override public CFGNode cfg0() { return null; } // Get the one control following; error to call with more than one e.g. an // IfNode or other multi-way branch. For Start, its "main" @Override public CFGNode uctrl() { - // Find "main", its the start. + // Find "main", it's the start. CFGNode C = null; for( Node use : _outputs ) if( use instanceof FunNode fun && fun.sig().isa(CodeGen.CODE._main) ) diff --git a/src/main/java/com/seaofnodes/simple/node/StopNode.java b/src/main/java/com/seaofnodes/simple/node/StopNode.java index b65535f1..4b03bf4e 100644 --- a/src/main/java/com/seaofnodes/simple/node/StopNode.java +++ b/src/main/java/com/seaofnodes/simple/node/StopNode.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; public class StopNode extends CFGNode { diff --git a/src/main/java/com/seaofnodes/simple/node/StoreNode.java b/src/main/java/com/seaofnodes/simple/node/StoreNode.java index 9b561bed..5fb274db 100644 --- a/src/main/java/com/seaofnodes/simple/node/StoreNode.java +++ b/src/main/java/com/seaofnodes/simple/node/StoreNode.java @@ -40,14 +40,16 @@ public class StoreNode extends MemOpNode { @Override public Type compute() { Type val = val()._type; - TypeMem mem = (TypeMem)mem()._type; // Invariant + Type mem0 = mem()._type; + if( mem0 == Type.TOP ) return TypeMem.TOP; + TypeMem mem = (TypeMem)mem0; // Invariant if( mem == TypeMem.TOP ) return TypeMem.TOP; Type t = Type.BOTTOM; // No idea on field contents // Same alias, lift val to the declared type and then meet into other fields if( mem._alias == _alias ) { - // Update declared forward ref to the actual - if( _declaredType.isFRef() && val instanceof TypeMemPtr tmp && !tmp.isFRef() ) - _declaredType = tmp; + assert !_declaredType.isFRef(); + // Sharpen memory value; required for narrowing stores where the parser inserts + // zero/sign masking and somebody reads the TypeMem type. val = val.join(_declaredType); t = val.meet(mem._t); } @@ -57,6 +59,11 @@ public class StoreNode extends MemOpNode { @Override public Node idealize() { + if( mem() instanceof CastNode cast ) { + setDef(1,cast.in(1)); + return this; + } + // Simple store-after-store on same address. Should pick up the // required init-store being stomped by a first user store. if( mem() instanceof StoreNode st && diff --git a/src/main/java/com/seaofnodes/simple/node/StructNode.java b/src/main/java/com/seaofnodes/simple/node/StructNode.java index 4efc0de9..b5b59b81 100644 --- a/src/main/java/com/seaofnodes/simple/node/StructNode.java +++ b/src/main/java/com/seaofnodes/simple/node/StructNode.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; import java.util.BitSet; /** @@ -9,7 +9,8 @@ import java.util.BitSet; */ public class StructNode extends Node { - public TypeStruct _ts; + public final TypeStruct _ts; + public StructNode(TypeStruct ts) { _ts=ts; assert !ts._open; } @Override public String label() { return _ts==null ? "STRUCT?" : _ts.str(); } @@ -19,7 +20,7 @@ public class StructNode extends Node { sb.append(_ts._name).append(" {"); for( int i=0; i<nIns(); i++ ) { sb.append(_ts._fields[i]._fname).append(":"); - sb.append((in(i)==null ? Type.BOTTOM : in(i)._type).print(new SB())); + sb.append(in(i)==null ? Type.BOTTOM : in(i)._type); sb.append("; "); } sb.setLength(sb.length()-2); @@ -32,7 +33,7 @@ public class StructNode extends Node { Field[] fs = new Field[_ts._fields.length]; for( int i=0; i<fs.length; i++ ) fs[i] = _ts._fields[i].makeFrom(in(i)==null ? Type.TOP : in(i)._type); - return TypeStruct.make(_ts._name,fs); + return TypeStruct.make(_ts._name,false,fs); } @Override diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java index f37738bf..1c865254 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class AddARM extends MachConcreteNode implements MachNode { AddARM( Node add) { super(add); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java index 209f24f4..eb75c1a0 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddFARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class AddFARM extends MachConcreteNode implements MachNode { AddFARM(Node addf) { super(addf); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java index a1cd8306..93c9e8c3 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AddIARM.java @@ -1,6 +1,6 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; +import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java index ad76ca4c..77115d54 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndARM.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.MachConcreteNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; public class AndARM extends MachConcreteNode implements MachNode { AndARM(Node and) { super(and); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java index 1f12ef13..5b739cd3 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AndIARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class AndIARM extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java index 342b7519..b83fb3cb 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Arithmetic Shift Right (register) public class AsrARM extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java index a1775dde..38373e67 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/AsrIARM.java @@ -1,12 +1,12 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.node.MachConcreteNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; public class AsrIARM extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java index b36a395b..b9ede544 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/BranchARM.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Jump on flags, uses flags public class BranchARM extends IfNode implements MachNode, RIPRelSize { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java index 989bd366..a2cb9bba 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallARM.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; public class CallARM extends CallNode implements MachNode, RIPRelSize { final TypeFunPtr _tfp; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java index 87dde38c..a3e1cf19 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CallRRARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class CallRRARM extends CallNode implements MachNode { CallRRARM(CallNode call) { super(call); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java index dbc86f62..794ff0c9 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class CmpARM extends MachConcreteNode implements MachNode { CmpARM( Node cmp ) { super(cmp); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java index e82a2ee3..67ffc27b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpFARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // compare instruction on float regs input(D-registers) public class CmpFARM extends MachConcreteNode implements MachNode{ diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java index 8a4f242a..f84a1649 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/CmpIARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Compare with immediate. // CMP (immediate) - SUBS diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java index 40bd8387..de254eeb 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class DivARM extends MachConcreteNode implements MachNode { DivARM( Node div ) { super(div); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java index 72b76444..813bebe4 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/DivFARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class DivFARM extends MachConcreteNode implements MachNode { DivFARM( Node divf) { super(divf); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java index 63c57770..b47b65ad 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FloatARM.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; //FMOV (scalar, immediate) //Floating-point move immediate. diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java index 32777f03..44a417f9 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/FunARM.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.FunNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class FunARM extends FunNode implements MachNode { FunARM(FunNode fun) { super(fun); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java index 5ecc98b6..f1fa162f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/I2F8ARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class I2F8ARM extends MachConcreteNode implements MachNode { I2F8ARM(Node i2f8) { super(i2f8); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java index 0a07b07a..ee74b95e 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/IntARM.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; // Integer constants public class IntARM extends ConstantNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java index 44c13321..1e5d2094 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LoadARM.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.LoadNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; // Load memory addressing on ARM // Support imm, reg(direct), or reg+off(indirect) addressing diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java index 055d6dcc..80ce493f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Logical Shift Left (register) public class LslARM extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java index 94d3e25b..7fe16cbe 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LslIARM.java @@ -1,12 +1,12 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.node.MachConcreteNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; public class LslIARM extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java index a691e0fe..fc005e04 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Logical Shift Right (register) public class LsrARM extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java index 094cd30f..78844b0a 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/LsrIARM.java @@ -1,9 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; - -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // logical right shift immediate public class LsrIARM extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java index 6d8344a2..e877931d 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MemOpARM.java @@ -1,14 +1,13 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; - +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.lang.StringBuilder; import java.util.BitSet; - public abstract class MemOpARM extends MemOpNode implements MachNode { final int _off; // Limit 9 bits sized, or (13 bits<<logsize) unsigned final int _imm; // Limit ? bits diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java index 3514db9b..a23ec75b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // mulh signed multiply instruction(no-imm form) public class MulARM extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java index 89dba172..73ebbf00 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/MulFARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class MulFARM extends MachConcreteNode implements MachNode{ MulFARM(Node mulf) {super(mulf);} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java index b7c3c803..881b41f9 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NegARM.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.node.MachConcreteNode; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; public class NegARM extends MachConcreteNode implements MachNode { NegARM(Node sub) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java index cb51eea2..c1aad15f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NewARM.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class NewARM extends NewNode implements MachNode, RIPRelSize { // A pre-zeroed chunk of memory. diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java index 5a8d882d..027a8128 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/NotARM.java @@ -1,10 +1,9 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; - import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.util.SB; public class NotARM extends MachConcreteNode implements MachNode{ NotARM(NotNode not) {super(not);} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java index b5cfa8cf..e8245749 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Not using the ORRS variant. public class OrARM extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java index 2a2d199a..a48caa51 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/OrIARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class OrIARM extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java index 246e482a..01b46b8d 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SetARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // conditional set? // e.g CSET, stores flag info into GPRS after compare diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java index 62bb75aa..5af45892 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SplitARM.java @@ -1,12 +1,11 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.FunNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.node.SplitNode; -import com.seaofnodes.simple.node.cpus.riscv.riscv; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class SplitARM extends SplitNode { SplitARM(String kind, byte round) { super(kind,round,new Node[2]);} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java index 688d8731..91385ac9 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/StoreARM.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; -import com.seaofnodes.simple.node.StoreNode; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.node.StoreNode; import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; // Store memory addressing on ARM // Support imm, reg(direct), or reg+off(indirect) addressing diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java index 552b46df..e3b95e50 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class SubARM extends MachConcreteNode implements MachNode { SubARM(Node sub) { super(sub); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java index 0d8d3c10..a252e542 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubFARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class SubFARM extends MachConcreteNode implements MachNode { SubFARM(Node subf) {super(subf);} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java index b882c5a4..b50107c9 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/SubIARM.java @@ -1,11 +1,10 @@ package com.seaofnodes.simple.node.cpus.arm; import com.seaofnodes.simple.codegen.*; -import com.seaofnodes.simple.node.MachConcreteNode; - -import com.seaofnodes.simple.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.MachConcreteNode; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; public class SubIARM extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java index 606b03f0..29d490ef 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TFPARM.java @@ -1,11 +1,12 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class TFPARM extends ConstantNode implements MachNode, RIPRelSize { TFPARM( ConstantNode con ) { super(con); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java index 68e32c78..cdcaa433 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/TMPARM.java @@ -1,11 +1,12 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class TMPARM extends ConstantNode implements MachNode, RIPRelSize { TMPARM( ConstantNode con ) { super(con); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java index a69c3c7c..2dd5fd6b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/UJmpARM.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; // unconditional jump diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java index ec86cfa5..52bda021 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorARM.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class XorARM extends MachConcreteNode implements MachNode{ XorARM(Node xor) {super(xor);} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java index e2582d22..23b29644 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/XorIARM.java @@ -1,11 +1,10 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.node.MachConcreteNode; -import com.seaofnodes.simple.node.MachNode; - -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.MachConcreteNode; +import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; public class XorIARM extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java b/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java index e6f64158..9dbf724d 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/arm/arm.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.arm; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; public class arm extends Machine { public arm( CodeGen code ) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java index 37383608..2cd00845 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AUIPC.java @@ -1,10 +1,11 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Add upper 20bits to PC. Immediate comes from the relocation info. public class AUIPC extends ConstantNode implements MachNode, RIPRelSize { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java index 4d2ac916..8636df9f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddFRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // fadd.d public class AddFRISC extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java index a85ce5d0..511b0583 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddIRISC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class AddIRISC extends ImmRISC { // Used to inst-selection as a direct match against an ideal Add/Sub diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java index df392a0e..7010916f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AddRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class AddRISC extends MachConcreteNode implements MachNode { public AddRISC( Node add ) { super(add); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java index ba88bb48..842c8bdc 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndIRISC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class AndIRISC extends ImmRISC { public AndIRISC( Node and, int imm) { super(and,imm); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java index 93ef95c0..1845985e 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/AndRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class AndRISC extends MachConcreteNode implements MachNode { public AndRISC(Node and) { super(and); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java index 44ff4e8b..b7284265 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/BranchRISC.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; // Conditional branch such as: BEQ diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java index 89b2c865..a676ba60 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRISC.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class CallRISC extends CallNode implements MachNode, RIPRelSize { final TypeFunPtr _tfp; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java index dcc53cbf..ac36ed12 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/CallRRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class CallRRISC extends CallNode implements MachNode { CallRRISC( CallNode call ) { super(call); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java index c67d7b3d..68ed6f6c 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivFRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // fdiv.d public class DivFRISC extends MachConcreteNode implements MachNode{ diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java index 8367ee68..515ffa47 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/DivRISC.java @@ -1,6 +1,6 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; +import com.seaofnodes.simple.util.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java index be699280..81726200 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FltRISC.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class FltRISC extends ConstantNode implements MachNode, RIPRelSize { FltRISC(ConstantNode con) { super(con); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java index 84f0f4c7..6fce6244 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/FunRISC.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.FunNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class FunRISC extends FunNode implements MachNode { FunRISC(FunNode fun) {super(fun);} diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java index 5519fe5b..db0547fe 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/I2F8RISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // fcvt.d.w // Converts a 32-bit signed integer, in integer register rs1 into a double-precision floating-point number in floating-point register rd. diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java index 9e7f456a..f2beb25c 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/ImmRISC.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; import java.util.BitSet; abstract public class ImmRISC extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java index f9b7daee..edd1850f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/Int8RISC.java @@ -1,10 +1,9 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.node.ConstantNode; - -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; // Special instruction for loading 8 byte constants from the constant pool. diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java index 70d5c18f..f8af913a 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/IntRISC.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; // 12-bit integer constant. Larger constants are made up in the instruction // selection by adding with a LUI. diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java index b65afc79..7333f2b7 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LUI.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; // Load upper 20bits. public class LUI extends ConstantNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java index 7b0e9138..7e08a01d 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/LoadRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Load memory addressing on RISC // Support imm, reg(direct), or reg+off(indirect) addressing diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java index 8b84a2b9..93c90052 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MemOpRISC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java index c9917b4f..5cc40079 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulFRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // fmul.d public class MulFRISC extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java index a7961627..9cb9ace7 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/MulRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // mulh signed multiply instruction(no-imm form) public class MulRISC extends MachConcreteNode implements MachNode{ diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java index 77f4a497..d8183d09 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NegRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class NegRISC extends MachConcreteNode implements MachNode { public NegRISC( Node neg ) { super(neg); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java index e395a811..6c03bda6 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NewRISC.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.print.ASMPrinter; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class NewRISC extends NewNode implements MachNode, RIPRelSize { // A pre-zeroed chunk of memory. diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java index 9cbd5025..1369ee76 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/NotRISC.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.MachConcreteNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.NotNode; +import com.seaofnodes.simple.util.SB; public class NotRISC extends MachConcreteNode implements MachNode { public NotRISC(NotNode not) { super(not); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java index f6a888d9..963b9d50 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrIRISC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class OrIRISC extends ImmRISC { public OrIRISC( Node and, int imm) { super(and,imm); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java index 103d4c7d..a310a1f4 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/OrRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class OrRISC extends MachConcreteNode implements MachNode { public OrRISC(Node or) { super(or); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java index 8a8186cd..7e4631d3 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/RetRISC.java @@ -1,12 +1,12 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.node.FunNode; -import com.seaofnodes.simple.node.ReturnNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.node.ReturnNode; +import com.seaofnodes.simple.util.Utils; public class RetRISC extends ReturnNode implements MachNode { public RetRISC(ReturnNode ret, FunNode fun) { super(ret, fun); fun.setRet(this); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java index 9ee19e42..3424cd01 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetFRISC.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.BoolNode; import com.seaofnodes.simple.node.MachConcreteNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; // corresponds to feq.d = equal // fle.d = less than or equal diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java index f270bf12..690e2102 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetIRISC.java @@ -1,6 +1,6 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.Utils; import com.seaofnodes.simple.node.Node; // corresponds to slti,sltiu diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java index 8d4a2f71..848cc59f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SetRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // corresponds to slt sltu public class SetRISC extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java index 4edecc04..12c0ddec 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllIRISC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class SllIRISC extends ImmRISC { public SllIRISC( Node and, int imm) { super(and,imm); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java index 87e6693e..5a4d4cc6 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SllRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Shift left logical public class SllRISC extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java index 569fa2e0..6082cbbf 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SplitRISC.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.FunNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.node.SplitNode; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class SplitRISC extends SplitNode { SplitRISC( String kind, byte round ) { super(kind,round, new Node[2]); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java index 1533003c..fcfa0774 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraIRISC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class SraIRISC extends ImmRISC { public SraIRISC( Node and, int imm) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java index 1e930e72..e2e34415 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SraRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Right Shift Arithmetic public class SraRISC extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java index ed697678..2f73e139 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlIRISC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class SrlIRISC extends ImmRISC { public SrlIRISC( Node and, int imm, boolean pop) { super(and,imm,pop); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java index 47712585..1eccc1c8 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SrlRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Right Shift Logical public class SrlRISC extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java index 7305c4d9..d06c0c35 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/StoreRISC.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.codegen.RegMask; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Store memory addressing on ARM // Support imm, reg(direct), or reg+off(indirect) addressing diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java index 1e1b43c7..da3e92f4 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubFRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // fsub.d public class SubFRISC extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java index 7ab4f904..2adfce23 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/SubRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class SubRISC extends MachConcreteNode implements MachNode { public SubRISC( Node sub ) { super(sub); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java index 15be82bc..7e057507 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TFPRISC.java @@ -1,11 +1,12 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class TFPRISC extends ConstantNode implements MachNode, RIPRelSize { TFPRISC(ConstantNode con) { super(con); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java index 860e5eaf..44e73d1d 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/TMPRISC.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.SB; public class TMPRISC extends ConstantNode implements MachNode, RIPRelSize { TMPRISC(ConstantNode con) { super(con); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java index 6473d81c..c4d5d8af 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/UJmpRISC.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; // unconditional jump diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java index 27098033..19ea6bc7 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorIRISC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class XorIRISC extends ImmRISC { public XorIRISC( Node and, int imm) { super(and,imm); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java index 725d2b78..413a7c3b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/XorRISC.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class XorRISC extends MachConcreteNode implements MachNode { public XorRISC(Node or) { super(or); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java index 9c5bfa10..7a6361bc 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/riscv/riscv.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.riscv; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; public class riscv extends Machine { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java index d54c7c31..2513de37 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFMemX86.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class AddFMemX86 extends MemOpX86 { AddFMemX86( AddFNode add, LoadNode ld , Node base, Node idx, int off, int scale, Node val ) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java index a4166bc7..02e0c7ea 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddFX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class AddFX86 extends MachConcreteNode implements MachNode { AddFX86( Node addf ) { super(addf); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java index 050451f1..0ba390c6 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddIX86.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class AddIX86 extends ImmX86 { AddIX86( Node add, int imm ) { super(add,imm); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java index f97a7cb8..3ee721e3 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/AddMemX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class AddMemX86 extends MemOpX86 { AddMemX86( AddNode add, LoadNode ld , Node base, Node idx, int off, int scale, int imm, Node val ) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java index 1a74f817..460f568b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallRX86.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.CallNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; public class CallRX86 extends CallNode implements MachNode { CallRX86( CallNode call ) { super(call); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java index 4696c859..ffdce7df 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CallX86.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; public class CallX86 extends CallNode implements MachNode, RIPRelSize { final TypeFunPtr _tfp; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java index 35b92170..5b97ef63 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpFX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class CmpFX86 extends MachConcreteNode implements MachNode { CmpFX86( Node cmp ) { super(cmp); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java index 91b6d43c..8b8318eb 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpIX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Compare immediate. Sets flags. public class CmpIX86 extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java index a1845363..11f900ed 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpMemX86.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; public class CmpMemX86 extends MemOpX86 { final boolean _swap; // Op switched LHS, RHS diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java index 3e4200c0..e7305cdf 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/CmpX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class CmpX86 extends MachConcreteNode implements MachNode { CmpX86( Node add ) { super(add); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java index 9509a1f5..3427aea5 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivFX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class DivFX86 extends MachConcreteNode implements MachNode { DivFX86( Node divf) { super(divf); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java index 06f001b0..b5904a7f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/DivX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class DivX86 extends MachConcreteNode implements MachNode { DivX86( Node div ) { super(div); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java index e3b20003..9bcbac8f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FltX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class FltX86 extends ConstantNode implements MachNode, RIPRelSize{ private byte _encSize; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java index 07418eb0..cbd5fdbf 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/FunX86.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.node.FunNode; import com.seaofnodes.simple.node.MachNode; +import com.seaofnodes.simple.util.SB; public class FunX86 extends FunNode implements MachNode { FunX86( FunNode fun ) { super(fun); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java index d3213ae4..9f3d7905 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/I2f8X86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class I2f8X86 extends MachConcreteNode implements MachNode { I2f8X86(Node i2f8 ) { super(i2f8); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java index 95f617e7..5e406911 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ImmX86.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; public abstract class ImmX86 extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java index 6d9110f2..3f2f696c 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/IntX86.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; // Integer constants public class IntX86 extends ConstantNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java index d7acf8b8..de27aa5c 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/JmpX86.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Jump on flags, uses flags public class JmpX86 extends IfNode implements MachNode, RIPRelSize { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java index dce8a49a..2cd6018f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LeaX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class LeaX86 extends MachConcreteNode implements MachNode { final int _scale; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java index 6e72a540..441cf693 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/LoadX86.java @@ -1,14 +1,11 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.LoadNode; import com.seaofnodes.simple.node.Node; -import com.seaofnodes.simple.type.Type; -import com.seaofnodes.simple.type.TypeFloat; -import com.seaofnodes.simple.type.TypeInteger; -import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class LoadX86 extends MemOpX86 { LoadX86( LoadNode ld, Node base, Node idx, int off, int scale ) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java index f0d01b3d..bd56d022 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemAddX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class MemAddX86 extends MemOpX86 { MemAddX86( StoreNode st, Node base, Node idx, int off, int scale, int imm, Node val ) { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java index 97586d87..5f090717 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MemOpX86.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; - +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.lang.StringBuilder; import java.util.BitSet; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java index c1edb082..7932c893 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulFX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class MulFX86 extends MachConcreteNode implements MachNode { MulFX86( Node mulf) { super(mulf); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java index 0dc16ab1..280b8185 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulIX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.codegen.*; +import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class MulIX86 extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java index 3cd1f795..4d2a11ed 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/MulX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class MulX86 extends MachConcreteNode implements MachNode { MulX86( Node mul ) { super(mul); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java index b8b83cb0..0c2baced 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NegX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class NegX86 extends MachConcreteNode implements MachNode { NegX86(MinusNode not) { super(not); } @@ -10,6 +10,7 @@ public class NegX86 extends MachConcreteNode implements MachNode { @Override public RegMask regmap(int i) { return x86_64_v2.RMASK; } @Override public RegMask outregmap() { return x86_64_v2.RMASK; } @Override public RegMask killmap() { return x86_64_v2.FLAGS_MASK; } + @Override public int twoAddress() { return 1; } @Override public void encoding( Encoding enc ) { short dst = enc.reg(this ); diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java index 0439adfd..fc896dce 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NewX86.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; public class NewX86 extends NewNode implements MachNode { // A pre-zeroed chunk of memory. diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java index b23249b8..d9056be9 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/NotX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class NotX86 extends MachConcreteNode implements MachNode { NotX86(NotNode not) { super(not); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java index a4a6a814..5a475efe 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/RegX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public abstract class RegX86 extends MachConcreteNode { RegX86( Node add ) { super(add); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java index 07256604..95e0c336 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarIX86.java @@ -1,13 +1,12 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.codegen.RegMask; +import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.node.MachNode; import com.seaofnodes.simple.node.Node; - -import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; // Arithmetic Right Shift public class SarIX86 extends MachConcreteNode implements MachNode { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java index b1be643c..4cc8b558 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SarX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class SarX86 extends RegX86 { SarX86( Node add ) { super(add); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java index 775ea8eb..0eff2afe 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SetX86.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; // Corresponds to the x86 instruction "sete && setne". // Use result of comparison without jump. diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java index 0b75b456..f7b2f28a 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlIX86.java @@ -1,10 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.node.Node; - -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; public class ShlIX86 extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java index 9f358575..5fee72d9 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShlX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class ShlX86 extends RegX86 { ShlX86( Node add ) { super(add); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java index 893eb23d..7e0378b1 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrIX86.java @@ -1,10 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.node.Node; - -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.SB; public class ShrIX86 extends MachConcreteNode implements MachNode { final int _imm; diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java index d869260f..67dcf055 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/ShrX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.Node; +import com.seaofnodes.simple.util.Utils; public class ShrX86 extends RegX86 { ShrX86( Node add ) { super(add); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java index 960ea6f8..4a14240a 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SplitX86.java @@ -1,7 +1,5 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.FunNode; import com.seaofnodes.simple.node.Node; @@ -9,6 +7,8 @@ import com.seaofnodes.simple.node.SplitNode; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; import com.seaofnodes.simple.type.TypeInteger; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; public class SplitX86 extends SplitNode { SplitX86( String kind, byte round ) { super(kind,round, new Node[2]); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java index 76fb4e8d..4403b02b 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/StoreX86.java @@ -1,12 +1,12 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.ConstantNode; import com.seaofnodes.simple.node.Node; import com.seaofnodes.simple.node.StoreNode; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFloat; +import com.seaofnodes.simple.util.SB; import java.util.BitSet; public class StoreX86 extends MemOpX86 { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java index 0a169a22..b6530a87 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/SubFX86.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; +import com.seaofnodes.simple.util.SB; public class SubFX86 extends MachConcreteNode implements MachNode { SubFX86( Node subf) { super(subf); } diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java index d7566f9e..359b6d83 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TFPX86.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.node.cpus.riscv.riscv; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.SB; // Function constants public class TFPX86 extends ConstantNode implements MachNode, RIPRelSize { diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java index c44cf2f9..c23f6c5f 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/TMPX86.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.SB; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeMemPtr; +import com.seaofnodes.simple.util.SB; public class TMPX86 extends ConstantNode implements MachNode, RIPRelSize{ TMPX86(ConstantNode con ) { super(con); } @@ -17,7 +17,11 @@ public class TMPX86 extends ConstantNode implements MachNode, RIPRelSize{ short dst = enc.reg(this); x86_64_v2.rexF(dst, 0, 0, true, enc); enc.add1(0x8D).add1(x86_64_v2.modrm(x86_64_v2.MOD.INDIRECT, dst, 0b101)).add4(0); - enc.largeConstant(this,((TypeMemPtr)_con)._obj,7-4,2/*ELF encoding PC32*/); + int opLen = 1/*rexF*/+1/*opcode 0x8D*/+1/*modrm*/+4/*pc rel offset*/; + // Base of constant array + TypeMemPtr tmp = (TypeMemPtr)_con; + int baseOff = tmp._obj.aryBase(); + enc.largeConstant(this,tmp._obj,opLen-baseOff,2/*ELF encoding PC32*/); } // Delta is from opcode start diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java index ec4eeb3b..92d2a87d 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/UJmpX86.java @@ -1,9 +1,10 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.*; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.Type; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.BitSet; // unconditional jump diff --git a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java index 6706635f..026e12aa 100644 --- a/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java +++ b/src/main/java/com/seaofnodes/simple/node/cpus/x86_64_v2/x86_64_v2.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.node.cpus.x86_64_v2; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.*; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Utils; public class x86_64_v2 extends Machine { public x86_64_v2( CodeGen code ) {} @@ -486,7 +486,8 @@ public class x86_64_v2 extends Machine { return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(rhs), val, false); // Operands swap in the encoding directly, no need for Set/Jmp to swap `bop` - if( rhs instanceof LoadNode ld && ld.nOuts() == 1 && lhs._type.isa(ld._declaredType)) + if( rhs instanceof LoadNode ld && ld.nOuts() == 1 && lhs._type.isa(ld._declaredType) && + (val!=null || bool.op()=="==" || bool.op()=="!=") ) return new CmpMemX86(bool, address(ld), ld.ptr(), idx, off, scale, imm(lhs), val, true ); // Vs immediate diff --git a/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java b/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java index 366ae376..a9f86ce8 100644 --- a/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java +++ b/src/main/java/com/seaofnodes/simple/print/ASMPrinter.java @@ -1,13 +1,13 @@ package com.seaofnodes.simple.print; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.CodeGen; -import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.codegen.Encoding.Relo; +import com.seaofnodes.simple.codegen.Encoding; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.HashSet; public abstract class ASMPrinter { @@ -98,7 +98,8 @@ public abstract class ASMPrinter { if( fun._name != null ) sb.p(fun._name).p(" "); fun.sig().print(sb); sb.p("---------------------------").nl(); - iadr = (iadr + 15)&-16; // All function entries padded to 16 align + if( code._encoding!=null && code._encoding._padFunHeads ) + iadr = (iadr + 15)&-16; // All function entries padded to 16 align if( fun._frameAdjust != 0 ) iadr = doInst(iadr,sb,code,fun,cfgidx,fun,true,true); diff --git a/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java b/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java index e4cf2c31..20c8439a 100644 --- a/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java +++ b/src/main/java/com/seaofnodes/simple/print/GraphVisualizer.java @@ -3,7 +3,7 @@ package com.seaofnodes.simple.print; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.node.*; import java.util.*; -import static com.seaofnodes.simple.Utils.TODO; +import static com.seaofnodes.simple.util.Utils.TODO; /** * Simple visualizer that outputs GraphViz dot format. @@ -155,7 +155,7 @@ public class GraphVisualizer { private void scope( StringBuilder sb, ScopeNode scope ) { sb.append("\tnode [shape=plaintext];\n"); int last = scope.nIns(); - int max = scope._lexSize.size(); + int max = scope.depth(); for( int i = 0; i < max; i++ ) { int level = max-i-1; String scopeName = makeScopeName(scope, level); @@ -169,7 +169,7 @@ public class GraphVisualizer { sb.append("\t\t\t<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n"); // Add the scope level sb.append("\t\t\t<TR><TD BGCOLOR=\"cyan\">").append(level).append("</TD>"); - int lexStart=scope._lexSize.at(level); + int lexStart = scope._kinds.at(level)._lexSize; for( int j=lexStart; j<last; j++ ) { var v = scope._vars.at(j); sb.append("<TD PORT=\"").append(makePortName(scopeName, v._name)).append("\">").append(v._name).append("</TD>"); @@ -243,7 +243,7 @@ public class GraphVisualizer { while( def instanceof ScopeNode lazy ) def = lazy.in(v._idx); if( def==null ) continue; - while( level < scope._lexSize.size() && v._idx >= scope._lexSize.at(level) ) + while( level < scope.depth() && v._idx >= scope._kinds.at(level)._lexSize ) level++; String scopeName = makeScopeName(scope, level-1); sb.append("\t") diff --git a/src/main/java/com/seaofnodes/simple/print/IRPrinter.java b/src/main/java/com/seaofnodes/simple/print/IRPrinter.java index c6e478c5..d1265bef 100644 --- a/src/main/java/com/seaofnodes/simple/print/IRPrinter.java +++ b/src/main/java/com/seaofnodes/simple/print/IRPrinter.java @@ -1,11 +1,11 @@ package com.seaofnodes.simple.print; -import com.seaofnodes.simple.Ary; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.TypeFunPtr; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.ArrayList; import java.util.BitSet; import java.util.HashMap; @@ -61,7 +61,7 @@ public abstract class IRPrinter { if( n instanceof CFGNode || n instanceof MultiNode ) { if( !gap ) sb.p("\n"); // Blank before multihead if( n instanceof FunNode fun ) - fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" "),false).p("----------------------\n"); + fun.sig().print(sb.p("--- ").p(fun._name==null ? "" : fun._name).p(" ")).p("----------------------\n"); printLine( n, sb ); // Print head while( --i >= 0 ) { Node t = rpos.get(i); @@ -72,7 +72,7 @@ public abstract class IRPrinter { FunNode fun = ret.fun(); sb.p("--- "); if( fun != null ) - fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" "),false); + fun.sig().print(sb.p(fun._name==null ? "" : fun._name).p(" ")); sb.p("----------------------\n"); } if( !(n instanceof CallNode) ) { diff --git a/src/main/java/com/seaofnodes/simple/print/JSViewer.java b/src/main/java/com/seaofnodes/simple/print/JSViewer.java index 76c64c71..62ff0001 100644 --- a/src/main/java/com/seaofnodes/simple/print/JSViewer.java +++ b/src/main/java/com/seaofnodes/simple/print/JSViewer.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.print; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.node.*; import com.seaofnodes.simple.type.*; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.io.IOException; import java.nio.file.Paths; import java.util.Collection; @@ -192,14 +192,14 @@ public class JSViewer implements AutoCloseable { private static void scope( SB sb, ScopeNode scope ) { sb.i().p("node [shape=plaintext];\n"); int last = scope.nIns(); - int max = scope._lexSize.size()+1; // One more than lexsize + int max = scope.depth()+1; // One more than lexsize for( int i = 0; i < max; i++ ) { int level = max-i-1; String scopeName = makeScopeName(scope, level); sb.i().p("subgraph cluster_").p(scopeName).p(" {\n").ii(); // Magic "cluster_" in the subgraph name sb.i().p(scopeName).p(" [label=<\n").ii(); sb.i().p("<TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\">\n"); - int lexStart = level==0 ? 0 : scope._lexSize.at(level-1); + int lexStart = level==0 ? 0 : scope._kinds.at(level-1)._lexSize; // Special for memory ScopeMinNode MemMergeNode n = scope.nIns()>1 ? scope.mem() : null; @@ -365,7 +365,7 @@ public class JSViewer implements AutoCloseable { while( def instanceof ScopeNode lazy ) def = lazy.in(v._idx); if( def==null ) continue; - while( level < scope._lexSize.size() && v._idx >= scope._lexSize.at(level) ) + while( level < scope.depth() && v._idx >= scope._kinds.at(level)._lexSize ) level++; String scopeName = makeScopeName(scope, level); sb.i() diff --git a/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java b/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java index 7655213d..4077533d 100644 --- a/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java +++ b/src/main/java/com/seaofnodes/simple/print/SimpleWebSocket.java @@ -1,6 +1,6 @@ package com.seaofnodes.simple.print; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.Utils; import java.io.*; import java.net.ServerSocket; import java.net.Socket; diff --git a/src/main/java/com/seaofnodes/simple/sys/sys.smp b/src/main/java/com/seaofnodes/simple/sys/sys.smp deleted file mode 100644 index 4ac925db..00000000 --- a/src/main/java/com/seaofnodes/simple/sys/sys.smp +++ /dev/null @@ -1,58 +0,0 @@ -// -*- mode: java; -*- - -// top-level default import -struct sys { - // libc bindings - /** https://www.man7.org/linux/man-pages/man2/<libc call>.2.html */ - struct libc { - i32 errno = "C"; - // fd buf len -> len - { i32 i64 u32 -> u32 } write = "C"; - // fd buf len -> len - { i32 i64 u32 -> u32 } read = "C"; - // status - { i32 -> i32 } _exit = "C"; - // addr len prot flags fd off -> void* - { i64 i64 i32 i32 i32 i32 -> i64 } mmap = "C"; - // mmap flags - i32 PROT_EXEC = 4; - i32 PROT_READ = 1; - i32 PROT_WRITE= 2; - i32 PROT_NONE = 0; - i32 MAP_PRIVATE = 2; - i32 MAP_ANON = 32; - }; - struct ary { - val copy = { u8[] dst, int doff, u8[~] src, int soff, int len -> - for( int i=0; i<len; i++ ) - dst[i+doff] = src[i+soff]; - return dst; - }; - }; - struct io { - // Print string to stdout - val p = { u8[~] str -> - i64 ptr = str; // cast array base to i64 - return sys.libc.write(1,ptr,str#); - }; - - // Return stdin as a u8[] - val stdin = { -> - var buf = new u8[8*1024]; - i64 ptr = buf; - int len = 0; - while( true ) { - int rez = sys.libc.read(0,ptr,buf#); - if( rez < 0 ) sys.libc._exit(sys.libc.errno); - len += rez; - if( rez < buf# ) - break; - sys.libc._exit(-2); // Need to implement - } - // Compress - var dst = new u8[len]; - return sys.ary.copy(dst,0,buf,0,len); - }; - - }; -}; diff --git a/src/main/java/com/seaofnodes/simple/type/Field.java b/src/main/java/com/seaofnodes/simple/type/Field.java index ad96369b..b2b2deca 100644 --- a/src/main/java/com/seaofnodes/simple/type/Field.java +++ b/src/main/java/com/seaofnodes/simple/type/Field.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import java.util.ArrayList; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import java.util.*; /** * Represents a field in a struct. This is not a Type in the type system. @@ -12,65 +12,125 @@ public class Field extends Type { // The pair {fieldName,type} uniquely identifies a field. // Field name - public final String _fname; + public String _fname; // Type of the field - public final Type _type; + public Type _t; // Unique memory alias, not sensibly part of a "type" but very convenient here. - public final int _alias; + public int _alias; // Field must be written to exactly once, no more, no less - public final boolean _final; + public boolean _final; + // Field is final in the declaration; value is the same for all instances + // and will be moved to the class object + public boolean _one; - private Field(String fname, Type type, int alias, boolean xfinal ) { - super(TFLD); + private static final Ary<Field> FREE = new Ary<>(Field.class); + private Field(String fname, Type type, int alias, boolean xfinal, boolean one ) { super(TFLD); init(fname,type,alias,xfinal,one); } + private Field init(String fname, Type type, int alias, boolean xfinal, boolean one ) { _fname = fname; - _type = type; + _t = type; _alias = alias; _final = xfinal; + _one = one; + return this; } - // Make with existing alias - public static Field make( String fname, Type type, int alias, boolean xfinal ) { - return new Field(fname,type,alias,xfinal).intern(); + + // Return a filled-in Field; either from free list or alloc new. + private static Field malloc(String fname, Type type, int alias, boolean xfinal, boolean one ) { + return FREE.isEmpty() ? new Field(fname,type,alias,xfinal,one) : FREE.pop().init(fname,type,alias,xfinal,one); + } + // Malloc-from + public Field malloc( ) { return malloc(_fname,null,_alias,_final,_one); } + @Override Field free(Type t) { + Field f = (Field)t; + assert !f.isFree() && !f._terned; + f._t = null; + f._dual = null; + f._hash = 0; + FREE.push(f); + return this; + } + @Override boolean isFree() { return _t ==null; } + + // Make and intern with listed fields + public static Field make( String fname, Type type, int alias, boolean xfinal, boolean one ) { + Field f = malloc(fname,type,alias,xfinal,one); + Field f2 = f.intern(); + if( f2==f ) return f; + return VISIT.isEmpty() ? f2.free(f) : f2.delayFree(f); } public Field makeFrom( Type type ) { - return type == _type ? this : new Field(_fname,type,_alias,_final).intern(); + return type == _t ? this : make(_fname,type,_alias,_final,_one); + } + public Field makeFrom( boolean xfinal ) { + return xfinal == _final ? this : make(_fname,_t,_alias,xfinal,_one); } - @Override public Field makeRO() { return _final ? this : make(_fname,_type.makeRO(),_alias,true); } - @Override public boolean isFinal() { return _final && _type.isFinal(); } - public static final Field TEST = make("test",Type.NIL,-2,false); - public static final Field TEST2= make("test",Type.NIL,-2,true); - public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST2); } + // Cycle-making-breaking + void setType(Type t) { assert _t ==null; _t = t; } + + public static final Field BOT = make(" ",Type.BOTTOM,-999,true,false); + public static final Field TEST = make("test",Type.NIL,-2,false,false); + public static final Field TEST2 = make("test",Type.NIL,-2,true, false); + public static final Field FLT = make("flt ",TypeFloat.F32,-2,false,false); + public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST2); ts.add(FLT); } @Override Field xmeet( Type that ) { Field fld = (Field)that; // Invariant - assert _fname.equals(fld._fname); + if( this==BOT || fld==BOT ) return BOT; + if( this==BOT.dual() ) return fld ; + if( fld ==BOT.dual() ) return this; + if( _fname!=fld._fname ) { assert !_fname.equals(fld._fname); return BOT; } assert _alias==fld._alias; - return make(_fname,_type.meet(fld._type),_alias,_final | fld._final); + assert _one ==fld._one ; + return make(_fname, _t.meet(fld._t ),_alias,_final | fld._final, _one); } @Override - public Field dual() { return make(_fname,_type.dual(),_alias,!_final); } + Field xdual() { return malloc(_fname, _t.dual(),_alias,!_final,_one); } - @Override public boolean isConstant() { return _type.isConstant(); } + @Override Field rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + Field d = malloc(_fname,null,_alias,!_final,_one); + (_dual = d)._dual = this; // Cross link duals + d._t = _t._terned ? _t.dual() : _t.rdual(); + return d; + } - @Override public Field glb(boolean mem) { - Type glb = _type.glb(mem); - return (glb==_type && _final) ? this : make(_fname,glb,_alias,true); + @Override boolean _isConstant() { return _t._isConstant(); } + @Override boolean _isFinal() { return _final && _t._isFinal(); } + @Override Field _makeRO() { return _final ? this : make(_fname, _t._makeRO(),_alias,true,_one); } + boolean isGLB2() { return _final && _t._isGLB(true); } + Field glb2() { + Type glb = _t._glb(true); + return (glb== _t && _final ) ? this : make(_fname,glb,_alias,true,_one); } + @Override Field _close() { return makeFrom( _t._close()); } // Override in subclasses - int hash() { return _fname.hashCode() ^ _type.hashCode() ^ _alias ^ (_final ? 1024 : 0); } + int hash() { return _fname.hashCode() ^ _t.hashCode() ^ _alias ^ (_final ? 1024 : 0) ^ (_one ? 2048 : 0); } - boolean eq(Type t) { + private boolean static_eq( Field f ) { + return _fname.equals(f._fname) && _alias==f._alias && _final==f._final && _one==f._one && _t !=null && f._t !=null; + } + @Override boolean eq( Type t ) { + Field f = (Field)t; + return static_eq(f) && _t ==f._t; + } + @Override boolean cycle_eq(Type t) { Field f = (Field)t; - return _fname.equals(f._fname) && _type==f._type && _alias==f._alias && _final==f._final; + return static_eq(f) && _t.cycle_eq(f._t ); } + @Override int nkids() { return 1; } + @Override Type at( int idx ) { return _t; } + @Override void set( int idx, Type t ) { _t = t; } @Override - public SB print( SB sb ) { - return _type.print(sb.p(_final?"":"!").p(_fname).p(":").p(_alias).p(" : ")); + public SB _print( SB sb, BitSet visit, boolean html ) { + sb.p(_final?"":"!").p(_one?"$":"").p(_fname).p(":").p(_alias).p(" : "); + return _t ==null ? sb.p("---") : _t.print(sb,visit,html); } - @Override public String str() { return (_final?"":"!")+_fname; } + @Override public String str() { return (_final?"":"!")+(_one?"$":"")+_fname; } } diff --git a/src/main/java/com/seaofnodes/simple/type/Type.java b/src/main/java/com/seaofnodes/simple/type/Type.java index a44cdd61..b7a8408e 100644 --- a/src/main/java/com/seaofnodes/simple/type/Type.java +++ b/src/main/java/com/seaofnodes/simple/type/Type.java @@ -1,9 +1,7 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import java.util.ArrayList; -import java.util.HashMap; +import com.seaofnodes.simple.util.*; +import java.util.*; /** * These types are part of a Monotone Analysis Framework, @@ -21,8 +19,33 @@ import java.util.HashMap; * simple constant folding e.g. 1+2 == 3 stuff. */ -public class Type { +public class Type /*implements Cloneable*/ { + // Interning tables + + // Main intern table; a collection of all unique types. static final HashMap<Type,Type> INTERN = new HashMap<>(); + // Starting intern table; used to rapidly reset the main table between tests + private static final HashMap<Type,Type> INTERN0= new HashMap<>(); + // Lifetime management during cyclic installs is complex; this is used to + // track created-but-already-interned objects + private static final Ary<Type> FREES = new Ary<>(Type.class); + // "visit" bit management, based solely on _uid + static final BitSet BITS = new BitSet(); + + // "visit" bit management. Key varies by kind of visit: + + // - "close" an open cyclic type. Used by the Parser, it will hit on + // same-named structs, even if the structs have different states of + // completion/fields. + // - "uid/name" - Either the UID or name works (unlike "close" which must + // use the name). Used to make cyclic copies with changes, like make + // read-only where there should be only 1 copy of a name in a cycle. + // - "pair of uids" - For recursive MEET, where we need to key off two types + static final HashMap<Object,Type> VISIT = new HashMap<>(); + + // Every Type has a UID to allow visit bits on cyclic visits + private static int UID=1; + public char _uid; // Unique ID for every type // ---------------------------------------------------------- // Simple types are implemented fully here. "Simple" means: the code and @@ -38,33 +61,42 @@ public class Type { static final byte TPTR = 7; // All nil-able scalar values static final byte TINT = 8; // All Integers; see TypeInteger static final byte TFLT = 9; // All Floats ; see TypeFloat - static final byte TMEMPTR =10; // Memory pointer to a struct type - static final byte TFUNPTR =11; // Function pointer; unique signature and code address (just a bit) + static final byte TCONARY =10; // Constant array + static final byte TRPC =11; // Return Program Control (Return PC or RPC) static final byte TTUPLE =12; // Tuples; finite collections of unrelated Types, kept in parallel - static final byte TMEM =13; // All memory (alias 0) or A slice of memory - with specific alias - static final byte TSTRUCT =14; // Structs; tuples with named fields - static final byte TFLD =15; // Named fields in structs - static final byte TCONARY =16; // Constant array - static final byte TRPC =17; // Return Program Control (Return PC or RPC) + static final byte TCYCLIC =13; // Has internal pointers, needs recursive treatment + static final byte TMEMPTR =13; // Memory pointer to a struct type + static final byte TFUNPTR =14; // Function pointer; unique signature and code address (just a bit) + static final byte TMEM =15; // All memory (alias 0) or A slice of memory - with specific alias + static final byte TSTRUCT =16; // Structs; tuples with named fields + static final byte TFLD =17; // Named fields in structs + + // Basic RTTI, useful for a lot of fast tests. public final byte _type; + public boolean _terned; public boolean is_simple() { return _type < TSIMPLE; } private static final String[] STRS = new String[]{"Bot","Top","Ctrl","~Ctrl","null","~nil"}; - protected Type(byte type) { _type = type; } + static final int[] CNTS = new int[TFLD+1]; + protected Type(byte type) { + _type = type; // RTTI + _uid = (char)UID++; // A unique ID for every type + assert _uid!=0; // Overflow + CNTS[type]++; + } public static final Type BOTTOM = new Type( TBOT ).intern(); // ALL - public static final Type TOP = new Type( TTOP ).intern(); // ANY + public static final Type TOP = BOTTOM.dual(); public static final Type CONTROL = new Type( TCTRL ).intern(); // Ctrl - public static final Type XCONTROL = new Type( TXCTRL ).intern(); // ~Ctrl + public static final Type XCONTROL = CONTROL.dual(); public static final Type NIL = new Type( TNIL ).intern(); // low null of all flavors - public static final Type XNIL = new Type( TXNIL ).intern(); // high or choice null + public static final Type XNIL = NIL.dual(); public static Type[] gather() { ArrayList<Type> ts = new ArrayList<>(); ts.add(BOTTOM); ts.add(CONTROL); ts.add(NIL); - ts.add(XNIL); TypeNil.gather(ts); TypePtr.gather(ts); TypeInteger.gather(ts); @@ -77,6 +109,7 @@ public class Type { TypeTuple.gather(ts); TypeRPC.gather(ts); TypeConAry.gather(ts); + int sz = ts.size(); for( int i = 0; i < sz; i++ ) ts.add(ts.get(i).dual()); @@ -87,10 +120,6 @@ public class Type { public boolean isHigh () { return _type==TTOP || _type==TXCTRL || _type==TXNIL; } public boolean isHighOrConst() { return isHigh() || isConstant(); } - // Strict constant values, things on the lattice centerline. - // Excludes both high and low values - public boolean isConstant() { return _type==TNIL; } - // ---------------------------------------------------------- // Notes on Type interning: At the moment it is not easy to reset the @@ -106,14 +135,68 @@ public class Type { // Factory method which interns "this" @SuppressWarnings("unchecked") - public <T extends Type> T intern() { - T nnn = (T)INTERN.get(this); - if( nnn==null ) - INTERN.put(nnn=(T)this,this); - return nnn; + <T extends Type> T intern() { + //assert check(); + assert !_terned; // Do not ask for already-interned + T t2 = (T)INTERN.get(this); + if( t2!=null ) { + assert t2._dual != null; // Prior is complete with dual + assert this != t2; // Do not hashcons twice, should not get self back + return t2; // Return prior + } + // Mid recursive type construction + if( !VISIT.isEmpty() && _type >= TCYCLIC ) { + // No intern attempt at all + return (T)this; + } + // Not in type table + _dual = null; // No dual yet + INTERN.put(this,this); // Put in table without dual + _terned = true; + //Util.hash_quality_check_per(INTERN,"INTERN"); + T d = xdual(); // Compute dual without requiring table lookup, and not setting name + _dual = d; + if( this==d ) return d; // Self-symmetric? Dual is self + assert !equals(d); // Self-symmetric is handled by caller + assert d._dual==null; // Else dual-dual not computed yet + assert INTERN.get(d)==null; + d._dual = (T)this; + INTERN.put(d,d); // Install dual also + d._terned = true; + //assert check(); + return (T)this; + } + + // Recursive visit elsewhere, interns with dual already + <T extends Type> T _intern() { + //assert check(); + assert !_terned; + Type t = INTERN.get(this); + if( t!=null ) return (T)t.delayFree(this).delayFree(_dual); + assert !INTERN.containsKey( _dual ); + INTERN.put(this,this); + INTERN.put(_dual,_dual); + _terned = _dual._terned = true; + //assert check(); + return (T)this; } - private int _hash; // Hash cache; not-zero when set. + private static boolean check() { + for( Type t : INTERN.keySet() ) { + Type t2 = INTERN.get(t); + assert t==t2; + } + return true; + } + + public static Type find(int uid) { + for( Type t : INTERN.keySet() ) + if( t._uid==uid ) return t; + return null; + } + + + int _hash; // Hash cache; not-zero when set. @Override public final int hashCode() { if( _hash!=0 ) return _hash; @@ -132,8 +215,42 @@ public class Type { return eq(t); } // Overridden in subclasses; subclass can assume "this!=t" and java classes are same - boolean eq(Type t) { return true; } + boolean eq(Type t) { return this==t; } + boolean cycle_eq(Type t) { assert _type < TCYCLIC; return eq(t); } + // A pair of uids + int pid( Type that ) { + return _uid < that._uid ? (_uid<<16 | that._uid) : (that._uid<<16 | _uid); + } + // At/Set child at 'idx' to t + Type at ( int idx ) { throw Utils.TODO(); } + void set( int idx, Type t ) { throw Utils.TODO(); } + int nkids() { assert _type < TTUPLE; return 0; } // Number of kids + + + // Clear and re-insert the basic Type INTERN table + public static void reset() { + VISIT.clear(); + FREES.clear(); + if( INTERN0.isEmpty() ) { + // First time run all <clinit> and collect basic types + Type t = TypeRPC .BOT; // Force class load, intern + Type u = TypeTuple.BOT; // Force class load, intern + Type w = TypePtr .PTR; // Force class load, intern + INTERN0.putAll(INTERN); + } else { + // Later times, reset back to first time + VISIT.put(0,CONTROL); // Defeat assert + for( Iterator<Type> it = INTERN.keySet().iterator(); it.hasNext(); ) { + Type t = it.next(); + if( !INTERN0.containsKey(t) ) + { t._terned=false; t.free(t); } + it.remove(); + } + VISIT.clear(); + INTERN.putAll(INTERN0); + } + } // ---------------------------------------------------------- public final Type meet(Type t) { @@ -172,18 +289,24 @@ public class Type { return _type==TCTRL || t._type==TCTRL ? CONTROL : XCONTROL; } - public Type dual() { - return switch( _type ) { - case TBOT -> TOP; - case TTOP -> BOTTOM; - case TCTRL ->XCONTROL; - case TXCTRL-> CONTROL; - case TNIL ->XNIL; - case TXNIL -> NIL; + + // The dual is pre-computed on creation and available "for free" thereafter + Type _dual; + public final <T extends Type> T dual() { return (T)_dual; } + + <T extends Type> T xdual() { + return (T)new Type(switch( _type ) { + case TBOT -> TTOP; + case TTOP -> TBOT; + case TCTRL -> TXCTRL; + case TXCTRL-> TCTRL; + case TNIL -> TXNIL; + case TXNIL -> TNIL; default -> throw Utils.TODO(); // Should not reach here - }; + }); } + // ---------------------------------------------------------- // Our lattice is defined with a MEET and a DUAL. // JOIN is dual of meet of both duals. @@ -203,18 +326,157 @@ 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. 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; } - // All reachable struct Fields are final - public boolean isFinal() { return true; } + // ---------------------------------------------------------- - // Make all reachable struct Fields final - public Type makeRO() { return this; } + // Cyclic types! Flag the start of a cyclic type by putting a sentinel in + // VISIT (and eventually clearing VISIT when done). Then do a normal + // recursive descent visit of all types; this will accumilate types without + // interning them. When done we have to visit the possibly cyclic type and + // intern the whole cycle, possibly hitting the entire cycle on a prior + // interned cycle. Any sub-part might also be interned, including whole + // disjoint cycles. + + // E.g. a new type: "A<->B -> C1<->D1" gets created; the "C1<->D1" cycle + // already exists as "C0<->D0", but the "A<->B" cycle is new. The "A<->B" + // cycle will get interned - except the pointer to C1 needs to get replaced + // with C0. The "C1<->D1" cycle gets freed and "B" will point to the + // "C0<->D0" cycle. + + Type recurOpen() { assert VISIT.isEmpty(); VISIT.put(0L,BOTTOM); return this; } + Type recurClose() { + VISIT.remove(0L); // Just ignore the sentinel + Ary<Type> ts = new Ary<>(Type.class); + ts.addAll(VISIT.values()); + if( ts.find(this)== -1 ) ts.add(this); + + // Pass #1: replace already interned fields + assert BITS.isEmpty(); + for( int i=0; i<ts._len; i++ ) + if( ts.at(i).tern()._terned ) + ts.del(i--); + BITS.clear(); + + // Pass#2: compute recursive duals + for( Type t : ts ) + t.rdual(); + + // Pass#3: Recursive install + for( Type t : ts ) + if( !t._terned && INTERN.get(t)==null ) + t.install(); + // Upgrade the result + Type rez = INTERN.get(this); + assert rez!=null; + + // Pass#4?: Free up any created-but-already interned + for( Type t : FREES ) + t.rfree(); + FREES.clear(); + VISIT.clear(); + return rez; + } + + // Read-only recursive visits do not *make* cyclic types and so the cleanup + // is much easier. + static boolean recurClose(boolean rez) { VISIT.clear(); return rez; } + + final Type tern() { + if( _terned ) return this; + if( !BITS.get(_uid) ) { + BITS.set(_uid); + int nkids = nkids(); + for( int i=0; i<nkids; i++ ) + set(i,at(i).tern()); + } + Type told = INTERN.get(this); + return told==null ? this : told.delayFree(this); + } + + // Recursive dual. Visit all types recursively. Each visited type is + // *new*, and hits in the intern table, or not. If not, we recursively + // call rdual to get its dual, and cross-link the duals. If hitting, we + // use the intern type and mark the prior type for freeing. + Type rdual() { assert !_terned; return xdual(); } + + // Recursively free type and children + final void rfree() { + if( isFree() ) return; + int nkids = nkids(); + for( int i=0; i<nkids; i++ ) + if( !at(i)._terned ) + at(i).rfree(); + free(this); + } + + Type free(Type free) { return this; } + boolean isFree() { return false; } + + <T extends Type> T delayFree(Type free) { + assert !free._terned; + FREES.push(free); + return (T)this; + } + + final Type install() { + if( this instanceof TypeStruct ) { + Type x = _intern(); // Stop the recursion + assert x==this; + } + int nkids = nkids(); + for( int i=0; i<nkids; i++ ) { + Type kid = at(i); + if( !kid._terned ) { + Type ikid = kid.install(); + if( ikid != kid ) { + set(i,ikid); + _dual.set(i,ikid.dual()); + } + } + } + return this instanceof TypeStruct ? this : _intern(); + } + + // Strict constant values, things on the lattice centerline. + // Excludes both high and low values + public final boolean isConstant() { return recurClose(recurOpen()._isConstant()); } + boolean _isConstant() { return _type==TNIL; } + + // Are all reachable struct Fields are final? + public final boolean isFinal() { return recurClose(recurOpen()._isFinal()); } + boolean _isFinal() { assert _type < TCYCLIC; return true; } + + public final Type makeRO() { + if( isFinal() ) return this; + return recurOpen()._makeRO().recurClose(); + } + Type _makeRO() { return this; } + + // Compute greatest lower bound in the lattice. If values are in memory, + // ints and floats cannot widen. + public final boolean isGLB(boolean mem) { return recurClose(recurOpen()._isGLB(mem)); }; + boolean _isGLB(boolean mem) { + return switch(_type) { + case TBOT -> false; + case TNIL -> false; + case TCTRL -> true; + case TXCTRL -> false; + case TXNIL -> false; + case TTOP -> false; + default -> throw Utils.TODO(); + }; + } + public final Type glb(boolean mem) { + if( isGLB(mem) ) return this; + Type glb = recurOpen()._glb(mem).recurClose(); + assert this.isa(glb); + return glb; + } + Type _glb(boolean mem) { assert is_simple(); return Type.BOTTOM; } + + Type _close() { return this; } // ---------------------------------------------------------- @@ -231,11 +493,21 @@ public class Type { // This is a more verbose dev-friendly print. @Override public final String toString() { - return print(new SB()).toString(); + return print(new SB(), new BitSet(), false).toString(); } - - public SB print(SB sb) { return sb.p(str()); } - public SB gprint(SB sb) { return print(sb); } + public final String gprint() { + return print(new SB(), new BitSet(), true).toString(); + } + public final SB print(SB sb) { return print(sb, new BitSet(), false); } + public final SB gprint(SB sb) { return print(sb, new BitSet(), true ); } + + // Used during recursive printing, or combined with SB Node printing + public final SB print(SB sb, BitSet visit, boolean html ) { + if( visit.get(_uid) ) return sb.p(str()); + visit.set(_uid); + return _print(sb,visit,html); + } + SB _print(SB sb, BitSet visit, boolean html ) { return sb.p(str()); } // This is used by error messages, and is a shorted print. public String str() { return STRS[_type]; } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeConAry.java b/src/main/java/com/seaofnodes/simple/type/TypeConAry.java index 29496af6..d4003f87 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeConAry.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeConAry.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import java.util.ArrayList; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.io.ByteArrayOutputStream; +import java.util.ArrayList; /** * Represents a constant array of primitives @@ -13,9 +13,8 @@ public class TypeConAry<A> extends Type { // One of byte,short,int,long,float,double array public final A _ary; - TypeConAry( boolean any, A ary ) { super(TCONARY); _any = any; _ary = ary; } - private static final TypeConAry TOP = new TypeConAry(true ,null).intern(); - public static final TypeConAry BOT = new TypeConAry(false,null).intern(); + TypeConAry( boolean any, byte type, A ary ) { super(type); _any = any; _ary = ary; } + public static final TypeConAry BOT = new TypeConAry(false, TINT, null).intern(); public static void gather(ArrayList<Type> ts) { ts.add(BOT); TypeConAryB.gather(ts); @@ -23,42 +22,56 @@ public class TypeConAry<A> extends Type { } @Override public String str() { return (_any?"~":"") + "[]"; } - @Override public boolean isConstant() { return true; } - @Override public TypeConAry dual() { - if( this== BOT ) return TOP; - if( this== TOP ) return BOT; + @Override TypeConAry xdual() { + if( _ary==null ) + return new TypeConAry(!_any,_type,null); return this; } @Override Type xmeet(Type t) { + if( t instanceof TypeInteger ti ) return imeet(ti); TypeConAry ary = (TypeConAry)t; // Invariant - if( this==TOP ) return ary ; - if( ary ==TOP ) return this; + if( this==BOT ) return BOT; + if( ary ==BOT ) return BOT; + if( this==BOT.dual() ) return ary ; + if( ary ==BOT.dual() ) return this; assert _ary!=ary._ary; // Already interned and this!=t - return BOT; + return elem().meet(ary.elem()); + } + Type imeet( TypeInteger ti ) { + if( this==BOT.dual() ) return ti; + if( this==BOT ) return BOT; + Type elem = elem(); + if( !(elem instanceof TypeInteger) ) return BOTTOM; + if( ti.isHigh() && elem.isa(ti.dual()) ) + return this; + return elem.meet(ti); } + + @Override public boolean isHigh() { return this==TOP; } + @Override boolean _isConstant() { return true; } + // Meet-over-elements type public Type elem() { if( _ary==null ) - return _any ? TOP : BOTTOM; + return _any ? Type.TOP : BOTTOM; int len = len(); long min = Long.MAX_VALUE; long max = Long.MIN_VALUE; for( int i=0; i<len; i++ ) { - min = Math.min(min,at(i)); - max = Math.max(max,at(i)); + min = Math.min(min,at8(i)); + max = Math.max(max,at8(i)); } return TypeInteger.make(min,max); } - public long at(int idx) { throw Utils.TODO(); } + public long at8(int idx) { throw Utils.TODO(); } public int len() { throw Utils.TODO(); } - @Override public int alignment() { return 0; } + @Override public int log_size() { throw Utils.TODO(); } public void write( ByteArrayOutputStream baos ) { throw Utils.TODO(); } @Override boolean eq(Type t) { - TypeConAry ary = (TypeConAry)t; // Invariant - return _any==ary._any && ary._ary==null; + return t instanceof TypeConAry ary && _any==ary._any && ary._ary==null; } @Override int hash() { diff --git a/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java b/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java index c057c6a5..fd2b2635 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeConAryB.java @@ -5,15 +5,15 @@ import java.util.Arrays; import java.io.ByteArrayOutputStream; public class TypeConAryB extends TypeConAry<byte[]> { - private TypeConAryB(byte[] bs) { super(false,bs); } + private TypeConAryB(byte[] bs) { super(false,TINT,bs); } public static TypeConAryB make( byte[] bs ) { return new TypeConAryB(bs).intern(); } public static TypeConAryB make( String s ) { return make(s.getBytes()); } static final TypeConAryB ABC = make("abc"); static final TypeConAryB ABCD = make("abcd"); public static void gather(ArrayList<Type> ts) { ts.add(ABC); ts.add(ABCD); } - @Override public long at(int idx) { return _ary[idx]; } + @Override public long at8(int idx) { return _ary[idx]; } @Override public int len() { return _ary.length; } - @Override public int alignment() { return 0; } + @Override public int log_size() { return 0; } @Override public String str() { return "[\""+new String(_ary)+"\"]"; } @Override boolean eq(Type t) { return Arrays.equals(_ary,((TypeConAryB)t)._ary); } @Override int hash() { return Arrays.hashCode(_ary); } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java b/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java index f888a93d..924e3d73 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeConAryI.java @@ -4,12 +4,14 @@ import java.util.ArrayList; import java.util.Arrays; public class TypeConAryI extends TypeConAry<int[]> { - private TypeConAryI(int[] bs) { super(false,bs); } + private TypeConAryI(int[] bs) { super(false,TINT,bs); } public static TypeConAryI make( int[] bs ) { return new TypeConAryI(bs).intern(); } private static final TypeConAryI I123 = make(new int[]{1,2,3}); public static void gather(ArrayList<Type> ts) { ts.add(I123); } + @Override public long at8(int idx) { return _ary[idx]; } + @Override public int len() { return _ary.length; } + @Override public int log_size() { return 2; } @Override public String str() { return "[i32]"; } - @Override public int alignment() { return 2; } @Override boolean eq(Type t) { return Arrays.equals(_ary,((TypeConAryI)t)._ary); } @Override int hash() { return Arrays.hashCode(_ary); } } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeFloat.java b/src/main/java/com/seaofnodes/simple/type/TypeFloat.java index a0940f8b..f3de581c 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeFloat.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeFloat.java @@ -1,7 +1,8 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.util.Ary; import java.util.ArrayList; /** @@ -9,30 +10,38 @@ import java.util.ArrayList; */ public class TypeFloat extends Type { - public final static TypeFloat ONE = constant(1.0); - public final static TypeFloat FZERO = constant(0.0); - public final static TypeFloat F32 = make(32, 0); - public final static TypeFloat F64 = make(64, 0); - // - high -64, high -32, con 0, low +32, low +64 - public final byte _sz; + public byte _sz; /** * The constant value or 0 */ - public final double _con; + public double _con; - private TypeFloat(byte sz, double con) { - super(TFLT); - _sz = sz; - _con = con; - } + private static final Ary<TypeFloat> FREE = new Ary<>(TypeFloat.class); + private TypeFloat(byte sz, double con) { super(TFLT); init(sz,con); } + private TypeFloat init( byte sz, double con ) { _sz = sz; _con = con; return this; } + public static TypeFloat malloc(byte sz, double con) { return FREE.isEmpty() ? new TypeFloat(sz,con) : FREE.pop().init(sz,con); } private static TypeFloat make(int sz, double con) { - return new TypeFloat((byte)sz,con).intern(); + TypeFloat f = malloc((byte)sz,con); + TypeFloat t2 = f.intern(); + return t2==f ? f : t2.free(f); + } + @Override TypeFloat free(Type t) { + TypeFloat f = (TypeFloat)t; + f._hash = 0; + f._dual=null; + FREE.push(f); + return this; } public static TypeFloat constant(double con) { return make(0, con); } + public final static TypeFloat ONE = constant(1.0); + public final static TypeFloat FZERO = constant(0.0); + public final static TypeFloat F32 = make(32, 0); + public final static TypeFloat F64 = make(64, 0); + public static void gather(ArrayList<Type> ts) { ts.add(F64); ts.add(F32); ts.add(constant(3.141592653589793)); } @Override public String str() { @@ -48,7 +57,6 @@ public class TypeFloat extends Type { private boolean isF32() { return ((float)_con)==_con; } @Override public boolean isHigh () { return _sz< 0; } - @Override public boolean isConstant() { return _sz==0; } @Override public int log_size() { return _sz==32 || _sz==-32 ? 2 : 3; } public double value() { return _con; } @@ -76,13 +84,20 @@ public class TypeFloat extends Type { } @Override - public Type dual() { - return isConstant() ? this : make(-_sz,0); // Constants are a self-dual + TypeFloat xdual() { + return _isConstant() ? this : new TypeFloat((byte)-_sz,0); // Constants are a self-dual } - @Override public Type makeZero() { return FZERO; } - @Override public Type glb(boolean mem) { return mem ? (isHigh() ? dual() : this) : F64; } + @Override boolean _isGLB(boolean mem) { return _glb(mem)==this; } + @Override Type _glb(boolean mem) { + if( !mem ) return F64; + if( _isConstant() ) return isF32() ? F32 : F64; + return isHigh() ? dual() : this; + } + @Override boolean _isConstant() { return _sz==0; } + + @Override public Type makeZero() { return FZERO; } @Override int hash() { return (int)(Double.hashCode(_con) ^ _sz ^ (1<<17)); } @Override diff --git a/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java b/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java index abfcf1e3..b21dd451 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeFunPtr.java @@ -1,9 +1,9 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import java.util.ArrayList; -import java.util.HashMap; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import com.seaofnodes.simple.util.Ary; +import java.util.*; /** * Represents a Pointer to a function. @@ -19,86 +19,220 @@ import java.util.HashMap; */ public class TypeFunPtr extends TypeNil { // A TypeFunPtr is Signature and a set of functions. - public final TypeTuple _sig; - public final Type _ret; + public Type[] _sig; + public Type _ret; + // TODO: + boolean _open; // Extra args are true:BOTTOM, false:TOP // Cheesy easy implementation for a small set; 1 bit per unique function - // within the TypeTuple. Can be upgraded to a BitSet for larger classes of - // functions. Negative means "these 63 concrete bits plus infinite unknown more" - public final long _fidxs; // 63 unique functions per signature - - private TypeFunPtr(byte nil, TypeTuple sig, Type ret, long fidxs) { - super(TFUNPTR,nil); + // within the same Type[]. Can be upgraded to a BitSet for larger classes + // of functions. Negative means "these 63 concrete bits plus infinite + // unknown more" + public long _fidxs; // 63 unique functions per signature + + private static final Ary<TypeFunPtr> FREE = new Ary<>(TypeFunPtr.class); + private TypeFunPtr(byte nil, boolean open, Type[] sig, Type ret, long fidxs) { super(TFUNPTR,nil); init(nil,open,sig,ret,fidxs); } + private TypeFunPtr init(byte nil, boolean open, Type[] sig, Type ret, long fidxs ) { assert sig != null; - _sig = sig; - _ret = ret; - _fidxs = fidxs; + _nil = nil; + _open = open; + _sig = sig; + _ret = ret; + _fidxs= fidxs; + return this; + } + static TypeFunPtr malloc( byte nil, boolean open, Type[] sig, Type ret, long fidxs ) { + return FREE.isEmpty() ? new TypeFunPtr(nil,open,sig,ret,fidxs) : FREE.pop().init(nil,open,sig,ret,fidxs); + } + @Override TypeFunPtr free(Type t) { + TypeFunPtr fun = (TypeFunPtr)t; + assert !fun.isFree() && !fun._terned; + fun._sig = null; + fun._ret = null; + fun._dual = null; + fun._hash = 0; + FREE.push(fun); + return this; } + @Override boolean isFree() { return _sig==null; } + + // All fields directly listed + public static TypeFunPtr make( byte nil, boolean open, Type[] sig, Type ret, long fidxs ) { + TypeFunPtr fun = malloc(nil,open,sig,ret,fidxs); + TypeFunPtr f2 = fun.intern(); + if( f2==fun ) return fun; + return VISIT.isEmpty() ? f2.free(fun) : f2.delayFree(fun); + } + public static TypeFunPtr make( boolean nil, boolean open, Type[] sig, Type ret ) { return make((byte)(nil ? 3 : 2),open,sig,ret,-1); } + + + @Override TypeFunPtr makeFrom( byte nil ) { return nil ==_nil ? this : make( nil,_open,_sig,_ret, _fidxs); } + public TypeFunPtr makeFrom( Type ret ) { return ret ==_ret ? this : make( _nil,_open,_sig, ret, _fidxs); } + public TypeFunPtr makeFrom( int fidx ) { return make((byte)2, _open, _sig,_ret,1L<<fidx ); } - public static TypeFunPtr make( byte nil, TypeTuple sig, Type ret, long fidxs ) { return new TypeFunPtr(nil,sig,ret,fidxs).intern(); } - public static TypeFunPtr make( boolean nil, TypeTuple sig, Type ret ) { return make((byte)(nil ? 3 : 2),sig,ret,-1); } - @Override TypeFunPtr makeFrom( byte nil ) { return nil ==_nil ? this : make( nil,_sig,_ret, _fidxs); } - public TypeFunPtr makeFrom( Type ret ) { return ret ==_ret ? this : make( _nil,_sig, ret, _fidxs); } - public TypeFunPtr makeFrom( int fidx ) { return make((byte)2, _sig,_ret,1L<<fidx ); } - public static TypeFunPtr BOT = make((byte)3,TypeTuple.BOT,Type.BOTTOM,-1); - public static TypeFunPtr TEST = make((byte)2,TypeTuple.TEST,TypeInteger.BOT,1); - public static TypeFunPtr TEST0 = make((byte)3,TypeTuple.TEST,TypeInteger.BOT,3); - public static TypeFunPtr MAIN = make((byte)3,TypeTuple.MAIN,TypeInteger.BOT,-1); - public static TypeFunPtr CALLOC= make((byte)3,TypeTuple.CALLOC,TypeMemPtr.BOT,-1); - public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST0); ts.add(BOT); ts.add(MAIN); } + public static final Type[] TEMPTY = new Type[0]; + static final Type[] TINT = new Type[]{TypeInteger.BOT}; + static final Type[] TINTMEM = new Type[]{TypeInteger.BOT,TypeFloat.F32}; + static final Type[] TINTINT = new Type[]{TypeInteger.BOT,TypeInteger.BOT}; + public static TypeFunPtr BOT = make((byte)3,true ,TEMPTY,Type.BOTTOM,-1); + public static TypeFunPtr TEST = make((byte)2,false,TINTMEM,TypeInteger.BOT, 1); + public static TypeFunPtr TEST0 = make((byte)3,false,TINTMEM,TypeInteger.BOT, 3); + public static TypeFunPtr MAIN = make((byte)3,false,TINT ,Type.BOTTOM,-1); // Main can return anything + public static TypeFunPtr CALLOC= make((byte)3,false,TINTINT,TypeMemPtr .BOT,-1); + public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(TEST0); ts.add(BOT); ts.add(MAIN);ts.add(CALLOC); } @Override Type xmeet(Type t) { TypeFunPtr that = (TypeFunPtr) t; - return TypeFunPtr.make(xmeet0(that),(TypeTuple)_sig.meet(that._sig), _ret.meet(that._ret), _fidxs | that._fidxs); + // if equal, no matters. + // if short is BOT, chop ; recurPre on short. + // if short is TOP, copy long; recurPre on long. + TypeFunPtr min = _sig.length < that._sig.length ? this : that; + if( _sig.length != that._sig.length && (min._open ^ min==this) ) + return that.xmeet(this); + // Recurse all common fields + Type[] args = new Type[_sig.length]; + for( int i=0; i<min._sig.length; i++ ) + args[i] = _sig[i].meet(that._sig[i]); + // Handle extra args + for( int i=min._sig.length; i<_sig.length; i++ ) + args[i] = _sig[i]; + return make(xmeet0(that),_open | that._open, args, _ret.meet(that._ret), _fidxs | that._fidxs); + } + static Type[] xmeet( Type[] ts0, Type[] ts1) { + if( ts0==ts1 ) return ts0; + assert ts0.length==ts1.length; + Type[] ts = new Type[ts0.length]; + for( int i=0; i<ts0.length; i++ ) + ts[i] = ts0[i].meet(ts1[i]); + return ts; } - @Override - public TypeFunPtr dual() { return TypeFunPtr.make(dual0(), _sig.dual(), _ret.dual(), ~_fidxs); } + @Override TypeFunPtr xdual() { return malloc(dual0(), !_open, xdual(_sig), _ret.dual(), ~_fidxs); } + static Type[] xdual(Type[] ts) { + Type[] dual = new Type[ts.length]; + for( int i=0; i<ts.length; i++ ) + dual[i] = ts[i].dual(); + return dual; + } + + @Override TypeFunPtr rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + Type[] sigs = new Type[_sig.length]; + TypeFunPtr d = malloc(dual0(),!_open,sigs,null,~_fidxs); + (_dual = d)._dual = this; // Cross link duals + // Return rdual + d._ret = _ret._terned ? _ret.dual() : _ret.rdual(); + // Signature rdual + for( int i=0; i<_sig.length; i++ ) + sigs[i] = _sig[i]._terned ? _sig[i].dual() : _sig[i].rdual(); + return d; + } // 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 Type meet0() { return _nil==3 ? this : make((byte)3,_open,_sig,_ret,_fidxs); } - @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 isHigh () { return _nil <= 1 || (_nil==2 && _fidxs==0); } - @Override public boolean isConstant() { return (_nil==2 && Long.bitCount(_fidxs)==1) || (_nil==3 && _fidxs==0); } + @Override boolean _isConstant() { return (_nil==2 && Long.bitCount(_fidxs)==1) || (_nil==3 && _fidxs==0); } + + @Override boolean _isFinal() { return true; } + @Override boolean _isGLB(boolean mem) { return true; } + @Override TypeFunPtr _glb(boolean mem) { return this; } + @Override TypeFunPtr _close() { + Type[] sig = new Type[_sig.length]; + TypeFunPtr fun = malloc(_nil,false,sig,null,_fidxs); + // Now start the recursion + fun._ret = _ret._close(); + for( int i=0; i<sig.length; i++ ) + sig[i] = _sig[i]._close(); + + return fun; + } @Override public int log_size() { return 2; } // (1<<2)==4-byte pointers - public Type arg(int i) { return _sig._types[i]; } + public Type arg(int i) { return _sig[i]; } public long fidxs() { return _fidxs; } public Type ret() { return _ret; } - public int nargs() { return _sig._types.length; } + public int nargs() { return _sig.length; } public int fidx() { assert Long.bitCount(_fidxs)==1; return Long.numberOfTrailingZeros(_fidxs); } + + @Override int nkids() { return _sig.length+1; } + @Override Type at( int idx ) { + return idx == _sig.length ? _ret : _sig[idx]; + } + @Override void set( int idx, Type t ) { + if( idx == _sig.length ) _ret = t; + else _sig[idx] = t; + } + @Override - int hash() { return Utils.fold(_sig.hashCode() ^ _ret.hashCode() ^ _fidxs ^ super.hash()); } + int hash() { + long hash = _ret.hashCode() ^ _fidxs ^ super.hash(); + for( Type arg : _sig ) + hash = hash*19 ^ arg.hashCode(); + return Utils.fold(hash); + } @Override boolean eq(Type t) { - TypeFunPtr ptr = (TypeFunPtr)t; // Invariant - return _sig == ptr._sig && _ret == ptr._ret && _fidxs == ptr._fidxs && super.eq(ptr); + // Recursive; so use cyclic equals + if( !VISIT.isEmpty() ) { + assert TypeStruct.CEQUALS.isEmpty(); + boolean rez = cycle_eq(t); + TypeStruct.CEQUALS.clear(); + return rez; + } + TypeFunPtr fun = (TypeFunPtr)t; // Invariant + if( !super.eq(fun) || _open != fun._open || _fidxs != fun._fidxs || _sig.length != fun._sig.length ) return false; + if( _sig == fun._sig && _ret == fun._ret ) return true; + + if( !_ret.eq(fun._ret) ) return false; + for( int i = 0; i < _sig.length; i++ ) + if( !_sig[i].eq(fun._sig[i]) ) + return false; + return true; + } + @Override boolean cycle_eq(Type t) { + if( t._type != TFUNPTR ) return false; + TypeFunPtr fun = (TypeFunPtr)t; // Invariant + if( !super.eq(fun) || _open != fun._open || _fidxs != fun._fidxs || _sig.length != fun._sig.length ) return false; + if( _sig == fun._sig && _ret == fun._ret ) return true; + + // Check to see if we've ever compared this pair of types before; + // if so, then assume the cycle is equal here. + int pid = pid(fun); + if( TypeStruct.CEQUALS.find(pid)!= -1 ) return true; + TypeStruct.CEQUALS.push(pid); + if( !_ret.cycle_eq(fun._ret) ) return false; + for( int i = 0; i < _sig.length; i++ ) + if( !_sig[i].cycle_eq(fun._sig[i]) ) + return false; + return true; } - @Override public String str() { return print(new SB()).toString(); } - @Override public SB print(SB sb) { return _print(sb,false,true); } - public SB print(SB sb, boolean n) { return _print(sb,false,n); } - @Override public SB gprint(SB sb) { return _print(sb,true ,true); } - private static SB _print(SB sb, boolean g, Type t) { return g ? t.gprint(sb) : t.print(sb); } - private SB _print(SB sb, boolean g, boolean n) { + @Override public String str() { return "{"+printFIDX()+"}"; } + + SB _print(SB sb, BitSet visit, boolean html ) { sb.p(x()).p("{ "); - if( _sig._types!=null ) - for( Type t : _sig._types ) - _print(sb,g,t).p(" "); - _print(sb.p(g ? "→ " : "-> "),g,_ret).p(" #"); - if( isHigh() ) sb.p("~"); + if( _sig!=null ) + for( Type t : _sig ) + sb.p(t.str()).p(" "); // Short form in signature + _ret.print(sb.p(html ? "→ " : "-> "),visit,html).p(" #"); + // Print fidxs + return sb.p(printFIDX()).p("}").p(q()); + } + String printFIDX() { + String tilde = isHigh() ? "~" : ""; long fidxs = isHigh() ? ~_fidxs : _fidxs; String fidx = fidxs==0 ? "" : Long.bitCount(fidxs) == 1 ? ""+Long.numberOfTrailingZeros(fidxs) : fidxs == -1 ? "ALL" : "b"+Long.toBinaryString(fidxs); // Just some function bits - return sb.p(fidx).p("}").p(q()); + return tilde+fidx; } // Usage: for( long fidxs=fidxs(); fidxs!=0; fidxs=nextFIDX(fidxs) { int fidxs = Long.numberOfTrailingZeros(fidxs); ... } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeInteger.java b/src/main/java/com/seaofnodes/simple/type/TypeInteger.java index 59378ef3..99f237a9 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeInteger.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeInteger.java @@ -1,24 +1,54 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.ArrayList; /** * Integer Type */ public class TypeInteger extends Type { + /** + * Describes an integer *range* - everything from min to max; both min and + * max are inclusive. If min==max, this is a constant. + * <br> + * If min <= max, this is a below center (towards bottom). + * If min > max, this is an above center (towards top). + */ + public long _min, _max; + + private static final Ary<TypeInteger> FREE = new Ary<>(TypeInteger.class); + private TypeInteger(long min, long max) { super(TINT); init(min,max); } + private TypeInteger init(long min, long max) { _min = min; _max = max; return this; } + public static TypeInteger malloc(long lo, long hi) { return FREE.isEmpty() ? new TypeInteger(lo,hi) : FREE.pop().init(lo,hi); } + public static TypeInteger make(long lo, long hi) { + TypeInteger i = malloc(lo,hi); + TypeInteger t2 = i.intern(); + return t2==i ? i : t2.free(i); + } + @Override TypeInteger free(Type t) { + TypeInteger i = (TypeInteger)t; + i._min = i._max = 0; + i._hash = 0; + i._dual = null; + FREE.push(i); + return this; + } + + public static TypeInteger constant(long con) { return make(con, con); } public final static TypeInteger ZERO= make(0,0); public final static TypeInteger FALSE=ZERO; public final static TypeInteger TRUE= make(1,1); + public final static TypeInteger TWO = make(2,2); // Shows up in some Simple tests as the starting argument public final static TypeInteger I1 = make(-1,0); public final static TypeInteger I8 = make(-128,127); public final static TypeInteger I16 = make(-32768,32767); public final static TypeInteger I32 = make(-1L<<31,(1L<<31)-1); public final static TypeInteger BOT = make(Long.MIN_VALUE,Long.MAX_VALUE); - public final static TypeInteger TOP = BOT.dual(); + public final static TypeInteger TOP = (TypeInteger)BOT.dual(); public final static TypeInteger U1 = make(0,1); public final static TypeInteger BOOL= U1; @@ -26,30 +56,10 @@ public class TypeInteger extends Type { public final static TypeInteger U16 = make(0,65535); public final static TypeInteger U32 = make(0,(1L<<32)-1); - /** - * Describes an integer *range* - everything from min to max; both min and - * max are inclusive. If min==max, this is a constant. - * <br> - * If min <= max, this is a below center (towards bottom). - * If min > max, this is an above center (towards top). - */ - public final long _min, _max; - - private TypeInteger(long min, long max) { - super(TINT); - _min = min; - _max = max; - } - - // Strict non-zero contract - public static TypeInteger make(long lo, long hi) { return new TypeInteger(lo,hi).intern(); } - - public static TypeInteger constant(long con) { return make(con, con); } - public static void gather(ArrayList<Type> ts) { ts.add(I32); ts.add(BOT); ts.add(U1); ts.add(I1); ts.add(U8); } @Override public String str() { - if( isConstant() ) return ""+_min; + if( _isConstant() ) return ""+_min; long lo = _min, hi = _max; String x = ""; if( hi < lo ) { @@ -59,7 +69,7 @@ public class TypeInteger extends Type { return x+_str(lo,hi); } private static String _str(long lo, long hi) { - if( lo==Long.MIN_VALUE && hi==Long.MAX_VALUE ) return "int"; + if( lo==Long.MIN_VALUE && hi==Long.MAX_VALUE ) return "i64"; if( lo== 0 && hi== 1 ) return "bool"; if( lo== -1 && hi== 0 ) return "i1"; if( lo== -128 && hi== 127 ) return "i8"; @@ -72,7 +82,6 @@ public class TypeInteger extends Type { } @Override public boolean isHigh () { return _min > _max; } - @Override public boolean isConstant() { return _min == _max; } @Override public int log_size() { if( isHigh() ) return 0; // High types are dead, and should never hit code emission. @@ -110,12 +119,15 @@ public class TypeInteger extends Type { @Override public Type xmeet(Type other) { + if( other instanceof TypeConAry ary ) return ary.imeet(this); // Invariant from caller: 'this' != 'other' and same class (TypeInteger) TypeInteger i = (TypeInteger)other; // Contract return make(Math.min(_min,i._min), Math.max(_max,i._max)); } - @Override public TypeInteger dual() { return make(_max,_min); } + @Override TypeInteger xdual() { + return _min==_max ? this : malloc(_max,_min); + } @Override public TypeInteger nonZero() { if( isHigh() ) return this; @@ -125,10 +137,17 @@ public class TypeInteger extends Type { return this; } @Override public Type makeZero() { return ZERO; } - @Override public Type glb(boolean mem) { return mem ? (isHigh() ? dual() : this) : BOT; } + @Override boolean _isConstant() { return _min == _max; } + @Override boolean _isGLB(boolean mem) { return _glb(mem)==this; } + @Override Type _glb(boolean mem) { + if( !mem ) return BOT; + // GLB is not well-defined in memory; depends on the size of the memory field + if( _isConstant() ) return BOT; + return isHigh() ? dual() : this; + } + @Override int hash() { return Utils.fold(_min) * Utils.fold(_max); } @Override public boolean eq( Type t ) { - TypeInteger i = (TypeInteger)t; // Contract - return _min==i._min && _max==i._max; + return t instanceof TypeInteger i && _min==i._min && _max==i._max; } } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeMem.java b/src/main/java/com/seaofnodes/simple/type/TypeMem.java index 63fb30ce..99b19c75 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeMem.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeMem.java @@ -1,10 +1,10 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import java.lang.Long; -import java.util.BitSet; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.ArrayList; +import java.util.BitSet; /** @@ -13,24 +13,44 @@ import java.util.ArrayList; public class TypeMem extends Type { // Which slice of memory? - // 0 means TOP, no slice. - // 0 means BOT, all memory. - // N means slice#N. - public final int _alias; - public final Type _t; // Memory contents, some scalar type - - private TypeMem(int alias, Type t) { - super(TMEM); - assert alias!=0 || (t==Type.TOP || t==Type.BOTTOM); + // 1 and TOP means no slice. + // 1 and BOT means all memory. + // N means alias slice#N. + public int _alias; + public Type _t; // Memory contents, some scalar type + + private static final Ary<TypeMem> FREE = new Ary<>(TypeMem.class); + private TypeMem(int alias, Type t) { super(TMEM); init(alias,t); } + private TypeMem init(int alias, Type t) { + assert alias>1 || (t==Type.TOP || t==Type.BOTTOM); _alias = alias; _t = t; + return this; + } + @Override TypeMem free(Type t) { + TypeMem mem = (TypeMem)t; + mem._alias= -99; + mem._dual = null; + mem._hash = 0; + FREE.push(mem); + return this; + } + @Override boolean isFree() { return _alias == -99; } + + public static TypeMem malloc(int alias, Type t) { + return FREE.isEmpty() ? new TypeMem(alias,t) : FREE.pop().init(alias,t); + } + public static TypeMem make(int alias, Type t) { + TypeMem f = malloc(alias,t); + TypeMem f2 = f.intern(); + if( f2==f ) return f; + return VISIT.isEmpty() ? f2.free(f) : f2.delayFree(f); } - public static TypeMem make(int alias, Type t) { return new TypeMem(alias,t).intern(); } - public static final TypeMem TOP = make(0, Type.TOP ); - public static final TypeMem BOT = make(0, Type.BOTTOM); + public static final TypeMem TOP = make(1, Type.TOP ); + public static final TypeMem BOT = make(1, Type.BOTTOM); - public static void gather(ArrayList<Type> ts) { ts.add(make(1,Type.NIL)); ts.add(make(1,TypeInteger.ZERO)); ts.add(BOT); } + public static void gather(ArrayList<Type> ts) { ts.add(make(2,Type.NIL)); ts.add(make(2,TypeInteger.ZERO)); ts.add(BOT); } @Override TypeMem xmeet(Type t) { @@ -39,19 +59,28 @@ public class TypeMem extends Type { if( that==TOP ) return this; if( this==BOT ) return BOT; if( that==BOT ) return BOT; - int alias = _alias==that._alias ? _alias : 0; + int alias = _alias==that._alias ? _alias : 1; Type mt = _t.meet(that._t); return make(alias,mt); } @Override - public Type dual() { - return make(_alias,_t.dual()); + Type xdual() { return _t._dual==_t ? this : malloc(_alias,_t.dual()); } + + @Override TypeMem rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + TypeMem d = malloc(_alias,null); + (_dual = d)._dual = this; // Cross link duals + d._t = _t._terned ? _t.dual() : _t.rdual(); + return d; } @Override public boolean isHigh() { return _t.isHigh(); } @Override public int log_size() { throw Utils.TODO(); } - @Override public Type glb(boolean mem) { return make(_alias,_t.glb(true)); } + @Override boolean _isFinal() { return _t._isFinal(); } + @Override boolean _isGLB(boolean mem) { return _t._isGLB(true); } + @Override public Type _glb(boolean mem) { return make(_alias,_t._glb(true)); } @Override int hash() { return 9876543 + _alias + _t.hashCode(); } @@ -60,15 +89,19 @@ public class TypeMem extends Type { return _alias == that._alias && _t == that._t; } - @Override public SB print(SB sb) { - sb.p("#"); - if( _alias==0 ) return sb.p(_t._type==TTOP ? "TOP" : "BOT"); - return _t.print(sb.p(_alias).p(":")); + @Override boolean cycle_eq(Type t) { + TypeMem that = (TypeMem) t; // Invariant + return _alias == that._alias && _t.cycle_eq(that._t); } - @Override public SB gprint(SB sb) { + + @Override int nkids() { return 1; } + @Override Type at( int idx ) { return _t; } + @Override void set( int idx, Type t ) { _t = t; } + + @Override public SB _print(SB sb, BitSet visit, boolean html) { sb.p("#"); if( _alias==0 ) return sb.p(_t._type==TTOP ? "TOP" : "BOT"); - return _t.gprint(sb.p(_alias).p(":")); + return _t.print(sb.p(_alias).p(":"),visit,html); } @Override public String str() { return toString(); } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java b/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java index 78605e81..6041155d 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeMemPtr.java @@ -1,8 +1,9 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import java.util.ArrayList; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.*; /** * Represents a Pointer to memory. @@ -24,16 +25,35 @@ public class TypeMemPtr extends TypeNil { // (BOT ,false) - a not-nil void* (unspecified struct) // (TOP ,true ) - a nil - public final TypeStruct _obj; - public final boolean _one; // Singleton instance + public TypeStruct _obj; + public boolean _one; // Singleton instance - private TypeMemPtr(byte nil, TypeStruct obj, boolean singleton) { - super(TMEMPTR,nil); - assert obj!=null; - _obj = obj; - _one = singleton; + private static final Ary<TypeMemPtr> FREE = new Ary<>(TypeMemPtr.class); + private TypeMemPtr(byte nil, TypeStruct obj, boolean one) { super(TMEMPTR,nil); init(nil,obj,one); } + private TypeMemPtr init(byte nil, TypeStruct obj, boolean one) { _nil=nil; _obj=obj; _one=one; return this; } + // Return a filled-in TypeMemPtr; either from free list or alloc new. + private static TypeMemPtr malloc(byte nil, TypeStruct obj, boolean one) { + return FREE.isEmpty() ? new TypeMemPtr(nil,obj,one) : FREE.pop().init(nil,obj,one); } - public static TypeMemPtr make(byte nil, TypeStruct obj, boolean one) { return new TypeMemPtr(nil, obj, one).intern(); } + + // All fields directly listed + public static TypeMemPtr make(byte nil, TypeStruct obj, boolean one) { + TypeMemPtr tmp = malloc(nil, obj, one); + TypeMemPtr t2 = tmp.intern(); + if( t2==tmp ) return tmp; + return VISIT.isEmpty() ? t2.free(tmp) : t2.delayFree(tmp); + } + @Override TypeMemPtr free(Type t) { + TypeMemPtr tmp = (TypeMemPtr)t; + tmp._nil = -99; + tmp._obj = null; + tmp._dual = null; + tmp._hash = 0; + FREE.push(tmp); + return this; + } + @Override boolean isFree() { return _obj==null; } + static TypeMemPtr make(byte nil, TypeStruct obj) { return make(nil, obj, false); } public static TypeMemPtr make (TypeStruct obj) { return make((byte)2, obj); } public static TypeMemPtr makeNullable(TypeStruct obj) { return make((byte)3, obj); } @@ -41,8 +61,6 @@ public class TypeMemPtr extends TypeNil { public TypeMemPtr makeFrom(TypeStruct obj) { return obj==_obj ? this : make(_nil, obj, _one); } public TypeMemPtr makeNullable() { return makeFrom((byte)3); } @Override TypeMemPtr makeFrom(byte nil) { return nil==_nil ? this : make(nil, _obj, _one); } - @Override public TypeMemPtr makeRO() { return makeFrom(_obj.makeRO()); } - @Override public boolean isFinal() { return _obj.isFinal(); } // An abstract pointer, pointing to either a Struct or an Array. // Can also be null or not, so 4 choices {TOP,BOT} x {nil,not} @@ -56,16 +74,32 @@ public class TypeMemPtr extends TypeNil { @Override public TypeNil xmeet(Type t) { TypeMemPtr that = (TypeMemPtr) t; + assert !isFree() && !that.isFree(); return make(xmeet0(that), (TypeStruct)_obj.meet(that._obj), _one & that._one); } @Override - public TypeMemPtr dual() { return make( dual0(), _obj.dual(), !_one); } + TypeMemPtr xdual() { return malloc( dual0(), _obj.dual(), _one); } + + @Override TypeMemPtr rdual() { + if( _dual!=null ) return dual(); + assert !_terned; + TypeMemPtr d = malloc(dual0(), null, _one); + (_dual = d)._dual = this; // Cross link duals + d._obj = _obj._terned ? _obj.dual() : _obj.rdual(); + return d; + } - // RHS is NIL; do not deep-dual when crossing the centerline + // RHS is NIL; do not deep-dual when crossing the center line @Override Type meet0() { return _nil==3 ? this : make((byte)3,_obj); } - @Override public boolean isConstant() { return _one && _obj.isConstant(); } + @Override boolean _isConstant() { return _one && _obj._isConstant(); } + @Override boolean _isFinal() { return _obj._isFinal(); } + @Override TypeMemPtr _makeRO() { return makeFrom(_obj._makeRO()); } + @Override boolean _isGLB(boolean mem) { return _obj.isGLB2(); } + @Override TypeMemPtr _glb(boolean mem) { return make((byte)3,_obj.glb2()); } + @Override TypeMemPtr _close() { return makeFrom(_obj._close()); } + // True if this "isa" t up to named structures @Override public boolean shallowISA( Type t ) { @@ -78,7 +112,6 @@ public class TypeMemPtr extends TypeNil { throw Utils.TODO(); // return _obj.shallowISA(that._obj); } - @Override public TypeMemPtr glb(boolean mem) { return make((byte)3,_obj.glb(true)); } // Is forward-reference @Override public boolean isFRef() { return _obj.isFRef(); } @@ -88,8 +121,17 @@ public class TypeMemPtr extends TypeNil { @Override boolean eq(Type t) { TypeMemPtr ptr = (TypeMemPtr)t; // Invariant - return _obj == ptr._obj && _one == ptr._one && super.eq(ptr); + return super.eq(ptr) && _one == ptr._one && _obj == ptr._obj; } + @Override boolean cycle_eq(Type t) { + if( t._type != TMEMPTR ) return false; + TypeMemPtr ptr = (TypeMemPtr)t; // Invariant + return super.eq(ptr) && _one == ptr._one && _obj.cycle_eq(ptr._obj); + } + + @Override int nkids() { return 1; } + @Override Type at( int idx ) { return _obj; } + @Override void set( int idx, Type t ) { _obj = (TypeStruct)t; } @Override public String str() { if( this== NOTBOT) return "*void"; @@ -97,14 +139,9 @@ public class TypeMemPtr extends TypeNil { return x()+"*"+_obj.str()+q(); } - @Override public SB print(SB sb) { - if( this== NOTBOT) return sb.p("*void"); - if( this== BOT) return sb.p("*void?"); - return _obj.print(sb.p(x()).p("*")).p(q()); - } - @Override public SB gprint(SB sb) { + @Override SB _print(SB sb, BitSet visit, boolean html ) { if( this== NOTBOT) return sb.p("*void"); if( this== BOT) return sb.p("*void?"); - return _obj.gprint(sb.p(x()).p("*")).p(q()); + return _obj.print(sb.p(x()).p("*"),visit,html).p(q()); } } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeNil.java b/src/main/java/com/seaofnodes/simple/type/TypeNil.java index 3902c40b..56d73b00 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeNil.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeNil.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.ArrayList; /** @@ -12,7 +12,7 @@ public abstract class TypeNil extends Type { // 1 = high-subclass no nil // 2 = low -subclass no nil // 3 = low -subclass also nil - final byte _nil; + byte _nil; TypeNil(byte t, byte nil ) { super(t); _nil = nil; } @@ -45,18 +45,18 @@ public abstract class TypeNil extends Type { } @Override public boolean isHigh () { return _nil <= 1; } - @Override public boolean isConstant () { return false; } @Override public boolean isHighOrConst() { return isHigh() || isConstant(); } - @Override public Type glb(boolean mem) { return Type.NIL; } - public boolean notNull() { return _nil==1 || _nil==2; } public boolean nullable() { return _nil==3; } + @Override boolean _isConstant() { return false; } + @Override Type _glb(boolean mem) { return Type.NIL; } + final String q() { return _nil == 1 || _nil == 2 ? "" : "?"; } final String x() { return isHigh() ? "~" : ""; } int hash() { return _nil<<17; } - boolean eq(TypeNil ptr) { return _nil == ptr._nil; } + @Override boolean eq(Type ptr) { return ptr instanceof TypeNil nil && _nil ==nil._nil; } } diff --git a/src/main/java/com/seaofnodes/simple/type/TypePtr.java b/src/main/java/com/seaofnodes/simple/type/TypePtr.java index d9de5cd7..75478119 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypePtr.java +++ b/src/main/java/com/seaofnodes/simple/type/TypePtr.java @@ -1,13 +1,15 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.ArrayList; +import java.util.BitSet; /** * Represents a Scalar; a single register-sized value. */ public class TypePtr extends TypeNil { + private static final String[] STRS = new String[]{"~ptr","~nptr","nptr","ptr"}; private TypePtr(byte nil) { super(TPTR,nil); } @@ -15,8 +17,8 @@ public class TypePtr extends TypeNil { // Can also be null or not, so 4 choices {TOP,BOT} x {nil,not} public static TypePtr XPTR = new TypePtr((byte)0).intern(); public static TypePtr XNPTR= new TypePtr((byte)1).intern(); - public static TypePtr NPTR = new TypePtr((byte)2).intern(); - public static TypePtr PTR = new TypePtr((byte)3).intern(); + public static TypePtr NPTR = (TypePtr)XNPTR.dual(); + public static TypePtr PTR = (TypePtr)XPTR.dual(); private static final TypePtr[] PTRS = new TypePtr[]{XPTR,XNPTR,NPTR,PTR}; public static void gather(ArrayList<Type> ts) { ts.add(PTR); ts.add(NPTR); } @@ -28,7 +30,7 @@ public class TypePtr extends TypeNil { return PTRS[xmeet0(that)]; } - @Override public TypePtr dual() { return PTRS[dual0()]; } + @Override TypePtr xdual() { return new TypePtr((byte)(3-_nil)); } // High scalar loses, low scalar wins @Override TypeNil nmeet(TypeNil tn) { @@ -45,9 +47,9 @@ 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(boolean mem) { return PTR; } + boolean _isGLB(boolean mem) { return this==PTR; } + @Override TypePtr _glb(boolean mem) { return PTR; } - private static final String[] STRS = new String[]{"~ptr","~nptr","nptr","ptr"}; @Override public String str() { return STRS[_nil]; } - @Override public SB print(SB sb) { return sb.p(str()); } + @Override public SB _print(SB sb, BitSet visit, boolean html) { return sb.p(str()); } } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeRPC.java b/src/main/java/com/seaofnodes/simple/type/TypeRPC.java index ec2f5f0a..bd5e2923 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeRPC.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeRPC.java @@ -1,7 +1,7 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; import java.util.ArrayList; import java.util.BitSet; import java.util.HashSet; @@ -48,10 +48,6 @@ public class TypeRPC extends Type { return "$["+(_any ? "-" : "")+_rpcs+"]"; } - @Override public boolean isConstant() { - return !_any && _rpcs.size()==1; - } - @Override public TypeRPC xmeet(Type other) { TypeRPC rpc = (TypeRPC)other; @@ -87,7 +83,10 @@ public class TypeRPC extends Type { } @Override - public Type dual() { return make(!_any,_rpcs); } + Type xdual() { return new TypeRPC(!_any,_rpcs); } + + @Override boolean _isConstant() { return !_any && _rpcs.size()==1; } + @Override boolean _isGLB(boolean mem) { return true; } @Override int hash() { return _rpcs.hashCode() ^ (_any ? -1 : 0) ; } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeStruct.java b/src/main/java/com/seaofnodes/simple/type/TypeStruct.java index 66a37d41..73fecdab 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeStruct.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeStruct.java @@ -1,8 +1,8 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import java.util.ArrayList; +import com.seaofnodes.simple.codegen.CodeGen; +import com.seaofnodes.simple.util.*; +import java.util.*; /** * Represents a struct type. @@ -11,69 +11,129 @@ public class TypeStruct extends Type { // A Struct has a name and a set of fields; the fields themselves have // names, types and aliases. The name has no semantic meaning, but is - // useful for debugging. Briefly during parsing a Struct can be a - // forward-ref; in this case the _fields array is null. - - // Its illegal to attempt to load a field from a forward-ref struct. - - // Example: "int rez = new S.x; struct S { int x; } return rez;" // Error, S not defined - // Rewrite: "struct S { int x; } int rez = new S.x; return rez;" // Ok, no forward ref - // - // During the normal optimization run, struct types "bottom out" at further - // struct references, so we don't have to handle e.g. cyclic types. The - // "bottom out" is again the forward-ref struct. - public final String _name; - public final Field[] _fields; - public final TypeConAry _con; // Optional, constant array contents - - private TypeStruct(String name, TypeConAry con, Field[] fields) { + // useful for debugging. + + // During parsing a mid-declaration struct is flagged as a "open". It is + // treated as having infinite fields with correct name and type BOTTOM. + + public String _name; // Struct name + public boolean _open; // infinite fields are all true:BOTTOM, false:TOP + public Field[] _fields; + + private TypeStruct(String name, boolean open, Field[] fields) { super(TSTRUCT); _name = name; + _open = open; _fields = fields; - _con = con; } + private static final Ary<TypeStruct> FREE = new Ary<>(TypeStruct.class); + // Return a filled-in TypeStruct; either from free list or alloc new. + private static TypeStruct malloc(String name, boolean open, Field[] fields) { + if( FREE.isEmpty() ) return new TypeStruct(name,open,fields); + TypeStruct ts = FREE.pop(); + assert ts.isFree(); + ts._name = name; + ts._open = open; + ts._fields = fields; + return ts; + } + // Free ts; return this. + @Override TypeStruct free(Type t) { + TypeStruct ts = (TypeStruct)t; + assert !ts.isFree() && !ts._terned; + ts._fields = null; + ts._offs = null; + ts._dual = null; + ts._hash = 0; + FREE.push(ts); + return this; + } + @Override boolean isFree() { return _fields==null; } + + // All fields directly listed - public static TypeStruct make(String name, TypeConAry con, Field... fields) { return new TypeStruct(name, con, fields).intern(); } - public static TypeStruct make(String name, Field... fields) { return make(name, TypeConAry.BOT, fields); } - public static final TypeStruct TOP = make("$TOP",new Field[0]); - public static final TypeStruct BOT = make("$BOT",new Field[0]); - public static final TypeStruct TEST = make("test",new Field[]{Field.TEST}); - // Forward-ref version - public static TypeStruct makeFRef(String name) { return make(name, (Field[])null); } - // Make a read-only version - @Override public TypeStruct makeRO() { - if( isFinal() ) return this; - Field[] flds = new Field[_fields.length]; - for( int i=0; i<flds.length; i++ ) - flds[i] = _fields[i].makeRO(); - return make(_name,flds); + public static TypeStruct make(String name, boolean open, Field... fields) { + TypeStruct ts = malloc(name, open, fields); + TypeStruct t2 = ts.intern(); + if( t2==ts ) return ts; + return VISIT.isEmpty() ? t2.free(ts) : ts.delayFree(ts); } + // New open struct with no fields + public static TypeStruct open( String name ) { return make(name,true); } // Array - public static TypeStruct makeAry(String name, TypeInteger len, int lenAlias, Type body, int bodyAlias) { - return makeAry(name,len,lenAlias,body,bodyAlias,false,TypeConAry.BOT); + public static TypeStruct makeAry(String name, TypeInteger len, int lenAlias, Type body, int bodyAlias, boolean efinal) { + return make(name,false, + Field.make("#" ,len , lenAlias,true ,false), + Field.make("[]",body,bodyAlias,efinal,false)); } - public static TypeStruct makeAry(String name, TypeInteger len, int lenAlias, Type body, int bodyAlias, boolean efinal, TypeConAry con) { - assert body instanceof TypeInteger || body instanceof TypeFloat || (body instanceof TypeNil tn && tn.nullable()); - assert efinal || con==TypeConAry.BOT; // No mutable constant arrays - return make(name, - con, - Field.make("#" ,len , lenAlias,true ), - Field.make("[]",body,bodyAlias,efinal)); + + public TypeStruct add( Field f ) { + assert _open && find(f._fname)==-1; // No double field names + Field[] flds = Arrays.copyOf(_fields,_fields.length+1); + flds[_fields.length] = f; + return make(_name,true,flds); + } + public TypeStruct replace( Field f ) { + assert !_open; + Field[] flds = Arrays.copyOf(_fields,_fields.length); + flds[find(f._fname)] = f; + return make(_name,false,flds); } - // A pair of self-cyclic types - private static final TypeStruct S1F = makeFRef("S1"); - private static final TypeStruct S2F = makeFRef("S2"); - public static final TypeStruct S1 = make("S1", Field.make("a", TypeInteger.BOT, -1, false), Field.make("s2",TypeMemPtr.make((byte)2,S2F),-2, false) ); - private static final TypeStruct S2 = make("S2", Field.make("b", TypeFloat .F64, -3, false), Field.make("s1",TypeMemPtr.make((byte)2,S1F),-4, false) ); - private static final TypeStruct ARY = makeAry("[i64]",TypeInteger.U32,-1,TypeInteger.BOT,-2); - private static final TypeStruct STR = makeAry("[u8]",TypeInteger.U32,-1,TypeInteger.U8,-2); - private static final TypeStruct HELLO= makeAry("[u8]",TypeInteger.constant(3),-1,TypeInteger.U8,-2,true,TypeConAryB.ABC); + public final TypeStruct close() { + return (TypeStruct)recurOpen()._close().recurClose(); + } + @Override TypeStruct _close() { + TypeStruct ts = (TypeStruct)VISIT.get(_name); + if( ts!=null ) return ts; + ts = recurPre(_name,false); + Field[] flds = ts._fields; + + // Now start the recursion + for( int i=0; i<flds.length; i++ ) + flds[i].setType(_fields[i]._t._close()); + + return ts; + } + + static final AryInt CEQUALS = new AryInt(); - public static void gather(ArrayList<Type> ts) { ts.add(TEST); ts.add(BOT); ts.add(S1); ts.add(S2); ts.add(ARY); ts.add(STR); ts.add(HELLO); } + public static final TypeStruct BOT = open("$STRUCT"); + public static final TypeStruct TOP = BOT.dual(); + public static final TypeStruct TEST= make("test",false,Field.TEST); + private static final TypeStruct ARY = makeAry("[]i64",TypeInteger.U32,-1,TypeInteger.BOT,-2,false); + private static final TypeStruct STR = makeAry("[]u8" ,TypeInteger.U32,-1,TypeInteger.U8 ,-4,false); + private static final TypeStruct ABC = makeAry("[]u8",TypeInteger.constant(3),-1,TypeConAryB.ABC,-4,true); + + // A pair of self-cyclic types + private static final TypeStruct SINT0 = open("%SINT"); + private static final TypeStruct SFLT0 = open("%SFLT"); + private static final TypeStruct SINT1 = SINT0.add(Field.make("a", TypeInteger.U32, -1, false, false)).add(Field.make("s2",TypeMemPtr.make((byte)2,SFLT0),-2, false, false)); + private static final TypeStruct SFLT1 = SFLT0.add(Field.make("b", TypeFloat .F32, -3, false, false)).add(Field.make("s1",TypeMemPtr.make((byte)2,SINT1),-4, false, false)); + public static final TypeStruct SFLT2 = SFLT1.close(); + + + public static void gather(ArrayList<Type> ts) { + ts.add(BOT); + ts.add(TEST); + ts.add(ARY); + ts.add(STR); + ts.add(ABC); + ts.add(SINT0); + ts.add(SFLT0); + ts.add(SINT1); + ts.add(SFLT1); + ts.add(SFLT2); + ts.add(((TypeMemPtr)(SFLT2.field("s1")._t))._obj); + // Break cyclic init: built a struct + Field fcalloc = Field.make("calloc",TypeFunPtr.CALLOC,-2,true,true); + TypeStruct scalloc = make("calloc",false,fcalloc); + ts.add(scalloc); + + } // Find field index by name public int find(String fname) { @@ -95,10 +155,10 @@ public class TypeStruct extends Type { return -1; } - @Override - Type xmeet(Type t) { + TypeStruct xmeet(Type t) { TypeStruct that = (TypeStruct) t; + assert !isFree() && !that.isFree(); if( this==TOP ) return that; if( that==TOP ) return this; if( this==BOT ) return BOT; @@ -112,96 +172,154 @@ public class TypeStruct extends Type { // And the answer is: "don't ask". if( !_name.equals(that._name) ) return BOT; // It's a struct; that's about all we know - if( this._fields==null ) return that; - if( that._fields==null ) return this; - if( _fields.length != that._fields.length ) return BOT; - // Just do field meets - Field[] flds = new Field[_fields.length]; - for( int i=0; i<_fields.length; i++ ) { + + // if equal, no matters. + // if short is BOT, chop ; recurPre on short. + // if short is TOP, copy long; recurPre on long. + TypeStruct min = _fields.length < that._fields.length ? this : that; + if( _fields.length != that._fields.length && (min._open ^ min==this) ) + return that.xmeet(this); + + // Check all other fields are sanely similar; same struct type but + // different field contents (e.g. field "age" is either 'int' or '18'). + int len = Math.min(_fields.length,that._fields.length); + for( int i=0; i<len; i++ ) { Field f0 = _fields[i], f1 = that._fields[i]; - if( !f0._fname.equals(f1._fname) || f0._alias != f1._alias ) + if( !f0._fname.equals(f1._fname) || f0._alias != f1._alias || f0._one != f1._one ) return BOT; - flds[i] = (Field)f0.meet(f1); } - TypeConAry con = (TypeConAry)_con.meet(that._con); - return make(_name, con, flds); + + // See if we get a mid-recursion hit; breaks cycles + Integer pid = pid(that); + TypeStruct ts = (TypeStruct)VISIT.get(pid); + if( ts!=null ) return ts; + // If not mid-recursion, we are now; flag recursion. + boolean notRecur = VISIT.isEmpty(); + if( notRecur ) recurOpen(); + + // Setup and install the type, prior to recursing, so we can find our + // recursive self again. + ts = recurPre(pid,_open | that._open); + + // Recurse all common fields + Field[] flds = ts._fields; + for( int i=0; i<len; i++ ) { + Field f0 = _fields[i], f1 = that._fields[i]; + flds[i].setType(f0._t.meet(f1._t )); + flds[i]._final = f0._final | f1._final; + } + + // Handle extra fields via `_open` + for( int i=len; i<_fields.length; i++ ) + flds[i].setType(_fields[i]._t ); + + // Cleanup post-recursion; intern/install at cycle end + if( notRecur ) ts = (TypeStruct)ts.recurClose(); + return ts; } @Override - public TypeStruct dual() { - if( this==TOP ) return BOT; - if( this==BOT ) return TOP; - if( _fields == null ) return this; + TypeStruct xdual() { + if( _name=="$STRUCT" ) + return malloc("$STRUCT",false,new Field[0]); Field[] flds = new Field[_fields.length]; for( int i=0; i<_fields.length; i++ ) flds[i] = _fields[i].dual(); - TypeConAry con = _con.dual(); - return make(_name,con,flds); + return malloc(_name,!_open,flds); } - // Keeps the same struct, but lower-bounds all fields. - @Override public TypeStruct glb(boolean mem) { - if( _glb(mem) ) return this; - // Need to glb each field + // Recursive dual + @Override TypeStruct rdual() { + if( _dual!=null ) return dual(); + assert !_terned; Field[] flds = new Field[_fields.length]; + TypeStruct d = malloc(_name,!_open,flds); + (_dual = d)._dual = this; // Cross link duals for( int i=0; i<_fields.length; i++ ) - flds[i] = _fields[i].glb(mem); - return make(_name,flds); - } - private boolean _glb(boolean mem) { - if( _fields!=null ) - for( Field f : _fields ) - if( f.glb(mem) != f ) - return false; - return true; + flds[i] = _fields[i]._terned ? _fields[i].dual() : _fields[i].rdual(); + return d; } // Is forward-reference - @Override public boolean isFRef() { return _fields==null; } + @Override public boolean isFRef() { return _open; } + + @Override boolean _isConstant() { + if( VISIT.containsKey(_uid) ) return true; // Cycles assume constant + VISIT.put(_uid,this); + // Check all fields for being constant + for( Field field : _fields ) + if( !field._isConstant() ) + return false; + return true; + } + // All fields are final - @Override public boolean isFinal() { - if( _fields==null ) return true; + @Override boolean _isFinal() { + if( _open ) return false; // May have more more non-final fields + if( VISIT.containsKey(_uid) ) // Test: been here before? + return true; // Cycles assume final + VISIT.put(_uid,this); // Set: dont do this again for( Field fld : _fields ) - if( !fld.isFinal() ) + if( !fld._isFinal() ) return false; return true; } - @Override public boolean isConstant() { - int len = _fields.length; - // If we have a constant array, then ignore the last 2 array fields- - // they are effectively constant. - - // Fields are given sizes according to their types at *offset time*. - // And thus layout, packing & padding are determined by the Types - // at *offset-time*, which means *offset-time* has to be picked - // when types are Stable - post/during TypeCheck. - - // The array-length field is shared with other like-sized arrays, so - // you are allowed to mix "abc" and "very_hugh_>256_char_string" and - // the resulting TMP can query the length field (getting 3 or >256 - // respectively), and reading from a prolly 16bit length field. - - // Basically asking: forward-flow declared-types, are these compatible? - // Only array-lengths have an issue here? So internally name fields - // `#0` or `#1` or `#2` or `#3`. - // - // Also means I cannot track exact array length without losing the - // "declared type requires a 4-byte field". - // - // Same-same for all fields in a struct, space in memory is based on - // declared-type at least, possible (future work) optimized where all - // memory versions of the same field get a smaller footprint (or even a - // constant past or moved into prototype) past construction - - if( _con!=TypeConAry.BOT ) len -= 2; - // Check all fields for being constant - for( int i=0; i<len; i++ ) - if( !_fields[i].isConstant() ) + private TypeStruct recurPre(Object key, boolean open) { + // Make a clone of original; suitable for hashing so can build + // e.g. TMPs to clone as part of cycles - but will fail the 'eq' check + // until the entire cycle is built. + Field[] flds = new Field[_fields.length]; + for( int i=0; i<flds.length; i++ ) + flds[i] = _fields[i].malloc(); // Blank copy, but can be hashed + TypeStruct ts = malloc(_name, open, flds ); + VISIT.put(key,ts); + return ts; + } + + // Make a read-only version + @Override TypeStruct _makeRO() { + // Check for already visited + TypeStruct ts = (TypeStruct)VISIT.get(_name); + if( ts!=null ) return ts; // Already visited + ts = recurPre(_name,_open); // Make a new type with blank fields + Field[] flds = ts._fields; + for( Field fld : flds ) fld._final = true; + + // Now start the recursion + for( int i=0; i<flds.length; i++ ) + flds[i].setType(_fields[i]._t._makeRO()); + + return ts; + } + + + // All fields are at GLB already + boolean isGLB2() { + if( VISIT.containsKey(_uid) ) return true; // Cycles assume GLB + VISIT.put(_uid,this); + for( Field fld : _fields ) + if( !fld.isGLB2() ) return false; return true; } + // Keeps the same struct, but lower-bounds all fields. + public TypeStruct glb2() { + TypeStruct ts = (TypeStruct)VISIT.get(_name); + if( ts!=null ) return ts; + ts = recurPre(_name,_open); + Field[] flds = ts._fields; + for( int i=0; i<flds.length; i++ ) + flds[i]._final = true ; + + // Now start the recursion + for( int i=0; i<flds.length; i++ ) + flds[i].setType(_fields[i]._t._glb(true)); + + return ts; + } + // log_size for a struct is not defined, unless its exactly some power of // 2. *Total size* is well-defined, and is available in the offsets. @Override public int log_size() { throw Utils.TODO(); } @@ -209,48 +327,79 @@ public class TypeStruct extends Type { @Override public int alignment() { int align = 0; for( Field f : _fields ) - align = Math.max(align, (f._fname!="[]" || _con==TypeConAry.BOT ? f._type : _con).alignment()); + align = Math.max(align, f._t.alignment()); return align; } - @Override - boolean eq(Type t) { + // If false, always false. + // If true , maybe true, need to check recursive fields. + private boolean static_eq( TypeStruct ts ) { + return _name.equals(ts._name) && _open==ts._open && _fields.length==ts._fields.length; + } + + @Override boolean eq(Type t) { + // Recursive; so use cyclic equals + if( !VISIT.isEmpty() ) { + assert CEQUALS.isEmpty(); + boolean rez = cycle_eq(t); + CEQUALS.clear(); + return rez; + } + // Normal equals + TypeStruct ts = (TypeStruct)t; // Invariant + if( !static_eq(ts) ) return false; + if( _fields==ts._fields ) return true; + for( int i = 0; i < _fields.length; i++ ) + if( !_fields[i].eq(ts._fields[i]) ) + return false; + return true; + } + + @Override boolean cycle_eq(Type t) { + if( this==t ) return true; TypeStruct ts = (TypeStruct)t; // Invariant - if( !_name.equals(ts._name) || _con!=ts._con ) - return false; - if( _fields == ts._fields ) return true; - if( _fields==null || ts._fields==null ) return false; - if( _fields.length!=ts._fields.length ) - return false; + if( !static_eq(ts) ) return false; + if( _fields==ts._fields ) return true; + // Check to see if we've ever compared this pair of types before; + // if so, then assume the cycle is equal here. + int pid = pid(ts); + if( CEQUALS.find(pid)!= -1 ) return true; + CEQUALS.push(pid); + // Recursively check fields for( int i = 0; i < _fields.length; i++ ) - if( _fields[i] != ts._fields[i] ) + if( !_fields[i].cycle_eq(ts._fields[i]) ) return false; return true; } @Override int hash() { - long hash = _name.hashCode(); - if( _fields != null ) - for( Field f : _fields ) - hash = Utils.rot(hash,13) ^ f.hashCode(); - return Utils.fold(hash ^ _con.hashCode()); + long hash = _name.hashCode() ^ (_open ? 4 : 0); + for( Field f : _fields ) + hash = Utils.rot(hash,13) ^ ((long)f._fname.hashCode() * f._alias); + return Utils.fold(hash); } + @Override int nkids() { return _fields.length; } + @Override Type at( int idx ) { return _fields[idx]; } + @Override void set( int idx, Type t ) { _fields[idx] = (Field)t; } + @Override - public SB print(SB sb) { - if( _con!=TypeConAry.BOT ) return sb.p(_con.str()); + SB _print(SB sb, BitSet visit, boolean html ) { + if( isFree() ) return sb.p("FREE:").p(_name); + if( isAry() && field("[]")._t instanceof TypeConAry con ) + return sb.p(con.str()); sb.p(_name); - if( _fields == null || isAry() ) // Forward reference struct, just print the name - return sb.p(isFinal() ? "" : "!"); + if( html || isAry() ) + return sb; sb.p(" {"); for( Field f : _fields ) - f._type.print(sb).p(f._final ? " " : " !").p(f._fname).p("; "); + (f._t ==null ? sb.p("---") : f._t.print(sb,visit,html)).p(f._final ? " " : " !").p(f._fname).p("; "); + if( _open ) sb.p("... "); return sb.p("}"); } - @Override public SB gprint( SB sb ) { return sb.p(_name); } - @Override public String str() { return _con==TypeConAry.BOT ? _name : _con.str(); } + @Override public String str() { return (isFree() ? "FREE:":"")+_name; } public boolean isAry() { return _fields.length>=2 && _fields[_fields.length-1]._fname=="[]"; } @@ -262,7 +411,7 @@ public class TypeStruct extends Type { } public int aryScale() { assert isAry(); - return _fields[1]._type.log_size(); + return _fields[1]._t.log_size(); } @@ -273,42 +422,44 @@ public class TypeStruct extends Type { return _offs[idx]; } private int[] offsets() { // Field byte offsets + assert CodeGen.CODE._phase.ordinal() >= CodeGen.Phase.Opto.ordinal(); // Compute a layout for a collection of fields assert _fields != null; // No forward refs // Compute a layout - int[] cnts = new int[5]; // Count of fields at log field size - int flen = _fields.length; - if( isAry() ) flen--; // Array field is aligned differently - for( int i=0; i<flen; i++ ) - cnts[_fields[i]._type.log_size()]++; // Log size is 0(byte), 1(i16/u16), 2(i32/f32), 3(i64/dbl) - int off = 0, idx = 0; // Base common struct fields go here, e.g. Mark/Klass - // Compute offsets to the start of each power-of-2 aligned fields. - int[] offs = new int[4]; - for( int i=3; i>=0; i-- ) { - offs[i] = off; - off += cnts[i]<<i; - } - // Assign offsets to all fields. - // Really a hidden radix sort. _offs = new int[_fields.length+1]; - for( int i=0; i<flen; i++ ) { - int log = _fields[i]._type.log_size(); - _offs[idx++] = offs[log]; // Field offset - offs[log] += 1<<log; // Next field offset at same alignment - cnts[log]--; // Count down, should be all zero at end - } - - // Array bits - if( isAry() ) { + if( isAry() ) { // Arrays used fixed u32 len, padding to elems, var length + assert _fields[1]._fname=="[]"; // Pad out to the element alignment - int align = (_fields[flen]._fname!="[]" || _con==TypeConAry.BOT ? _fields[flen]._type : _con).alignment(); - off = (off + ((1<<align)-1)) & -(1<<align); - _offs[flen] = off; - if( _con!=TypeConAry.BOT ) - _offs[flen+1] = off+_con.len(); - } else + int align = _fields[1]._t.alignment(); + _offs[1] = (4 + ((1<<align)-1)) & -(1<<align); + if( _fields[1]._t instanceof TypeConAry ary ) // Array length is well-defined for constants, not defined for runtime arrays + _offs[2] = _offs[1]+ary.len(); + + } else { + int[] cnts = new int[5]; // Count of fields at log field size + int flen = _fields.length; + for( int i=0; i<flen; i++ ) + if( !_fields[i]._one ) + cnts[_fields[i]._t.log_size()]++; // Log size is 0(byte), 1(i16/u16), 2(i32/f32), 3(i64/dbl) + int off = 0, idx = 0; // Base common struct fields go here, e.g. Mark/Klass + // Compute offsets to the start of each power-of-2 aligned fields. + int[] offs = new int[4]; + for( int i=3; i>=0; i-- ) { + offs[i] = off; + off += cnts[i]<<i; + } + // Assign offsets to all fields. + // Really a hidden radix sort. + for( int i=0; i<flen; i++ ) { + if( _fields[i]._one ) continue; + int log = _fields[i]._t.log_size(); + _offs[idx++] = offs[log]; // Field offset + offs[log] += 1<<log; // Next field offset at same alignment + cnts[log]--; // Count down, should be all zero at end + } _offs[flen] = off; // Max struct size, no trailing padding + } return _offs; } diff --git a/src/main/java/com/seaofnodes/simple/type/TypeTuple.java b/src/main/java/com/seaofnodes/simple/type/TypeTuple.java index bc57871a..df9aba31 100644 --- a/src/main/java/com/seaofnodes/simple/type/TypeTuple.java +++ b/src/main/java/com/seaofnodes/simple/type/TypeTuple.java @@ -1,67 +1,75 @@ package com.seaofnodes.simple.type; -import com.seaofnodes.simple.SB; -import com.seaofnodes.simple.Utils; -import java.util.ArrayList; +import com.seaofnodes.simple.util.Ary; +import com.seaofnodes.simple.util.SB; +import com.seaofnodes.simple.util.Utils; +import java.util.*; public class TypeTuple extends Type { - public final Type[] _types; + public Type[] _types; + private static final Ary<TypeTuple> FREE = new Ary<>(TypeTuple.class); private TypeTuple(Type[] types) { super(TTUPLE); _types = types; } - public static TypeTuple make(Type... types) { return new TypeTuple(types).intern(); } + private TypeTuple init( Type[] types ) { _types = types; return this; } + private static TypeTuple malloc(Type[] types) { + return FREE.isEmpty() ? new TypeTuple(types) : FREE.pop().init(types); + } + // All fields directly listed + public static TypeTuple make(Type... types) { + TypeTuple tt = malloc(types); + TypeTuple t2 = tt.intern(); + return t2==tt ? tt : t2.free(tt); + } + @Override TypeTuple free(Type t) { + TypeTuple tt = (TypeTuple)t; + tt._types = null; + tt._dual = null; + tt._hash = 0; + FREE.push(tt); + return this; + } + @Override boolean isFree() { return _types==null; } - public static final TypeTuple BOT = new TypeTuple(new Type[0]).intern(); - public static final TypeTuple TOP = new TypeTuple(null).intern(); + + public static final TypeTuple BOT = malloc(new Type[0]).intern(); + public static final TypeTuple TOP = BOT.dual(); public static final TypeTuple TEST = make(TypeInteger.BOT,TypeMemPtr.TEST); public static final TypeTuple START= make(Type.CONTROL,TypeMem.TOP,TypeInteger.BOT); - public static final TypeTuple MAIN = make(TypeInteger.BOT); public static final TypeTuple RET = make(Type.CONTROL,TypeMem.BOT,Type.BOTTOM); - public static final TypeTuple CALLOC = make(TypeInteger.BOT,TypeInteger.BOT); - public static final TypeTuple IF_BOTH = make(new Type[]{Type. CONTROL,Type. CONTROL}); - public static final TypeTuple IF_NEITHER = make(new Type[]{Type.XCONTROL,Type.XCONTROL}); - public static final TypeTuple IF_TRUE = make(new Type[]{Type. CONTROL,Type.XCONTROL}); - public static final TypeTuple IF_FALSE = make(new Type[]{Type.XCONTROL,Type. CONTROL}); + public static final TypeTuple IF_BOTH = make(Type. CONTROL,Type. CONTROL); + public static final TypeTuple IF_NEITHER = make(Type.XCONTROL,Type.XCONTROL); + public static final TypeTuple IF_TRUE = make(Type. CONTROL,Type.XCONTROL); + public static final TypeTuple IF_FALSE = make(Type.XCONTROL,Type. CONTROL); - public static void gather(ArrayList<Type> ts) { ts.add(BOT); ts.add(TEST); ts.add(START); ts.add(MAIN); ts.add(IF_TRUE); } + public static void gather(ArrayList<Type> ts) { ts.add(BOT); ts.add(TEST); ts.add(START); ts.add(IF_TRUE); } @Override Type xmeet(Type other) { - TypeTuple tt = (TypeTuple)other; // contract from xmeet - if( this==TOP ) return other; - if( tt ==TOP ) return this ; - if( _types.length != tt._types.length ) + TypeTuple that = (TypeTuple)other; // contract from xmeet + if( this==TOP ) return that; + if( that==TOP ) return this; + if( _types.length != that._types.length ) return BOT; - Type[] ts = new Type[_types.length]; - for( int i=0; i<_types.length; i++ ) - ts[i] = _types[i].meet(tt._types[i]); - return make(ts); + return make(TypeFunPtr.xmeet(_types,that._types)); } - @Override public TypeTuple dual() { - if( this==TOP ) return BOT; - if( this==BOT ) return TOP; - Type[] ts = new Type[_types.length]; - for( int i=0; i<_types.length; i++ ) - ts[i] = _types[i].dual(); - return make(ts); - } - - @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(mem); - return make(ts); + @Override TypeTuple xdual() { + if( _types.length==0 ) return malloc(null); + return malloc(TypeFunPtr.xdual(_types)); } - @Override public boolean isConstant() { + @Override boolean _isConstant() { for( Type t : _types ) - if( !t.isConstant() ) + if( !t._isConstant() ) return false; return true; } + @Override boolean _isFinal() { throw Utils.TODO(); } + + @Override TypeMemPtr _makeRO() { throw Utils.TODO(); } @Override public int log_size() { throw Utils.TODO(); } @Override public int alignment() { @@ -74,25 +82,17 @@ public class TypeTuple extends Type { public Type ret() { assert _types.length==3; return _types[2]; } - @Override public String str() { return print(new SB()).toString(); } - - @Override public SB print(SB sb) { + @Override SB _print(SB sb, BitSet visit, boolean html ) { if( this==TOP ) return sb.p("[TOP]"); if( this==BOT ) return sb.p("[BOT]"); sb.p("[ "); for( Type t : _types ) - t.print(sb).p(", "); - return sb.unchar(2).p("]"); - } - @Override public SB gprint(SB sb) { - if( this==TOP ) return sb.p("[TOP]"); - if( this==BOT ) return sb.p("[BOT]"); - sb.p("[ "); - for( Type t : _types ) - t.gprint(sb).p(", "); + t.print(sb,visit,html).p(", "); return sb.unchar(2).p("]"); } + @Override public String str() { return print(new SB(),new BitSet(),false).toString(); } + @Override int hash() { int sum = 0; @@ -102,15 +102,18 @@ public class TypeTuple extends Type { @Override boolean eq( Type t ) { - TypeTuple tt = (TypeTuple)t; // Contract - if( _types==null && tt._types==null ) return true; - if( _types==null || tt._types==null ) return false; - if( _types.length != tt._types.length ) return false; + TypeTuple that = (TypeTuple)t; // Contract + if( _types==null && that._types==null ) return true; + if( _types==null || that._types==null ) return false; + if( _types.length != that._types.length ) return false; for( int i=0; i<_types.length; i++ ) - if( _types[i]!=tt._types[i] ) + if( _types[i]!=that._types[i] ) return false; return true; } + @Override int nkids() { return _types.length; } + @Override Type at( int idx ) { return _types[idx]; } + @Override void set( int idx, Type t ) { _types[idx] = t; } } diff --git a/src/main/java/com/seaofnodes/simple/Ary.java b/src/main/java/com/seaofnodes/simple/util/Ary.java index f43179ad..d67801c2 100644 --- a/src/main/java/com/seaofnodes/simple/Ary.java +++ b/src/main/java/com/seaofnodes/simple/util/Ary.java @@ -1,4 +1,4 @@ -package com.seaofnodes.simple; +package com.seaofnodes.simple.util; import java.lang.StringBuilder; import java.lang.reflect.Array; @@ -36,6 +36,7 @@ public class Ary<E> extends AbstractList<E> implements List<E> { /** @return last element */ public E last( ) { return at(_len-1); } + public E last(int x ) { return at(_len-1+x); } /** Add element in amortized constant time * @param e Element to add at end of list diff --git a/src/main/java/com/seaofnodes/simple/util/AryInt.java b/src/main/java/com/seaofnodes/simple/util/AryInt.java new file mode 100644 index 00000000..b498fd78 --- /dev/null +++ b/src/main/java/com/seaofnodes/simple/util/AryInt.java @@ -0,0 +1,192 @@ +package com.seaofnodes.simple.util; + +import java.util.Arrays; +import java.util.Collection; +import java.util.function.IntUnaryOperator; + +// ArrayList with saner syntax +public class AryInt { + public int[] _es; + public int _len; + public AryInt(int[] es) { this(es,es.length); } + public AryInt(int[] es, int len) { _es=es; _len=len; } + public AryInt() { this(new int[1],0); } + + /** @return list is empty */ + public boolean isEmpty() { return _len==0; } + /** @return active list length */ + public int len() { return _len; } + /** @param i element index + * @return element being returned; throws if OOB */ + public int at( int i ) { + range_check(i); + return _es[i]; + } + /** @param i element index + * @return element being returned, or 0 if OOB */ + public int atX( int i ) { + return i < _len ? _es[i] : 0; + } + /** @return last element */ + public int last( ) { return at(_len-1); } + public int last(int x ) { return at(_len-1+x); } + + /** @return remove and return last element */ + public int pop( ) { + range_check(0); + return _es[--_len]; + } + + /** Add element in amortized constant time + * @param e element to add at end of list + * @return 'this' for flow-coding */ + public AryInt push( int e ) { + if( _len >= _es.length ) _es = Arrays.copyOf(_es,Math.max(1,_es.length<<1)); + _es[_len++] = e; + return this; + } + + /** Slow, linear-time, element insert. Preserves order. + * @param i index to insert at, between 0 and _len inclusive. + * @param e intlement to insert + */ + public void insert( int i, int 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 int del( int i ) { + range_check(i); + int tmp = _es[i]; + _es[i]=_es[--_len]; + return tmp; + } + + /** Slow, linear-time, element removal. Preserves order. + * @param i element to be removed + * @return element removed */ + public int remove( int i ) { + range_check(i); + int e = _es[i]; + System.arraycopy(_es,i+1,_es,i,(--_len)-i); + return e; + } + + /** Remove all elements */ + public void clear( ) { Arrays.fill(_es,0,_len,0); _len=0; } + + // Extend and set + public int setX( int i, int e ) { + while( i>= _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + if( i >= _len ) _len = i+1; + return (_es[i] = e); + } + + public int set( int i, int e ) { + range_check(i); + return (_es[i] = e); + } + + public AryInt set_as( int e ) { _es[0] = e; _len=1; return this; } + public AryInt set_len( 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); + return this; + } + + /** @param c Collection to be added */ + public AryInt addAll( Collection<? extends Integer> c ) { for( int e : c ) push(e); return this; } + + /** @param es Array to be added */ + public AryInt addAll( int[] es ) { + if( 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 es Array to be added */ + public AryInt addAll( AryInt ary ) { + if( ary._len==0 ) return this; + while( _len+ary._len > _es.length ) _es = Arrays.copyOf(_es,_es.length<<1); + System.arraycopy(ary._es,0,_es,_len,ary._len); + _len += ary._len; + return this; + } + + public AryInt map_update( IntUnaryOperator f ) { for( int i = 0; i<_len; i++ ) _es[i] = f.applyAsInt(_es[i]); return this; } + + /** @return compact array version, using the internal base array where possible. */ + public int[] asAry() { return _len==_es.length ? _es : Arrays.copyOf(_es,_len); } + + /** Sorts in-place */ + public void sort_update() { Arrays.sort(_es, 0, _len); } + /** 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 intlement to find + * @return index of first matching element, or -1 if none */ + public int find( int e ) { + for( int i=0; i<_len; i++ ) if( _es[i]==e ) return i; + return -1; + } + + @Override public String toString() { + SB sb = new SB().p('['); + for( int i=0; i<_len; i++ ) + sb.p(_es[i]).p(','); + return sb.unchar().p(']').toString(); + } + + private void range_check( int i ) { + if( i < 0 || i>=_len ) + throw new ArrayIndexOutOfBoundsException(""+i+" >= "+_len); + } + + // Binary search sorted _es. Returns insertion point. + // Undefined results if _es is not sorted. + public int binary_search( int e ) { + int lo=0, hi=_len-1; + while( lo <= hi ) { + int mid = (hi + lo) >>> 1; // midpoint, rounded down + int mval = _es[mid]; + if( e==mval ) { + // If dups, get to the first. + while( mid>0 && e==_es[mid-1] ) mid--; + return mid; + } + if( e >mval ) lo = mid+1; + else hi = mid-1; + } + return lo; + } + + // 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 AryInt 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] != ary._es[i] ) + return false; + return true; + } + @Override public int hashCode( ) { + int sum=_len; + for( int i=0; i<_len; i++ ) + sum += _es[i]; + return sum; + } +} diff --git a/src/main/java/com/seaofnodes/simple/SB.java b/src/main/java/com/seaofnodes/simple/util/SB.java index 978fbed9..d7afd6eb 100644 --- a/src/main/java/com/seaofnodes/simple/SB.java +++ b/src/main/java/com/seaofnodes/simple/util/SB.java @@ -1,4 +1,4 @@ -package com.seaofnodes.simple; +package com.seaofnodes.simple.util; /** Tight/tiny StringBuilder wrapper. * Short short names on purpose; so they don't obscure the printing. diff --git a/src/main/java/com/seaofnodes/simple/Utils.java b/src/main/java/com/seaofnodes/simple/util/Utils.java index 1346c3ea..577a60af 100644 --- a/src/main/java/com/seaofnodes/simple/Utils.java +++ b/src/main/java/com/seaofnodes/simple/util/Utils.java @@ -1,4 +1,4 @@ -package com.seaofnodes.simple; +package com.seaofnodes.simple.util; import java.util.ArrayList; |
