package com.seaofnodes.simple.node; import com.seaofnodes.print.ExprPrinter; import com.seaofnodes.simple.Parser; import com.seaofnodes.simple.codegen.CodeGen; import com.seaofnodes.simple.type.Type; import com.seaofnodes.simple.type.TypeFunPtr; import com.seaofnodes.simple.type.TypeMem; import com.seaofnodes.simple.type.TypeRPC; import com.seaofnodes.simple.type.XInt; import com.seaofnodes.simple.util.BAOS; import com.seaofnodes.simple.util.Utils; import java.util.HashMap; import java.util.IdentityHashMap; /** * Call */ public class CallNode extends CFGNode { // Source location for late reported errors public final Parser.Lexer _loc; public CallNode(Parser.Lexer loc, Node... nodes) { super(nodes); _loc = loc; } public CallNode(CallNode call) { super(call); _loc = call._loc; } @Override public Tag serialTag() { return Tag.Call; } public void packed( BAOS baos, HashMap strs, HashMap types, IdentityHashMap anodes ) { baos.packed1(nIns()); } static Node make( BAOS bais ) { return new CallNode(null,new Node[bais.packed1()]); } @Override protected ExprPrinter _print1(ExprPrinter p) { String fname = name(); if( fname == null ) p.n(fptr()); else p.p(fname); p.p("( "); for( int i=2; i0 && out(0) instanceof CallEndNode cend ) { assert _cend()==cend; return cend; } else { assert _cend()==null; return null; } } private CallEndNode _cend() { CallEndNode cend=null; for( Node n : _outputs ) if( n instanceof CallEndNode cend0 ) { assert cend == null; cend = cend0; } return cend; } // Get the one control following; error to call with more than one e.g. an // IfNode or other multi-way branch. @Override public CFGNode uctrl() { return cend(); } @Override public Type compute() { return ctrl()._type; } @Override public Node idealize() { CallEndNode cend = cend(); if( cend==null ) return null; // Still building // Link: call calls target function. Linking makes the target FunNode // point to this Call, and all his Parms point to the call arguments; // also the CallEnd points to the Return. Node progress = null; if( fptr()._type instanceof TypeFunPtr tfp && tfp.nargs() == nargs() ) { // If fidxs is negative, then infinite unknown functions int[] fidxs = tfp.fidxs(); if( !XInt.isHigh(fidxs) ) { // Walk the bits and link for( int fidx = XInt.next(fidxs,0); fidx > 0; fidx = XInt.next(fidxs,fidx) ) { FunNode fun = CodeGen.CODE.link(fidx); if( fun!=null && !fun._folding && !linked(fun) ) progress = link(fun); } } } return progress; } // True if Fun is linked to this Call public boolean linked( FunNode fun ) { for( Node n : fun._inputs ) if( n == this ) return true; return false; } // Link so this calls fun public Node link( FunNode fun ) { assert !linked(fun); CodeGen.CODE.add(fun).addDef(this); for( Node use : fun._outputs ) if( use instanceof ParmNode parm ) { Node def = parm._idx==0 ? ConstantNode.seed(cend()._rpc).peephole() : arg(parm._idx); CodeGen.CODE.add(parm).addDef(def); // Linking can happen during post-SCCP inlining. Keep an RPC // Parm's cached finite set synchronized with its newly added // input instead of waiting for the next worklist visit. if( parm._idx==0 && parm._type instanceof TypeRPC ) parm._type = parm._type.meet(def._type); } // Call end points to function return CodeGen.CODE.add(cend()).addDef(fun.ret()); return this; } // Unlink a single function public void unlink( FunNode fun, int path ) { assert linked(fun); for( Node use : fun._outputs ) if( use instanceof ParmNode ) use.delDef(path); fun.delDef(path); CodeGen.CODE.add(fun); CallEndNode cend = cend(); ReturnNode ret = fun.ret(); if( cend != null ) { ret.keep(); cend.delDef(cend._inputs.find(ret)); CodeGen.CODE.add(cend); ret.unkeep(); } assert !linked(fun); } // Unlink all linked functions public void unlink_all() { for( int i=0; i<_outputs._len; i++ ) if( out(i) instanceof FunNode fun ) { int path = fun._inputs.find(this); unlink(fun,path); i--; } } @Override public Parser.ParseException err() { if( fptr()._type == Type.BOTTOM ) return null; // Wrong, but failing earlier if( !(fptr()._type instanceof TypeFunPtr tfp) ) return Parser.error("Expected a function, but found " + fptr()._type, _loc); if( !tfp.notNull() ) return Parser.error( "Might be null calling "+tfp, _loc); if( nargs() != tfp.nargs() ) return Parser.error( "Expecting "+tfp.nargs()+" arguments, but found "+nargs(), _loc); // Check for args for( int i=0; i