aa
FunNode.java
Go to the documentation of this file.
1 package com.cliffc.aa.node;
2 
3 import com.cliffc.aa.Env;
4 import com.cliffc.aa.GVNGCM;
5 import com.cliffc.aa.tvar.TV2;
6 import com.cliffc.aa.type.*;
7 import com.cliffc.aa.util.*;
8 import org.jetbrains.annotations.NotNull;
9 
10 import java.util.*;
11 
12 import static com.cliffc.aa.AA.*;
13 
14 // FunNodes are lexically scoped. During parsing/graph-gen a closure is
15 // allocated for local variables as a standard NewObj. Local escape analysis
16 // is used to remove NewObjs that do not escape the local lifetime. Scoped
17 // variables pass in their NewObj pointer just "as if" a normal struct.
18 //
19 // Function bodies are self-contained; they only take data in through ParmNodes
20 // and ConNodes, and only control through the Fun. They only return values
21 // through the Ret - including exposed lexically scoped uses.
22 //
23 // FunNode is a RegionNode; args point to all the known callers. Zero slot is
24 // null, same as a C2 Region. Args 1+ point to the callers control. Before
25 // GCP/opto arg 1 points to ALL_CTRL as the generic unknown worse-case caller.
26 // ALL_CTRL is removed just prior to GCP, the precise call-graph is discovered,
27 // and calls are directly wired to the FunNode as part of GCP. After GCP the
28 // call-graph is known precisely and is explicit in the graph.
29 //
30 // FunNodes are finite in count and are unique densely numbered, see BitsFun.
31 // A single function number is generally called a 'fidx' and collections 'fidxs'.
32 //
33 // Pointing to the FunNode are ParmNodes which are also PhiNodes; one input
34 // path for each known caller. Zero slot points to the FunNode. Arg1 points
35 // to the generic unknown worse-case caller (a type-specific ConNode with
36 // worse-case legit bottom type). ParmNodes merge all input path types (since
37 // they are a Phi), and the call "loses precision" for type inference there.
38 // Parm#1 and up (NOT the zero-slot but the zero idx) are the classic function
39 // arguments; Parm#-1 is for the RPC and Parm#0 is for memory.
40 //
41 // Ret points to the return control, memory, value and RPC, as well as the
42 // original Fun. A FunPtr points to a Ret, and a Call will use a FunPtr (or a
43 // merge of FunPtrs) to indicate which function it calls. After a call-graph
44 // edge is discovered, the Call is "wired" to the Fun. A CallEpi points to the
45 // Ret, the Fun control points to a CProj to the Call, and each Parm points to
46 // a DProj (MProj) to the Call. These direct edges allow direct data flow
47 // during gcp & iter.
48 //
49 // Memory both is and is-not treated special: the function body flows memory
50 // through from the initial Parm to the Ret in the normal way. However the
51 // incoming memory argument is specifically trimmed by the Call to only those
52 // aliases used by the function body (either read or write), and the Ret only
53 // returns those memories explicitly written. All the other aliases are
54 // treated as "pass-through" and explicitly routed around the Fun/Ret by the
55 // Call/CallEpi pair.
56 
57 
58 public class FunNode extends RegionNode {
59  public String _name; // Debug-only name
60  public String _bal_close; // null for everything except "balanced oper functions", e.g. "[]"
61  public int _fidx; // Unique number for this piece of code
62  public TypeFunSig _sig; // Apparent signature; clones typically sharpen
63  // Operator precedence; only set on top-level primitive wrappers.
64  // -1 for normal non-operator functions and -2 for forward_decls.
65  public final byte _op_prec; // Operator precedence; only set on top-level primitive wrappers
66  // Function is parsed infix, with the RHS argument thunked. Flag is used by
67  // the Parser only for short-circuit operations like '||' and '&&'.
68  public final boolean _thunk_rhs;
69  // Hindly-Milner non-generative set, used during cloning
70  private TV2[] _nongens;
71 
72  private byte _cnt_size_inlines; // Count of size-based inlines; prevents infinite unrolling via inlining
73  public static int _must_inline; // Used for asserts
74 
75  // Used to make the primitives at boot time. Note the empty displays: in
76  // theory Primitives should get the top-level primitives-display, but in
77  // practice most primitives neither read nor write their own scope.
78  public FunNode( PrimNode prim) { this(prim._name,prim._sig,prim._op_prec,prim._thunk_rhs); }
79  public FunNode(NewNode.NewPrimNode prim) { this(prim._name,prim._sig,prim._op_prec,false); }
80  // Used to start an anonymous function in the Parser
81  public FunNode(String[] flds, Type[] ts) { this(null,TypeFunSig.make(flds,TypeTuple.make_args(ts),TypeTuple.RET),-1,false); }
82  // Used to forward-decl anon functions
84  // Shared common constructor
85  FunNode(String name, TypeFunSig sig, int op_prec, boolean thunk_rhs ) { this(name,sig,op_prec,thunk_rhs,BitsFun.new_fidx()); }
86  // Shared common constructor
87  private FunNode(String name, TypeFunSig sig, int op_prec, boolean thunk_rhs, int fidx) {
88  super(OP_FUN);
89  _name = name;
90  _fidx = fidx;
91  _sig = sig;
92  _op_prec = (byte)op_prec;
93  _thunk_rhs = thunk_rhs;
94  FUNS.setX(fidx(),this); // Track FunNode by fidx; assert single-bit fidxs
95  keep(); // Always keep, until RetNode is constructed
96  }
97 
98  // Find FunNodes by fidx
99  static Ary<FunNode> FUNS = new Ary<>(new FunNode[]{null,});
100  public static void reset() { FUNS.clear(); _must_inline=0; }
101  public static FunNode find_fidx( int fidx ) { return FUNS.atX(fidx); }
102  int fidx() { return _fidx; }
103 
104  // Short self name
105  @Override public String xstr() { return name(); }
106  // Inline longer info
107  @Override public String str() { return is_forward_ref() ? xstr() : _sig.str(new SB(),new VBitSet(),null,false).toString(); }
108  // Name from fidx alone
109  private static String name( int fidx, boolean debug) {
110  FunNode fun = find_fidx(fidx);
111  return fun==null ? name(null,null,fidx,-1,false,debug) : fun.name(debug);
112  }
113  // Name from FunNode
114  String name() { return name(true); }
115  public String name(boolean debug) {
116  String name = _name;
117  if( name==null ) {
118  FunPtrNode fptr = fptr();
119  name=fptr==null ? null : fptr._name;
120  }
121  return name(name,_bal_close,fidx(),_op_prec,is_forward_ref(),debug);
122  }
123  static String name(String name, String bal, int fidx, int op_prec, boolean fref, boolean debug) {
124  if( op_prec >= 0 && name != null ) name = '{'+name+(bal==null?"":bal)+'}'; // Primitives wrap
125  if( name==null ) name="";
126  if( debug ) name = name + "["+fidx+"]"; // FIDX in debug
127  return fref ? "?"+name : name; // Leading '?'
128  }
129 
130  // Can return nothing, or "name" or "[name0,name1,name2...]" or "[35]"
131  public static SB names(BitsFun fidxs, SB sb, boolean debug ) {
132  int fidx = fidxs.abit();
133  if( fidx >= 0 ) return sb.p(name(fidx,debug));
134  if( fidxs==BitsFun.EMPTY ) return sb.p("[]");
135  // See if this is just one common name, common for overloaded functions
136  String s=null;
137  boolean prim=false;
138  for( Integer ii : fidxs ) {
139  FunNode fun = find_fidx(ii);
140  if( fun!=null ) {
141  prim |= fun._op_prec >= 0;
142  if( fun._name != null ) s = fun._name;
143  else if( !fun.is_dead() )
144  for( Node fptr : fun.ret()._uses ) // For all displays for this fun
145  if( fptr instanceof FunPtrNode ) {
146  String name = ((FunPtrNode)fptr)._name; // Get debug name
147  if( s==null ) s=name; // Capture debug name
148  else if( !Util.eq(s,name) ) // Same name is OK
149  { s=null; break; } // Too many different names
150  }
151  if( s==null ) break; // Unnamed fidx
152  }
153  }
154  if( s!=null )
155  if( prim ) sb.p('{').p(s).p('}'); else sb.p(s);
156  // Make a list of the fidxs
157  if( debug ) {
158  int cnt = 0;
159  sb.p('[');
160  for( Integer ii : fidxs ) {
161  if( ++cnt == 5 ) break;
162  sb.p(ii).p(fidxs.above_center() ? '+' : ',');
163  }
164  if( cnt >= 5 ) sb.p("...");
165  else sb.unchar();
166  sb.p(']');
167  }
168  return sb;
169  }
170 
171  // Debug only: make an attempt to bind name to a function
172  public void bind( String tok ) {
173  if( _name==null ) _name = tok;
174  if( !_name.equals(tok) ) // Attempt to double-bind
175  _name = _name+":"+tok;
176  }
177 
178  // This function has disabled inlining
179  public boolean noinline() { return in(0)==null && name(false).startsWith("noinline"); }
180 
181  // Never inline with a nested function
182  @Override @NotNull public Node copy( boolean copy_edges) { throw unimpl(); }
183 
184  // True if may have future unknown callers.
185  boolean has_unknown_callers() { return _defs._len > 1 && in(1) == Env.ALL_CTRL; }
186  // Formal types.
187  Type formal(int idx) {
188  return idx == -1 ? TypeRPC.ALL_CALL : _sig.arg(idx);
189  }
190  public int nargs() { return _sig.nargs(); }
191 
192  public void set_nongens(TV2[] nongens) { _nongens = nongens; }
193 
194  // ----
195  // Graph rewriting via general inlining. All other graph optimizations are
196  // already done.
197  @Override public Node ideal_reduce() {
198  Node rez = super.ideal_reduce();
199  if( rez != null ) return rez;
200  // Check for FunPtr/Ret dead/gone, and the function is no longer callable
201  // from anybody.
202  RetNode ret = ret();
203  if( has_unknown_callers() && ret==null && _keep==0 ) {
204  assert !is_prim();
205  assert in(1)==Env.ALL_CTRL;
206  return set_def(1,Env.XCTRL);
207  }
208 
209  // Update _sig if parms are unused. SIG falls during Iter and lifts during
210  // GCP. If parm is missing or not-live, then the corresponding SIG
211  // argument can be ALL (all args allowed, including errors).
212  if( !is_forward_ref() && !is_prim() && _keep==0 ) {
213  Node[] parms = parms();
214  TypeFunSig progress = _sig;
215  for( int i=1; i<parms.length; i++ )
216  if( (parms[i]==null || parms[i]._live==TypeMem.DEAD) && _sig._formals.at(i)!=Type.ALL )
218  // Can resolve some least_cost choices
219  if( progress != _sig ) {
220  FunPtrNode fptr = fptr();
221  if( fptr != null )
222  for( Node use : fptr()._uses )
223  if( use instanceof UnresolvedNode )
224  Env.GVN.add_reduce_uses(use);
225  }
226  }
227 
228  return null;
229  }
230 
231  public Node ideal_inline(boolean check_progress) {
232  // If no trailing RetNode and hence no FunPtr... function is uncallable
233  // from the unknown caller.
234  RetNode ret = ret();
235  if( has_unknown_callers() && ret == null && Env.GVN._opt_mode != GVNGCM.Mode.Parse ) // Dead after construction?
236  return null;
237 
238  if( is_forward_ref() ) return null; // No mods on a forward ref
239  Node[] parms = parms();
240  Node rpc_parm = parms[0];
241  if( rpc_parm == null ) return null; // Single caller const-folds the RPC, but also inlines in CallNode
242  if( !check_callers() ) return null;
243  if( _defs._len <= 2 ) return null; // No need to split callers if only 1
244 
245  // Every input path is wired to an output path
246  for( int i=1+(has_unknown_callers() ? 1 : 0); i<_defs._len; i++ ) {
247  Node c = in(i);
248  if( !(c.in(0) instanceof CallNode) ) return null; // If this is not a CallNode, just bail
249  CallNode call = (CallNode)c.in(0);
250  CallEpiNode cepi = call.cepi();
251  if( cepi==null ) return null;
252  assert cepi._defs.find(ret)!= -1; // If this is not wired, just bail
253  }
254  // Memory is not 'lifted' by DefMem, a sign that a bad-memory-arg is being
255  // passed in.
256  if( has_unknown_callers() ) {
257  Node mem = parms[MEM_IDX];
258  if( mem!=null && !mem._val.isa(Env.DEFMEM._val) )
259  return null; // Do not inline a bad memory type
260  }
261 
262  // Look for appropriate type-specialize callers
263  TypeTuple formals = _thunk_rhs ? null : type_special(parms);
264  Ary<Node> body = find_body(ret);
265  int path = -1; // Paths will split according to type
266  if( formals == null ) { // No type-specialization to do
267  formals = _sig._formals; // Use old args
268  if( _cnt_size_inlines >= 10 && !is_prim() ) return null;
269  // Large code-expansion allowed; can inline for other reasons
270  path = _thunk_rhs ? 2 : split_size(body,parms); // Forcible size-splitting first path
271  if( path == -1 ) return null;
272  assert CallNode.ttfp(in(path).val(0)).fidx()!=-1; // called by a single-target call
273  if( !is_prim() ) _cnt_size_inlines++; // Disallow infinite size-inlining of recursive non-primitives
274  }
275 
276  // Check for dups (already done this but failed to resolve all calls, so trying again).
277  TypeTuple fformals = formals;
278  if( path == -1 && FUNS.find(fun -> fun != null && !fun.is_dead() &&
279  fun._sig._formals==fformals && fun._sig._ret == _sig._ret &&
280  fun.in(1)==in(1)) != -1 )
281  return null; // Done this before
282  if( noinline() ) return null;
283 
284  assert _must_inline==0; // Failed to inline a prior inline?
285  if( path > 0 ) _must_inline = in(path).in(0)._uid;
286  assert !check_progress; // Not expecting progress
287 
288  // --------------
289  // Split the callers according to the new 'fun'.
290  FunNode fun = make_new_fun(ret, formals);
291  split_callers(ret,fun,body,path);
292  assert Env.START.more_flow(true)==0; // Initial conditions are correct
293  return this;
294  }
295 
296  @Override void unwire(int idx) {
297  Node ctl = in(idx);
298  if( !(ctl instanceof ConNode) ) {
299  if( ctl.in(0)._op != OP_CALL ) return;
300  CallNode call = (CallNode)ctl.in(0);
301  CallEpiNode cepi = call.cepi();
302  if( cepi != null ) {
303  int ridx = cepi._defs.find(ret());
304  if( ridx != -1 ) Env.GVN.add_flow(cepi).remove(ridx);
305  }
306  }
307  }
308 
309  // Return false if any input path is dead (would rather fold away dead paths
310  // before inlining), or if not exactly 1 return.
311  private boolean check_callers( ) {
312  // No dead input paths
313  for( int i=1; i<_defs._len; i++ ) if( val(i)==Type.XCTRL && !in(i).is_prim() ) return false;
314  // Gather the ParmNodes and the RetNode. Ignore other (control) uses
315  Node ret=null;
316  for( Node use : _uses )
317  if( use instanceof RetNode ) {
318  if( ret!=null && ret!=use ) return false;
319  ret = use;
320  }
321  return true;
322  }
323 
324  // Visit all ParmNodes, looking for unresolved call uses that can be improved
325  // by type-splitting
326  private int find_type_split_index( Node[] parms ) {
327  assert has_unknown_callers();// Only overly-wide calls.
328  for( Node parm : parms ) // For all parms
329  if( parm != null ) // (some can be dead)
330  for( Node use : parm._uses ) { // See if a parm-user needs a type-specialization split
331  if( use instanceof CallNode ) {
332  CallNode call = (CallNode)use;
333  Node fdx = call.fdx();
334  if( fdx instanceof FreshNode ) fdx = ((FreshNode)fdx).id();
335  if( (fdx==parm && !parm._val.isa(TypeFunPtr.GENERIC_FUNPTR) ) ||
336  fdx instanceof UnresolvedNode ) { // Call overload not resolved
337  Type t0 = parm.val(1); // Generic type in slot#1
338  for( int i=2; i<parm._defs._len; i++ ) { // For all other inputs
339  Type tp = parm.val(i);
340  if( tp.above_center() ) continue; // This parm input is in-error
341  Type ti = tp.widen(); // Get the widen'd type
342  if( !ti.isa(t0) ) continue; // Must be isa-generic type, or else type-error
343  if( ti != t0 ) return i; // Sharpens? Then splitting here should help
344  }
345  }
346  // Else no split will help this call, look for other calls to help
347  }
348  }
349 
350  return -1; // No unresolved calls; no point in type-specialization
351  }
352 
353  // Find types for which splitting appears to help.
354  private Type[] find_type_split( Node[] parms ) {
355  assert has_unknown_callers(); // Only overly-wide calls.
356 
357  // Look for splitting to help an Unresolved Call.
358  int idx = find_type_split_index(parms);
359  if( idx != -1 ) { // Found; split along a specific input path using widened types
360  Type[] sig = Types.get(parms.length);
361  sig[CTL_IDX] = Type.CTRL;
362  sig[MEM_IDX] = TypeMem.MEM;
363  sig[DSP_IDX] = parms[DSP_IDX]==null
364  ? _sig.display().simple_ptr()
365  : parms[DSP_IDX].val(idx);
366  for( int i=ARG_IDX; i<parms.length; i++ )
367  sig[i] = parms[i]==null ? Type.ALL : parms[i].val(idx).widen();
368  return sig;
369  }
370 
371  // Look for splitting to help a pointer from an unspecialized type
372  boolean progress = false;
373  Type[] sig = new Type[parms.length];
374  Type tmem = parms[MEM_IDX]._val;
375  sig[CTL_IDX] = Type.CTRL;
376  sig[MEM_IDX] = TypeMem.MEM;
377  if( tmem instanceof TypeMem ) {
378  for( int i=DSP_IDX; i<parms.length; i++ ) { // For all parms
379  Node parm = parms[i];
380  if( parm == null ) { sig[i]=Type.ALL; continue; } // (some can be dead)
381  if( parm._val==Type.ALL ) return null; // No split with error args
382  sig[i] = parm._val; // Current type
383  if( i==DSP_IDX ) continue; // No split on the display
384  // Best possible type
385  Type tp = Type.ALL;
386  for( Node def : parm._defs )
387  if( def != this )
388  tp = tp.join(def._val);
389  if( !(tp instanceof TypeMemPtr) ) continue; // Not a pointer
390  TypeObj to = ((TypeMem)tmem).ld((TypeMemPtr)tp).widen(); //
391  // Are all the uses of parm compatible with this TMP?
392  // Also, flag all used fields.
393  if( bad_mem_use(parm, to) )
394  continue; // So bad usage
395 
396  sig[i] = TypeMemPtr.make(BitsAlias.FULL,to); // Signature takes any alias but has sharper guts
397  progress = true;
398  }
399  }
400  if( progress ) return sig;
401 
402  return null;
403  }
404 
405  // Check all uses are compatible with sharpening to a pointer.
406  // TODO: Really should be a virtual call
407  private static boolean bad_mem_use( Node n, TypeObj to) {
408  for( Node use : n._uses ) {
409  switch( use._op ) {
410  case OP_NEWOBJ: break; // Field use is like store.value use
411  case OP_IF: break; // Zero check is ok
412  case OP_CAST: // Cast propagates check
413  case OP_FRESH: // No value change
414  if( bad_mem_use(use, to) ) return true;
415  break;
416  case OP_LOAD:
417  if( !(to instanceof TypeStruct) ||
418  ((LoadNode)use).find((TypeStruct)to)== -1 )
419  return true; // Did not find field
420  break;
421  case OP_STORE:
422  if( ((StoreNode)use).rez()==n) break; // Storing as value is ok
423  if( !(to instanceof TypeStruct) || // Address needs to find field
424  ((StoreNode)use).find((TypeStruct)to)== -1 )
425  return true; // Did not find field
426  break;
427  case OP_CALL: break; // Argument pass-thru probably needs to check formals
428  case OP_RET: break; // Return pass-thru should be ok
429  case OP_NEWSTR:
430  TypeFunSig sig = ((NewStrNode)use)._sig;
431  Type formal = sig._formals.at(use._defs.find(n)-2);
432  if( !TypeMemPtr.OOP0.dual().isa(formal) )
433  return true;
434  break;
435  case OP_NAME: break; // Pointer to a nameable struct
436  case OP_PRIM:
437  if( use instanceof PrimNode.EQ_OOP ) break;
438  if( use instanceof PrimNode.NE_OOP ) break;
439  if( use instanceof MemPrimNode.LValueLength ) break;
440  if( use instanceof MemPrimNode.LValueRead )
441  if( ((MemPrimNode)use).idx() == n ) return true; // Use as index is broken
442  else break; // Use for array base is fine
443  if( use instanceof MemPrimNode.LValueWrite || use instanceof MemPrimNode.LValueWriteFinal )
444  if( ((MemPrimNode)use).idx() == n ) return true; // Use as index is broken
445  else break; // Use for array base or value is fine
446  if( use instanceof PrimNode.MulF64 ) return true;
447  if( use instanceof PrimNode.MulI64 ) return true;
448  if( use instanceof PrimNode.AndI64 ) return true;
449  if( use instanceof PrimNode.EQ_F64 ) return true;
450  if( use instanceof PrimNode.EQ_I64 ) return true;
451  throw unimpl();
452  default: throw unimpl();
453  }
454  }
455  return false;
456  }
457 
458 
459  // Look for type-specialization inlining. If any ParmNode has an unresolved
460  // Call user, then we'd like to make a clone of the function body (in least
461  // up to getting all the Unresolved functions to clear out). The specialized
462  // code uses generalized versions of the arguments, where we only specialize
463  // on arguments that help immediately.
464  //
465  // Same argument for field Loads from unspecialized values.
467  if( !has_unknown_callers() ) return null; // Only overly-wide calls.
468  Type[] sig = find_type_split(parms);
469  if( sig == null ) return null; // No unresolved calls; no point in type-specialization
470  // Make a new function header with new signature
471  TypeTuple formals = TypeTuple.make_args(sig);
472  if( !formals.isa(_sig._formals) ) return null; // Fails in error cases
473  return formals == _sig._formals ? null : formals; // Must see improvement
474  }
475 
476 
477  // Return the function body.
479  // Find the function body. Do a forwards walk first, stopping at the
480  // obvious function exit. If function does not expose its display then
481  // this is the complete function body with nothing extra walked. If it has
482  // a nested function or returns a nested function then its display is may
483  // be reached by loads & stores from outside the function.
484  //
485  // Then do a backwards walk, intersecting with the forwards walk. A
486  // backwards walk will find upwards-exposed values, typically constants and
487  // display references - could be a lot of them. Minor opt to do the
488  // forward walk first.
489  VBitSet freached = new VBitSet(); // Forwards reached
490  Ary<Node> work = new Ary<>(new Node[1],0);
491  work.add(this); // Prime worklist
492  while( !work.isEmpty() ) { // While have work
493  Node n = work.pop(); // Get work
494  int op = n._op; // opcode
495  if( op == OP_FUN && n != this ) continue; // Call to other function, not part of inlining
496  if( op == OP_PARM && n.in(0) != this ) continue; // Arg to other function, not part of inlining
497  if( op == OP_DEFMEM ) continue; // Never part of body, but reachable from all allocations
498  if( op == OP_RET && n != ret ) continue; // Return (of other function)
499  // OP_FUNPTR: Can be reached from an internal NewObjNode/display, or
500  // following the local Return. The local FunPtrs are added below.
501  // Adding the reached FunPtrs here clones them, making new FunPtrs using
502  // either the old or new display.
503  if( freached.tset(n._uid) ) continue; // Already visited?
504  if( op == OP_RET ) continue; // End of this function
505  if( n instanceof ProjNode && n.in(0) instanceof CallNode ) continue; // Wired call; all projs lead to other functions
506  work.addAll(n._uses); // Visit all uses
507  }
508 
509  // Backwards walk, trimmed to reachable from forwards
510  VBitSet breached = new VBitSet(); // Backwards and forwards reached
511  Ary<Node> body = new Ary<>(new Node[1],0);
512  for( Node use : ret._uses ) // Include all FunPtrs as part of body
513  if( use instanceof FunPtrNode )
514  body.push(use);
515  work.add(ret);
516  while( !work.isEmpty() ) { // While have work
517  Node n = work.pop(); // Get work
518  if( n==null ) continue; // Defs can be null
519  if( !freached.get (n._uid) ) continue; // Not reached from fcn top
520  if( breached.tset(n._uid) ) continue; // Already visited?
521  body.push(n); // Part of body
522  work.addAll(n._defs); // Visit all defs
523  if( n.is_multi_head() ) // Multi-head?
524  work.addAll(n._uses); // All uses are ALSO part, even if not reachable in this fcn
525  }
526  return body;
527  }
528 
529  // Split a single-use copy (e.g. fully inline) if the function is "small
530  // enough". Include anything with just a handful of primitives, or a single
531  // call, possible with a single if. Disallow functions returning a new
532  // allocation & making other (possibly recursive) calls: the recursive-loop
533  // prevents lifting the allocations from the default parent to either child
534  // without a full GCP pass - which means we split_size but then cannot inline
535  // in CEPI because the Ret memory type will never lift to the default memory.
536  private int split_size( Ary<Node> body, Node[] parms ) {
537  if( _defs._len <= 1 ) return -1; // No need to split callers if only 2
538  boolean self_recursive=false;
539 
540  // Count function body size. Requires walking the function body and
541  // counting opcodes. Some opcodes are ignored, because they manage
542  // dependencies but make no code.
543  int call_indirect=0, call_thunk=0; // Count of calls to e.g. loads/args/parms
544  int[] cnts = new int[OP_MAX];
545  for( Node n : body ) {
546  int op = n._op; // opcode
547  if( op == OP_CALL ) { // Call-of-primitive?
548  Node n1 = ((CallNode)n).fdx();
549  if( !(n1._val instanceof TypeFunPtr) ) return -1; // Calling an unknown function, await GCP
550  TypeFunPtr tfp = (TypeFunPtr)n1._val;
551  if( tfp._fidxs.test(_fidx) ) self_recursive = true; // May be self-recursive
552  Node n2 = n1 instanceof UnOrFunPtrNode ? ((UnOrFunPtrNode)n1).funptr() : n1;
553  if( n2 instanceof FunPtrNode ) {
554  FunPtrNode fpn = (FunPtrNode) n2;
555  if( fpn.ret().rez() instanceof PrimNode )
556  op = OP_PRIM; // Treat as primitive for inlining purposes
557  } else if( n2!=null && n2._val==TypeTuple.RET ) { // Thunks are encouraged to inline
558  call_thunk++;
559  } else
560  call_indirect++;
561  }
562  cnts[op]++; // Histogram ops
563  }
564  assert cnts[OP_FUN]==1 && cnts[OP_RET]==1;
565  assert cnts[OP_SCOPE]==0;
566  assert cnts[OP_REGION] <= cnts[OP_IF];
567 
568  // Specifically ignoring constants, parms, phis, rpcs, types,
569  // unresolved, and casts. These all track & control values, but actually
570  // do not generate any code.
571  if( cnts[OP_CALL] > 2 || // Careful inlining more calls; leads to exponential growth
572  cnts[OP_LOAD] > 4 ||
573  cnts[OP_STORE]> 2 ||
574  cnts[OP_PRIM] > 6 || // Allow small-ish primitive counts to inline
575  cnts[OP_NEWOBJ]>2 || // Display and return is OK
576  (cnts[OP_NEWOBJ]>1 && self_recursive) ||
577  call_indirect > 0 )
578  return -1;
579 
580  if( !Env.GVN._opt_mode._CG && self_recursive ) return -1; // Await GCP & call-graph discovery before inlining self-recursive functions
581 
582  // Pick which input to inline. Only based on having some constant inputs
583  // right now.
584  Node mem = parms[MEM_IDX]; // Memory, used to sharpen input ptrs
585  int m=-1, mncons = -1;
586  for( int i=has_unknown_callers() ? 2 : 1; i<_defs._len; i++ ) {
587  Node call = in(i).in(0);
588  if( !(call instanceof CallNode) ) continue; // Not well formed
589  if( ((CallNode)call).nargs() != nargs() ) continue; // Will not inline
590  if( call._val == Type.ALL ) continue; // Otherwise in-error
591  TypeFunPtr tfp = CallNode.ttfp(call._val);
592  int fidx = tfp.fidxs().abit();
593  if( fidx < 0 || BitsFun.is_parent(fidx) ) continue; // Call must only target one fcn
594  if( self_recursive && body.find(call)!=-1 ) continue; // Self-recursive; amounts to unrolling
595  int ncon=0;
596  // Count constant inputs on non-error paths
597  for( int j=MEM_IDX; j<parms.length; j++ ) {
598  Node parm = parms[j];
599  if( parm != null ) { // Some can be dead
600  Type actual = parm.in(i).sharptr(mem.in(i));
601  Type formal = formal(j);
602  if( !actual.isa(formal) ) // Path is in-error?
603  { ncon = -2; break; } // This path is in-error, cannot inline even if small & constants
604  if( actual.is_con() ) ncon++; // Count constants along each path
605  }
606  }
607  if( ncon > mncons )
608  { mncons = ncon; m = i; } // Path with the most constants
609  }
610  if( m == -1 ) // No paths are not in-error? (All paths have an error-parm)
611  return -1; // No inline
612 
613  if( cnts[OP_IF] > 1+mncons) // Allow some trivial filtering to inline
614  return -1;
615 
616  return m; // Return path to split on
617  }
618 
619  private FunNode make_new_fun(RetNode ret, TypeTuple new_formals) {
620  // Make a prototype new function header split from the original.
621  int oldfidx = fidx();
623  fun._bal_close = _bal_close;
624  fun.pop(); // Remove null added by RegionNode, will be added later
625  fun.unkeep(); // Ret will clone and not construct
626  // Renumber the original as well; the original _fidx is now a *class* of 2
627  // fidxs. Each FunNode fidx is only ever a constant, so the original Fun
628  // becomes the other child fidx.
629  int newfidx = _fidx = BitsFun.new_fidx(oldfidx);
630  FUNS.setX(newfidx,this); // Track FunNode by fidx
631  FUNS.clear(oldfidx); // Old fidx no longer refers to a single FunNode
632  ret.set_fidx(newfidx); // Renumber in the old RetNode
633  // Right now, force the type upgrade on old_fptr. old_fptr carries the old
634  // parent FIDX and is on the worklist. Eventually, it comes off and the
635  // value() call lifts to the child fidx. Meanwhile its value can be used
636  // to wire a size-split to itself (e.g. fib()), which defeats the purpose
637  // of a size-split (single caller only, so inlines).
638  for( Node old_fptr : ret._uses )
639  if( old_fptr instanceof FunPtrNode ) // Can be many old funptrs with different displays
640  old_fptr.xval(); // Upgrade FIDX
641  Env.GVN.add_flow(ret);
642  Env.GVN.add_flow(this);
643  Env.GVN.add_flow_uses(this);
644  return fun;
645  }
646 
647  // ---------------------------------------------------------------------------
648  // Clone the function body, and split the callers of 'this' into 2 sets; one
649  // for the old and one for the new body. The new function may have a more
650  // refined signature, and perhaps no unknown callers.
651  //
652  // When doing type-based splitting the old and new FunPtrs are gathered into
653  // an Unresolved which replaces the old uses. When doing path-based
654  // splitting, the one caller on the split path is wired to the new function,
655  // and all other calls keep their original FunPtr.
656  //
657  // Wired calls: unwire all calls *to* this function, including self-calls.
658  // Clone the function; wire calls *from* the clone same as the original.
659  // Then rewire all calls that were unwired; for a type-split wire both targets
660  // with an Unresolved. For a path-split rewire left-or-right by path.
661  private void split_callers( RetNode oldret, FunNode fun, Ary<Node> body, int path ) {
662  // Unwire this function and collect unwired calls. Leave the
663  // unknown-caller, if any.
664  CallNode path_call = path < 0 ? null : (CallNode)in(path).in(0);
665  Ary<CallEpiNode> unwireds = new Ary<>(new CallEpiNode[1],0);
666  final int zlen = has_unknown_callers() ? 2 : 1;
667  while( _defs._len > zlen ) { // For all paths (except unknown-caller)
668  Node ceproj = pop();
669  CallNode call = (CallNode)ceproj.in(0); // Unhook without removal
670  CallEpiNode cepi = call.cepi();
671  cepi.del(cepi._defs.find(oldret));
672  unwireds.add(cepi);
673  Env.GVN.add_reduce(cepi); // Visit for inlining later
674  // And remove path from all Parms
675  for( Node parm : _uses )
676  if( parm instanceof ParmNode )
677  parm.pop();
678  }
679 
680  // Map from old to cloned function body
681  HashMap<Node,Node> map = new HashMap<>();
682  // Collect aliases that are cloning.
683  BitSet aliases = new BitSet();
684  // Clone the function body
685  map.put(this,fun);
686  for( Node n : body ) {
687  if( n==this ) continue; // Already cloned the FunNode
688  int old_alias = n instanceof NewNode ? ((NewNode)n)._alias : -1;
689  Node c = n.copy(false); // Make a blank copy with no edges
690  map.put(n,c); // Map from old to new
691  if( old_alias != -1 ) // Was a NewNode?
692  aliases.set(old_alias); // Record old alias before copy/split
693  // Slightly better error message when cloning constructors
694  if( path > 0 ) {
695  if( n instanceof IntrinsicNode ) ((IntrinsicNode)c)._badargs = path_call._badargs[1];
696  if( n instanceof MemPrimNode ) (( MemPrimNode)c)._badargs = path_call._badargs;
697  }
698  }
699 
700  // Fill in edges. New Nodes point to New instead of Old; everybody
701  // shares old nodes not in the function (and not cloned).
702  for( Node n : map.keySet() ) {
703  Node c = map.get(n);
704  assert c._defs._len==0;
705  for( Node def : n._defs ) {
706  Node newdef = map.get(def);// Map old to new
707  c.add_def(newdef==null ? def : newdef);
708  }
709  }
710 
711  // Keep around the old body, even as the FunPtrs get shuffled from Call to Call
712  for( Node use : oldret._uses ) if( use instanceof FunPtrNode ) use.keep();
713 
714  // Collect the old/new returns and funptrs and add to map also. The old
715  // Ret has a set (not 1!) of FunPtrs, one per unique Display.
716  RetNode newret = (RetNode)map.get(oldret);
717  newret._fidx = fun.fidx();
718  if( path < 0 ) { // Type split
719  for( Node use : oldret._uses )
720  if( use instanceof FunPtrNode ) { // Old-return FunPtrs; varies by Display & by internal/external
721  // Make an Unresolved choice of the old and new functions, to be used
722  // by everything except mutually recursive calls; including
723  // external/top-level calls, storing to memory, external merges, etc.
724  Node old_funptr = use;
725  Node new_funptr = map.get(old_funptr);
726  new_funptr.insert(old_funptr);
727  new_funptr.xval(); // Build type so Unresolved can compute type
728  UnresolvedNode new_unr = new UnresolvedNode(null,new_funptr);
729  old_funptr.insert(new_unr);
730  new_unr.add_def(old_funptr);
731  new_unr._val = new_unr.value(GVNGCM.Mode.PesiNoCG);
732  }
733  } else { // Path split
734  Node old_funptr = fptr(); // Find the funptr for the path split
735  Node new_funptr = map.get(old_funptr);
736  new_funptr.insert(old_funptr); // Make cloned recursive calls, call the old version not the new version
737  TypeFunPtr ofptr = (TypeFunPtr) old_funptr._val;
738  path_call.set_fdx(new_funptr); // Force new_funptr, will re-wire later
739  TypeFunPtr nfptr = TypeFunPtr.make(BitsFun.make0(newret._fidx),ofptr._nargs,ofptr._disp);
740  path_call._val = CallNode.set_ttfp((TypeTuple) path_call._val,nfptr);
741  for( Node use : oldret._uses ) // Check extra FunPtrs are dead
742  if( use instanceof FunPtrNode ) Env.GVN.add_dead(map.get(use));
743 
744  } // Else other funptr/displays on unrelated path, dead, can be ignored
745 
746  // For all aliases split in this pass, update in-node both old and new.
747  // This changes their hash, and afterwards the keys cannot be looked up.
748  for( Map.Entry<Node,Node> e : map.entrySet() )
749  if( e.getKey() instanceof MemSplitNode )
750  ((MemSplitNode)e.getKey()).split_alias(e.getValue(),aliases);
751 
752  // Wired Call Handling:
753  if( has_unknown_callers() ) { // Not called by any unknown caller
754  if( path < 0 ) { // Type Split
755  // Change the unknown caller parm types to match the new sig. Default
756  // memory includes the other half of alias splits, which might be
757  // passed in from recursive calls.
758  for( Node p : fun._uses )
759  if( p instanceof ParmNode ) {
760  ParmNode parm = (ParmNode)p;
761  Node defx;
762  if( parm._idx==0 ) defx = Node.con(TypeRPC.ALL_CALL);
763  else if( parm._idx==MEM_IDX ) defx = Env.DEFMEM;
764  else {
765  Type tx = fun.formal(parm._idx).simple_ptr();
766  defx = Node.con(tx);
767  }
768  parm.set_def(1,defx);
769  }
770  } else // Path Split
771  fun.set_def(1,Env.XCTRL);
772  }
773 
774  // Put all new nodes into the GVN tables and worklist
775  boolean split_alias=false;
776  for( Map.Entry<Node,Node> e : map.entrySet() ) {
777  Node oo = e.getKey(); // Old node
778  Node nn = e.getValue(); // New node
779  Type nt = oo._val; // Generally just copy type from original nodes
780  if( nn instanceof MrgProjNode ) { // Cloned allocations registers with default memory
781  MrgProjNode nnrg = (MrgProjNode)nn;
782  MrgProjNode oorg = (MrgProjNode)oo;
783  Env.DEFMEM.make_mem(nnrg.nnn()._alias,nnrg);
784  Env.DEFMEM.make_mem(oorg.nnn()._alias,oorg);
785  int oldalias = BitsAlias.parent(oorg.nnn()._alias);
786  Env.DEFMEM.set_def(oldalias,Node.con(TypeObj.UNUSED));
787  Env.GVN.add_mono(oorg.nnn());
788  Env.GVN.add_flow_uses(oorg);
789  split_alias=true;
790  }
791 
792  if( nn instanceof FunPtrNode ) { // FunPtrs pick up the new fidx
793  TypeFunPtr ofptr = (TypeFunPtr)nt;
794  if( ofptr.fidx()==oldret._fidx )
795  nt = TypeFunPtr.make(BitsFun.make0(newret._fidx),ofptr._nargs,ofptr._disp);
796  }
797  nn._val = nt; // Values
798  nn._elock(); // In GVN table
799  }
800  if( split_alias ) {
801  Env.DEFMEM.xval();
802  }
803 
804  // Eagerly lift any Unresolved types, so they quit propagating the parent
805  // (and both children) to all targets.
806  for( Node fptr : oldret._uses )
807  if( fptr instanceof FunPtrNode )
808  for( Node unr : fptr._uses )
809  if( unr instanceof UnresolvedNode )
810  unr._val = unr.value(GVNGCM.Mode.PesiCG);
811 
812  // Rewire all unwired calls.
813  for( CallEpiNode cepi : unwireds ) {
814  CallNode call = cepi.call();
815  CallEpiNode cepi2 = (CallEpiNode)map.get(cepi);
816  if( path < 0 ) { // Type-split, wire both & resolve later
817  BitsFun call_fidxs = ((TypeFunPtr) call.fdx()._val).fidxs();
818  assert call_fidxs.test_recur( fidx()) ; cepi.wire1(call,this,oldret);
819  if( call_fidxs.test_recur(fun.fidx()) ) cepi.wire1(call, fun,newret);
820  if( cepi2!=null ) {
821  // Found an unwired call in original: musta been a recursive self-
822  // call. wire the clone, same as the original was wired, so the
823  // clone keeps knowledge about its return type.
824  CallNode call2 = cepi2.call();
825  BitsFun call_fidxs2 = ((TypeFunPtr) call2.fdx()._val).fidxs();
826  if( call_fidxs2.test_recur( fidx()) ) cepi2.wire1(call2,this,oldret);
827  assert call_fidxs2.test_recur(fun.fidx()) ; cepi2.wire1(call2, fun,newret);
828  }
829  } else { // Non-type split, wire left or right
830  if( call==path_call ) cepi.wire1(call, fun,newret);
831  else cepi.wire1(call,this,oldret);
832  if( cepi2!=null && cepi2.call()!=path_call ) {
833  CallNode call2 = cepi2.call();
834  // Found an unwired call in original: musta been a recursive
835  // self-call. wire the clone, same as the original was wired, so the
836  // clone keeps knowledge about its return type.
837  //call2.set_fdx(call.fdx());
838  cepi2.wire1(call2,this,oldret);
839  call2.xval();
840  Env.GVN.add_flow_uses(this); // This gets wired, that gets wired, revisit all
841  }
842  Env.GVN.add_unuse(cepi);
843  }
844  }
845 
846  // Look for wired new not-recursive CallEpis; these will have an outgoing
847  // edge to some other RetNode, but the Call will not be wired. Wire.
848  for( Node nn : map.values() ) {
849  if( nn instanceof CallEpiNode ) {
850  CallEpiNode ncepi = (CallEpiNode)nn;
851  for( int i=0; i<ncepi.nwired(); i++ ) {
852  RetNode xxxret = ncepi.wired(i); // Neither newret nor oldret
853  if( xxxret != newret && xxxret != oldret ) { // Not self-recursive
854  ncepi.wire0(ncepi.call(),xxxret.fun());
855  }
856  }
857  }
858  }
859 
860  // Retype memory, so we can everywhere lift the split-alias parents "up and out".
861  GVNGCM.retype_mem(aliases,this.parm(MEM_IDX), oldret, true);
862  GVNGCM.retype_mem(aliases,fun .parm(MEM_IDX), newret, true);
863 
864  // Unhook the hooked FunPtrs
865  for( Node use : oldret._uses ) if( use instanceof FunPtrNode ) use.unkeep();
866  }
867 
868  // Compute value from inputs. Simple meet over inputs.
869  @Override public Type value(GVNGCM.Mode opt_mode) {
870  // Will be an error eventually, but act like its executed so the trailing
871  // EpilogNode gets visited during GCP
872  if( is_forward_ref() ) return Type.CTRL;
873  if( _defs._len==2 && in(1)==this ) return Type.XCTRL; // Dead self-loop
874  if( in(0)==this ) return _defs._len>=2 ? val(1) : Type.XCTRL; // is_copy
875  for( int i=1; i<_defs._len; i++ ) {
876  Type c = val(i);
877  if( c == Type.CTRL || c == Type.ALL ) return Type.CTRL; // Valid path
878  }
879  return Type.XCTRL;
880  }
881 
882  // Funs get special treatment by the H-M algo.
883  @Override public boolean unify( boolean test ) { return false; }
884 
885  // True if this is a forward_ref
886  @Override public boolean is_forward_ref() { return _op_prec==-2; }
887  public ParmNode parm( int idx ) {
888  for( Node use : _uses )
889  if( use instanceof ParmNode && ((ParmNode)use)._idx==idx )
890  return (ParmNode)use;
891  return null;
892  }
893  public Node[] parms() {
894  Node[] parms = new Node[nargs()];
895  for( Node use : _uses )
896  if( use instanceof ParmNode )
897  parms[((ParmNode)use)._idx] = use;
898  return parms;
899  }
900  public RetNode ret() {
901  if( is_dead() ) return null;
902  for( Node use : _uses )
903  if( use instanceof RetNode && use._defs._len==5 && !((RetNode)use).is_copy() && ((RetNode)use).fun()==this )
904  return (RetNode)use;
905  return null;
906  }
907  // Returns first - not ALL - FunPtrs
908  public FunPtrNode fptr() {
909  RetNode ret = ret();
910  if( ret==null ) return null;
911  for( Node fptr : ret._uses )
912  if( fptr instanceof FunPtrNode )
913  return (FunPtrNode)fptr;
914  return null;
915  }
916 
917  @Override public boolean equals(Object o) { return this==o; } // Only one
918  @Override public Node is_copy(int idx) { return in(0)==this ? in(1) : null; }
919  void set_is_copy() { set_def(0,this); Env.GVN.add_reduce_uses(this); }
920 }
com.cliffc.aa.type.BitsAlias.FULL
static BitsAlias FULL
Definition: BitsAlias.java:27
com.cliffc.aa.node.FunNode.FunNode
FunNode(PrimNode prim)
Definition: FunNode.java:78
com.cliffc.aa.node.MrgProjNode.nnn
NewNode nnn()
Definition: MrgProjNode.java:14
com.cliffc.aa.node.FunNode.FunNode
FunNode(String name, TypeFunSig sig, int op_prec, boolean thunk_rhs, int fidx)
Definition: FunNode.java:87
com.cliffc.aa.node.MemPrimNode
Definition: MemPrimNode.java:10
com.cliffc.aa.type.BitsFun.EMPTY
static final BitsFun EMPTY
Definition: BitsFun.java:37
com.cliffc.aa.GVNGCM.add_unuse
Node add_unuse(Node n)
Definition: GVNGCM.java:59
com.cliffc.aa.type.TypeMem.DEAD
static final TypeMem DEAD
Definition: TypeMem.java:226
com.cliffc.aa.type.TypeFunPtr
Definition: TypeFunPtr.java:23
com.cliffc.aa.node.CallEpiNode.wire0
void wire0(CallNode call, Node fun)
Definition: CallEpiNode.java:218
com.cliffc.aa.node.PrimNode
Definition: PrimNode.java:20
com.cliffc.aa.util.Ary.push
E push(E e)
Add element in amortized constant time.
Definition: Ary.java:58
com.cliffc.aa.node.FunNode.unwire
void unwire(int idx)
Definition: FunNode.java:296
com.cliffc.aa.type.TypeTuple.make_args
static TypeTuple make_args(Type[] ts)
Definition: TypeTuple.java:106
com.cliffc.aa.node.CallEpiNode.call
CallNode call()
Definition: CallEpiNode.java:35
com.cliffc.aa.type.TypeFunPtr._nargs
int _nargs
Definition: TypeFunPtr.java:27
com.cliffc.aa.type.BitsFun.make0
static BitsFun make0(int bit)
Definition: BitsFun.java:44
com.cliffc.aa.util.Ary.isEmpty
boolean isEmpty()
Definition: Ary.java:20
com.cliffc.aa.type.Type.isa
boolean isa(Type t)
Definition: Type.java:623
com.cliffc.aa.node.FunNode.find_type_split
Type[] find_type_split(Node[] parms)
Definition: FunNode.java:354
com.cliffc.aa.node.FunNode.FunNode
FunNode(String name)
Definition: FunNode.java:83
com.cliffc.aa.node.CallNode.cepi
CallEpiNode cepi()
Definition: CallNode.java:769
com.cliffc.aa.Env.XCTRL
static ConNode XCTRL
Definition: Env.java:21
com.cliffc.aa.type.TypeMem
Memory type; the state of all of memory; memory edges order memory ops.
Definition: TypeMem.java:53
com.cliffc.aa.node.FunNode._nongens
TV2[] _nongens
Definition: FunNode.java:70
com.cliffc.aa.util.Util.eq
static boolean eq(String s0, String s1)
Definition: Util.java:16
com.cliffc.aa.node.FunNode.make_new_fun
FunNode make_new_fun(RetNode ret, TypeTuple new_formals)
Definition: FunNode.java:619
com.cliffc.aa.GVNGCM.add_mono
public< N extends Node > N add_mono(N n)
Definition: GVNGCM.java:51
com.cliffc.aa.type.Type.join
Type join(Type t)
Definition: Type.java:619
com.cliffc.aa.node.FunNode.value
Type value(GVNGCM.Mode opt_mode)
Definition: FunNode.java:869
com.cliffc.aa.GVNGCM.Mode.PesiCG
PesiCG
Definition: GVNGCM.java:18
com.cliffc.aa.node.FunNode._name
String _name
Definition: FunNode.java:59
com.cliffc.aa.node.FunNode.fidx
int fidx()
Definition: FunNode.java:102
com.cliffc.aa.node.PrimNode._thunk_rhs
boolean _thunk_rhs
Definition: PrimNode.java:25
com.cliffc.aa.node.Node._live
TypeMem _live
Definition: Node.java:89
com.cliffc.aa.node.FunNode._op_prec
final byte _op_prec
Definition: FunNode.java:65
com.cliffc.aa.GVNGCM.add_flow_uses
void add_flow_uses(Node n)
Definition: GVNGCM.java:55
com.cliffc
com.cliffc.aa.node.FunNode.ideal_reduce
Node ideal_reduce()
Definition: FunNode.java:197
com.cliffc.aa.type.Type.widen
Type widen()
Definition: Type.java:828
com.cliffc.aa.util.Ary.pop
E pop()
Definition: Ary.java:41
com.cliffc.aa.node.FunNode.type_special
TypeTuple type_special(Node[] parms)
Definition: FunNode.java:466
com.cliffc.aa.util.Ary.addAll
Ary< E > addAll(Collection<? extends E > c)
Definition: Ary.java:151
com.cliffc.aa.node.FunNode.split_size
int split_size(Ary< Node > body, Node[] parms)
Definition: FunNode.java:536
com.cliffc.aa.node.Node
Definition: Node.java:16
com.cliffc.aa.node.FunNode.has_unknown_callers
boolean has_unknown_callers()
Definition: FunNode.java:185
com.cliffc.aa.type.TypeRPC.ALL_CALL
static final TypeRPC ALL_CALL
Definition: TypeRPC.java:31
com.cliffc.aa.util
Definition: AbstractEntry.java:1
com.cliffc.aa.node.MemPrimNode.LValueLength
Definition: MemPrimNode.java:85
com.cliffc.aa.node.UnOrFunPtrNode
Definition: UnOrFunPtrNode.java:6
com.cliffc.aa.type.TypeFunPtr.GENERIC_FUNPTR
static final TypeFunPtr GENERIC_FUNPTR
Definition: TypeFunPtr.java:80
com.cliffc.aa.tvar
Definition: TV2.java:1
com.cliffc.aa.type.Type
an implementation of language AA
Definition: Type.java:94
com.cliffc.aa.node.FunNode.names
static SB names(BitsFun fidxs, SB sb, boolean debug)
Definition: FunNode.java:131
com.cliffc.aa.type.TypeFunSig.make
static TypeFunSig make(String[] args, TypeTuple formals, TypeTuple ret)
Definition: TypeFunSig.java:71
com.cliffc.aa.node.StoreNode
Definition: StoreNode.java:14
com.cliffc.aa.util.Ary
Definition: Ary.java:11
com.cliffc.aa.type.BitsAlias
Definition: BitsAlias.java:8
com.cliffc.aa.node.NewNode.NewPrimNode
Definition: NewNode.java:170
com.cliffc.aa.type.TypeTuple
Definition: TypeTuple.java:11
com.cliffc.aa.node.Node.keep
public< N extends Node > N keep()
Definition: Node.java:228
com.cliffc.aa.node.FunNode.str
String str()
Definition: FunNode.java:107
com.cliffc.aa.type.TypeFunPtr._fidxs
BitsFun _fidxs
Definition: TypeFunPtr.java:26
com.cliffc.aa.type.TypeFunPtr.fidxs
BitsFun fidxs()
Definition: TypeFunPtr.java:127
com.cliffc.aa.GVNGCM.Mode._CG
final boolean _CG
Definition: GVNGCM.java:19
com.cliffc.aa.node.Node._val
Type _val
Definition: Node.java:88
com.cliffc.aa.node.LoadNode
Definition: LoadNode.java:13
com.cliffc.aa.node.Node.find
Node find(int uid)
Definition: Node.java:427
com.cliffc.aa.node.Node.OP_FRESH
static final byte OP_FRESH
Definition: Node.java:25
com.cliffc.aa.node.Node.OP_FUN
static final byte OP_FUN
Definition: Node.java:27
com.cliffc.aa.node.ConNode
Definition: ConNode.java:9
com.cliffc.aa.node.Node.add_def
Node add_def(Node n)
Definition: Node.java:152
com.cliffc.aa.node.FunPtrNode
Definition: FunPtrNode.java:40
com.cliffc.aa.node.PrimNode.NE_OOP
Definition: PrimNode.java:446
com.cliffc.aa.node.PrimNode.MulF64
Definition: PrimNode.java:293
com.cliffc.aa.node.FunNode.xstr
String xstr()
Definition: FunNode.java:105
com.cliffc.aa.node.FunNode.formal
Type formal(int idx)
Definition: FunNode.java:187
com.cliffc.aa.node.RetNode
Definition: RetNode.java:19
com.cliffc.aa.type.TypeStruct
A memory-based collection of optionally named fields.
Definition: TypeStruct.java:50
com.cliffc.aa.type.Bits.test_recur
boolean test_recur(int i)
Definition: Bits.java:232
com.cliffc.aa.node.CallNode
Definition: CallNode.java:86
com.cliffc.aa.type.Bits.test
static boolean test(long[] bits, int i)
Definition: Bits.java:224
com.cliffc.aa.node.PrimNode.EQ_I64
Definition: PrimNode.java:411
com.cliffc.aa.node.Node.OP_CALL
static final byte OP_CALL
Definition: Node.java:17
com.cliffc.aa.type.TypeFunSig.str
SB str(SB sb, VBitSet dups, TypeMem mem, boolean debug)
Definition: TypeFunSig.java:50
com.cliffc.aa.node.PrimNode._name
final String _name
Definition: PrimNode.java:21
com.cliffc.aa.node.FunNode._cnt_size_inlines
byte _cnt_size_inlines
Definition: FunNode.java:72
com.cliffc.aa.type.Types
Definition: Types.java:9
com.cliffc.aa.Env.START
static StartNode START
Definition: Env.java:14
com.cliffc.aa.GVNGCM.Mode.PesiNoCG
PesiNoCG
Definition: GVNGCM.java:16
com.cliffc.aa.node.Node.ideal_reduce
Node ideal_reduce()
Definition: Node.java:441
com.cliffc.aa.util.SB.unchar
SB unchar()
Definition: SB.java:58
com.cliffc.aa.type.Type.ALL
static final Type ALL
Definition: Type.java:324
com.cliffc.aa.type.TypeFunSig._ret
TypeTuple _ret
Definition: TypeFunSig.java:16
com.cliffc.aa.node.Node.is_prim
boolean is_prim()
Definition: Node.java:260
com.cliffc.aa.node.RetNode.set_fidx
void set_fidx(int fidx)
Definition: RetNode.java:47
com.cliffc.aa.util.VBitSet.tset
boolean tset(int idx)
Definition: VBitSet.java:7
com.cliffc.aa.type.TypeFunSig._args
String[] _args
Definition: TypeFunSig.java:14
com.cliffc.aa.node.Node.OP_MAX
static final byte OP_MAX
Definition: Node.java:52
com.cliffc.aa.type.TypeFunSig.arg
Type arg(int idx)
Definition: TypeFunSig.java:88
com.cliffc.aa.Env.GVN
static final GVNGCM GVN
Definition: Env.java:13
com.cliffc.aa.node.FunNode.find_type_split_index
int find_type_split_index(Node[] parms)
Definition: FunNode.java:326
com.cliffc.aa.node.FunNode.name
static String name(int fidx, boolean debug)
Definition: FunNode.java:109
com.cliffc.aa.node.MemPrimNode.LValueWriteFinal
Definition: MemPrimNode.java:226
com.cliffc.aa.type.TypeFunSig.nargs
int nargs()
Definition: TypeFunSig.java:87
com.cliffc.aa.type.TypeObj
Definition: TypeObj.java:15
com.cliffc.aa.node.FunNode.fptr
FunPtrNode fptr()
Definition: FunNode.java:908
com.cliffc.aa.node.Node.unkeep
public< N extends Node > N unkeep()
Definition: Node.java:232
com.cliffc.aa.type.Type.is_con
boolean is_con()
Definition: Type.java:776
com.cliffc.aa.util.Ary.add
Ary< E > add(E e)
Add element in amortized constant time.
Definition: Ary.java:49
com.cliffc.aa.type.BitsFun.is_parent
static boolean is_parent(int idx)
Definition: BitsFun.java:48
com.cliffc.aa.node.Node.OP_CAST
static final byte OP_CAST
Definition: Node.java:19
com.cliffc.aa.type.Type.above_center
boolean above_center()
Definition: Type.java:741
com.cliffc.aa.node.FunNode._fidx
int _fidx
Definition: FunNode.java:61
com.cliffc.aa.node.Node.is_dead
boolean is_dead()
Definition: Node.java:820
com.cliffc.aa.node.Node.value
abstract Type value(GVNGCM.Mode opt_mode)
com.cliffc.aa.type.TypeFunPtr.fidx
int fidx()
Definition: TypeFunPtr.java:128
com.cliffc.aa.node.Node.OP_IF
static final byte OP_IF
Definition: Node.java:29
com.cliffc.aa.node.Node.OP_DEFMEM
static final byte OP_DEFMEM
Definition: Node.java:23
com.cliffc.aa.node.PrimNode._sig
final TypeFunSig _sig
Definition: PrimNode.java:22
com.cliffc.aa.type.TypeTuple.RET
static final TypeTuple RET
Definition: TypeTuple.java:130
com.cliffc.aa.node.RetNode._fidx
int _fidx
Definition: RetNode.java:20
com.cliffc.aa.node.Node._keep
byte _keep
Definition: Node.java:86
com.cliffc.aa.type.TypeFunPtr._disp
Type _disp
Definition: TypeFunPtr.java:28
com.cliffc.aa.node.FunNode.bind
void bind(String tok)
Definition: FunNode.java:172
com.cliffc.aa.GVNGCM.add_reduce_uses
void add_reduce_uses(Node n)
Definition: GVNGCM.java:57
com.cliffc.aa.node.NewStrNode
Definition: NewStrNode.java:11
com.cliffc.aa.node.FunNode.check_callers
boolean check_callers()
Definition: FunNode.java:311
com.cliffc.aa.util.Util
Definition: Util.java:5
com.cliffc.aa.type.Type.CTRL
static final Type CTRL
Definition: Type.java:326
com.cliffc.aa.type.TypeObj.UNUSED
static final TypeObj UNUSED
Definition: TypeObj.java:46
com.cliffc.aa.node.FunNode.find_fidx
static FunNode find_fidx(int fidx)
Definition: FunNode.java:101
com.cliffc.aa.node.FunNode._must_inline
static int _must_inline
Definition: FunNode.java:73
com.cliffc.aa.node.FunNode.set_is_copy
void set_is_copy()
Definition: FunNode.java:919
com.cliffc.aa.GVNGCM.retype_mem
static void retype_mem(BitSet aliases, Node mem, Node exit, boolean skip_calls)
Definition: GVNGCM.java:330
com.cliffc.aa.node.FunNode.reset
static void reset()
Definition: FunNode.java:100
com.cliffc.aa.node.FunNode.parms
Node[] parms()
Definition: FunNode.java:893
com.cliffc.aa.node.Node.in
Node in(int i)
Definition: Node.java:126
com.cliffc.aa.node.Node.OP_SCOPE
static final byte OP_SCOPE
Definition: Node.java:43
com.cliffc.aa.type.Types.get
Type[] get()
Definition: Types.java:66
com.cliffc.aa.node.FunNode.set_nongens
void set_nongens(TV2[] nongens)
Definition: FunNode.java:192
com.cliffc.aa.node.CallEpiNode.wire1
void wire1(CallNode call, Node fun, Node ret)
Definition: CallEpiNode.java:207
com.cliffc.aa.node.Node.OP_LOAD
static final byte OP_LOAD
Definition: Node.java:31
com.cliffc.aa.type.Type.XCTRL
static final Type XCTRL
Definition: Type.java:327
com.cliffc.aa.GVNGCM
Definition: GVNGCM.java:12
com.cliffc.aa.type.TypeFunPtr.make
static TypeFunPtr make(BitsFun fidxs, int nargs, Type disp)
Definition: TypeFunPtr.java:67
com.cliffc.aa.node.Node.OP_NEWOBJ
static final byte OP_NEWOBJ
Definition: Node.java:34
com.cliffc.aa.node.FunNode.name
String name()
Definition: FunNode.java:114
com.cliffc.aa.type.Type.simple_ptr
Type simple_ptr()
Definition: Type.java:358
com.cliffc.aa.node.PrimNode.EQ_OOP
Definition: PrimNode.java:415
com.cliffc.aa.type.BitsAlias.parent
static int parent(int kid)
Definition: BitsAlias.java:59
com.cliffc.aa.node.FunNode.FunNode
FunNode(NewNode.NewPrimNode prim)
Definition: FunNode.java:79
com.cliffc.aa.node.FunNode.noinline
boolean noinline()
Definition: FunNode.java:179
com.cliffc.aa.node.FreshNode
Definition: FreshNode.java:11
com.cliffc.aa.node.ProjNode
Definition: ProjNode.java:11
com.cliffc.aa.node.FunPtrNode.ret
RetNode ret()
Definition: FunPtrNode.java:62
com.cliffc.aa.util.VBitSet
Definition: VBitSet.java:5
com.cliffc.aa.type.TypeFunSig.make_from_arg
TypeFunSig make_from_arg(int idx, Type arg)
Definition: TypeFunSig.java:80
com.cliffc.aa.type.BitsFun
Definition: BitsFun.java:7
com.cliffc.aa.node.Node.insert
Node insert(int idx, Node n)
Definition: Node.java:165
NotNull
com.cliffc.aa.util.SB
Tight/tiny StringBuilder wrapper.
Definition: SB.java:8
com.cliffc.aa.node.FunNode.name
String name(boolean debug)
Definition: FunNode.java:115
com.cliffc.aa.node.Node.con
static Node con(Type t)
Definition: Node.java:670
com.cliffc.aa.node.Node._uses
Ary< Node > _uses
Definition: Node.java:245
com.cliffc.aa.node.Node.OP_NEWSTR
static final byte OP_NEWSTR
Definition: Node.java:36
com.cliffc.aa.node.FunNode.nargs
int nargs()
Definition: FunNode.java:190
com.cliffc.aa.AA
an implementation of language AA
Definition: AA.java:9
com.cliffc.aa.node.FunNode.equals
boolean equals(Object o)
Definition: FunNode.java:917
com.cliffc.aa.node.Node.OP_STORE
static final byte OP_STORE
Definition: Node.java:47
com.cliffc.aa.node.Node.val
Type val(int idx)
Definition: Node.java:470
com.cliffc.aa.node.MemPrimNode.LValueRead
Definition: MemPrimNode.java:130
com.cliffc.aa.node.UnresolvedNode.value
Type value(GVNGCM.Mode opt_mode)
Definition: UnresolvedNode.java:45
com.cliffc.aa
Definition: AA.java:1
com.cliffc.aa.node.UnresolvedNode
Definition: UnresolvedNode.java:13
com.cliffc.aa.node.FunNode.FunNode
FunNode(String name, TypeFunSig sig, int op_prec, boolean thunk_rhs)
Definition: FunNode.java:85
com.cliffc.aa.node.NewNode
Definition: NewNode.java:17
com.cliffc.aa.node.FunNode._sig
TypeFunSig _sig
Definition: FunNode.java:62
com.cliffc.aa.node.Node._elock
boolean _elock
Definition: Node.java:87
com.cliffc.aa.node.MrgProjNode
Definition: MrgProjNode.java:10
com.cliffc.aa.node.RetNode.rez
Node rez()
Definition: RetNode.java:30
com.cliffc.aa.node.FunNode.name
static String name(String name, String bal, int fidx, int op_prec, boolean fref, boolean debug)
Definition: FunNode.java:123
com.cliffc.aa.node.CallEpiNode.wired
RetNode wired(int x)
Definition: CallEpiNode.java:38
com.cliffc.aa.node.Node.copy
Node copy(boolean copy_edges)
Definition: Node.java:264
com.cliffc.aa.node.PrimNode._op_prec
byte _op_prec
Definition: PrimNode.java:24
com.cliffc.aa.node.FunPtrNode._name
String _name
Definition: FunPtrNode.java:41
com.cliffc.aa.type.Bits.abit
int abit()
Definition: Bits.java:203
com.cliffc.aa.util.SB.p
SB p(String s)
Definition: SB.java:13
com.cliffc.aa.node.CallEpiNode.nwired
int nwired()
Definition: CallEpiNode.java:37
com.cliffc.aa.node.Node.OP_PRIM
static final byte OP_PRIM
Definition: Node.java:39
com.cliffc.aa.node.CallNode.ttfp
static TypeFunPtr ttfp(Type tcall)
Definition: CallNode.java:157
com.cliffc.aa.type.TypeTuple.at
Type at(int idx)
Definition: TypeTuple.java:182
com.cliffc.aa.node.FunNode.is_copy
Node is_copy(int idx)
Definition: FunNode.java:918
com.cliffc.aa.type.TypeFunSig.display
Type display()
Definition: TypeFunSig.java:89
com.cliffc.aa.node.FunNode.ideal_inline
Node ideal_inline(boolean check_progress)
Definition: FunNode.java:231
com.cliffc.aa.node.Node.set_def
Node set_def(int idx, Node n)
Definition: Node.java:154
com.cliffc.aa.type.TypeFunSig
Definition: TypeFunSig.java:10
com.cliffc.aa.node.PrimNode.AndI64
Definition: PrimNode.java:350
com.cliffc.aa.node.Node.sharptr
Type sharptr(Node mem)
Definition: Node.java:855
com.cliffc.aa.GVNGCM.add_reduce
public< N extends Node > N add_reduce(N n)
Definition: GVNGCM.java:49
com.cliffc.aa.node.Node.del
void del(int idx)
Definition: Node.java:169
com.cliffc.aa.type.Type.dual
final T dual()
Definition: Type.java:361
com.cliffc.aa.node.CallEpiNode
Definition: CallEpiNode.java:24
com.cliffc.aa.node.FunNode.parm
ParmNode parm(int idx)
Definition: FunNode.java:887
com.cliffc.aa.node.Node._op
final byte _op
Definition: Node.java:85
com.cliffc.aa.node.PrimNode.MulI64
Definition: PrimNode.java:335
com.cliffc.aa.node.ParmNode
Definition: ParmNode.java:14
com.cliffc.aa.tvar.TV2
Definition: TV2.java:23
com.cliffc.aa.node.FunNode._bal_close
String _bal_close
Definition: FunNode.java:60
com.cliffc.aa.node.MemSplitNode
Definition: MemSplitNode.java:19
com.cliffc.aa.type.TypeRPC
Definition: TypeRPC.java:7
com.cliffc.aa.node.Node.OP_PARM
static final byte OP_PARM
Definition: Node.java:37
com.cliffc.aa.node.Node.is_multi_head
boolean is_multi_head()
Definition: Node.java:354
com.cliffc.aa.node.Node.xval
Type xval()
Definition: Node.java:460
com.cliffc.aa.node.RetNode.fun
FunNode fun()
Definition: RetNode.java:32
com.cliffc.aa.node.Node.OP_RET
static final byte OP_RET
Definition: Node.java:42
com.cliffc.aa.GVNGCM._opt_mode
Mode _opt_mode
Definition: GVNGCM.java:22
com.cliffc.aa.node.Node.pop
Node pop()
Definition: Node.java:174
com.cliffc.aa.GVNGCM.add_flow
public< N extends Node > N add_flow(N n)
Definition: GVNGCM.java:50
com.cliffc.aa.node.CallNode.set_fdx
Node set_fdx(Node fun)
Definition: CallNode.java:132
com.cliffc.aa.node.FunNode.unify
boolean unify(boolean test)
Definition: FunNode.java:883
com.cliffc.aa.GVNGCM.add_dead
void add_dead(Node n)
Definition: GVNGCM.java:48
com.cliffc.aa.node.NewNode._alias
int _alias
Definition: NewNode.java:20
com.cliffc.aa.node.IntrinsicNode
Definition: IntrinsicNode.java:15
com.cliffc.aa.node.CallNode.set_ttfp
static TypeTuple set_ttfp(TypeTuple tcall, TypeFunPtr nfptr)
Definition: CallNode.java:168
com.cliffc.aa.node.Node.OP_NAME
static final byte OP_NAME
Definition: Node.java:33
com.cliffc.aa.node.Node._uid
int _uid
Definition: Node.java:84
com.cliffc.aa.type.TypeMemPtr.OOP0
static final TypeMemPtr OOP0
Definition: TypeMemPtr.java:93
com.cliffc.aa.node.FunNode
Definition: FunNode.java:58
com.cliffc.aa.node.CallNode.fdx
Node fdx()
Definition: CallNode.java:121
com.cliffc.aa.node.CallNode._badargs
Parse[] _badargs
Definition: CallNode.java:94
com.cliffc.aa.node.RegionNode
Definition: RegionNode.java:11
com.cliffc.aa.node.PrimNode.EQ_F64
Definition: PrimNode.java:314
com.cliffc.aa.node.FunNode.copy
Node copy(boolean copy_edges)
Definition: FunNode.java:182
com.cliffc.aa.node.FunNode.FunNode
FunNode(String[] flds, Type[] ts)
Definition: FunNode.java:81
com
com.cliffc.aa.type.TypeMem.MEM
static final TypeMem MEM
Definition: TypeMem.java:224
com.cliffc.aa.Env.DEFMEM
static DefMemNode DEFMEM
Definition: Env.java:19
com.cliffc.aa.type.BitsFun.new_fidx
static int new_fidx(int par)
Definition: BitsFun.java:25
com.cliffc.aa.type.TypeTuple.NO_ARGS
static final TypeTuple NO_ARGS
Definition: TypeTuple.java:135
com.cliffc.aa.node.Node.op_prec
byte op_prec()
Definition: Node.java:533
com.cliffc.aa.Env
Definition: Env.java:12
com.cliffc.aa.node.FunNode.is_forward_ref
boolean is_forward_ref()
Definition: FunNode.java:886
com.cliffc.aa.GVNGCM.Mode.Parse
Parse
Definition: GVNGCM.java:15
com.cliffc.aa.util.SB.toString
String toString()
Definition: SB.java:62
com.cliffc.aa.node.FunNode.FUNS
static Ary< FunNode > FUNS
Definition: FunNode.java:99
com.cliffc.aa.type
Definition: Bits.java:1
com.cliffc.aa.node.MemPrimNode.LValueWrite
Definition: MemPrimNode.java:200
com.cliffc.aa.node.Node._defs
Ary< Node > _defs
Definition: Node.java:124
com.cliffc.aa.node.UnOrFunPtrNode.funptr
abstract FunPtrNode funptr()
com.cliffc.aa.node.FunNode._thunk_rhs
final boolean _thunk_rhs
Definition: FunNode.java:68
com.cliffc.aa.type.TypeMemPtr
Definition: TypeMemPtr.java:14
com.cliffc.aa.node.Node.OP_REGION
static final byte OP_REGION
Definition: Node.java:41
com.cliffc.aa.Env.ALL_CTRL
static ConNode ALL_CTRL
Definition: Env.java:20
com.cliffc.aa.node.FunNode.bad_mem_use
static boolean bad_mem_use(Node n, TypeObj to)
Definition: FunNode.java:407
com.cliffc.aa.node.FunNode.ret
RetNode ret()
Definition: FunNode.java:900
com.cliffc.aa.GVNGCM.Mode
Definition: GVNGCM.java:14
com.cliffc.aa.type.TypeFunSig._formals
TypeTuple _formals
Definition: TypeFunSig.java:15
com.cliffc.aa.node.FunNode.find_body
Ary< Node > find_body(RetNode ret)
Definition: FunNode.java:478
com.cliffc.aa.node.ParmNode._idx
final int _idx
Definition: ParmNode.java:15
com.cliffc.aa.type.TypeMemPtr.make
static TypeMemPtr make(BitsAlias aliases, TypeObj obj)
Definition: TypeMemPtr.java:66
com.cliffc.aa.node.FunNode.split_callers
void split_callers(RetNode oldret, FunNode fun, Ary< Node > body, int path)
Definition: FunNode.java:661