Skip to content

Commit bf3482d

Browse files
AdUhTkJmmengzhuo
authored andcommitted
Lowering to virtasm for basic instructions
1 parent 7d2da5a commit bf3482d

File tree

3 files changed

+318
-17
lines changed

3 files changed

+318
-17
lines changed

src/riscv_reg.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ Immediate values can either be an integer (`IntImm`) or a floating-point number
170170
module Imm = struct
171171
type t =
172172
| IntImm of int (* Integer immediate value *)
173+
| Int64Imm of int64
173174
| FloatImm of float (* Floating-point immediate value *)
174175

175176
let to_string imm =

src/riscv_virtasm.ml

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ module Slots = struct
4343
type i_slot =
4444
{ rd : Slot.t
4545
; rs1 : Slot.t
46-
; imm : Imm.t
46+
; imm : int
4747
}
4848

4949
(** Defines a single floating-point register assignment with a destination register `frd`. *)
@@ -138,13 +138,13 @@ module Slots = struct
138138
type mem_slot =
139139
{ rd : Slot.t
140140
; base : Slot.t
141-
; offset : Imm.t
141+
; offset : int
142142
}
143143

144144
type mem_fslot =
145145
{ frd : Slot.t
146146
; base : Slot.t
147-
; offset : Imm.t
147+
; offset : int
148148
}
149149

150150
(**
@@ -172,27 +172,75 @@ module Inst = struct
172172
type t =
173173
(* Integer Arithmetic Instructions *)
174174
| Add of r_slot
175+
| Addw of r_slot
176+
| Addu of r_slot
177+
| Adduw of r_slot
178+
175179
| Sub of r_slot
180+
| Subw of r_slot
181+
| Subu of r_slot
182+
| Subuw of r_slot
183+
184+
| Mul of r_slot
185+
| Mulw of r_slot
186+
187+
| Div of r_slot (* signed divide *)
188+
| Divw of r_slot
189+
| Divu of r_slot (* unsigned divide *)
190+
| Divuw of r_slot
191+
192+
| Rem of r_slot (* signed remainder *)
193+
| Remw of r_slot
194+
| Remu of r_slot (* unsigned remainder *)
195+
| Remuw of r_slot
196+
197+
| Sextw of assign_slot (* signed extend *)
198+
| Zextw of assign_slot (* unsigned extend *)
199+
176200
| Addi of i_slot
201+
| Addiw of i_slot
177202
(* Logical and Shift Instructions *)
178203
| And of r_slot
179204
| Or of r_slot
180205
| Xor of r_slot
206+
207+
| Andi of i_slot
208+
| Ori of i_slot
209+
| Xori of i_slot
210+
211+
| Slt of r_slot (* set less than *)
212+
| Sltw of r_slot
213+
| Sltu of r_slot
214+
| Sltuw of r_slot
215+
181216
| Sll of r_slot (* shift left logical *)
217+
| Sllw of r_slot
218+
182219
| Srl of r_slot (* shift right logical *)
220+
| Srlw of r_slot
221+
183222
| Sra of r_slot (* shift right arithmetic *)
223+
| Sraw of r_slot
224+
184225
| Slli of i_slot (* shift left logical immediate *)
226+
| Slliw of i_slot
185227
| Srli of i_slot (* shift right logical immediate *)
228+
| Srliw of i_slot
186229
| Srai of i_slot (* shift right arithmetic immediate *)
230+
| Sraiw of i_slot
231+
| Slti of i_slot
232+
| Sltiw of i_slot
187233
(* Multiplication and Division Instructions *)
188-
| Mul of r_slot
189-
| Div of r_slot (* signed divide *)
190-
| Divu of r_slot (* unsigned divide *)
191-
| Rem of r_slot (* signed remainder *)
192-
| Remu of r_slot (* unsigned remainder *)
193234
(* Memory Access Instructions *)
235+
| Lb of mem_slot
236+
| Lbu of mem_slot
237+
| Lh of mem_slot
238+
| Lhu of mem_slot
194239
| Lw of mem_slot (* load word 32-bit *)
195240
| Ld of mem_slot (* load doubleword 64-bit *)
241+
242+
| Sb of mem_slot
243+
| Sh of mem_slot
196244
| Sw of mem_slot (* store word 32-bit *)
197245
| Sd of mem_slot (* store doubleword 64-bit *)
198246
(* Floating-Point Arithmetic Instructions *)

src/riscv_virtasm_generate.ml

Lines changed: 261 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,265 @@
11
open Riscv_virtasm
22
module Ssa = Riscv_ssa
33

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)
1150
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

Comments
 (0)