aa
RetNode.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.Type;
6 import com.cliffc.aa.type.TypeMem;
7 import com.cliffc.aa.type.TypeTuple;
8 
9 import static com.cliffc.aa.AA.MEM_IDX;
10 import static com.cliffc.aa.AA.REZ_IDX;
11 
12 // See CallNode comments. The RetNode gathers {control (function exits or
13 // not), memory, value, rpc, fun}, and sits at the end of a function. The RPC
14 // dictates which calls can be reached from here. The Fun is used to rapidly
15 // find the FunNode, as a SESE region shortcut. A FunPtrNode points to this
16 // Ret, and is used for all function-pointer uses. Otherwise only CallEpis
17 // point to a Ret representing wired calls.
18 
19 public final class RetNode extends Node {
20  int _fidx; // Shortcut to fidx when the FunNode has collapsed
21  int _nargs; // Replicated from FunNode
22  public RetNode( Node ctrl, Node mem, Node val, Node rpc, FunNode fun ) {
23  super(OP_RET,ctrl,mem,val,rpc,fun);
24  _fidx = fun._fidx;
25  _nargs=fun.nargs();
26  fun.unkeep(); // Unkeep the extra, now that a Ret completes the Fun
27  }
28  public Node ctl() { return in(0); }
29  public Node mem() { return in(1); }
30  public Node rez() { return in(2); }
31  public Node rpc() { return in(3); }
32  public FunNode fun() { return (FunNode)in(4); }
33  @Override public boolean is_mem() { return true; }
34  // If this function is not using any displays, then there is a single unique
35  // FunPtr. Otherwise this call is ambiguous, as each execution of the
36  // FunPtrNode makes a new display.
37  public FunPtrNode funptr() {
38  FunPtrNode fpn=null;
39  for( Node use : _uses )
40  if( use instanceof FunPtrNode ) {
41  if( fpn!=null ) return null; // Ambiguous; several displays from the same function
42  fpn = (FunPtrNode)use;
43  }
44  return fpn; // Zero (null) or 1 display.
45  }
46  public int fidx() { return _fidx; }
47  void set_fidx(int fidx) { unelock(); _fidx = fidx; } // Unlock before changing hash
48  @Override public int hashCode() { return super.hashCode()+_fidx; }
49  @Override public boolean equals(Object o) {
50  if( !super.equals(o) ) return false;
51  return _fidx==((RetNode)o)._fidx;
52  }
53 
54  // Short self name
55  @Override public String xstr() {
56  if( is_dead() ) return "Ret";
58  return "Ret_"+(is_copy() ? "!copy!" : (fun==null ? ""+_fidx : fun.name()));
59  }
60 
61  @Override public Node ideal_reduce() {
62  // If control is dead, but the Ret is alive, we're probably only using the
63  // FunPtr as a 'gensym'. Nuke the function body.
64  if( !is_copy() && ctl()._val == Type.XCTRL && !is_prim() && fun()._val ==Type.XCTRL )
65  set_def(4,null); // We're a copy now!
66 
67  // If no users inlining, wipe out all edges
68  if( is_copy() && in(0)!=null ) {
69  boolean only_fptr = true;
70  for( Node use : _uses ) if( !(use instanceof FunPtrNode) ) { only_fptr=false; break; }
71  if( only_fptr ) { // Only funptr uses, make them all gensyms
72  set_def(0,null); // No ctrl
73  set_def(1,null); if( is_dead() ) return this; // No mem
74  set_def(2,null); // No val
75  set_def(3,null); // No rpc
76  set_def(4,null); // No fun
77  return this; // Progress
78  }
79  }
80  if( is_copy() ) return null;
81  // Collapsed to a constant? Remove any control interior.
82  Node ctl = ctl();
83  if( rez()._val.is_con() && ctl!=fun() && // Profit: can change control and delete function interior
84  (mem()._val ==TypeMem.EMPTY || (mem() instanceof ParmNode && mem().in(0)==fun())) ) // Memory has to be trivial also
85  return set_def(0,fun()); // Gut function body
86  return null;
87  }
88 
89  // Look for a tail recursive call
90  @Override public Node ideal_mono() { return is_copy() ? null : tail_recursive(); }
91 
92  // Look for a tail-Call. There should be 1 (collapsed) Region, and maybe a
93  // tail Call. Look no further than 1 Region, since collapsing will fold
94  // nested regions up. Since the RetNode is a single "pinch point" for
95  // control flow in the entire function, if we see a tail-call here, it means
96  // the function ends in an infinite loop, not currently optimized.
98  Node ctl = ctl();
99  if( ctl._op!=OP_REGION ) return null;
100  int idx; for( idx=1; idx<ctl._defs._len; idx++ ) {
101  Node c = ctl.in(idx), cepi = c.in(0);
102  if( c._op == OP_CPROJ && cepi._op == OP_CALLEPI &&
103  ((CallEpiNode)cepi).nwired()==1 &&
104  ((CallEpiNode)cepi).wired(0)== this && // TODO: if in tail position, can be a tail call not self-recursive
105  ((CallEpiNode)cepi).call().fdx()._op == OP_FUNPTR ) // And a direct call
106  break;
107  }
108  if( idx == ctl._defs._len ) return null; // No call-epi found
109  CallEpiNode cepi = (CallEpiNode)ctl.in(idx).in(0);
110  CallNode call = cepi.call();
111  if( call.ctl()._val != Type.CTRL ) return null; // Dead call
112  // Every Phi on the region must come directly from the CallEpi.
113  for( Node phi : ctl._uses )
114  if( phi._op == OP_PHI && phi.in(idx).in(0)!=cepi )
115  return null;
116  FunNode fun = fun();
117  // Every Phi must be type compatible
118  for( int i=MEM_IDX; i<call.nargs(); i++ )
119  if( !check_phi_type(fun,call, i) )
120  return null;
121 
122  // TODO: Turn this back on.
123  // Currently does not unroll, which is the moral equivalent of repeated inlining...
124  // so fails the Church-Rosser 1-step property.
125  if( true ) return null;
126 
127  // Behind the function entry, split out a LoopNode/Phi setup - one phi for
128  // every argument. The first input comes from the parms; the second input
129  // from the Call arguments - including the control. Cut the call control,
130  // which will go dead & collapse.
131 
132  // Find the trailing control behind the Fun.
133  Node cuse = null; // Control use behind fun.
134  for( Node use : fun._uses )
135  if( use != this && use.is_CFG() )
136  { assert cuse==null; cuse = use; }
137  assert cuse!=null;
138  int cidx = cuse._defs.find(fun);
139  // Insert loop in-the-middle
140  try(GVNGCM.Build<Node> X = Env.GVN.new Build<>()) {
141  LoopNode loop = new LoopNode();
142  loop.add_def(fun);
143  loop.add_def(call.ctl());
144  X.xform(loop);
145  cuse.set_def(cidx,loop);
146  // Insert loop phis in-the-middle
147  for( int argn=MEM_IDX; argn<call.nargs(); argn++ ) {
148  ParmNode parm = fun.parm(argn);
149  if( parm==null ) continue; // arg/parm might be dead
150  Node phi = new PhiNode(parm._t,parm._badgc,loop,null,call.arg(argn));
151  phi._val = parm._val ; // Inserting inside a loop, take optimistic values
152  phi._live = parm._live; // Inserting inside a loop, take optimistic lives
153  parm.insert(phi);
154  phi.set_def(1,parm);
155  X.add(phi);
156  }
157  // Cut the Call control
158  call.set_def(0, Env.XCTRL);
159  Env.GVN.add_unuse(call);
160  return this;
161  }
162  }
163 
164  private static boolean check_phi_type( FunNode fun, CallNode call, int argn ) {
165  ParmNode parm = fun.parm(argn);
166  if( parm==null ) return true; // arg/parm might be dead
167  Type tenter = parm._val;
168  Type tback = call.arg(argn)._val;
169  return tback.isa(tenter);
170  }
171 
172 
173  @Override public Type value(GVNGCM.Mode opt_mode) {
174  if( ctl()==null ) return _val; // No change if a copy
175  Type ctl = ctl()._val;
176  if( ctl != Type.CTRL ) return ctl.oob(TypeTuple.RET);
177  Type mem = mem()._val;
178  if( !(mem instanceof TypeMem) ) mem = mem.oob(TypeMem.ALLMEM);
179  Type val = rez()._val;
180  return TypeTuple.make(ctl,mem,val);
181  }
182 
183 
184  @Override public TypeMem all_live() { return TypeMem.ALLMEM; }
185  @Override public TypeMem live(GVNGCM.Mode opt_mode) {
186  // Pre-GCP, might be used anywhere (still finding CFG)
187  return !is_copy() && fun().has_unknown_callers() && !opt_mode._CG ? TypeMem.ALLMEM : super.live(opt_mode);
188  }
189  @Override public TypeMem live_use(GVNGCM.Mode opt_mode, Node def ) {
190  if( def==mem() ) return _live;
191  if( def==rez() ) return TypeMem.ESCAPE;
192  return TypeMem.ALIVE; // Basic aliveness
193  }
194 
195  //@Override public TV2 new_tvar(String alloc_site) {
196  // return TV2.make("Ret",this,alloc_site);
197  //}
198  //
199  //@Override public boolean unify( boolean test ) {
200  // if( is_copy() ) return false; // Disappearing
201  // FunPtrNode fptr = funptr();
202  // if( fptr != null && fptr.is_forward_ref() ) return false;
203  // TV2 tvar = tvar();
204  // if( tvar.is_dead() ) return false;
205  // assert tvar.isa("Ret");
206  // boolean progress = false;
207  // for( int i=0; i<=REZ_IDX; i++ )
208  // progress |= tvar.unify_at(i,tvar(i),test);
209  // return progress;
210  //}
211 
212  @Override public Node is_copy(int idx) { throw com.cliffc.aa.AA.unimpl(); }
213  boolean is_copy() { return !(in(4) instanceof FunNode) || fun()._fidx != _fidx; }
214  @Override public boolean is_forward_ref() { return fun().is_forward_ref(); }
215 }
com.cliffc.aa.node.RetNode.ctl
Node ctl()
Definition: RetNode.java:28
com.cliffc.aa.node.RetNode.check_phi_type
static boolean check_phi_type(FunNode fun, CallNode call, int argn)
Definition: RetNode.java:164
com.cliffc.aa.GVNGCM.add_unuse
Node add_unuse(Node n)
Definition: GVNGCM.java:59
com.cliffc.aa.node.CallEpiNode.call
CallNode call()
Definition: CallEpiNode.java:35
com.cliffc.aa.type.Type.isa
boolean isa(Type t)
Definition: Type.java:623
com.cliffc.aa.node.RetNode.hashCode
int hashCode()
Definition: RetNode.java:48
com.cliffc.aa.node.RetNode.live
TypeMem live(GVNGCM.Mode opt_mode)
Definition: RetNode.java:185
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.Node._live
TypeMem _live
Definition: Node.java:89
com.cliffc.aa.node.RetNode.tail_recursive
Node tail_recursive()
Definition: RetNode.java:97
com.cliffc
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.node.RetNode.live_use
TypeMem live_use(GVNGCM.Mode opt_mode, Node def)
Definition: RetNode.java:189
com.cliffc.aa.node.PhiNode._badgc
final Parse _badgc
Definition: PhiNode.java:10
com.cliffc.aa.type.TypeMem.ESCAPE
static final TypeMem ESCAPE
Definition: TypeMem.java:227
com.cliffc.aa.node.Node.OP_FUNPTR
static final byte OP_FUNPTR
Definition: Node.java:28
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.node.PhiNode
Definition: PhiNode.java:9
com.cliffc.aa.AA.MEM_IDX
static final int MEM_IDX
Definition: AA.java:14
com.cliffc.aa.type.TypeTuple
Definition: TypeTuple.java:11
com.cliffc.aa.node.RetNode.mem
Node mem()
Definition: RetNode.java:29
com.cliffc.aa.node.Node.unelock
void unelock()
Definition: Node.java:128
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.node.RetNode.equals
boolean equals(Object o)
Definition: RetNode.java:49
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.RetNode
Definition: RetNode.java:19
com.cliffc.aa.node.CallNode
Definition: CallNode.java:86
com.cliffc.aa.AA.unimpl
static RuntimeException unimpl()
Definition: AA.java:10
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.Env.GVN
static final GVNGCM GVN
Definition: Env.java:13
com.cliffc.aa.node.FunNode.name
static String name(int fidx, boolean debug)
Definition: FunNode.java:109
com.cliffc.aa.node.RetNode.RetNode
RetNode(Node ctrl, Node mem, Node val, Node rpc, FunNode fun)
Definition: RetNode.java:22
com.cliffc.aa.node.Node.unkeep
public< N extends Node > N unkeep()
Definition: Node.java:232
com.cliffc.aa.node.RetNode.value
Type value(GVNGCM.Mode opt_mode)
Definition: RetNode.java:173
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.RetNode.is_copy
Node is_copy(int idx)
Definition: RetNode.java:212
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.type.TypeMem.live
TypeLive live()
Definition: TypeMem.java:559
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.AA.REZ_IDX
static final int REZ_IDX
Definition: AA.java:16
com.cliffc.aa.type.Type.CTRL
static final Type CTRL
Definition: Type.java:326
com.cliffc.aa.node.RetNode.all_live
TypeMem all_live()
Definition: RetNode.java:184
com.cliffc.aa.node.FunNode.find_fidx
static FunNode find_fidx(int fidx)
Definition: FunNode.java:101
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.RetNode._nargs
int _nargs
Definition: RetNode.java:21
com.cliffc.aa.type.TypeMem.ALIVE
static final TypeMem ALIVE
Definition: TypeMem.java:226
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.node.RetNode.rpc
Node rpc()
Definition: RetNode.java:31
com.cliffc.aa.node.Node.insert
Node insert(int idx, Node n)
Definition: Node.java:165
com.cliffc.aa.node.RetNode.is_forward_ref
boolean is_forward_ref()
Definition: RetNode.java:214
com.cliffc.aa.node.CallNode.ctl
Node ctl()
Definition: CallNode.java:118
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.Node.OP_CPROJ
static final byte OP_CPROJ
Definition: Node.java:22
com.cliffc.aa.node.Node.is_CFG
boolean is_CFG()
Definition: Node.java:356
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.RetNode.rez
Node rez()
Definition: RetNode.java:30
com.cliffc.aa.node.PhiNode._t
final Type _t
Definition: PhiNode.java:11
com.cliffc.aa.node.RetNode.fidx
int fidx()
Definition: RetNode.java:46
com.cliffc.aa.node.RetNode.is_copy
boolean is_copy()
Definition: RetNode.java:213
com.cliffc.aa.node.RetNode.ideal_mono
Node ideal_mono()
Definition: RetNode.java:90
com.cliffc.aa.node.Node.set_def
Node set_def(int idx, Node n)
Definition: Node.java:154
com.cliffc.aa.node.LoopNode
Definition: LoopNode.java:6
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.ParmNode
Definition: ParmNode.java:14
com.cliffc.aa.node.RetNode.is_mem
boolean is_mem()
Definition: RetNode.java:33
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.Build
Definition: GVNGCM.java:356
com.cliffc.aa.node.RetNode.funptr
FunPtrNode funptr()
Definition: RetNode.java:37
com.cliffc.aa.node.CallNode.arg
Node arg(int x)
Definition: CallNode.java:127
com.cliffc.aa.node.FunNode
Definition: FunNode.java:58
com
com.cliffc.aa.node.RetNode.xstr
String xstr()
Definition: RetNode.java:55
com.cliffc.aa.node.Node.OP_PHI
static final byte OP_PHI
Definition: Node.java:38
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.type
Definition: Bits.java:1
com.cliffc.aa.node.Node._defs
Ary< Node > _defs
Definition: Node.java:124
com.cliffc.aa.type.TypeMem.EMPTY
static final TypeMem EMPTY
Definition: TypeMem.java:223
com.cliffc.aa.node.Node.OP_REGION
static final byte OP_REGION
Definition: Node.java:41
com.cliffc.aa.GVNGCM.Mode
Definition: GVNGCM.java:14
com.cliffc.aa.node.RetNode.ideal_reduce
Node ideal_reduce()
Definition: RetNode.java:61