Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions langs/a86/ast.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
(error n "expects register; given ~v" a1))
(unless (or (exact-integer? a2) (register? a2) (offset? a2))
(error n "expects exact integer, register, or offset; given ~v" a2))
(when (and (exact-integer? a2) (> (integer-length a2) 32))
(error n "literal must not exceed 32-bits; given ~v (~v bits); go through a register instead" a2 (integer-length a2)))
(values a1 a2)))

(define check:register
Expand All @@ -51,6 +53,22 @@
(error n "expects register, offset, exact integer, or defined constant; given ~v" a2))
(when (and (offset? a1) (offset? a2))
(error n "cannot use two memory locations; given ~v, ~v" a1 a2))
(when (and (exact-integer? a2) (> (integer-length a2) 32))
(error n "literal must not exceed 32-bits; given ~v (~v bits); go through a register instead" a2 (integer-length a2)))
(when (and (offset? a1) (exact-integer? a2))
(error n "cannot use a memory locations and literal; given ~v, ~v; go through a register instead" a1 a2))
(values a1 a2)))

(define check:mov
(λ (a1 a2 n)
(unless (or (register? a1) (offset? a1))
(error n "expects register or offset; given ~v" a1))
(unless (or (register? a2) (offset? a2) (exact-integer? a2) (Const? a2))
(error n "expects register, offset, exact integer, or defined constant; given ~v" a2))
(when (and (offset? a1) (offset? a2))
(error n "cannot use two memory locations; given ~v, ~v" a1 a2))
(when (and (exact-integer? a2) (> (integer-length a2) 64))
(error n "literal must not exceed 64-bits; given ~v (~v bits)" a2 (integer-length a2)))
(when (and (offset? a1) (exact-integer? a2))
(error n "cannot use a memory locations and literal; given ~v, ~v; go through a register instead" a1 a2))
(values a1 a2)))
Expand All @@ -76,6 +94,8 @@
(λ (a1 n)
(unless (or (exact-integer? a1) (register? a1))
(error n "expects exact integer or register; given ~v" a1))
(when (and (exact-integer? a1) (> (integer-length a1) 32))
(error n "literal must not exceed 32-bits; given ~v (~v bits); go through a register instead" a1 (integer-length a1)))
a1))

(define check:lea
Expand Down Expand Up @@ -126,7 +146,7 @@
(instruct Label (x) check:label-symbol)
(instruct Call (x) check:target)
(instruct Ret () check:none)
(instruct Mov (dst src) check:src-dest)
(instruct Mov (dst src) check:mov)
(instruct Add (dst src) check:arith)
(instruct Sub (dst src) check:arith)
(instruct Cmp (a1 a2) check:src-dest)
Expand Down Expand Up @@ -169,14 +189,22 @@
(symbol? x)
(integer? x)))

(provide offset? register? instruction? label?)
(provide offset? register? instruction? label? 64-bit-integer? 32-bit-integer?)

(define offset? Offset?)

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

(define (64-bit-integer? x)
(and (exact-integer? x)
(<= (integer-length x) 64)))

(define (32-bit-integer? x)
(and (exact-integer? x)
(<= (integer-length x) 32)))

(define (label? x)
(and (symbol? x)
(nasm-label? x)
Expand Down
18 changes: 18 additions & 0 deletions langs/a86/test/errors.rkt
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,21 @@
(require rackunit "../ast.rkt")
(check-exn exn:fail?
(thunk (Mov (Offset 'rax 0) 100)))

;; Checking literal widths
(check-exn exn:fail? (thunk (Mov 'rax (expt 2 64))))
(check-not-exn (thunk (Mov 'rax (sub1 (expt 2 64)))))
(check-exn exn:fail? (thunk (Cmp 'rax (expt 2 32))))
(check-not-exn (thunk (Cmp 'rax (sub1 (expt 2 32)))))
(check-exn exn:fail? (thunk (And 'rax (expt 2 32))))
(check-not-exn (thunk (And 'rax (sub1 (expt 2 32)))))
(check-exn exn:fail? (thunk (Or 'rax (expt 2 32))))
(check-not-exn (thunk (Or 'rax (sub1 (expt 2 32)))))
(check-exn exn:fail? (thunk (Xor 'rax (expt 2 32))))
(check-not-exn (thunk (Xor 'rax (sub1 (expt 2 32)))))
(check-exn exn:fail? (thunk (Push (expt 2 32))))
(check-not-exn (thunk (Push (sub1 (expt 2 32)))))
(check-exn exn:fail? (thunk (Add 'rax (expt 2 32))))
(check-not-exn (thunk (Add 'rax (sub1 (expt 2 32)))))
(check-exn exn:fail? (thunk (Sub 'rax (expt 2 32))))
(check-not-exn (thunk (Sub 'rax (sub1 (expt 2 32)))))
38 changes: 30 additions & 8 deletions www/notes/a86.scrbl
Original file line number Diff line number Diff line change
Expand Up @@ -720,6 +720,28 @@ Each register plays the same role as in x86, so for example
A predicate for offsets.
}

@defproc[(64-bit-integer? [x any/c]) boolean?]{
A predicate for determining if a value is an integer that fits in 64-bits.

@ex[
(64-bit-integer? 0)
(64-bit-integer? (sub1 (expt 2 64)))
(64-bit-integer? (expt 2 64))
(64-bit-integer? (- (expt 2 63)))
(64-bit-integer? (sub1 (- (expt 2 63))))]
}

@defproc[(32-bit-integer? [x any/c]) boolean?]{
A predicate for determining if a value is an integer that fits in 64-bits.

@ex[
(32-bit-integer? 0)
(32-bit-integer? (sub1 (expt 2 32)))
(32-bit-integer? (expt 2 32))
(32-bit-integer? (- (expt 2 32)))
(32-bit-integer? (sub1 (- (expt 2 32))))]
}

@defproc[(seq [x (or/c instruction? (listof instruction?))] ...) (listof instruction?)]{
A convenience function for splicing togeter instructions and lists of instructions.

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

}

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

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

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

}

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

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

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

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

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

Expand Down Expand Up @@ -1028,7 +1050,7 @@ Each register plays the same role as in x86, so for example
]
}

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

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

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

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

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

@#reader scribble/comment-reader
Expand Down Expand Up @@ -1113,7 +1135,7 @@ Each register plays the same role as in x86, so for example
)
}

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

Decrements the stack pointer and then stores the source
operand on the top of the stack.
Expand Down