@@ -449,7 +449,8 @@ let deal_with_prim tac rd (prim: Primitive.prim) args =
449
449
(* Load from the offset plus 4 for the tag *)
450
450
Vec. push tac (Load { rd; rs = arg; offset = offset + 4 ; byte = size })
451
451
452
- | Pignore -> ()
452
+ | Pignore ->
453
+ Vec. push tac (Assign { rd; rs = unit })
453
454
454
455
(* Calculates whether two references are equal; gets a boolean value *)
455
456
| Prefeq ->
@@ -710,9 +711,9 @@ let rec do_convert tac (expr: Mcore.expr) =
710
711
711
712
(* If this is a `Join`, then we must jump to the corresponding letfn *)
712
713
if kind = Join then (
713
- Vec. push tac (Jump ! current_join);
714
714
Vec. push tac (Assign { rd = ! current_join_ret; rs = rd });
715
- unit
715
+ Vec. push tac (Jump ! current_join);
716
+ ! current_join_ret
716
717
) else (
717
718
Vec. append tac after;
718
719
rd
@@ -1020,10 +1021,10 @@ let rec do_convert tac (expr: Mcore.expr) =
1020
1021
1021
1022
current_join := join;
1022
1023
current_join_ret := rd;
1024
+
1025
+ let ret = do_convert tac afterwards in
1023
1026
1024
- (* This is definitely a unit *)
1025
- let _ = do_convert tac afterwards in
1026
-
1027
+ Vec. push tac (Assign { rd; rs = ret });
1027
1028
Vec. push tac (Jump join);
1028
1029
Vec. push tac (Label join);
1029
1030
@@ -1072,68 +1073,82 @@ let rec do_convert tac (expr: Mcore.expr) =
1072
1073
let index = new_temp Mtype. T_int in
1073
1074
Vec. push tac (Load { rd = index; rs = obj; offset = 0 ; byte = 4 });
1074
1075
1076
+ let tag_offsets = Hashtbl. find variants (nameof obj.ty) in
1077
+
1075
1078
(* Generate a jump table *)
1076
1079
let label = new_label " jumptable_" in
1077
- let jumps = List. init (List. length cases ) (fun _ -> new_label " jumptable_" ) in
1080
+ let jumps = List. init (List. length tag_offsets ) (fun _ -> new_label " jumptable_" ) in
1078
1081
let out = new_label " jumptable_out_" in
1079
- Vec. push global_inst ( ExtArray { label; values = jumps; elem_size = 8 });
1082
+ let default_lbl = new_label " jumptable_default_ " in
1080
1083
1081
1084
(* Choose which place to jump to *)
1082
1085
let jtable = new_temp Mtype. T_bytes in
1083
1086
let ptr_sz = new_temp Mtype. T_int in
1084
- let off = new_temp Mtype. T_int in
1085
- let place = new_temp Mtype. T_bytes in
1087
+ let off = new_temp Mtype. T_bytes in
1088
+ let altered = new_temp Mtype. T_bytes in
1086
1089
let target = new_temp Mtype. T_bytes in
1090
+
1091
+ (* Assign all these different possibilities into rd *)
1092
+ let rd = new_temp ty in
1093
+
1087
1094
(* Load the address *)
1088
1095
Vec. push tac (AssignLabel { rd = jtable; imm = label });
1089
1096
Vec. push tac (AssignInt { rd = ptr_sz; imm = pointer_size });
1090
1097
Vec. push tac (Mul { rd = off; rs1 = index; rs2 = ptr_sz });
1091
- Vec. push tac (Add { rd = place; rs1 = jtable; rs2 = off });
1092
- Vec. push tac (Load { rd = target; rs = place; offset = 0 ; byte = pointer_size });
1093
- (* Jump to that address *)
1094
- Vec. push tac (JumpIndirect { rs = target; possibilities = jumps });
1098
+ Vec. push tac (Add { rd = altered; rs1 = jtable; rs2 = off });
1099
+ Vec. push tac (Load { rd = target; rs = altered; offset = 0 ; byte = pointer_size });
1095
1100
1096
- let tag_offsets = Hashtbl. find variants (nameof obj.ty) in
1097
- let returns = Vec. empty () in
1098
1101
let visited = Vec. empty () in
1099
1102
let correspondence = Array. make (List. length tag_offsets) " _uninit" in
1100
- (* For each label, generate the code for each label *)
1103
+
1104
+ (* For each label, generate the code of it *)
1105
+ let tac_cases = Vec. empty () in
1106
+
1101
1107
List. iter (fun ((tag : Tag.t ), ident , expr ) ->
1102
1108
let lbl = List. nth jumps tag.index in
1103
1109
1104
- Vec. push tac (Label lbl);
1110
+ Vec. push tac_cases (Label lbl);
1105
1111
(match ident with
1106
1112
| None -> ()
1107
1113
| Some x ->
1108
- Vec. push tac (Assign { rd = { name = Ident. to_string x; ty = obj.ty }; rs = obj }));
1109
- let ret = do_convert tac expr in
1110
- Vec. push tac ( Jump out );
1111
- Vec. push returns (ret, lbl );
1114
+ Vec. push tac_cases (Assign { rd = { name = Ident. to_string x; ty = obj.ty }; rs = obj }));
1115
+ let ret = do_convert tac_cases expr in
1116
+ Vec. push tac_cases ( Assign { rd; rs = ret } );
1117
+ Vec. push tac_cases ( Jump out );
1112
1118
Vec. push visited tag.index;
1113
1119
correspondence.(tag.index) < - lbl
1114
1120
) cases;
1115
1121
1116
1122
(match default with
1117
1123
| None -> ()
1118
1124
| Some x ->
1119
- let default_lbl = new_label " jumptable_default_" in
1120
1125
let visited = visited |> Vec. to_list in
1121
1126
1122
- Vec. push tac (Label default_lbl);
1123
- let ret = do_convert tac expr in
1124
- Vec. push tac (Jump out);
1127
+ Vec. push tac_cases (Label default_lbl);
1128
+ let ret = do_convert tac_cases x in
1129
+ Vec. push tac_cases (Assign { rd; rs = ret });
1130
+ Vec. push tac_cases (Jump out);
1131
+
1125
1132
List. iteri (fun i x ->
1126
1133
if not (List. mem i visited) then (
1127
- Vec. push returns (ret, default_lbl);
1128
1134
correspondence.(i) < - default_lbl
1129
1135
)
1130
- ) tag_offsets);
1136
+ ) tag_offsets; );
1131
1137
1132
- (* Now assign all these different things into rd *)
1133
- let rd = new_temp ty in
1138
+ Vec. push tac_cases (Label out);
1139
+
1140
+ (* Deduplicate all possible targets *)
1141
+ let possibilities =
1142
+ Array. to_list correspondence |> Stringset. of_list |> Stringset. to_seq |> List. of_seq
1143
+ in
1144
+ (* Jump to the correct target *)
1145
+ Vec. push tac (JumpIndirect { rs = target; possibilities });
1146
+
1147
+ (* Emit all match cases *)
1148
+ Vec. append tac tac_cases;
1134
1149
1135
- Vec. push tac ( Label out);
1136
- Vec. push tac ( Phi { rd; rs = Vec . to_list returns });
1150
+ (* Record the correct label order *)
1151
+ Vec. push global_inst ( ExtArray { label; values = Array . to_list correspondence; elem_size = 8 });
1137
1152
rd
1138
1153
1139
1154
| Cexpr_letrec _ ->
@@ -1145,7 +1160,7 @@ let rec do_convert tac (expr: Mcore.expr) =
1145
1160
unit
1146
1161
1147
1162
| Cexpr_switch_constant { obj; cases; default; ty; _ } ->
1148
- let obj = do_convert tac obj in
1163
+ let index = do_convert tac obj in
1149
1164
1150
1165
let die () =
1151
1166
failwith " riscv_generate.ml: bad match on constants"
@@ -1170,20 +1185,106 @@ let rec do_convert tac (expr: Mcore.expr) =
1170
1185
) cases
1171
1186
in
1172
1187
1173
- let mx = List. fold_left (fun mx x -> max mx x) 0 values in
1174
- let mn = List. fold_left (fun mn x -> min mx x) 0 values in
1175
-
1176
- let value = new_temp Mtype. T_int in
1188
+ let mx = List. fold_left (fun mx x -> max mx x) (- 2147483647-1 ) values in
1189
+ let mn = List. fold_left (fun mn x -> min mn x) 2147483647 values in
1177
1190
1178
1191
(* Sparse values, generate a hash function *)
1179
- if mx - mn > = 10 then (
1180
- failwith " TODO: large "
1181
- ) else
1182
- Vec. push tac (Assign { rd = value; rs = obj });
1183
-
1184
- (* Compile into jump table *)
1185
- failwith " TODO: jump table" ;
1186
- ()
1192
+ if mx - mn > = 20 then (
1193
+ failwith " TODO: large"
1194
+ )
1195
+
1196
+ (* Dense values, just get a jump table *)
1197
+ else (
1198
+ let table = new_label " jumptable_int_" in
1199
+ let jump = new_label " do_jump_int_" in
1200
+ let jumps = List. init (mx - mn + 1 ) (fun _ -> new_label " jumptable_int_" ) in
1201
+ let out = new_label " jumptable_int_out_" in
1202
+ let default_lbl = new_label " jumptable_default_" in
1203
+
1204
+ (* If the value is outside the min/max range, jump to default *)
1205
+ let inrange = new_temp Mtype. T_bool in
1206
+ let maximum = new_temp Mtype. T_int in
1207
+ let minimum = new_temp Mtype. T_int in
1208
+ let _1 = new_temp Mtype. T_bool in
1209
+ let _2 = new_temp Mtype. T_bool in
1210
+
1211
+ (* Evaluate (x < max) && (x > min), which is the range where we can use jump table *)
1212
+ Vec. push tac (AssignInt { rd = maximum; imm = mx });
1213
+ Vec. push tac (AssignInt { rd = minimum; imm = mn });
1214
+ Vec. push tac (Leq { rd = _1; rs1 = index; rs2 = maximum });
1215
+ Vec. push tac (Geq { rd = _2; rs1 = index; rs2 = minimum });
1216
+ Vec. push tac (And { rd = inrange; rs1 = _1; rs2 = _2 });
1217
+ Vec. push tac (Branch { cond = inrange; ifso = jump; ifnot = default_lbl });
1218
+
1219
+ (* Load the address *)
1220
+ Vec. push tac (Label jump);
1221
+
1222
+ let jtable = new_temp Mtype. T_bytes in
1223
+ let ptr_sz = new_temp Mtype. T_int in
1224
+ let off = new_temp Mtype. T_int in
1225
+ let altered = new_temp Mtype. T_bytes in
1226
+ let target = new_temp Mtype. T_bytes in
1227
+
1228
+ Vec. push tac (AssignLabel { rd = jtable; imm = table });
1229
+ Vec. push tac (AssignInt { rd = ptr_sz; imm = pointer_size });
1230
+
1231
+ (* We must also minus the minimum, unlike switch_constr *)
1232
+ let min_var = new_temp Mtype. T_int in
1233
+ let ind_2 = new_temp Mtype. T_int in
1234
+
1235
+ Vec. push tac (AssignInt { rd = min_var; imm = mn });
1236
+ Vec. push tac (Sub { rd = ind_2; rs1 = index; rs2 = min_var });
1237
+
1238
+ (* Now find which address to jump to *)
1239
+ Vec. push tac (Mul { rd = off; rs1 = ind_2; rs2 = ptr_sz });
1240
+ Vec. push tac (Add { rd = altered; rs1 = jtable; rs2 = off });
1241
+ Vec. push tac (Load { rd = target; rs = altered; offset = 0 ; byte = pointer_size });
1242
+
1243
+ let visited = Vec. empty () in
1244
+ let correspondence = Array. make (List. length cases) " _uninit" in
1245
+
1246
+ (* For each label, generate the code of it *)
1247
+ let tac_cases = Vec. empty () in
1248
+
1249
+ List. iter2 (fun value (_ , expr ) ->
1250
+ let lbl = List. nth jumps (value - mn) in
1251
+
1252
+ Vec. push tac_cases (Label lbl);
1253
+ let ret = do_convert tac_cases expr in
1254
+ Vec. push tac_cases (Assign { rd; rs = ret });
1255
+ Vec. push tac_cases (Jump out);
1256
+ Vec. push visited value;
1257
+ correspondence.(value - mn) < - lbl
1258
+ ) values cases;
1259
+
1260
+ (* For each values in the (min, max) range, redirect them into default *)
1261
+ let visited = visited |> Vec. to_list in
1262
+
1263
+ Vec. push tac_cases (Label default_lbl);
1264
+ let ret = do_convert tac_cases default in
1265
+ Vec. push tac_cases (Assign { rd; rs = ret });
1266
+ Vec. push tac_cases (Jump out);
1267
+
1268
+ List. iter (fun i ->
1269
+ if not (List. mem i visited) then (
1270
+ correspondence.(i - mn) < - default_lbl
1271
+ )
1272
+ ) (List. init (mx - mn) (fun i -> i + mn));
1273
+
1274
+ (* Store the correct order of jump table *)
1275
+ Vec. push tac_cases (Label out);
1276
+ Vec. push global_inst (ExtArray
1277
+ { label = table; values = Array. to_list correspondence; elem_size = 8 });
1278
+
1279
+ (* Deduplicate possibilities and jump there *)
1280
+ let possibilities =
1281
+ Array. to_list correspondence |> Stringset. of_list |> Stringset. to_seq |> List. of_seq
1282
+ in
1283
+
1284
+ Vec. push tac (JumpIndirect { rs = target; possibilities });
1285
+ Vec. append tac tac_cases;
1286
+
1287
+ )
1187
1288
1188
1289
| _ -> failwith " TODO: unsupported switch constant type" );
1189
1290
@@ -1275,6 +1376,7 @@ let rec do_convert tac (expr: Mcore.expr) =
1275
1376
rd
1276
1377
1277
1378
| Cexpr_function _ ->
1379
+ Printf. printf " unconverted: %s\n " (Mcore. sexp_of_expr expr |> S. to_string);
1278
1380
failwith " riscv_generate.ml: Cexpr_function should have been converted into letfn"
1279
1381
1280
1382
let generate_vtables () =
@@ -1455,6 +1557,10 @@ let analyze_closure (top: Mcore.top_item) =
1455
1557
iter_expr find_closures func.body;
1456
1558
Vec. iter process_closure worklist
1457
1559
1560
+ | Ctop_expr { expr } ->
1561
+ iter_expr find_closures expr;
1562
+ Vec. iter process_closure worklist
1563
+
1458
1564
| _ -> ()
1459
1565
1460
1566
let convert_toplevel _start (top : Mcore.top_item ) =
@@ -1548,7 +1654,7 @@ let ssa_of_mcore (core: Mcore.t) =
1548
1654
(* Deal with main *)
1549
1655
let with_main = match core.main with
1550
1656
| Some (main_expr , _ ) ->
1551
- let lambda_removed = convert_lambda main_expr in
1657
+ let lambda_removed = map_expr convert_lambda main_expr in
1552
1658
1553
1659
(* Find closures in main *)
1554
1660
let closures = Vec. empty () in
0 commit comments