-
Notifications
You must be signed in to change notification settings - Fork 1
/
xpiu.rkt
292 lines (289 loc) · 11.1 KB
/
xpiu.rkt
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
#lang racket
(require racket/mpair)
(require "xresfn.rkt"
"x-misc.rkt")
(define (upiu:prevent-infinite-unfolding! prog)
(define (find-loops-prog rf prog)
(define loops #f)
(define (find-loops-func fname)
(let ((%%1 (assq fname prog)))
(let ((body (car (cddddr %%1))))
(find-loops body fname '() (list fname) '()))))
(define (find-loops exp fn trace fn-path path)
(cond ((symbol? exp) #f)
((equal? (car exp) 'static)
(let ((exp1 (cadr exp))) #f))
((equal? (car exp) 'ifs)
(let ((exp* (cddr exp)) (exp0 (cadr exp)))
(find-loops* exp* 1 fn trace fn-path path)))
((equal? (car exp) 'ifd)
(let ((exp* (cdr exp)))
(find-loops* exp* 0 fn trace fn-path path)))
((equal? (car exp) 'call)
(let ((d-exp* (cadddr exp))
(s-exp* (caddr exp))
(fname (cadr exp)))
(find-loops* d-exp* 0 fn trace fn-path path)
(if (memq fname fn-path)
(record-loop fname fn trace path)
(visit-function fname fn trace fn-path path))))
((equal? (car exp) 'rcall)
(let ((d-exp* (cadddr exp))
(s-exp* (caddr exp))
(fname (cadr exp)))
(find-loops* d-exp* 0 fn trace fn-path path)))
((equal? (car exp) 'xcall)
(let ((exp* (cddr exp)) (fname (cadr exp)))
(find-loops* exp* 0 fn trace fn-path path)))
(else
(let ((exp* (cdr exp)) (op (car exp)))
(find-loops* exp* 0 fn trace fn-path path)))))
(define (find-loops* exp* num fn trace fn-path path)
(if (null? exp*)
#f
(let ((rest (cdr exp*)) (exp (car exp*)))
(find-loops
exp
fn
`(,num unquote trace)
fn-path
path)
(find-loops*
rest
(+ num 1)
fn
trace
fn-path
path))))
(define (record-loop fname fn trace path)
(let ((new-loop
`((,fn unquote (reverse trace))
unquote
(extract-loop
fname
`((,fn unquote trace) unquote path)
'()))))
(when (not (member new-loop loops))
(begin (set! loops `(,new-loop unquote loops))))))
(define (extract-loop fname path loop)
(let ((path-rest (cdr path))
(trace1 (cdar path))
(fname1 (caar path)))
(let ((%%2 `((,fname1 unquote (reverse trace1)) unquote loop)))
(let ((loop %%2))
(if (eq? fname fname1)
loop
(extract-loop fname path-rest loop))))))
(define (visit-function fname fn trace fn-path path)
(let ((%%3 (assq fname prog)))
(let ((body (car (cddddr %%3))))
(find-loops
body
fname
'()
`(,fname unquote fn-path)
`((,fn unquote trace) unquote path)))))
(set! loops '())
(for-each
(lambda (fname) (find-loops-func fname))
rf)
loops)
(define (collect-dangerous-calls loops prog)
(define dangerous-calls #f)
(define (collect-in-fundef loop)
(let ((path (cdr loop)) (back-call (car loop)))
(cond ((member back-call dangerous-calls) #f)
((dangerous-path? path)
(set! dangerous-calls
`(,back-call unquote dangerous-calls)))
(else #f))))
(define (dangerous-path? path)
(let ((path-rest (cdr path))
(trace (cdar path))
(fname (caar path)))
(let ((%%4 (assq fname prog)))
(let ((body (car (cddddr %%4)))
(dvn (caddr %%4))
(svn (cadr %%4)))
(let ((%%5 (go-through-path
body
trace
path-rest
svn
(make-le svn))))
(let ((new-svv %%5))
(or (not (all-non-increasing? svn new-svv))
(not (some-decreasing? new-svv)))))))))
(define (go-through-path exp trace path vn vv)
(cond ((symbol? exp)
(error "No way in the expression" exp))
((equal? (car exp) 'static)
(error "No way in the expression" exp))
((equal? (car exp) 'call)
(let ((d-exp* (cadddr exp))
(s-exp* (caddr exp))
(fname (cadr exp)))
(if (null? trace)
(go-through-call
fname
(decr-eval* s-exp* vn vv)
path)
(let ((trace-rest (cdr trace)) (num (car trace)))
(go-through-path
(list-ref d-exp* num)
trace-rest
path
vn
vv)))))
((equal? (car exp) 'rcall)
(let ((d-exp* (cadddr exp))
(s-exp* (caddr exp))
(fname (cadr exp)))
(let ((trace-rest (cdr trace)) (num (car trace)))
(go-through-path
(list-ref d-exp* num)
trace-rest
path
vn
vv))))
((equal? (car exp) 'xcall)
(let ((exp* (cddr exp)) (fname (cadr exp)))
(let ((trace-rest (cdr trace)) (num (car trace)))
(go-through-path
(list-ref exp* num)
trace-rest
path
vn
vv))))
(else
(let ((exp* (cdr exp)) (op (car exp)))
(let ((trace-rest (cdr trace)) (num (car trace)))
(go-through-path
(list-ref exp* num)
trace-rest
path
vn
vv))))))
(define (go-through-call fname svv path)
(if (null? path)
svv
(let ((path-rest (cdr path)) (path-head (car path)))
(let ((%%6 (assq fname prog)))
(let ((trace (cdr path-head))
(body (car (cddddr %%6)))
(dvn (caddr %%6))
(svn (cadr %%6)))
(go-through-path body trace path-rest svn svv))))))
(define (decr-eval exp vn vv)
(cond ((symbol? exp) (lookup-variable exp vn vv))
((equal? (car exp) 'quote) 'any)
((let ((exp* (cdr exp)) (op (car exp)))
(memq op '(car cdr)))
(let ((exp* (cdr exp)) (op (car exp)))
(decr-eval-sel (decr-eval (car exp*) vn vv))))
(else 'any)))
(define (decr-eval* exp* vn vv)
(map (lambda (exp) (decr-eval exp vn vv)) exp*))
(define (decr-eval-sel a-value)
(cond ((equal? a-value 'any) 'any)
((equal? (car a-value) 'lt)
(let ((vname (cdr a-value))) a-value))
((equal? (car a-value) 'le)
(let ((vname (cdr a-value))) `(lt unquote vname)))
(else (error "SELECT: no match for" a-value))))
(define (make-le vn)
(map (lambda (vname) `(le unquote vname)) vn))
(define (all-non-increasing? vn vv)
(if (and (null? vn) (null? vv))
#t
(let ((vv-rest (cdr vv))
(vvalue (car vv))
(vn-rest (cdr vn))
(vname (car vn)))
(cond ((equal? vvalue 'any) #f)
((equal? (car vvalue) 'lt)
(let ((vname1 (cdr vvalue)))
(and (eq? vname vname1)
(all-non-increasing? vn-rest vv-rest))))
((equal? (car vvalue) 'le)
(let ((vname1 (cdr vvalue)))
(and (eq? vname vname1)
(all-non-increasing? vn-rest vv-rest))))
(else (error "SELECT: no match for" vvalue))))))
(define (some-decreasing? vv)
(or-map
(lambda (vvalue)
(cond ((equal? (car vvalue) 'lt) #t)
((equal? (car vvalue) 'le) #f)
(else (error "SELECT: no match for" vvalue))))
vv))
(define (lookup-variable vname vn vv)
(if (and (null? vn) (null? vv))
(error "Undefined variable: " vname)
(let ((vrest (cdr vv))
(vv (car vv))
(nrest (cdr vn))
(vn (car vn)))
(if (eq? vname vn)
vv
(lookup-variable vname nrest vrest)))))
(set! dangerous-calls '())
(for-each collect-in-fundef loops)
dangerous-calls)
(define (mark-dangerous-calls! prog dangerous-calls)
(define (mark-dc-fundef! fname trace prog)
(let ((%%7 (massq fname prog)))
(let ((body (mcar (mcddddr %%7))))
(mark-dc! body trace))))
(define (mark-dc! exp trace)
(cond ((symbol? exp)
(error "No way in the expression: " exp))
((equal? (mcar exp) 'static)
(let ((exp1 (mcadr exp)))
(error "No way in the expression: " exp)))
((let ((&call (mcar exp)))
(memq &call '(call rcall)))
(let ((&call (mcar exp)))
(let ((d-exp* (mcadddr exp))
(s-exp* (mcaddr exp))
(fname (mcadr exp)))
(if (null? trace)
(set-mcar! exp 'rcall)
(let ((trace-rest (cdr trace)) (num (car trace)))
(mark-dc! (mlist-ref d-exp* num) trace-rest))))))
((equal? (mcar exp) 'xcall)
(let ((exp* (mcddr exp)) (fname (mcadr exp)))
(let ((trace-rest (cdr trace)) (num (car trace)))
(mark-dc! (list-ref exp* num) trace-rest))))
(else
(let ((exp* (mcdr exp)) (op (mcar exp)))
(let ((trace-rest (cdr trace)) (num (car trace)))
(mark-dc! (mlist-ref exp* num) trace-rest))))))
(for-each
(lambda (back-call)
(let ((trace (cdr back-call)) (fname (car back-call)))
(mark-dc-fundef! fname trace prog)))
dangerous-calls))
(display "Preventing Infinite Unfolding")
(newline)
(let ((s-fundef* (caddr prog))
(d-fundef* (cadr prog))
(d-fundef** (pairs->mpairs (cadr prog))) ; converting to mutable
(rf (car prog)))
(display "Finding Loops")
(newline)
(let* ((loops (find-loops-prog rf d-fundef*))
(dangerous-calls
(collect-dangerous-calls loops d-fundef*)))
(display "Dangerous calls:")
(newline)
(write dangerous-calls)
(newline)
(display "Cutting Dangerous Loops")
(newline)
(mark-dangerous-calls! d-fundef** dangerous-calls)
(let* ((rf (uresfn:collect-residual-functions d-fundef*)))
(display "-- Done --")
(newline)
`(,rf ,d-fundef** ,s-fundef*)))))
(provide (all-defined-out))