1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
|
package com.seaofnodes.simple.node;
import com.seaofnodes.print.ExprPrinter;
import com.seaofnodes.simple.Parser;
import com.seaofnodes.simple.codegen.CodeGen;
import com.seaofnodes.simple.type.Type;
import com.seaofnodes.simple.type.TypeFunPtr;
import com.seaofnodes.simple.type.TypeMem;
import com.seaofnodes.simple.type.TypeRPC;
import com.seaofnodes.simple.type.XInt;
import com.seaofnodes.simple.util.BAOS;
import com.seaofnodes.simple.util.Utils;
import java.util.HashMap;
import java.util.IdentityHashMap;
/**
* Call
*/
public class CallNode extends CFGNode {
// Source location for late reported errors
public final Parser.Lexer _loc;
public CallNode(Parser.Lexer loc, Node... nodes) { super(nodes); _loc = loc; }
public CallNode(CallNode call) { super(call); _loc = call._loc; }
@Override public Tag serialTag() { return Tag.Call; }
public void packed( BAOS baos, HashMap<String,Integer> strs, HashMap<Type,Integer> types, IdentityHashMap<Node, Integer> anodes ) { baos.packed1(nIns()); }
static Node make( BAOS bais ) { return new CallNode(null,new Node[bais.packed1()]); }
@Override protected ExprPrinter<Node> _print1(ExprPrinter<Node> p) {
String fname = name();
if( fname == null ) p.n(fptr());
else p.p(fname);
p.p("( ");
for( int i=2; i<nIns()-1; i++ )
p.n(in(i)).p(",");
return p.unchar(',').unchar(' ').close();
}
public String name() {
if( fptr()._type instanceof TypeFunPtr tfp && tfp._isConstant() && tfp.notNull() ) {
FunNode fun = CodeGen.CODE._link(tfp);
if( fun !=null ) return fun._name;
if( fptr() instanceof ExternNode ex ) return ex._extern;
}
return null;
}
Node ctrl() { return in(0); }
Node mem () { return in(1); }
// Args mapped 1-to-1 on inputs, so conceptually start at 2
public Node arg(int idx) { return in(idx); }
// Same arg accounting as TFPs, although the numbering starts at 2
public int nargs() { return nIns()-3; } // Minus control, memory, fptr
// args from input 2 to last; last is function input
public Node fptr() { return _inputs.last(); }
// Error if not a TFP
public TypeFunPtr tfp() { return (TypeFunPtr)fptr()._type; }
// Call is to an externally supplied code
public boolean external() { return false; }
// Find the Call End from the Call
public CallEndNode cend() {
// Always in use slot 0
if( nOuts()>0 && out(0) instanceof CallEndNode cend ) {
assert _cend()==cend;
return cend;
} else {
assert _cend()==null;
return null;
}
}
private CallEndNode _cend() {
CallEndNode cend=null;
for( Node n : _outputs )
if( n instanceof CallEndNode cend0 )
{ assert cend == null; cend = cend0; }
return cend;
}
// Get the one control following; error to call with more than one e.g. an
// IfNode or other multi-way branch.
@Override public CFGNode uctrl() { return cend(); }
@Override
public Type compute() {
return ctrl()._type;
}
@Override
public Node idealize() {
CallEndNode cend = cend();
if( cend==null ) return null; // Still building
// Link: call calls target function. Linking makes the target FunNode
// point to this Call, and all his Parms point to the call arguments;
// also the CallEnd points to the Return.
Node progress = null;
if( fptr()._type instanceof TypeFunPtr tfp && tfp.nargs() == nargs() ) {
// If fidxs is negative, then infinite unknown functions
int[] fidxs = tfp.fidxs();
if( !XInt.isHigh(fidxs) ) {
// Walk the bits and link
for( int fidx = XInt.next(fidxs,0); fidx > 0; fidx = XInt.next(fidxs,fidx) ) {
FunNode fun = CodeGen.CODE.link(fidx);
if( fun!=null && !fun._folding && !linked(fun) )
progress = link(fun);
}
}
}
return progress;
}
// True if Fun is linked to this Call
public boolean linked( FunNode fun ) {
for( Node n : fun._inputs )
if( n == this )
return true;
return false;
}
// Link so this calls fun
public Node link( FunNode fun ) {
assert !linked(fun);
CodeGen.CODE.add(fun).addDef(this);
for( Node use : fun._outputs )
if( use instanceof ParmNode parm ) {
Node def = parm._idx==0 ? ConstantNode.seed(cend()._rpc).peephole() : arg(parm._idx);
CodeGen.CODE.add(parm).addDef(def);
// Linking can happen during post-SCCP inlining. Keep an RPC
// Parm's cached finite set synchronized with its newly added
// input instead of waiting for the next worklist visit.
if( parm._idx==0 && parm._type instanceof TypeRPC )
parm._type = parm._type.meet(def._type);
}
// Call end points to function return
CodeGen.CODE.add(cend()).addDef(fun.ret());
return this;
}
// Unlink a single function
public void unlink( FunNode fun, int path ) {
assert linked(fun);
for( Node use : fun._outputs )
if( use instanceof ParmNode )
use.delDef(path);
fun.delDef(path);
CodeGen.CODE.add(fun);
CallEndNode cend = cend();
ReturnNode ret = fun.ret();
if( cend != null ) {
ret.keep();
cend.delDef(cend._inputs.find(ret));
CodeGen.CODE.add(cend);
ret.unkeep();
}
assert !linked(fun);
}
// Unlink all linked functions
public void unlink_all() {
for( int i=0; i<_outputs._len; i++ )
if( out(i) instanceof FunNode fun ) {
int path = fun._inputs.find(this);
unlink(fun,path);
i--;
}
}
@Override
public Parser.ParseException err() {
if( fptr()._type == Type.BOTTOM )
return null; // Wrong, but failing earlier
if( !(fptr()._type instanceof TypeFunPtr tfp) )
return Parser.error("Expected a function, but found " + fptr()._type, _loc);
if( !tfp.notNull() )
return Parser.error( "Might be null calling "+tfp, _loc);
if( nargs() != tfp.nargs() )
return Parser.error( "Expecting "+tfp.nargs()+" arguments, but found "+nargs(), _loc);
// Check for args
for( int i=0; i<tfp.nargs(); i++ )
if( !arg(i+2)._type.isa(tfp.arg(i)) || !arg(i+2)._type.accessISA(tfp.arg(i)) ) {
// Constructors return private memory and carry hidden self and
// selfMem arguments ahead of the source-level arguments.
int argno = i - (tfp.ret() instanceof TypeMem ? 2 : 0);
return Parser.error( "Argument #" + argno + " isa " + arg(i+2)._type + ", but must be a " + tfp.arg(i), _loc );
}
if( tfp.isHigh() )
throw Utils.TODO(); // Infinite unknown TFPs? Should be fairly precise CG
return null;
}
}
|