effects-analysis.scm 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738
  1. ;;; Effects analysis on CPS
  2. ;; Copyright (C) 2011-2015,2017-2021 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. (logtest 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 (logtest a &write)
  205. (logtest b (logior &read &write))
  206. (locations-same?)))
  207. (define (compute-known-allocations conts effects)
  208. "Return a map of ACCESS-LABEL to ALLOC-LABEL, indicating stores to and
  209. loads from objects created at known allocation sites."
  210. ;; VAR -> ALLOC map of defining allocations, where ALLOC is a label or
  211. ;; #f. Possibly sparse.
  212. (define allocations
  213. (intmap-fold
  214. (lambda (label fx out)
  215. (match (intmap-ref conts label)
  216. (($ $kargs _ _ ($ $continue k))
  217. (match (intmap-ref conts k)
  218. (($ $kargs (_) (var))
  219. (intmap-add out var
  220. (and (not (causes-all-effects? fx))
  221. (logtest fx &allocation)
  222. label)
  223. (lambda (old new) #f)))
  224. (_ out)))
  225. (_ out)))
  226. effects empty-intmap))
  227. (persistent-intmap
  228. (intmap-fold
  229. (lambda (label fx out)
  230. (cond
  231. ((causes-all-effects? fx) out)
  232. ((logtest fx (logior &read &write))
  233. (match (intmap-ref conts label)
  234. ;; Assume that instructions which cause a known set of effects
  235. ;; and which
  236. (($ $kargs names vars
  237. ($ $continue k src
  238. ($ $primcall name param (obj . args))))
  239. (match (intmap-ref allocations obj (lambda (_) #f))
  240. (#f out)
  241. (allocation-label
  242. (intmap-add! out label allocation-label))))
  243. (_ out)))
  244. (else out)))
  245. effects empty-intmap)))
  246. (define (compute-clobber-map conts effects)
  247. "For the map LABEL->EFFECTS, compute a map LABEL->LABELS indicating
  248. the LABELS that are clobbered by the effects of LABEL."
  249. (define known-allocations (compute-known-allocations conts effects))
  250. (define (filter-may-alias write-label clobbered-labels)
  251. ;; We may be able to remove some entries from CLOBBERED-LABELS, if
  252. ;; we can prove they are not aliased by WRITE-LABEL.
  253. (match (intmap-ref known-allocations write-label (lambda (_) #f))
  254. (#f
  255. ;; We don't know what object WRITE-LABEL refers to; can't refine.
  256. clobbered-labels)
  257. (clobber-alloc
  258. (intset-fold
  259. (lambda (clobbered-label clobbered-labels)
  260. (match (intmap-ref known-allocations clobbered-label (lambda (_) #f))
  261. (#f
  262. ;; We don't know what object CLOBBERED-LABEL refers to;
  263. ;; can't refine.
  264. clobbered-labels)
  265. (clobbered-alloc
  266. ;; We know that WRITE-LABEL and CLOBBERED-LABEL refer to
  267. ;; known allocations. The write will only clobber the read
  268. ;; if the two allocations are the same.
  269. (if (eqv? clobber-alloc clobbered-alloc)
  270. clobbered-labels
  271. (intset-remove clobbered-labels clobbered-label)))))
  272. clobbered-labels clobbered-labels))))
  273. (let ((clobbered-by-write (make-hash-table)))
  274. (intmap-fold
  275. (lambda (label fx)
  276. ;; Unless an expression causes a read, it isn't clobbered by
  277. ;; anything.
  278. (when (causes-effect? fx &read)
  279. (let ((me (intset label)))
  280. (define (add! kind field)
  281. (let* ((k (logior (ash field &memory-kind-bits) kind))
  282. (clobber (hashv-ref clobbered-by-write k empty-intset)))
  283. (hashv-set! clobbered-by-write k (intset-union me clobber))))
  284. ;; Clobbered by write to specific field of this memory
  285. ;; kind, write to any field of this memory kind, or
  286. ;; write to any field of unknown memory kinds.
  287. (let* ((loc (ash fx (- &effect-kind-bits)))
  288. (kind (logand loc &memory-kind-mask))
  289. (field (ash loc (- &memory-kind-bits))))
  290. (add! kind field)
  291. (add! kind -1)
  292. (add! &unknown-memory-kinds -1))))
  293. (values))
  294. effects)
  295. (intmap-map (lambda (label fx)
  296. (if (causes-effect? fx &write)
  297. (filter-may-alias
  298. label
  299. (hashv-ref clobbered-by-write
  300. (ash fx (- &effect-kind-bits))
  301. empty-intset))
  302. empty-intset))
  303. effects)))
  304. (define *primitive-effects* (make-hash-table))
  305. (define-syntax-rule (define-primitive-effects* param
  306. ((name . args) effects ...)
  307. ...)
  308. (begin
  309. (hashq-set! *primitive-effects* 'name
  310. (case-lambda*
  311. ((param . args) (logior effects ...))
  312. (_ &all-effects)))
  313. ...))
  314. (define-syntax-rule (define-primitive-effects ((name . args) effects ...) ...)
  315. (define-primitive-effects* param ((name . args) effects ...) ...))
  316. ;; Miscellaneous.
  317. (define-primitive-effects
  318. ((load-const/unlikely))
  319. ((values . _)))
  320. ;; Generic effect-free predicates.
  321. (define-primitive-effects
  322. ((eq? x y))
  323. ((equal? x y))
  324. ((fixnum? arg))
  325. ((char? arg))
  326. ((eq-constant? arg))
  327. ((undefined? arg))
  328. ((null? arg))
  329. ((false? arg))
  330. ((nil? arg))
  331. ((heap-object? arg))
  332. ((pair? arg))
  333. ((symbol? arg))
  334. ((variable? arg))
  335. ((vector? arg))
  336. ((struct? arg))
  337. ((string? arg))
  338. ((number? arg))
  339. ((bytevector? arg))
  340. ((keyword? arg))
  341. ((bitvector? arg))
  342. ((procedure? arg))
  343. ((thunk? arg))
  344. ((heap-number? arg))
  345. ((bignum? arg))
  346. ((flonum? arg))
  347. ((compnum? arg))
  348. ((fracnum? arg)))
  349. ;; Fluids.
  350. (define-primitive-effects
  351. ((fluid-ref f) (&read-object &fluid) &type-check)
  352. ((fluid-set! f v) (&write-object &fluid) &type-check)
  353. ((push-fluid f v) (&write-object &fluid) &type-check)
  354. ((pop-fluid) (&write-object &fluid))
  355. ((push-dynamic-state state) (&write-object &fluid) &type-check)
  356. ((pop-dynamic-state) (&write-object &fluid)))
  357. ;; Threads. Calls cause &all-effects, which reflects the fact that any
  358. ;; call can capture a partial continuation and reinstate it on another
  359. ;; thread.
  360. (define-primitive-effects
  361. ((current-thread) (&read-object &thread)))
  362. ;; Prompts.
  363. (define-primitive-effects
  364. ((make-prompt-tag #:optional arg) (&allocate &unknown-memory-kinds)))
  365. ;; Generic objects.
  366. (define (annotation->memory-kind* annotation idx)
  367. (match (cons annotation idx)
  368. (('vector . 0) &header)
  369. (('string . (or 0 1 2 3)) &header)
  370. (('stringbuf . (or 0 1)) &header)
  371. (('bytevector . (or 0 1 2 3)) &header)
  372. (('symbol . (or 0 1 2)) &header)
  373. (('box . 0) &header)
  374. (('closure . (or 0 1)) &header)
  375. (('struct . 0) &header)
  376. (('atomic-box . 0) &header)
  377. (_ (annotation->memory-kind annotation))))
  378. (define (annotation->memory-kind annotation)
  379. (match annotation
  380. ('pair &pair)
  381. ('vector &vector)
  382. ('string &string)
  383. ('stringbuf &string)
  384. ('symbol &unknown-memory-kinds)
  385. ('bytevector &bytevector)
  386. ('bitmask &bitmask)
  387. ('box &box)
  388. ('closure &closure)
  389. ('struct &struct)
  390. ('atomic-box &unknown-memory-kinds)))
  391. (define-primitive-effects* param
  392. ((allocate-words size) (&allocate (annotation->memory-kind param)))
  393. ((allocate-words/immediate) (match param
  394. ((ann . size)
  395. (&allocate
  396. (annotation->memory-kind ann)))))
  397. ((allocate-pointerless-words size)
  398. (&allocate (annotation->memory-kind param)))
  399. ((allocate-pointerless-words/immediate)
  400. (match param
  401. ((ann . size)
  402. (&allocate
  403. (annotation->memory-kind ann)))))
  404. ((scm-ref obj idx) (&read-object
  405. (annotation->memory-kind param)))
  406. ((scm-ref/tag obj) (&read-field
  407. (annotation->memory-kind* param 0) 0))
  408. ((scm-ref/immediate obj) (match param
  409. ((ann . idx)
  410. (&read-field
  411. (annotation->memory-kind* ann idx) idx))))
  412. ((scm-set! obj idx val) (&write-object
  413. (annotation->memory-kind param)))
  414. ((scm-set/tag! obj val) (&write-field
  415. (annotation->memory-kind* param 0) 0))
  416. ((scm-set!/immediate obj val) (match param
  417. ((ann . idx)
  418. (&write-field
  419. (annotation->memory-kind* ann idx) idx))))
  420. ((word-ref obj idx) (&read-object
  421. (annotation->memory-kind param)))
  422. ((word-ref/immediate obj) (match param
  423. ((ann . idx)
  424. (&read-field
  425. (annotation->memory-kind* ann idx) idx))))
  426. ((word-set! obj idx val) (&read-object
  427. (annotation->memory-kind param)))
  428. ((word-set!/immediate obj val) (match param
  429. ((ann . idx)
  430. (&write-field
  431. (annotation->memory-kind* ann idx) idx))))
  432. ((pointer-ref/immediate obj) (match param
  433. ((ann . idx)
  434. (&read-field
  435. (annotation->memory-kind* ann idx) idx))))
  436. ((pointer-set!/immediate obj val)
  437. (match param
  438. ((ann . idx)
  439. (&write-field
  440. (annotation->memory-kind* ann idx) idx))))
  441. ((tail-pointer-ref/immediate obj)))
  442. ;; Strings.
  443. (define-primitive-effects
  444. ((string-set! s n c) (&write-object &string) &type-check)
  445. ((number->string _) (&allocate &string) &type-check)
  446. ((string->number _) (&read-object &string) &type-check))
  447. ;; Unboxed floats and integers.
  448. (define-primitive-effects
  449. ((scm->f64 _) &type-check)
  450. ((load-f64))
  451. ((f64->scm _))
  452. ((scm->u64 _) &type-check)
  453. ((scm->u64/truncate _) &type-check)
  454. ((load-u64))
  455. ((u64->scm _))
  456. ((u64->scm/unlikely _))
  457. ((scm->s64 _) &type-check)
  458. ((load-s64))
  459. ((s64->scm _))
  460. ((s64->scm/unlikely _))
  461. ((u64->s64 _))
  462. ((s64->u64 _))
  463. ((assume-u64 _))
  464. ((assume-s64 _))
  465. ((untag-fixnum _))
  466. ((tag-fixnum _))
  467. ((tag-fixnum/unlikely _)))
  468. ;; Pointers.
  469. (define-primitive-effects* param
  470. ((u8-ref obj bv n) (&read-object (annotation->memory-kind param)))
  471. ((s8-ref obj bv n) (&read-object (annotation->memory-kind param)))
  472. ((u16-ref obj bv n) (&read-object (annotation->memory-kind param)))
  473. ((s16-ref obj bv n) (&read-object (annotation->memory-kind param)))
  474. ((u32-ref obj bv n) (&read-object (annotation->memory-kind param)))
  475. ((s32-ref obj bv n) (&read-object (annotation->memory-kind param)))
  476. ((u64-ref obj bv n) (&read-object (annotation->memory-kind param)))
  477. ((s64-ref obj bv n) (&read-object (annotation->memory-kind param)))
  478. ((f32-ref obj bv n) (&read-object (annotation->memory-kind param)))
  479. ((f64-ref obj bv n) (&read-object (annotation->memory-kind param)))
  480. ((u8-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  481. ((s8-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  482. ((u16-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  483. ((s16-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  484. ((u32-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  485. ((s32-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  486. ((u64-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  487. ((s64-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  488. ((f32-set! obj bv n x) (&write-object (annotation->memory-kind param)))
  489. ((f64-set! obj bv n x) (&write-object (annotation->memory-kind param))))
  490. ;; Modules.
  491. (define-primitive-effects
  492. ((current-module) (&read-object &module))
  493. ((cache-current-module! m) (&write-object &cache))
  494. ((resolve name) (&read-object &module) &type-check)
  495. ((resolve-module mod) (&read-object &module) &type-check)
  496. ((module-variable mod name) (&read-object &module) &type-check)
  497. ((lookup mod name) (&read-object &module) &type-check)
  498. ((lookup-bound mod name) (&read-object &module) &type-check)
  499. ((lookup-bound-public) &type-check)
  500. ((lookup-bound-private) &type-check)
  501. ((cached-toplevel-box) &type-check)
  502. ((cached-module-box) &type-check)
  503. ((define! mod name) (&read-object &module)))
  504. ;; Cache cells.
  505. (define-primitive-effects
  506. ((cache-ref) (&read-object &cache))
  507. ((cache-set! x) (&write-object &cache)))
  508. ;; Numbers.
  509. (define-primitive-effects
  510. ((heap-numbers-equal? . _))
  511. ((= . _) &type-check)
  512. ((<= . _) &type-check)
  513. ((< . _) &type-check)
  514. ((u64-= . _))
  515. ((u64-imm-= . _))
  516. ((u64-< . _))
  517. ((u64-imm-< . _))
  518. ((imm-u64-< . _))
  519. ((s64-= . _))
  520. ((s64-imm-= . _))
  521. ((s64-< . _))
  522. ((s64-imm-< . _))
  523. ((imm-s64-< . _))
  524. ((f64-= . _))
  525. ((f64-< . _))
  526. ((f64-<= . _))
  527. ((zero? . _) &type-check)
  528. ((add . _) &type-check)
  529. ((add/immediate . _) &type-check)
  530. ((mul . _) &type-check)
  531. ((sub . _) &type-check)
  532. ((sub/immediate . _) &type-check)
  533. ((div . _) &type-check)
  534. ((fadd . _))
  535. ((fsub . _))
  536. ((fmul . _))
  537. ((fdiv . _))
  538. ((uadd . _))
  539. ((usub . _))
  540. ((umul . _))
  541. ((uadd/immediate . _))
  542. ((usub/immediate . _))
  543. ((umul/immediate . _))
  544. ((sadd . _))
  545. ((ssub . _))
  546. ((smul . _))
  547. ((sadd/immediate . _))
  548. ((ssub/immediate . _))
  549. ((smul/immediate . _))
  550. ((quo . _) &type-check)
  551. ((rem . _) &type-check)
  552. ((mod . _) &type-check)
  553. ((inexact _) &type-check)
  554. ((s64->f64 _))
  555. ((complex? _) &type-check)
  556. ((real? _) &type-check)
  557. ((rational? _) &type-check)
  558. ((inf? _) &type-check)
  559. ((nan? _) &type-check)
  560. ((integer? _) &type-check)
  561. ((exact? _) &type-check)
  562. ((inexact? _) &type-check)
  563. ((even? _) &type-check)
  564. ((odd? _) &type-check)
  565. ((rsh n m) &type-check)
  566. ((lsh n m) &type-check)
  567. ((rsh/immediate n) &type-check)
  568. ((lsh/immediate n) &type-check)
  569. ((logand . _) &type-check)
  570. ((logior . _) &type-check)
  571. ((logxor . _) &type-check)
  572. ((logsub . _) &type-check)
  573. ((lognot . _) &type-check)
  574. ((ulogand . _))
  575. ((ulogior . _))
  576. ((ulogxor . _))
  577. ((ulogsub . _))
  578. ((ursh . _))
  579. ((srsh . _))
  580. ((ulsh . _))
  581. ((slsh . _))
  582. ((ursh/immediate . _))
  583. ((srsh/immediate . _))
  584. ((ulsh/immediate . _))
  585. ((slsh/immediate . _))
  586. ((logtest a b) &type-check)
  587. ((logbit? a b) &type-check)
  588. ((sqrt _) &type-check)
  589. ((abs _) &type-check)
  590. ((floor _) &type-check)
  591. ((ceiling _) &type-check)
  592. ((sin _) &type-check)
  593. ((cos _) &type-check)
  594. ((tan _) &type-check)
  595. ((asin _) &type-check)
  596. ((acos _) &type-check)
  597. ((atan _) &type-check)
  598. ((atan2 x y) &type-check)
  599. ((fsqrt _))
  600. ((fabs _))
  601. ((ffloor _))
  602. ((fceiling _))
  603. ((fsin _))
  604. ((fcos _))
  605. ((ftan _))
  606. ((fasin _))
  607. ((facos _))
  608. ((fatan _))
  609. ((fatan2 x y)))
  610. ;; Characters.
  611. (define-primitive-effects
  612. ((untag-char _))
  613. ((tag-char _)))
  614. ;; Atomics are a memory and a compiler barrier; they cause all effects
  615. ;; so no need to have a case for them here. (Though, see
  616. ;; https://jfbastien.github.io/no-sane-compiler/.)
  617. (define (primitive-effects param name args)
  618. (let ((proc (hashq-ref *primitive-effects* name)))
  619. (if proc
  620. (apply proc param args)
  621. &all-effects)))
  622. (define (expression-effects exp)
  623. (match exp
  624. ((or ($ $const) ($ $prim) ($ $values) ($ $code) ($ $const-fun))
  625. &no-effects)
  626. ((or ($ $fun) ($ $rec))
  627. (&allocate &unknown-memory-kinds))
  628. ((or ($ $call) ($ $callk))
  629. &all-effects)
  630. (($ $primcall name param args)
  631. (primitive-effects param name args))))
  632. (define (compute-effects conts)
  633. (intmap-map
  634. (lambda (label cont)
  635. (match cont
  636. (($ $kargs names syms ($ $continue k src exp))
  637. (expression-effects exp))
  638. (($ $kargs names syms ($ $branch kf kt src op param args))
  639. (primitive-effects param op args))
  640. (($ $kargs names syms ($ $switch)) &no-effects)
  641. (($ $kargs names syms ($ $prompt))
  642. ;; Although the "main" path just writes &prompt, we don't know
  643. ;; what nonlocal predecessors of the handler do, so we
  644. ;; conservatively assume &all-effects.
  645. &all-effects)
  646. (($ $kargs names syms ($ $throw))
  647. ;; A reachable "throw" term can never be elided.
  648. &all-effects)
  649. (($ $kreceive arity kargs)
  650. (match arity
  651. (($ $arity _ () #f () #f) &type-check)
  652. (($ $arity () () _ () #f) (&allocate &pair))
  653. (($ $arity _ () _ () #f) (logior (&allocate &pair) &type-check))))
  654. (($ $kfun) &type-check)
  655. (($ $kclause) &type-check)
  656. (($ $ktail) &no-effects)))
  657. conts))
  658. ;; There is a way to abuse effects analysis in CSE to also do scalar
  659. ;; replacement, effectively adding `car' and `cdr' expressions to `cons'
  660. ;; expressions, and likewise with other constructors and setters. This
  661. ;; routine adds appropriate effects to `cons' and `set-car!' and the
  662. ;; like.
  663. ;;
  664. ;; This doesn't affect CSE's ability to eliminate expressions, given
  665. ;; that allocations aren't eliminated anyway, and the new effects will
  666. ;; just cause the allocations not to commute with e.g. set-car! which
  667. ;; is what we want anyway.
  668. (define (synthesize-definition-effects effects)
  669. (intmap-map (lambda (label fx)
  670. (if (logtest (logior &write &allocation) fx)
  671. (logior fx &read)
  672. fx))
  673. effects))