From ca3e1df031f944a18dc702548adacfd19f0124b8 Mon Sep 17 00:00:00 2001 From: Mariano Uvalle Date: Wed, 12 Feb 2025 18:55:15 -0800 Subject: [PATCH] Format backend.ml in hw3. Signed-off-by: Mariano Uvalle --- hw3/bin/backend.ml | 153 ++++++++++++++++++++++----------------------- 1 file changed, 76 insertions(+), 77 deletions(-) diff --git a/hw3/bin/backend.ml b/hw3/bin/backend.ml index 48d9c71..41e5b91 100644 --- a/hw3/bin/backend.ml +++ b/hw3/bin/backend.ml @@ -2,7 +2,6 @@ open Ll open X86 - module Platform = Util.Platform (* Overview ----------------------------------------------------------------- *) @@ -12,19 +11,17 @@ module Platform = Util.Platform plan for implementing the compiler is provided on the project web page. *) - (* helpers ------------------------------------------------------------------ *) (* Map LL comparison operations to X86 condition codes *) let compile_cnd = function - | Ll.Eq -> X86.Eq - | Ll.Ne -> X86.Neq + | Ll.Eq -> X86.Eq + | Ll.Ne -> X86.Neq | Ll.Slt -> X86.Lt | Ll.Sle -> X86.Le | Ll.Sgt -> X86.Gt | Ll.Sge -> X86.Ge - - +;; (* locals and layout -------------------------------------------------------- *) @@ -56,14 +53,14 @@ type layout = (uid * X86.operand) list (* A context contains the global type declarations (needed for getelementptr calculations) and a stack layout. *) -type ctxt = { tdecls : (tid * ty) list - ; layout : layout - } +type ctxt = + { tdecls : (tid * ty) list + ; layout : layout + } (* useful for looking up items in tdecls or layouts *) let lookup m x = List.assoc x m - (* compiling operands ------------------------------------------------------ *) (* LLVM IR instructions support several kinds of operands. @@ -72,17 +69,24 @@ let lookup m x = List.assoc x m global addresses that must be computed from a label. Constants are immediately available, and the operand Null is the 64-bit 0 value. - NOTE: two important facts about global identifiers: + NOTE: two important facts about global identifiers: - (1) You should use (Platform.mangle gid) to obtain a string - suitable for naming a global label on your platform (OS X expects - "_main" while linux expects "main"). + (1) You should use (Platform.mangle gid) to obtain a string + suitable for naming a global label on your platform (OS X expects + "_main" while linux expects "main"). - (2) 64-bit assembly labels are not allowed as immediate operands. - That is, the X86 code: movq _gid %rax which looks like it should - put the address denoted by _gid into %rax is not allowed. - Instead, you need to compute an %rip-relative address using the - leaq instruction: leaq _gid(%rip) %rax. + (2) 64-bit assembly labels are not allowed as immediate operands. + That is, the X86 code: movq _gid %rax which looks like it should + put the address denoted by _gid into %rax is not allowed. + Instead, you need to compute an %rip-relative address using the + leaq instruction: leaq _gid(%rip) %rax. + + NOTE(jmug): _gid(%rip) is interpreted as simply _gid ONLY when + the register is %rip and is called RIP relative addressing, read + more about it here: https://www.cs.unc.edu/~porter/courses/cse506/s16/ref/assembly.html#:~:text=RIP%20relative%20addressing,of%20the%20redundant%20SIB%20form. + + TODO: The section below still reads like giberish, + mabye reading the rest of the code/tests will help. One strategy for compiling instruction operands is to use a designated register (or registers) for holding the values being @@ -91,10 +95,9 @@ let lookup m x = List.assoc x m the X86 instruction that moves an LLVM operand into a designated destination (usually a register). *) -let compile_operand (ctxt:ctxt) (dest:X86.operand) : Ll.operand -> ins = - function _ -> failwith "compile_operand unimplemented" - - +let compile_operand (ctxt : ctxt) (dest : X86.operand) : Ll.operand -> ins = function + | _ -> failwith "compile_operand unimplemented" +;; (* compiling call ---------------------------------------------------------- *) @@ -147,9 +150,6 @@ let compile_operand (ctxt:ctxt) (dest:X86.operand) : Ll.operand -> ins = ] *) - - - (* compiling getelementptr (gep) ------------------------------------------- *) (* The getelementptr instruction computes an address by indexing into @@ -162,7 +162,7 @@ let compile_operand (ctxt:ctxt) (dest:X86.operand) : Ll.operand -> ins = *) (* [size_ty] maps an LLVMlite type to a size in bytes. - (needed for getelementptr) + (needed for getelementptr) - the size of a struct is the sum of the sizes of each component - the size of an array of t's with n elements is n * the size of t @@ -172,11 +172,9 @@ let compile_operand (ctxt:ctxt) (dest:X86.operand) : Ll.operand -> ins = - Void, i8, and functions have undefined sizes according to LLVMlite. Your function should simply return 0 in those cases *) -let rec size_ty (tdecls:(tid * ty) list) (t:Ll.ty) : int = -failwith "size_ty not implemented" - - - +let rec size_ty (tdecls : (tid * ty) list) (t : Ll.ty) : int = + failwith "size_ty not implemented" +;; (* Generates code that computes a pointer value. @@ -185,28 +183,29 @@ failwith "size_ty not implemented" 2. the value of op is the base address of the calculation 3. the first index in the path is treated as the index into an array - of elements of type t located at the base address + of elements of type t located at the base address 4. subsequent indices are interpreted according to the type t: - - if t is a struct, the index must be a constant n and it - picks out the n'th element of the struct. [ NOTE: the offset + - if t is a struct, the index must be a constant n and it + picks out the n'th element of the struct. [ NOTE: the offset within the struct of the n'th element is determined by the sizes of the types of the previous elements ] - - if t is an array, the index can be any operand, and its - value determines the offset within the array. + - if t is an array, the index can be any operand, and its + value determines the offset within the array. - - if t is any other type, the path is invalid + - if t is any other type, the path is invalid 5. if the index is valid, the remainder of the path is computed as - in (4), but relative to the type f the sub-element picked out - by the path so far + in (4), but relative to the type f the sub-element picked out + by the path so far *) -let compile_gep (ctxt:ctxt) (op : Ll.ty * Ll.operand) (path: Ll.operand list) : ins list = -failwith "compile_gep not implemented" - - +let compile_gep (ctxt : ctxt) (op : Ll.ty * Ll.operand) (path : Ll.operand list) + : ins list + = + failwith "compile_gep not implemented" +;; (* compiling instructions -------------------------------------------------- *) @@ -231,16 +230,15 @@ failwith "compile_gep not implemented" - Bitcast: does nothing interesting at the assembly level *) -let compile_insn (ctxt:ctxt) ((uid:uid), (i:Ll.insn)) : X86.ins list = - failwith "compile_insn not implemented" - - +let compile_insn (ctxt : ctxt) ((uid : uid), (i : Ll.insn)) : X86.ins list = + failwith "compile_insn not implemented" +;; (* compiling terminators --------------------------------------------------- *) -(* prefix the function name [fn] to a label to ensure that the X86 labels are +(* prefix the function name [fn] to a label to ensure that the X86 labels are globally unique . *) -let mk_lbl (fn:string) (l:string) = fn ^ "." ^ l +let mk_lbl (fn : string) (l : string) = fn ^ "." ^ l (* Compile block terminators is not too difficult: @@ -254,28 +252,27 @@ let mk_lbl (fn:string) (l:string) = fn ^ "." ^ l [fn] - the name of the function containing this terminator *) -let compile_terminator (fn:string) (ctxt:ctxt) (t:Ll.terminator) : ins list = +let compile_terminator (fn : string) (ctxt : ctxt) (t : Ll.terminator) : ins list = failwith "compile_terminator not implemented" - +;; (* compiling blocks --------------------------------------------------------- *) -(* We have left this helper function here for you to complete. +(* We have left this helper function here for you to complete. [fn] - the name of the function containing this block [ctxt] - the current context [blk] - LLVM IR code for the block *) -let compile_block (fn:string) (ctxt:ctxt) (blk:Ll.block) : ins list = +let compile_block (fn : string) (ctxt : ctxt) (blk : Ll.block) : ins list = failwith "compile_block not implemented" +;; let compile_lbl_block fn lbl ctxt blk : elem = Asm.text (mk_lbl fn lbl) (compile_block fn ctxt blk) - - +;; (* compile_fdecl ------------------------------------------------------------ *) - (* Complete this helper function, which computes the location of the nth incoming function argument: either in a register or relative to %rbp, according to the calling conventions. We will test this function as part of @@ -285,9 +282,7 @@ let compile_lbl_block fn lbl ctxt blk : elem = [ NOTE: the first six arguments are numbered 0 .. 5 ] *) -let arg_loc (n : int) : operand = -failwith "arg_loc not implemented" - +let arg_loc (n : int) : operand = failwith "arg_loc not implemented" (* We suggest that you create a helper function that computes the stack layout for a given function declaration. @@ -296,10 +291,10 @@ failwith "arg_loc not implemented" - in this (inefficient) compilation strategy, each local id is also stored as a stack slot. - see the discussion about locals - *) -let stack_layout (args : uid list) ((block, lbled_blocks):cfg) : layout = -failwith "stack_layout not implemented" +let stack_layout (args : uid list) ((block, lbled_blocks) : cfg) : layout = + failwith "stack_layout not implemented" +;; (* The code for the entry-point of a function must do several things: @@ -317,28 +312,32 @@ failwith "stack_layout not implemented" - the function entry code should allocate the stack storage needed to hold all of the local stack slots. *) -let compile_fdecl (tdecls:(tid * ty) list) (name:string) ({ f_param; f_cfg; _ }:fdecl) : prog = -failwith "compile_fdecl unimplemented" - - +let compile_fdecl + (tdecls : (tid * ty) list) + (name : string) + ({ f_param; f_cfg; _ } : fdecl) + : prog + = + failwith "compile_fdecl unimplemented" +;; (* compile_gdecl ------------------------------------------------------------ *) (* Compile a global value into an X86 global data declaration and map a global uid to its associated X86 label. *) let rec compile_ginit : ginit -> X86.data list = function - | GNull -> [Quad (Lit 0L)] - | GGid gid -> [Quad (Lbl (Platform.mangle gid))] - | GInt c -> [Quad (Lit c)] - | GString s -> [Asciz s] + | GNull -> [ Quad (Lit 0L) ] + | GGid gid -> [ Quad (Lbl (Platform.mangle gid)) ] + | GInt c -> [ Quad (Lit c) ] + | GString s -> [ Asciz s ] | GArray gs | GStruct gs -> List.map compile_gdecl gs |> List.flatten - | GBitcast (_t1,g,_t2) -> compile_ginit g + | GBitcast (_t1, g, _t2) -> compile_ginit g and compile_gdecl (_, g) = compile_ginit g - (* compile_prog ------------------------------------------------------------- *) -let compile_prog {tdecls; gdecls; fdecls; _} : X86.prog = - let g = fun (lbl, gdecl) -> Asm.data (Platform.mangle lbl) (compile_gdecl gdecl) in - let f = fun (name, fdecl) -> compile_fdecl tdecls name fdecl in - (List.map g gdecls) @ (List.map f fdecls |> List.flatten) +let compile_prog { tdecls; gdecls; fdecls; _ } : X86.prog = + let g (lbl, gdecl) = Asm.data (Platform.mangle lbl) (compile_gdecl gdecl) in + let f (name, fdecl) = compile_fdecl tdecls name fdecl in + List.map g gdecls @ (List.map f fdecls |> List.flatten) +;;