Skip to content

Commit 6c5fc43

Browse files
committed
Check immediate ranges. Addresses much of #115.
1 parent d13554f commit 6c5fc43

3 files changed

Lines changed: 70 additions & 15 deletions

File tree

langs/a86/ast.rkt

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@
3535
(error n "expects register; given ~v" a1))
3636
(unless (or (exact-integer? a2) (register? a2) (offset? a2))
3737
(error n "expects exact integer, register, or offset; given ~v" a2))
38+
(when (and (exact-integer? a2) (> (integer-length a2) 32))
39+
(error n "literal must not exceed 32-bits; given ~v (~v bits); go through a register instead" a2 (integer-length a2)))
3840
(values a1 a2)))
3941

4042
(define check:register
@@ -43,18 +45,21 @@
4345
(error n "expects register; given ~v" a1))
4446
a1))
4547

46-
(define check:src-dest
48+
(define (check:src-dest width)
4749
(λ (a1 a2 n)
4850
(unless (or (register? a1) (offset? a1))
4951
(error n "expects register or offset; given ~v" a1))
5052
(unless (or (register? a2) (offset? a2) (exact-integer? a2) (Const? a2))
5153
(error n "expects register, offset, exact integer, or defined constant; given ~v" a2))
5254
(when (and (offset? a1) (offset? a2))
5355
(error n "cannot use two memory locations; given ~v, ~v" a1 a2))
56+
(when (and (exact-integer? a2) (> (integer-length a2) width))
57+
(error n "literal must not exceed ~v-bits; given ~v (~v bits); go through a register instead" width a2 (integer-length a2)))
5458
(when (and (offset? a1) (exact-integer? a2))
5559
(error n "cannot use a memory locations and literal; given ~v, ~v; go through a register instead" a1 a2))
5660
(values a1 a2)))
5761

62+
5863
(define check:shift
5964
(λ (a1 a2 n)
6065
(unless (register? a1)
@@ -76,6 +81,8 @@
7681
(λ (a1 n)
7782
(unless (or (exact-integer? a1) (register? a1))
7883
(error n "expects exact integer or register; given ~v" a1))
84+
(when (and (exact-integer? a1) (> (integer-length a1) 32))
85+
(error n "literal must not exceed 32-bits; given ~v (~v bits); go through a register instead" a1 (integer-length a1)))
7986
a1))
8087

8188
(define check:lea
@@ -126,20 +133,20 @@
126133
(instruct Label (x) check:label-symbol)
127134
(instruct Call (x) check:target)
128135
(instruct Ret () check:none)
129-
(instruct Mov (dst src) check:src-dest)
136+
(instruct Mov (dst src) (check:src-dest 64))
130137
(instruct Add (dst src) check:arith)
131138
(instruct Sub (dst src) check:arith)
132-
(instruct Cmp (a1 a2) check:src-dest)
139+
(instruct Cmp (a1 a2) (check:src-dest 32))
133140
(instruct Jmp (x) check:target)
134141
(instruct Je (x) check:target)
135142
(instruct Jne (x) check:target)
136143
(instruct Jl (x) check:target)
137144
(instruct Jle (x) check:target)
138145
(instruct Jg (x) check:target)
139146
(instruct Jge (x) check:target)
140-
(instruct And (dst src) check:src-dest)
141-
(instruct Or (dst src) check:src-dest)
142-
(instruct Xor (dst src) check:src-dest)
147+
(instruct And (dst src) (check:src-dest 32))
148+
(instruct Or (dst src) (check:src-dest 32))
149+
(instruct Xor (dst src) (check:src-dest 32))
143150
(instruct Sal (dst i) check:shift)
144151
(instruct Sar (dst i) check:shift)
145152
(instruct Push (a1) check:push)
@@ -169,14 +176,22 @@
169176
(symbol? x)
170177
(integer? x)))
171178

172-
(provide offset? register? instruction? label?)
179+
(provide offset? register? instruction? label? 64-bit-integer? 32-bit-integer?)
173180

174181
(define offset? Offset?)
175182

176183
(define (register? x)
177184
(and (memq x '(cl eax rax rbx rcx rdx rbp rsp rsi rdi r8 r9 r10 r11 r12 r13 r14 r15))
178185
#t))
179186

187+
(define (64-bit-integer? x)
188+
(and (exact-integer? x)
189+
(<= (integer-length x) 64)))
190+
191+
(define (32-bit-integer? x)
192+
(and (exact-integer? x)
193+
(<= (integer-length x) 32)))
194+
180195
(define (label? x)
181196
(and (symbol? x)
182197
(nasm-label? x)

langs/a86/test/errors.rkt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,21 @@
22
(require rackunit "../ast.rkt")
33
(check-exn exn:fail?
44
(thunk (Mov (Offset 'rax 0) 100)))
5+
6+
;; Checking literal widths
7+
(check-exn exn:fail? (thunk (Mov 'rax (expt 2 64))))
8+
(check-not-exn (thunk (Mov 'rax (sub1 (expt 2 64)))))
9+
(check-exn exn:fail? (thunk (Cmp 'rax (expt 2 32))))
10+
(check-not-exn (thunk (Cmp 'rax (sub1 (expt 2 32)))))
11+
(check-exn exn:fail? (thunk (And 'rax (expt 2 32))))
12+
(check-not-exn (thunk (And 'rax (sub1 (expt 2 32)))))
13+
(check-exn exn:fail? (thunk (Or 'rax (expt 2 32))))
14+
(check-not-exn (thunk (Or 'rax (sub1 (expt 2 32)))))
15+
(check-exn exn:fail? (thunk (Xor 'rax (expt 2 32))))
16+
(check-not-exn (thunk (Xor 'rax (sub1 (expt 2 32)))))
17+
(check-exn exn:fail? (thunk (Push (expt 2 32))))
18+
(check-not-exn (thunk (Push (sub1 (expt 2 32)))))
19+
(check-exn exn:fail? (thunk (Add 'rax (expt 2 32))))
20+
(check-not-exn (thunk (Add 'rax (sub1 (expt 2 32)))))
21+
(check-exn exn:fail? (thunk (Sub 'rax (expt 2 32))))
22+
(check-not-exn (thunk (Sub 'rax (sub1 (expt 2 32)))))

www/notes/a86.scrbl

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,28 @@ Each register plays the same role as in x86, so for example
720720
A predicate for offsets.
721721
}
722722

723+
@defproc[(64-bit-integer? [x any/c]) boolean?]{
724+
A predicate for determining if a value is an integer that fits in 64-bits.
725+
726+
@ex[
727+
(64-bit-integer? 0)
728+
(64-bit-integer? (sub1 (expt 2 64)))
729+
(64-bit-integer? (expt 2 64))
730+
(64-bit-integer? (- (expt 2 63)))
731+
(64-bit-integer? (sub1 (- (expt 2 63))))]
732+
}
733+
734+
@defproc[(32-bit-integer? [x any/c]) boolean?]{
735+
A predicate for determining if a value is an integer that fits in 64-bits.
736+
737+
@ex[
738+
(32-bit-integer? 0)
739+
(32-bit-integer? (sub1 (expt 2 32)))
740+
(32-bit-integer? (expt 2 32))
741+
(32-bit-integer? (- (expt 2 32)))
742+
(32-bit-integer? (sub1 (- (expt 2 32))))]
743+
}
744+
723745
@defproc[(seq [x (or/c instruction? (listof instruction?))] ...) (listof instruction?)]{
724746
A convenience function for splicing togeter instructions and lists of instructions.
725747

@@ -866,7 +888,7 @@ Each register plays the same role as in x86, so for example
866888

867889
}
868890

869-
@defstruct*[Mov ([dst (or/c register? offset?)] [src (or/c register? offset? exact-integer?)])]{
891+
@defstruct*[Mov ([dst (or/c register? offset?)] [src (or/c register? offset? 64-bit-integer?)])]{
870892

871893
A move instruction. Moves @racket[src] to @racket[dst].
872894

@@ -885,7 +907,7 @@ Each register plays the same role as in x86, so for example
885907

886908
}
887909

888-
@defstruct*[Add ([dst register?] [src (or/c register? offset? exact-integer?)])]{
910+
@defstruct*[Add ([dst register?] [src (or/c register? offset? 32-bit-integer?)])]{
889911

890912
An addition instruction. Adds @racket[src] to @racket[dst]
891913
and writes the result to @racket[dst].
@@ -901,7 +923,7 @@ Each register plays the same role as in x86, so for example
901923
]
902924
}
903925

904-
@defstruct*[Sub ([dst register?] [src (or/c register? offset? exact-integer?)])]{
926+
@defstruct*[Sub ([dst register?] [src (or/c register? offset? 32-bit-integer?)])]{
905927

906928
A subtraction instruction. Subtracts @racket[src] frrom
907929
@racket[dst] and writes the result to @racket[dst].
@@ -917,7 +939,7 @@ Each register plays the same role as in x86, so for example
917939
]
918940
}
919941

920-
@defstruct*[Cmp ([a1 (or/c register? offset?)] [a2 (or/c register? offset? exact-integer?)])]{
942+
@defstruct*[Cmp ([a1 (or/c register? offset?)] [a2 (or/c register? offset? 32-bit-integer?)])]{
921943
Compare @racket[a1] to @racket[a2]. Doing a comparison
922944
sets the status flags that affect the conditional instructions like @racket[Je], @racket[Jl], etc.
923945

@@ -1028,7 +1050,7 @@ Each register plays the same role as in x86, so for example
10281050
]
10291051
}
10301052

1031-
@defstruct*[And ([dst (or/c register? offset?)] [src (or/c register? offset? exact-integer?)])]{
1053+
@defstruct*[And ([dst (or/c register? offset?)] [src (or/c register? offset? 32-bit-integer?)])]{
10321054
Compute logical ``and'' of @racket[dst] and @racket[src] and put result in @racket[dst].
10331055

10341056
@#reader scribble/comment-reader
@@ -1043,7 +1065,7 @@ Each register plays the same role as in x86, so for example
10431065
)
10441066
}
10451067

1046-
@defstruct*[Or ([dst (or/c register? offset?)] [src (or/c register? offset? exact-integer?)])]{
1068+
@defstruct*[Or ([dst (or/c register? offset?)] [src (or/c register? offset? 32-bit-integer?)])]{
10471069
Compute logical ``or'' of @racket[dst] and @racket[src] and put result in @racket[dst].
10481070

10491071
@#reader scribble/comment-reader
@@ -1058,7 +1080,7 @@ Each register plays the same role as in x86, so for example
10581080
)
10591081
}
10601082

1061-
@defstruct*[Xor ([dst (or/c register? offset?)] [src (or/c register? offset? exact-integer?)])]{
1083+
@defstruct*[Xor ([dst (or/c register? offset?)] [src (or/c register? offset? 32-bit-integer?)])]{
10621084
Compute logical ``exclusive or'' of @racket[dst] and @racket[src] and put result in @racket[dst].
10631085

10641086
@#reader scribble/comment-reader
@@ -1113,7 +1135,7 @@ Each register plays the same role as in x86, so for example
11131135
)
11141136
}
11151137

1116-
@defstruct*[Push ([a1 (or/c exact-integer? register?)])]{
1138+
@defstruct*[Push ([a1 (or/c 32-bit-integer? register?)])]{
11171139

11181140
Decrements the stack pointer and then stores the source
11191141
operand on the top of the stack.

0 commit comments

Comments
 (0)