aboutsummaryrefslogtreecommitdiff
path: root/cljcc-compiler/src/cljcc/emit.clj
diff options
context:
space:
mode:
authorYour Name <agrawalshagun07@gmail.com>2025-03-16 02:01:52 +0530
committerYour Name <agrawalshagun07@gmail.com>2025-03-16 02:01:52 +0530
commit39b6930e14cfda58fd066805f5da447c685ab67f (patch)
tree2b0f2eae0d6eb3e6c99143d67db3177534a2c1c2 /cljcc-compiler/src/cljcc/emit.clj
parent0321df3708cfa4d1440faf3f407611df85484b4b (diff)
Rename all compiler files to cljc.
Diffstat (limited to 'cljcc-compiler/src/cljcc/emit.clj')
-rw-r--r--cljcc-compiler/src/cljcc/emit.clj325
1 files changed, 0 insertions, 325 deletions
diff --git a/cljcc-compiler/src/cljcc/emit.clj b/cljcc-compiler/src/cljcc/emit.clj
deleted file mode 100644
index 0686b31..0000000
--- a/cljcc-compiler/src/cljcc/emit.clj
+++ /dev/null
@@ -1,325 +0,0 @@
-(ns cljcc.emit
- (:require
- [cljcc.util :refer [get-os]]
- [cljcc.compiler :as c]
- [clojure.string :as str]
- [cljcc.exception :as exc]))
-
-(defn- handle-label [identifier]
- (condp = (get-os)
- :mac (str "L" identifier)
- :linux (str ".L" identifier)
- (throw (ex-info "Error in generating label." {}))))
-
-(defn- handle-symbol-name [name]
- (if (= :mac (get-os))
- (str "_" name)
- name))
-
-(defn- handle-current-translation-unit [name ident->asm-entry]
- (if (= :mac (get-os))
- (handle-symbol-name name)
- (if (get-in ident->asm-entry [name :defined?])
- name
- (str name "@PLT"))))
-
-;;;; Operand Emit
-
-(defn- imm-opernad-emit [operand _opts]
- (format "$%d" (:value operand)))
-
-(defn- stack-operand-emit [operand _opts]
- (format "%d(%%rbp)" (:value operand)))
-
-(defn- data-operand-emit [operand _opts]
- (format "%s(%%rip)" (handle-symbol-name (:identifier operand))))
-
-(defn- register-operand [{:keys [register] :as operand} {register-width :register-width :or {register-width :4-byte}}]
- (let [register->width->output {:ax {:8-byte "%rax"
- :4-byte "%eax"
- :1-byte "%al"}
-
- :dx {:8-byte "%rdx"
- :4-byte "%edx"
- :1-byte "%dl"}
-
- :cx {:8-byte "%rcx"
- :4-byte "%ecx"
- :1-byte "%cl"}
-
- :di {:8-byte "%rdi"
- :4-byte "%edi"
- :1-byte "%dil"}
-
- :si {:8-byte "%rsi"
- :4-byte "%esi"
- :1-byte "%sil"}
-
- :r8 {:8-byte "%r8"
- :4-byte "%r8d"
- :1-byte "%r8b"}
-
- :r9 {:8-byte "%r9"
- :4-byte "%r9d"
- :1-byte "%r9b"}
-
- :r10 {:8-byte "%r10"
- :4-byte "%r10d"
- :1-byte "%r10b"}
-
- :r11 {:8-byte "%r11"
- :4-byte "%r11d"
- :1-byte "%r11b"}
-
- :cl {:4-byte "%cl"
- :1-byte "%cl"}
-
- :sp {:8-byte "%rsp"
- :4-byte "%rsp"
- :1-byte "%rsp"}}]
- (if-let [out (get-in register->width->output [register register-width])]
- out
- (exc/emit-error "Invalid register and width" {:operand operand
- :opts register-width}))))
-
-(def operand-emitters
- "Map of assembly operands to operand emitters."
- {:imm #'imm-opernad-emit
- :reg #'register-operand
- :data #'data-operand-emit
- :stack #'stack-operand-emit})
-
-(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
-
-(defn- assembly-type->instruction-suffix [atype]
- (condp = atype
- :longword "l"
- :quadword "q"))
-
-(defn- assembly-type->operand-size [atype]
- (condp = atype
- :longword :4-byte
- :quadword :8-byte))
-
-(defn- mov-instruction-emit [instruction]
- (let [atype (:assembly-type instruction)
- opts {:register-width (assembly-type->operand-size atype)}
- src (operand-emit (:src instruction) opts)
- dst (operand-emit (:dst instruction) opts)
- suffix (assembly-type->instruction-suffix atype)]
- [(format " %s%s %s, %s" "mov" suffix src dst)]))
-
-(defn- movsx-instruction-emit [instruction]
- (let [src (operand-emit (:src instruction) {:register-width :4-byte})
- dst (operand-emit (:dst instruction) {:register-width :8-byte})]
- [(format " %s %s, %s" "movslq" src dst)]))
-
-(defn- cmp-instruction-emit [instruction]
- (let [atype (:assembly-type instruction)
- opts {:register-width (assembly-type->operand-size atype)}
- src (operand-emit (:src instruction) opts)
- dst (operand-emit (:dst instruction) opts)
- suffix (assembly-type->instruction-suffix atype)]
- [(format " %s%s %s, %s" "cmp" suffix 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) {:register-width :1-byte})]
- [(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"
- " ret"])
-
-(defn- unary-instruction-emit [instruction]
- (let [atype (:assembly-type instruction)
- opts {:register-width (assembly-type->operand-size atype)}
- operand (operand-emit (:operand instruction) opts)
- suffix (assembly-type->instruction-suffix (:assembly-type instruction))
- assembly-operator (condp = (:unary-operator instruction)
- :bit-not "not"
- :negate "neg"
- (throw (AssertionError. (str "Invalid unary operator: " instruction))))]
- [(format " %s%s %s" assembly-operator suffix operand)]))
-
-(defn- binary-instruction-emit [instruction]
- (let [atype (:assembly-type instruction)
- opts {:register-width (assembly-type->operand-size atype)}
- src (operand-emit (:src instruction) opts)
- dst (operand-emit (:dst instruction) opts)
- suffix (assembly-type->instruction-suffix (:assembly-type instruction))
- binop (:binary-operator instruction)
- binop-operator (condp = binop
- :add "add"
- :sub "sub"
- :mul "imul"
- :bit-and "and"
- :bit-xor "xor"
- :bit-or "or"
- :bit-left-shift "sal"
- :bit-right-shift "sar"
- (throw (AssertionError. (str "Invalid binary operator: " instruction))))]
- [(format " %s%s %s, %s" binop-operator suffix src dst)]))
-
-(defn- cdq-instruction-emit [{:keys [assembly-type] :as _instruction}]
- (let [opcode (if (= :longword assembly-type)
- "cdq"
- "cqo")]
- [(format " %s" opcode)]))
-
-(defn- idiv-instruction-emit [instruction]
- (let [atype (:assembly-type instruction)
- opts {:register-width (assembly-type->operand-size atype)}
- op (operand-emit (:operand instruction) opts)
- suffix (assembly-type->instruction-suffix (:assembly-type instruction))]
- [(format " idiv%s %s" suffix op)]))
-
-(defn- div-instruction-emit [instruction]
- (let [atype (:assembly-type instruction)
- opts {:register-width (assembly-type->operand-size atype)}
- op (operand-emit (:operand instruction) opts)
- suffix (assembly-type->instruction-suffix (:assembly-type instruction))]
- [(format " div%s %s" suffix op)]))
-
-(defn- push-instruction-emit [instruction]
- [(format " pushq %s" (operand-emit (:operand instruction) {:register-width :8-byte}))])
-
-(defn- call-instruction-emit [instruction m]
- [(format " call %s" (handle-current-translation-unit (:identifier instruction) m))])
-
-(def instruction-emitters
- "Map of assembly instructions to function emitters."
- {:mov #'mov-instruction-emit
- :movsx #'movsx-instruction-emit
- :ret #'ret-instruction-emit
- :binary #'binary-instruction-emit
- :cdq #'cdq-instruction-emit
- :idiv #'idiv-instruction-emit
- :div #'div-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
- :push #'push-instruction-emit
- :call #'call-instruction-emit})
-
-(defn instruction-emit [instruction ident->asm-entry]
- (if-let [[op-type instruction-emit-fn] (find instruction-emitters (:op instruction))]
- (if (= :call op-type)
- (instruction-emit-fn instruction ident->asm-entry)
- (instruction-emit-fn instruction))
- (throw (AssertionError. (str "Invalid instruction: " instruction)))))
-
-(defn function-definition-emit [{:keys [identifier instructions global?]} ident->asm-entry]
- (let [name (handle-symbol-name identifier)
- globl (if global?
- (format " .globl %s", name)
- "")
- name-line (format "%s:" name)
- instructions (mapv #(instruction-emit % ident->asm-entry) instructions)]
- (->> [globl
- " .text"
- name-line
- " pushq %rbp"
- " movq %rsp, %rbp"
- instructions
- "\n"]
- flatten
- (filterv not-empty))))
-
-(defn- static-variable-definition-emit [{:keys [identifier global? alignment initial]} _ident->asm-entry]
- (let [name (handle-symbol-name identifier)
- value-type (:type (:static-init initial))
- value (:value (:static-init initial))
- globl (if global?
- (format " .globl %s" name)
- "")
- data-or-bss (if (zero? value)
- " .bss"
- " .data")
- initializer-directive (cond
- (or (= :int-init value-type)
- (= :uint-init value-type)) (if (zero? value)
- " .zero 4"
- (format " .long %d" value))
- (or (= :long-init value-type)
- (= :ulong-init value-type)) (if (zero? value)
- " .zero 8"
- (format " .quad %d" value)))]
- (filterv not-empty [globl
- data-or-bss
- (format " .balign %d" alignment)
- (format "%s:" name)
- initializer-directive
- "\n"])))
-
-(def emitters-top-level
- "Map of assembly top level constructs to their emitters."
- {:function #'function-definition-emit
- :static-variable #'static-variable-definition-emit})
-
-(defn emit-top-level [ast ident->asm-entry]
- (if-let [[_ emit-fn] (find emitters-top-level (:op ast))]
- (emit-fn ast ident->asm-entry)
- (exc/emit-error "Invalid ast." ast)))
-
-(def linux-assembly-end ".section .note.GNU-stack,\"\",@progbits\n")
-
-(defn emit [{:keys [program backend-symbol-table]}]
- (let [handle-os (fn [ast]
- (if (= :linux (get-os))
- (conj (conj (conj (vec ast) linux-assembly-end) "\n"))
- ast))]
- (->> program
- (mapv #(emit-top-level % backend-symbol-table))
- concat
- flatten
- handle-os
- (str/join "\n"))))
-
-(comment
-
- (def file-path "./test-programs/example.c")
-
- (slurp "./test-programs/example.c")
-
- (-> file-path
- slurp
- c/assembly-from-src)
-
- (str/split-lines
- (-> file-path
- slurp
- c/assembly-from-src
- emit))
-
- (spit
- "./test-programs/example.s"
- (-> file-path
- slurp
- c/assembly-from-src
- emit))
-
- ())