primitives.scm 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. ;;; open-coding primitive procedures
  2. ;; Copyright (C) 2009-2015, 2017-2019 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. ;;; Code:
  17. (define-module (language tree-il primitives)
  18. #:use-module (system base pmatch)
  19. #:use-module (ice-9 match)
  20. #:use-module (ice-9 threads)
  21. #:use-module (rnrs bytevectors)
  22. #:use-module (system base syntax)
  23. #:use-module (language tree-il)
  24. #:use-module (srfi srfi-4)
  25. #:use-module (srfi srfi-16)
  26. #:export (resolve-primitives add-interesting-primitive!
  27. expand-primcall expand-primitives
  28. effect-free-primitive? effect+exception-free-primitive?
  29. constructor-primitive?
  30. singly-valued-primitive? equality-primitive?
  31. bailout-primitive?
  32. negate-primitive))
  33. ;; When adding to this, be sure to update *multiply-valued-primitives*
  34. ;; if appropriate.
  35. (define *interesting-primitive-names*
  36. '(apply
  37. call-with-values
  38. call-with-current-continuation
  39. call/cc
  40. dynamic-wind
  41. values
  42. eq? eqv? equal?
  43. memq memv
  44. = < > <= >= zero? positive? negative?
  45. + * - / 1- 1+ quotient remainder modulo exact->inexact
  46. ash logand logior logxor lognot logtest logbit?
  47. sqrt abs floor ceiling sin cos tan asin acos atan
  48. not
  49. pair? null? list? symbol? vector? string? struct? number? char? nil?
  50. bytevector? keyword? bitvector?
  51. symbol->string string->symbol
  52. procedure? thunk?
  53. complex? real? rational? inf? nan? integer? exact? inexact? even? odd?
  54. exact-integer?
  55. char<? char<=? char>=? char>?
  56. integer->char char->integer number->string string->number
  57. acons cons cons*
  58. list vector
  59. car cdr
  60. set-car! set-cdr!
  61. caar cadr cdar cddr
  62. caaar caadr cadar caddr cdaar cdadr cddar cdddr
  63. caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
  64. cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
  65. length
  66. make-vector vector-length vector-ref vector-set!
  67. variable? variable-ref variable-set!
  68. variable-bound?
  69. current-module define!
  70. current-thread fluid-ref fluid-set! with-fluid* with-dynamic-state
  71. call-with-prompt
  72. abort-to-prompt* abort-to-prompt
  73. make-prompt-tag
  74. throw error scm-error
  75. string-length string-ref string-set!
  76. make-struct/simple struct-vtable struct-ref struct-set!
  77. bytevector-length
  78. bytevector-u8-ref bytevector-u8-set!
  79. bytevector-s8-ref bytevector-s8-set!
  80. u8vector-ref u8vector-set! s8vector-ref s8vector-set!
  81. bytevector-u16-ref bytevector-u16-set!
  82. bytevector-u16-native-ref bytevector-u16-native-set!
  83. bytevector-s16-ref bytevector-s16-set!
  84. bytevector-s16-native-ref bytevector-s16-native-set!
  85. u16vector-ref u16vector-set! s16vector-ref s16vector-set!
  86. bytevector-u32-ref bytevector-u32-set!
  87. bytevector-u32-native-ref bytevector-u32-native-set!
  88. bytevector-s32-ref bytevector-s32-set!
  89. bytevector-s32-native-ref bytevector-s32-native-set!
  90. u32vector-ref u32vector-set! s32vector-ref s32vector-set!
  91. bytevector-u64-ref bytevector-u64-set!
  92. bytevector-u64-native-ref bytevector-u64-native-set!
  93. bytevector-s64-ref bytevector-s64-set!
  94. bytevector-s64-native-ref bytevector-s64-native-set!
  95. u64vector-ref u64vector-set! s64vector-ref s64vector-set!
  96. bytevector-ieee-single-ref bytevector-ieee-single-set!
  97. bytevector-ieee-single-native-ref bytevector-ieee-single-native-set!
  98. bytevector-ieee-double-ref bytevector-ieee-double-set!
  99. bytevector-ieee-double-native-ref bytevector-ieee-double-native-set!
  100. f32vector-ref f32vector-set! f64vector-ref f64vector-set!))
  101. (define (add-interesting-primitive! name)
  102. (hashq-set! *interesting-primitive-vars*
  103. (or (module-variable (current-module) name)
  104. (error "unbound interesting primitive" name))
  105. name))
  106. (define *interesting-primitive-vars* (make-hash-table))
  107. (for-each add-interesting-primitive! *interesting-primitive-names*)
  108. (define *primitive-constructors*
  109. ;; Primitives that return a fresh object.
  110. '(acons cons cons* list vector make-vector
  111. make-struct/simple
  112. make-prompt-tag))
  113. (define *primitive-accessors*
  114. ;; Primitives that are pure, but whose result depends on the mutable
  115. ;; memory pointed to by their operands.
  116. ;;
  117. ;; Note: if you add an accessor here, be sure to add a corresponding
  118. ;; case in (language tree-il effects)!
  119. '(vector-ref
  120. car cdr
  121. memq memv
  122. struct-ref
  123. string-ref
  124. bytevector-u8-ref bytevector-s8-ref
  125. bytevector-u16-ref bytevector-u16-native-ref
  126. bytevector-s16-ref bytevector-s16-native-ref
  127. bytevector-u32-ref bytevector-u32-native-ref
  128. bytevector-s32-ref bytevector-s32-native-ref
  129. bytevector-u64-ref bytevector-u64-native-ref
  130. bytevector-s64-ref bytevector-s64-native-ref
  131. bytevector-ieee-single-ref bytevector-ieee-single-native-ref
  132. bytevector-ieee-double-ref bytevector-ieee-double-native-ref))
  133. (define *effect-free-primitives*
  134. `(values
  135. eq? eqv? equal?
  136. = < > <= >= zero? positive? negative?
  137. ash logand logior logxor lognot logtest logbit?
  138. + * - / 1- 1+ sqrt abs quotient remainder modulo exact->inexact
  139. floor ceiling sin cos tan asin acos atan
  140. not
  141. pair? null? nil? list?
  142. symbol? variable? vector? struct? string? number? char?
  143. bytevector? keyword? bitvector? atomic-box?
  144. complex? real? rational? inf? nan? integer? exact? inexact? even? odd?
  145. exact-integer?
  146. char<? char<=? char>=? char>?
  147. integer->char char->integer number->string string->number
  148. symbol->string string->symbol
  149. struct-vtable
  150. length string-length vector-length bytevector-length
  151. ;; These all should get expanded out by expand-primitives.
  152. caar cadr cdar cddr
  153. caaar caadr cadar caddr cdaar cdadr cddar cdddr
  154. caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr
  155. cdaaar cdaadr cdadar cdaddr cddaar cddadr cdddar cddddr
  156. ,@*primitive-constructors*
  157. ,@*primitive-accessors*))
  158. ;; Like *effect-free-primitives* above, but further restricted in that they
  159. ;; cannot raise exceptions.
  160. (define *effect+exception-free-primitives*
  161. '(values
  162. eq? eqv? equal?
  163. not
  164. pair? null? nil? list?
  165. symbol? variable? vector? struct? string? number? char?
  166. exact-integer?
  167. bytevector? keyword? bitvector?
  168. procedure? thunk? atomic-box?
  169. acons cons cons* list vector))
  170. ;; Primitives that don't always return one value.
  171. (define *multiply-valued-primitives*
  172. '(apply
  173. call-with-values
  174. call-with-current-continuation
  175. call/cc
  176. dynamic-wind
  177. values
  178. call-with-prompt
  179. @abort abort-to-prompt))
  180. ;; Procedures that cause a nonlocal, non-resumable abort.
  181. (define *bailout-primitives*
  182. '(throw error scm-error))
  183. ;; Negatable predicates.
  184. (define *negatable-primitives*
  185. '((even? . odd?)
  186. (exact? . inexact?)
  187. ;; (< <= > >=) are not negatable because of NaNs.
  188. (char<? . char>=?)
  189. (char>? . char<=?)))
  190. (define *equality-primitives*
  191. '(eq? eqv? equal?))
  192. (define *effect-free-primitive-table* (make-hash-table))
  193. (define *effect+exceptions-free-primitive-table* (make-hash-table))
  194. (define *equality-primitive-table* (make-hash-table))
  195. (define *multiply-valued-primitive-table* (make-hash-table))
  196. (define *bailout-primitive-table* (make-hash-table))
  197. (define *negatable-primitive-table* (make-hash-table))
  198. (for-each (lambda (x)
  199. (hashq-set! *effect-free-primitive-table* x #t))
  200. *effect-free-primitives*)
  201. (for-each (lambda (x)
  202. (hashq-set! *effect+exceptions-free-primitive-table* x #t))
  203. *effect+exception-free-primitives*)
  204. (for-each (lambda (x)
  205. (hashq-set! *equality-primitive-table* x #t))
  206. *equality-primitives*)
  207. (for-each (lambda (x)
  208. (hashq-set! *multiply-valued-primitive-table* x #t))
  209. *multiply-valued-primitives*)
  210. (for-each (lambda (x)
  211. (hashq-set! *bailout-primitive-table* x #t))
  212. *bailout-primitives*)
  213. (for-each (lambda (x)
  214. (hashq-set! *negatable-primitive-table* (car x) (cdr x))
  215. (hashq-set! *negatable-primitive-table* (cdr x) (car x)))
  216. *negatable-primitives*)
  217. (define (constructor-primitive? prim)
  218. (memq prim *primitive-constructors*))
  219. (define (effect-free-primitive? prim)
  220. (hashq-ref *effect-free-primitive-table* prim))
  221. (define (effect+exception-free-primitive? prim)
  222. (hashq-ref *effect+exceptions-free-primitive-table* prim))
  223. (define (equality-primitive? prim)
  224. (hashq-ref *equality-primitive-table* prim))
  225. (define (singly-valued-primitive? prim)
  226. (not (hashq-ref *multiply-valued-primitive-table* prim)))
  227. (define (bailout-primitive? prim)
  228. (hashq-ref *bailout-primitive-table* prim))
  229. (define (negate-primitive prim)
  230. (hashq-ref *negatable-primitive-table* prim))
  231. (define (resolve-primitives x mod)
  232. (define local-definitions
  233. (make-hash-table))
  234. ;; Assume that any definitions with primitive names in the root module
  235. ;; have the same semantics as the primitives.
  236. (unless (eq? mod the-root-module)
  237. (let collect-local-definitions ((x x))
  238. (record-case x
  239. ((<toplevel-define> name)
  240. (hashq-set! local-definitions name #t))
  241. ((<seq> head tail)
  242. (collect-local-definitions head)
  243. (collect-local-definitions tail))
  244. (else #f))))
  245. (post-order
  246. (lambda (x)
  247. (or
  248. (record-case x
  249. ((<toplevel-ref> src name)
  250. (and=> (and (not (hashq-ref local-definitions name))
  251. (hashq-ref *interesting-primitive-vars*
  252. (module-variable mod name)))
  253. (lambda (name) (make-primitive-ref src name))))
  254. ((<module-ref> src mod name public?)
  255. ;; for the moment, we're disabling primitive resolution for
  256. ;; public refs because resolve-interface can raise errors.
  257. (and=> (and=> (resolve-module mod)
  258. (if public?
  259. module-public-interface
  260. identity))
  261. (lambda (m)
  262. (and=> (hashq-ref *interesting-primitive-vars*
  263. (module-variable m name))
  264. (lambda (name)
  265. (make-primitive-ref src name))))))
  266. ((<call> src proc args)
  267. (and (primitive-ref? proc)
  268. (make-primcall src (primitive-ref-name proc) args)))
  269. (else #f))
  270. x))
  271. x))
  272. (define *primitive-expand-table* (make-hash-table))
  273. (define (expand-primcall x)
  274. (record-case x
  275. ((<primcall> src name args)
  276. (let ((expand (hashq-ref *primitive-expand-table* name)))
  277. (or (and expand (apply expand src args))
  278. x)))
  279. (else x)))
  280. (define (expand-primitives x)
  281. (pre-order expand-primcall x))
  282. (define-syntax-rule (define-primitive-expander! sym proc)
  283. (hashq-set! *primitive-expand-table* sym proc))
  284. (define-syntax primitive-expander
  285. (lambda (stx)
  286. (define (expand-args args)
  287. (syntax-case args ()
  288. (() #''())
  289. ((a . b) #`(cons #,(expand-expr #'a) #,(expand-args #'b)))
  290. (a (expand-expr #'a))))
  291. (define (expand-expr body)
  292. (syntax-case body (quote)
  293. (id (identifier? #'id) #'id)
  294. ((quote x) #'(make-const src 'x))
  295. ((op . args) #`(make-primcall src 'op #,(expand-args #'args)))
  296. (x (self-evaluating? (syntax->datum #'x)) #'(make-const src x))))
  297. (define (match-clauses args+body)
  298. (syntax-case args+body (if)
  299. (() '())
  300. ((args body . args+body)
  301. (cons #`(args #,(expand-expr #'body))
  302. (match-clauses #'args+body)))))
  303. (syntax-case stx ()
  304. ((_ args+body ...)
  305. #`(lambda (src . args)
  306. (match args
  307. #,@(match-clauses #'(args+body ...))
  308. (_ #f)))))))
  309. (define-syntax-rule (define-primitive-expander sym . clauses)
  310. (define-primitive-expander! 'sym (primitive-expander . clauses)))
  311. ;; Oddly, scm-error is just an explicitly 5-argument `throw'. Weird.
  312. (define-primitive-expander scm-error (key who message args data)
  313. (throw key who message args data))
  314. (define (escape-format-directives str)
  315. (string-join (string-split str #\~) "~~"))
  316. (define-primitive-expander! 'error
  317. (match-lambda*
  318. ((src)
  319. (make-primcall src 'throw
  320. (list (make-const src 'misc-error)
  321. (make-const src #f)
  322. (make-const src "?")
  323. (make-const src #f)
  324. (make-const src #f))))
  325. ((src ($ <const> src2 (? string? message)) . args)
  326. (let ((msg (string-join (cons (escape-format-directives message)
  327. (make-list (length args) "~S")))))
  328. (make-primcall src 'throw
  329. (list (make-const src 'misc-error)
  330. (make-const src #f)
  331. (make-const src2 msg)
  332. (make-primcall src 'list args)
  333. (make-const src #f)))))
  334. ((src message . args)
  335. (let ((msg (string-join (cons "~A" (make-list (length args) "~S")))))
  336. (make-primcall src 'throw
  337. (list (make-const src 'misc-error)
  338. (make-const src #f)
  339. (make-const src msg)
  340. (make-const src "?")
  341. (make-primcall src 'list (cons message args))
  342. (make-const src #f)))))))
  343. (define-primitive-expander define! (sym val)
  344. (%variable-set! (module-ensure-local-variable! (current-module) sym) val))
  345. (define-primitive-expander module-define! (mod sym val)
  346. (%variable-set! (module-ensure-local-variable! mod sym) val))
  347. (define-primitive-expander zero? (x)
  348. (= x 0))
  349. (define-primitive-expander positive? (x)
  350. (> x 0))
  351. (define-primitive-expander negative? (x)
  352. (< x 0))
  353. ;; FIXME: All the code that uses `const?' is redundant with `peval'.
  354. (define-primitive-expander 1+ (x)
  355. (+ x 1))
  356. (define-primitive-expander 1- (x)
  357. (- x 1))
  358. (define-primitive-expander +
  359. () 0
  360. (x) (values x)
  361. (x y) (+ x y)
  362. (x y z ... last) (+ (+ x y . z) last))
  363. (define-primitive-expander *
  364. () 1
  365. (x) (values x)
  366. (x y z ... last) (* (* x y . z) last))
  367. (define-primitive-expander -
  368. (x) (- 0 x)
  369. (x y) (- x y)
  370. (x y z ... last) (- (- x y . z) last))
  371. (define-primitive-expander /
  372. (x) (/ 1 x)
  373. (x y z ... last) (/ (/ x y . z) last))
  374. (define-primitive-expander atan
  375. (x) (atan x)
  376. (x y) (atan2 x y))
  377. (define-primitive-expander logior
  378. () 0
  379. (x) (logior x 0)
  380. (x y) (logior x y)
  381. (x y z ... last) (logior (logior x y . z) last))
  382. (define-primitive-expander logand
  383. () -1
  384. (x) (logand x -1)
  385. (x y) (logand x y)
  386. (x y z ... last) (logand (logand x y . z) last))
  387. (define-primitive-expander! 'make-vector
  388. (match-lambda*
  389. ((src len)
  390. (make-primcall src 'make-vector (list len (make-const src *unspecified*))))
  391. ((src len init)
  392. (make-primcall src 'make-vector (list len init)))
  393. ((src . args)
  394. (make-call src (make-primitive-ref src 'make-vector) args))))
  395. (define-primitive-expander caar (x) (car (car x)))
  396. (define-primitive-expander cadr (x) (car (cdr x)))
  397. (define-primitive-expander cdar (x) (cdr (car x)))
  398. (define-primitive-expander cddr (x) (cdr (cdr x)))
  399. (define-primitive-expander caaar (x) (car (car (car x))))
  400. (define-primitive-expander caadr (x) (car (car (cdr x))))
  401. (define-primitive-expander cadar (x) (car (cdr (car x))))
  402. (define-primitive-expander caddr (x) (car (cdr (cdr x))))
  403. (define-primitive-expander cdaar (x) (cdr (car (car x))))
  404. (define-primitive-expander cdadr (x) (cdr (car (cdr x))))
  405. (define-primitive-expander cddar (x) (cdr (cdr (car x))))
  406. (define-primitive-expander cdddr (x) (cdr (cdr (cdr x))))
  407. (define-primitive-expander caaaar (x) (car (car (car (car x)))))
  408. (define-primitive-expander caaadr (x) (car (car (car (cdr x)))))
  409. (define-primitive-expander caadar (x) (car (car (cdr (car x)))))
  410. (define-primitive-expander caaddr (x) (car (car (cdr (cdr x)))))
  411. (define-primitive-expander cadaar (x) (car (cdr (car (car x)))))
  412. (define-primitive-expander cadadr (x) (car (cdr (car (cdr x)))))
  413. (define-primitive-expander caddar (x) (car (cdr (cdr (car x)))))
  414. (define-primitive-expander cadddr (x) (car (cdr (cdr (cdr x)))))
  415. (define-primitive-expander cdaaar (x) (cdr (car (car (car x)))))
  416. (define-primitive-expander cdaadr (x) (cdr (car (car (cdr x)))))
  417. (define-primitive-expander cdadar (x) (cdr (car (cdr (car x)))))
  418. (define-primitive-expander cdaddr (x) (cdr (car (cdr (cdr x)))))
  419. (define-primitive-expander cddaar (x) (cdr (cdr (car (car x)))))
  420. (define-primitive-expander cddadr (x) (cdr (cdr (car (cdr x)))))
  421. (define-primitive-expander cdddar (x) (cdr (cdr (cdr (car x)))))
  422. (define-primitive-expander cddddr (x) (cdr (cdr (cdr (cdr x)))))
  423. (define-primitive-expander cons*
  424. (x) (values x)
  425. (x y) (cons x y)
  426. (x y . rest) (cons x (cons* y . rest)))
  427. (define-primitive-expander acons (x y z)
  428. (cons (cons x y) z))
  429. (define-primitive-expander call/cc (proc)
  430. (call-with-current-continuation proc))
  431. (define-primitive-expander u8vector-ref (vec i)
  432. (bytevector-u8-ref vec i))
  433. (define-primitive-expander u8vector-set! (vec i x)
  434. (bytevector-u8-set! vec i x))
  435. (define-primitive-expander s8vector-ref (vec i)
  436. (bytevector-s8-ref vec i))
  437. (define-primitive-expander s8vector-set! (vec i x)
  438. (bytevector-s8-set! vec i x))
  439. (define-primitive-expander u16vector-ref (vec i)
  440. (bytevector-u16-native-ref vec (* i 2)))
  441. (define-primitive-expander u16vector-set! (vec i x)
  442. (bytevector-u16-native-set! vec (* i 2) x))
  443. (define-primitive-expander s16vector-ref (vec i)
  444. (bytevector-s16-native-ref vec (* i 2)))
  445. (define-primitive-expander s16vector-set! (vec i x)
  446. (bytevector-s16-native-set! vec (* i 2) x))
  447. (define-primitive-expander u32vector-ref (vec i)
  448. (bytevector-u32-native-ref vec (* i 4)))
  449. (define-primitive-expander u32vector-set! (vec i x)
  450. (bytevector-u32-native-set! vec (* i 4) x))
  451. (define-primitive-expander s32vector-ref (vec i)
  452. (bytevector-s32-native-ref vec (* i 4)))
  453. (define-primitive-expander s32vector-set! (vec i x)
  454. (bytevector-s32-native-set! vec (* i 4) x))
  455. (define-primitive-expander u64vector-ref (vec i)
  456. (bytevector-u64-native-ref vec (* i 8)))
  457. (define-primitive-expander u64vector-set! (vec i x)
  458. (bytevector-u64-native-set! vec (* i 8) x))
  459. (define-primitive-expander s64vector-ref (vec i)
  460. (bytevector-s64-native-ref vec (* i 8)))
  461. (define-primitive-expander s64vector-set! (vec i x)
  462. (bytevector-s64-native-set! vec (* i 8) x))
  463. (define-primitive-expander f32vector-ref (vec i)
  464. (bytevector-ieee-single-native-ref vec (* i 4)))
  465. (define-primitive-expander f32vector-set! (vec i x)
  466. (bytevector-ieee-single-native-set! vec (* i 4) x))
  467. (define-primitive-expander f32vector-ref (vec i)
  468. (bytevector-ieee-single-native-ref vec (* i 4)))
  469. (define-primitive-expander f32vector-set! (vec i x)
  470. (bytevector-ieee-single-native-set! vec (* i 4) x))
  471. (define-primitive-expander f64vector-ref (vec i)
  472. (bytevector-ieee-double-native-ref vec (* i 8)))
  473. (define-primitive-expander f64vector-set! (vec i x)
  474. (bytevector-ieee-double-native-set! vec (* i 8) x))
  475. (define-primitive-expander f64vector-ref (vec i)
  476. (bytevector-ieee-double-native-ref vec (* i 8)))
  477. (define-primitive-expander f64vector-set! (vec i x)
  478. (bytevector-ieee-double-native-set! vec (* i 8) x))
  479. (define (chained-comparison-expander prim-name)
  480. (case-lambda
  481. ((src) (make-const src #t))
  482. ((src a) #f)
  483. ((src a b) #f)
  484. ((src a b . rest)
  485. (let* ((b-sym (gensym "b"))
  486. (b* (make-lexical-ref src 'b b-sym)))
  487. (make-let src
  488. '(b)
  489. (list b-sym)
  490. (list b)
  491. (make-conditional src
  492. (make-primcall src prim-name (list a b*))
  493. (make-primcall src prim-name (cons b* rest))
  494. (make-const src #f)))))))
  495. (for-each (lambda (prim-name)
  496. (define-primitive-expander! prim-name
  497. (chained-comparison-expander prim-name)))
  498. '(< > <= >= =))
  499. (define (character-comparison-expander char< <)
  500. (lambda (src . args)
  501. (expand-primcall
  502. (make-primcall src <
  503. (map (lambda (arg)
  504. (make-primcall src 'char->integer (list arg)))
  505. args)))))
  506. (for-each (match-lambda
  507. ((char< . <)
  508. (define-primitive-expander! char<
  509. (character-comparison-expander char< <))))
  510. '((char<? . <)
  511. (char>? . >)
  512. (char<=? . <=)
  513. (char>=? . >=)
  514. (char=? . =)))
  515. ;; Appropriate for use with either 'eqv?' or 'equal?'.
  516. (define (maybe-simplify-to-eq prim)
  517. (case-lambda
  518. ((src) (make-const src #t))
  519. ((src a) (make-const src #t))
  520. ((src a b)
  521. ;; Simplify cases where either A or B is constant.
  522. (define (maybe-simplify a b)
  523. (and (const? a)
  524. (let ((v (const-exp a)))
  525. (and (or (memq v '(#f #t () #nil))
  526. (symbol? v)
  527. (and (integer? v)
  528. (exact? v)
  529. (<= v most-positive-fixnum)
  530. (>= v most-negative-fixnum)))
  531. (make-primcall src 'eq? (list a b))))))
  532. (or (maybe-simplify a b) (maybe-simplify b a)))
  533. ((src a b . rest)
  534. (make-conditional src (make-primcall src prim (list a b))
  535. (make-primcall src prim (cons b rest))
  536. (make-const src #f)))
  537. (else #f)))
  538. (define-primitive-expander! 'eqv? (maybe-simplify-to-eq 'eqv?))
  539. (define-primitive-expander! 'equal? (maybe-simplify-to-eq 'equal?))
  540. (define (expand-chained-comparisons prim)
  541. (case-lambda
  542. ((src) (make-const src #t))
  543. ((src a)
  544. ;; (< x) -> (begin (< x 0) #t). Residualizes side-effects from x
  545. ;; and, for numeric comparisons, checks that x is a number.
  546. (make-seq src
  547. (make-primcall src prim (list a (make-const src 0)))
  548. (make-const src #t)))
  549. ((src a b) #f)
  550. ((src a b . rest)
  551. (make-conditional src (make-primcall src prim (list a b))
  552. (make-primcall src prim (cons b rest))
  553. (make-const src #f)))
  554. (else #f)))
  555. (for-each (lambda (prim)
  556. (define-primitive-expander! prim
  557. (expand-chained-comparisons prim)))
  558. '(< <= = >= > eq?))
  559. (define-primitive-expander! 'call-with-prompt
  560. (case-lambda
  561. ((src tag thunk handler)
  562. (make-prompt src #f tag thunk handler))
  563. (else #f)))
  564. (define-primitive-expander! 'abort-to-prompt*
  565. (case-lambda
  566. ((src tag tail-args)
  567. (make-abort src tag '() tail-args))
  568. (else #f)))
  569. (define-primitive-expander! 'abort-to-prompt
  570. (case-lambda
  571. ((src tag . args)
  572. (make-abort src tag args (make-const #f '())))
  573. (else #f)))