type-fold.scm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779
  1. ;;; Abstract constant folding on CPS
  2. ;;; Copyright (C) 2014-2020 Free Software Foundation, Inc.
  3. ;;;
  4. ;;; This library is free software: you can redistribute it and/or modify
  5. ;;; it under the terms of the GNU Lesser General Public License as
  6. ;;; published by the Free Software Foundation, either version 3 of the
  7. ;;; License, or (at your option) any later version.
  8. ;;;
  9. ;;; This library is distributed in the hope that it will be useful, but
  10. ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
  11. ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. ;;; Lesser General Public License for more details.
  13. ;;;
  14. ;;; You should have received a copy of the GNU Lesser General Public
  15. ;;; License along with this program. If not, see
  16. ;;; <http://www.gnu.org/licenses/>.
  17. ;;; Commentary:
  18. ;;;
  19. ;;; This pass uses the abstract interpretation provided by type analysis
  20. ;;; to fold constant values and type predicates. It is most profitably
  21. ;;; run after CSE, to take advantage of scalar replacement.
  22. ;;;
  23. ;;; Code:
  24. (define-module (language cps type-fold)
  25. #:use-module (ice-9 match)
  26. #:use-module (language cps)
  27. #:use-module (language cps utils)
  28. #:use-module (language cps renumber)
  29. #:use-module (language cps types)
  30. #:use-module (language cps with-cps)
  31. #:use-module (language cps intmap)
  32. #:use-module (language cps intset)
  33. #:use-module (system base target)
  34. #:export (type-fold))
  35. ;; Branch folders.
  36. (define &scalar-types
  37. (logior &fixnum &bignum &flonum &char &special-immediate))
  38. (define (materialize-constant type min max kt kf)
  39. (cond
  40. ((zero? type) (kf))
  41. ((not (and (zero? (logand type (1- type)))
  42. (zero? (logand type (lognot &scalar-types)))
  43. (eqv? min max))) (kf))
  44. ((eqv? type &fixnum) (kt min))
  45. ((eqv? type &bignum) (kt min))
  46. ((eqv? type &flonum) (kt (exact->inexact min)))
  47. ((eqv? type &char) (kt (integer->char min)))
  48. ((eqv? type &special-immediate)
  49. (cond
  50. ((eqv? min &null) (kt '()))
  51. ((eqv? min &nil) (kt #nil))
  52. ((eqv? min &false) (kt #f))
  53. ((eqv? min &true) (kt #t))
  54. ((eqv? min &unspecified) (kt *unspecified*))
  55. ;; FIXME: &undefined here
  56. ((eqv? min &eof) (kt the-eof-object))
  57. (else (kf))))
  58. (else (kf))))
  59. (define *branch-folders* (make-hash-table))
  60. (define-syntax-rule (define-branch-folder op f)
  61. (hashq-set! *branch-folders* 'op f))
  62. (define-syntax-rule (define-branch-folder-alias to from)
  63. (hashq-set! *branch-folders* 'to (hashq-ref *branch-folders* 'from)))
  64. (define-syntax-rule (define-unary-branch-folder* (op param arg min max)
  65. body ...)
  66. (define-branch-folder op (lambda (param arg min max) body ...)))
  67. (define-syntax-rule (define-unary-branch-folder (op arg min max) body ...)
  68. (define-unary-branch-folder* (op param arg min max) body ...))
  69. (define-syntax-rule (define-binary-branch-folder (op arg0 min0 max0
  70. arg1 min1 max1)
  71. body ...)
  72. (define-branch-folder op (lambda (param arg0 min0 max0 arg1 min1 max1) body ...)))
  73. (define (fold-eq-constant? ctype cval type min max)
  74. (cond
  75. ((zero? (logand type ctype)) (values #t #f))
  76. ((eqv? type ctype)
  77. (cond
  78. ((or (< cval min) (< max cval)) (values #t #f))
  79. ((= cval min max) (values #t #t))
  80. (else (values #f #f))))
  81. (else (values #f #f))))
  82. (define-unary-branch-folder* (eq-constant? param type min max)
  83. (call-with-values (lambda () (constant-type param))
  84. (lambda (ctype cval cval*)
  85. ;; cval either equals cval* or is meaningless.
  86. (fold-eq-constant? ctype cval type min max))))
  87. (define-unary-branch-folder (undefined? type min max)
  88. (fold-eq-constant? &special-immediate &undefined type min max))
  89. (define-syntax-rule (define-nullish-predicate-folder op imin imax)
  90. (define-unary-branch-folder (op type min max)
  91. (let ((type* (logand type &special-immediate)))
  92. (cond
  93. ((zero? (logand type &special-immediate)) (values #t #f))
  94. ((eqv? type &special-immediate)
  95. (cond
  96. ((or (< imax min) (< max imin)) (values #t #f))
  97. ((<= imin min max imax) (values #t #t))
  98. (else (values #f #f))))
  99. (else (values #f #f))))))
  100. (define-nullish-predicate-folder null? &null &nil)
  101. (define-nullish-predicate-folder false? &nil &false)
  102. (define-nullish-predicate-folder nil? &null &false) ;; &nil in middle
  103. (define-syntax-rule (define-unary-type-predicate-folder op &type)
  104. (define-unary-branch-folder (op type min max)
  105. (let ((type* (logand type &type)))
  106. (cond
  107. ((zero? type*) (values #t #f))
  108. ((eqv? type type*) (values #t #t))
  109. (else (values #f #f))))))
  110. (define-unary-branch-folder (heap-object? type min max)
  111. (define &immediate-types (logior &fixnum &char &special-immediate))
  112. (cond
  113. ((zero? (logand type &immediate-types)) (values #t #t))
  114. ((type<=? type &immediate-types) (values #t #f))
  115. (else (values #f #f))))
  116. (define-unary-branch-folder (heap-number? type min max)
  117. (define &types (logior &bignum &flonum &fraction &complex))
  118. (cond
  119. ((zero? (logand type &types)) (values #t #f))
  120. ((type<=? type &types) (values #t #t))
  121. (else (values #f #f))))
  122. ;; All the cases that are in compile-bytecode.
  123. (define-unary-type-predicate-folder fixnum? &fixnum)
  124. (define-unary-type-predicate-folder bignum? &bignum)
  125. (define-unary-type-predicate-folder pair? &pair)
  126. (define-unary-type-predicate-folder symbol? &symbol)
  127. (define-unary-type-predicate-folder variable? &box)
  128. (define-unary-type-predicate-folder mutable-vector? &mutable-vector)
  129. (define-unary-type-predicate-folder immutable-vector? &immutable-vector)
  130. (define-unary-type-predicate-folder struct? &struct)
  131. (define-unary-type-predicate-folder string? &string)
  132. (define-unary-type-predicate-folder number? &number)
  133. (define-unary-type-predicate-folder char? &char)
  134. (define-unary-branch-folder (vector? type min max)
  135. (cond
  136. ((zero? (logand type &vector)) (values #t #f))
  137. ((type<=? type &vector) (values #t #t))
  138. (else (values #f #f))))
  139. (define-binary-branch-folder (eq? type0 min0 max0 type1 min1 max1)
  140. (cond
  141. ((or (zero? (logand type0 type1)) (< max0 min1) (< max1 min0))
  142. (values #t #f))
  143. ((and (eqv? type0 type1)
  144. (eqv? min0 min1 max0 max1)
  145. (zero? (logand type0 (1- type0)))
  146. (not (zero? (logand type0 &scalar-types))))
  147. (values #t #t))
  148. (else
  149. (values #f #f))))
  150. (define-branch-folder-alias heap-numbers-equal? eq?)
  151. (define (compare-exact-ranges min0 max0 min1 max1)
  152. (and (cond ((< max0 min1) '<)
  153. ((> min0 max1) '>)
  154. ((= min0 max0 min1 max1) '=)
  155. ((<= max0 min1) '<=)
  156. ((>= min0 max1) '>=)
  157. (else #f))))
  158. (define-binary-branch-folder (< type0 min0 max0 type1 min1 max1)
  159. (if (type<=? (logior type0 type1) &exact-number)
  160. (case (compare-exact-ranges min0 max0 min1 max1)
  161. ((<) (values #t #t))
  162. ((= >= >) (values #t #f))
  163. (else (values #f #f)))
  164. (values #f #f)))
  165. (define-binary-branch-folder (u64-< type0 min0 max0 type1 min1 max1)
  166. (case (compare-exact-ranges min0 max0 min1 max1)
  167. ((<) (values #t #t))
  168. ((= >= >) (values #t #f))
  169. (else (values #f #f))))
  170. (define-branch-folder-alias s64-< u64-<)
  171. ;; We currently cannot define branch folders for floating point
  172. ;; comparison ops like the commented one below because we can't prove
  173. ;; there are no nans involved.
  174. ;;
  175. ;; (define-branch-folder-alias f64-< <)
  176. (define-binary-branch-folder (<= type0 min0 max0 type1 min1 max1)
  177. (if (type<=? (logior type0 type1) &exact-number)
  178. (case (compare-exact-ranges min0 max0 min1 max1)
  179. ((< <= =) (values #t #t))
  180. ((>) (values #t #f))
  181. (else (values #f #f)))
  182. (values #f #f)))
  183. (define-unary-branch-folder* (u64-imm-= c type min max)
  184. (cond
  185. ((= c min max) (values #t #t))
  186. ((<= min c max) (values #f #f))
  187. (else (values #t #f))))
  188. (define-branch-folder-alias s64-imm-= u64-imm-=)
  189. (define-unary-branch-folder* (u64-imm-< c type min max)
  190. (cond
  191. ((< max c) (values #t #t))
  192. ((>= min c) (values #t #f))
  193. (else (values #f #f))))
  194. (define-branch-folder-alias s64-imm-< u64-imm-<)
  195. (define-unary-branch-folder* (imm-u64-< c type min max)
  196. (cond
  197. ((< c min) (values #t #t))
  198. ((>= c max) (values #t #f))
  199. (else (values #f #f))))
  200. (define-branch-folder-alias imm-s64-< imm-u64-<)
  201. (define-binary-branch-folder (= type0 min0 max0 type1 min1 max1)
  202. (cond
  203. ((not (type<=? (logior type0 type1) &exact-number))
  204. (values #f #f))
  205. ((zero? (logand type0 type1))
  206. ;; If both values are exact but of different types, they are not
  207. ;; equal.
  208. (values #t #f))
  209. (else
  210. (case (compare-exact-ranges min0 max0 min1 max1)
  211. ((=) (values #t #t))
  212. ((< >) (values #t #f))
  213. (else (values #f #f))))))
  214. (define-binary-branch-folder (u64-= type0 min0 max0 type1 min1 max1)
  215. (case (compare-exact-ranges min0 max0 min1 max1)
  216. ((=) (values #t #t))
  217. ((< >) (values #t #f))
  218. (else (values #f #f))))
  219. (define-branch-folder-alias s64-= u64-=)
  220. (define *branch-reducers* (make-hash-table))
  221. (define-syntax-rule (define-branch-reducer op f)
  222. (hashq-set! *branch-reducers* 'op f))
  223. (define-syntax-rule (define-binary-branch-reducer
  224. (op cps kf kt src
  225. arg0 type0 min0 max0
  226. arg1 type1 min1 max1)
  227. body ...)
  228. (define-branch-reducer op
  229. (lambda (cps kf kt src param arg0 type0 min0 max0 arg1 type1 min1 max1)
  230. body ...)))
  231. (define-binary-branch-reducer (eq? cps kf kt src
  232. arg0 type0 min0 max0
  233. arg1 type1 min1 max1)
  234. (materialize-constant
  235. type0 min0 max0
  236. (lambda (const)
  237. (with-cps cps
  238. (build-term
  239. ($branch kf kt src 'eq-constant? const (arg1)))))
  240. (lambda ()
  241. (materialize-constant
  242. type1 min1 max1
  243. (lambda (const)
  244. (with-cps cps
  245. (build-term
  246. ($branch kf kt src 'eq-constant? const (arg0)))))
  247. (lambda () (with-cps cps #f))))))
  248. ;; Convert e.g. rsh to rsh/immediate.
  249. (define *primcall-macro-reducers* (make-hash-table))
  250. (define-syntax-rule (define-primcall-macro-reducer op f)
  251. (hashq-set! *primcall-macro-reducers* 'op f))
  252. (define-syntax-rule (define-unary-primcall-macro-reducer (op cps k src
  253. arg type min max)
  254. body ...)
  255. (define-primcall-macro-reducer op
  256. (lambda (cps k src param arg type min max)
  257. body ...)))
  258. (define-syntax-rule (define-binary-primcall-macro-reducer
  259. (op cps k src
  260. arg0 type0 min0 max0
  261. arg1 type1 min1 max1)
  262. body ...)
  263. (define-primcall-macro-reducer op
  264. (lambda (cps k src param arg0 type0 min0 max0 arg1 type1 min1 max1)
  265. body ...)))
  266. (define-binary-primcall-macro-reducer (mul cps k src
  267. arg0 type0 min0 max0
  268. arg1 type1 min1 max1)
  269. (cond
  270. ((and (type<=? type0 &exact-integer) (= min0 max0))
  271. (with-cps cps
  272. (build-term
  273. ($continue k src ($primcall 'mul/immediate min0 (arg1))))))
  274. ((and (type<=? type1 &exact-integer) (= min1 max1))
  275. (with-cps cps
  276. (build-term
  277. ($continue k src ($primcall 'mul/immediate min1 (arg0))))))
  278. (else
  279. (with-cps cps #f))))
  280. (define-binary-primcall-macro-reducer (lsh cps k src
  281. arg0 type0 min0 max0
  282. arg1 type1 min1 max1)
  283. (cond
  284. ((= min1 max1)
  285. (with-cps cps
  286. (build-term
  287. ($continue k src ($primcall 'lsh/immediate min1 (arg0))))))
  288. (else
  289. (with-cps cps #f))))
  290. (define-binary-primcall-macro-reducer (rsh cps k src
  291. arg0 type0 min0 max0
  292. arg1 type1 min1 max1)
  293. (cond
  294. ((= min1 max1)
  295. (with-cps cps
  296. (build-term
  297. ($continue k src ($primcall 'rsh/immediate min1 (arg0))))))
  298. (else
  299. (with-cps cps #f))))
  300. ;; Strength reduction.
  301. (define *primcall-reducers* (make-hash-table))
  302. (define-syntax-rule (define-primcall-reducer op f)
  303. (hashq-set! *primcall-reducers* 'op f))
  304. (define-syntax-rule (define-unary-primcall-reducer (op cps k src param
  305. arg type min max)
  306. body ...)
  307. (define-primcall-reducer op
  308. (lambda (cps k src param arg type min max)
  309. body ...)))
  310. (define-syntax-rule (define-binary-primcall-reducer (op cps k src param
  311. arg0 type0 min0 max0
  312. arg1 type1 min1 max1)
  313. body ...)
  314. (define-primcall-reducer op
  315. (lambda (cps k src param arg0 type0 min0 max0 arg1 type1 min1 max1)
  316. body ...)))
  317. (define (power-of-two? constant)
  318. (and (positive? constant)
  319. (zero? (logand constant (1- constant)))))
  320. (define-binary-primcall-reducer (quo cps k src param
  321. arg0 type0 min0 max0
  322. arg1 type1 min1 max1)
  323. (cond
  324. ((not (type<=? (logior type0 type1) &exact-integer))
  325. (with-cps cps #f))
  326. ((and (eqv? type1 &fixnum) (eqv? min1 max1) (power-of-two? min1))
  327. (with-cps cps
  328. (build-term
  329. ($continue k src
  330. ($primcall 'rsh/immediate (logcount (1- min1)) (arg0))))))
  331. (else
  332. (with-cps cps #f))))
  333. (define-binary-primcall-reducer (rem cps k src param
  334. arg0 type0 min0 max0
  335. arg1 type1 min1 max1)
  336. (cond
  337. ((not (type<=? (logior type0 type1) &exact-integer))
  338. (with-cps cps #f))
  339. ((and (eqv? type1 &fixnum) (eqv? min1 max1) (power-of-two? min1)
  340. (<= 0 min0))
  341. (with-cps cps
  342. (letv mask)
  343. (letk kmask
  344. ($kargs ('mask) (mask)
  345. ($continue k src
  346. ($primcall 'logand #f (arg0 mask)))))
  347. (build-term
  348. ($continue kmask src ($const (1- min1))))))
  349. (else
  350. (with-cps cps #f))))
  351. (define-binary-primcall-reducer (mod cps k src param
  352. arg0 type0 min0 max0
  353. arg1 type1 min1 max1)
  354. (cond
  355. ((not (type<=? (logior type0 type1) &exact-integer))
  356. (with-cps cps #f))
  357. ((and (eqv? type1 &fixnum) (eqv? min1 max1) (power-of-two? min1))
  358. (with-cps cps
  359. (letv mask)
  360. (letk kmask
  361. ($kargs ('mask) (mask)
  362. ($continue k src
  363. ($primcall 'logand #f (arg0 mask)))))
  364. (build-term
  365. ($continue kmask src ($const (1- min1))))))
  366. (else
  367. (with-cps cps #f))))
  368. (define-unary-primcall-reducer (mul/immediate cps k src constant
  369. arg type min max)
  370. (cond
  371. ((not (type<=? type &number))
  372. (with-cps cps #f))
  373. ((eqv? constant -1)
  374. ;; (* arg -1) -> (- 0 arg)
  375. (with-cps cps
  376. ($ (with-cps-constants ((zero 0))
  377. (build-term
  378. ($continue k src ($primcall 'sub #f (zero arg))))))))
  379. ((and (eqv? constant 0) (type<=? type &exact-number))
  380. ;; (* arg 0) -> 0 if arg is exact
  381. (with-cps cps
  382. (build-term ($continue k src ($const 0)))))
  383. ((eqv? constant 1)
  384. ;; (* arg 1) -> arg
  385. (with-cps cps
  386. (build-term ($continue k src ($values (arg))))))
  387. ((eqv? constant 2)
  388. ;; (* arg 2) -> (+ arg arg)
  389. (with-cps cps
  390. (build-term ($continue k src ($primcall 'add #f (arg arg))))))
  391. ((and (type<=? type &exact-integer)
  392. (positive? constant)
  393. (zero? (logand constant (1- constant))))
  394. ;; (* arg power-of-2) -> (lsh arg (log2 power-of-2))
  395. (let ((n (let lp ((bits 0) (constant constant))
  396. (if (= constant 1) bits (lp (1+ bits) (ash constant -1))))))
  397. (with-cps cps
  398. (build-term ($continue k src ($primcall 'lsh/immediate n (arg)))))))
  399. (else
  400. (with-cps cps #f))))
  401. (define-binary-primcall-reducer (logbit? cps k src param
  402. arg0 type0 min0 max0
  403. arg1 type1 min1 max1)
  404. (define (compute-mask cps kmask src)
  405. (if (eq? min0 max0)
  406. (with-cps cps
  407. (build-term
  408. ($continue kmask src ($const (ash 1 min0)))))
  409. (with-cps cps
  410. ($ (with-cps-constants ((one 1))
  411. (letv n)
  412. (letk kn ($kargs ('n) (n)
  413. ($continue kmask src
  414. ($primcall 'lsh #f (one n)))))
  415. (build-term
  416. ($continue kn src ($primcall 'untag-fixnum #f (arg0)))))))))
  417. (cond
  418. ((and (type<=? type0 &exact-integer)
  419. (<= 0 min0 (target-most-positive-fixnum))
  420. (<= 0 max0 (target-most-positive-fixnum)))
  421. (with-cps cps
  422. (letv mask res u64)
  423. (letk kt ($kargs () () ($continue k src ($const #t))))
  424. (letk kf ($kargs () () ($continue k src ($const #f))))
  425. (letk ku64 ($kargs (#f) (u64)
  426. ($branch kt kf src 's64-imm-= 0 (u64))))
  427. (letk kand ($kargs (#f) (res)
  428. ($continue ku64 src ($primcall 'untag-fixnum #f (res)))))
  429. (letk kmask ($kargs (#f) (mask)
  430. ($continue kand src
  431. ($primcall 'logand #f (mask arg1)))))
  432. ($ (compute-mask kmask src))))
  433. (else
  434. (with-cps cps #f))))
  435. (define-binary-primcall-reducer (logior cps k src param
  436. arg0 type0 min0 max0
  437. arg1 type1 min1 max1)
  438. (cond
  439. ((type<=? (logior type0 type1) &exact-integer)
  440. (cond
  441. ((= 0 min0 max0)
  442. (with-cps cps
  443. (build-term
  444. ($continue k src ($values (arg1))))))
  445. ((= 0 min1 max1)
  446. (with-cps cps
  447. (build-term
  448. ($continue k src ($values (arg0))))))
  449. (else
  450. (with-cps cps #f))))
  451. (else
  452. (with-cps cps #f))))
  453. (define-unary-primcall-reducer (u64->scm cps k src constant arg type min max)
  454. (cond
  455. ((<= max (target-most-positive-fixnum))
  456. (with-cps cps
  457. (letv s64)
  458. (letk ks64 ($kargs ('s64) (s64)
  459. ($continue k src
  460. ($primcall 'tag-fixnum #f (s64)))))
  461. (build-term
  462. ($continue ks64 src
  463. ($primcall 'u64->s64 #f (arg))))))
  464. (else
  465. (with-cps cps #f))))
  466. (define-unary-primcall-reducer (s64->scm cps k src constant arg type min max)
  467. (cond
  468. ((<= (target-most-negative-fixnum) min max (target-most-positive-fixnum))
  469. (with-cps cps
  470. (build-term
  471. ($continue k src
  472. ($primcall 'tag-fixnum #f (arg))))))
  473. (else
  474. (with-cps cps #f))))
  475. (define-unary-primcall-reducer (scm->s64 cps k src constant arg type min max)
  476. (cond
  477. ((and (type<=? type &exact-integer)
  478. (<= (target-most-negative-fixnum) min max (target-most-positive-fixnum)))
  479. (with-cps cps
  480. (build-term
  481. ($continue k src
  482. ($primcall 'untag-fixnum #f (arg))))))
  483. (else
  484. (with-cps cps #f))))
  485. (define-unary-primcall-reducer (scm->u64 cps k src constant arg type min max)
  486. (cond
  487. ((and (type<=? type &exact-integer)
  488. (<= 0 min max (target-most-positive-fixnum)))
  489. (with-cps cps
  490. (letv s64)
  491. (letk ks64 ($kargs ('s64) (s64)
  492. ($continue k src
  493. ($primcall 's64->u64 #f (s64)))))
  494. (build-term
  495. ($continue ks64 src
  496. ($primcall 'untag-fixnum #f (arg))))))
  497. (else
  498. (with-cps cps #f))))
  499. (define-unary-primcall-reducer (scm->f64 cps k src constant arg type min max)
  500. (cond
  501. ((and (type<=? type &exact-integer)
  502. (<= (target-most-negative-fixnum) min max (target-most-positive-fixnum)))
  503. (with-cps cps
  504. (letv s64)
  505. (letk ks64 ($kargs ('s64) (s64)
  506. ($continue k src
  507. ($primcall 's64->f64 #f (s64)))))
  508. (build-term
  509. ($continue ks64 src
  510. ($primcall 'untag-fixnum #f (arg))))))
  511. (else
  512. (with-cps cps #f))))
  513. (define-unary-primcall-reducer (inexact cps k src constant arg type min max)
  514. (cond
  515. ((and (type<=? type &exact-integer)
  516. (<= (target-most-negative-fixnum) min max (target-most-positive-fixnum)))
  517. (with-cps cps
  518. (letv s64 f64)
  519. (letk kf64 ($kargs ('f64) (f64)
  520. ($continue k src
  521. ($primcall 'f64->scm #f (f64)))))
  522. (letk ks64 ($kargs ('s64) (s64)
  523. ($continue kf64 src
  524. ($primcall 's64->f64 #f (s64)))))
  525. (build-term
  526. ($continue ks64 src
  527. ($primcall 'untag-fixnum #f (arg))))))
  528. ((type<=? type &flonum)
  529. (with-cps cps
  530. (build-term
  531. ($continue k src ($primcall 'values #f (arg))))))
  532. (else
  533. (with-cps cps #f))))
  534. (define (local-type-fold start end cps)
  535. (let ((types (infer-types cps start)))
  536. (define (fold-primcall cps label names vars k src op param args def)
  537. (call-with-values (lambda () (lookup-post-type types label def 0))
  538. (lambda (type min max)
  539. (materialize-constant
  540. type min max
  541. (lambda (val)
  542. ;; (pk 'folded src op args val)
  543. (with-cps cps
  544. (letv v*)
  545. (letk k* ($kargs (#f) (v*)
  546. ($continue k src ($const val))))
  547. ;; Rely on DCE to elide this expression, if possible.
  548. (setk label
  549. ($kargs names vars
  550. ($continue k* src ($primcall op param args))))))
  551. (lambda () #f)))))
  552. (define (transform-primcall f cps label names vars k src op param args)
  553. (and f
  554. (match args
  555. ((arg0)
  556. (call-with-values (lambda () (lookup-pre-type types label arg0))
  557. (lambda (type0 min0 max0)
  558. (call-with-values (lambda ()
  559. (f cps k src param arg0 type0 min0 max0))
  560. (lambda (cps term)
  561. (and term
  562. (with-cps cps
  563. (setk label ($kargs names vars ,term)))))))))
  564. ((arg0 arg1)
  565. (call-with-values (lambda () (lookup-pre-type types label arg0))
  566. (lambda (type0 min0 max0)
  567. (call-with-values (lambda () (lookup-pre-type types label arg1))
  568. (lambda (type1 min1 max1)
  569. (call-with-values (lambda ()
  570. (f cps k src param arg0 type0 min0 max0
  571. arg1 type1 min1 max1))
  572. (lambda (cps term)
  573. (and term
  574. (with-cps cps
  575. (setk label ($kargs names vars ,term)))))))))))
  576. (_ #f))))
  577. (define (reduce-primcall cps label names vars k src op param args)
  578. (cond
  579. ((transform-primcall (hashq-ref *primcall-macro-reducers* op)
  580. cps label names vars k src op param args)
  581. => (lambda (cps)
  582. (match (intmap-ref cps label)
  583. (($ $kargs names vars
  584. ($ $continue k src ($ $primcall op param args)))
  585. (reduce-primcall cps label names vars k src op param args)))))
  586. ((transform-primcall (hashq-ref *primcall-reducers* op)
  587. cps label names vars k src op param args))
  588. (else cps)))
  589. (define (reduce-branch cps label names vars kf kt src op param args)
  590. (and=>
  591. (hashq-ref *branch-reducers* op)
  592. (lambda (reducer)
  593. (match args
  594. ((arg0 arg1)
  595. (call-with-values (lambda () (lookup-pre-type types label arg0))
  596. (lambda (type0 min0 max0)
  597. (call-with-values (lambda () (lookup-pre-type types label arg1))
  598. (lambda (type1 min1 max1)
  599. (call-with-values (lambda ()
  600. (reducer cps kf kt src param
  601. arg0 type0 min0 max0
  602. arg1 type1 min1 max1))
  603. (lambda (cps term)
  604. (and term
  605. (with-cps cps
  606. (setk label
  607. ($kargs names vars ,term)))))))))))))))
  608. (define (branch-folded cps label names vars src k)
  609. (with-cps cps
  610. (setk label
  611. ($kargs names vars
  612. ($continue k src ($values ()))))))
  613. (define (fold-unary-branch cps label names vars kf kt src op param arg)
  614. (and=>
  615. (hashq-ref *branch-folders* op)
  616. (lambda (folder)
  617. (call-with-values (lambda () (lookup-pre-type types label arg))
  618. (lambda (type min max)
  619. (call-with-values (lambda () (folder param type min max))
  620. (lambda (f? v)
  621. ;; (when f? (pk 'folded-unary-branch label op arg v))
  622. (and f?
  623. (branch-folded cps label names vars src
  624. (if v kt kf))))))))))
  625. (define (fold-binary-branch cps label names vars kf kt src op param arg0 arg1)
  626. (and=>
  627. (hashq-ref *branch-folders* op)
  628. (lambda (folder)
  629. (call-with-values (lambda () (lookup-pre-type types label arg0))
  630. (lambda (type0 min0 max0)
  631. (call-with-values (lambda () (lookup-pre-type types label arg1))
  632. (lambda (type1 min1 max1)
  633. (call-with-values (lambda ()
  634. (folder param type0 min0 max0 type1 min1 max1))
  635. (lambda (f? v)
  636. ;; (when f? (pk 'folded-binary-branch label op arg0 arg1 v))
  637. (and f?
  638. (branch-folded cps label names vars src
  639. (if v kt kf))))))))))))
  640. (define (fold-branch cps label names vars kf kt src op param args)
  641. (match args
  642. ((x)
  643. (fold-unary-branch cps label names vars kf kt src op param x))
  644. ((x y)
  645. (fold-binary-branch cps label names vars kf kt src op param x y))))
  646. (define (visit-primcall cps label names vars k src op param args)
  647. ;; We might be able to fold primcalls that define a value.
  648. (match (intmap-ref cps k)
  649. (($ $kargs (_) (def))
  650. (or (fold-primcall cps label names vars k src op param args def)
  651. (reduce-primcall cps label names vars k src op param args)))
  652. (_
  653. (reduce-primcall cps label names vars k src op param args))))
  654. (define (visit-branch cps label names vars kf kt src op param args)
  655. ;; We might be able to fold primcalls that branch.
  656. (or (fold-branch cps label names vars kf kt src op param args)
  657. (reduce-branch cps label names vars kf kt src op param args)
  658. cps))
  659. (define (visit-switch cps label names vars kf kt* src arg)
  660. ;; We might be able to fold or reduce a switch.
  661. (let ((ntargets (length kt*)))
  662. (call-with-values (lambda () (lookup-pre-type types label arg))
  663. (lambda (type min max)
  664. (cond
  665. ((<= ntargets min)
  666. (branch-folded cps label names vars src kf))
  667. ((= min max)
  668. (branch-folded cps label names vars src (list-ref kt* min)))
  669. (else
  670. ;; There are two more optimizations we could do here: one,
  671. ;; if max is less than ntargets, we can prune targets at
  672. ;; the end of the switch, and perhaps reduce the switch
  673. ;; back to a branch; and two, if min is greater than 0,
  674. ;; then we can subtract off min and prune targets at the
  675. ;; beginning. Not done yet though.
  676. cps))))))
  677. (let lp ((label start) (cps cps))
  678. (if (<= label end)
  679. (lp (1+ label)
  680. (match (intmap-ref cps label)
  681. (($ $kargs names vars ($ $continue k src
  682. ($ $primcall op param args)))
  683. (visit-primcall cps label names vars k src op param args))
  684. (($ $kargs names vars ($ $branch kf kt src op param args))
  685. (visit-branch cps label names vars kf kt src op param args))
  686. (($ $kargs names vars ($ $switch kf kt* src arg))
  687. (visit-switch cps label names vars kf kt* src arg))
  688. (_ cps)))
  689. cps))))
  690. (define (fold-functions-in-renumbered-program f conts seed)
  691. (let* ((conts (persistent-intmap conts))
  692. (end (1+ (intmap-prev conts))))
  693. (let lp ((label 0) (seed seed))
  694. (if (eqv? label end)
  695. seed
  696. (match (intmap-ref conts label)
  697. (($ $kfun src meta self tail clause)
  698. (lp (1+ tail) (f label tail seed))))))))
  699. (define (type-fold conts)
  700. ;; Type analysis wants a program whose labels are sorted.
  701. (let ((conts (renumber conts)))
  702. (with-fresh-name-state conts
  703. (persistent-intmap
  704. (fold-functions-in-renumbered-program local-type-fold conts conts)))))