(load "typecheck.scm")
(load "ast.scm")
(load "platform.scm")
+(load "stdlib.scm")
(define target host-os)
(define wordsize 8)
-(define (stack-type? data-layouts type)
- (if (assoc type data-layouts) #t #f))
+(define (stack-type? dls type)
+ (if (adt? dls type)
+ (> (type-size dls type) wordsize)
+ #f))
+(define (adt? data-layouts type) (assoc type data-layouts))
(define (type-size data-layouts type)
(case type
['Int wordsize]
- ['Bool wordsize]
[else
(let ([adt (assoc type data-layouts)])
(if adt
(adt-size adt)
(error #f "unknown size" type)))]))
+(define (singletons dls)
+ (flat-map
+ (lambda (sums)
+ (fold-left append '()
+ (filter (lambda (x) (= 1 (length x))) sums)))
+ (map cdr dls)))
+
+(define (singleton? dls x)
+ (memv x (singletons dls)))
+
; returns the size of an expression's result in bytes
(define (expr-size dls e)
(if (eqv? (ast-type e) 'stack)
[dls (env-data-layouts env)]
- [singleton? (and stack-type
- (assoc name
- (cdr (assoc stack-type dls))))]
[stack-offset (assoc name (env-bindings env))])
+
(when (and (not stack-offset) (not singleton?))
(error #f (format "Variable ~a is not bound" name)))
- (if (on-stack? e)
- (if singleton?
+ (cond
+ [(singleton? dls name)
; singletons don't need to be in the environment
- ; just copy over the tag
- (emit "movq $~a, ~a(%rbp)"
- (data-sum-tag (env-data-layouts env)
- stack-type
- name)
- si)
- (emit-stack-copy (cdr stack-offset) si (type-size dls stack-type)))
- (emit "movq ~a(%rbp), %rax" (cdr stack-offset)))))
+ ; just store the tag
+ (let ([tag (data-sum-tag (env-data-layouts env) name)])
+ (if (on-stack? e)
+ (emit "movq $~a, ~a(%rbp)" tag si)
+ (emit "movq $~a, %rax" tag)))]
+ [(on-stack? e) (emit-stack-copy (cdr stack-offset) si (type-size dls stack-type))]
+ [else (emit "movq ~a(%rbp), %rax" (cdr stack-offset))])))
(define cur-lambda 0)
(define (fresh-lambda)
(define (codegen-lambda l)
(let* ((label (car l))
(stuff (cdr l))
- (captives (car stuff))
- (args (cadr stuff))
- (body (caddr stuff))
+ (dls (car stuff))
+ (captives (cadr stuff))
+ (args (caddr stuff))
+ (body (cadddr stuff))
; params = what actually gets passed
(params (append captives args))
(range 0 (length params))))
[bindings (map cons params stack-offsets)]
- [env (make-env '() bindings)])
+ [env (make-env dls bindings)])
(emit "~a:" label)
(display "## lambda captives: ")
(range 0 (length (cdr x))))))))
- (let ([sums (assoc type dls)])
- (if sums
+ (if (adt? dls type)
(let* ([sum (if (list? x) (car x) x)] ; can sometimes be a singleton
- [tag (data-sum-tag dls type sum)])
+ [tag (data-sum-tag dls sum)])
; the tag is at the top (beginning) of the adt on the stack
(emit "cmpq $~a, ~a(%rbp)" tag inner-offset)
(emit "jne ~a" jne-label)
(begin
(emit "cmpq $~a, ~a(%rbp)" x inner-offset)
(emit "jne ~a" jne-label)
- '() )))))
+ '() ))))
(define (codegen-adt-match type case)
(let* ([match (car case)]
(emit "~a:" next-section-label)))
(define (codegen-literal-match case)
- (let ([next-section-label (fresh-label)])
- (emit "cmpq $~a, %rax" (car case))
+ (let* ([next-section-label (fresh-label)]
+ [match (car case)]
+ [val (if (singleton? dls match)
+ (data-sum-tag dls match)
+ match)])
+ (emit "cmpq $~a, %rax" val)
(emit "jne ~a" next-section-label)
(codegen-expr (cadr case) si env)
(emit "jmp ~a" exit-label)
; (and store it on the stack if not a stack value)
(codegen-expr switch si env)
- (if (eqv? 'stack (ast-type switch))
+ (if (on-stack? switch)
; adt pattern match
(for-each (lambda (x) (codegen-adt-match (cadr switch) x)) cases)
(for-each codegen-literal-match cases))
wordsize ; skip the tag in the first word
to-traverse)))
-(define (data-sum-tag data-layouts type sum)
+(define (data-sum-tag data-layouts sum)
(define (go acc sums)
(when (null? sums) (error #f "data-sum-tag no sum for type" sum type))
(if (eqv? sum (car sums))
acc
(go (+ 1 acc) (cdr sums))))
- (let* ([type-sums (cdr (assoc type data-layouts))])
+ (let* ([all-sum-names (flat-map (lambda (x) (map (lambda (y) (cons (car y) (car x))) (cdr x))) data-layouts)]
+ [type (cdr (assoc sum all-sum-names))]
+ [type-sums (cdr (assoc type data-layouts))])
(go 0 (map car type-sums))))
(define (codegen-data-tor e si env)
[args (cdr e)]
[tag (data-sum-tag (env-data-layouts env)
- type
sum)]
[inner-si (- si (type-size dls type))]
; takes in a expr annotated with types and returns a type-less AST
; with stack values wrapped
(define (annotate-stack-values data-layouts ann-e)
- (define (stack-type? type)
- (assoc type data-layouts))
(define (strip e)
(ast-traverse strip (ann-expr e)))
(let* ([e (ann-expr ann-e)]
[type (ann-type ann-e)])
- (if (stack-type? type)
+ (if (stack-type? data-layouts type)
`(stack ,type
,(ast-traverse (lambda (x) (annotate-stack-values data-layouts x)) e))
(ast-traverse (lambda (x)
(annotate-stack-values data-layouts x))
e))))
-(define (free-vars prog)
- (define bound '())
+(define (free-vars dls prog)
+ (define bound (singletons dls))
(define (collect e)
(case (ast-type e)
('builtin '()) ; do nothing
; outside of an immediate app
; but only one closure for each builtin
-(define (extract-lambdas program)
+(define (extract-lambdas dls program)
(define lambdas '())
(define (add-lambda e)
(let* ((label (fresh-lambda))
(args (lambda-args e))
- (captured (free-vars e))
+ (captured (free-vars dls e))
(body (extract (lambda-body e)))
- (new-lambda (cons label (list captured args body))))
+ (new-lambda (cons label (list dls captured args body))))
(set! lambdas (cons new-lambda lambdas))
`(closure ,label ,captured))) ; todo: should we string->symbol?
(captured '())
(args (builtin-args e))
(body `(,e ,@args))
- (new-lambda (cons label (list captured args body)))]
+ (new-lambda (cons label (list dls captured args body)))]
(set! lambdas (cons new-lambda lambdas))
`(closure ,label ,captured)))
(emit "movq heap_start@GOTPCREL(%rip), %rsi")
(emit "movq %rax, (%rsi)")))
-(define (codegen program)
+(define (codegen program-without-stdlib)
(set! cur-label 0)
(set! cur-lambda 0)
- (let* ([data-layouts (program-data-layouts program)]
+ (let* ([program (append stdlib program-without-stdlib)]
+ [data-layouts (program-data-layouts program)]
[pattern-matched (expand-pattern-matches program)]
[type-annotated (annotate-types pattern-matched)]
(strings-res (extract-strings stack-annotated))
(strings (car strings-res))
- (lambdas-res (extract-lambdas (cdr strings-res)))
+ (lambdas-res (extract-lambdas data-layouts (cdr strings-res)))
(lambdas (car lambdas-res))
(xform-prog (cdr lambdas-res)))
+ ; verify pattern matches are total
+ (verify-cases data-layouts type-annotated)
+
(emit "\t.global _start")
(emit "\t.text")
- ; (emit ".p2align 4,,15") is this needed?
(for-each codegen-lambda lambdas)
(initialize-heap)
(emit "movq %rsp, %rbp") ; set up the base pointer
-
(codegen-expr xform-prog (- wordsize) (make-env data-layouts '()))
; exit syscall