aa
CallEpiNode.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.type.*;
6 
7 import static com.cliffc.aa.AA.*;
8 import static com.cliffc.aa.Env.GVN;
9 
10 // See CallNode. Slot 0 is the Call. The remaining slots are Returns which
11 // are typed as standard function returns: {Ctrl,Mem,Val}. These Returns
12 // represent call-graph edges that are known to be possible and thus their fidx
13 // appears in the Call's BitsFun type.
14 //
15 // Pre-opto it is possible for the all-functions type to appear at a Call, and
16 // in this case the CallEpi must assume all possible calls may happen, they are
17 // just not wired up yet.
18 //
19 // It is also possible that we have discovered and wired up a function, but
20 // that the input/output types are not yet monotonic, and we do not flow values
21 // across those edges until the types align. This is controlled with a small
22 // bit-vector.
23 
24 public final class CallEpiNode extends Node {
25  public boolean _is_copy;
26  public CallEpiNode( Node... nodes ) {
27  super(OP_CALLEPI,nodes);
28  assert nodes[1] instanceof DefMemNode;
29  }
30  @Override public String xstr() {// Self short name
31  if( _is_copy ) return "CopyEpi";
32  if( is_dead() ) return "XallEpi";
33  return "CallEpi";
34  }
35  public CallNode call() { return (CallNode)in(0); }
36  @Override public boolean is_mem() { return true; }
37  public int nwired() { return _defs._len-2; }
38  public RetNode wired(int x) { return (RetNode)in(x+2); }
39 
40  @Override public Node ideal_reduce() {
41  if( _is_copy ) return null;
42  CallNode call = call();
43  Type tc = call._val;
44  if( !(tc instanceof TypeTuple) ) return null;
45  TypeTuple tcall = (TypeTuple)tc;
46  if( CallNode.tctl(tcall) != Type.CTRL ) return null; // Call not executable
47  // Get calls resolved function.
48  BitsFun fidxs = CallNode.ttfp(tcall).fidxs();
49 
50  // If the call's allowed functions excludes any wired, remove the extras
51  if( !fidxs.test(BitsFun.ALL) ) { // Shortcut
52  for( int i = 0; i < nwired(); i++ ) {
53  RetNode ret = wired(i);
54  if( !fidxs.test_recur(ret.fidx()) ) { // Wired call not in execution set?
55  assert !BitsFun.is_parent(ret.fidx());
56  // Remove the edge. Pre-GCP all CG edges are virtual, and are lazily
57  // and pessimistically filled in by ideal calls. During the course
58  // of lifting types some of the manifested CG edges are killed.
59  // Post-GCP all CG edges are manifest, but types can keep lifting
60  // and so CG edges can still be killed.
61  unwire(call,ret);
62  return this; // Return with progress
63  }
64  }
65  }
66 
67  // See if we can wire any new fidxs directly between Call/Fun and Ret/CallEpi.
68  // This *adds* edges, but enables a lot of shrinking via inlining.
69  if( check_and_wire() ) return this;
70 
71  // The one allowed function is already wired? Then directly inline.
72  // Requires this calls 1 target, and the 1 target is only called by this.
73  if( nwired()==1 && fidxs.abit() != -1 ) { // Wired to 1 target
74  RetNode ret = wired(0); // One wired return
75  FunNode fun = ret.fun();
76  Type tdef = Env.DEFMEM._uses._len==0 ? null : Env.DEFMEM._val;
77  TypeTuple tret = ret._val instanceof TypeTuple ? (TypeTuple) ret._val : (TypeTuple)ret._val.oob(TypeTuple.RET);
78  Type tretmem = tret.at(1);
79  if( fun != null && fun._defs._len==2 && // Function is only called by 1 (and not the unknown caller)
80  (call.err(true)==null || fun._thunk_rhs) && // And args are ok
81  (tdef==null || CallNode.emem(tcall).isa(tdef)) && // Pre-GCP, call memory has to be as good as the default
82  (tdef==null || tretmem.isa(tdef)) && // Call and return memory at least as good as default
83  call.mem().in(0) != call && // Dead self-recursive
84  fun.in(1)._uses._len==1 && // And only calling fun
85  ret._live.isa(_live) && // Call and return liveness compatible
86  !fun.noinline() ) { // And not turned off
87  assert fun.in(1).in(0)==call; // Just called by us
88  fun.set_is_copy(); // Collapse the FunNode into the Call
89  return set_is_copy(ret.ctl(), ret.mem(), ret.rez()); // Collapse the CallEpi into the Ret
90  }
91  }
92 
93  // Parser thunks eagerly inline
94  if( call.fdx() instanceof ThretNode ) {
95  ThretNode tret = (ThretNode)call.fdx();
96  wire1(call,tret.thunk(),tret);
97  return set_is_copy(tret.ctrl(), tret.mem(), tret.rez()); // Collapse the CallEpi into the Thret
98  }
99 
100  // Only inline wired single-target function with valid args. CallNode wires.
101  if( nwired()!=1 ) return null; // More than 1 wired, inline only via FunNode
102  int fidx = fidxs.abit(); // Could be 1 or multi
103  if( fidx == -1 ) return null; // Multi choices, only 1 wired at the moment.
104  if( fidxs.above_center() ) return null; // Can be unresolved yet
105  if( BitsFun.is_parent(fidx) ) return null; // Parent, only 1 child wired
106 
107  if( call.err(true)!=null ) return null; // CallNode claims args in-error, do not inline
108 
109  // Call allows 1 function not yet inlined, sanity check it.
110  int cnargs = call.nargs();
111  FunNode fun = FunNode.find_fidx(fidx);
112  assert !fun.is_forward_ref() && !fun.is_dead()
113  && fun.nargs() == cnargs; // All checked by call.err
114  if( fun._val != Type.CTRL ) return null;
115  RetNode ret = fun.ret(); // Return from function
116  if( ret==null ) return null;
117 
118  // Single choice; check no conversions needed.
119  TypeTuple formals = fun._sig._formals;
120  for( Node parm : fun._uses ) {
121  if( parm instanceof ParmNode && parm.in(0)==fun ) {
122  int idx = ((ParmNode)parm)._idx;
123  if( idx < 0 ) continue; // RPC
124  Type actual = CallNode.targ(tcall,idx);
125  if( actual.isBitShape(formals.at(idx)) == 99 ) // Requires user-specified conversion
126  return null;
127  }
128  }
129 
130 
131  // Check for several trivial cases that can be fully inlined immediately.
132  Node cctl = call.ctl();
133  Node cmem = call.mem();
134  Node rctl = ret.ctl(); // Control being returned
135  Node rmem = ret.mem(); // Memory being returned
136  Node rrez = ret.rez(); // Result being returned
137  boolean inline = !fun.noinline();
138  // If the function does nothing with memory, then use the call memory directly.
139  if( (rmem instanceof ParmNode && rmem.in(CTL_IDX) == fun) || rmem._val ==TypeMem.XMEM )
140  rmem = cmem;
141  // Check that function return memory and post-call memory are compatible
142  if( !(_val instanceof TypeTuple) ) return null;
143  Type selfmem = ((TypeTuple) _val).at(MEM_IDX);
144  if( !rmem._val.isa( selfmem ) && !(selfmem==TypeMem.ANYMEM && call.is_pure_call()!=null) )
145  return null;
146 
147  // Check for zero-op body (id function)
148  if( rrez instanceof ParmNode && rrez.in(CTL_IDX) == fun && cmem == rmem && inline )
149  return unwire(call,ret).set_is_copy(cctl,cmem,call.arg(((ParmNode)rrez)._idx)); // Collapse the CallEpi
150 
151  // Check for constant body
152  Type trez = rrez._val;
153  if( trez.is_con() && rctl==fun && cmem == rmem && inline )
154  return unwire(call,ret).set_is_copy(cctl,cmem,Node.con(trez));
155 
156  // Check for a 1-op body using only constants or parameters and no memory effects
157  boolean can_inline=!(rrez instanceof ParmNode) && rmem==cmem && inline;
158  for( Node parm : rrez._defs )
159  if( parm != null && parm != fun &&
160  !(parm instanceof ParmNode && parm.in(0) == fun) &&
161  !(parm instanceof ConNode) )
162  can_inline=false; // Not trivial
163  if( can_inline ) {
164  Node irez = rrez.copy(false); // Copy the entire function body
165  ProjNode proj = ProjNode.proj(this,REZ_IDX);
166  irez._live = proj==null ? TypeMem.ESCAPE : proj._live;
167  for( Node parm : rrez._defs )
168  irez.add_def((parm instanceof ParmNode && parm.in(CTL_IDX) == fun) ? call.arg(((ParmNode)parm)._idx) : parm);
169  if( irez instanceof PrimNode ) ((PrimNode)irez)._badargs = call._badargs;
170  GVN.add_work_all(irez);
171  return unwire(call,ret).set_is_copy(cctl,cmem,irez);
172  }
173 
174  return null;
175  }
176 
177  // Used during GCP and Ideal calls to see if wiring is possible.
178  // Return true if a new edge is wired
179  public boolean check_and_wire( ) {
180  if( !(_val instanceof TypeTuple) ) return false; // Collapsing
181  CallNode call = call();
182  Type tcall = call._val;
183  if( !(tcall instanceof TypeTuple) ) return false;
184  BitsFun fidxs = CallNode.ttfp(tcall)._fidxs;
185  if( fidxs.above_center() ) return false; // Still choices to be made during GCP.
186 
187  // Check all fidxs for being wirable
188  boolean progress = false;
189  for( int fidx : fidxs ) { // For all fidxs
190  if( BitsFun.is_parent(fidx) ) continue; // Do not wire parents, as they will eventually settle out
191  FunNode fun = FunNode.find_fidx(fidx); // Lookup, even if not wired
192  if( fun.is_dead() ) continue; // Already dead, stale fidx
193  if( fun.is_forward_ref() ) continue; // Not forward refs, which at GCP just means a syntax error
194  RetNode ret = fun.ret();
195  if( ret==null ) continue; // Mid-death
196  if( _defs.find(ret) != -1 ) continue; // Wired already
197  if( !CEProjNode.good_call(tcall,fun) ) continue; // Args fail basic sanity
198  progress=true;
199  wire1(call,fun,ret); // Wire Call->Fun, Ret->CallEpi
200  }
201  return progress;
202  }
203 
204  // Wire the call args to a known function, letting the function have precise
205  // knowledge of its callers and arguments. This adds a edges in the graph
206  // but NOT in the CG, until _cg_wired gets set.
207  void wire1( CallNode call, Node fun, Node ret ) {
208  assert _defs.find(ret)==-1; // No double wiring
209  wire0(call,fun);
210  // Wire self to the return
211  add_def(ret);
212  GVN.add_flow(this);
213  GVN.add_flow(call);
214  GVN.add_flow_defs(call);
215  }
216 
217  // Wire without the redundancy check, or adding to the CallEpi
218  void wire0(CallNode call, Node fun) {
219  // Wire. Bulk parallel function argument path add
220 
221  // Add an input path to all incoming arg ParmNodes from the Call. Cannot
222  // assert finding all args, because dead args may already be removed - and
223  // so there's no Parm/Phi to attach the incoming arg to.
224  for( Node arg : fun._uses ) {
225  if( arg.in(0) != fun || !(arg instanceof ParmNode) ) continue;
226  Node actual;
227  int idx = ((ParmNode)arg)._idx;
228  switch( idx ) {
229  case 0: actual = new ConNode<>(TypeRPC.make(call._rpc)); break; // Always RPC is a constant
230  case MEM_IDX: actual = new MProjNode(call,(Env.DEFMEM._uses._len==0) ? Env.ANY : Env.DEFMEM); break; // Memory into the callee
231  default: actual = idx >= call.nargs() // Check for args present
232  ? new ConNode<>(Type.ALL) // Missing args, still wire (to keep FunNode neighbors) but will error out later.
233  : new ProjNode(call,idx); // Normal args
234  break;
235  }
236  actual._live = arg._live; // Set it before CSE during init1
237  arg.add_def(actual.init1());
238  if( arg._val.is_con() ) // Added an edge, value may change or go in-error
239  GVN.add_flow_defs(arg); // So use-liveness changes
240  }
241 
242  // Add matching control to function via a CallGraph edge.
243  fun.add_def(new CEProjNode(call,fun instanceof FunNode && !((FunNode) fun)._thunk_rhs ? ((FunNode)fun)._sig : null).init1());
244  GVN.add_flow(fun);
245  GVN.add_flow_uses(fun);
246  if( fun instanceof ThunkNode ) GVN.add_reduce_uses(fun);
247  if( fun instanceof FunNode ) GVN.add_inline((FunNode)fun);
248  }
249 
250  // Merge call-graph edges, but the call-graph is not discovered prior to GCP.
251  // If the Call's type includes all-functions, then the CallEpi must assume
252  // unwired Returns may yet appear, and be conservative. Otherwise it can
253  // just meet the set of known functions.
254  @Override public Type value(GVNGCM.Mode opt_mode) {
255  if( _is_copy ) return _val; // A copy
256  Type tin0 = val(0);
257  if( !(tin0 instanceof TypeTuple) )
258  return tin0.oob(); // Weird stuff?
259  TypeTuple tcall = (TypeTuple)tin0;
260  if( tcall._ts.length < ARG_IDX ) return tcall.oob(); // Weird stuff
261 
262  // Get Call result. If the Call args are in-error, then the Call is called
263  // and we flow types to the post-call.... BUT the bad args are NOT passed
264  // along to the function being called.
265  // tcall[0] = Control
266  // tcall[1] = Memory passed around the functions.
267  // tcall[2] = TypeFunPtr passed to FP2Closure
268  // tcall[3+]= Arg types
269  Type ctl = CallNode.tctl(tcall); // Call is reached or not?
270  if( ctl != Type.CTRL && ctl != Type.ALL )
271  return TypeTuple.CALLE.dual();
272  TypeFunPtr tfptr= CallNode.ttfpx(tcall); // Peel apart Call tuple
273  TypeMemPtr tescs= CallNode.tesc(tcall); // Peel apart Call tuple
274 
275  // Fidxes; if still in the parser, assuming calling everything
276  BitsFun fidxs = tfptr==null || tfptr.is_forward_ref() ? BitsFun.FULL : tfptr.fidxs();
277  // NO fidxs, means we're not calling anything.
278  if( fidxs==BitsFun.EMPTY ) return TypeTuple.CALLE.dual();
279  if( fidxs.above_center() ) return TypeTuple.CALLE.dual(); // Not resolved yet
280 
281  // Default memory: global worse-case scenario
282  TypeMem defmem = Env.DEFMEM._val instanceof TypeMem
283  ? (TypeMem)Env.DEFMEM._val
284  : Env.DEFMEM._val.oob(TypeMem.ALLMEM);
285 
286  // Any not-wired unknown call targets?
287  if( fidxs!=BitsFun.FULL ) {
288  // If fidxs includes a parent fidx, then it was split - currently exactly
289  // in two. If both children are wired, then proceed to merge both
290  // children as expected; same if the parent is still wired (perhaps with
291  // some children). If only 1 child is wired, then we have an extra fidx
292  // for a not-wired child. If this fidx is really some unknown caller we
293  // would have to get super conservative; but its actually just a recently
294  // split child fidx. If we get the RetNode via FunNode.find_fidx we suffer
295  // the non-local progress curse. If we get super conservative, we end up
296  // rolling backwards (original fidx returned int; each split will only
297  // ever return int-or-better). So instead we "freeze in place".
298  outerloop:
299  for( int fidx : fidxs ) {
300  int kids=0;
301  for( int i=0; i<nwired(); i++ ) {
302  int rfidx = wired(i)._fidx;
303  if( fidx == rfidx ) continue outerloop; // Directly wired is always OK
304  if( fidx == BitsFun.parent(rfidx) ) kids++; // Count wired kids of a parent fidx
305  }
306  if( BitsFun.is_parent(fidx) ) { // Child of a split parent, need both kids wired
307  if( kids==2 ) continue; // Both kids wired, this is ok
308  return _val; // "Freeze in place"
309  }
310  if( !opt_mode._CG ) // Before GCP? Fidx is an unwired unknown call target
311  { fidxs = BitsFun.FULL; break; }
312  }
313  }
314 
315  // Compute call-return value from all callee returns
316  Type trez = Type .ANY ;
317  Type tmem = TypeMem.ANYMEM;
318  if( fidxs == BitsFun.FULL ) { // Called something unknown
319  trez = Type.ALL; // Unknown target does worst thing
320  tmem = defmem;
321  } else { // All targets are known & wired
322  for( int i=0; i<nwired(); i++ ) {
323  RetNode ret = wired(i);
324  if( fidxs.test_recur(ret._fidx) ) { // Can be wired, but later fidx is removed
325  Type tret = ret._val;
326  if( !(tret instanceof TypeTuple) ) tret = tret.oob(TypeTuple.RET);
327  tmem = tmem.meet(((TypeTuple)tret).at(MEM_IDX));
328  trez = trez.meet(((TypeTuple)tret).at(REZ_IDX));
329  }
330  }
331  }
332  TypeMem post_call = (TypeMem)tmem;
333 
334  // If no memory projection, then do not compute memory
335  if( (_keep==0 && ProjNode.proj(this,MEM_IDX)==null) || call().mem()==null )
336  return TypeTuple.make(Type.CTRL,TypeMem.ANYMEM,trez);
337  Type premem = call().mem()._val;
338 
339  // Build epilog memory.
340 
341  // Approximate "live out of call", includes things that are alive before
342  // the call but not flowing in. Catches all the "new in call" returns.
343  BitsAlias esc_out = esc_out(post_call,trez);
344  TypeMem caller_mem = premem instanceof TypeMem ? (TypeMem)premem : premem.oob(TypeMem.ALLMEM);
345  int len = opt_mode._CG ? Math.max(caller_mem.len(),post_call.len()) : defmem.len();
346  TypeObj[] pubs = new TypeObj[len];
347  for( int i=1; i<pubs.length; i++ ) {
348  boolean ein = tescs._aliases.test_recur(i);
349  boolean eout = esc_out .test_recur(i);
350  TypeObj pre = caller_mem.at(i);
351  TypeObj obj = ein || eout ? (TypeObj)(pre.meet(post_call.at(i))) : pre;
352  if( !opt_mode._CG ) // Before GCP, must use DefMem to keeps types strong as the Parser
353  obj = (TypeObj)obj.join(defmem.at(i));
354  pubs[i] = obj;
355  }
356  TypeMem tmem3 = TypeMem.make0(pubs);
357 
358  return TypeTuple.make(Type.CTRL,tmem3,trez);
359  }
360 
361  static BitsAlias esc_out( TypeMem tmem, Type trez ) {
362  if( trez == Type.XNIL || trez == Type.NIL ) return BitsAlias.EMPTY;
363  if( trez instanceof TypeFunPtr ) trez = ((TypeFunPtr)trez)._disp;
364  if( trez instanceof TypeMemPtr )
365  return tmem.all_reaching_aliases(((TypeMemPtr)trez)._aliases);
366  return TypeMemPtr.OOP0.dual().isa(trez) ? BitsAlias.NZERO : BitsAlias.EMPTY;
367  }
368 
369  @Override public void add_flow_use_extra(Node chg) {
370  if( chg instanceof CallNode ) { // If the Call changes value
371  Env.GVN.add_flow(chg.in(MEM_IDX)); // The called memory changes liveness
372  Env.GVN.add_flow(((CallNode)chg).fdx()); // The called function changes liveness
373  for( int i=0; i<nwired(); i++ ) // Called returns change liveness
374  Env.GVN.add_flow(wired(i));
375  }
376  }
377 
378  // Sanity check
379  boolean sane_wiring() {
380  CallNode call = call();
381  for( int i=0; i<nwired(); i++ ) {
382  RetNode ret = wired(i);
383  if( ret.is_copy() ) return true; // Abort check, will be misaligned until dead path removed
384  FunNode fun = ret.fun();
385  boolean found=false;
386  for( Node def : fun._defs )
387  if( def instanceof CEProjNode && def.in(0)==call )
388  { found=true; break; }
389  if( !found ) return false;
390  }
391  return true;
392  }
393 
394  @Override public Node is_copy(int idx) { return _is_copy ? in(idx) : null; }
395 
396  private CallEpiNode set_is_copy( Node ctl, Node mem, Node rez ) {
397  CallNode call = call();
398  if( FunNode._must_inline == call._uid ) // Assert an expected inlining happens
399  FunNode._must_inline = 0;
400  if( mem instanceof IntrinsicNode ) // Better error message for Intrinsic if Call args are bad
401  ((IntrinsicNode)mem)._badargs = call._badargs[1];
402  call._is_copy=_is_copy=true;
403  // Memory was split at the Call, according to the escapes aliases, and
404  // rejoined at the CallEpi. We need to make that explicit here.
405  GVNGCM.retype_mem(null,call,this,false);
406 
408  Env.GVN.add_reduce_uses(this);
409  while( _defs._len>0 ) pop();
410  add_def(ctl);
411  add_def(mem);
412  add_def(rez);
413  return this;
414  }
415 
417  assert sane_wiring();
418  if( !ret.is_copy() ) {
419  FunNode fun = ret.fun();
420  for( int i = 1; i < fun._defs._len; i++ ) // Unwire
421  if( fun.in(i).in(0) == call ) {
422  fun.set_def(i, Env.XCTRL);
423  Env.GVN.add_flow(fun);
424  for( Node use : fun._uses ) {
425  Env.GVN.add_flow(use); // Dead path, all Phis can lift
426  Env.GVN.add_flow_defs(use); // All Phi uses lose a use
427  }
428  break;
429  }
430  }
431  del(_defs.find(ret));
432  Env.GVN.add_reduce(ret);
433  assert sane_wiring();
434  return this;
435  }
436 
437  @Override public TypeMem all_live() { return TypeMem.ALLMEM; }
438  // Compute local contribution of use liveness to this def. If the call is
439  // Unresolved, then none of CallEpi targets are (yet) alive.
440  @Override public TypeMem live_use(GVNGCM.Mode opt_mode, Node def ) {
441  assert _keep==0 || _live==all_live();
442  if( _is_copy ) return def._live; // A copy
443  // Not a copy
444  if( def==in(0) ) return _live; // The Call
445  if( def==in(1) ) return opt_mode._CG ? TypeMem.DEAD : _live; // The DefMem
446  // Wired return.
447  // The given function is alive, only if the Call will Call it.
448  Type tcall = call()._val;
449  if( !(tcall instanceof TypeTuple) ) return tcall.above_center() ? TypeMem.DEAD : _live;
450  BitsFun fidxs = CallNode.ttfp(tcall).fidxs();
451  int fidx = ((RetNode)def).fidx();
452  if( fidxs.above_center() || !fidxs.test_recur(fidx) )
453  return TypeMem.DEAD; // Call does not call this, so not alive.
454  return _live;
455  }
456 
457  //@Override public TV2 new_tvar(String alloc_site) {
458  // return _is_copy
459  // ? TV2.make_leaf(this,alloc_site)
460  // : TV2.make("Ret",this,alloc_site).push_dep(this);
461  //}
462 
463  //@Override public boolean unify( boolean test ) {
464  // if( _is_copy ) return false; // A copy
465  // // Build a HM tvar (args->ret), same as HM.java Apply does.
466  // Node fdx = call().fdx();
467  // TV2 tfdx = fdx.tvar();
468  // if( tfdx.is_leaf() ) return false; // Wait? probably need for force fresh-fun
469  // if( tfdx.is_dead() ) return false;
470  // TV2 tcargs = call().tvar();
471  // TV2 tcret = tvar();
472  // if( tcret.is_dead() ) return false;
473  //
474  // // Thunks are a little odd, because they cheat on graph structure.
475  // if( tfdx.isa("Ret") ) { // The fdx._tvar is a Ret not a Fun
476  // if( tcret == tfdx ) return false;
477  // boolean progress = tfdx.unify(tcret,test);
478  // if( progress && !test )
479  // Env.GVN.add_flow_uses(call()); // Progress, neighbors on list
480  // return progress;
481  // }
482  //
483  // // In an effort to detect possible progress without constructing endless
484  // // new TV2s, we look for a common no-progress situation by inspecting the
485  // // first layer in.
486  // TV2 tfargs = tfdx.get("Args");
487  // TV2 tfret = tfdx.get("Ret" );
488  // if( tfdx.isa("Fun") && tcargs==tfargs && tcret==tfret ) return false; // Equal parts, no progress
489  //
490  // // Will make progress aligning the shapes
491  // NonBlockingHashMap<Comparable,TV2> args = new NonBlockingHashMap<Comparable,TV2>(){{ put("Args",tcargs); put("Ret",tcret); }};
492  // TV2 tfun = TV2.make("Fun",fdx,"CallEpi_unify_Fun",args);
493  // boolean progress = tfdx.unify(tfun,test);
494  // if( progress && !test ) {
495  // Env.GVN.add_flow_uses(call()); // Progress, neighbors on list
496  // tcret.find().push_dep(this);
497  // if( fdx instanceof FreshNode )
498  // Env.GVN.add_reduce(fdx);
499  // }
500  // return progress;
501  //}
502 
503  @Override Node is_pure_call() { return in(0) instanceof CallNode ? call().is_pure_call() : null; }
504  // Return the set of updatable memory - including everything reachable from
505  // every call argument (including the display), and any calls reachable from
506  // there, transitively through memory.
507  //
508  // In practice, just the no-escape aliases
509  @Override BitsAlias escapees() { return BitsAlias.FULL; }
510 }
com.cliffc.aa.type.BitsAlias.FULL
static BitsAlias FULL
Definition: BitsAlias.java:27
com.cliffc.aa.node.RetNode.ctl
Node ctl()
Definition: RetNode.java:28
com.cliffc.aa.node.CallEpiNode.all_live
TypeMem all_live()
Definition: CallEpiNode.java:437
com.cliffc.aa.type.BitsFun.parent
static int parent(int kid)
Definition: BitsFun.java:50
com.cliffc.aa.type.BitsFun.EMPTY
static final BitsFun EMPTY
Definition: BitsFun.java:37
com.cliffc.aa.node.CEProjNode.good_call
static boolean good_call(Type tcall, Node ftun)
Definition: CEProjNode.java:20
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.ThretNode
Definition: ThretNode.java:14
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.node.CallEpiNode.call
CallNode call()
Definition: CallEpiNode.java:35
com.cliffc.aa.type.TypeRPC.make
static TypeRPC make(BitsRPC rpcs)
Definition: TypeRPC.java:25
com.cliffc.aa.type.Type.isa
boolean isa(Type t)
Definition: Type.java:623
com.cliffc.aa.node.CallNode.mem
Node mem()
Definition: CallNode.java:119
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.type.Type.join
Type join(Type t)
Definition: Type.java:619
com.cliffc.aa.node.Node.len
int len()
Definition: Node.java:125
com.cliffc.aa.type.TypeMem.XMEM
static final TypeMem XMEM
Definition: TypeMem.java:225
com.cliffc.aa.node.Node._live
TypeMem _live
Definition: Node.java:89
com.cliffc
com.cliffc.aa.node.CallNode._is_copy
boolean _is_copy
Definition: CallNode.java:89
com.cliffc.aa.node.Node
Definition: Node.java:16
com.cliffc.aa.node.CallEpiNode.is_mem
boolean is_mem()
Definition: CallEpiNode.java:36
com.cliffc.aa.type.TypeMem.ESCAPE
static final TypeMem ESCAPE
Definition: TypeMem.java:227
com.cliffc.aa.type.Type
an implementation of language AA
Definition: Type.java:94
com.cliffc.aa.node.Node.OP_CALLEPI
static final byte OP_CALLEPI
Definition: Node.java:18
com.cliffc.aa.type.BitsFun.FULL
static final BitsFun FULL
Definition: BitsFun.java:33
com.cliffc.aa.type.BitsAlias
Definition: BitsAlias.java:8
com.cliffc.aa.type.TypeTuple
Definition: TypeTuple.java:11
com.cliffc.aa.node.RetNode.mem
Node mem()
Definition: RetNode.java:29
com.cliffc.aa.type.TypeFunPtr._fidxs
BitsFun _fidxs
Definition: TypeFunPtr.java:26
com.cliffc.aa.node.CallEpiNode.value
Type value(GVNGCM.Mode opt_mode)
Definition: CallEpiNode.java:254
com.cliffc.aa.node.CallNode.ttfpx
static TypeFunPtr ttfpx(Type tcall)
Definition: CallNode.java:162
com.cliffc.aa.type.TypeFunPtr.fidxs
BitsFun fidxs()
Definition: TypeFunPtr.java:127
com.cliffc.aa.type.TypeMem.ALLMEM
static final TypeMem ALLMEM
Definition: TypeMem.java:228
com.cliffc.aa.node.Node._val
Type _val
Definition: Node.java:88
com.cliffc.aa.type.Type.ANY
static final Type ANY
Definition: Type.java:325
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.type.BitsFun.ALL
static final int ALL
Definition: BitsFun.java:24
com.cliffc.aa.type.Type.meet
final Type meet(Type t)
Definition: Type.java:412
com.cliffc.aa.node.CallEpiNode.check_and_wire
boolean check_and_wire()
Definition: CallEpiNode.java:179
com.cliffc.aa.node.RetNode
Definition: RetNode.java:19
com.cliffc.aa.node.CallEpiNode.is_pure_call
Node is_pure_call()
Definition: CallEpiNode.java:503
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.MProjNode
Definition: MProjNode.java:10
com.cliffc.aa.type.TypeMem.ANYMEM
static final TypeMem ANYMEM
Definition: TypeMem.java:228
com.cliffc.aa.type.Type.ALL
static final Type ALL
Definition: Type.java:324
com.cliffc.aa.node.CallEpiNode.CallEpiNode
CallEpiNode(Node... nodes)
Definition: CallEpiNode.java:26
com.cliffc.aa.type.TypeFunPtr.is_forward_ref
boolean is_forward_ref()
Definition: TypeFunPtr.java:186
com.cliffc.aa.type.Bits.above_center
boolean above_center()
Definition: Bits.java:204
com.cliffc.aa.type.TypeMem.make0
static TypeMem make0(TypeObj[] as)
Definition: TypeMem.java:170
com.cliffc.aa.Env.GVN
static final GVNGCM GVN
Definition: Env.java:13
com.cliffc.aa.type.TypeObj
Definition: TypeObj.java:15
com.cliffc.aa.type.Type.isBitShape
byte isBitShape(Type t)
Definition: Type.java:814
com.cliffc.aa.node.CallNode.nargs
int nargs()
Definition: CallNode.java:125
com.cliffc.aa.type.Type.is_con
boolean is_con()
Definition: Type.java:776
com.cliffc.aa.node.ThretNode.rez
Node rez()
Definition: ThretNode.java:18
com.cliffc.aa.type.BitsFun.is_parent
static boolean is_parent(int idx)
Definition: BitsFun.java:48
com.cliffc.aa.type.TypeMem.len
int len()
Definition: TypeMem.java:149
com.cliffc.aa.node.RetNode.is_copy
Node is_copy(int idx)
Definition: RetNode.java:212
com.cliffc.aa.type.Type.above_center
boolean above_center()
Definition: Type.java:741
com.cliffc.aa.node.Node.is_dead
boolean is_dead()
Definition: Node.java:820
com.cliffc.aa.node.CallNode._rpc
int _rpc
Definition: CallNode.java:87
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.node.ProjNode.proj
static ProjNode proj(Node head, int idx)
Definition: ProjNode.java:50
com.cliffc.aa.GVNGCM.add_reduce_uses
void add_reduce_uses(Node n)
Definition: GVNGCM.java:57
com.cliffc.aa.node.CallEpiNode.set_is_copy
CallEpiNode set_is_copy(Node ctl, Node mem, Node rez)
Definition: CallEpiNode.java:396
com.cliffc.aa.type.Type.CTRL
static final Type CTRL
Definition: Type.java:326
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.node.CallEpiNode.esc_out
static BitsAlias esc_out(TypeMem tmem, Type trez)
Definition: CallEpiNode.java:361
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.type.TypeTuple.make
static TypeTuple make(boolean any, Type[] ts)
Definition: TypeTuple.java:82
com.cliffc.aa.node.Node.in
Node in(int i)
Definition: Node.java:126
com.cliffc.aa.node.CallEpiNode.wire1
void wire1(CallNode call, Node fun, Node ret)
Definition: CallEpiNode.java:207
com.cliffc.aa.node.CallEpiNode.xstr
String xstr()
Definition: CallEpiNode.java:30
com.cliffc.aa.GVNGCM
Definition: GVNGCM.java:12
com.cliffc.aa.node.CallEpiNode._is_copy
boolean _is_copy
Definition: CallEpiNode.java:25
com.cliffc.aa.node.CEProjNode
Definition: CEProjNode.java:7
com.cliffc.aa.node.FunNode.noinline
boolean noinline()
Definition: FunNode.java:179
com.cliffc.aa.type.BitsAlias.EMPTY
static BitsAlias EMPTY
Definition: BitsAlias.java:27
com.cliffc.aa.node.ProjNode
Definition: ProjNode.java:11
com.cliffc.aa.node.DefMemNode
Definition: DefMemNode.java:8
com.cliffc.aa.type.BitsFun
Definition: BitsFun.java:7
com.cliffc.aa.node.CallNode.ctl
Node ctl()
Definition: CallNode.java:118
com.cliffc.aa.type.Type.NIL
static final Type NIL
Definition: Type.java:332
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.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.CallEpiNode.ideal_reduce
Node ideal_reduce()
Definition: CallEpiNode.java:40
com.cliffc.aa.node.Node.val
Type val(int idx)
Definition: Node.java:470
com.cliffc.aa
Definition: AA.java:1
com.cliffc.aa.node.FunNode._sig
TypeFunSig _sig
Definition: FunNode.java:62
com.cliffc.aa.node.RetNode.rez
Node rez()
Definition: RetNode.java:30
com.cliffc.aa.node.CallEpiNode.wired
RetNode wired(int x)
Definition: CallEpiNode.java:38
com.cliffc.aa.node.ThretNode.ctrl
Node ctrl()
Definition: ThretNode.java:16
com.cliffc.aa.node.Node.copy
Node copy(boolean copy_edges)
Definition: Node.java:264
com.cliffc.aa.node.RetNode.fidx
int fidx()
Definition: RetNode.java:46
com.cliffc.aa.type.Bits.abit
int abit()
Definition: Bits.java:203
com.cliffc.aa.node.CallEpiNode.nwired
int nwired()
Definition: CallEpiNode.java:37
com.cliffc.aa.node.CallNode.ttfp
static TypeFunPtr ttfp(Type tcall)
Definition: CallNode.java:157
com.cliffc.aa.type.TypeMemPtr._aliases
BitsAlias _aliases
Definition: TypeMemPtr.java:16
com.cliffc.aa.type.TypeTuple.at
Type at(int idx)
Definition: TypeTuple.java:182
com.cliffc.aa.node.Node.set_def
Node set_def(int idx, Node n)
Definition: Node.java:154
com.cliffc.aa.node.CallEpiNode.sane_wiring
boolean sane_wiring()
Definition: CallEpiNode.java:379
com.cliffc.aa.type.TypeTuple.CALLE
static final TypeTuple CALLE
Definition: TypeTuple.java:131
com.cliffc.aa.node.ThunkNode
Definition: ThunkNode.java:16
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.unwire
CallEpiNode unwire(CallNode call, RetNode ret)
Definition: CallEpiNode.java:416
com.cliffc.aa.node.CallEpiNode
Definition: CallEpiNode.java:24
com.cliffc.aa.node.CallNode.tctl
static Type tctl(Type tcall)
Definition: CallNode.java:148
com.cliffc.aa.node.ParmNode
Definition: ParmNode.java:14
com.cliffc.aa.node.ThretNode.mem
Node mem()
Definition: ThretNode.java:17
com.cliffc.aa.GVNGCM.add_flow_defs
void add_flow_defs(Node n)
Definition: GVNGCM.java:54
com.cliffc.aa.type.TypeRPC
Definition: TypeRPC.java:7
com.cliffc.aa.type.Type.oob
Type oob()
Definition: Type.java:635
com.cliffc.aa.type.TypeMem.all_reaching_aliases
BitsAlias all_reaching_aliases(BitsAlias aliases)
Definition: TypeMem.java:349
com.cliffc.aa.node.RetNode.fun
FunNode fun()
Definition: RetNode.java:32
com.cliffc.aa.type.TypeTuple._ts
Type[] _ts
Definition: TypeTuple.java:13
com.cliffc.aa.type.Type.XNIL
static final Type XNIL
Definition: Type.java:333
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.targ
static Type targ(Type tcall, int x)
Definition: CallNode.java:169
com.cliffc.aa.node.IntrinsicNode
Definition: IntrinsicNode.java:15
com.cliffc.aa.node.CallEpiNode.is_copy
Node is_copy(int idx)
Definition: CallEpiNode.java:394
com.cliffc.aa.node.Node._uid
int _uid
Definition: Node.java:84
com.cliffc.aa.node.CallEpiNode.live_use
TypeMem live_use(GVNGCM.Mode opt_mode, Node def)
Definition: CallEpiNode.java:440
com.cliffc.aa.node.CallNode.arg
Node arg(int x)
Definition: CallNode.java:127
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.type.BitsAlias.NZERO
static BitsAlias NZERO
Definition: BitsAlias.java:27
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.Node.init1
Node init1()
Definition: Node.java:708
com.cliffc.aa.node.CallNode.is_pure_call
Node is_pure_call()
Definition: CallNode.java:785
com.cliffc.aa.Env.ANY
static ConNode ANY
Definition: Env.java:24
com
com.cliffc.aa.node.CallNode.err
ErrMsg err(boolean fast)
Definition: CallNode.java:694
com.cliffc.aa.node.CallEpiNode.escapees
BitsAlias escapees()
Definition: CallEpiNode.java:509
com.cliffc.aa.Env.DEFMEM
static DefMemNode DEFMEM
Definition: Env.java:19
com.cliffc.aa.type.TypeMem.at
TypeObj at(int alias)
Definition: TypeMem.java:135
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.node.ThretNode.thunk
ThunkNode thunk()
Definition: ThretNode.java:19
com.cliffc.aa.type
Definition: Bits.java:1
com.cliffc.aa.node.Node._defs
Ary< Node > _defs
Definition: Node.java:124
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.CallNode.emem
static TypeMem emem(Type tcall)
Definition: CallNode.java:149
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.CallNode.tesc
static TypeMemPtr tesc(Type tcall)
Definition: CallNode.java:151
com.cliffc.aa.node.CallEpiNode.add_flow_use_extra
void add_flow_use_extra(Node chg)
Definition: CallEpiNode.java:369