aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc/emit.clj
diff options
context:
space:
mode:
Diffstat (limited to 'src/cljcc/emit.clj')
-rw-r--r--src/cljcc/emit.clj76
1 files changed, 60 insertions, 16 deletions
diff --git a/src/cljcc/emit.clj b/src/cljcc/emit.clj
index e69f07a..8a12d76 100644
--- a/src/cljcc/emit.clj
+++ b/src/cljcc/emit.clj
@@ -5,23 +5,38 @@
[clojure.string :as str]
[clojure.pprint :as pp]))
+(defn- handle-label [identifier]
+ (condp = (get-os)
+ :mac (str "L" identifier)
+ :linux (str ".L" identifier)
+ (throw (ex-info "Error in generating label." {}))))
+
;;;; Operand Emit
-(defn- imm-opernad-emit [operand]
+(defn- imm-opernad-emit [operand _opts]
(format "$%d" (:value operand)))
-(defn- stack-operand-emit [operand]
+(defn- stack-operand-emit [operand _opts]
(format "%d(%%rbp)" (:value operand)))
-(defn- register-operand [operand]
- (condp = (:register operand)
- :ax "%eax"
- :dx "%edx"
- :r10 "%r10d"
- :r11 "%r11d"
- :cx "%ecx"
- :cl "%cl"
- (throw (AssertionError. (str "Invalid register operand: " operand)))))
+(defn- register-operand [operand opts]
+ (if (contains? opts :byte-1)
+ (condp = (:register operand)
+ :ax "%al"
+ :dx "%dl"
+ :r10 "%r10b"
+ :r11 "%r11b"
+ :cx "%cl"
+ :cl "%cl"
+ (throw (AssertionError. (str "Invalid register operand: " operand))))
+ (condp = (:register operand)
+ :ax "%eax"
+ :dx "%edx"
+ :r10 "%r10d"
+ :r11 "%r11d"
+ :cx "%ecx"
+ :cl "%cl"
+ (throw (AssertionError. (str "Invalid register operand: " operand))))))
(def operand-emitters
"Map of assembly operands to operand emitters."
@@ -29,10 +44,13 @@
:reg #'register-operand
:stack #'stack-operand-emit})
-(defn- operand-emit [operand]
- (if-let [[_ operand-emit-fn] (find operand-emitters (:operand operand))]
- (operand-emit-fn operand)
- (throw (AssertionError. (str "Invalid operand: " operand)))))
+(defn- operand-emit
+ ([operand]
+ (operand-emit operand {}))
+ ([operand opts]
+ (if-let [[_ operand-emit-fn] (find operand-emitters (:operand operand))]
+ (operand-emit-fn operand opts)
+ (throw (AssertionError. (str "Invalid operand: " operand))))))
;;;; Instruction Emit
@@ -41,6 +59,27 @@
dst (operand-emit (:dst instruction))]
[(format " %s %s, %s" "movl" src dst)]))
+(defn- cmp-instruction-emit [instruction]
+ (let [src (operand-emit (:src instruction))
+ dst (operand-emit (:dst instruction))]
+ [(format " %s %s, %s" "cmpl" src dst)]))
+
+(defn- jmp-instruction-emit [instruction]
+ [(format " jmp %s" (handle-label (:identifier instruction)))])
+
+(defn- jmpcc-instruction-emit [instruction]
+ (let [cc (name (:cond-code instruction))
+ label (handle-label (:identifier instruction))]
+ [(format " j%s %s" cc label)]))
+
+(defn- setcc-instruction-emit [instruction]
+ (let [cc (name (:cond-code instruction))
+ operand (operand-emit (:operand instruction) {:byte-1 true})]
+ [(format " set%s %s" cc operand)]))
+
+(defn- label-instruction-emit [instruction]
+ [(format " %s:" (handle-label (:identifier instruction)))])
+
(defn- ret-instruction-emit [_instruction]
[" movq %rbp, %rsp"
" popq %rbp"
@@ -87,6 +126,11 @@
:cdq #'cdq-instruction-emit
:idiv #'idiv-instruction-emit
:unary #'unary-instruction-emit
+ :setcc #'setcc-instruction-emit
+ :jmp #'jmp-instruction-emit
+ :jmpcc #'jmpcc-instruction-emit
+ :label #'label-instruction-emit
+ :cmp #'cmp-instruction-emit
:allocate-stack #'allocate-stack-instruction-emit})
(defn instruction-emit [instruction]
@@ -157,7 +201,7 @@
(emit
(c/generate-assembly
"int main(void) {
- return 6 / 3 / 2;
+ return 1 + 2 == 4 + 5;
}")))
(println