cse.scm 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795
  1. ;;; Continuation-passing style (CPS) intermediate language (IL)
  2. ;; Copyright (C) 2013-2021, 2023 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. ;;; Common subexpression elimination for CPS.
  19. ;;;
  20. ;;; Code:
  21. (define-module (language cps cse)
  22. #:use-module (ice-9 match)
  23. #:use-module (srfi srfi-1)
  24. #:use-module (srfi srfi-9)
  25. #:use-module (srfi srfi-11)
  26. #:use-module (language cps)
  27. #:use-module (language cps utils)
  28. #:use-module (language cps effects-analysis)
  29. #:use-module (language cps intmap)
  30. #:use-module (language cps intset)
  31. #:use-module (language cps renumber)
  32. #:export (eliminate-common-subexpressions))
  33. (define (intset-intersect* out out*)
  34. (if out (intset-intersect out out*) out*))
  35. (define (compute-available-expressions succs kfun clobbers)
  36. "Compute and return a map of LABEL->ANCESTOR..., where ANCESTOR... is
  37. an intset containing ancestor labels whose value is available at LABEL."
  38. (let ((init (intmap-map (lambda (label succs) #f) succs))
  39. (kill clobbers)
  40. (gen (intmap-map (lambda (label succs) (intset label)) succs))
  41. (subtract (lambda (in-1 kill-1)
  42. (if in-1
  43. (intset-subtract in-1 kill-1)
  44. empty-intset)))
  45. (add intset-union)
  46. (meet intset-intersect*))
  47. (let ((in (intmap-replace init kfun empty-intset))
  48. (out init)
  49. (worklist (intset kfun)))
  50. (solve-flow-equations succs in out kill gen subtract add meet worklist))))
  51. (define (intset-pop set)
  52. (match (intset-next set)
  53. (#f (values set #f))
  54. (i (values (intset-remove set i) i))))
  55. (define-syntax-rule (make-worklist-folder* seed ...)
  56. (lambda (f worklist seed ...)
  57. (let lp ((worklist worklist) (seed seed) ...)
  58. (call-with-values (lambda () (intset-pop worklist))
  59. (lambda (worklist i)
  60. (if i
  61. (call-with-values (lambda () (f i seed ...))
  62. (lambda (i* seed ...)
  63. (let add ((i* i*) (worklist worklist))
  64. (match i*
  65. (() (lp worklist seed ...))
  66. ((i . i*) (add i* (intset-add worklist i)))))))
  67. (values seed ...)))))))
  68. (define worklist-fold*
  69. (case-lambda
  70. ((f worklist seed)
  71. ((make-worklist-folder* seed) f worklist seed))))
  72. (define-syntax-rule (true-idx idx) (ash idx 1))
  73. (define-syntax-rule (false-idx idx) (1+ (ash idx 1)))
  74. (define (compute-truthy-expressions conts kfun)
  75. "Compute a \"truth map\", indicating which expressions can be shown to
  76. be true and/or false at each label in the function starting at KFUN.
  77. Returns an intmap of intsets. The even elements of the intset indicate
  78. labels that may be true, and the odd ones indicate those that may be
  79. false. It could be that both true and false proofs are available."
  80. (define (propagate boolv succ out)
  81. (let* ((in (intmap-ref boolv succ (lambda (_) #f)))
  82. (in* (if in (intset-union in out) out)))
  83. (if (eq? in in*)
  84. (values '() boolv)
  85. (values (list succ)
  86. (intmap-add boolv succ in* (lambda (old new) new))))))
  87. (define (visit-cont label boolv)
  88. (let ((in (intmap-ref boolv label)))
  89. (define (propagate0)
  90. (values '() boolv))
  91. (define (propagate1 succ)
  92. (propagate boolv succ in))
  93. (define (propagate2 succ0 succ1)
  94. (let*-values (((changed0 boolv) (propagate boolv succ0 in))
  95. ((changed1 boolv) (propagate boolv succ1 in)))
  96. (values (append changed0 changed1) boolv)))
  97. (define (propagate-branch succ0 succ1)
  98. (let*-values (((changed0 boolv)
  99. (propagate boolv succ0
  100. (intset-add in (false-idx label))))
  101. ((changed1 boolv)
  102. (propagate boolv succ1
  103. (intset-add in (true-idx label)))))
  104. (values (append changed0 changed1) boolv)))
  105. (define (propagate* succs)
  106. (fold2 (lambda (succ changed boolv)
  107. (call-with-values (lambda () (propagate boolv succ in))
  108. (lambda (changed* boolv)
  109. (values (append changed* changed) boolv))))
  110. succs '() boolv))
  111. (match (intmap-ref conts label)
  112. (($ $kargs names vars term)
  113. (match term
  114. (($ $continue k) (propagate1 k))
  115. (($ $branch kf kt) (propagate-branch kf kt))
  116. (($ $switch kf kt*) (propagate* (cons kf kt*)))
  117. (($ $prompt k kh) (propagate2 k kh))
  118. (($ $throw) (propagate0))))
  119. (($ $kreceive arity k)
  120. (propagate1 k))
  121. (($ $kfun src meta self tail clause)
  122. (if clause
  123. (propagate1 clause)
  124. (propagate0)))
  125. (($ $kclause arity kbody kalt)
  126. (if kalt
  127. (propagate2 kbody kalt)
  128. (propagate1 kbody)))
  129. (($ $ktail) (propagate0)))))
  130. (worklist-fold* visit-cont
  131. (intset kfun)
  132. (intmap-add empty-intmap kfun empty-intset)))
  133. (define (lset-unionq old new)
  134. (lset-union eq? old new))
  135. (define (meet-constants out out*)
  136. (if out (intmap-intersect out out* lset-unionq) out*))
  137. (define (adjoin-constant in k v)
  138. (intmap-add in k (list v) lset-unionq))
  139. (define (set-constants consts k in)
  140. (intmap-add consts k in (lambda (old new) new)))
  141. (define (compute-consts conts kfun)
  142. "Compute a map of var to a list of constant values known to be bound
  143. to variables at each label in CONTS. If a var isn't present in the map
  144. for a label, it isn't known to be constant at that label."
  145. (define (propagate consts succ out)
  146. (let* ((in (intmap-ref consts succ (lambda (_) #f)))
  147. (in* (meet-constants in out)))
  148. (if (eq? in in*)
  149. (values '() consts)
  150. (values (list succ) (set-constants consts succ in*)))))
  151. (define (visit-cont label consts)
  152. (let ((in (intmap-ref consts label)))
  153. (define (propagate0)
  154. (values '() consts))
  155. (define (propagate1 succ)
  156. (propagate consts succ in))
  157. (define (propagate2 succ0 succ1)
  158. (let*-values (((changed0 consts) (propagate consts succ0 in))
  159. ((changed1 consts) (propagate consts succ1 in)))
  160. (values (append changed0 changed1) consts)))
  161. (define (propagate-branch succ0 succ1)
  162. (let*-values (((changed0 consts)
  163. (propagate consts succ0
  164. (intset-add in (false-idx label))))
  165. ((changed1 consts)
  166. (propagate consts succ1
  167. (intset-add in (true-idx label)))))
  168. (values (append changed0 changed1) consts)))
  169. (define (propagate* succs)
  170. (fold2 (lambda (succ changed consts)
  171. (call-with-values (lambda () (propagate consts succ in))
  172. (lambda (changed* consts)
  173. (values (append changed* changed) consts))))
  174. succs '() consts))
  175. (define (get-def k)
  176. (match (intmap-ref conts k)
  177. (($ $kargs (_) (v)) v)))
  178. (define (propagate-constant consts k v c)
  179. (propagate consts k (adjoin-constant in v c)))
  180. (match (intmap-ref conts label)
  181. (($ $kargs names vars term)
  182. (match term
  183. (($ $continue k src ($ $const c))
  184. (propagate-constant consts k (get-def k) c))
  185. (($ $continue k)
  186. (propagate1 k))
  187. (($ $branch kf kt src 'eq-constant? c (v))
  188. (let*-values (((changed0 consts) (propagate1 kf))
  189. ((changed1 consts)
  190. (propagate-constant consts kt v c)))
  191. (values (append changed0 changed1) consts)))
  192. (($ $branch kf kt) (propagate2 kf kt))
  193. (($ $switch kf kt* src v)
  194. (let-values (((changed consts) (propagate1 kf)))
  195. (let lp ((i 0) (kt* kt*) (changed changed) (consts consts))
  196. (match kt*
  197. (() (values changed consts))
  198. ((k . kt*)
  199. (call-with-values (lambda ()
  200. (propagate-constant consts k v i))
  201. (lambda (changed* consts)
  202. (lp (1+ i) kt* (append changed* changed) consts))))))))
  203. (($ $prompt k kh) (propagate2 k kh))
  204. (($ $throw) (propagate0))))
  205. (($ $kreceive arity k)
  206. (propagate1 k))
  207. (($ $kfun src meta self tail clause)
  208. (if clause
  209. (propagate1 clause)
  210. (propagate0)))
  211. (($ $kclause arity kbody kalt)
  212. (if kalt
  213. (propagate2 kbody kalt)
  214. (propagate1 kbody)))
  215. (($ $ktail) (propagate0)))))
  216. (worklist-fold* visit-cont
  217. (intset kfun)
  218. (intmap-add empty-intmap kfun empty-intmap)))
  219. (define-record-type <analysis>
  220. (make-analysis effects clobbers preds avail truthy-labels consts)
  221. analysis?
  222. (effects analysis-effects)
  223. (clobbers analysis-clobbers)
  224. (preds analysis-preds)
  225. (avail analysis-avail)
  226. (truthy-labels analysis-truthy-labels)
  227. (consts analysis-consts))
  228. ;; When we determine that we can replace an expression with
  229. ;; already-bound variables, we change the expression to a $values. At
  230. ;; its continuation, if it turns out that the $values expression is the
  231. ;; only predecessor, we elide the predecessor, to make redundant branch
  232. ;; folding easier. Ideally, elision results in redundant branches
  233. ;; having multiple predecessors which already have values for the
  234. ;; branch.
  235. ;;
  236. ;; We could avoid elision, and instead search backwards when we get to a
  237. ;; branch that we'd like to elide. However it's gnarly: branch elisions
  238. ;; reconfigure the control-flow graph, and thus affect the avail /
  239. ;; truthy maps. If we forwarded such a distant predecessor, if there
  240. ;; were no intermediate definitions, we'd have to replay the flow
  241. ;; analysis from far away. Maybe it's possible but it's not obvious.
  242. ;;
  243. ;; The elision mechanism is to rewrite predecessors to continue to the
  244. ;; successor. We could have instead replaced the predecessor with the
  245. ;; body of the successor, but that would invalidate the values of the
  246. ;; avail / truthy maps, as well as the clobber sets.
  247. ;;
  248. ;; We can't always elide the predecessor though. If any of the
  249. ;; predecessor's predecessors is a back-edge, it hasn't been
  250. ;; residualized yet and so we can't rewrite it. This is an
  251. ;; implementation limitation.
  252. ;;
  253. (define (forward-cont cont from to)
  254. (define (rename k) (if (eqv? k from) to k))
  255. (rewrite-cont cont
  256. (($ $kargs names vals ($ $continue k src exp))
  257. ($kargs names vals ($continue (rename k) src ,exp)))
  258. (($ $kargs names vals ($ $branch kf kt src op param args))
  259. ($kargs names vals ($branch (rename kf) (rename kt) src op param args)))
  260. (($ $kargs names vals ($ $switch kf kt* src arg))
  261. ($kargs names vals ($switch (rename kf) (map rename kt*) src arg)))
  262. (($ $kargs names vals ($ $prompt k kh src escape? tag))
  263. ($kargs names vals ($prompt (rename k) (rename kh) src escape? tag)))
  264. (($ $kreceive ($ $arity req () rest () #f) kbody)
  265. ($kreceive req rest (rename kbody)))
  266. (($ $kclause arity kbody kalternate)
  267. ;; Can only be a body continuation.
  268. ($kclause ,arity (rename kbody) kalternate))
  269. (($ $kfun src meta self tail kentry)
  270. ;; Can only be a $kargs clause continuation.
  271. ($kfun src meta self tail (rename kentry)))))
  272. (define (elide-predecessor label pred out analysis)
  273. (match analysis
  274. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  275. (let ((pred-preds (intmap-ref preds pred)))
  276. (and
  277. ;; Don't elide predecessors that are the targets of back-edges.
  278. (< (intset-prev pred-preds) pred)
  279. (cons
  280. (intset-fold
  281. (lambda (pred-pred out)
  282. (define (rename k) (if (eqv? k pred) label k))
  283. (intmap-replace!
  284. out pred-pred
  285. (forward-cont (intmap-ref out pred-pred) pred label)))
  286. pred-preds
  287. (intmap-remove out pred))
  288. (make-analysis effects
  289. clobbers
  290. (intmap-add (intmap-add preds label pred intset-remove)
  291. label pred-preds intset-union)
  292. avail
  293. truthy-labels
  294. consts)))))))
  295. (define (prune-branch analysis pred succ)
  296. (match analysis
  297. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  298. (make-analysis effects
  299. clobbers
  300. (intmap-add preds succ pred intset-remove)
  301. avail
  302. truthy-labels
  303. consts))))
  304. (define (forward-branch analysis pred old-succ new-succ)
  305. (match analysis
  306. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  307. (make-analysis effects
  308. clobbers
  309. (let ((preds (intmap-add preds old-succ pred
  310. intset-remove)))
  311. (intmap-add preds new-succ pred intset-add))
  312. avail
  313. truthy-labels
  314. consts))))
  315. (define (prune-successors analysis pred succs)
  316. (intset-fold (lambda (succ analysis)
  317. (prune-branch analysis pred succ))
  318. succs analysis))
  319. (define (compute-out-edges analysis pred succ out)
  320. (match analysis
  321. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  322. (let ((avail (intmap-ref avail pred))
  323. (kill (intmap-ref clobbers pred))
  324. (bool (intmap-ref truthy-labels pred))
  325. (consts (intmap-ref consts pred)))
  326. (values (intset-add (intset-subtract avail kill) pred)
  327. (match (and (< pred succ) (intmap-ref out pred))
  328. (($ $kargs _ _ ($ $branch kf kt))
  329. (define (maybe-add bool k idx)
  330. (if (eqv? k succ) (intset-add bool idx) bool))
  331. (maybe-add (maybe-add bool kf (false-idx pred))
  332. kt (true-idx pred)))
  333. (_ bool))
  334. (match (and (< pred succ) (intmap-ref out pred))
  335. (($ $kargs _ _ ($ $branch kf kt src 'eq-constant? c (v)))
  336. (if (eqv? kf succ)
  337. consts
  338. (adjoin-constant consts v c)))
  339. (_ consts)))))))
  340. (define (propagate-analysis analysis label out)
  341. (match analysis
  342. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  343. (call-with-values
  344. (lambda ()
  345. (intset-fold
  346. (lambda (pred avail-in bool-in consts-in)
  347. (call-with-values
  348. (lambda ()
  349. (compute-out-edges analysis pred label out))
  350. (lambda (avail-in* bool-in* consts-in*)
  351. (values (intset-intersect* avail-in avail-in*)
  352. (intset-union bool-in bool-in*)
  353. (meet-constants consts-in consts-in*)))))
  354. (intmap-ref preds label) #f empty-intset #f))
  355. (lambda (avail-in bool-in consts-in)
  356. (make-analysis effects clobbers preds
  357. (intmap-replace avail label avail-in)
  358. (intmap-replace truthy-labels label bool-in)
  359. (intmap-replace consts label consts-in)))))))
  360. (define (term-successors term)
  361. (define (list->intset ls)
  362. (fold1 (lambda (elt set) (intset-add set elt)) ls empty-intset))
  363. (match term
  364. (($ $continue k) (intset k))
  365. (($ $branch kf kt) (intset kf kt))
  366. (($ $switch kf kt*) (list->intset (cons kf kt*)))
  367. (($ $prompt k kh) (intset k kh))
  368. (($ $throw) empty-intset)))
  369. (define (intmap-select map keys)
  370. (persistent-intmap
  371. (intmap-fold (lambda (k v out)
  372. (if (intset-ref keys k)
  373. (intmap-add! out k v)
  374. out))
  375. map empty-intmap)))
  376. (define (make-equivalent-expression-table)
  377. ;; Table associating expressions with equivalent variables, indexed by
  378. ;; the label that defines them.
  379. (make-hash-table))
  380. (define (add-equivalent-expression! table key label vars)
  381. (let ((equiv (hash-ref table key empty-intmap)))
  382. (define (allow-equal old new)
  383. (if (equal? old new)
  384. old
  385. (error "bad equiv var update" label old new)))
  386. (hash-set! table key
  387. (intmap-add equiv label vars allow-equal))))
  388. (define (lookup-equivalent-expressions table key avail)
  389. (match (hash-ref table key)
  390. (#f empty-intmap)
  391. (equiv (intmap-select equiv avail))))
  392. ;; return #(taken not-taken), or #f if can't decide.
  393. (define (fold-branch table key kf kt avail bool consts)
  394. (define (fold-constant-comparison)
  395. (match key
  396. (('eq-constant? c v)
  397. (match (intmap-ref consts v (lambda (v) #f))
  398. (#f #f)
  399. ((c') (if (eq? c c')
  400. (vector kt kf)
  401. (vector kf kt)))
  402. (c* (if (memq c c*)
  403. #f
  404. (vector kf kt)))))
  405. (_ #f)))
  406. (define (fold-redundant-branch)
  407. (let ((equiv (lookup-equivalent-expressions table key avail)))
  408. (let lp ((candidate (intmap-prev equiv)))
  409. (match candidate
  410. (#f #f)
  411. (_ (let ((t (intset-ref bool (true-idx candidate)))
  412. (f (intset-ref bool (false-idx candidate))))
  413. (if (eqv? t f)
  414. (lp (intmap-prev equiv (1- candidate)))
  415. (if t
  416. (vector kt kf)
  417. (vector kf kt)))))))))
  418. (or (fold-constant-comparison)
  419. (fold-redundant-branch)))
  420. (define (eliminate-common-subexpressions-in-fun kfun conts out substs)
  421. (define equivalent-expressions (make-equivalent-expression-table))
  422. (define (subst-var substs var)
  423. (intmap-ref substs var (lambda (var) var)))
  424. (define (subst-vars substs vars)
  425. (let lp ((vars vars))
  426. (match vars
  427. (() '())
  428. ((var . vars) (cons (subst-var substs var) (lp vars))))))
  429. (define (compute-branch-key branch)
  430. (match branch
  431. (($ $branch kf kt src op param args) (cons* op param args))))
  432. (define (compute-expr-key expr)
  433. (match expr
  434. (($ $const val) (cons 'const val))
  435. (($ $prim name) (cons 'prim name))
  436. (($ $fun body) #f)
  437. (($ $rec names syms funs) #f)
  438. (($ $const-fun label) #f)
  439. (($ $code label) (cons 'code label))
  440. (($ $call proc args) #f)
  441. (($ $callk k proc args) #f)
  442. (($ $calli args callee) #f)
  443. (($ $primcall name param args) (cons* name param args))
  444. (($ $values args) #f)))
  445. (define (compute-term-key term)
  446. (match term
  447. (($ $continue k src exp) (compute-expr-key exp))
  448. (($ $branch) (compute-branch-key term))
  449. (($ $switch) #f)
  450. (($ $prompt) #f)
  451. (($ $throw) #f)))
  452. (define (add-auxiliary-definitions! label defs substs term-key)
  453. (define (add-def! aux-key var)
  454. (add-equivalent-expression! equivalent-expressions aux-key label
  455. (list var)))
  456. (define-syntax add-definitions
  457. (syntax-rules (<-)
  458. ((add-definitions)
  459. #f)
  460. ((add-definitions
  461. ((def <- op arg ...) (aux <- op* arg* ...) ...)
  462. . clauses)
  463. (match term-key
  464. (('op arg ...)
  465. (match defs
  466. ((def) (add-def! (list 'op* arg* ...) aux) ...)))
  467. (_ (add-definitions . clauses))))
  468. ((add-definitions
  469. ((op arg ...) (aux <- op* arg* ...) ...)
  470. . clauses)
  471. (match term-key
  472. (('op arg ...)
  473. (add-def! (list 'op* arg* ...) aux) ...)
  474. (_ (add-definitions . clauses))))))
  475. (add-definitions
  476. ((scm-set! p s i x) (x <- scm-ref p s i))
  477. ((scm-set!/tag p s x) (x <- scm-ref/tag p s))
  478. ((scm-set!/immediate p s x) (x <- scm-ref/immediate p s))
  479. ((word-set! p s i x) (x <- word-ref p s i))
  480. ((word-set!/immediate p s x) (x <- word-ref/immediate p s))
  481. ((pointer-set!/immediate p s x) (x <- pointer-ref/immediate p s))
  482. ((p <- cons #f x y) (x <- car #f p)
  483. (y <- cdr #f p))
  484. ((set-car! #f p x) (x <- car #f p))
  485. ((set-cdr! #f p y) (y <- cdr #f p))
  486. ((b <- box #f x) (x <- box-ref #f b))
  487. ((box-set! #f b x) (x <- box-ref #f b))
  488. ((v <- allocate-vector #f n) (n <- vector-length #f v))
  489. ((vector-set!/immediate p v x) (x <- vector-ref/immediate p v))
  490. ((vector-set! #f v i x) (x <- vector-ref #f v i))
  491. ((s <- allocate-struct n v) (v <- struct-vtable #f s))
  492. ((struct-set! p s x) (x <- struct-ref p s))
  493. ((u <- scm->f64 #f s) (s <- f64->scm #f u))
  494. ((s <- f64->scm #f u) (u <- scm->f64 #f s))
  495. ((u <- scm->u64 #f s) (s <- u64->scm #f u))
  496. ((s <- u64->scm #f u) (u <- scm->u64 #f s)
  497. (u <- scm->u64/truncate #f s))
  498. ((s <- u64->scm/unlikely #f u) (u <- scm->u64 #f s)
  499. (u <- scm->u64/truncate #f s))
  500. ((u <- scm->s64 #f s) (s <- s64->scm #f u))
  501. ((s <- s64->scm #f u) (u <- scm->s64 #f s))
  502. ((s <- s64->scm/unlikely #f u) (u <- scm->s64 #f s))
  503. ((u <- untag-fixnum #f s) (s <- s64->scm #f u)
  504. (s <- tag-fixnum #f u))
  505. ;; NB: These definitions rely on U having top 2 bits equal to
  506. ;; 3rd (sign) bit.
  507. ((s <- tag-fixnum #f u) (u <- scm->s64 #f s)
  508. (u <- untag-fixnum #f s))
  509. ((s <- u64->s64 #f u) (u <- s64->u64 #f s))
  510. ((u <- s64->u64 #f s) (s <- u64->s64 #f u))
  511. ((u <- untag-char #f s) (s <- tag-char #f u))
  512. ((s <- tag-char #f u) (u <- untag-char #f s))))
  513. (define (rename-uses term substs)
  514. (define (subst-var var)
  515. (intmap-ref substs var (lambda (var) var)))
  516. (define (rename-exp exp)
  517. (rewrite-exp exp
  518. ((or ($ $const) ($ $prim) ($ $fun) ($ $rec) ($ $const-fun) ($ $code))
  519. ,exp)
  520. (($ $call proc args)
  521. ($call (subst-var proc) ,(map subst-var args)))
  522. (($ $callk k proc args)
  523. ($callk k (and proc (subst-var proc)) ,(map subst-var args)))
  524. (($ $calli args callee)
  525. ($calli ,(map subst-var args) (subst-var callee)))
  526. (($ $primcall name param args)
  527. ($primcall name param ,(map subst-var args)))
  528. (($ $values args)
  529. ($values ,(map subst-var args)))))
  530. (rewrite-term term
  531. (($ $branch kf kt src op param args)
  532. ($branch kf kt src op param ,(map subst-var args)))
  533. (($ $switch kf kt* src arg)
  534. ($switch kf kt* src (subst-var arg)))
  535. (($ $continue k src exp)
  536. ($continue k src ,(rename-exp exp)))
  537. (($ $prompt k kh src escape? tag)
  538. ($prompt k kh src escape? (subst-var tag)))
  539. (($ $throw src op param args)
  540. ($throw src op param ,(map subst-var args)))))
  541. (define (visit-exp label exp analysis)
  542. (define (residualize) exp)
  543. (define (forward vals) (build-exp ($values vals)))
  544. (match (compute-expr-key exp)
  545. (#f (residualize))
  546. (key
  547. (match analysis
  548. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  549. (match (lookup-equivalent-expressions equivalent-expressions
  550. key (intmap-ref avail label))
  551. ((? (lambda (x) (eq? x empty-intmap)))
  552. (residualize))
  553. (equiv
  554. (forward (intmap-ref equiv (intmap-next equiv))))))))))
  555. (define (maybe-forward-branch-predecessor label pred key kf kt out analysis)
  556. (cond
  557. ((<= label pred)
  558. ;; A backwards branch; punt.
  559. (values out analysis))
  560. (else
  561. (call-with-values (lambda ()
  562. (compute-out-edges analysis pred label out))
  563. (lambda (pred-avail pred-bool pred-consts)
  564. (match (fold-branch equivalent-expressions key kf kt
  565. pred-avail pred-bool pred-consts)
  566. (#(taken not-taken)
  567. (values (intmap-replace!
  568. out pred
  569. (forward-cont (intmap-ref out pred) label taken))
  570. (forward-branch analysis pred label taken)))
  571. (#f
  572. (values out analysis))))))))
  573. (define (simplify-branch-predecessors label term out analysis)
  574. ;; if any predecessor's truthy-edge folds the branch, forward the
  575. ;; precedecessor. may cause branch to become dead, or cause
  576. ;; remaining predecessor to eliminate.
  577. (match term
  578. (($ $branch kf kt)
  579. (let ((key (compute-branch-key term)))
  580. (match analysis
  581. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  582. (call-with-values
  583. (lambda ()
  584. (intset-fold
  585. (lambda (pred out analysis)
  586. (maybe-forward-branch-predecessor label pred
  587. key kf kt out analysis))
  588. (intmap-ref preds label) out analysis))
  589. (lambda (out* analysis*)
  590. (if (eq? analysis analysis*)
  591. #f
  592. (cons out* analysis*))))))))))
  593. (define (visit-branch label term analysis)
  594. (match term
  595. (($ $branch kf kt src)
  596. (match analysis
  597. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  598. (let ((key (compute-branch-key term))
  599. (avail (intmap-ref avail label))
  600. (bool (intmap-ref truthy-labels label))
  601. (consts (intmap-ref consts label)))
  602. (match (fold-branch equivalent-expressions key kf kt avail bool
  603. consts)
  604. (#(taken not-taken)
  605. (values (build-term ($continue taken src ($values ())))
  606. (prune-branch analysis label not-taken)))
  607. (#f
  608. (values term analysis)))))))))
  609. (define (visit-term label names vars term out substs analysis)
  610. (let ((term (rename-uses term substs))
  611. (analysis (propagate-analysis analysis label out)))
  612. (match term
  613. (($ $branch)
  614. ;; Can only forward predecessors if this continuation binds no
  615. ;; values.
  616. (match (and (null? vars)
  617. (simplify-branch-predecessors label term out analysis))
  618. (#f
  619. (call-with-values (lambda ()
  620. (visit-branch label term analysis))
  621. (lambda (term analysis)
  622. (values (intmap-add! out label
  623. (build-cont ($kargs names vars ,term)))
  624. substs
  625. analysis))))
  626. ((out . analysis)
  627. ;; Recurse.
  628. (visit-label label (build-cont ($kargs names vars ,term))
  629. out substs analysis))))
  630. (($ $continue k src exp)
  631. (values (intmap-add! out label
  632. (build-cont
  633. ($kargs names vars
  634. ($continue k src
  635. ,(visit-exp label exp analysis)))))
  636. substs
  637. analysis))
  638. ((or ($ $switch) ($ $prompt) ($ $throw))
  639. (values (intmap-add! out label (build-cont ($kargs names vars ,term)))
  640. substs
  641. analysis)))))
  642. (define (visit-label label cont out substs analysis)
  643. (match cont
  644. (($ $kargs names vars term)
  645. (define (visit-term-normally)
  646. (visit-term label names vars term out substs analysis))
  647. (match analysis
  648. (($ <analysis> effects clobbers preds avail truthy-labels consts)
  649. (let ((preds (intmap-ref preds label)))
  650. (cond
  651. ((eq? preds empty-intset)
  652. ;; Branch folding made this term unreachable. Prune from
  653. ;; preds set.
  654. (values out substs
  655. (prune-successors analysis label (term-successors term))))
  656. ((trivial-intset preds)
  657. => (lambda (pred)
  658. (match (and (< pred label) (intmap-ref out pred))
  659. (#f
  660. ;; Orphan loop; branch folding must have removed
  661. ;; entry. Could still be alive though.
  662. (visit-term-normally))
  663. (($ $kargs names' vars' ($ $continue _ _ ($ $values vals)))
  664. ;; Substitute dominating definitions, and try to elide the
  665. ;; predecessor entirely.
  666. (let ((substs (fold (lambda (var val substs)
  667. (intmap-add substs var val))
  668. substs vars vals)))
  669. (match (elide-predecessor label pred out analysis)
  670. (#f
  671. ;; Can't elide; predecessor must be target of
  672. ;; backwards branch.
  673. (visit-term label names vars term out substs analysis))
  674. ((out . analysis)
  675. (visit-term label names' vars' term out substs analysis)))))
  676. (($ $kargs _ _ term)
  677. (match (compute-term-key term)
  678. (#f #f)
  679. (term-key
  680. (let ((fx (intmap-ref effects pred)))
  681. ;; Add residualized definition to the equivalence set.
  682. ;; Note that expressions that allocate a fresh object
  683. ;; or change the current fluid environment can't be
  684. ;; eliminated by CSE (though DCE might do it if the
  685. ;; value proves to be unused, in the allocation case).
  686. (when (and (not (causes-effect? fx &allocation))
  687. (not (effect-clobbers? fx (&read-object &fluid))))
  688. (add-equivalent-expression! equivalent-expressions term-key pred vars)))
  689. ;; If the predecessor defines auxiliary definitions, as
  690. ;; `cons' does for the results of `car' and `cdr', define
  691. ;; those as well.
  692. (add-auxiliary-definitions! pred vars substs term-key)))
  693. (visit-term-normally))
  694. ((or ($ $kclause) ($ $kfun) ($ $kreceive))
  695. (visit-term-normally)))))
  696. (else
  697. (visit-term-normally)))))))
  698. (_ (values (intmap-add! out label cont) substs analysis))))
  699. ;; Because of the renumber pass, the labels are numbered in reverse
  700. ;; post-order, so the intmap-fold will visit definitions before
  701. ;; uses.
  702. (let* ((effects (synthesize-definition-effects (compute-effects conts)))
  703. (clobbers (compute-clobber-map conts effects))
  704. (succs (compute-successors conts kfun))
  705. (preds (invert-graph succs))
  706. (avail (compute-available-expressions succs kfun clobbers))
  707. (truthy-labels (compute-truthy-expressions conts kfun))
  708. (consts (compute-consts conts kfun)))
  709. (call-with-values
  710. (lambda ()
  711. (intmap-fold visit-label conts out substs
  712. (make-analysis effects clobbers preds avail truthy-labels
  713. consts)))
  714. (lambda (out substs analysis)
  715. (values out substs)))))
  716. (define (fold-renumbered-functions f conts . seeds)
  717. ;; Precondition: CONTS has been renumbered, and therefore functions
  718. ;; contained within it are topologically sorted, and the conts of each
  719. ;; function's body are numbered sequentially after the function's
  720. ;; $kfun.
  721. (define (next-function-body kfun)
  722. (match (intmap-ref conts kfun (lambda (_) #f))
  723. (#f #f)
  724. ((and cont ($ $kfun))
  725. (let lp ((k (1+ kfun)) (body (intmap-add! empty-intmap kfun cont)))
  726. (match (intmap-ref conts k (lambda (_) #f))
  727. ((or #f ($ $kfun))
  728. (persistent-intmap body))
  729. (cont
  730. (lp (1+ k) (intmap-add! body k cont))))))))
  731. (let fold ((kfun 0) (seeds seeds))
  732. (match (next-function-body kfun)
  733. (#f (apply values seeds))
  734. (conts
  735. (call-with-values (lambda () (apply f kfun conts seeds))
  736. (lambda seeds
  737. (fold (1+ (intmap-prev conts)) seeds)))))))
  738. (define (eliminate-common-subexpressions conts)
  739. (let ((conts (renumber conts 0)))
  740. (persistent-intmap
  741. (fold-renumbered-functions eliminate-common-subexpressions-in-fun
  742. conts empty-intmap empty-intmap))))