wip: start working on trivial register allocation
This commit is contained in:
parent
9c2895e4ed
commit
8a4948475c
|
|
@ -1,6 +1,19 @@
|
||||||
#lang racket
|
#lang racket
|
||||||
|
|
||||||
(provide Label Var Reg Imm LMov Add Sub RetDefault Svc Bl)
|
(provide
|
||||||
|
(struct-out Label)
|
||||||
|
(struct-out Var)
|
||||||
|
(struct-out Reg)
|
||||||
|
(struct-out Imm)
|
||||||
|
(struct-out LMov)
|
||||||
|
(struct-out AMOffset)
|
||||||
|
(struct-out Ldr)
|
||||||
|
(struct-out Str)
|
||||||
|
(struct-out Add)
|
||||||
|
(struct-out Sub)
|
||||||
|
(struct-out RetDefault)
|
||||||
|
(struct-out Svc)
|
||||||
|
(struct-out Bl))
|
||||||
|
|
||||||
(require racket/struct)
|
(require racket/struct)
|
||||||
|
|
||||||
|
|
@ -10,6 +23,9 @@
|
||||||
(struct Reg (reg-name) #:transparent)
|
(struct Reg (reg-name) #:transparent)
|
||||||
(struct Imm (immediate) #:transparent)
|
(struct Imm (immediate) #:transparent)
|
||||||
(struct LMov (src dest) #:transparent)
|
(struct LMov (src dest) #:transparent)
|
||||||
|
(struct AMOffset (base-reg offset) #:transparent)
|
||||||
|
(struct Ldr (src dest) #:transparent)
|
||||||
|
(struct Str (src dest) #:transparent)
|
||||||
(struct Add (op1 op2 dest) #:transparent)
|
(struct Add (op1 op2 dest) #:transparent)
|
||||||
(struct Sub (op1 op2 dest) #:transparent)
|
(struct Sub (op1 op2 dest) #:transparent)
|
||||||
(struct RetDefault () #:transparent)
|
(struct RetDefault () #:transparent)
|
||||||
|
|
@ -23,3 +39,4 @@
|
||||||
x19 x20 x21 x22 x23 x24
|
x19 x20 x21 x22 x23 x24
|
||||||
x25 x26 x27 x28 x29 x30
|
x25 x26 x27 x28 x29 x30
|
||||||
sp pc xzr))
|
sp pc xzr))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,105 @@
|
||||||
|
#lang racket
|
||||||
|
|
||||||
|
(require "aarch64var.rkt")
|
||||||
|
|
||||||
|
; the allocation strategy is quite trivial:
|
||||||
|
; always use stack to store results of operations and retrieve operands
|
||||||
|
; use temporary registers starting from x0 to perform the operation
|
||||||
|
; note that this separation is necessary because ARM is a load/store ISA
|
||||||
|
; x0 is used to store the returned value as per Aarch64 calling convention,
|
||||||
|
; this is already handled by instruction selection
|
||||||
|
|
||||||
|
|
||||||
|
; allocate-regs-std-instr
|
||||||
|
; this procedure should only be applied to: Add, Sub, RetDefault, Svc, Bl etc
|
||||||
|
; Use allocate-regs-lmov-instr for LMov
|
||||||
|
|
||||||
|
; stack-map is a map with keys being the variables
|
||||||
|
; and values the position relative to stack base (frame pointer?)
|
||||||
|
|
||||||
|
; stack-top is the offset where an eventual next variable would be
|
||||||
|
; allocated into the stack
|
||||||
|
; note that this is a virtual offset; sp must by aligned to 16 bytes
|
||||||
|
|
||||||
|
; returns the generated instructions
|
||||||
|
; the stack-map is modified if needed
|
||||||
|
;
|
||||||
|
; TODO: does it make sense to use create-stack-bindings on instr-args?
|
||||||
|
(define (allocate-regs-std-instr! instr stack-map stack-top)
|
||||||
|
(begin
|
||||||
|
(define instr-dest (AArch64-instr-dest instr))
|
||||||
|
(define instr-args (AArch64-instr-args instr))
|
||||||
|
(create-stack-bindings! (append instr-args instr-dest) stack-map stack-top)
|
||||||
|
(define reg-args (generate-regs 0 (length instr-args)))
|
||||||
|
(define reg-dest (generate-regs (length instr-args) (length instr-dest)))
|
||||||
|
(append (generate-ldr instr-args stack-map)
|
||||||
|
(list (AArch64-instr-from-dest-args instr reg-dest reg-args))
|
||||||
|
(generate-str instr-dest stack-map))))
|
||||||
|
|
||||||
|
(define (generate-regs start len)
|
||||||
|
(map (lambda (i)
|
||||||
|
(Reg (string->symbol (string-append "x" (number->string i)))))
|
||||||
|
(range start (+ start len))))
|
||||||
|
|
||||||
|
(define (generate-ldr var-list stack-map)
|
||||||
|
(for/list ([var var-list]
|
||||||
|
[reg (generate-regs 0 (length var-list))])
|
||||||
|
(Ldr (AMOffset 'sp (hash-ref stack-map (Var-var-name var))) reg)))
|
||||||
|
|
||||||
|
(define (generate-str var-list stack-map)
|
||||||
|
(list))
|
||||||
|
|
||||||
|
|
||||||
|
; generate stack read/writes and allocate registers for
|
||||||
|
; a LMov instruction
|
||||||
|
;(define (allocate-regs-lmov-instr! instr stack-map))
|
||||||
|
|
||||||
|
; create bindings for the operands that are Var
|
||||||
|
(define (create-stack-bindings! operand-list stack-map stack-top)
|
||||||
|
(begin
|
||||||
|
(for-each (lambda (op)
|
||||||
|
(match op
|
||||||
|
[(Var var-name)
|
||||||
|
(begin
|
||||||
|
(create-stack-binding! var-name stack-map stack-top))]
|
||||||
|
[_ '()]))
|
||||||
|
operand-list)))
|
||||||
|
|
||||||
|
; modify the stack map if the variable is not there yet
|
||||||
|
; only works for 64 bit integers
|
||||||
|
(define (create-stack-binding! var-name stack-map stack-top)
|
||||||
|
(begin
|
||||||
|
(hash-update! stack-map
|
||||||
|
var-name
|
||||||
|
identity
|
||||||
|
stack-top)
|
||||||
|
(set! stack-top (- stack-top 8))))
|
||||||
|
|
||||||
|
(define (AArch64-instr-dest instr)
|
||||||
|
(match instr
|
||||||
|
[(? LMov?) (list (LMov-dest instr))]
|
||||||
|
[(? Add?) (list (Add-dest instr))]
|
||||||
|
[(? Sub?) (list (Sub-dest instr))]
|
||||||
|
[(? RetDefault?) (list)]))
|
||||||
|
|
||||||
|
(define (AArch64-instr-args instr)
|
||||||
|
(match instr
|
||||||
|
[(? LMov?) (list (LMov-src instr))]
|
||||||
|
[(Add op1 op2 _) (list op1 op2)]
|
||||||
|
[(Sub op1 op2 _) (list op1 op2)]
|
||||||
|
[(? RetDefault?) (list)]))
|
||||||
|
|
||||||
|
(define (AArch64-instr-from-dest-args instr dest args)
|
||||||
|
(let ([constructor-args
|
||||||
|
(match instr
|
||||||
|
[(? LMov?) (append args dest)]
|
||||||
|
[(? Add?) (append args dest)]
|
||||||
|
[(? Sub?) (append args dest)]
|
||||||
|
[(? RetDefault?) (list)])])
|
||||||
|
(construct-new-instr instr constructor-args)))
|
||||||
|
|
||||||
|
(define (construct-new-instr instr args)
|
||||||
|
(let*-values ([(struct-type _) (struct-info instr)]
|
||||||
|
[(constructor) (struct-type-make-constructor struct-type)])
|
||||||
|
(apply constructor args)))
|
||||||
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
;(require "test-explicate-control.rkt")
|
;(require "test-explicate-control.rkt")
|
||||||
(require "test-cvar-to-bril.rkt")
|
(require "test-cvar-to-bril.rkt")
|
||||||
(require "test-select-instr.rkt")
|
(require "test-select-instr.rkt")
|
||||||
|
(require "test-allocate-regs.rkt")
|
||||||
|
|
||||||
(define all-tests
|
(define all-tests
|
||||||
(test-suite
|
(test-suite
|
||||||
|
|
@ -22,5 +23,6 @@
|
||||||
;remove-complex-opera-tests
|
;remove-complex-opera-tests
|
||||||
;explicate-control-tests
|
;explicate-control-tests
|
||||||
cvar-to-bril-tests
|
cvar-to-bril-tests
|
||||||
select-instr-tests))
|
select-instr-tests
|
||||||
|
allocate-regs-tests))
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
#lang racket
|
||||||
|
|
||||||
|
(provide allocate-regs-tests)
|
||||||
|
|
||||||
|
(require rackunit)
|
||||||
|
|
||||||
|
(require "../aarch64var.rkt")
|
||||||
|
(require/expose "../allocate-regs.rkt"
|
||||||
|
(allocate-regs-std-instr!))
|
||||||
|
|
||||||
|
(define listing-1
|
||||||
|
(list (Label "main")
|
||||||
|
(LMov (Imm 0) (Var "c"))
|
||||||
|
(LMov (Imm 2) (Var "d"))
|
||||||
|
(Add (Var "c") (Var "d") (Var "b"))
|
||||||
|
(LMov (Reg 'x0) (Var "b"))
|
||||||
|
(RetDefault)))
|
||||||
|
|
||||||
|
(define allocate-regs-tests
|
||||||
|
(test-suite
|
||||||
|
"Register Allocation"
|
||||||
|
|
||||||
|
(test-suite
|
||||||
|
"Single instruction allocation"
|
||||||
|
(test-case
|
||||||
|
"Add"
|
||||||
|
(check-equal?
|
||||||
|
(allocate-regs-std-instr! (Add (Var "a") (Var "b") (Var "c"))
|
||||||
|
(make-hash (list (cons "a" -0) (cons "b" -8)))
|
||||||
|
-16)
|
||||||
|
(list (Ldr (AMOffset 'sp 0) (Reg 'x0))
|
||||||
|
(Ldr (AMOffset 'sp -8) (Reg 'x1))
|
||||||
|
(Add (Reg 'x0) (Reg 'x1) (Reg 'x2))))))))
|
||||||
|
|
||||||
Loading…
Reference in New Issue