Skip to content

Commit 348b4c0

Browse files
committed
make UFix arithmetic processor-native
This commit also fixes UFix underflow issues - make RANGE-DECREASING handle unsigned types gracefully - fix Seq's CST-SEARCH - fix use of DECREMENT! in Brainfold example
1 parent 119dea4 commit 348b4c0

File tree

5 files changed

+84
-13
lines changed

5 files changed

+84
-13
lines changed

examples/small-coalton-programs/src/brainfold.lisp

+8-2
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
(define (value-at-pointer bfs)
7979
"Returns the value at the current pointer."
8080
(vec:index-unsafe (cell:read (.pointer bfs))
81-
(.memory bfs))))
81+
(.memory bfs))))
8282

8383
;;;
8484
;;; Commands (Functions called by Brainfold Cmds)
@@ -98,12 +98,18 @@
9898
(pure (cell:increment! (.pointer bfs)))
9999
(state:put bfs)))
100100

101+
(define (dec! cell)
102+
(let ((value (cell:read cell)))
103+
(if (arith:zero? value)
104+
0
105+
(cell:write! cell (1- value)))))
106+
101107
(declare move-left (Unit -> (state:ST BF-State Unit)))
102108
(define (move-left)
103109
"Moves the pointer one bf-cell to the left."
104110
(do
105111
(bfs <- state:get)
106-
(pure (cell:decrement! (.pointer bfs)))
112+
(pure (dec! (.pointer bfs)))
107113
(state:put bfs)))
108114

109115
;;

library/iterator.lisp

+38-7
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,17 @@ iterator is empty."
191191
"An iterator which begins at zero and counts up through and including LIMIT."
192192
(up-to (+ 1 limit)))
193193

194+
195+
;; All the haranguing below is so that we don't overflow a bounded
196+
;; type in a range-decreasing call. We generally assume a lower
197+
;; bound (e.g., 0 for unsigned types) is more common than an upper
198+
;; bound.
199+
(repr :enum)
200+
(define-type RangeStatus
201+
RangeContinue
202+
RangeLast
203+
RangeDone)
204+
194205
(declare range-decreasing ((Num :num) (Ord :num) =>
195206
:num ->
196207
:num ->
@@ -201,16 +212,36 @@ iterator is empty."
201212
202213
Equivalent to reversing `range-increasing`"
203214
(assert (<= end start)
204-
"END ~a should be less than or equal to START ~a in RANGE-INCREASING"
215+
"END ~a should be less than or equal to START ~a in RANGE-DECREASING"
205216
end start)
206217
(assert (> step 0)
207-
"STEP ~a should be positive and non-zero in RANGE-INCREASING"
218+
"STEP ~a should be positive and non-zero in RANGE-DECREASING"
208219
step)
209-
;; FIXME: avoid underflow in the DONE? test
210-
(recursive-iter ((flip -) step)
211-
(fn (n) (>= end (+ n step))) ; like (>= (- end step)), but without potential underflow
212-
(- start step) ; begin after START
213-
))
220+
(let ((end+step (+ end step)))
221+
(if (< start end+step)
222+
empty
223+
(let ((start-step (- start step))
224+
(next (cell:new start-step))
225+
(status (cell:new (if (< start-step end+step)
226+
RangeLast
227+
RangeContinue))))
228+
(%Iterator
229+
(fn ()
230+
(match (cell:read status)
231+
((RangeDone)
232+
None)
233+
((RangeLast)
234+
(cell:write! status RangeDone)
235+
(Some (cell:read next)))
236+
((RangeContinue)
237+
(let ((this (cell:read next))
238+
(next-next (- this step)))
239+
(cell:write! status (if (< next-next end+step)
240+
RangeLast
241+
RangeContinue))
242+
(cell:write! next next-next)
243+
(Some this)))))
244+
None)))))
214245

215246
(declare down-from ((Num :num) (Ord :num) => :num -> Iterator :num))
216247
(define (down-from limit)

library/math/num.lisp

+27-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
(:use
77
#:coalton
88
#:coalton-library/math/num-defining-macros)
9+
(:local-nicknames
10+
(#:cls #:coalton-library/classes))
911
(:import-from
1012
#:coalton-library/hash
1113
#:define-sxhash-hasher))
@@ -73,7 +75,31 @@
7375
(define-num-wrapping U16 16)
7476
(define-num-wrapping U32 32)
7577
(define-num-wrapping U64 64)
76-
(define-num-wrapping UFix #.+unsigned-fixnum-bits+)
78+
79+
;; UFixes are unsafe and depend on implementation.
80+
(define-instance (cls:Num UFix)
81+
(inline)
82+
(define (cls:+ a b)
83+
(lisp UFix (a b)
84+
(cl:locally (cl:declare (cl:optimize cl:speed (cl:safety 0)))
85+
(cl:+ a b))))
86+
87+
(inline)
88+
(define (cls:- a b)
89+
(lisp UFix (a b)
90+
(cl:locally (cl:declare (cl:optimize cl:speed (cl:safety 0)))
91+
(cl:- a b))))
92+
93+
(inline)
94+
(define (cls:* a b)
95+
(lisp UFix (a b)
96+
(cl:locally (cl:declare (cl:optimize cl:speed (cl:safety 0)))
97+
(cl:* a b))))
98+
99+
(inline)
100+
(define (cls:fromInt x)
101+
(lisp UFix (x)
102+
(cl:mod x #.(cl:expt 2 +fixnum-bits+)))))
77103

78104

79105
;;;

library/seq.lisp

+3-1
Original file line numberDiff line numberDiff line change
@@ -284,7 +284,9 @@ a new `Seq` instance."
284284
(if (< idx cumulative)
285285
(pure (Tuple gs last-cumulative))
286286
(search-forward (+ 1 gs) cumulative))))))
287-
(>>= (alt (vector:index (- guess 1) cst) ; Note, 0 <= guess <= 31
287+
(>>= (alt (if (math:zero? guess) ; avoid UFix underflow
288+
None
289+
(vector:index (- guess 1) cst)) ; Note, 0 < guess <= 31
288290
(pure 0))
289291
(search-forward guess))))
290292

tests/iterator-tests.lisp

+8-2
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,12 @@
100100
(iter:repeat-for "foo" 10)))))
101101

102102
(define-test iter-downfrom ()
103+
(is (== (the (List UFix) Nil)
104+
(iter:collect! (iter:down-from 0))))
105+
(is (== (the (List UFix) (make-list 0))
106+
(iter:collect! (iter:down-from 1))))
107+
(is (== (the (List UFix) (make-list 9 8 7 6 5 4 3 2 1 0))
108+
(iter:collect! (iter:down-from 10))))
103109
(is (== (the (List Integer) (make-list 9 8 7 6 5 4 3 2 1 0))
104110
(iter:collect! (iter:down-from 10))))
105111
(is (== (the (List Integer) (make-list 9 8 7 6 5 4 3 2 1 0))
@@ -120,10 +126,10 @@
120126
(iter:up-to 10)))))
121127
(is (== (Some (the Integer 0))
122128
(iter:maximize-by! negate (iter:chain! (iter:up-to 10)
123-
(iter:down-from 10)))))
129+
(iter:down-from 10)))))
124130
(is (== (Some (the Integer 10))
125131
(iter:minimize-by! negate (iter:chain! (iter:down-from 10)
126-
(iter:up-through 10))))))
132+
(iter:up-through 10))))))
127133

128134
(define-test iter-optimize-string-length ()
129135
(let ((longer? (fn (long short)

0 commit comments

Comments
 (0)