effects-analysis.scm 24 KB

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