HomeMAL' // MANUFACTORUM
datacrypt
Piton / src / mips-helper.rkt
src/mips-helper.rkt6.0 KB
#lang racket/base

(require racket/match
         racket/list
         "mips.rkt")
(provide move-val
         push-next-activlnk
         apply-bininstr
         apply-uninstr)

;; Move value (number, register, mem, label, outer-mem)
;; to location (register, local mem, outer-mem)
(define (move-val dest-loc src-val)
  (if (or (not dest-loc) (equal? dest-loc src-val))
      empty
      (let-values ([(pre-instrs dest-loc src-val) (fetch-if-outer dest-loc src-val)])
        ; $t9 register used as temp register for memory operations
        (define move-instrs
          (match (cons dest-loc src-val)
            ; number to register
            [(cons (? reg?) (? number?)) (list (li dest-loc src-val))]
            ; register to register
            [(cons (? reg?) (? reg?)) (list (move dest-loc src-val))]
            ; mem to register
            [(cons (? reg?) (? mem?)) (list (lw dest-loc src-val))]
            ; label to register
            [(cons (? reg?) (? label?)) (list (la dest-loc src-val))] ; la for str, lw for num

            ; number to mem
            [(cons (? mem?) (? number?)) (list (li $t9 src-val)
                                               (sw $t9 dest-loc))]
            ; register to mem
            [(cons (? mem?) (? reg?)) (list (sw src-val dest-loc))]
            ; mem to mem
            [(cons (? mem?) (? mem?)) (list (lw $t9 src-val)
                                            (sw $t9 dest-loc))]
            ; label to mem
            [(cons (? mem?) (? label?)) (list (la $t9 src-val) ; la for str, lw for num
                                              (sw $t9 dest-loc))]))
        (append pre-instrs move-instrs))))

;; Handles outer scope values for <move-val>
;; return instrs, dest-loc, src-val
(define (fetch-if-outer dest-loc src-val)
  (let-values
       ([(dest-instrs dest-loc)
        (match dest-loc
          ; transform outer-mem into mem by fetching outer ssp
          [(outer-mem level-offset stack-offset)
           ; use dedicated temp register $t8
           (values (fetch-outer-sp level-offset $t8)
                   (mem stack-offset $t8))]
          [_ (values empty dest-loc)])]
        [(src-instrs src-val)
        (match src-val
          ; transform outer-mem into mem by fetching outer $sp
          [(outer-mem level-offset stack-offset)
           ; use dedicated temp register $t7
           (values (fetch-outer-sp level-offset $t7)
                   (mem stack-offset $t7))]
          [_ (values empty src-val)])])

    (values (append dest-instrs src-instrs)
            dest-loc
            src-val)))

;; Fetch stack pointer of the outer scope at <level-offset> and store it into <reg>
;; <return> instructions
;; http://pages.cs.wisc.edu/~fischer/cs536.s06/course.hold/html/NOTES/8.RUNTIME-VAR-ACCESS.html
(define (fetch-outer-sp level-offset reg)
  ; starting from $sp, walk up the activation link chain until we reach outer level
  (append (list (move reg $sp))
          (for/list ([i level-offset])
            (lw reg (mem 0 reg)))))

;; Move into <dest-loc> the value of activation link to push on stack before a call
;; http://pages.cs.wisc.edu/~fischer/cs536.s06/course.hold/html/NOTES/8.RUNTIME-VAR-ACCESS.html
;; <return> instructions
(define (push-next-activlnk caller-level callee-level dest-loc)
  (if (< caller-level callee-level)
      (move-val dest-loc (mem $sp 0)) ;; push to callee activation link of caller
      (let ([level-offset (- caller-level callee-level)])
        (append (list (la $t9 (mem 0 $sp)))
                (for/list ([i level-offset])
                  (lw $t9 (mem 0 $t9)))
                (move-val dest-loc $t9)))))

;; Apply unary operation instruction
;; return instrs
(define (apply-uninstr instr dest-loc src-val)
  ; load src into temp register if needed
  (define-values (load-src-instrs loaded-val)
    (load-lhs-val src-val $t6))
  ; use a temp destination register if needed
  (define tmp-dest-loc (get-tmp-dest-loc dest-loc $t5))
  ; save to destination from temp register if needed
  (define save-dest-instrs (save-dest-loc dest-loc tmp-dest-loc))

  (append load-src-instrs
          (list (instr tmp-dest-loc loaded-val))
          save-dest-instrs))

;; Apply binary operation instruction
;; return instrs
(define (apply-bininstr instr dest-loc lhs-val rhs-val)
  ; load lhs into temp register if needed
  (define-values (load-lhs-instrs loaded-lhs-val)
    (load-lhs-val lhs-val $t6))
  ; load rhs in temp register if needed and if different from lhs,
  ; else reuse result of <load-lhs-val>
  (define-values (load-rhs-instrs loaded-rhs-val)
    (if (equal? rhs-val lhs-val)
        (values empty loaded-lhs-val)
        (load-rhs-val rhs-val $t5)))
  ; use a temp destination register if needed
  (define tmp-dest-loc (get-tmp-dest-loc dest-loc $t4))
  ; save to destination from temp register if needed
  (define save-dest-instrs (save-dest-loc dest-loc tmp-dest-loc))

  (append load-lhs-instrs
          load-rhs-instrs
          (list (instr tmp-dest-loc loaded-lhs-val loaded-rhs-val))
          save-dest-instrs))

;; Load source value if remote (mem or outer-mem) so it can
;; be passed as first argument of a mips instruction (no literal allowed)
;; return instrs, val
(define (load-lhs-val src-val reg)
  (if (or (mem? src-val) (outer-mem? src-val) (number? src-val))
      (values (move-val reg src-val)
              reg)
      (values empty
              src-val)))

;; Load source value if remote (mem or outer-mem) so it can
;; be passed as second argument of a mips instruction (literals are allowed)
(define (load-rhs-val src-val reg)
  (if (or (mem? src-val) (outer-mem? src-val))
      (values (move-val reg src-val)
              reg)
      (values empty
              src-val)))

;; <return> temp register for destination if remote (mem or outer-mem)
;; return loc
(define (get-tmp-dest-loc dest-loc reg)
  (if (or (mem? dest-loc) (outer-mem? dest-loc))
      reg
      dest-loc))

;; Save temp register to destination if remote (mem or outer-mem)
;; return instrs
(define (save-dest-loc dest-loc reg)
  (if (or (mem? dest-loc) (outer-mem? dest-loc))
      (move-val dest-loc reg)
      empty))