wip: start working on trivial register allocation

This commit is contained in:
Enrico Lumetti 2022-08-21 00:29:45 +02:00
parent 9c2895e4ed
commit 8a4948475c
4 changed files with 160 additions and 2 deletions

View File

@ -1,6 +1,19 @@
#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)
@ -10,6 +23,9 @@
(struct Reg (reg-name) #:transparent)
(struct Imm (immediate) #: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 Sub (op1 op2 dest) #:transparent)
(struct RetDefault () #:transparent)
@ -23,3 +39,4 @@
x19 x20 x21 x22 x23 x24
x25 x26 x27 x28 x29 x30
sp pc xzr))

105
allocate-regs.rkt Normal file
View File

@ -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)))

View File

@ -11,6 +11,7 @@
;(require "test-explicate-control.rkt")
(require "test-cvar-to-bril.rkt")
(require "test-select-instr.rkt")
(require "test-allocate-regs.rkt")
(define all-tests
(test-suite
@ -22,5 +23,6 @@
;remove-complex-opera-tests
;explicate-control-tests
cvar-to-bril-tests
select-instr-tests))
select-instr-tests
allocate-regs-tests))

View File

@ -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))))))))