aboutsummaryrefslogtreecommitdiff
path: root/src/cljcc
diff options
context:
space:
mode:
authorShagun Agrawal <agrawalshagun07@gmail.com>2024-10-30 00:34:36 +0530
committerShagun Agrawal <agrawalshagun07@gmail.com>2024-10-30 00:34:36 +0530
commita94b482b001d99ecffdb31067319773cbde4501e (patch)
tree65e53f128b7e63f1e8392e447d113d9dc827e7b4 /src/cljcc
parent40da421300b14e4766718984e0787550aadb9319 (diff)
Add emission for functions
Able to execute "hello, world" program. Some segmentation faults in specific test steps. Executables not exiting on their own.
Diffstat (limited to 'src/cljcc')
-rw-r--r--src/cljcc/compiler.clj2
-rw-r--r--src/cljcc/driver.clj7
-rw-r--r--src/cljcc/emit.clj134
-rw-r--r--src/cljcc/symbols.clj10
-rw-r--r--src/cljcc/tacky.clj8
5 files changed, 96 insertions, 65 deletions
diff --git a/src/cljcc/compiler.clj b/src/cljcc/compiler.clj
index b0e5770..c1af6de 100644
--- a/src/cljcc/compiler.clj
+++ b/src/cljcc/compiler.clj
@@ -394,7 +394,7 @@
flatten
(remove nil?))))
-(defn- tacky-function->assembly-function [{:keys [type identifier parameters instructions] :as function-definition}]
+(defn- tacky-function->assembly-function [{:keys [type identifier parameters instructions]}]
(let [parameter-instructions (parameters->assembly-instructions parameters)
body-instructions (->> instructions
(keep tacky-inst->assembly-inst)
diff --git a/src/cljcc/driver.clj b/src/cljcc/driver.clj
index 8485574..14b9e18 100644
--- a/src/cljcc/driver.clj
+++ b/src/cljcc/driver.clj
@@ -9,7 +9,8 @@
[clojure.pprint :as pp]
[cljcc.log :as log]
[cljcc.util :refer [get-os handle-sh mac-aarch64? make-file-name]]
- [cljcc.parser :as p]))
+ [cljcc.parser :as p]
+ [clojure.string :as str]))
(defn- validate-os []
(let [os (get-os)]
@@ -44,7 +45,9 @@
assembly-out-file-path (make-file-name directory (remove-extension filename) "s")
_ (println assembly-output)
_ (spit assembly-out-file-path assembly-output)
- output-file (str directory "/" file-without-ext)
+ output-file (if (:generate-object-file options)
+ (str directory "/" (str file-without-ext ".o"))
+ (str directory "/" file-without-ext))
output (if (:generate-object-file options)
(handle-sh "gcc" "-c" assembly-file "-o" output-file)
(handle-sh "gcc" assembly-file "-o" output-file))]
diff --git a/src/cljcc/emit.clj b/src/cljcc/emit.clj
index 8a12d76..1d8c51a 100644
--- a/src/cljcc/emit.clj
+++ b/src/cljcc/emit.clj
@@ -3,7 +3,8 @@
[cljcc.util :refer [get-os]]
[cljcc.compiler :as c]
[clojure.string :as str]
- [clojure.pprint :as pp]))
+ [clojure.pprint :as pp]
+ [cljcc.symbols :as symbols]))
(defn- handle-label [identifier]
(condp = (get-os)
@@ -11,6 +12,19 @@
:linux (str ".L" identifier)
(throw (ex-info "Error in generating label." {}))))
+
+(defn- handle-function-name [name]
+ (if (= :mac (get-os))
+ (str "_" name)
+ name))
+
+(defn- handle-current-translation-unit [name]
+ (if (= :mac (get-os))
+ (handle-function-name name)
+ (if (contains? @symbols/symbols name)
+ name
+ (str name "@PLT"))))
+
;;;; Operand Emit
(defn- imm-opernad-emit [operand _opts]
@@ -19,24 +33,48 @@
(defn- stack-operand-emit [operand _opts]
(format "%d(%%rbp)" (:value 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))))))
+(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"}}]
+ (if-let [out (get-in register->width->output [register register-width])]
+ out
+ (throw (AssertionError. (str "Invalid register operand register width " operand " " register-width))))))
(def operand-emitters
"Map of assembly operands to operand emitters."
@@ -74,7 +112,7 @@
(defn- setcc-instruction-emit [instruction]
(let [cc (name (:cond-code instruction))
- operand (operand-emit (:operand instruction) {:byte-1 true})]
+ operand (operand-emit (:operand instruction) {:register-width :1-byte})]
[(format " set%s %s" cc operand)]))
(defn- label-instruction-emit [instruction]
@@ -118,6 +156,15 @@
(defn- allocate-stack-instruction-emit [instruction]
[(format " subq $%d, %%rsp" (:value instruction))])
+(defn- deallocate-stack-instruction-emit [instruction]
+ [(format " addq $%d, %%rsp" (:value instruction))])
+
+(defn- push-instruction-emit [instruction]
+ [(format " pushq %s" (operand-emit (:operand instruction) {:register-width :8-byte}))])
+
+(defn- call-instruction-emit [instruction]
+ [(format " call %s" (handle-current-translation-unit (:identifier instruction)))])
+
(def instruction-emitters
"Map of assembly instructions to function emitters."
{:mov #'mov-instruction-emit
@@ -131,19 +178,17 @@
:jmpcc #'jmpcc-instruction-emit
:label #'label-instruction-emit
:cmp #'cmp-instruction-emit
- :allocate-stack #'allocate-stack-instruction-emit})
+ :allocate-stack #'allocate-stack-instruction-emit
+ :deallocate-stack #'deallocate-stack-instruction-emit
+ :push #'push-instruction-emit
+ :call #'call-instruction-emit})
(defn instruction-emit [instruction]
(if-let [[_ instruction-emit-fn] (find instruction-emitters (:op instruction))]
(instruction-emit-fn instruction)
(throw (AssertionError. (str "Invalid instruction: " instruction)))))
-(defn- handle-function-name [name]
- (if (= :mac (get-os))
- (str "_" name)
- name))
-
-(defn function-emit [f]
+(defn function-definition-emit [f]
(let [name (handle-function-name (:identifier f))
globl (format " .globl %s", name)
name-line (format "%s:" name)
@@ -156,7 +201,7 @@
(def emitters-top-level
"Map of assembly top level constructs to their emitters."
- {:function #'function-emit})
+ {:declaration #'function-definition-emit})
(defn emit-top-level [assembly-ast]
(if-let [[_ emit-fn] (find emitters-top-level (:op assembly-ast))]
@@ -179,39 +224,10 @@
(comment
- (def ex "int main(void) {return 2;}")
-
- (mov-instruction-emit
- {:op :mov
- :src {:operand :imm :value 1}
- :dst {:operand :stack :value -4}})
-
- (c/generate-assembly
- "int main(void) {
- return ~(-(~(-1)));
- }")
-
- (pp/pprint
- (c/generate-assembly
- "int main(void) {
- return ~(-(~(-1)));
- }"))
-
- (println
(emit
(c/generate-assembly
"int main(void) {
- return 1 + 2 == 4 + 5;
- }")))
-
- (println
- (emit
- (c/generate-assembly
- "int main(void) {
- return 6;
- }")))
-
- (-> ex
- p/parse)
+ return ~(-(~(-1)));
+ }"))
())
diff --git a/src/cljcc/symbols.clj b/src/cljcc/symbols.clj
new file mode 100644
index 0000000..1afbe47
--- /dev/null
+++ b/src/cljcc/symbols.clj
@@ -0,0 +1,10 @@
+(ns cljcc.symbols)
+
+(def symbols
+ "Holds global symbol table.
+
+ Maps identifiers to their types."
+ (atom {}))
+
+(defn reset-symbols [new-symbols]
+ (reset! symbols new-symbols))
diff --git a/src/cljcc/tacky.clj b/src/cljcc/tacky.clj
index 5451f78..1b339d9 100644
--- a/src/cljcc/tacky.clj
+++ b/src/cljcc/tacky.clj
@@ -4,7 +4,8 @@
[cljcc.lexer :as l]
[cljcc.util :as u]
[cljcc.parser :as p]
- [cljcc.analyzer :as a]))
+ [cljcc.analyzer :as a]
+ [cljcc.symbols :as symbols]))
(defn- variable
([]
@@ -379,8 +380,9 @@
(dissoc :body)
(assoc :instructions instructions))))
-(defn tacky-generate [{ast :block}]
- (let [defined? (fn [x] (seq (:body x)))]
+(defn tacky-generate [{ast :block symbols :decl-name->symbol}]
+ (let [_ (symbols/reset-symbols symbols)
+ defined? (fn [x] (or (= (:identifier x) "main") (seq (:body x))))]
(->> ast
(filter defined?)
(map function-definition->tacky-function))))