effects-analysis.scm 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. ;;; Effects analysis on CPS
  2. ;; Copyright (C) 2011, 2012, 2013, 2014, 2015 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 intmap)
  42. #:use-module (ice-9 match)
  43. #:export (expression-effects
  44. compute-effects
  45. synthesize-definition-effects
  46. &allocation
  47. &type-check
  48. &read
  49. &write
  50. &fluid
  51. &prompt
  52. &car
  53. &cdr
  54. &vector
  55. &box
  56. &module
  57. &struct
  58. &string
  59. &thread
  60. &bytevector
  61. &closure
  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. exclude-effects
  72. effect-free?
  73. constant?
  74. causes-effect?
  75. causes-all-effects?
  76. effect-clobbers?))
  77. (define-syntax define-flags
  78. (lambda (x)
  79. (syntax-case x ()
  80. ((_ all shift name ...)
  81. (let ((count (length #'(name ...))))
  82. (with-syntax (((n ...) (iota count))
  83. (count count))
  84. #'(begin
  85. (define-syntax name (identifier-syntax (ash 1 n)))
  86. ...
  87. (define-syntax all (identifier-syntax (1- (ash 1 count))))
  88. (define-syntax shift (identifier-syntax count)))))))))
  89. (define-syntax define-enumeration
  90. (lambda (x)
  91. (define (count-bits n)
  92. (let lp ((out 1))
  93. (if (< n (ash 1 (1- out)))
  94. out
  95. (lp (1+ out)))))
  96. (syntax-case x ()
  97. ((_ mask shift name ...)
  98. (let* ((len (length #'(name ...)))
  99. (bits (count-bits len)))
  100. (with-syntax (((n ...) (iota len))
  101. (bits bits))
  102. #'(begin
  103. (define-syntax name (identifier-syntax n))
  104. ...
  105. (define-syntax mask (identifier-syntax (1- (ash 1 bits))))
  106. (define-syntax shift (identifier-syntax bits)))))))))
  107. (define-flags &all-effect-kinds &effect-kind-bits
  108. ;; Indicates that an expression may cause a type check. A type check,
  109. ;; for the purposes of this analysis, is the possibility of throwing
  110. ;; an exception the first time an expression is evaluated. If the
  111. ;; expression did not cause an exception to be thrown, users can
  112. ;; assume that evaluating the expression again will not cause an
  113. ;; exception to be thrown.
  114. ;;
  115. ;; For example, (+ x y) might throw if X or Y are not numbers. But if
  116. ;; it doesn't throw, it should be safe to elide a dominated, common
  117. ;; subexpression (+ x y).
  118. &type-check
  119. ;; Indicates that an expression may return a fresh object. The kind
  120. ;; of object is indicated in the object kind field.
  121. &allocation
  122. ;; Indicates that an expression may cause a read from memory. The
  123. ;; kind of memory is given in the object kind field. Some object
  124. ;; kinds have finer-grained fields; those are expressed in the "field"
  125. ;; part of the effects value. -1 indicates "the whole object".
  126. &read
  127. ;; Indicates that an expression may cause a write to memory.
  128. &write)
  129. (define-enumeration &memory-kind-mask &memory-kind-bits
  130. ;; Indicates than an expression may access unknown kinds of memory.
  131. &unknown-memory-kinds
  132. ;; Indicates that an expression depends on the value of a fluid
  133. ;; variable, or on the current fluid environment.
  134. &fluid
  135. ;; Indicates that an expression depends on the current prompt
  136. ;; stack.
  137. &prompt
  138. ;; Indicates that an expression depends on the value of the car or cdr
  139. ;; of a pair.
  140. &pair
  141. ;; Indicates that an expression depends on the value of a vector
  142. ;; field. The effect field indicates the specific field, or zero for
  143. ;; an unknown field.
  144. &vector
  145. ;; Indicates that an expression depends on the value of a variable
  146. ;; cell.
  147. &box
  148. ;; Indicates that an expression depends on the current module.
  149. &module
  150. ;; Indicates that an expression depends on the current thread.
  151. &thread
  152. ;; Indicates that an expression depends on the value of a struct
  153. ;; field. The effect field indicates the specific field, or zero for
  154. ;; an unknown field.
  155. &struct
  156. ;; Indicates that an expression depends on the contents of a string.
  157. &string
  158. ;; Indicates that an expression depends on the contents of a
  159. ;; bytevector. We cannot be more precise, as bytevectors may alias
  160. ;; other bytevectors.
  161. &bytevector
  162. ;; Indicates a dependency on a free variable of a closure.
  163. &closure)
  164. (define-inlinable (&field kind field)
  165. (ash (logior (ash field &memory-kind-bits) kind) &effect-kind-bits))
  166. (define-inlinable (&object kind)
  167. (&field kind -1))
  168. (define-inlinable (&allocate kind)
  169. (logior &allocation (&object kind)))
  170. (define-inlinable (&read-field kind field)
  171. (logior &read (&field kind field)))
  172. (define-inlinable (&read-object kind)
  173. (logior &read (&object kind)))
  174. (define-inlinable (&write-field kind field)
  175. (logior &write (&field kind field)))
  176. (define-inlinable (&write-object kind)
  177. (logior &write (&object kind)))
  178. (define-syntax &no-effects (identifier-syntax 0))
  179. (define-syntax &all-effects
  180. (identifier-syntax
  181. (logior &all-effect-kinds (&object &unknown-memory-kinds))))
  182. (define-inlinable (constant? effects)
  183. (zero? effects))
  184. (define-inlinable (causes-effect? x effects)
  185. (not (zero? (logand x effects))))
  186. (define-inlinable (causes-all-effects? x)
  187. (eqv? x &all-effects))
  188. (define (effect-clobbers? a b)
  189. "Return true if A clobbers B. This is the case if A is a write, and B
  190. is or might be a read or a write to the same location as A."
  191. (define (locations-same?)
  192. (let ((a (ash a (- &effect-kind-bits)))
  193. (b (ash b (- &effect-kind-bits))))
  194. (or (eqv? &unknown-memory-kinds (logand a &memory-kind-mask))
  195. (eqv? &unknown-memory-kinds (logand b &memory-kind-mask))
  196. (and (eqv? (logand a &memory-kind-mask) (logand b &memory-kind-mask))
  197. ;; A negative field indicates "the whole object".
  198. ;; Non-negative fields indicate only part of the object.
  199. (or (< a 0) (< b 0) (= a b))))))
  200. (and (not (zero? (logand a &write)))
  201. (not (zero? (logand b (logior &read &write))))
  202. (locations-same?)))
  203. (define-inlinable (indexed-field kind var constants)
  204. (let ((val (intmap-ref constants var (lambda (_) #f))))
  205. (if (and (exact-integer? val) (<= 0 val))
  206. (&field kind val)
  207. (&object kind))))
  208. (define *primitive-effects* (make-hash-table))
  209. (define-syntax-rule (define-primitive-effects* constants
  210. ((name . args) effects ...)
  211. ...)
  212. (begin
  213. (hashq-set! *primitive-effects* 'name
  214. (case-lambda*
  215. ((constants . args) (logior effects ...))
  216. (_ &all-effects)))
  217. ...))
  218. (define-syntax-rule (define-primitive-effects ((name . args) effects ...) ...)
  219. (define-primitive-effects* constants ((name . args) effects ...) ...))
  220. ;; Miscellaneous.
  221. (define-primitive-effects
  222. ((values . _)))
  223. ;; Generic effect-free predicates.
  224. (define-primitive-effects
  225. ((eq? . _))
  226. ((eqv? . _))
  227. ((equal? . _))
  228. ((pair? arg))
  229. ((null? arg))
  230. ((nil? arg ))
  231. ((symbol? arg))
  232. ((variable? arg))
  233. ((vector? arg))
  234. ((struct? arg))
  235. ((string? arg))
  236. ((number? arg))
  237. ((char? arg))
  238. ((bytevector? arg))
  239. ((keyword? arg))
  240. ((bitvector? arg))
  241. ((procedure? arg))
  242. ((thunk? arg)))
  243. ;; Fluids.
  244. (define-primitive-effects
  245. ((fluid-ref f) (&read-object &fluid) &type-check)
  246. ((fluid-set! f v) (&write-object &fluid) &type-check)
  247. ((push-fluid f v) (&write-object &fluid) &type-check)
  248. ((pop-fluid) (&write-object &fluid) &type-check))
  249. ;; Threads. Calls cause &all-effects, which reflects the fact that any
  250. ;; call can capture a partial continuation and reinstate it on another
  251. ;; thread.
  252. (define-primitive-effects
  253. ((current-thread) (&read-object &thread)))
  254. ;; Prompts.
  255. (define-primitive-effects
  256. ((make-prompt-tag #:optional arg) (&allocate &unknown-memory-kinds)))
  257. ;; Pairs.
  258. (define-primitive-effects
  259. ((cons a b) (&allocate &pair))
  260. ((list . _) (&allocate &pair))
  261. ((car x) (&read-field &pair 0) &type-check)
  262. ((set-car! x y) (&write-field &pair 0) &type-check)
  263. ((cdr x) (&read-field &pair 1) &type-check)
  264. ((set-cdr! x y) (&write-field &pair 1) &type-check)
  265. ((memq x y) (&read-object &pair) &type-check)
  266. ((memv x y) (&read-object &pair) &type-check)
  267. ((list? arg) (&read-field &pair 1))
  268. ((length l) (&read-field &pair 1) &type-check))
  269. ;; Variables.
  270. (define-primitive-effects
  271. ((box v) (&allocate &box))
  272. ((box-ref v) (&read-object &box) &type-check)
  273. ((box-set! v x) (&write-object &box) &type-check))
  274. ;; Vectors.
  275. (define (vector-field n constants)
  276. (indexed-field &vector n constants))
  277. (define (read-vector-field n constants)
  278. (logior &read (vector-field n constants)))
  279. (define (write-vector-field n constants)
  280. (logior &write (vector-field n constants)))
  281. (define-primitive-effects* constants
  282. ((vector . _) (&allocate &vector))
  283. ((make-vector n init) (&allocate &vector))
  284. ((make-vector/immediate n init) (&allocate &vector))
  285. ((vector-ref v n) (read-vector-field n constants) &type-check)
  286. ((vector-ref/immediate v n) (read-vector-field n constants) &type-check)
  287. ((vector-set! v n x) (write-vector-field n constants) &type-check)
  288. ((vector-set!/immediate v n x) (write-vector-field n constants) &type-check)
  289. ((vector-length v) &type-check))
  290. ;; Structs.
  291. (define (struct-field n constants)
  292. (indexed-field &struct n constants))
  293. (define (read-struct-field n constants)
  294. (logior &read (struct-field n constants)))
  295. (define (write-struct-field n constants)
  296. (logior &write (struct-field n constants)))
  297. (define-primitive-effects* constants
  298. ((allocate-struct vt n) (&allocate &struct) &type-check)
  299. ((allocate-struct/immediate v n) (&allocate &struct) &type-check)
  300. ((make-struct vt ntail . _) (&allocate &struct) &type-check)
  301. ((make-struct/no-tail vt . _) (&allocate &struct) &type-check)
  302. ((struct-ref s n) (read-struct-field n constants) &type-check)
  303. ((struct-ref/immediate s n) (read-struct-field n constants) &type-check)
  304. ((struct-set! s n x) (write-struct-field n constants) &type-check)
  305. ((struct-set!/immediate s n x) (write-struct-field n constants) &type-check)
  306. ((struct-vtable s) &type-check))
  307. ;; Strings.
  308. (define-primitive-effects
  309. ((string-ref s n) (&read-object &string) &type-check)
  310. ((string-set! s n c) (&write-object &string) &type-check)
  311. ((number->string _) (&allocate &string) &type-check)
  312. ((string->number _) (&read-object &string) &type-check)
  313. ((string-length s) &type-check))
  314. ;; Unboxed floats and integers.
  315. (define-primitive-effects
  316. ((scm->f64 _) &type-check)
  317. ((load-f64 _))
  318. ((f64->scm _))
  319. ((scm->u64 _) &type-check)
  320. ((scm->u64/truncate _) &type-check)
  321. ((load-u64 _))
  322. ((u64->scm _))
  323. ((scm->s64 _) &type-check)
  324. ((load-s64 _))
  325. ((s64->scm _)))
  326. ;; Bytevectors.
  327. (define-primitive-effects
  328. ((bv-length _) &type-check)
  329. ((bv-u8-ref bv n) (&read-object &bytevector) &type-check)
  330. ((bv-s8-ref bv n) (&read-object &bytevector) &type-check)
  331. ((bv-u16-ref bv n) (&read-object &bytevector) &type-check)
  332. ((bv-s16-ref bv n) (&read-object &bytevector) &type-check)
  333. ((bv-u32-ref bv n) (&read-object &bytevector) &type-check)
  334. ((bv-s32-ref bv n) (&read-object &bytevector) &type-check)
  335. ((bv-u64-ref bv n) (&read-object &bytevector) &type-check)
  336. ((bv-s64-ref bv n) (&read-object &bytevector) &type-check)
  337. ((bv-f32-ref bv n) (&read-object &bytevector) &type-check)
  338. ((bv-f64-ref bv n) (&read-object &bytevector) &type-check)
  339. ((bv-u8-set! bv n x) (&write-object &bytevector) &type-check)
  340. ((bv-s8-set! bv n x) (&write-object &bytevector) &type-check)
  341. ((bv-u16-set! bv n x) (&write-object &bytevector) &type-check)
  342. ((bv-s16-set! bv n x) (&write-object &bytevector) &type-check)
  343. ((bv-u32-set! bv n x) (&write-object &bytevector) &type-check)
  344. ((bv-s32-set! bv n x) (&write-object &bytevector) &type-check)
  345. ((bv-u64-set! bv n x) (&write-object &bytevector) &type-check)
  346. ((bv-s64-set! bv n x) (&write-object &bytevector) &type-check)
  347. ((bv-f32-set! bv n x) (&write-object &bytevector) &type-check)
  348. ((bv-f64-set! bv n x) (&write-object &bytevector) &type-check))
  349. ;; Closures.
  350. (define (closure-field n constants)
  351. (indexed-field &closure n constants))
  352. (define (read-closure-field n constants)
  353. (logior &read (closure-field n constants)))
  354. (define (write-closure-field n constants)
  355. (logior &write (closure-field n constants)))
  356. (define-primitive-effects* constants
  357. ((free-ref closure idx) (read-closure-field idx constants))
  358. ((free-set! closure idx val) (write-closure-field idx constants)))
  359. ;; Modules.
  360. (define-primitive-effects
  361. ((current-module) (&read-object &module))
  362. ((cache-current-module! m scope) (&write-object &box))
  363. ((resolve name bound?) (&read-object &module) &type-check)
  364. ((cached-toplevel-box scope name bound?) &type-check)
  365. ((cached-module-box mod name public? bound?) &type-check)
  366. ((define! name val) (&read-object &module) (&write-object &box)))
  367. ;; Numbers.
  368. (define-primitive-effects
  369. ((= . _) &type-check)
  370. ((< . _) &type-check)
  371. ((> . _) &type-check)
  372. ((<= . _) &type-check)
  373. ((>= . _) &type-check)
  374. ((u64-= . _))
  375. ((u64-< . _))
  376. ((u64-> . _))
  377. ((u64-<= . _))
  378. ((u64->= . _))
  379. ((u64-<-scm . _) &type-check)
  380. ((u64-<=-scm . _) &type-check)
  381. ((u64-=-scm . _) &type-check)
  382. ((u64->=-scm . _) &type-check)
  383. ((u64->-scm . _) &type-check)
  384. ((zero? . _) &type-check)
  385. ((add . _) &type-check)
  386. ((add/immediate . _) &type-check)
  387. ((mul . _) &type-check)
  388. ((sub . _) &type-check)
  389. ((sub/immediate . _) &type-check)
  390. ((div . _) &type-check)
  391. ((fadd . _))
  392. ((fsub . _))
  393. ((fmul . _))
  394. ((fdiv . _))
  395. ((uadd . _))
  396. ((usub . _))
  397. ((umul . _))
  398. ((uadd/immediate . _))
  399. ((usub/immediate . _))
  400. ((umul/immediate . _))
  401. ((quo . _) &type-check)
  402. ((rem . _) &type-check)
  403. ((mod . _) &type-check)
  404. ((complex? _) &type-check)
  405. ((real? _) &type-check)
  406. ((rational? _) &type-check)
  407. ((inf? _) &type-check)
  408. ((nan? _) &type-check)
  409. ((integer? _) &type-check)
  410. ((exact? _) &type-check)
  411. ((inexact? _) &type-check)
  412. ((even? _) &type-check)
  413. ((odd? _) &type-check)
  414. ((ash n m) &type-check)
  415. ((logand . _) &type-check)
  416. ((logior . _) &type-check)
  417. ((logxor . _) &type-check)
  418. ((logsub . _) &type-check)
  419. ((lognot . _) &type-check)
  420. ((ulogand . _))
  421. ((ulogior . _))
  422. ((ulogsub . _))
  423. ((ursh . _))
  424. ((ulsh . _))
  425. ((ursh/immediate . _))
  426. ((ulsh/immediate . _))
  427. ((logtest a b) &type-check)
  428. ((logbit? a b) &type-check)
  429. ((sqrt _) &type-check)
  430. ((abs _) &type-check))
  431. ;; Characters.
  432. (define-primitive-effects
  433. ((char<? . _) &type-check)
  434. ((char<=? . _) &type-check)
  435. ((char>=? . _) &type-check)
  436. ((char>? . _) &type-check)
  437. ((integer->char _) &type-check)
  438. ((char->integer _) &type-check))
  439. (define (primitive-effects constants name args)
  440. (let ((proc (hashq-ref *primitive-effects* name)))
  441. (if proc
  442. (apply proc constants args)
  443. &all-effects)))
  444. (define (expression-effects exp constants)
  445. (match exp
  446. ((or ($ $const) ($ $prim) ($ $values))
  447. &no-effects)
  448. (($ $closure _ 0)
  449. &no-effects)
  450. ((or ($ $fun) ($ $rec) ($ $closure))
  451. (&allocate &unknown-memory-kinds))
  452. (($ $prompt)
  453. (&write-object &prompt))
  454. ((or ($ $call) ($ $callk))
  455. &all-effects)
  456. (($ $branch k exp)
  457. (expression-effects exp constants))
  458. (($ $primcall name args)
  459. (primitive-effects constants name args))))
  460. (define (compute-effects conts)
  461. (let ((constants (compute-constant-values conts)))
  462. (intmap-map
  463. (lambda (label cont)
  464. (match cont
  465. (($ $kargs names syms ($ $continue k src exp))
  466. (expression-effects exp constants))
  467. (($ $kreceive arity kargs)
  468. (match arity
  469. (($ $arity _ () #f () #f) &type-check)
  470. (($ $arity () () _ () #f) (&allocate &pair))
  471. (($ $arity _ () _ () #f) (logior (&allocate &pair) &type-check))))
  472. (($ $kfun) &type-check)
  473. (($ $kclause) &type-check)
  474. (($ $ktail) &no-effects)))
  475. conts)))
  476. ;; There is a way to abuse effects analysis in CSE to also do scalar
  477. ;; replacement, effectively adding `car' and `cdr' expressions to `cons'
  478. ;; expressions, and likewise with other constructors and setters. This
  479. ;; routine adds appropriate effects to `cons' and `set-car!' and the
  480. ;; like.
  481. ;;
  482. ;; This doesn't affect CSE's ability to eliminate expressions, given
  483. ;; that allocations aren't eliminated anyway, and the new effects will
  484. ;; just cause the allocations not to commute with e.g. set-car! which
  485. ;; is what we want anyway.
  486. (define (synthesize-definition-effects effects)
  487. (intmap-map (lambda (label fx)
  488. (if (logtest (logior &write &allocation) fx)
  489. (logior fx &read)
  490. fx))
  491. effects))