-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathCFA.dl
436 lines (373 loc) · 12.9 KB
/
CFA.dl
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
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
/*
Handles:
- function calls
- partial applications
*/
/*
control flow analysis
each value can be:
- constructor (node) ; collected data: source instruction name
- partially applied function / closure ;
NOTE:
partial application requires computation and the computattion details need to be recorded
collected data: apply chain; how application evolves and got saturated and results new values
decls
ApplyChain
Q: how to normalize/reduce apply chain?
how do we know the final result of it?
decl
PNode : store the result of apply chain if it is still a partial application
Node and PNode is the normal form
Idea: use points-to relation for simple way value passing
*/
.decl ApplyChain(namespace:symbol, v:Variable, f:CodeName, step:number, consumed:number, arg_count:number)
.decl PNode(v:Variable, fun:CodeName, arity:number, missing:number)
.decl PNodeArgument(v:Variable, fun:CodeName, i:number, value:CodeName)
.decl Called(instruction:Variable, f:CodeName)
.output PNode
.output PNodeArgument
.output ApplyChain
.output Called
/*
apply chain
origin cases:
- calling known function
- calling PNode
step cases:
- extend same PNode ; add more arguments but still understaurated
- PNode got saturated without leftover arguments
- PNode got saturated, still remain some argument ; call function then apply the remained arguments to the function result
IDEA:
- build ApplyChains
- propagate call/PNode arguments to function parameters
Design Idea:
- the function in apply chain refers to the function which result sould be used to create the next link
- function parameters are applied by the rule that creates the ApplyChain value
*/
// create PNodes for referred functions in call or node argument or in move
USED("CFA-01")
PNode(f, f, arity, arity) :-
( IsFunction(f)
; IsClosure(f)
),
CodeArity(f, arity),
( CallArgument(_, _, f)
; NodeArgument(_, _, f)
; Move(_, f)
; ReturnValue(_, f)
).
// CHECKED
/*
NOTE:
separate return value and parameter handling
parameters are optional, so they absence can block the return value handling
separate PNode and PNodeArgument: PNodeArguments are optionalm, so they can block PNode handling
*/
//////////////////////////////////
/*
NOTES:
- copy Call and CallArgument
- add namespace or result target
- nampespace might be unnecessary
*/
.decl ExecCall(namespace:symbol, call_result:Variable, fun:CodeName, arg_count:number)
.decl ExecCallArgument(namespace:symbol, call_result:Variable, fun:CodeName, i:number, value:Variable)
.output ExecCall
.output ExecCallArgument
USED("CFA-01-A")
ExecCall("normal-call", r, fun, arg_count) :-
REACHABLE(r)
Call(r, fun, arg_count),
EvalMode(r, "strict").
// CHECKED
USED("CFA-01-B")
ExecCallArgument("normal-call", r, fun, call_arg_i, arg) :-
REACHABLE(r)
Call(r, fun, arg_count),
EvalMode(r, "strict"),
// call arguments
call_arg_i >= 0,
call_arg_i < arg_count,
CallArgument(r, call_arg_i, arg).
// CHECKED
//////////////////////////////////
// strict, saturated, known function/closure call: execute function call
USED("CFA-02")
ReachableCode(fun),
PointsTo(r, ret_var) :- // return value
ExecCall(_, r, fun, arg_count),
CodeArity(fun, arity), // arity is only for known callables
arg_count = arity,
// set return value as result
ReturnValue(fun, ret_var).
// CHECKED
USED("CFA-03")
PointsTo(param, arg) :- // pass arguments to function parameters
ExecCall(ns, r, fun, arg_count),
CodeArity(fun, arity), // arity is only for known callables
arg_count = arity,
// call parameters
call_arg_i >= 0,
call_arg_i < arity,
ExecCallArgument(ns, r, fun, call_arg_i, arg),
CodeParameter(fun, call_arg_i, param).
// CHECKED
//////////////////////////////////
// strict, undersaturated known call: create PNode
USED("CFA-04")
PNode(r, fun, arity, arity - arg_count) :-
ExecCall(_, r, fun, arg_count),
CodeArity(fun, arity), // arity is only for known callables
arg_count < arity.
// CHECKED
USED("CFA-05")
PNodeArgument(r, fun, call_arg_i, arg_value) :-
ExecCall(ns, r, fun, arg_count),
CodeArity(fun, arity), // arity is only for known callables
arg_count < arity,
// pnode arguments
call_arg_i >= 0,
call_arg_i < arg_count,
ExecCallArgument(ns, r, fun, call_arg_i, arg_value).
// CHECKED
//////////////////////////////////
// strict, saturated PNode call: execute function call
USED("CFA-06")
ReachableCode(fun),
PointsTo(r, ret_var) :- // return value
ExecCall(_, r, pnode, arg_count),
PNode(pnode, fun, _, missing),
arg_count = missing,
// return value
ReturnValue(fun, ret_var).
// CHECKED
USED("CFA-07")
PointsTo(param, arg) :- // pass call arguments to saturate function call
ExecCall(ns, r, pnode, arg_count),
PNode(pnode, fun, arity, missing),
arg_count = missing,
// call parameters
call_arg_i >= 0,
call_arg_i < missing,
ExecCallArgument(ns, r, pnode, call_arg_i, arg),
CodeParameter(fun, call_arg_i + arity - missing, param).
// CHECKED
USED("CFA-08")
PointsTo(bound_param, pnode_arg) :- // pass PNode arguments for the function call
ExecCall(_, _, pnode, arg_count),
PNode(pnode, fun, arity, missing),
arg_count = missing,
0 <= missing,
// pnode parameters
pnode_i >= 0,
pnode_i < arity - missing,
PNodeArgument(pnode, fun, pnode_i, pnode_arg),
CodeParameter(fun, pnode_i, bound_param).
// CHECKED
//////////////////////////////////
// strict, undersaturated PNode call: create new PNode
USED("CFA-09")
PNode(r, fun, arity, missing - arg_count) :-
ExecCall(_, r, pnode, arg_count),
PNode(pnode, fun, arity, missing),
arg_count < missing.
// CHECKED
USED("CFA-10")
PNodeArgument(r, fun, call_arg_i + arity - missing, arg) :-
ExecCall(ns, r, pnode, arg_count),
PNode(pnode, fun, arity, missing),
arg_count < missing,
// new pnode aruments
call_arg_i >= 0,
call_arg_i < arg_count,
ExecCallArgument(ns, r, pnode, call_arg_i, arg).
// CHECKED
USED("CFA-11")
PNodeArgument(r, fun, bound_i, bound_value) :-
ExecCall(_, r, pnode, arg_count),
PNode(pnode, fun, arity, missing),
arg_count < missing,
// copy old pnode arguments
bound_i >= 0,
bound_i < arity - missing,
PNodeArgument(pnode, fun, bound_i, bound_value).
// CHECKED
//////////////////////////////////
// strict, oversaturated, known function/closure call: execute function call + create ApplyChain
USED("CFA-12")
ReachableCode(fun),
ApplyChain(ns, r, fun, 0, arity, arg_count) :-
ExecCall(ns, r, fun, arg_count),
CodeArity(fun, arity), // arity is only for known callables
arg_count > arity.
// CHECKED
USED("CFA-13")
PointsTo(param, arg) :- // pass arguments to function parameters
ExecCall(ns, r, fun, arg_count),
CodeArity(fun, arity), // arity is only for known callables
arg_count > arity,
// call parameters
call_arg_i >= 0,
call_arg_i < arity,
ExecCallArgument(ns, r, fun, call_arg_i, arg),
CodeParameter(fun, call_arg_i, param).
// CHECKED
//////////////////////////////////
// strict, oversaturated PNode call: execute the first function call + create ApplyChain
USED("CFA-14")
ReachableCode(fun), // initiate call
ApplyChain(ns, r, fun, 0, missing, arg_count) :-
ExecCall(ns, r, pnode, arg_count),
PNode(pnode, fun, _, missing),
arg_count > missing,
0 <= missing.
// CHECKED
USED("CFA-15")
PointsTo(bound_param, pnode_arg) :- // pass PNode arguments for the initial function call
PNode(pnode, fun, arity, missing),
ExecCall(_, _, pnode, arg_count),
arg_count > missing,
0 <= missing,
// pnode parameters
pnode_i >= 0,
pnode_i < arity - missing,
PNodeArgument(pnode, fun, pnode_i, pnode_arg),
CodeParameter(fun, pnode_i, bound_param).
// CHECKED
USED("CFA-16")
PointsTo(param, arg) :- // pass call arguments to saturate the initial function call
PNode(pnode, fun, arity, missing),
ExecCall(ns, r, pnode, arg_count),
ExecCallArgument(ns, r, pnode, call_arg_i, arg),
arg_count > missing,
0 < missing, // consume call arguments only if the PNode is not already saturated
// call parameters
call_arg_i >= 0,
call_arg_i < missing,
CodeParameter(fun, call_arg_i + arity - missing, param).
// CHECKED
//////////////////////////////////
// SECTION: apply chain elaboration: apply remained call arguments to 'fun' result PNodes
// saturated apply chain link: execute function call + create result
USED("CFA-17")
ReachableCode(p_fun),
PointsTo(r, p_ret_var) :- // return value
ApplyChain(_, r, fun, _, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, _, p_missing),
consumed + p_missing = arg_count, // only saturated PNode calls
REACHABLE(r)
// return value
ReturnValue(p_fun, p_ret_var).
// CHECKED
USED("CFA-18")
PointsTo(bound_param, pnode_arg) :- // pass PNode arguments to function
ApplyChain(_, _, fun, _, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, p_arity, p_missing),
consumed + p_missing = arg_count, // only saturated PNode calls
// pass pnode arguments
bound_i >= 0,
bound_i < p_arity - p_missing,
REACHABLE(pnode)
CodeParameter(p_fun, bound_i, bound_param),
PNodeArgument(pnode, p_fun, bound_i, pnode_arg).
// CHECKED
USED("CFA-19")
PointsTo(param, arg) :- // pass PNode arguments to function to saturate the call
ApplyChain(ns, r, fun, _, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, p_arity, p_missing),
consumed + p_missing = arg_count, // only saturated PNode calls
// pass call arguments
call_arg_i >= consumed, // NOTE: call_arg_i has to be grounded so this is the simplest indexing solution
call_arg_i < consumed + p_missing,
ExecCallArgument(ns, r, _, call_arg_i, arg),
CodeParameter(p_fun, call_arg_i - consumed + p_arity - p_missing, param).
// CHECKED
//////////////////////////////////
// undersaturated apply chain link: create PNode as the result
USED("CFA-20")
PNode(r, p_fun, p_arity, p_missing - (arg_count - consumed)) :-
ApplyChain(_, r, fun, _, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, p_arity, p_missing),
p_missing > arg_count - consumed.
// CHECKED
USED("CFA-21")
PNodeArgument(r, p_fun, (p_arity - p_missing) + (call_arg_i - consumed), arg) :- // save call arguments
ApplyChain(ns, r, fun, _, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, p_arity, p_missing),
p_missing > arg_count - consumed,
// copy call arguments
call_arg_i >= consumed,
call_arg_i < arg_count,
ExecCallArgument(ns, r, _, call_arg_i, arg).
// CHECKED
USED("CFA-22")
PNodeArgument(r, p_fun, bound_i, pnode_arg) :- // copy PNode arguments
ApplyChain(_, r, fun, _, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, p_arity, p_missing),
p_missing > arg_count - consumed,
// copy old pnode arguments
bound_i >= 0,
bound_i < p_arity - p_missing,
PNodeArgument(pnode, p_fun, bound_i, pnode_arg).
// CHECKED
//////////////////////////////////
// oversaturated apply chain link: execute function + create the next ApplyChain link
USED("CFA-23")
ReachableCode(p_fun),
ApplyChain(ns, r, p_fun, step + 1, consumed + p_missing, arg_count) :-
ApplyChain(ns, r, fun, step, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, _, p_missing),
consumed + p_missing < arg_count.
// CHECKED
USED("CFA-24")
PointsTo(bound_param, pnode_arg) :- // pass PNode arguments to function
ApplyChain(_, r, fun, _, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, p_arity, p_missing),
consumed + p_missing < arg_count,
// pass pnode arguments
bound_i >= 0,
bound_i < p_arity - p_missing,
CodeParameter(p_fun, bound_i, bound_param),
REACHABLE(r)
PNodeArgument(pnode, p_fun, bound_i, pnode_arg).
// CHECKED
USED("CFA-25")
PointsTo(param, arg) :- // pass call arguments to saturate function call
ApplyChain(ns, r, fun, _, consumed, arg_count),
ReturnValue(fun, pnode),
PNode(pnode, p_fun, p_arity, p_missing),
consumed + p_missing < arg_count,
// pass call arguments
call_arg_i >= consumed, // NOTE: call_arg_i has to be grounded so this is the simplest indexing solution
call_arg_i < consumed + p_missing,
ExecCallArgument(ns, r, _, call_arg_i, arg),
CodeParameter(p_fun, call_arg_i - consumed + p_arity - p_missing, param).
// CHECKED
///////////////////////
// utility
///////////////////////
// NOTE: does not handle return value ; only pass parameters
.decl CallPNode1(namespace:symbol, inst:Variable, pnode:Variable, last_arg:Variable)
.output CallPNode1
USED("CFA-26-CallPNode1")
ExecCallArgument(ns, inst, pnode, 0, last_arg),
ExecCall(ns, inst, pnode, 1) :-
CallPNode1(ns, inst, pnode, last_arg).
// CHECKED
// NOTE: does not handle return value ; only pass parameters
.decl CallPNode2(namespace:symbol, inst:Variable, pnode:Variable, before_last_arg:Variable, last_arg:Variable)
.output CallPNode2
USED("CFA-27-CallPNode2")
ExecCallArgument(ns, inst, pnode, 0, before_last_arg),
ExecCallArgument(ns, inst, pnode, 1, last_arg),
ExecCall(ns, inst, pnode, 2) :-
CallPNode2(ns, inst, pnode, before_last_arg, last_arg).
// CHECKED