aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc/compiler.clj
diff options
context:
space:
mode:
Diffstat (limited to 'src/cljcc/compiler.clj')
-rw-r--r--src/cljcc/compiler.clj110
1 files changed, 98 insertions, 12 deletions
diff --git a/src/cljcc/compiler.clj b/src/cljcc/compiler.clj
index 4862d95..a7ee8c9 100644
--- a/src/cljcc/compiler.clj
+++ b/src/cljcc/compiler.clj
@@ -4,7 +4,9 @@
[cljcc.tacky :as t]
[cljcc.lexer :as l]))
-(def registers #{:ax :dx :r10 :r11})
+(def registers #{:ax :dx :r10 :r11 :cx :cl})
+
+(def cond-codes #{:e :ne :g :ge :l :le})
;;;; Instructions
@@ -13,13 +15,6 @@
:src src
:dst dst})
-(defn- ret-instruction []
- {:op :ret})
-
-(defn- allocate-stack-instruction [v]
- {:op :allocate-stack
- :value v})
-
(defn- unary-instruction [unary-operator operand]
{:op :unary
:unary-operator unary-operator
@@ -31,6 +26,11 @@
:src src
:dst dst})
+(defn- cmp-instruction [src dst]
+ {:op :cmp
+ :src src
+ :dst dst})
+
(defn- cdq-instruction []
{:op :cdq})
@@ -38,6 +38,33 @@
{:op :idiv
:operand operand})
+(defn- jmp-instruction [identifier]
+ {:op :jmp
+ :identifier identifier})
+
+(defn- jmpcc-instruction [cond-code identifier]
+ {:pre [(contains? cond-codes cond-code)]}
+ {:op :jmpcc
+ :identifier identifier
+ :cond-code cond-code})
+
+(defn- setcc-instruction [cond-code operand]
+ {:pre [(contains? cond-codes cond-code)]}
+ {:op :setcc
+ :operand operand
+ :cond-code cond-code})
+
+(defn- label-instruction [identifier]
+ {:op :label
+ :identifier identifier})
+
+(defn- allocate-stack-instruction [v]
+ {:op :allocate-stack
+ :value v})
+
+(defn- ret-instruction []
+ {:op :ret})
+
;;;; Operands
(defn- imm-operand [v]
@@ -45,6 +72,7 @@
:value v})
(defn- reg-operand [reg]
+ {:pre [(contains? registers reg)]}
{:operand :reg
:register reg})
@@ -74,8 +102,21 @@
(defn- tacky-unary->assembly [instruction]
(let [src (tacky-val->assembly-operand (:src instruction))
dst (tacky-val->assembly-operand (:dst instruction))
- unop (:unary-operator instruction)]
- [(mov-instruction src dst) (unary-instruction unop dst)]))
+ unop (:unary-operator instruction)
+ logical-not? (= :logical-not unop)]
+ (cond
+ logical-not? [(cmp-instruction (imm-operand 0) src)
+ (mov-instruction (imm-operand 0) dst)
+ (setcc-instruction :e dst)]
+ :else [(mov-instruction src dst) (unary-instruction unop dst)])))
+
+(def relational-ops
+ {:greater-than :g
+ :less-than :l
+ :equal :e
+ :not-equal :ne
+ :less-or-equal :le
+ :greater-or-equal :ge})
(defn- tacky-binary->assembly [instruction]
(let [binop (:binary-operator instruction)
@@ -84,6 +125,7 @@
dst (tacky-val->assembly-operand (:dst instruction))
div? (= binop :div)
mod? (= binop :mod)
+ relational? (contains? relational-ops binop)
bit-shift? (contains? #{:bit-right-shift :bit-left-shift} binop)]
(cond
div? [(mov-instruction src1 (reg-operand :ax))
@@ -94,15 +136,46 @@
(cdq-instruction)
(idiv-instruction src2)
(mov-instruction (reg-operand :dx) dst)]
+ relational? [(cmp-instruction src2 src1)
+ (mov-instruction (imm-operand 0) dst)
+ (setcc-instruction (binop relational-ops) dst)]
bit-shift? [(mov-instruction src1 dst)
(mov-instruction src2 (reg-operand :cx))
(binary-instruction binop (reg-operand :cl) dst)]
:else [(mov-instruction src1 dst) (binary-instruction binop src2 dst)])))
+(defn- tacky-jump-if-zero->assembly [instruction]
+ (let [val (tacky-val->assembly-operand (:val instruction))
+ target (:identifier instruction)]
+ [(cmp-instruction (imm-operand 0) val)
+ (jmpcc-instruction :e target)]))
+
+(defn- tacky-jump-if-not-zero->assembly [instruction]
+ (let [val (tacky-val->assembly-operand (:val instruction))
+ target (:identifier instruction)]
+ [(cmp-instruction (imm-operand 0) val)
+ (jmpcc-instruction :ne target)]))
+
+(defn- tacky-jump->assembly [instruction]
+ [(jmp-instruction (:identifier instruction))])
+
+(defn- tacky-copy->assembly [instruction]
+ (let [src (tacky-val->assembly-operand (:src instruction))
+ dst (tacky-val->assembly-operand (:dst instruction))]
+ [(mov-instruction src dst)]))
+
+(defn- tacky-label->assembly [instruction]
+ [(label-instruction (:identifier instruction))])
+
(def tacky->assembly-transformers
{:unary #'tacky-unary->assembly
:return #'tacky-return->assembly
- :binary #'tacky-binary->assembly})
+ :binary #'tacky-binary->assembly
+ :copy #'tacky-copy->assembly
+ :jump #'tacky-jump->assembly
+ :label #'tacky-label->assembly
+ :jump-if-zero #'tacky-jump-if-zero->assembly
+ :jump-if-not-zero #'tacky-jump-if-not-zero->assembly})
(defn- tacky-inst->assembly-inst [inst]
(let [transformer-fn ((:type inst) tacky->assembly-transformers)]
@@ -189,9 +262,22 @@
(idiv-instruction (reg-operand :r10))]
instruction))
+(defn- fix-cmp-instruction [instruction]
+ (let [both-memory-address? (and
+ (= :stack (get-in instruction [:src :operand]))
+ (= :stack (get-in instruction [:dst :operand])))
+ dst-constant? (= :imm (get-in instruction [:dst :operand]))]
+ (cond
+ both-memory-address? [(mov-instruction (get instruction :src) (reg-operand :r10))
+ (cmp-instruction (reg-operand :r10) (get instruction :dst))]
+ dst-constant? [(mov-instruction (get instruction :dst) (reg-operand :r11))
+ (cmp-instruction (get instruction :src) (reg-operand :r11))]
+ :else instruction)))
+
(def fix-instruction-map
{:idiv #'fix-idiv-instruction
:mov #'fix-mov-instruction
+ :cmp #'fix-cmp-instruction
:binary #'fix-binary-instruction})
(defn- fix-instruction [instruction]
@@ -236,7 +322,7 @@
(pp/pprint
(generate-assembly
"int main(void) {
-return 1 + 2;
+return 1 >= 2;
}"))
())