effects-analysis.scm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622
  1. ;;; Effects analysis on CPS
  2. ;; Copyright (C) 2011-2015, 2017, 2018 Free Software Foundation, Inc.
  3. ;;;; This library is free software; you can redistribute it and/or
  4. ;;;; modify it under the terms of the GNU Lesser General Public
  5. ;;;; License as published by the Free Software Foundation; either
  6. ;;;; version 3 of the License, or (at your option) any later version.
  7. ;;;;
  8. ;;;; This library is distributed in the hope that it will be useful,
  9. ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. ;;;; Lesser General Public License for more details.
  12. ;;;;
  13. ;;;; You should have received a copy of the GNU Lesser General Public
  14. ;;;; License along with this library; if not, write to the Free Software
  15. ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  16. ;;; Commentary:
  17. ;;;
  18. ;;; A helper module to compute the set of effects caused by an
  19. ;;; expression. This information is useful when writing algorithms that
  20. ;;; move code around, while preserving the semantics of an input
  21. ;;; program.
  22. ;;;
  23. ;;; The effects set is represented as an integer with three parts. The
  24. ;;; low 4 bits indicate effects caused by an expression, as a bitfield.
  25. ;;; The next 4 bits indicate the kind of memory accessed by the
  26. ;;; expression, if it accesses mutable memory. Finally the rest of the
  27. ;;; bits indicate the field in the object being accessed, if known, or
  28. ;;; -1 for unknown.
  29. ;;;
  30. ;;; In this way we embed a coarse type-based alias analysis in the
  31. ;;; effects analysis. For example, a "car" call is modelled as causing
  32. ;;; a read to field 0 on a &pair, and causing a &type-check effect. If
  33. ;;; any intervening code sets the car of any pair, that will block
  34. ;;; motion of the "car" call, because any write to field 0 of a pair is
  35. ;;; seen by effects analysis as being a write to field 0 of all pairs.
  36. ;;;
  37. ;;; Code:
  38. (define-module (language cps effects-analysis)
  39. #:use-module (language cps)
  40. #:use-module (language cps utils)
  41. #:use-module (language cps intset)
  42. #:use-module (language cps intmap)
  43. #:use-module (ice-9 match)
  44. #:export (expression-effects
  45. compute-effects
  46. synthesize-definition-effects
  47. &allocation
  48. &type-check
  49. &read
  50. &write
  51. &fluid
  52. &prompt
  53. &vector
  54. &box
  55. &module
  56. &struct
  57. &string
  58. &thread
  59. &bytevector
  60. &closure
  61. &object
  62. &field
  63. &allocate
  64. &read-object
  65. &read-field
  66. &write-object
  67. &write-field
  68. &no-effects
  69. &all-effects
  70. causes-effect?
  71. causes-all-effects?
  72. effect-clobbers?
  73. compute-clobber-map))
  74. (define-syntax define-flags
  75. (lambda (x)
  76. (syntax-case x ()
  77. ((_ all shift name ...)
  78. (let ((count (length #'(name ...))))
  79. (with-syntax (((n ...) (iota count))
  80. (count count))
  81. #'(begin
  82. (define-syntax name (identifier-syntax (ash 1 n)))
  83. ...
  84. (define-syntax all (identifier-syntax (1- (ash 1 count))))
  85. (define-syntax shift (identifier-syntax count)))))))))
  86. (define-syntax define-enumeration
  87. (lambda (x)
  88. (define (count-bits n)
  89. (let lp ((out 1))
  90. (if (< n (ash 1 (1- out)))
  91. out
  92. (lp (1+ out)))))
  93. (syntax-case x ()
  94. ((_ mask shift name ...)
  95. (let* ((len (length #'(name ...)))
  96. (bits (count-bits len)))
  97. (with-syntax (((n ...) (iota len))
  98. (bits bits))
  99. #'(begin
  100. (define-syntax name (identifier-syntax n))
  101. ...
  102. (define-syntax mask (identifier-syntax (1- (ash 1 bits))))
  103. (define-syntax shift (identifier-syntax bits)))))))))
  104. (define-flags &all-effect-kinds &effect-kind-bits
  105. ;; Indicates that an expression may cause a type check. A type check,
  106. ;; for the purposes of this analysis, is the possibility of throwing
  107. ;; an exception the first time an expression is evaluated. If the
  108. ;; expression did not cause an exception to be thrown, users can
  109. ;; assume that evaluating the expression again will not cause an
  110. ;; exception to be thrown.
  111. ;;
  112. ;; For example, (+ x y) might throw if X or Y are not numbers. But if
  113. ;; it doesn't throw, it should be safe to elide a dominated, common
  114. ;; subexpression (+ x y).
  115. &type-check
  116. ;; Indicates that an expression may return a fresh object. The kind
  117. ;; of object is indicated in the object kind field.
  118. &allocation
  119. ;; Indicates that an expression may cause a read from memory. The
  120. ;; kind of memory is given in the object kind field. Some object
  121. ;; kinds have finer-grained fields; those are expressed in the "field"
  122. ;; part of the effects value. -1 indicates "the whole object".
  123. &read
  124. ;; Indicates that an expression may cause a write to memory.
  125. &write)
  126. (define-enumeration &memory-kind-mask &memory-kind-bits
  127. ;; Indicates than an expression may access unknown kinds of memory.
  128. &unknown-memory-kinds
  129. ;; Indicates that an expression depends on the value of a fluid
  130. ;; variable, or on the current fluid environment.
  131. &fluid
  132. ;; Indicates that an expression depends on the current prompt
  133. ;; stack.
  134. &prompt
  135. ;; Indicates that an expression depends on the value of the car or cdr
  136. ;; of a pair.
  137. &pair
  138. ;; Indicates that an expression depends on the value of a vector
  139. ;; field. The effect field indicates the specific field, or zero for
  140. ;; an unknown field.
  141. &vector
  142. ;; Indicates that an expression depends on the value of a variable
  143. ;; cell.
  144. &box
  145. ;; Indicates that an expression depends on the current module.
  146. &module
  147. ;; Indicates that an expression depends on the current thread.
  148. &thread
  149. ;; Indicates that an expression depends on the value of a struct
  150. ;; field. The effect field indicates the specific field, or zero for
  151. ;; an unknown field.
  152. &struct
  153. ;; Indicates that an expression depends on the contents of a string.
  154. &string
  155. ;; Indicates that an expression depends on the contents of a
  156. ;; bytevector. We cannot be more precise, as bytevectors may alias
  157. ;; other bytevectors.
  158. &bytevector
  159. ;; Indicates a dependency on a free variable of a closure.
  160. &closure
  161. ;; Indicates a dependency on a raw bitmask, measured in 32-bit units.
  162. &bitmask
  163. ;; Indicates a dependency on the value of a cache cell.
  164. &cache)
  165. (define-inlinable (&field kind field)
  166. (ash (logior (ash field &memory-kind-bits) kind) &effect-kind-bits))
  167. (define-inlinable (&object kind)
  168. (&field kind -1))
  169. (define-inlinable (&allocate kind)
  170. (logior &allocation (&object kind)))
  171. (define-inlinable (&read-field kind field)
  172. (logior &read (&field kind field)))
  173. (define-inlinable (&read-object kind)
  174. (logior &read (&object kind)))
  175. (define-inlinable (&write-field kind field)
  176. (logior &write (&field kind field)))
  177. (define-inlinable (&write-object kind)
  178. (logior &write (&object kind)))
  179. (define-syntax &no-effects (identifier-syntax 0))
  180. (define-syntax &all-effects
  181. (identifier-syntax
  182. (logior &all-effect-kinds (&object &unknown-memory-kinds))))
  183. (define-inlinable (causes-effect? x effects)
  184. (not (zero? (logand x effects))))
  185. (define-inlinable (causes-all-effects? x)
  186. (eqv? x &all-effects))
  187. (define (effect-clobbers? a b)
  188. "Return true if A clobbers B. This is the case if A is a write, and B
  189. is or might be a read or a write to the same location as A."
  190. (define (locations-same?)
  191. (let ((a (ash a (- &effect-kind-bits)))
  192. (b (ash b (- &effect-kind-bits))))
  193. (or (eqv? &unknown-memory-kinds (logand a &memory-kind-mask))
  194. (eqv? &unknown-memory-kinds (logand b &memory-kind-mask))
  195. (and (eqv? (logand a &memory-kind-mask) (logand b &memory-kind-mask))
  196. ;; A negative field indicates "the whole object".
  197. ;; Non-negative fields indicate only part of the object.
  198. (or (< a 0) (< b 0) (= a b))))))
  199. (and (not (zero? (logand a &write)))
  200. (not (zero? (logand b (logior &read &write))))
  201. (locations-same?)))
  202. (define (compute-clobber-map effects)
  203. "For the map LABEL->EFFECTS, compute a map LABEL->LABELS indicating
  204. the LABELS that are clobbered by the effects of LABEL."
  205. (let ((clobbered-by-write (make-hash-table)))
  206. (intmap-fold
  207. (lambda (label fx)
  208. ;; Unless an expression causes a read, it isn't clobbered by
  209. ;; anything.
  210. (when (causes-effect? fx &read)
  211. (let ((me (intset label)))
  212. (define (add! kind field)
  213. (let* ((k (logior (ash field &memory-kind-bits) kind))
  214. (clobber (hashv-ref clobbered-by-write k empty-intset)))
  215. (hashv-set! clobbered-by-write k (intset-union me clobber))))
  216. ;; Clobbered by write to specific field of this memory
  217. ;; kind, write to any field of this memory kind, or
  218. ;; write to any field of unknown memory kinds.
  219. (let* ((loc (ash fx (- &effect-kind-bits)))
  220. (kind (logand loc &memory-kind-mask))
  221. (field (ash loc (- &memory-kind-bits))))
  222. (add! kind field)
  223. (add! kind -1)
  224. (add! &unknown-memory-kinds -1))))
  225. (values))
  226. effects)
  227. (intmap-map (lambda (label fx)
  228. (if (causes-effect? fx &write)
  229. (hashv-ref clobbered-by-write
  230. (ash fx (- &effect-kind-bits))
  231. empty-intset)
  232. empty-intset))
  233. effects)))
  234. (define *primitive-effects* (make-hash-table))
  235. (define-syntax-rule (define-primitive-effects* param
  236. ((name . args) effects ...)
  237. ...)
  238. (begin
  239. (hashq-set! *primitive-effects* 'name
  240. (case-lambda*
  241. ((param . args) (logior effects ...))
  242. (_ &all-effects)))
  243. ...))
  244. (define-syntax-rule (define-primitive-effects ((name . args) effects ...) ...)
  245. (define-primitive-effects* param ((name . args) effects ...) ...))
  246. ;; Miscellaneous.
  247. (define-primitive-effects
  248. ((load-const/unlikely))
  249. ((values . _)))
  250. ;; Generic effect-free predicates.
  251. (define-primitive-effects
  252. ((eq? x y))
  253. ((equal? x y))
  254. ((fixnum? arg))
  255. ((char? arg))
  256. ((eq-null? arg))
  257. ((eq-nil? arg))
  258. ((eq-false? arg))
  259. ((eq-true? arg))
  260. ((unspecified? arg))
  261. ((undefined? arg))
  262. ((eof-object? arg))
  263. ((null? arg))
  264. ((false? arg))
  265. ((nil? arg))
  266. ((heap-object? arg))
  267. ((pair? arg))
  268. ((symbol? arg))
  269. ((variable? arg))
  270. ((vector? arg))
  271. ((struct? arg))
  272. ((string? arg))
  273. ((number? arg))
  274. ((bytevector? arg))
  275. ((keyword? arg))
  276. ((bitvector? arg))
  277. ((procedure? arg))
  278. ((thunk? arg))
  279. ((heap-number? arg))
  280. ((bignum? arg))
  281. ((flonum? arg))
  282. ((compnum? arg))
  283. ((fracnum? arg)))
  284. ;; Fluids.
  285. (define-primitive-effects
  286. ((fluid-ref f) (&read-object &fluid) &type-check)
  287. ((fluid-set! f v) (&write-object &fluid) &type-check)
  288. ((push-fluid f v) (&write-object &fluid) &type-check)
  289. ((pop-fluid) (&write-object &fluid))
  290. ((push-dynamic-state state) (&write-object &fluid) &type-check)
  291. ((pop-dynamic-state) (&write-object &fluid)))
  292. ;; Threads. Calls cause &all-effects, which reflects the fact that any
  293. ;; call can capture a partial continuation and reinstate it on another
  294. ;; thread.
  295. (define-primitive-effects
  296. ((current-thread) (&read-object &thread)))
  297. ;; Prompts.
  298. (define-primitive-effects
  299. ((make-prompt-tag #:optional arg) (&allocate &unknown-memory-kinds)))
  300. ;; Generic objects.
  301. (define (annotation->memory-kind annotation)
  302. (match annotation
  303. ('pair &pair)
  304. ('vector &vector)
  305. ('string &string)
  306. ('stringbuf &string)
  307. ('bytevector &bytevector)
  308. ('bitmask &bitmask)
  309. ('box &box)
  310. ('closure &closure)
  311. ('struct &struct)
  312. ('atomic-box &unknown-memory-kinds)))
  313. (define-primitive-effects* param
  314. ((allocate-words size) (&allocate (annotation->memory-kind param)))
  315. ((allocate-words/immediate) (match param
  316. ((ann . size)
  317. (&allocate
  318. (annotation->memory-kind ann)))))
  319. ((scm-ref obj idx) (&read-object
  320. (annotation->memory-kind param)))
  321. ((scm-ref/tag obj) (&read-field
  322. (annotation->memory-kind param) 0))
  323. ((scm-ref/immediate obj) (match param
  324. ((ann . idx)
  325. (&read-field
  326. (annotation->memory-kind ann) idx))))
  327. ((scm-set! obj idx val) (&write-object
  328. (annotation->memory-kind param)))
  329. ((scm-set/tag! obj val) (&write-field
  330. (annotation->memory-kind param) 0))
  331. ((scm-set!/immediate obj val) (match param
  332. ((ann . idx)
  333. (&write-field
  334. (annotation->memory-kind ann) idx))))
  335. ((word-ref obj idx) (&read-object
  336. (annotation->memory-kind param)))
  337. ((word-ref/immediate obj) (match param
  338. ((ann . idx)
  339. (&read-field
  340. (annotation->memory-kind ann) idx))))
  341. ((word-set! obj idx val) (&read-object
  342. (annotation->memory-kind param)))
  343. ((word-set!/immediate obj val) (match param
  344. ((ann . idx)
  345. (&write-field
  346. (annotation->memory-kind ann) idx))))
  347. ((pointer-ref/immediate obj) (match param
  348. ((ann . idx)
  349. (&read-field
  350. (annotation->memory-kind ann) idx))))
  351. ((pointer-set!/immediate obj val)
  352. (match param
  353. ((ann . idx)
  354. (&write-field
  355. (annotation->memory-kind ann) idx))))
  356. ((tail-pointer-ref/immediate obj)))
  357. ;; Strings.
  358. (define-primitive-effects
  359. ((string-set! s n c) (&write-object &string) &type-check)
  360. ((number->string _) (&allocate &string) &type-check)
  361. ((string->number _) (&read-object &string) &type-check))
  362. ;; Unboxed floats and integers.
  363. (define-primitive-effects
  364. ((scm->f64 _) &type-check)
  365. ((load-f64))
  366. ((f64->scm _))
  367. ((scm->u64 _) &type-check)
  368. ((scm->u64/truncate _) &type-check)
  369. ((load-u64))
  370. ((u64->scm _))
  371. ((u64->scm/unlikely _))
  372. ((scm->s64 _) &type-check)
  373. ((load-s64))
  374. ((s64->scm _))
  375. ((s64->scm/unlikely _))
  376. ((u64->s64 _))
  377. ((s64->u64 _))
  378. ((assume-u64 _))
  379. ((assume-s64 _))
  380. ((untag-fixnum _))
  381. ((tag-fixnum _))
  382. ((tag-fixnum/unlikely _)))
  383. ;; Pointers.
  384. (define-primitive-effects* param
  385. ((u8-ref obj bv n) (&read-object (annotation->memory-kind param)))
  386. ((s8-ref obj bv n) (&read-object (annotation->memory-kind param)))
  387. ((u16-ref obj bv n) (&read-object (annotation->memory-kind param)))
  388. ((s16-ref obj bv n) (&read-object (annotation->memory-kind param)))
  389. ((u32-ref obj bv n) (&read-object (annotation->memory-kind param)))
  390. ((s32-ref obj bv n) (&read-object (annotation->memory-kind param)))
  391. ((u64-ref obj bv n) (&read-object (annotation->memory-kind param)))
  392. ((s64-ref obj bv n) (&read-object (annotation->memory-kind param)))
  393. ((f32-ref obj bv n) (&read-object (annotation->memory-kind param)))
  394. ((f64-ref obj bv n) (&read-object (annotation->memory-kind param)))
  395. ((u8-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  396. ((s8-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  397. ((u16-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  398. ((s16-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  399. ((u32-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  400. ((s32-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  401. ((u64-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  402. ((s64-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  403. ((f32-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  404. ((f64-set! obj bv n x) (&write-object (annotation->memory-kind param))))
  405. ;; Modules.
  406. (define-primitive-effects
  407. ((current-module) (&read-object &module))
  408. ((cache-current-module! m) (&write-object &cache))
  409. ((resolve name) (&read-object &module) &type-check)
  410. ((resolve-module mod) (&read-object &module) &type-check)
  411. ((lookup mod name) (&read-object &module) &type-check)
  412. ((cached-toplevel-box) &type-check)
  413. ((cached-module-box) &type-check)
  414. ((define! mod name) (&read-object &module)))
  415. ;; Cache cells.
  416. (define-primitive-effects
  417. ((cache-ref) (&read-object &cache))
  418. ((cache-set! x) (&write-object &cache)))
  419. ;; Numbers.
  420. (define-primitive-effects
  421. ((heap-numbers-equal? . _))
  422. ((= . _) &type-check)
  423. ((<= . _) &type-check)
  424. ((< . _) &type-check)
  425. ((u64-= . _))
  426. ((u64-imm-= . _))
  427. ((u64-< . _))
  428. ((u64-imm-< . _))
  429. ((imm-u64-< . _))
  430. ((s64-= . _))
  431. ((s64-imm-= . _))
  432. ((s64-< . _))
  433. ((s64-imm-< . _))
  434. ((imm-s64-< . _))
  435. ((f64-= . _))
  436. ((f64-< . _))
  437. ((f64-<= . _))
  438. ((zero? . _) &type-check)
  439. ((add . _) &type-check)
  440. ((add/immediate . _) &type-check)
  441. ((mul . _) &type-check)
  442. ((sub . _) &type-check)
  443. ((sub/immediate . _) &type-check)
  444. ((div . _) &type-check)
  445. ((fadd . _))
  446. ((fsub . _))
  447. ((fmul . _))
  448. ((fdiv . _))
  449. ((uadd . _))
  450. ((usub . _))
  451. ((umul . _))
  452. ((uadd/immediate . _))
  453. ((usub/immediate . _))
  454. ((umul/immediate . _))
  455. ((sadd . _))
  456. ((ssub . _))
  457. ((smul . _))
  458. ((sadd/immediate . _))
  459. ((ssub/immediate . _))
  460. ((smul/immediate . _))
  461. ((quo . _) &type-check)
  462. ((rem . _) &type-check)
  463. ((mod . _) &type-check)
  464. ((complex? _) &type-check)
  465. ((real? _) &type-check)
  466. ((rational? _) &type-check)
  467. ((inf? _) &type-check)
  468. ((nan? _) &type-check)
  469. ((integer? _) &type-check)
  470. ((exact? _) &type-check)
  471. ((inexact? _) &type-check)
  472. ((even? _) &type-check)
  473. ((odd? _) &type-check)
  474. ((rsh n m) &type-check)
  475. ((lsh n m) &type-check)
  476. ((rsh/immediate n) &type-check)
  477. ((lsh/immediate n) &type-check)
  478. ((logand . _) &type-check)
  479. ((logior . _) &type-check)
  480. ((logxor . _) &type-check)
  481. ((logsub . _) &type-check)
  482. ((lognot . _) &type-check)
  483. ((ulogand . _))
  484. ((ulogior . _))
  485. ((ulogxor . _))
  486. ((ulogsub . _))
  487. ((ursh . _))
  488. ((srsh . _))
  489. ((ulsh . _))
  490. ((slsh . _))
  491. ((ursh/immediate . _))
  492. ((srsh/immediate . _))
  493. ((ulsh/immediate . _))
  494. ((slsh/immediate . _))
  495. ((logtest a b) &type-check)
  496. ((logbit? a b) &type-check)
  497. ((sqrt _) &type-check)
  498. ((abs _) &type-check))
  499. ;; Characters.
  500. (define-primitive-effects
  501. ((untag-char _))
  502. ((tag-char _)))
  503. ;; Atomics are a memory and a compiler barrier; they cause all effects
  504. ;; so no need to have a case for them here. (Though, see
  505. ;; https://jfbastien.github.io/no-sane-compiler/.)
  506. (define (primitive-effects param name args)
  507. (let ((proc (hashq-ref *primitive-effects* name)))
  508. (if proc
  509. (apply proc param args)
  510. &all-effects)))
  511. (define (expression-effects exp)
  512. (match exp
  513. ((or ($ $const) ($ $prim) ($ $values) ($ $code) ($ $const-fun))
  514. &no-effects)
  515. ((or ($ $fun) ($ $rec))
  516. (&allocate &unknown-memory-kinds))
  517. ((or ($ $call) ($ $callk))
  518. &all-effects)
  519. (($ $primcall name param args)
  520. (primitive-effects param name args))))
  521. (define (compute-effects conts)
  522. (intmap-map
  523. (lambda (label cont)
  524. (match cont
  525. (($ $kargs names syms ($ $continue k src exp))
  526. (expression-effects exp))
  527. (($ $kargs names syms ($ $branch kf kt src op param args))
  528. (primitive-effects param op args))
  529. (($ $kargs names syms ($ $prompt))
  530. ;; Although the "main" path just writes &prompt, we don't know
  531. ;; what nonlocal predecessors of the handler do, so we
  532. ;; conservatively assume &all-effects.
  533. &all-effects)
  534. (($ $kargs names syms ($ $throw))
  535. ;; A reachable "throw" term can never be elided.
  536. &all-effects)
  537. (($ $kreceive arity kargs)
  538. (match arity
  539. (($ $arity _ () #f () #f) &type-check)
  540. (($ $arity () () _ () #f) (&allocate &pair))
  541. (($ $arity _ () _ () #f) (logior (&allocate &pair) &type-check))))
  542. (($ $kfun) &type-check)
  543. (($ $kclause) &type-check)
  544. (($ $ktail) &no-effects)))
  545. conts))
  546. ;; There is a way to abuse effects analysis in CSE to also do scalar
  547. ;; replacement, effectively adding `car' and `cdr' expressions to `cons'
  548. ;; expressions, and likewise with other constructors and setters. This
  549. ;; routine adds appropriate effects to `cons' and `set-car!' and the
  550. ;; like.
  551. ;;
  552. ;; This doesn't affect CSE's ability to eliminate expressions, given
  553. ;; that allocations aren't eliminated anyway, and the new effects will
  554. ;; just cause the allocations not to commute with e.g. set-car! which
  555. ;; is what we want anyway.
  556. (define (synthesize-definition-effects effects)
  557. (intmap-map (lambda (label fx)
  558. (if (logtest (logior &write &allocation) fx)
  559. (logior fx &read)
  560. fx))
  561. effects))