1 ;;; Functional name maps
2 ;;; Copyright (C) 2014 Free Software Foundation, Inc.
4 ;;; This library is free software: you can redistribute it and/or modify
5 ;;; it under the terms of the GNU Lesser General Public License as
6 ;;; published by the Free Software Foundation, either version 3 of the
7 ;;; License, or (at your option) any later version.
9 ;;; This library is distributed in the hope that it will be useful, but
10 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ;;; Lesser General Public License for more details.
14 ;;; You should have received a copy of the GNU Lesser General Public
15 ;;; License along with this program. If not, see
16 ;;; <http://www.gnu.org/licenses/>.
20 ;;; Some CPS passes need to perform a flow analysis in which every
21 ;;; program point has an associated map over some set of labels or
22 ;;; variables. The naive way to implement this is with an array of
23 ;;; arrays, but this has N^2 complexity, and it really can hurt us.
25 ;;; Instead, this module provides a functional map that can share space
26 ;;; between program points, reducing the amortized space complexity of
27 ;;; the representations down to O(n log n). Adding entries to the
28 ;;; mapping and lookup are O(log n). Intersection and union between
29 ;;; intmaps that share state are fast, too.
33 (define-module (language cps intmap)
34 #:use-module (srfi srfi-9)
35 #:use-module (ice-9 match)
36 #:export (empty-intmap
45 ;; Persistent sparse intmaps.
47 (define-syntax-rule (define-inline name val)
48 (define-syntax name (identifier-syntax val)))
50 (define-inline *branch-bits* 4)
51 (define-inline *branch-size* (ash 1 *branch-bits*))
52 (define-inline *branch-mask* (1- *branch-size*))
54 (define-record-type <intmap>
55 (make-intmap min shift root)
62 (make-vector *branch-size* #f))
63 (define (clone-branch-and-set branch i elt)
64 (let ((new (new-branch)))
65 (when branch (vector-move-left! branch 0 *branch-size* new 0))
66 (vector-set! new i elt)
68 (define (branch-empty? branch)
70 (or (= i *branch-size*)
71 (and (not (vector-ref branch i))
74 (define (round-down min shift)
75 (logand min (lognot (1- (ash 1 shift)))))
77 (define empty-intmap (make-intmap 0 0 #f))
79 (define (add-level min shift root)
80 (let* ((shift* (+ shift *branch-bits*))
81 (min* (round-down min shift*))
82 (idx (logand (ash (- min min*) (- shift))
84 (make-intmap min* shift* (clone-branch-and-set #f idx root))))
86 (define (make-intmap/prune min shift root)
88 (make-intmap min shift root)
89 (let lp ((i 0) (elt #f))
92 (if (vector-ref root i)
94 (make-intmap min shift root)
98 (let ((shift (- shift *branch-bits*)))
99 (make-intmap/prune (+ min (ash elt shift))
101 (vector-ref root elt))))
102 ;; Shouldn't be reached...
103 (else empty-intmap)))))
105 (define (intmap-add bs i val meet)
106 (define (adjoin i shift root)
110 ((eq? root val) root)
112 (else (meet root val))))
114 (let* ((shift (- shift *branch-bits*))
115 (idx (logand (ash i (- shift)) *branch-mask*))
116 (node (and root (vector-ref root idx)))
117 (new-node (adjoin i shift node)))
118 (if (eq? node new-node)
120 (clone-branch-and-set root idx new-node))))))
122 (($ <intmap> min shift root)
125 ;; The power-of-two spanning trick doesn't work across 0.
126 (error "Intmaps can only map non-negative integers." i))
127 ((not val) (intmap-remove bs i))
129 ;; Add first element.
130 (make-intmap i 0 val))
131 ((and (<= min i) (< i (+ min (ash 1 shift))))
132 ;; Add element to map; level will not change.
133 (let ((old-root root)
134 (root (adjoin (- i min) shift root)))
135 (if (eq? root old-root)
137 (make-intmap min shift root))))
139 ;; Rebuild the tree by unioning two intmaps.
140 (intmap-union (intmap-add empty-intmap i val error) bs error))
142 ;; Add a new level and try again.
143 (intmap-add (add-level min shift root) i val error))))))
145 (define (intmap-remove bs i)
146 (define (remove i shift root)
150 (let* ((shift (- shift *branch-bits*))
151 (idx (logand (ash i (- shift)) *branch-mask*)))
153 ((vector-ref root idx)
155 (let ((new-node (remove i shift node)))
156 (if (eq? node new-node)
158 (let ((root (clone-branch-and-set root idx new-node)))
159 (and (or new-node (not (branch-empty? root)))
163 (($ <intmap> min shift root)
166 ((and (<= min i) (< i (+ min (ash 1 shift))))
167 ;; Add element to map; level will not change.
168 (let ((old-root root)
169 (root (remove (- i min) shift root)))
170 (if (eq? root old-root)
172 (make-intmap/prune min shift root))))
175 (define (intmap-ref bs i)
177 (($ <intmap> min shift root)
178 (and (<= min i) (< i (+ min (ash 1 shift)))
180 (let lp ((node root) (shift shift))
182 (if (= shift *branch-bits*)
183 (vector-ref node (logand i *branch-mask*))
184 (let* ((shift (- shift *branch-bits*))
185 (idx (logand (ash i (- shift))
187 (lp (vector-ref node idx) shift))))))))))
189 (define (intmap-next bs i)
190 (define (visit-branch node shift i)
191 (let lp ((i i) (idx (logand (ash i (- shift)) *branch-mask*)))
192 (and (< idx *branch-size*)
193 (or (visit-node (vector-ref node idx) shift i)
194 (let ((inc (ash 1 shift)))
195 (lp (+ (round-down i shift) inc) (1+ idx)))))))
196 (define (visit-node node shift i)
200 (visit-branch node (- shift *branch-bits*) i))))
202 (($ <intmap> min shift root)
203 (let ((i (if (and i (< min i))
206 (and (< i (ash 1 shift))
207 (let ((i (visit-node root shift i)))
208 (and i (+ min i))))))))
210 (define (intmap-union a b meet)
211 ;; Union A and B from index I; the result will be fresh.
212 (define (union-branches/fresh shift a b i fresh)
216 (let* ((a-child (vector-ref a i))
217 (b-child (vector-ref b i)))
218 (vector-set! fresh i (union shift a-child b-child))
221 ;; Union A and B from index I; the result may be eq? to A.
222 (define (union-branches/a shift a b i)
226 (let* ((a-child (vector-ref a i))
227 (b-child (vector-ref b i)))
228 (if (eq? a-child b-child)
230 (let ((child (union shift a-child b-child)))
235 (let ((result (clone-branch-and-set a i child)))
236 (union-branches/fresh shift a b (1+ i) result))))))))
238 ;; Union A and B; the may could be eq? to either.
239 (define (union-branches shift a b)
243 (let* ((a-child (vector-ref a i))
244 (b-child (vector-ref b i)))
245 (if (eq? a-child b-child)
247 (let ((child (union shift a-child b-child)))
250 (union-branches/a shift a b (1+ i)))
252 (union-branches/a shift b a (1+ i)))
254 (let ((result (clone-branch-and-set a i child)))
255 (union-branches/fresh shift a b (1+ i) result))))))))
256 ;; Seems they are the same but not eq?. Odd.
258 (define (union shift a-node b-node)
260 ((not a-node) b-node)
261 ((not b-node) a-node)
262 ((eq? a-node b-node) a-node)
263 ((zero? shift) (meet a-node b-node))
264 (else (union-branches (- shift *branch-bits*) a-node b-node))))
266 ((($ <intmap> a-min a-shift a-root) . ($ <intmap> b-min b-shift b-root))
268 ((not (= b-shift a-shift))
269 ;; Hoist the map with the lowest shift to meet the one with the
271 (if (< b-shift a-shift)
272 (intmap-union a (add-level b-min b-shift b-root) meet)
273 (intmap-union (add-level a-min a-shift a-root) b meet)))
274 ((not (= b-min a-min))
275 ;; Nodes at the same shift but different minimums will cover
276 ;; disjoint ranges (due to the round-down call on min). Hoist
277 ;; both until they cover the same range.
278 (intmap-union (add-level a-min a-shift a-root)
279 (add-level b-min b-shift b-root)
282 ;; At this point, A and B cover the same range.
283 (let ((root (union a-shift a-root b-root)))
285 ((eq? root a-root) a)
286 ((eq? root b-root) b)
287 (else (make-intmap a-min a-shift root)))))))))
289 (define (intmap-intersect a b meet)
290 ;; Intersect A and B from index I; the result will be fresh.
291 (define (intersect-branches/fresh shift a b i fresh)
295 (let* ((a-child (vector-ref a i))
296 (b-child (vector-ref b i)))
297 (vector-set! fresh i (intersect shift a-child b-child))
299 ((branch-empty? fresh) #f)
301 ;; Intersect A and B from index I; the result may be eq? to A.
302 (define (intersect-branches/a shift a b i)
306 (let* ((a-child (vector-ref a i))
307 (b-child (vector-ref b i)))
308 (if (eq? a-child b-child)
310 (let ((child (intersect shift a-child b-child)))
315 (let ((result (clone-branch-and-set a i child)))
316 (intersect-branches/fresh shift a b (1+ i) result))))))))
318 ;; Intersect A and B; the may could be eq? to either.
319 (define (intersect-branches shift a b)
323 (let* ((a-child (vector-ref a i))
324 (b-child (vector-ref b i)))
325 (if (eq? a-child b-child)
327 (let ((child (intersect shift a-child b-child)))
330 (intersect-branches/a shift a b (1+ i)))
332 (intersect-branches/a shift b a (1+ i)))
334 (let ((result (clone-branch-and-set a i child)))
335 (intersect-branches/fresh shift a b (1+ i) result))))))))
336 ;; Seems they are the same but not eq?. Odd.
338 (define (intersect shift a-node b-node)
340 ((or (not a-node) (not b-node)) #f)
341 ((eq? a-node b-node) a-node)
342 ((zero? shift) (meet a-node b-node))
343 (else (intersect-branches (- shift *branch-bits*) a-node b-node))))
345 (define (different-mins lo-min lo-shift lo-root hi-min hi-shift hi lo-is-a?)
347 ((<= lo-shift hi-shift)
348 ;; If LO has a lower shift and a lower min, it is disjoint. If
349 ;; it has the same shift and a different min, it is also
353 (let* ((lo-shift (- lo-shift *branch-bits*))
354 (lo-idx (ash (- hi-min lo-min) (- lo-shift))))
356 ((>= lo-idx *branch-size*)
357 ;; HI has a lower shift, but it not within LO.
359 ((vector-ref lo-root lo-idx)
361 (let ((lo (make-intmap (+ lo-min (ash lo-idx lo-shift))
365 (intmap-intersect lo hi meet)
366 (intmap-intersect hi lo meet)))))
367 (else empty-intmap))))))
369 (define (different-shifts-same-min min hi-shift hi-root lo lo-is-a?)
371 ((vector-ref hi-root 0)
373 (let ((hi (make-intmap min
374 (- hi-shift *branch-bits*)
377 (intmap-intersect lo hi meet)
378 (intmap-intersect hi lo meet)))))
379 (else empty-intmap)))
382 ((($ <intmap> a-min a-shift a-root) . ($ <intmap> b-min b-shift b-root))
385 (different-mins a-min a-shift a-root b-min b-shift b #t))
387 (different-mins b-min b-shift b-root a-min a-shift a #f))
389 (different-shifts-same-min b-min b-shift b-root a #t))
391 (different-shifts-same-min a-min a-shift a-root b #f))
393 ;; At this point, A and B cover the same range.
394 (let ((root (intersect a-shift a-root b-root)))
396 ((eq? root a-root) a)
397 ((eq? root b-root) b)
398 (else (make-intmap/prune a-min a-shift root)))))))))