arith.scm 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Mike Sperber
  3. (define (put-literal-first call)
  4. (if (and (not (literal-node? (call-arg call 0)))
  5. (literal-node? (call-arg call 1)))
  6. (let ((arg1 (detach (call-arg call 0)))
  7. (arg0 (detach (call-arg call 1))))
  8. (attach call 0 arg0)
  9. (attach call 1 arg1))))
  10. (define-syntax addition-simplifier
  11. (syntax-rules ()
  12. ((addition-simplifier + - zero)
  13. (lambda (call)
  14. (simplify-args call 0)
  15. (put-literal-first call)
  16. ((pattern-simplifier
  17. ((+ 'zero x) x)
  18. ((+ 'a 'b) '(+ a b))
  19. ((+ 'a (+ 'b x)) (+ x '(+ a b)))
  20. ((+ 'a (- x 'b)) (+ x '(- a b))) ; no overflow in Scheme, but what
  21. ((+ 'a (- 'b x)) (- '(+ a b) x)) ; about PreScheme? Could check the
  22. ((+ (+ 'a x) (+ 'b y)) (+ '(+ a b) (+ x y)))
  23. ((+ x (+ 'a y)) (+ 'a (+ x y)))) ; result of the literal. Maybe these
  24. call))))) ; should be left out.
  25. (define-scheme-primop + #f type/integer (addition-simplifier + - 0))
  26. (define-scheme-primop fl+ #f type/float (addition-simplifier fl+ fl- 0.0))
  27. (define-scheme-primop un+ #f type/unsigned-integer (addition-simplifier un+ un- 0))
  28. ; The simplifiers think that the constant folders have the same name as
  29. ; the primops. It is easier to define these than to change the simplifiers.
  30. (define fl+ +)
  31. (define fl- -)
  32. (define fl* *)
  33. (define un+ +)
  34. (define un- -)
  35. (define un* *)
  36. (define-syntax subtraction-simplifier
  37. (syntax-rules ()
  38. ((subtraction-simplifier + - zero)
  39. (lambda (call)
  40. (simplify-args call 0)
  41. ((pattern-simplifier
  42. ((- 'a 'b) '(- a b))
  43. ((- x 'a) (+ '(- zero a) x))
  44. ((- 'a (+ 'b x)) (- '(- a b) x)) ; more overflow problems
  45. ((- 'a (- 'b x)) (+ x '(- a b)))
  46. ((- x (+ 'a y)) (+ '(- zero a) (- x y)))
  47. ; ((- (+ 'a x) y) (+ 'a (- x y))) need to come up with a normal form
  48. ((- (+ 'a x) (+ 'b y)) (- (+ '(- a b) x) y)))
  49. call)))))
  50. (define-scheme-primop - #f type/integer (subtraction-simplifier + - 0))
  51. (define-scheme-primop un- #f type/unsigned-integer (subtraction-simplifier un+ un- 0))
  52. (define-scheme-primop fl- #f type/float (subtraction-simplifier fl+ fl- 0.0))
  53. ; This should check for multiply by powers of 2 (other constants can be
  54. ; done later).
  55. (define (simplify-multiply call)
  56. (simplify-args call 0)
  57. (put-literal-first call)
  58. (cond ((power-of-two-literal (call-arg call 0))
  59. => (lambda (i)
  60. (set-call-primop! call (get-prescheme-primop 'ashl))
  61. (replace (call-arg call 0) (detach (call-arg call 1)))
  62. (attach call 1 (make-literal-node i type/unknown))))
  63. (else
  64. ((pattern-simplifier
  65. ((* '0 x) '0)
  66. ((* '1 x) x)
  67. ((* 'a 'b) '(* a b))
  68. ((* 'a (* x 'b)) (* x '(* a b)))
  69. ((* 'a (* 'b x)) (* x '(* a b))))
  70. call))))
  71. (define (power-of-two-literal node)
  72. (if (not (literal-node? node))
  73. #f
  74. (let ((value (literal-value node)))
  75. (if (not (and (integer? value)
  76. (<= 1 value)))
  77. #f
  78. (do ((v value (arithmetic-shift v -1))
  79. (i 0 (+ i 1)))
  80. ((odd? v)
  81. (if (= v 1) i #f)))))))
  82. (define simplify-float-multiply
  83. (pattern-simplifier
  84. ((fl* '0.0 x) '0.0)
  85. ((fl* '1.0 x) x)
  86. ((fl* 'a 'b) '(fl* a b))
  87. ((fl* 'a (fl* x 'b)) (fl* x '(fl* a b)))
  88. ((fl* 'a (fl* 'b x)) (fl* x '(fl* a b)))))
  89. (define-scheme-primop * #f type/integer simplify-multiply)
  90. (define-scheme-primop un* #f type/unsigned-integer simplify-multiply)
  91. (define-scheme-primop small* #f type/integer simplify-multiply)
  92. (define-scheme-primop fl* #f type/float simplify-float-multiply)
  93. (define-syntax quotient-simplifier
  94. (syntax-rules ()
  95. ((quotient-simplifier id zero one op)
  96. (lambda (call)
  97. (simplify-args call 0)
  98. ((pattern-simplifier
  99. ((id x 'zero) '((lambda ()
  100. (error "program divides by zero"))))
  101. ((id x 'one) x)
  102. ((id 'zero x) 'zero)
  103. ((id 'a 'b) '(op a b)))
  104. call)))))
  105. (define-scheme-primop quotient exception type/integer
  106. (quotient-simplifier quotient 0 1 quotient))
  107. (define-scheme-primop unquotient exception type/unsigned-integer
  108. (quotient-simplifier unquotient 0 1 quotient))
  109. (define-scheme-primop fl/ exception type/float
  110. (quotient-simplifier fl/ 0.0 1.0 /))
  111. (define-scheme-primop remainder exception type/integer)
  112. (define-scheme-primop unremainder exception type/unsigned-integer)
  113. (define (simplify-ashl call)
  114. (simplify-args call 0)
  115. ((pattern-simplifier
  116. ((ashl '0 x) '0)
  117. ((ashl x '0) x)
  118. ((ashl 'a 'b) '(arithmetic-shift a b))
  119. ((ashl (ashl x 'a) 'b) (ashl x '(+ a b)))
  120. ((ashl (ashr x 'a) 'b)
  121. (<= a b) ; condition
  122. (ashl (bitwise-and x '(bitwise-not (- (expt 2 a) 1))) '(- b a)))
  123. ((ashl (ashr x 'a) 'b)
  124. (>= a b) ; condition
  125. (bitwise-and (ashr x '(- a b)) '(bitwise-not (- (expt 2 b) 1))))
  126. ((ashl (+ 'a x) 'b) (+ (ashl x 'b) '(arithmetic-shift a b))))
  127. call))
  128. (define (simplify-ashr call)
  129. (simplify-args call 0)
  130. ((pattern-simplifier
  131. ((ashr '0 x) '0)
  132. ((ashr x '0) x)
  133. ((ashr 'a 'b) '(arithmetic-shift a (- b)))
  134. ((ashr (ashr x 'a) 'b) (ashr x '(+ a b))))
  135. call))
  136. (define (simplify-lshr call)
  137. (simplify-args call 0)
  138. ((pattern-simplifier
  139. ((lshr '0 x) '0)
  140. ((lshr x '0) x)
  141. ((lshr 'a 'b) '(lshr a (- b)))
  142. ((lshr (lshr x 'a) 'b) (lshr x '(+ a b)))
  143. ((ashr (lshr x 'a) 'b) (lshr x '(+ a b)))) ; depends on shifts by zero
  144. ; having been constant folded
  145. call))
  146. (define-scheme-primop ashl #f type/integer simplify-ashl)
  147. (define-scheme-primop ashr #f type/integer simplify-ashr)
  148. (define-scheme-primop lshr #f type/integer simplify-lshr)
  149. (define (simplify-bitwise-and call)
  150. (simplify-args call 0)
  151. (put-literal-first call)
  152. ((pattern-simplifier
  153. ((bitwise-and '0 x) '0)
  154. ((bitwise-and '-1 x) x)
  155. ((bitwise-and 'a 'b) '(bitwise-and a b)))
  156. call))
  157. (define (simplify-bitwise-ior call)
  158. (simplify-args call 0)
  159. (put-literal-first call)
  160. ((pattern-simplifier
  161. ((bitwise-ior '0 x) x)
  162. ((bitwise-ior '-1 x) '-1)
  163. ((bitwise-ior 'a 'b) '(bitwise-ior a b)))
  164. call))
  165. (define (simplify-bitwise-xor call)
  166. (simplify-args call 0)
  167. (put-literal-first call)
  168. ((pattern-simplifier
  169. ((bitwise-xor '0 x) x)
  170. ((bitwise-xor 'a 'b) '(bitwise-xor a b)))
  171. call))
  172. (define (simplify-bitwise-not call)
  173. (simplify-args call 0)
  174. ((pattern-simplifier
  175. ((bitwise-not 'a) '(bitwise-not a)))
  176. call))
  177. (define-scheme-primop bitwise-and #f type/integer simplify-bitwise-and)
  178. (define-scheme-primop bitwise-ior #f type/integer simplify-bitwise-ior)
  179. (define-scheme-primop bitwise-xor #f type/integer simplify-bitwise-xor)
  180. (define-scheme-primop bitwise-not #f type/integer simplify-bitwise-not)
  181. (define-syntax simplify-=
  182. (syntax-rules ()
  183. ((simplify-= = op + -)
  184. (lambda (call)
  185. (simplify-args call 0)
  186. (put-literal-first call)
  187. ((pattern-simplifier
  188. ((= 'a 'b) '(op a b))
  189. ((= 'a (+ 'b c)) (= '(- a b) c)) ; will these ever be used?
  190. ((= 'a (- 'b c)) (= '(- b a) c)))
  191. call)))))
  192. (define-syntax simplify-<
  193. (syntax-rules ()
  194. ((simplify-< < op + -)
  195. (lambda (call)
  196. (simplify-args call 0)
  197. ((pattern-simplifier
  198. ((< 'a 'b) '(op a b))
  199. ((< 'a (+ 'b c)) (< '(- a b) c)) ; will these ever be used?
  200. ((< (+ 'b c) 'a) (< c '(- a b)))
  201. ((< 'a (- 'b c)) (< c '(- b a)))
  202. ((< (- 'b c) 'a) (< '(- b a) c)))
  203. call)))))
  204. (define (simplify-char=? call)
  205. (simplify-args call 0)
  206. (put-literal-first call)
  207. ((pattern-simplifier
  208. ((char=? 'a 'b) '(char=? a b))
  209. ((char=? 'a (+ 'b c)) (char=? '(- a b) c))
  210. ((char=? 'a (- 'b c)) (char=? '(- b a) c)))
  211. call))
  212. (define (simplify-char<? call)
  213. (simplify-args call 0)
  214. ((pattern-simplifier
  215. ((char<? 'a 'b) '(char<? a b))
  216. ((char<? 'a (+ 'b c)) (char<? '(- a b) c))
  217. ((char<? (+ 'b c) 'a) (char<? c '(- a b)))
  218. ((char<? 'a (- 'b c)) (char<? c '(- b a)))
  219. ((char<? (- 'b c) 'a) (char<? '(- b a) c)))
  220. call))
  221. (define bool-type
  222. (lambda (call)
  223. type/boolean))
  224. (define-scheme-primop = #f bool-type (simplify-= = = + -))
  225. (define-scheme-primop fl= #f bool-type (simplify-= fl= = fl+ fl-))
  226. (define-scheme-primop un= #f bool-type (simplify-= un= = un+ un-))
  227. (define-scheme-primop < #f bool-type (simplify-< < < + -))
  228. (define-scheme-primop fl< #f bool-type (simplify-< fl< < fl+ fl-))
  229. (define-scheme-primop un< #f bool-type (simplify-< un< < un+ un-))
  230. (define-scheme-primop char=? #f bool-type simplify-char=?)
  231. (define-scheme-primop char<? #f bool-type simplify-char<?)
  232. (define (simplify-char->ascii call)
  233. (simplify-args call 0)
  234. (let ((arg (call-arg call 0)))
  235. (if (literal-node? arg)
  236. (let ((value (literal-value arg)))
  237. (if (char? value)
  238. (replace call (make-literal-node (char->ascii value) #f))
  239. (breakpoint "char->ascii is applied to a non-character literal ~S"
  240. value))))))
  241. (define (simplify-ascii->char call)
  242. (simplify-args call 0)
  243. (let ((arg (call-arg call 0)))
  244. (if (literal-node? arg)
  245. (let ((value (literal-value arg)))
  246. (if (integer? value)
  247. (replace call (make-literal-node (ascii->char value) #f))
  248. (breakpoint "ascii->char is applied to a non-integer literal ~S"
  249. value))))))
  250. (define-scheme-primop char->ascii #f type/integer simplify-char->ascii)
  251. (define-scheme-primop ascii->char #f type/integer simplify-ascii->char)
  252. (define-scheme-primop unsigned->integer type/integer)
  253. (define-scheme-primop integer->unsigned type/unsigned-integer)
  254. ;(define (simplify-sign-extend call)
  255. ; (simplify-args call 0)
  256. ; (let ((value (call-arg call 0)))
  257. ; (cond ((literal-node? value)
  258. ; (set-literal-type! value type/integer)
  259. ; (replace call (detach value))))))
  260. ;
  261. ;(define-scheme-primop sign-extend #f type/integer simplify-sign-extend)
  262. ;(define-scheme-primop zero-extend #f type/integer simplify-sign-extend)