type-fold.scm 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076
  1. ;;; Abstract constant folding on CPS
  2. ;;; Copyright (C) 2014-2020, 2023 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. ;; All the cases that are in compile-bytecode.
  117. (define-unary-type-predicate-folder bignum? &bignum)
  118. (define-unary-type-predicate-folder bitvector? &bitvector)
  119. (define-unary-type-predicate-folder bytevector? &bytevector)
  120. (define-unary-type-predicate-folder char? &char)
  121. (define-unary-type-predicate-folder compnum? &complex)
  122. (define-unary-type-predicate-folder fixnum? &fixnum)
  123. (define-unary-type-predicate-folder flonum? &flonum)
  124. (define-unary-type-predicate-folder fluid? &fluid)
  125. (define-unary-type-predicate-folder fracnum? &fraction)
  126. (define-unary-type-predicate-folder immutable-vector? &immutable-vector)
  127. (define-unary-type-predicate-folder keyword? &keyword)
  128. (define-unary-type-predicate-folder mutable-vector? &mutable-vector)
  129. (define-unary-type-predicate-folder pair? &pair)
  130. (define-unary-type-predicate-folder pointer? &pointer)
  131. (define-unary-type-predicate-folder program? &procedure)
  132. (define-unary-type-predicate-folder string? &string)
  133. (define-unary-type-predicate-folder struct? &struct)
  134. (define-unary-type-predicate-folder symbol? &symbol)
  135. (define-unary-type-predicate-folder syntax? &syntax)
  136. (define-unary-type-predicate-folder variable? &box)
  137. (define-unary-branch-folder (vector? type min max)
  138. (cond
  139. ((zero? (logand type &vector)) (values #t #f))
  140. ((type<=? type &vector) (values #t #t))
  141. (else (values #f #f))))
  142. (define-unary-branch-folder (procedure? type min max)
  143. (define applicable-types (logior &procedure &struct &other-heap-object))
  144. (cond
  145. ((zero? (logand type applicable-types)) (values #t #f))
  146. ((= type &procedure) (values #t #t))
  147. (else (values #f #f))))
  148. (let ((&heap-number (logior &bignum &flonum &fraction &complex)))
  149. (define-unary-type-predicate-folder heap-number? &heap-number))
  150. (define-unary-type-predicate-folder number? &number)
  151. (define-unary-type-predicate-folder complex? &number)
  152. (define-unary-type-predicate-folder real? &real)
  153. (define-unary-type-predicate-folder exact-integer? &exact-integer)
  154. (define-unary-type-predicate-folder exact? &exact-number)
  155. (let ((&inexact (logior &flonum &complex)))
  156. (define-unary-type-predicate-folder inexact? &inexact))
  157. (define-unary-branch-folder (rational? type min max)
  158. (cond
  159. ((zero? (logand type &number)) (values #t #f))
  160. ((eqv? type (logand type &exact-number)) (values #t #t))
  161. (else (values #f #f))))
  162. (define-unary-branch-folder (integer? type min max)
  163. (cond
  164. ((zero? (logand type &number)) (values #t #f))
  165. ((eqv? type (logand type &exact-integer)) (values #t #t))
  166. (else (values #f #f))))
  167. (define-binary-branch-folder (eq? type0 min0 max0 type1 min1 max1)
  168. (cond
  169. ((or (zero? (logand type0 type1)) (< max0 min1) (< max1 min0))
  170. (values #t #f))
  171. ((and (eqv? type0 type1)
  172. (eqv? min0 min1 max0 max1)
  173. (zero? (logand type0 (1- type0)))
  174. (not (zero? (logand type0 &scalar-types))))
  175. (values #t #t))
  176. (else
  177. (values #f #f))))
  178. (define-branch-folder-alias heap-numbers-equal? eq?)
  179. (define (compare-exact-ranges min0 max0 min1 max1)
  180. (and (cond ((< max0 min1) '<)
  181. ((> min0 max1) '>)
  182. ((= min0 max0 min1 max1) '=)
  183. ((<= max0 min1) '<=)
  184. ((>= min0 max1) '>=)
  185. (else #f))))
  186. (define-binary-branch-folder (< type0 min0 max0 type1 min1 max1)
  187. (if (type<=? (logior type0 type1) &exact-number)
  188. (case (compare-exact-ranges min0 max0 min1 max1)
  189. ((<) (values #t #t))
  190. ((= >= >) (values #t #f))
  191. (else (values #f #f)))
  192. (values #f #f)))
  193. (define-binary-branch-folder (u64-< type0 min0 max0 type1 min1 max1)
  194. (case (compare-exact-ranges min0 max0 min1 max1)
  195. ((<) (values #t #t))
  196. ((= >= >) (values #t #f))
  197. (else (values #f #f))))
  198. (define-branch-folder-alias s64-< u64-<)
  199. ;; We currently cannot define branch folders for floating point
  200. ;; comparison ops like the commented one below because we can't prove
  201. ;; there are no nans involved.
  202. ;;
  203. ;; (define-branch-folder-alias f64-< <)
  204. (define-binary-branch-folder (<= type0 min0 max0 type1 min1 max1)
  205. (if (type<=? (logior type0 type1) &exact-number)
  206. (case (compare-exact-ranges min0 max0 min1 max1)
  207. ((< <= =) (values #t #t))
  208. ((>) (values #t #f))
  209. (else (values #f #f)))
  210. (values #f #f)))
  211. (define-unary-branch-folder* (u64-imm-= c type min max)
  212. (cond
  213. ((= c min max) (values #t #t))
  214. ((<= min c max) (values #f #f))
  215. (else (values #t #f))))
  216. (define-branch-folder-alias s64-imm-= u64-imm-=)
  217. (define-unary-branch-folder* (u64-imm-< c type min max)
  218. (cond
  219. ((< max c) (values #t #t))
  220. ((>= min c) (values #t #f))
  221. (else (values #f #f))))
  222. (define-branch-folder-alias s64-imm-< u64-imm-<)
  223. (define-unary-branch-folder* (imm-u64-< c type min max)
  224. (cond
  225. ((< c min) (values #t #t))
  226. ((>= c max) (values #t #f))
  227. (else (values #f #f))))
  228. (define-branch-folder-alias imm-s64-< imm-u64-<)
  229. (define-binary-branch-folder (= type0 min0 max0 type1 min1 max1)
  230. (cond
  231. ((not (type<=? (logior type0 type1) &exact-number))
  232. (values #f #f))
  233. ((zero? (logand type0 type1))
  234. ;; If both values are exact but of different types, they are not
  235. ;; equal.
  236. (values #t #f))
  237. (else
  238. (case (compare-exact-ranges min0 max0 min1 max1)
  239. ((=) (values #t #t))
  240. ((< >) (values #t #f))
  241. (else (values #f #f))))))
  242. (define-binary-branch-folder (u64-= type0 min0 max0 type1 min1 max1)
  243. (case (compare-exact-ranges min0 max0 min1 max1)
  244. ((=) (values #t #t))
  245. ((< >) (values #t #f))
  246. (else (values #f #f))))
  247. (define-branch-folder-alias s64-= u64-=)
  248. (define *branch-reducers* (make-hash-table))
  249. (define-syntax-rule (define-branch-reducer op f)
  250. (hashq-set! *branch-reducers* 'op f))
  251. (define-syntax-rule (define-branch-reducer-aliases def use ...)
  252. (let ((proc (or (hashq-ref *branch-reducers* 'def)
  253. (error "not found" 'def))))
  254. (define-branch-reducer use proc)
  255. ...))
  256. (define-syntax-rule (define-unary-branch-reducer
  257. (op cps kf kt src arg type min max)
  258. body ...)
  259. (define-branch-reducer op
  260. (lambda (cps kf kt src param arg type min max)
  261. body ...)))
  262. (define-syntax-rule (define-binary-branch-reducer
  263. (op cps kf kt src
  264. arg0 type0 min0 max0
  265. arg1 type1 min1 max1)
  266. body ...)
  267. (define-branch-reducer op
  268. (lambda (cps kf kt src param arg0 type0 min0 max0 arg1 type1 min1 max1)
  269. body ...)))
  270. (define-unary-branch-reducer (number? cps kf kt src arg type min max)
  271. (let ((number-types (logand type &number)))
  272. (when (or (zero? number-types) (eqv? type number-types))
  273. (error "should have folded!"))
  274. (define-syntax-rule (define-heap-number-test test &type pred next-test)
  275. (define (test cps)
  276. (if (logtest type &type)
  277. (with-cps cps
  278. (let$ kf (next-test))
  279. (letk k ($kargs () ()
  280. ($branch kf kt src 'pred #f (arg))))
  281. k)
  282. (next-test cps))))
  283. (define (done cps) (with-cps cps kf))
  284. (define-heap-number-test compnum-test &complex compnum? done)
  285. (define-heap-number-test fracnum-test &fraction fracnum? compnum-test)
  286. (define-heap-number-test bignum-test &bignum bignum? fracnum-test)
  287. (define-heap-number-test flonum-test &flonum flonum? bignum-test)
  288. (define (heap-number-tests cps) (flonum-test cps))
  289. (cond
  290. ((eqv? number-types &number)
  291. ;; Generic: no reduction.
  292. (with-cps cps #f))
  293. ((eqv? number-types &fixnum)
  294. (with-cps cps
  295. (build-term
  296. ($branch kf kt src 'fixnum? #f (arg)))))
  297. ((logtest type &fixnum)
  298. (with-cps cps
  299. (let$ ktest (heap-number-tests))
  300. (letk kheap ($kargs () ()
  301. ($branch kf ktest src 'heap-object? #f (arg))))
  302. (build-term
  303. ($branch kheap kt src 'fixnum? #f (arg)))))
  304. (else
  305. (with-cps cps
  306. (let$ ktest (heap-number-tests))
  307. (build-term
  308. ($branch kf ktest src 'heap-object? #f (arg))))))))
  309. (define-branch-reducer-aliases number? complex?)
  310. (define-unary-branch-reducer (real? cps kf kt src arg type min max)
  311. (let ((real-types (logand type &real)))
  312. (when (or (zero? real-types) (eqv? type real-types))
  313. (error "should have folded!"))
  314. (define-syntax-rule (define-heap-number-test test &type pred next-test)
  315. (define (test cps)
  316. (if (logtest type &type)
  317. (with-cps cps
  318. (let$ kf (next-test))
  319. (letk k ($kargs () ()
  320. ($branch kf kt src 'pred #f (arg))))
  321. k)
  322. (next-test cps))))
  323. (define (done cps) (with-cps cps kf))
  324. (define-heap-number-test fracnum-test &fraction fracnum? done)
  325. (define-heap-number-test bignum-test &bignum bignum? fracnum-test)
  326. (define-heap-number-test flonum-test &flonum flonum? bignum-test)
  327. (define (heap-number-tests cps) (flonum-test cps))
  328. (cond
  329. ((eqv? real-types &real)
  330. ;; Generic: no reduction.
  331. (with-cps cps #f))
  332. ((eqv? real-types &fixnum)
  333. (with-cps cps
  334. (build-term
  335. ($branch kf kt src 'fixnum? #f (arg)))))
  336. ((logtest type &fixnum)
  337. (with-cps cps
  338. (let$ ktest (heap-number-tests))
  339. (letk kheap ($kargs () ()
  340. ($branch kf ktest src 'heap-object? #f (arg))))
  341. (build-term
  342. ($branch kheap kt src 'fixnum? #f (arg)))))
  343. (else
  344. (with-cps cps
  345. (let$ ktest (heap-number-tests))
  346. (build-term
  347. ($branch kf ktest src 'heap-object? #f (arg))))))))
  348. (define-unary-branch-reducer (rational? cps kf kt src arg type min max)
  349. (let ((number-types (logand type &number)))
  350. (when (or (zero? number-types) (eqv? type (logand type &exact-number)))
  351. (error "should have folded!"))
  352. (define-syntax-rule (define-heap-number-test test &type pred next-test)
  353. (define (test cps)
  354. (if (logtest type &type)
  355. (with-cps cps
  356. (let$ kf (next-test))
  357. (letk k ($kargs () ()
  358. ($branch kf kt src 'pred #f (arg))))
  359. k)
  360. (next-test cps))))
  361. (define (done cps) (with-cps cps kf))
  362. (define-heap-number-test fracnum-test &fraction fracnum? done)
  363. (define-heap-number-test bignum-test &bignum bignum? fracnum-test)
  364. (define (heap-number-tests cps) (bignum-test cps))
  365. (cond
  366. ((logtest type (logior &complex &flonum))
  367. ;; Too annoying to inline inf / nan tests.
  368. (with-cps cps #f))
  369. ((eqv? number-types &fixnum)
  370. (with-cps cps
  371. (build-term
  372. ($branch kf kt src 'fixnum? #f (arg)))))
  373. ((logtest type &fixnum)
  374. (with-cps cps
  375. (let$ ktest (heap-number-tests))
  376. (letk kheap ($kargs () ()
  377. ($branch kf ktest src 'heap-object? #f (arg))))
  378. (build-term
  379. ($branch kheap kt src 'fixnum? #f (arg)))))
  380. (else
  381. (with-cps cps
  382. (let$ ktest (heap-number-tests))
  383. (build-term
  384. ($branch kf ktest src 'heap-object? #f (arg))))))))
  385. (define-unary-branch-reducer (integer? cps kf kt src arg type min max)
  386. (define &integer-types (logior &fixnum &bignum &flonum &complex))
  387. (let ((integer-types (logand type &integer-types)))
  388. (when (or (zero? integer-types) (eqv? type (logand type &exact-integer)))
  389. (error "should have folded!"))
  390. (define-syntax-rule (define-heap-number-test test &type pred next-test)
  391. (define (test cps)
  392. (if (logtest type &type)
  393. (with-cps cps
  394. (let$ kf (next-test))
  395. (letk k ($kargs () ()
  396. ($branch kf kt src 'pred #f (arg))))
  397. k)
  398. (next-test cps))))
  399. (define (done cps) (with-cps cps kf))
  400. (define-heap-number-test bignum-test &bignum bignum? done)
  401. (define (heap-number-tests cps) (bignum-test cps))
  402. (cond
  403. ((logtest type (logior &complex &flonum))
  404. ;; Too annoying to inline integer tests.
  405. (with-cps cps #f))
  406. ((eqv? integer-types &fixnum)
  407. (with-cps cps
  408. (build-term
  409. ($branch kf kt src 'fixnum? #f (arg)))))
  410. ((logtest type &fixnum)
  411. (with-cps cps
  412. (let$ ktest (heap-number-tests))
  413. (letk kheap ($kargs () ()
  414. ($branch kf ktest src 'heap-object? #f (arg))))
  415. (build-term
  416. ($branch kheap kt src 'fixnum? #f (arg)))))
  417. (else
  418. (with-cps cps
  419. (let$ ktest (heap-number-tests))
  420. (build-term
  421. ($branch kf ktest src 'heap-object? #f (arg))))))))
  422. (define-unary-branch-reducer (exact-integer? cps kf kt src arg type min max)
  423. (let ((integer-types (logand type &exact-integer)))
  424. (when (or (zero? integer-types) (eqv? type integer-types))
  425. (error "should have folded!"))
  426. (cond
  427. ((eqv? integer-types &fixnum)
  428. (with-cps cps
  429. (build-term
  430. ($branch kf kt src 'fixnum? #f (arg)))))
  431. ((eqv? integer-types &bignum)
  432. (with-cps cps
  433. (letk kbig? ($kargs () ()
  434. ($branch kf kt src 'bignum? #f (arg))))
  435. (build-term
  436. ($branch kf kbig? src 'heap-object? #f (arg)))))
  437. (else
  438. ;; No reduction.
  439. (with-cps cps #f)))))
  440. (define-unary-branch-reducer (exact? cps kf kt src arg type min max)
  441. (let ((exact-types (logand type &exact-number)))
  442. (when (or (zero? exact-types) (eqv? type exact-types))
  443. (error "should have folded!"))
  444. ;; We have already passed a number? check, so we can assume either
  445. ;; fixnum or heap number.
  446. (define-syntax-rule (define-number-test test &type pred next-test)
  447. (define (test cps)
  448. (if (logtest type &type)
  449. (with-cps cps
  450. (let$ kf (next-test))
  451. (letk k ($kargs () ()
  452. ($branch kf kt src 'pred #f (arg))))
  453. k)
  454. (next-test cps))))
  455. (define (done cps) (with-cps cps kf))
  456. (define-number-test fracnum-test &fraction fracnum? done)
  457. (define-number-test bignum-test &bignum bignum? fracnum-test)
  458. (define-number-test fixnum-test &fixnum fixnum? bignum-test)
  459. (define (number-tests cps) (fixnum-test cps))
  460. (cond
  461. ((eqv? exact-types &exact-number)
  462. ;; Generic: no reduction.
  463. (with-cps cps #f))
  464. (else
  465. (with-cps cps
  466. (let$ ktest (number-tests))
  467. (build-term
  468. ($continue ktest #f ($values ()))))))))
  469. (define-unary-branch-reducer (inexact? cps kf kt src arg type min max)
  470. (define &inexact-number (logior &flonum &complex))
  471. (let ((inexact-types (logand type &inexact-number)))
  472. (when (or (zero? inexact-types) (eqv? type inexact-types))
  473. (error "should have folded!"))
  474. ;; We have already passed a number? check, so we can assume either
  475. ;; fixnum or heap number.
  476. (cond
  477. ((eqv? (logand type &exact-number) &fixnum)
  478. (with-cps cps
  479. (build-term
  480. ($branch kt kf src 'fixnum? #f (arg)))))
  481. ((logtest type &fixnum)
  482. (cond
  483. ((eqv? inexact-types &flonum)
  484. (with-cps cps
  485. (letk kflo ($kargs () ()
  486. ($branch kf kt src 'flonum? #f (arg))))
  487. (build-term
  488. ($branch kflo kf src 'fixnum? #f (arg)))))
  489. ((eqv? inexact-types &complex)
  490. (with-cps cps
  491. (letk kcomp ($kargs () ()
  492. ($branch kf kt src 'compnum? #f (arg))))
  493. (build-term
  494. ($branch kcomp kf src 'fixnum? #f (arg)))))
  495. (else
  496. ;; Generic: no reduction.
  497. (with-cps cps #f))))
  498. ((eqv? inexact-types &flonum)
  499. (with-cps cps
  500. (build-term
  501. ($branch kf kt src 'flonum? #f (arg)))))
  502. ((eqv? inexact-types &complex)
  503. (with-cps cps
  504. (build-term
  505. ($branch kf kt src 'compnum? #f (arg)))))
  506. (else
  507. ;; Still specialize, as we avoid heap-object?.
  508. (with-cps cps
  509. (letk kcomp ($kargs () ()
  510. ($branch kf kt src 'compnum? #f (arg))))
  511. (build-term
  512. ($branch kcomp kt src 'flonum? #f (arg))))))))
  513. (define-binary-branch-reducer (eq? cps kf kt src
  514. arg0 type0 min0 max0
  515. arg1 type1 min1 max1)
  516. (materialize-constant
  517. type0 min0 max0
  518. (lambda (const)
  519. (with-cps cps
  520. (build-term
  521. ($branch kf kt src 'eq-constant? const (arg1)))))
  522. (lambda ()
  523. (materialize-constant
  524. type1 min1 max1
  525. (lambda (const)
  526. (with-cps cps
  527. (build-term
  528. ($branch kf kt src 'eq-constant? const (arg0)))))
  529. (lambda () (with-cps cps #f))))))
  530. ;; Convert e.g. rsh to rsh/immediate.
  531. (define *primcall-macro-reducers* (make-hash-table))
  532. (define-syntax-rule (define-primcall-macro-reducer op f)
  533. (hashq-set! *primcall-macro-reducers* 'op f))
  534. (define-syntax-rule (define-unary-primcall-macro-reducer (op cps k src
  535. arg type min max)
  536. body ...)
  537. (define-primcall-macro-reducer op
  538. (lambda (cps k src param arg type min max)
  539. body ...)))
  540. (define-syntax-rule (define-binary-primcall-macro-reducer
  541. (op cps k src
  542. arg0 type0 min0 max0
  543. arg1 type1 min1 max1)
  544. body ...)
  545. (define-primcall-macro-reducer op
  546. (lambda (cps k src param arg0 type0 min0 max0 arg1 type1 min1 max1)
  547. body ...)))
  548. (define-binary-primcall-macro-reducer (mul cps k src
  549. arg0 type0 min0 max0
  550. arg1 type1 min1 max1)
  551. (cond
  552. ((and (type<=? type0 &exact-integer) (= min0 max0))
  553. (with-cps cps
  554. (build-term
  555. ($continue k src ($primcall 'mul/immediate min0 (arg1))))))
  556. ((and (type<=? type1 &exact-integer) (= min1 max1))
  557. (with-cps cps
  558. (build-term
  559. ($continue k src ($primcall 'mul/immediate min1 (arg0))))))
  560. (else
  561. (with-cps cps #f))))
  562. (define-binary-primcall-macro-reducer (lsh cps k src
  563. arg0 type0 min0 max0
  564. arg1 type1 min1 max1)
  565. (cond
  566. ((= min1 max1)
  567. (with-cps cps
  568. (build-term
  569. ($continue k src ($primcall 'lsh/immediate min1 (arg0))))))
  570. (else
  571. (with-cps cps #f))))
  572. (define-binary-primcall-macro-reducer (rsh cps k src
  573. arg0 type0 min0 max0
  574. arg1 type1 min1 max1)
  575. (cond
  576. ((= min1 max1)
  577. (with-cps cps
  578. (build-term
  579. ($continue k src ($primcall 'rsh/immediate min1 (arg0))))))
  580. (else
  581. (with-cps cps #f))))
  582. ;; Strength reduction.
  583. (define *primcall-reducers* (make-hash-table))
  584. (define-syntax-rule (define-primcall-reducer op f)
  585. (hashq-set! *primcall-reducers* 'op f))
  586. (define-syntax-rule (define-unary-primcall-reducer (op cps k src param
  587. arg type min max)
  588. body ...)
  589. (define-primcall-reducer op
  590. (lambda (cps k src param arg type min max)
  591. body ...)))
  592. (define-syntax-rule (define-binary-primcall-reducer (op cps k src param
  593. arg0 type0 min0 max0
  594. arg1 type1 min1 max1)
  595. body ...)
  596. (define-primcall-reducer op
  597. (lambda (cps k src param arg0 type0 min0 max0 arg1 type1 min1 max1)
  598. body ...)))
  599. (define (power-of-two? constant)
  600. (and (positive? constant)
  601. (zero? (logand constant (1- constant)))))
  602. (define-binary-primcall-reducer (quo cps k src param
  603. arg0 type0 min0 max0
  604. arg1 type1 min1 max1)
  605. (cond
  606. ((not (type<=? (logior type0 type1) &exact-integer))
  607. (with-cps cps #f))
  608. ((and (eqv? type1 &fixnum) (eqv? min1 max1) (power-of-two? min1))
  609. (with-cps cps
  610. (build-term
  611. ($continue k src
  612. ($primcall 'rsh/immediate (logcount (1- min1)) (arg0))))))
  613. (else
  614. (with-cps cps #f))))
  615. (define-binary-primcall-reducer (rem cps k src param
  616. arg0 type0 min0 max0
  617. arg1 type1 min1 max1)
  618. (cond
  619. ((not (type<=? (logior type0 type1) &exact-integer))
  620. (with-cps cps #f))
  621. ((and (eqv? type1 &fixnum) (eqv? min1 max1) (power-of-two? min1)
  622. (<= 0 min0))
  623. (with-cps cps
  624. (build-term
  625. ($continue k src
  626. ($primcall 'logand/immediate (1- min1) (arg0))))))
  627. (else
  628. (with-cps cps #f))))
  629. (define-binary-primcall-reducer (mod cps k src param
  630. arg0 type0 min0 max0
  631. arg1 type1 min1 max1)
  632. (cond
  633. ((not (type<=? (logior type0 type1) &exact-integer))
  634. (with-cps cps #f))
  635. ((and (eqv? type1 &fixnum) (eqv? min1 max1) (power-of-two? min1))
  636. (with-cps cps
  637. (build-term
  638. ($continue k src
  639. ($primcall 'logand/immediate (1- min1) (arg0))))))
  640. (else
  641. (with-cps cps #f))))
  642. (define-unary-primcall-reducer (mul/immediate cps k src constant
  643. arg type min max)
  644. (cond
  645. ((not (type<=? type &number))
  646. (with-cps cps #f))
  647. ((eqv? constant -1)
  648. ;; (* arg -1) -> (- 0 arg)
  649. (with-cps cps
  650. ($ (with-cps-constants ((zero 0))
  651. (build-term
  652. ($continue k src ($primcall 'sub #f (zero arg))))))))
  653. ((and (eqv? constant 0) (type<=? type &exact-number))
  654. ;; (* arg 0) -> 0 if arg is exact
  655. (with-cps cps
  656. (build-term ($continue k src ($const 0)))))
  657. ((eqv? constant 1)
  658. ;; (* arg 1) -> arg
  659. (with-cps cps
  660. (build-term ($continue k src ($values (arg))))))
  661. ((eqv? constant 2)
  662. ;; (* arg 2) -> (+ arg arg)
  663. (with-cps cps
  664. (build-term ($continue k src ($primcall 'add #f (arg arg))))))
  665. ((and (type<=? type &exact-integer)
  666. (positive? constant)
  667. (zero? (logand constant (1- constant))))
  668. ;; (* arg power-of-2) -> (lsh arg (log2 power-of-2))
  669. (let ((n (let lp ((bits 0) (constant constant))
  670. (if (= constant 1) bits (lp (1+ bits) (ash constant -1))))))
  671. (with-cps cps
  672. (build-term ($continue k src ($primcall 'lsh/immediate n (arg)))))))
  673. (else
  674. (with-cps cps #f))))
  675. (define-binary-primcall-reducer (logbit? cps k src param
  676. arg0 type0 min0 max0
  677. arg1 type1 min1 max1)
  678. (define (compute-mask cps kmask src)
  679. (if (eq? min0 max0)
  680. (with-cps cps
  681. (build-term
  682. ($continue kmask src ($const (ash 1 min0)))))
  683. (with-cps cps
  684. ($ (with-cps-constants ((one 1))
  685. (letv n)
  686. (letk kn ($kargs ('n) (n)
  687. ($continue kmask src
  688. ($primcall 'lsh #f (one n)))))
  689. (build-term
  690. ($continue kn src ($primcall 'untag-fixnum #f (arg0)))))))))
  691. (cond
  692. ((and (type<=? type0 &exact-integer)
  693. (<= 0 min0 (target-most-positive-fixnum))
  694. (<= 0 max0 (target-most-positive-fixnum)))
  695. (with-cps cps
  696. (letv mask res u64)
  697. (letk kt ($kargs () () ($continue k src ($const #t))))
  698. (letk kf ($kargs () () ($continue k src ($const #f))))
  699. (letk ku64 ($kargs (#f) (u64)
  700. ($branch kt kf src 's64-imm-= 0 (u64))))
  701. (letk kand ($kargs (#f) (res)
  702. ($continue ku64 src ($primcall 'untag-fixnum #f (res)))))
  703. (letk kmask ($kargs (#f) (mask)
  704. ($continue kand src
  705. ($primcall 'logand #f (mask arg1)))))
  706. ($ (compute-mask kmask src))))
  707. (else
  708. (with-cps cps #f))))
  709. (define-binary-primcall-reducer (logior cps k src param
  710. arg0 type0 min0 max0
  711. arg1 type1 min1 max1)
  712. (cond
  713. ((type<=? (logior type0 type1) &exact-integer)
  714. (cond
  715. ((= 0 min0 max0)
  716. (with-cps cps
  717. (build-term
  718. ($continue k src ($values (arg1))))))
  719. ((= 0 min1 max1)
  720. (with-cps cps
  721. (build-term
  722. ($continue k src ($values (arg0))))))
  723. (else
  724. (with-cps cps #f))))
  725. (else
  726. (with-cps cps #f))))
  727. (define-unary-primcall-reducer (u64->scm cps k src constant arg type min max)
  728. (cond
  729. ((<= max (target-most-positive-fixnum))
  730. (with-cps cps
  731. (letv s64)
  732. (letk ks64 ($kargs ('s64) (s64)
  733. ($continue k src
  734. ($primcall 'tag-fixnum #f (s64)))))
  735. (build-term
  736. ($continue ks64 src
  737. ($primcall 'u64->s64 #f (arg))))))
  738. (else
  739. (with-cps cps #f))))
  740. (define-unary-primcall-reducer (s64->scm cps k src constant arg type min max)
  741. (cond
  742. ((<= (target-most-negative-fixnum) min max (target-most-positive-fixnum))
  743. (with-cps cps
  744. (build-term
  745. ($continue k src
  746. ($primcall 'tag-fixnum #f (arg))))))
  747. (else
  748. (with-cps cps #f))))
  749. (define-unary-primcall-reducer (scm->s64 cps k src constant arg type min max)
  750. (cond
  751. ((and (type<=? type &exact-integer)
  752. (<= (target-most-negative-fixnum) min max (target-most-positive-fixnum)))
  753. (with-cps cps
  754. (build-term
  755. ($continue k src
  756. ($primcall 'untag-fixnum #f (arg))))))
  757. (else
  758. (with-cps cps #f))))
  759. (define-unary-primcall-reducer (scm->u64 cps k src constant arg type min max)
  760. (cond
  761. ((and (type<=? type &exact-integer)
  762. (<= 0 min max (target-most-positive-fixnum)))
  763. (with-cps cps
  764. (letv s64)
  765. (letk ks64 ($kargs ('s64) (s64)
  766. ($continue k src
  767. ($primcall 's64->u64 #f (s64)))))
  768. (build-term
  769. ($continue ks64 src
  770. ($primcall 'untag-fixnum #f (arg))))))
  771. (else
  772. (with-cps cps #f))))
  773. (define-unary-primcall-reducer (scm->f64 cps k src constant arg type min max)
  774. (cond
  775. ((and (type<=? type &exact-integer)
  776. (<= (target-most-negative-fixnum) min max (target-most-positive-fixnum)))
  777. (with-cps cps
  778. (letv s64)
  779. (letk ks64 ($kargs ('s64) (s64)
  780. ($continue k src
  781. ($primcall 's64->f64 #f (s64)))))
  782. (build-term
  783. ($continue ks64 src
  784. ($primcall 'untag-fixnum #f (arg))))))
  785. (else
  786. (with-cps cps #f))))
  787. (define-unary-primcall-reducer (inexact cps k src constant arg type min max)
  788. (cond
  789. ((and (type<=? type &exact-integer)
  790. (<= (target-most-negative-fixnum) min max (target-most-positive-fixnum)))
  791. (with-cps cps
  792. (letv s64 f64)
  793. (letk kf64 ($kargs ('f64) (f64)
  794. ($continue k src
  795. ($primcall 'f64->scm #f (f64)))))
  796. (letk ks64 ($kargs ('s64) (s64)
  797. ($continue kf64 src
  798. ($primcall 's64->f64 #f (s64)))))
  799. (build-term
  800. ($continue ks64 src
  801. ($primcall 'untag-fixnum #f (arg))))))
  802. ((type<=? type &flonum)
  803. (with-cps cps
  804. (build-term
  805. ($continue k src ($primcall 'values #f (arg))))))
  806. (else
  807. (with-cps cps #f))))
  808. (define (local-type-fold start end cps)
  809. (let ((types (infer-types cps start)))
  810. (define (fold-primcall cps label names vars k src op param args def)
  811. (call-with-values (lambda () (lookup-post-type types label def 0))
  812. (lambda (type min max)
  813. (materialize-constant
  814. type min max
  815. (lambda (val)
  816. ;; (pk 'folded src op args val)
  817. (with-cps cps
  818. (letv v*)
  819. (letk k* ($kargs (#f) (v*)
  820. ($continue k src ($const val))))
  821. ;; Rely on DCE to elide this expression, if possible.
  822. (setk label
  823. ($kargs names vars
  824. ($continue k* src ($primcall op param args))))))
  825. (lambda () #f)))))
  826. (define (transform-primcall f cps label names vars k src op param args)
  827. (and f
  828. (match args
  829. ((arg0)
  830. (call-with-values (lambda () (lookup-pre-type types label arg0))
  831. (lambda (type0 min0 max0)
  832. (call-with-values (lambda ()
  833. (f cps k src param arg0 type0 min0 max0))
  834. (lambda (cps term)
  835. (and term
  836. (with-cps cps
  837. (setk label ($kargs names vars ,term)))))))))
  838. ((arg0 arg1)
  839. (call-with-values (lambda () (lookup-pre-type types label arg0))
  840. (lambda (type0 min0 max0)
  841. (call-with-values (lambda () (lookup-pre-type types label arg1))
  842. (lambda (type1 min1 max1)
  843. (call-with-values (lambda ()
  844. (f cps k src param arg0 type0 min0 max0
  845. arg1 type1 min1 max1))
  846. (lambda (cps term)
  847. (and term
  848. (with-cps cps
  849. (setk label ($kargs names vars ,term)))))))))))
  850. (_ #f))))
  851. (define (reduce-primcall cps label names vars k src op param args)
  852. (cond
  853. ((transform-primcall (hashq-ref *primcall-macro-reducers* op)
  854. cps label names vars k src op param args)
  855. => (lambda (cps)
  856. (match (intmap-ref cps label)
  857. (($ $kargs names vars
  858. ($ $continue k src ($ $primcall op param args)))
  859. (reduce-primcall cps label names vars k src op param args)))))
  860. ((transform-primcall (hashq-ref *primcall-reducers* op)
  861. cps label names vars k src op param args))
  862. (else cps)))
  863. (define (reduce-branch cps label names vars kf kt src op param args)
  864. (and=>
  865. (hashq-ref *branch-reducers* op)
  866. (lambda (reducer)
  867. (match args
  868. ((arg0)
  869. (call-with-values (lambda () (lookup-pre-type types label arg0))
  870. (lambda (type0 min0 max0)
  871. (call-with-values (lambda ()
  872. (reducer cps kf kt src param
  873. arg0 type0 min0 max0))
  874. (lambda (cps term)
  875. (and term
  876. (with-cps cps
  877. (setk label
  878. ($kargs names vars ,term)))))))))
  879. ((arg0 arg1)
  880. (call-with-values (lambda () (lookup-pre-type types label arg0))
  881. (lambda (type0 min0 max0)
  882. (call-with-values (lambda () (lookup-pre-type types label arg1))
  883. (lambda (type1 min1 max1)
  884. (call-with-values (lambda ()
  885. (reducer cps kf kt src param
  886. arg0 type0 min0 max0
  887. arg1 type1 min1 max1))
  888. (lambda (cps term)
  889. (and term
  890. (with-cps cps
  891. (setk label
  892. ($kargs names vars ,term)))))))))))))))
  893. (define (branch-folded cps label names vars src k)
  894. (with-cps cps
  895. (setk label
  896. ($kargs names vars
  897. ($continue k src ($values ()))))))
  898. (define (fold-unary-branch cps label names vars kf kt src op param arg)
  899. (and=>
  900. (hashq-ref *branch-folders* op)
  901. (lambda (folder)
  902. (call-with-values (lambda () (lookup-pre-type types label arg))
  903. (lambda (type min max)
  904. (call-with-values (lambda () (folder param type min max))
  905. (lambda (f? v)
  906. ;; (when f? (pk 'folded-unary-branch label op arg v))
  907. (and f?
  908. (branch-folded cps label names vars src
  909. (if v kt kf))))))))))
  910. (define (fold-binary-branch cps label names vars kf kt src op param arg0 arg1)
  911. (and=>
  912. (hashq-ref *branch-folders* op)
  913. (lambda (folder)
  914. (call-with-values (lambda () (lookup-pre-type types label arg0))
  915. (lambda (type0 min0 max0)
  916. (call-with-values (lambda () (lookup-pre-type types label arg1))
  917. (lambda (type1 min1 max1)
  918. (call-with-values (lambda ()
  919. (folder param type0 min0 max0 type1 min1 max1))
  920. (lambda (f? v)
  921. ;; (when f? (pk 'folded-binary-branch label op arg0 arg1 v))
  922. (and f?
  923. (branch-folded cps label names vars src
  924. (if v kt kf))))))))))))
  925. (define (fold-branch cps label names vars kf kt src op param args)
  926. (match args
  927. ((x)
  928. (fold-unary-branch cps label names vars kf kt src op param x))
  929. ((x y)
  930. (fold-binary-branch cps label names vars kf kt src op param x y))))
  931. (define (visit-primcall cps label names vars k src op param args)
  932. ;; We might be able to fold primcalls that define a value.
  933. (match (intmap-ref cps k)
  934. (($ $kargs (_) (def))
  935. (or (fold-primcall cps label names vars k src op param args def)
  936. (reduce-primcall cps label names vars k src op param args)))
  937. (_
  938. (reduce-primcall cps label names vars k src op param args))))
  939. (define (visit-branch cps label names vars kf kt src op param args)
  940. ;; We might be able to fold primcalls that branch.
  941. (or (fold-branch cps label names vars kf kt src op param args)
  942. (reduce-branch cps label names vars kf kt src op param args)
  943. cps))
  944. (define (visit-switch cps label names vars kf kt* src arg)
  945. ;; We might be able to fold or reduce a switch.
  946. (let ((ntargets (length kt*)))
  947. (call-with-values (lambda () (lookup-pre-type types label arg))
  948. (lambda (type min max)
  949. (cond
  950. ((<= ntargets min)
  951. (branch-folded cps label names vars src kf))
  952. ((= min max)
  953. (branch-folded cps label names vars src (list-ref kt* min)))
  954. (else
  955. ;; There are two more optimizations we could do here: one,
  956. ;; if max is less than ntargets, we can prune targets at
  957. ;; the end of the switch, and perhaps reduce the switch
  958. ;; back to a branch; and two, if min is greater than 0,
  959. ;; then we can subtract off min and prune targets at the
  960. ;; beginning. Not done yet though.
  961. cps))))))
  962. (let lp ((label start) (cps cps))
  963. (if (<= label end)
  964. (lp (1+ label)
  965. (match (intmap-ref cps label)
  966. (($ $kargs names vars ($ $continue k src
  967. ($ $primcall op param args)))
  968. (visit-primcall cps label names vars k src op param args))
  969. (($ $kargs names vars ($ $branch kf kt src op param args))
  970. (visit-branch cps label names vars kf kt src op param args))
  971. (($ $kargs names vars ($ $switch kf kt* src arg))
  972. (visit-switch cps label names vars kf kt* src arg))
  973. (_ cps)))
  974. cps))))
  975. (define (fold-functions-in-renumbered-program f conts seed)
  976. (let* ((conts (persistent-intmap conts))
  977. (end (1+ (intmap-prev conts))))
  978. (let lp ((label 0) (seed seed))
  979. (if (eqv? label end)
  980. seed
  981. (match (intmap-ref conts label)
  982. (($ $kfun src meta self tail clause)
  983. (lp (1+ tail) (f label tail seed))))))))
  984. (define (type-fold conts)
  985. ;; Type analysis wants a program whose labels are sorted.
  986. (let ((conts (renumber conts)))
  987. (with-fresh-name-state conts
  988. (persistent-intmap
  989. (fold-functions-in-renumbered-program local-type-fold conts conts)))))