|
1 | 1 | open Riscv_virtasm |
2 | 2 | module Ssa = Riscv_ssa |
3 | 3 |
|
4 | | -let virtasm_of_ssa (ssa : Ssa.t list) = |
5 | | - let vprog : VProg.t = |
6 | | - { blocks = VBlockMap.empty |
7 | | - ; funcs = VFuncMap.empty |
8 | | - ; consts = VSymbolMap.empty |
9 | | - ; loop_vars = VBlockMap.empty |
10 | | - } |
| 4 | +open Riscv_virtasm |
| 5 | +open Riscv_ssa |
| 6 | +open Riscv_reg |
| 7 | +open Riscv_opt |
| 8 | + |
| 9 | +module Vec = Basic_vec |
| 10 | + |
| 11 | +let slot = ref 0 |
| 12 | +let vfuncs: VFunc.t Vec.t = Vec.empty () |
| 13 | +let vblocks: VBlock.t Vec.t = Vec.empty () |
| 14 | +let slot_map: (string, Slot.t) Hashtbl.t = Hashtbl.create 2048 |
| 15 | + |
| 16 | +(** Phi nodes at the beginning of each block *) |
| 17 | +let phis: (string, Riscv_ssa.phi Vec.t) Hashtbl.t = Hashtbl.create 256 |
| 18 | + |
| 19 | +let new_slot () = |
| 20 | + slot := !slot + 1; |
| 21 | + !slot |
| 22 | + |
| 23 | +(** Retrieve slot of the variable. When non-existent, create another one. *) |
| 24 | +let slot_v v = |
| 25 | + if v.name = "_" then |
| 26 | + Slot.Unit |
| 27 | + else if Hashtbl.mem slot_map v.name then |
| 28 | + Hashtbl.find slot_map v.name |
| 29 | + else ( |
| 30 | + let s = new_slot () in |
| 31 | + let new_slot = |
| 32 | + match v.ty with |
| 33 | + | T_float | T_double -> Slot.FSlot s |
| 34 | + | _ -> Slot s |
| 35 | + in |
| 36 | + Hashtbl.add slot_map v.name new_slot; |
| 37 | + new_slot |
| 38 | + ) |
| 39 | + |
| 40 | +(** Terminator and body are output arguments *) |
| 41 | +let convert_single name body terminator (inst: Riscv_ssa.t) = |
| 42 | + let die () = failwith "riscv_virtasm_generate.ml: unsupported" in |
| 43 | + |
| 44 | + let rslot ({ rd; rs1; rs2 }: Riscv_ssa.r_type) = |
| 45 | + ({ |
| 46 | + rd = slot_v rd; |
| 47 | + rs1 = slot_v rs1; |
| 48 | + rs2 = slot_v rs2 |
| 49 | + }: Slots.r_slot) |
11 | 50 | in |
12 | | - vprog |
13 | | -;; |
| 51 | + |
| 52 | + match inst with |
| 53 | + | Label l -> |
| 54 | + (* Don't care about labels. *) |
| 55 | + (* We're converting for a single basic block, *) |
| 56 | + (* and labels will be handled outside. *) |
| 57 | + () |
| 58 | + |
| 59 | + | Add ({ rd; rs1; rs2 } as x) -> |
| 60 | + let r = rslot x in |
| 61 | + Vec.push body (match rd.ty with |
| 62 | + | T_int -> Inst.Addw r |
| 63 | + | T_uint -> Inst.Adduw r |
| 64 | + | T_int64 -> Inst.Add r |
| 65 | + | T_uint64 -> Inst.Addu r |
| 66 | + | _ -> die()) |
| 67 | + |
| 68 | + | Sub ({ rd; rs1; rs2 } as x) -> |
| 69 | + let r = rslot x in |
| 70 | + Vec.push body (match rd.ty with |
| 71 | + | T_int -> Inst.Subw r |
| 72 | + | T_uint -> Inst.Subuw r |
| 73 | + | T_int64 -> Inst.Sub r |
| 74 | + | T_uint64 -> Inst.Subu r |
| 75 | + | _ -> die()) |
| 76 | + |
| 77 | + | Mul ({ rd; rs1; rs2 } as x) -> |
| 78 | + let r = rslot x in |
| 79 | + (match rd.ty with |
| 80 | + | T_int -> Vec.push body (Inst.Mulw r) |
| 81 | + | T_uint -> Vec.push body (Inst.Mulw r); Vec.push body (Zextw { rd = r.rd; rs = r.rd }) |
| 82 | + (* As only the last 64-bit is needed, we don't care about signedness *) |
| 83 | + | T_uint64 | T_int64 -> Vec.push body (Inst.Mul r) |
| 84 | + | _ -> die()) |
| 85 | + |
| 86 | + | Div ({ rd; rs1; rs2 } as x) -> |
| 87 | + let r = rslot x in |
| 88 | + Vec.push body (match rd.ty with |
| 89 | + | T_int -> Inst.Divw r |
| 90 | + | T_uint -> Inst.Divuw r |
| 91 | + | T_int64 -> Inst.Div r |
| 92 | + | T_uint64 -> Inst.Divu r |
| 93 | + | _ -> die()) |
| 94 | + |
| 95 | + | Less ({ rd; rs1; rs2 } as x) -> |
| 96 | + let r = rslot x in |
| 97 | + Vec.push body (match rd.ty with |
| 98 | + | T_int | T_int64 -> Inst.Slt r |
| 99 | + | T_uint | T_uint64 -> Inst.Sltu r |
| 100 | + | _ -> die()) |
| 101 | + |
| 102 | + | Great { rd; rs1; rs2 } -> |
| 103 | + (* Note rs1 and rs2 exchanged. *) |
| 104 | + let r = ({ |
| 105 | + rd = slot_v rd; |
| 106 | + rs1 = slot_v rs2; |
| 107 | + rs2 = slot_v rs1; |
| 108 | + }: Slots.r_slot) in |
| 109 | + |
| 110 | + Vec.push body (match rd.ty with |
| 111 | + | T_int | T_int64 -> Inst.Slt r |
| 112 | + | T_uint | T_uint64 -> Inst.Sltu r |
| 113 | + | _ -> die()) |
| 114 | + |
| 115 | + | Leq { rd; rs1; rs2 } -> |
| 116 | + (* rs1 <= rs2, means !(rs2 < rs1) *) |
| 117 | + |
| 118 | + let rd_s = slot_v rd in |
| 119 | + let r = ({ |
| 120 | + rd = rd_s; |
| 121 | + rs1 = slot_v rs2; |
| 122 | + rs2 = slot_v rs1; |
| 123 | + }: Slots.r_slot) in |
| 124 | + |
| 125 | + Vec.push body (match rd.ty with |
| 126 | + | T_int | T_int64 -> Inst.Slt r |
| 127 | + | T_uint | T_uint64 -> Inst.Sltu r |
| 128 | + | _ -> die()); |
| 129 | + |
| 130 | + (* We negate by xoring 1 *) |
| 131 | + Vec.push body (Inst.Xori { rd = rd_s; rs1 = rd_s; imm = 1 }) |
| 132 | + |
| 133 | + | Geq { rd; rs1; rs2 } -> |
| 134 | + (* rs1 >= rs2, means !(rs1 < rs2) *) |
| 135 | + |
| 136 | + let r = ({ |
| 137 | + rd = slot_v rd; |
| 138 | + rs1 = slot_v rs1; |
| 139 | + rs2 = slot_v rs2; |
| 140 | + }: Slots.r_slot) in |
| 141 | + |
| 142 | + Vec.push body (match rd.ty with |
| 143 | + | T_int | T_int64 -> Inst.Slt r |
| 144 | + | T_uint | T_uint64 -> Inst.Sltu r |
| 145 | + | _ -> die()); |
| 146 | + |
| 147 | + (* We negate by xoring 1 *) |
| 148 | + Vec.push body (Inst.Xori { rd = slot_v rd; rs1 = slot_v rd; imm = 1 }) |
| 149 | + |
| 150 | + | Eq { rd; rs1; rs2 } -> |
| 151 | + Vec.push body (Inst.Xor { rd = slot_v rd; rs1 = slot_v rs1; rs2 = slot_v rs2 }); |
| 152 | + Vec.push body (Inst.Slti { rd = slot_v rd; rs1 = slot_v rd; imm = 1 }) |
| 153 | + |
| 154 | + | Neq { rd; rs1; rs2 } -> |
| 155 | + Vec.push body (Inst.Xor { rd = slot_v rd; rs1 = slot_v rs1; rs2 = slot_v rs2 }); |
| 156 | + Vec.push body (Inst.Sltu { rd = slot_v rd; rs1 = Slot.Reg Zero; rs2 = slot_v rd }) |
| 157 | + |
| 158 | + | Call { rd; fn; args } |
| 159 | + | CallExtern { rd; fn; args } -> |
| 160 | + let r = slot_v rd in |
| 161 | + let int_args = Vec.empty () in |
| 162 | + let fp_args = Vec.empty () in |
| 163 | + |
| 164 | + List.iter (fun x -> match x.ty with |
| 165 | + | T_float | T_double -> Vec.push fp_args (slot_v x) |
| 166 | + | _ -> Vec.push int_args (slot_v x)) args; |
| 167 | + |
| 168 | + Vec.push body (Inst.Call { |
| 169 | + rd = r; fn = { name = fn; stamp = 0 }; |
| 170 | + args = Vec.to_list int_args; |
| 171 | + fargs = Vec.to_list fp_args |
| 172 | + }) |
| 173 | + |
| 174 | + | Load { rd; rs; offset; byte; } -> |
| 175 | + let mem_slot: Slots.mem_slot = { rd = slot_v rd; base = slot_v rs; offset } in |
| 176 | + Vec.push body (match byte with |
| 177 | + | 1 -> Inst.Lb mem_slot |
| 178 | + | 2 -> Inst.Lh mem_slot |
| 179 | + | 4 -> Inst.Lw mem_slot |
| 180 | + | 8 -> Inst.Ld mem_slot |
| 181 | + | _ -> die ()) |
| 182 | + |
| 183 | + | Store { rd; rs; offset; byte; } -> |
| 184 | + let mem_slot: Slots.mem_slot = { rd = slot_v rd; base = slot_v rs; offset } in |
| 185 | + Vec.push body (match byte with |
| 186 | + | 1 -> Inst.Sb mem_slot |
| 187 | + | 2 -> Inst.Sh mem_slot |
| 188 | + | 4 -> Inst.Sw mem_slot |
| 189 | + | 8 -> Inst.Sd mem_slot |
| 190 | + | _ -> die ()) |
| 191 | + |
| 192 | + | AssignInt { rd; imm } -> |
| 193 | + Vec.push body (Inst.Li { rd = slot_v rd; imm = IntImm imm }) |
| 194 | + |
| 195 | + | AssignInt64 { rd; imm } -> |
| 196 | + Vec.push body (Inst.Li { rd = slot_v rd; imm = Int64Imm imm }) |
| 197 | + |
| 198 | + | Assign { rd; rs } -> |
| 199 | + Vec.push body (Inst.Mv { rd = slot_v rd; rs = slot_v rs }) |
| 200 | + |
| 201 | + | Phi phi -> |
| 202 | + Vec.push (Hashtbl.find phis name) phi |
| 203 | + |
| 204 | + | Return ret -> |
| 205 | + terminator := Term.Ret (slot_v ret) |
| 206 | + |
| 207 | + | Branch { cond; ifso; ifnot } -> |
| 208 | + terminator := Term.Beq { |
| 209 | + rs1 = slot_v cond; rs2 = Slot.Reg Zero; |
| 210 | + ifso = { name = ifso; stamp = 0 }; |
| 211 | + ifnot = { name = ifnot; stamp = 0 } } |
| 212 | + |
| 213 | + | Jump label -> |
| 214 | + terminator := Term.J { name = label; stamp = 0 } |
| 215 | + |
| 216 | + | _ -> die() |
| 217 | + |
| 218 | +let gen_fn (f: fn) = |
| 219 | + let int_args = Vec.empty () in |
| 220 | + let fp_args = Vec.empty () in |
| 221 | + |
| 222 | + (* Split arguments into integral and FP *) |
| 223 | + List.iter (fun x -> match x.ty with |
| 224 | + | T_float | T_double -> Vec.push fp_args (slot_v x) |
| 225 | + | _ -> Vec.push int_args (slot_v x)) f.args; |
| 226 | + |
| 227 | + Vec.push vfuncs { |
| 228 | + funn = { name = f.fn; stamp = 0 }; |
| 229 | + args = Vec.to_list int_args; |
| 230 | + fargs = Vec.to_list fp_args; |
| 231 | + entry = { name = f.fn; stamp = 0 } |
| 232 | + }; |
| 233 | + |
| 234 | + let blocks = get_blocks f.fn in |
| 235 | + List.iter (fun x -> |
| 236 | + let block = block_of x in |
| 237 | + let body = Vec.empty () in |
| 238 | + let term = ref (Term.Ret Unit) in |
| 239 | + Vec.iter (convert_single x body term) block.body; |
| 240 | + Vec.push vblocks { |
| 241 | + body; term = !term; preds = |
| 242 | + Vec.to_list block.pred |
| 243 | + |> List.map (fun x -> VBlock.NormalEdge { name = x; stamp = 0 }) |
| 244 | + } |
| 245 | + ) blocks; |
| 246 | + () |
| 247 | + |
| 248 | +let gen_var v = () |
| 249 | + |
| 250 | +let gen_extarr arr = () |
| 251 | + |
| 252 | +(** On calling this function, `ssa` must be coherent with basic block information in `opt` *) |
| 253 | +let virtasm_of_ssa (ssa : Riscv_ssa.t list) = |
| 254 | + List.iter (fun x -> match x with |
| 255 | + | FnDecl f -> gen_fn f |
| 256 | + | GlobalVarDecl var -> gen_var var |
| 257 | + | ExtArray arr -> gen_extarr arr |
| 258 | + | _ -> failwith "riscv_virtasm_generate.ml: bad toplevel SSA") ssa; |
| 259 | + ({ |
| 260 | + funcs = Label.Map.empty; |
| 261 | + blocks = Label.Map.empty; |
| 262 | + consts = Label.Map.empty; |
| 263 | + loop_vars = Label.Map.empty; |
| 264 | + }: VProg.t) |
| 265 | + |
0 commit comments