authorgravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-24 05:53:57-07:00
committergravatar for david@vortan.devDavid Rubin <david@vortan.dev> 2024-07-26 04:19:13-07:00
log1a7d89a84d7fef87eb45da8207bbeb852e3f0c02
tree1d7306a194386d23d2ddfa3611c07613f68dbece
parent574028ed5ec6ad455961ed46babdb7a5fe9f68bb
signature Commit is signed but in an unrecognized format.

riscv: clean up and unify encoding logic


19 files changed, 1720 insertions(+), 2391 deletions(-)

CMakeLists.txt+2-2
...@@ -539,10 +539,10 @@ set(ZIG_STAGE2_SOURCES...@@ -539,10 +539,10 @@ set(ZIG_STAGE2_SOURCES
539 src/arch/riscv64/bits.zig539 src/arch/riscv64/bits.zig
540 src/arch/riscv64/CodeGen.zig540 src/arch/riscv64/CodeGen.zig
541 src/arch/riscv64/Emit.zig541 src/arch/riscv64/Emit.zig
542 src/arch/riscv64/encoder.zig542 src/arch/riscv64/encoding.zig
543 src/arch/riscv64/Encoding.zig
544 src/arch/riscv64/Lower.zig543 src/arch/riscv64/Lower.zig
545 src/arch/riscv64/Mir.zig544 src/arch/riscv64/Mir.zig
545 src/arch/riscv64/mnem.zig
546 src/arch/sparc64/CodeGen.zig546 src/arch/sparc64/CodeGen.zig
547 src/arch/sparc64/Emit.zig547 src/arch/sparc64/Emit.zig
548 src/arch/sparc64/Mir.zig548 src/arch/sparc64/Mir.zig
lib/compiler/test_runner.zig-1
...@@ -271,7 +271,6 @@ pub fn mainSimple() anyerror!void {...@@ -271,7 +271,6 @@ pub fn mainSimple() anyerror!void {
271 };271 };
272 // is the backend capable of using std.fmt.format to print a summary at the end?272 // is the backend capable of using std.fmt.format to print a summary at the end?
273 const print_summary = switch (builtin.zig_backend) {273 const print_summary = switch (builtin.zig_backend) {
274 .stage2_riscv64 => true,
275 else => false,274 else => false,
276 };275 };
277276
src/arch/riscv64/CodeGen.zig+217-306
...@@ -20,6 +20,7 @@ const InternPool = @import("../../InternPool.zig");...@@ -20,6 +20,7 @@ const InternPool = @import("../../InternPool.zig");
20const Compilation = @import("../../Compilation.zig");20const Compilation = @import("../../Compilation.zig");
21const trace = @import("../../tracy.zig").trace;21const trace = @import("../../tracy.zig").trace;
22const codegen = @import("../../codegen.zig");22const codegen = @import("../../codegen.zig");
23const Mnemonic = @import("mnem.zig").Mnemonic;
2324
24const ErrorMsg = Zcu.ErrorMsg;25const ErrorMsg = Zcu.ErrorMsg;
25const Target = std.Target;26const Target = std.Target;
...@@ -65,7 +66,6 @@ arg_index: usize,...@@ -65,7 +66,6 @@ arg_index: usize,
65src_loc: Zcu.LazySrcLoc,66src_loc: Zcu.LazySrcLoc,
6667
67mir_instructions: std.MultiArrayList(Mir.Inst) = .{},68mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
68mir_extra: std.ArrayListUnmanaged(u32) = .{},
6969
70owner: Owner,70owner: Owner,
7171
...@@ -794,7 +794,6 @@ pub fn generate(...@@ -794,7 +794,6 @@ pub fn generate(
794 function.const_tracking.deinit(gpa);794 function.const_tracking.deinit(gpa);
795 function.exitlude_jump_relocs.deinit(gpa);795 function.exitlude_jump_relocs.deinit(gpa);
796 function.mir_instructions.deinit(gpa);796 function.mir_instructions.deinit(gpa);
797 function.mir_extra.deinit(gpa);
798 }797 }
799798
800 wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)});799 wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)});
...@@ -855,7 +854,6 @@ pub fn generate(...@@ -855,7 +854,6 @@ pub fn generate(
855854
856 var mir: Mir = .{855 var mir: Mir = .{
857 .instructions = function.mir_instructions.toOwnedSlice(),856 .instructions = function.mir_instructions.toOwnedSlice(),
858 .extra = try function.mir_extra.toOwnedSlice(gpa),
859 .frame_locs = function.frame_locs.toOwnedSlice(),857 .frame_locs = function.frame_locs.toOwnedSlice(),
860 };858 };
861 defer mir.deinit(gpa);859 defer mir.deinit(gpa);
...@@ -940,10 +938,7 @@ pub fn generateLazy(...@@ -940,10 +938,7 @@ pub fn generateLazy(
940 .avl = null,938 .avl = null,
941 .vtype = null,939 .vtype = null,
942 };940 };
943 defer {941 defer function.mir_instructions.deinit(gpa);
944 function.mir_instructions.deinit(gpa);
945 function.mir_extra.deinit(gpa);
946 }
947942
948 function.genLazy(lazy_sym) catch |err| switch (err) {943 function.genLazy(lazy_sym) catch |err| switch (err) {
949 error.CodegenFail => return Result{ .fail = function.err_msg.? },944 error.CodegenFail => return Result{ .fail = function.err_msg.? },
...@@ -955,7 +950,6 @@ pub fn generateLazy(...@@ -955,7 +950,6 @@ pub fn generateLazy(
955950
956 var mir: Mir = .{951 var mir: Mir = .{
957 .instructions = function.mir_instructions.toOwnedSlice(),952 .instructions = function.mir_instructions.toOwnedSlice(),
958 .extra = try function.mir_extra.toOwnedSlice(gpa),
959 .frame_locs = function.frame_locs.toOwnedSlice(),953 .frame_locs = function.frame_locs.toOwnedSlice(),
960 };954 };
961 defer mir.deinit(gpa);955 defer mir.deinit(gpa);
...@@ -1022,7 +1016,6 @@ fn formatWipMir(...@@ -1022,7 +1016,6 @@ fn formatWipMir(
1022 .allocator = data.func.gpa,1016 .allocator = data.func.gpa,
1023 .mir = .{1017 .mir = .{
1024 .instructions = data.func.mir_instructions.slice(),1018 .instructions = data.func.mir_instructions.slice(),
1025 .extra = data.func.mir_extra.items,
1026 .frame_locs = data.func.frame_locs.slice(),1019 .frame_locs = data.func.frame_locs.slice(),
1027 },1020 },
1028 .cc = .Unspecified,1021 .cc = .Unspecified,
...@@ -1120,7 +1113,7 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {...@@ -1120,7 +1113,7 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
1120 try func.mir_instructions.ensureUnusedCapacity(gpa, 1);1113 try func.mir_instructions.ensureUnusedCapacity(gpa, 1);
1121 const result_index: Mir.Inst.Index = @intCast(func.mir_instructions.len);1114 const result_index: Mir.Inst.Index = @intCast(func.mir_instructions.len);
1122 func.mir_instructions.appendAssumeCapacity(inst);1115 func.mir_instructions.appendAssumeCapacity(inst);
1123 if (inst.tag != .pseudo or switch (inst.ops) {1116 if (switch (inst.tag) {
1124 else => true,1117 else => true,
1125 .pseudo_dbg_prologue_end,1118 .pseudo_dbg_prologue_end,
1126 .pseudo_dbg_line_column,1119 .pseudo_dbg_line_column,
...@@ -1131,49 +1124,13 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {...@@ -1131,49 +1124,13 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
1131 return result_index;1124 return result_index;
1132}1125}
11331126
1134fn addNop(func: *Func) error{OutOfMemory}!Mir.Inst.Index {1127fn addPseudo(func: *Func, mnem: Mnemonic) error{OutOfMemory}!Mir.Inst.Index {
1135 return func.addInst(.{
1136 .tag = .nop,
1137 .ops = .none,
1138 .data = undefined,
1139 });
1140}
1141
1142fn addPseudoNone(func: *Func, ops: Mir.Inst.Ops) !void {
1143 _ = try func.addInst(.{
1144 .tag = .pseudo,
1145 .ops = ops,
1146 .data = undefined,
1147 });
1148}
1149
1150fn addPseudo(func: *Func, ops: Mir.Inst.Ops) !Mir.Inst.Index {
1151 return func.addInst(.{1128 return func.addInst(.{
1152 .tag = .pseudo,1129 .tag = mnem,
1153 .ops = ops,1130 .data = .none,
1154 .data = undefined,
1155 });1131 });
1156}1132}
11571133
1158pub fn addExtra(func: *Func, extra: anytype) Allocator.Error!u32 {
1159 const fields = std.meta.fields(@TypeOf(extra));
1160 try func.mir_extra.ensureUnusedCapacity(func.gpa, fields.len);
1161 return func.addExtraAssumeCapacity(extra);
1162}
1163
1164pub fn addExtraAssumeCapacity(func: *Func, extra: anytype) u32 {
1165 const fields = std.meta.fields(@TypeOf(extra));
1166 const result: u32 = @intCast(func.mir_extra.items.len);
1167 inline for (fields) |field| {
1168 func.mir_extra.appendAssumeCapacity(switch (field.type) {
1169 u32 => @field(extra, field.name),
1170 i32 => @bitCast(@field(extra, field.name)),
1171 else => @compileError("bad field type"),
1172 });
1173 }
1174 return result;
1175}
1176
1177/// Returns a temporary register that contains the value of the `reg` csr.1134/// Returns a temporary register that contains the value of the `reg` csr.
1178///1135///
1179/// Caller's duty to lock the return register is needed.1136/// Caller's duty to lock the return register is needed.
...@@ -1182,14 +1139,11 @@ fn getCsr(func: *Func, csr: CSR) !Register {...@@ -1182,14 +1139,11 @@ fn getCsr(func: *Func, csr: CSR) !Register {
1182 const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.u64));1139 const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.u64));
1183 _ = try func.addInst(.{1140 _ = try func.addInst(.{
1184 .tag = .csrrs,1141 .tag = .csrrs,
1185 .ops = .csr,1142 .data = .{ .csr = .{
1186 .data = .{1143 .csr = csr,
1187 .csr = .{1144 .rd = dst_reg,
1188 .csr = csr,1145 .rs1 = .x0,
1189 .rd = dst_reg,1146 } },
1190 .rs1 = .x0,
1191 },
1192 },
1193 });1147 });
1194 return dst_reg;1148 return dst_reg;
1195}1149}
...@@ -1208,7 +1162,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {...@@ -1208,7 +1162,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
1208 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));1162 const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options));
1209 _ = try func.addInst(.{1163 _ = try func.addInst(.{
1210 .tag = .vsetvli,1164 .tag = .vsetvli,
1211 .ops = .rri,
1212 .data = .{ .i_type = .{1165 .data = .{ .i_type = .{
1213 .rd = dst_reg,1166 .rd = dst_reg,
1214 .rs1 = .zero,1167 .rs1 = .zero,
...@@ -1221,7 +1174,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {...@@ -1221,7 +1174,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
1221 const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options));1174 const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options));
1222 _ = try func.addInst(.{1175 _ = try func.addInst(.{
1223 .tag = .vsetivli,1176 .tag = .vsetivli,
1224 .ops = .rri,
1225 .data = .{1177 .data = .{
1226 .i_type = .{1178 .i_type = .{
1227 .rd = dst_reg,1179 .rd = dst_reg,
...@@ -1235,7 +1187,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {...@@ -1235,7 +1187,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void {
1235 const temp_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = avl });1187 const temp_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = avl });
1236 _ = try func.addInst(.{1188 _ = try func.addInst(.{
1237 .tag = .vsetvli,1189 .tag = .vsetvli,
1238 .ops = .rri,
1239 .data = .{ .i_type = .{1190 .data = .{ .i_type = .{
1240 .rd = dst_reg,1191 .rd = dst_reg,
1241 .rs1 = temp_reg,1192 .rs1 = temp_reg,
...@@ -1270,7 +1221,7 @@ fn gen(func: *Func) !void {...@@ -1270,7 +1221,7 @@ fn gen(func: *Func) !void {
1270 }1221 }
12711222
1272 if (fn_info.cc != .Naked) {1223 if (fn_info.cc != .Naked) {
1273 try func.addPseudoNone(.pseudo_dbg_prologue_end);1224 _ = try func.addPseudo(.pseudo_dbg_prologue_end);
12741225
1275 const backpatch_stack_alloc = try func.addPseudo(.pseudo_dead);1226 const backpatch_stack_alloc = try func.addPseudo(.pseudo_dead);
1276 const backpatch_ra_spill = try func.addPseudo(.pseudo_dead);1227 const backpatch_ra_spill = try func.addPseudo(.pseudo_dead);
...@@ -1300,11 +1251,11 @@ fn gen(func: *Func) !void {...@@ -1300,11 +1251,11 @@ fn gen(func: *Func) !void {
1300 try func.genBody(func.air.getMainBody());1251 try func.genBody(func.air.getMainBody());
13011252
1302 for (func.exitlude_jump_relocs.items) |jmp_reloc| {1253 for (func.exitlude_jump_relocs.items) |jmp_reloc| {
1303 func.mir_instructions.items(.data)[jmp_reloc].inst =1254 func.mir_instructions.items(.data)[jmp_reloc].j_type.inst =
1304 @intCast(func.mir_instructions.len);1255 @intCast(func.mir_instructions.len);
1305 }1256 }
13061257
1307 try func.addPseudoNone(.pseudo_dbg_epilogue_begin);1258 _ = try func.addPseudo(.pseudo_dbg_epilogue_begin);
13081259
1309 const backpatch_restore_callee_preserved_regs = try func.addPseudo(.pseudo_dead);1260 const backpatch_restore_callee_preserved_regs = try func.addPseudo(.pseudo_dead);
1310 const backpatch_ra_restore = try func.addPseudo(.pseudo_dead);1261 const backpatch_ra_restore = try func.addPseudo(.pseudo_dead);
...@@ -1314,7 +1265,6 @@ fn gen(func: *Func) !void {...@@ -1314,7 +1265,6 @@ fn gen(func: *Func) !void {
1314 // ret1265 // ret
1315 _ = try func.addInst(.{1266 _ = try func.addInst(.{
1316 .tag = .jalr,1267 .tag = .jalr,
1317 .ops = .rri,
1318 .data = .{1268 .data = .{
1319 .i_type = .{1269 .i_type = .{
1320 .rd = .zero,1270 .rd = .zero,
...@@ -1329,7 +1279,6 @@ fn gen(func: *Func) !void {...@@ -1329,7 +1279,6 @@ fn gen(func: *Func) !void {
13291279
1330 func.mir_instructions.set(backpatch_stack_alloc, .{1280 func.mir_instructions.set(backpatch_stack_alloc, .{
1331 .tag = .addi,1281 .tag = .addi,
1332 .ops = .rri,
1333 .data = .{ .i_type = .{1282 .data = .{ .i_type = .{
1334 .rd = .sp,1283 .rd = .sp,
1335 .rs1 = .sp,1284 .rs1 = .sp,
...@@ -1337,8 +1286,7 @@ fn gen(func: *Func) !void {...@@ -1337,8 +1286,7 @@ fn gen(func: *Func) !void {
1337 } },1286 } },
1338 });1287 });
1339 func.mir_instructions.set(backpatch_ra_spill, .{1288 func.mir_instructions.set(backpatch_ra_spill, .{
1340 .tag = .pseudo,1289 .tag = .pseudo_store_rm,
1341 .ops = .pseudo_store_rm,
1342 .data = .{ .rm = .{1290 .data = .{ .rm = .{
1343 .r = .ra,1291 .r = .ra,
1344 .m = .{1292 .m = .{
...@@ -1348,8 +1296,7 @@ fn gen(func: *Func) !void {...@@ -1348,8 +1296,7 @@ fn gen(func: *Func) !void {
1348 } },1296 } },
1349 });1297 });
1350 func.mir_instructions.set(backpatch_ra_restore, .{1298 func.mir_instructions.set(backpatch_ra_restore, .{
1351 .tag = .pseudo,1299 .tag = .pseudo_load_rm,
1352 .ops = .pseudo_load_rm,
1353 .data = .{ .rm = .{1300 .data = .{ .rm = .{
1354 .r = .ra,1301 .r = .ra,
1355 .m = .{1302 .m = .{
...@@ -1359,8 +1306,7 @@ fn gen(func: *Func) !void {...@@ -1359,8 +1306,7 @@ fn gen(func: *Func) !void {
1359 } },1306 } },
1360 });1307 });
1361 func.mir_instructions.set(backpatch_fp_spill, .{1308 func.mir_instructions.set(backpatch_fp_spill, .{
1362 .tag = .pseudo,1309 .tag = .pseudo_store_rm,
1363 .ops = .pseudo_store_rm,
1364 .data = .{ .rm = .{1310 .data = .{ .rm = .{
1365 .r = .s0,1311 .r = .s0,
1366 .m = .{1312 .m = .{
...@@ -1370,8 +1316,7 @@ fn gen(func: *Func) !void {...@@ -1370,8 +1316,7 @@ fn gen(func: *Func) !void {
1370 } },1316 } },
1371 });1317 });
1372 func.mir_instructions.set(backpatch_fp_restore, .{1318 func.mir_instructions.set(backpatch_fp_restore, .{
1373 .tag = .pseudo,1319 .tag = .pseudo_load_rm,
1374 .ops = .pseudo_load_rm,
1375 .data = .{ .rm = .{1320 .data = .{ .rm = .{
1376 .r = .s0,1321 .r = .s0,
1377 .m = .{1322 .m = .{
...@@ -1382,7 +1327,6 @@ fn gen(func: *Func) !void {...@@ -1382,7 +1327,6 @@ fn gen(func: *Func) !void {
1382 });1327 });
1383 func.mir_instructions.set(backpatch_fp_add, .{1328 func.mir_instructions.set(backpatch_fp_add, .{
1384 .tag = .addi,1329 .tag = .addi,
1385 .ops = .rri,
1386 .data = .{ .i_type = .{1330 .data = .{ .i_type = .{
1387 .rd = .s0,1331 .rd = .s0,
1388 .rs1 = .sp,1332 .rs1 = .sp,
...@@ -1391,7 +1335,6 @@ fn gen(func: *Func) !void {...@@ -1391,7 +1335,6 @@ fn gen(func: *Func) !void {
1391 });1335 });
1392 func.mir_instructions.set(backpatch_stack_alloc_restore, .{1336 func.mir_instructions.set(backpatch_stack_alloc_restore, .{
1393 .tag = .addi,1337 .tag = .addi,
1394 .ops = .rri,
1395 .data = .{ .i_type = .{1338 .data = .{ .i_type = .{
1396 .rd = .sp,1339 .rd = .sp,
1397 .rs1 = .sp,1340 .rs1 = .sp,
...@@ -1401,27 +1344,24 @@ fn gen(func: *Func) !void {...@@ -1401,27 +1344,24 @@ fn gen(func: *Func) !void {
14011344
1402 if (need_save_reg) {1345 if (need_save_reg) {
1403 func.mir_instructions.set(backpatch_spill_callee_preserved_regs, .{1346 func.mir_instructions.set(backpatch_spill_callee_preserved_regs, .{
1404 .tag = .pseudo,1347 .tag = .pseudo_spill_regs,
1405 .ops = .pseudo_spill_regs,
1406 .data = .{ .reg_list = frame_layout.save_reg_list },1348 .data = .{ .reg_list = frame_layout.save_reg_list },
1407 });1349 });
14081350
1409 func.mir_instructions.set(backpatch_restore_callee_preserved_regs, .{1351 func.mir_instructions.set(backpatch_restore_callee_preserved_regs, .{
1410 .tag = .pseudo,1352 .tag = .pseudo_restore_regs,
1411 .ops = .pseudo_restore_regs,
1412 .data = .{ .reg_list = frame_layout.save_reg_list },1353 .data = .{ .reg_list = frame_layout.save_reg_list },
1413 });1354 });
1414 }1355 }
1415 } else {1356 } else {
1416 try func.addPseudoNone(.pseudo_dbg_prologue_end);1357 _ = try func.addPseudo(.pseudo_dbg_prologue_end);
1417 try func.genBody(func.air.getMainBody());1358 try func.genBody(func.air.getMainBody());
1418 try func.addPseudoNone(.pseudo_dbg_epilogue_begin);1359 _ = try func.addPseudo(.pseudo_dbg_epilogue_begin);
1419 }1360 }
14201361
1421 // Drop them off at the rbrace.1362 // Drop them off at the rbrace.
1422 _ = try func.addInst(.{1363 _ = try func.addInst(.{
1423 .tag = .pseudo,1364 .tag = .pseudo_dbg_line_column,
1424 .ops = .pseudo_dbg_line_column,
1425 .data = .{ .pseudo_dbg_line_column = .{1365 .data = .{ .pseudo_dbg_line_column = .{
1426 .line = func.end_di_line,1366 .line = func.end_di_line,
1427 .column = func.end_di_column,1367 .column = func.end_di_column,
...@@ -1493,9 +1433,11 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -1493,9 +1433,11 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
1493 );1433 );
14941434
1495 exitlude_jump_reloc.* = try func.addInst(.{1435 exitlude_jump_reloc.* = try func.addInst(.{
1496 .tag = .pseudo,1436 .tag = .pseudo_j,
1497 .ops = .pseudo_j,1437 .data = .{ .j_type = .{
1498 .data = .{ .inst = undefined },1438 .rd = .zero,
1439 .inst = undefined,
1440 } },
1499 });1441 });
1500 func.performReloc(skip_reloc);1442 func.performReloc(skip_reloc);
15011443
...@@ -1508,7 +1450,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {...@@ -1508,7 +1450,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void {
15081450
1509 _ = try func.addInst(.{1451 _ = try func.addInst(.{
1510 .tag = .jalr,1452 .tag = .jalr,
1511 .ops = .rri,1453
1512 .data = .{1454 .data = .{
1513 .i_type = .{1455 .i_type = .{
1514 .rd = .zero,1456 .rd = .zero,
...@@ -2041,7 +1983,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {...@@ -2041,7 +1983,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
2041 .signed => {1983 .signed => {
2042 _ = try func.addInst(.{1984 _ = try func.addInst(.{
2043 .tag = .slli,1985 .tag = .slli,
2044 .ops = .rri,1986
2045 .data = .{1987 .data = .{
2046 .i_type = .{1988 .i_type = .{
2047 .rd = reg,1989 .rd = reg,
...@@ -2052,7 +1994,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {...@@ -2052,7 +1994,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
2052 });1994 });
2053 _ = try func.addInst(.{1995 _ = try func.addInst(.{
2054 .tag = .srai,1996 .tag = .srai,
2055 .ops = .rri,1997
2056 .data = .{1998 .data = .{
2057 .i_type = .{1999 .i_type = .{
2058 .rd = reg,2000 .rd = reg,
...@@ -2067,7 +2009,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {...@@ -2067,7 +2009,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
2067 if (mask < 256) {2009 if (mask < 256) {
2068 _ = try func.addInst(.{2010 _ = try func.addInst(.{
2069 .tag = .andi,2011 .tag = .andi,
2070 .ops = .rri,2012
2071 .data = .{2013 .data = .{
2072 .i_type = .{2014 .i_type = .{
2073 .rd = reg,2015 .rd = reg,
...@@ -2079,7 +2021,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {...@@ -2079,7 +2021,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
2079 } else {2021 } else {
2080 _ = try func.addInst(.{2022 _ = try func.addInst(.{
2081 .tag = .slli,2023 .tag = .slli,
2082 .ops = .rri,2024
2083 .data = .{2025 .data = .{
2084 .i_type = .{2026 .i_type = .{
2085 .rd = reg,2027 .rd = reg,
...@@ -2090,7 +2032,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {...@@ -2090,7 +2032,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void {
2090 });2032 });
2091 _ = try func.addInst(.{2033 _ = try func.addInst(.{
2092 .tag = .srli,2034 .tag = .srli,
2093 .ops = .rri,2035
2094 .data = .{2036 .data = .{
2095 .i_type = .{2037 .i_type = .{
2096 .rd = reg,2038 .rd = reg,
...@@ -2411,8 +2353,7 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {...@@ -2411,8 +2353,7 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
2411 switch (ty.zigTypeTag(zcu)) {2353 switch (ty.zigTypeTag(zcu)) {
2412 .Bool => {2354 .Bool => {
2413 _ = try func.addInst(.{2355 _ = try func.addInst(.{
2414 .tag = .pseudo,2356 .tag = .pseudo_not,
2415 .ops = .pseudo_not,
2416 .data = .{2357 .data = .{
2417 .rr = .{2358 .rr = .{
2418 .rs = operand_reg,2359 .rs = operand_reg,
...@@ -2430,7 +2371,6 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {...@@ -2430,7 +2371,6 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void {
2430 32, 64 => {2371 32, 64 => {
2431 _ = try func.addInst(.{2372 _ = try func.addInst(.{
2432 .tag = .xori,2373 .tag = .xori,
2433 .ops = .rri,
2434 .data = .{2374 .data = .{
2435 .i_type = .{2375 .i_type = .{
2436 .rd = dst_reg,2376 .rd = dst_reg,
...@@ -2628,7 +2568,7 @@ fn genBinOp(...@@ -2628,7 +2568,7 @@ fn genBinOp(
26282568
2629 switch (lhs_ty.zigTypeTag(zcu)) {2569 switch (lhs_ty.zigTypeTag(zcu)) {
2630 .Int => {2570 .Int => {
2631 const mir_tag: Mir.Inst.Tag = switch (tag) {2571 const mnem: Mnemonic = switch (tag) {
2632 .add, .add_wrap => switch (bit_size) {2572 .add, .add_wrap => switch (bit_size) {
2633 8, 16, 64 => .add,2573 8, 16, 64 => .add,
2634 32 => .addw,2574 32 => .addw,
...@@ -2656,8 +2596,7 @@ fn genBinOp(...@@ -2656,8 +2596,7 @@ fn genBinOp(
2656 };2596 };
26572597
2658 _ = try func.addInst(.{2598 _ = try func.addInst(.{
2659 .tag = mir_tag,2599 .tag = mnem,
2660 .ops = .rrr,
2661 .data = .{2600 .data = .{
2662 .r_type = .{2601 .r_type = .{
2663 .rd = dst_reg,2602 .rd = dst_reg,
...@@ -2668,7 +2607,7 @@ fn genBinOp(...@@ -2668,7 +2607,7 @@ fn genBinOp(
2668 });2607 });
2669 },2608 },
2670 .Float => {2609 .Float => {
2671 const mir_tag: Mir.Inst.Tag = switch (tag) {2610 const mir_tag: Mnemonic = switch (tag) {
2672 .add => switch (bit_size) {2611 .add => switch (bit_size) {
2673 32 => .fadds,2612 32 => .fadds,
2674 64 => .faddd,2613 64 => .faddd,
...@@ -2689,7 +2628,6 @@ fn genBinOp(...@@ -2689,7 +2628,6 @@ fn genBinOp(
26892628
2690 _ = try func.addInst(.{2629 _ = try func.addInst(.{
2691 .tag = mir_tag,2630 .tag = mir_tag,
2692 .ops = .rrr,
2693 .data = .{2631 .data = .{
2694 .r_type = .{2632 .r_type = .{
2695 .rd = dst_reg,2633 .rd = dst_reg,
...@@ -2705,7 +2643,7 @@ fn genBinOp(...@@ -2705,7 +2643,7 @@ fn genBinOp(
27052643
2706 const child_ty = lhs_ty.childType(zcu);2644 const child_ty = lhs_ty.childType(zcu);
27072645
2708 const mir_tag: Mir.Inst.Tag = switch (tag) {2646 const mir_tag: Mnemonic = switch (tag) {
2709 .add => switch (child_ty.zigTypeTag(zcu)) {2647 .add => switch (child_ty.zigTypeTag(zcu)) {
2710 .Int => .vaddvv,2648 .Int => .vaddvv,
2711 .Float => .vfaddvv,2649 .Float => .vfaddvv,
...@@ -2739,7 +2677,6 @@ fn genBinOp(...@@ -2739,7 +2677,6 @@ fn genBinOp(
27392677
2740 _ = try func.addInst(.{2678 _ = try func.addInst(.{
2741 .tag = mir_tag,2679 .tag = mir_tag,
2742 .ops = .rrr,
2743 .data = .{2680 .data = .{
2744 .r_type = .{2681 .r_type = .{
2745 .rd = dst_reg,2682 .rd = dst_reg,
...@@ -2764,7 +2701,6 @@ fn genBinOp(...@@ -2764,7 +2701,6 @@ fn genBinOp(
27642701
2765 _ = try func.addInst(.{2702 _ = try func.addInst(.{
2766 .tag = .add,2703 .tag = .add,
2767 .ops = .rrr,
2768 .data = .{ .r_type = .{2704 .data = .{ .r_type = .{
2769 .rd = tmp_reg,2705 .rd = tmp_reg,
2770 .rs1 = rhs_reg,2706 .rs1 = rhs_reg,
...@@ -2774,7 +2710,6 @@ fn genBinOp(...@@ -2774,7 +2710,6 @@ fn genBinOp(
27742710
2775 _ = try func.addInst(.{2711 _ = try func.addInst(.{
2776 .tag = .sltu,2712 .tag = .sltu,
2777 .ops = .rrr,
2778 .data = .{ .r_type = .{2713 .data = .{ .r_type = .{
2779 .rd = dst_reg,2714 .rd = dst_reg,
2780 .rs1 = tmp_reg,2715 .rs1 = tmp_reg,
...@@ -2785,7 +2720,6 @@ fn genBinOp(...@@ -2785,7 +2720,6 @@ fn genBinOp(
2785 // neg dst_reg, dst_reg2720 // neg dst_reg, dst_reg
2786 _ = try func.addInst(.{2721 _ = try func.addInst(.{
2787 .tag = .sub,2722 .tag = .sub,
2788 .ops = .rrr,
2789 .data = .{ .r_type = .{2723 .data = .{ .r_type = .{
2790 .rd = dst_reg,2724 .rd = dst_reg,
2791 .rs1 = .zero,2725 .rs1 = .zero,
...@@ -2795,7 +2729,6 @@ fn genBinOp(...@@ -2795,7 +2729,6 @@ fn genBinOp(
27952729
2796 _ = try func.addInst(.{2730 _ = try func.addInst(.{
2797 .tag = .@"or",2731 .tag = .@"or",
2798 .ops = .rrr,
2799 .data = .{ .r_type = .{2732 .data = .{ .r_type = .{
2800 .rd = dst_reg,2733 .rd = dst_reg,
2801 .rs1 = dst_reg,2734 .rs1 = dst_reg,
...@@ -2850,7 +2783,6 @@ fn genBinOp(...@@ -2850,7 +2783,6 @@ fn genBinOp(
2850 .bit_or, .bool_or => .@"or",2783 .bit_or, .bool_or => .@"or",
2851 else => unreachable,2784 else => unreachable,
2852 },2785 },
2853 .ops = .rrr,
2854 .data = .{2786 .data = .{
2855 .r_type = .{2787 .r_type = .{
2856 .rd = dst_reg,2788 .rd = dst_reg,
...@@ -2876,7 +2808,7 @@ fn genBinOp(...@@ -2876,7 +2808,7 @@ fn genBinOp(
2876 if (bit_size > 64) return func.fail("TODO: genBinOp shift > 64 bits, {}", .{bit_size});2808 if (bit_size > 64) return func.fail("TODO: genBinOp shift > 64 bits, {}", .{bit_size});
2877 try func.truncateRegister(rhs_ty, rhs_reg);2809 try func.truncateRegister(rhs_ty, rhs_reg);
28782810
2879 const mir_tag: Mir.Inst.Tag = switch (tag) {2811 const mir_tag: Mnemonic = switch (tag) {
2880 .shl, .shl_exact => switch (bit_size) {2812 .shl, .shl_exact => switch (bit_size) {
2881 1...31, 33...64 => .sll,2813 1...31, 33...64 => .sll,
2882 32 => .sllw,2814 32 => .sllw,
...@@ -2892,7 +2824,6 @@ fn genBinOp(...@@ -2892,7 +2824,6 @@ fn genBinOp(
28922824
2893 _ = try func.addInst(.{2825 _ = try func.addInst(.{
2894 .tag = mir_tag,2826 .tag = mir_tag,
2895 .ops = .rrr,
2896 .data = .{ .r_type = .{2827 .data = .{ .r_type = .{
2897 .rd = dst_reg,2828 .rd = dst_reg,
2898 .rs1 = lhs_reg,2829 .rs1 = lhs_reg,
...@@ -2910,8 +2841,7 @@ fn genBinOp(...@@ -2910,8 +2841,7 @@ fn genBinOp(
2910 .cmp_gte,2841 .cmp_gte,
2911 => {2842 => {
2912 _ = try func.addInst(.{2843 _ = try func.addInst(.{
2913 .tag = .pseudo,2844 .tag = .pseudo_compare,
2914 .ops = .pseudo_compare,
2915 .data = .{2845 .data = .{
2916 .compare = .{2846 .compare = .{
2917 .op = switch (tag) {2847 .op = switch (tag) {
...@@ -2966,7 +2896,6 @@ fn genBinOp(...@@ -2966,7 +2896,6 @@ fn genBinOp(
29662896
2967 _ = try func.addInst(.{2897 _ = try func.addInst(.{
2968 .tag = if (int_info.signedness == .unsigned) .sltu else .slt,2898 .tag = if (int_info.signedness == .unsigned) .sltu else .slt,
2969 .ops = .rrr,
2970 .data = .{ .r_type = .{2899 .data = .{ .r_type = .{
2971 .rd = mask_reg,2900 .rd = mask_reg,
2972 .rs1 = lhs_reg,2901 .rs1 = lhs_reg,
...@@ -2976,7 +2905,6 @@ fn genBinOp(...@@ -2976,7 +2905,6 @@ fn genBinOp(
29762905
2977 _ = try func.addInst(.{2906 _ = try func.addInst(.{
2978 .tag = .sub,2907 .tag = .sub,
2979 .ops = .rrr,
2980 .data = .{ .r_type = .{2908 .data = .{ .r_type = .{
2981 .rd = mask_reg,2909 .rd = mask_reg,
2982 .rs1 = .zero,2910 .rs1 = .zero,
...@@ -2986,7 +2914,6 @@ fn genBinOp(...@@ -2986,7 +2914,6 @@ fn genBinOp(
29862914
2987 _ = try func.addInst(.{2915 _ = try func.addInst(.{
2988 .tag = .xor,2916 .tag = .xor,
2989 .ops = .rrr,
2990 .data = .{ .r_type = .{2917 .data = .{ .r_type = .{
2991 .rd = dst_reg,2918 .rd = dst_reg,
2992 .rs1 = lhs_reg,2919 .rs1 = lhs_reg,
...@@ -2996,7 +2923,6 @@ fn genBinOp(...@@ -2996,7 +2923,6 @@ fn genBinOp(
29962923
2997 _ = try func.addInst(.{2924 _ = try func.addInst(.{
2998 .tag = .@"and",2925 .tag = .@"and",
2999 .ops = .rrr,
3000 .data = .{ .r_type = .{2926 .data = .{ .r_type = .{
3001 .rd = mask_reg,2927 .rd = mask_reg,
3002 .rs1 = dst_reg,2928 .rs1 = dst_reg,
...@@ -3006,7 +2932,6 @@ fn genBinOp(...@@ -3006,7 +2932,6 @@ fn genBinOp(
30062932
3007 _ = try func.addInst(.{2933 _ = try func.addInst(.{
3008 .tag = .xor,2934 .tag = .xor,
3009 .ops = .rrr,
3010 .data = .{ .r_type = .{2935 .data = .{ .r_type = .{
3011 .rd = dst_reg,2936 .rd = dst_reg,
3012 .rs1 = if (tag == .min) rhs_reg else lhs_reg,2937 .rs1 = if (tag == .min) rhs_reg else lhs_reg,
...@@ -3103,7 +3028,6 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {...@@ -3103,7 +3028,6 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
31033028
3104 _ = try func.addInst(.{3029 _ = try func.addInst(.{
3105 .tag = .add,3030 .tag = .add,
3106 .ops = .rrr,
3107 .data = .{ .r_type = .{3031 .data = .{ .r_type = .{
3108 .rs1 = rhs_reg,3032 .rs1 = rhs_reg,
3109 .rs2 = lhs_reg,3033 .rs2 = lhs_reg,
...@@ -3209,7 +3133,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {...@@ -3209,7 +3133,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
3209 .unsigned => {3133 .unsigned => {
3210 _ = try func.addInst(.{3134 _ = try func.addInst(.{
3211 .tag = .sltu,3135 .tag = .sltu,
3212 .ops = .rrr,
3213 .data = .{ .r_type = .{3136 .data = .{ .r_type = .{
3214 .rd = overflow_reg,3137 .rd = overflow_reg,
3215 .rs1 = lhs_reg,3138 .rs1 = lhs_reg,
...@@ -3231,7 +3154,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {...@@ -3231,7 +3154,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
3231 64 => {3154 64 => {
3232 _ = try func.addInst(.{3155 _ = try func.addInst(.{
3233 .tag = .slt,3156 .tag = .slt,
3234 .ops = .rrr,
3235 .data = .{ .r_type = .{3157 .data = .{ .r_type = .{
3236 .rd = overflow_reg,3158 .rd = overflow_reg,
3237 .rs1 = overflow_reg,3159 .rs1 = overflow_reg,
...@@ -3241,7 +3163,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {...@@ -3241,7 +3163,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
32413163
3242 _ = try func.addInst(.{3164 _ = try func.addInst(.{
3243 .tag = .slt,3165 .tag = .slt,
3244 .ops = .rrr,
3245 .data = .{ .r_type = .{3166 .data = .{ .r_type = .{
3246 .rd = rhs_reg,3167 .rd = rhs_reg,
3247 .rs1 = rhs_reg,3168 .rs1 = rhs_reg,
...@@ -3251,7 +3172,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {...@@ -3251,7 +3172,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void {
32513172
3252 _ = try func.addInst(.{3173 _ = try func.addInst(.{
3253 .tag = .xor,3174 .tag = .xor,
3254 .ops = .rrr,
3255 .data = .{ .r_type = .{3175 .data = .{ .r_type = .{
3256 .rd = lhs_reg,3176 .rd = lhs_reg,
3257 .rs1 = overflow_reg,3177 .rs1 = overflow_reg,
...@@ -3843,7 +3763,6 @@ fn genSliceElemPtr(func: *Func, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {...@@ -3843,7 +3763,6 @@ fn genSliceElemPtr(func: *Func, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue {
38433763
3844 _ = try func.addInst(.{3764 _ = try func.addInst(.{
3845 .tag = .add,3765 .tag = .add,
3846 .ops = .rrr,
3847 .data = .{ .r_type = .{3766 .data = .{ .r_type = .{
3848 .rd = addr_reg,3767 .rd = addr_reg,
3849 .rs1 = addr_reg,3768 .rs1 = addr_reg,
...@@ -3907,7 +3826,6 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -3907,7 +3826,6 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
39073826
3908 _ = try func.addInst(.{3827 _ = try func.addInst(.{
3909 .tag = .vslidedownvx,3828 .tag = .vslidedownvx,
3910 .ops = .rrr,
3911 .data = .{ .r_type = .{3829 .data = .{ .r_type = .{
3912 .rd = src_reg,3830 .rd = src_reg,
3913 .rs1 = index_reg,3831 .rs1 = index_reg,
...@@ -3925,7 +3843,6 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -3925,7 +3843,6 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void {
3925 defer func.register_manager.unlockReg(offset_lock);3843 defer func.register_manager.unlockReg(offset_lock);
3926 _ = try func.addInst(.{3844 _ = try func.addInst(.{
3927 .tag = .add,3845 .tag = .add,
3928 .ops = .rrr,
3929 .data = .{ .r_type = .{3846 .data = .{ .r_type = .{
3930 .rd = addr_reg,3847 .rd = addr_reg,
3931 .rs1 = addr_reg,3848 .rs1 = addr_reg,
...@@ -4080,7 +3997,6 @@ fn airClz(func: *Func, inst: Air.Inst.Index) !void {...@@ -4080,7 +3997,6 @@ fn airClz(func: *Func, inst: Air.Inst.Index) !void {
4080 32 => .clzw,3997 32 => .clzw,
4081 else => .clz,3998 else => .clz,
4082 },3999 },
4083 .ops = .rrr,
4084 .data = .{4000 .data = .{
4085 .r_type = .{4001 .r_type = .{
4086 .rs2 = .zero, // rs2 is 0 filled in the spec4002 .rs2 = .zero, // rs2 is 0 filled in the spec
...@@ -4093,7 +4009,6 @@ fn airClz(func: *Func, inst: Air.Inst.Index) !void {...@@ -4093,7 +4009,6 @@ fn airClz(func: *Func, inst: Air.Inst.Index) !void {
4093 if (!(bit_size == 32 or bit_size == 64)) {4009 if (!(bit_size == 32 or bit_size == 64)) {
4094 _ = try func.addInst(.{4010 _ = try func.addInst(.{
4095 .tag = .addi,4011 .tag = .addi,
4096 .ops = .rri,
4097 .data = .{ .i_type = .{4012 .data = .{ .i_type = .{
4098 .rd = dst_reg,4013 .rd = dst_reg,
4099 .rs1 = dst_reg,4014 .rs1 = dst_reg,
...@@ -4151,7 +4066,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {...@@ -4151,7 +4066,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
4151 64 => .srai,4066 64 => .srai,
4152 else => unreachable,4067 else => unreachable,
4153 },4068 },
4154 .ops = .rri,
4155 .data = .{ .i_type = .{4069 .data = .{ .i_type = .{
4156 .rd = temp_reg,4070 .rd = temp_reg,
4157 .rs1 = operand_reg,4071 .rs1 = operand_reg,
...@@ -4161,7 +4075,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {...@@ -4161,7 +4075,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
41614075
4162 _ = try func.addInst(.{4076 _ = try func.addInst(.{
4163 .tag = .xor,4077 .tag = .xor,
4164 .ops = .rrr,
4165 .data = .{ .r_type = .{4078 .data = .{ .r_type = .{
4166 .rd = operand_reg,4079 .rd = operand_reg,
4167 .rs1 = operand_reg,4080 .rs1 = operand_reg,
...@@ -4175,7 +4088,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {...@@ -4175,7 +4088,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
4175 64 => .sub,4088 64 => .sub,
4176 else => unreachable,4089 else => unreachable,
4177 },4090 },
4178 .ops = .rrr,
4179 .data = .{ .r_type = .{4091 .data = .{ .r_type = .{
4180 .rd = operand_reg,4092 .rd = operand_reg,
4181 .rs1 = operand_reg,4093 .rs1 = operand_reg,
...@@ -4187,14 +4099,14 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {...@@ -4187,14 +4099,14 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
4187 },4099 },
4188 .Float => {4100 .Float => {
4189 const float_bits = scalar_ty.floatBits(zcu.getTarget());4101 const float_bits = scalar_ty.floatBits(zcu.getTarget());
4190 switch (float_bits) {4102 const mnem: Mnemonic = switch (float_bits) {
4191 16 => return func.fail("TODO: airAbs 16-bit float", .{}),4103 16 => return func.fail("TODO: airAbs 16-bit float", .{}),
4192 32 => {},4104 32 => .fsgnjxs,
4193 64 => {},4105 64 => .fsgnjxd,
4194 80 => return func.fail("TODO: airAbs 80-bit float", .{}),4106 80 => return func.fail("TODO: airAbs 80-bit float", .{}),
4195 128 => return func.fail("TODO: airAbs 128-bit float", .{}),4107 128 => return func.fail("TODO: airAbs 128-bit float", .{}),
4196 else => unreachable,4108 else => unreachable,
4197 }4109 };
41984110
4199 const return_mcv = try func.copyToNewRegister(inst, operand);4111 const return_mcv = try func.copyToNewRegister(inst, operand);
4200 const operand_reg = return_mcv.register;4112 const operand_reg = return_mcv.register;
...@@ -4202,13 +4114,12 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {...@@ -4202,13 +4114,12 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void {
4202 assert(operand_reg.class() == .float);4114 assert(operand_reg.class() == .float);
42034115
4204 _ = try func.addInst(.{4116 _ = try func.addInst(.{
4205 .tag = .pseudo,4117 .tag = mnem,
4206 .ops = .pseudo_fabs,
4207 .data = .{4118 .data = .{
4208 .fabs = .{4119 .r_type = .{
4209 .rd = operand_reg,4120 .rd = operand_reg,
4210 .rs = operand_reg,4121 .rs1 = operand_reg,
4211 .bits = float_bits,4122 .rs2 = operand_reg,
4212 },4123 },
4213 },4124 },
4214 });4125 });
...@@ -4231,54 +4142,56 @@ fn airByteSwap(func: *Func, inst: Air.Inst.Index) !void {...@@ -4231,54 +4142,56 @@ fn airByteSwap(func: *Func, inst: Air.Inst.Index) !void {
4231 const ty = func.typeOf(ty_op.operand);4142 const ty = func.typeOf(ty_op.operand);
4232 const operand = try func.resolveInst(ty_op.operand);4143 const operand = try func.resolveInst(ty_op.operand);
42334144
4234 const int_bits = ty.intInfo(zcu).bits;4145 switch (ty.zigTypeTag(zcu)) {
4146 .Int => {
4147 const int_bits = ty.intInfo(zcu).bits;
42354148
4236 // bytes are no-op4149 // bytes are no-op
4237 if (int_bits == 8 and func.reuseOperand(inst, ty_op.operand, 0, operand)) {4150 if (int_bits == 8 and func.reuseOperand(inst, ty_op.operand, 0, operand)) {
4238 return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none });4151 return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none });
4239 }4152 }
42404153
4241 const dest_mcv = try func.copyToNewRegister(inst, operand);4154 const dest_mcv = try func.copyToNewRegister(inst, operand);
4242 const dest_reg = dest_mcv.register;4155 const dest_reg = dest_mcv.register;
42434156
4244 switch (int_bits) {4157 switch (int_bits) {
4245 16 => {4158 16 => {
4246 const temp_reg, const temp_lock = try func.allocReg(.int);4159 const temp_reg, const temp_lock = try func.allocReg(.int);
4247 defer func.register_manager.unlockReg(temp_lock);4160 defer func.register_manager.unlockReg(temp_lock);
42484161
4249 _ = try func.addInst(.{4162 _ = try func.addInst(.{
4250 .tag = .srli,4163 .tag = .srli,
4251 .ops = .rri,4164 .data = .{ .i_type = .{
4252 .data = .{ .i_type = .{4165 .imm12 = Immediate.s(8),
4253 .imm12 = Immediate.s(8),4166 .rd = temp_reg,
4254 .rd = temp_reg,4167 .rs1 = dest_reg,
4255 .rs1 = dest_reg,4168 } },
4256 } },4169 });
4257 });
42584170
4259 _ = try func.addInst(.{4171 _ = try func.addInst(.{
4260 .tag = .slli,4172 .tag = .slli,
4261 .ops = .rri,4173 .data = .{ .i_type = .{
4262 .data = .{ .i_type = .{4174 .imm12 = Immediate.s(8),
4263 .imm12 = Immediate.s(8),4175 .rd = dest_reg,
4264 .rd = dest_reg,4176 .rs1 = dest_reg,
4265 .rs1 = dest_reg,4177 } },
4266 } },4178 });
4267 });4179 _ = try func.addInst(.{
4268 _ = try func.addInst(.{4180 .tag = .@"or",
4269 .tag = .@"or",4181 .data = .{ .r_type = .{
4270 .ops = .rri,4182 .rd = dest_reg,
4271 .data = .{ .r_type = .{4183 .rs1 = dest_reg,
4272 .rd = dest_reg,4184 .rs2 = temp_reg,
4273 .rs1 = dest_reg,4185 } },
4274 .rs2 = temp_reg,4186 });
4275 } },4187 },
4276 });4188 else => return func.fail("TODO: {d} bits for airByteSwap", .{int_bits}),
4189 }
4190
4191 break :result dest_mcv;
4277 },4192 },
4278 else => return func.fail("TODO: {d} bits for airByteSwap", .{int_bits}),4193 else => return func.fail("TODO: airByteSwap {}", .{ty.fmt(pt)}),
4279 }4194 }
4280
4281 break :result dest_mcv;
4282 };4195 };
4283 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });4196 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
4284}4197}
...@@ -4322,7 +4235,6 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -4322,7 +4235,6 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
4322 .sqrt => {4235 .sqrt => {
4323 _ = try func.addInst(.{4236 _ = try func.addInst(.{
4324 .tag = if (operand_bit_size == 64) .fsqrtd else .fsqrts,4237 .tag = if (operand_bit_size == 64) .fsqrtd else .fsqrts,
4325 .ops = .rrr,
4326 .data = .{4238 .data = .{
4327 .r_type = .{4239 .r_type = .{
4328 .rd = dst_reg,4240 .rd = dst_reg,
...@@ -4332,6 +4244,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {...@@ -4332,6 +4244,7 @@ fn airUnaryMath(func: *Func, inst: Air.Inst.Index, tag: Air.Inst.Tag) !void {
4332 },4244 },
4333 });4245 });
4334 },4246 },
4247
4335 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),4248 else => return func.fail("TODO: airUnaryMath Float {s}", .{@tagName(tag)}),
4336 }4249 }
4337 },4250 },
...@@ -4538,17 +4451,14 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde...@@ -4538,17 +4451,14 @@ fn structFieldPtr(func: *Func, inst: Air.Inst.Index, operand: Air.Inst.Ref, inde
4538 const zcu = pt.zcu;4451 const zcu = pt.zcu;
4539 const ptr_field_ty = func.typeOfIndex(inst);4452 const ptr_field_ty = func.typeOfIndex(inst);
4540 const ptr_container_ty = func.typeOf(operand);4453 const ptr_container_ty = func.typeOf(operand);
4541 const ptr_container_ty_info = ptr_container_ty.ptrInfo(zcu);
4542 const container_ty = ptr_container_ty.childType(zcu);4454 const container_ty = ptr_container_ty.childType(zcu);
45434455
4544 const field_offset: i32 = if (zcu.typeToPackedStruct(container_ty)) |struct_obj|4456 const field_offset: i32 = switch (container_ty.containerLayout(zcu)) {
4545 if (ptr_field_ty.ptrInfo(zcu).packed_offset.host_size == 0)4457 .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, pt)),
4546 @divExact(pt.structPackedFieldBitOffset(struct_obj, index) +4458 .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) +
4547 ptr_container_ty_info.packed_offset.bit_offset, 8)4459 (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) -
4548 else4460 ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8),
4549 04461 };
4550 else
4551 @intCast(container_ty.structFieldOffset(index, pt));
45524462
4553 const src_mcv = try func.resolveInst(operand);4463 const src_mcv = try func.resolveInst(operand);
4554 const dst_mcv = if (switch (src_mcv) {4464 const dst_mcv = if (switch (src_mcv) {
...@@ -4600,7 +4510,6 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -4600,7 +4510,6 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void {
4600 if (field_off > 0) {4510 if (field_off > 0) {
4601 _ = try func.addInst(.{4511 _ = try func.addInst(.{
4602 .tag = .srli,4512 .tag = .srli,
4603 .ops = .rri,
4604 .data = .{ .i_type = .{4513 .data = .{ .i_type = .{
4605 .imm12 = Immediate.u(@intCast(field_off)),4514 .imm12 = Immediate.u(@intCast(field_off)),
4606 .rd = dst_reg,4515 .rd = dst_reg,
...@@ -4720,8 +4629,7 @@ fn airArg(func: *Func, inst: Air.Inst.Index) !void {...@@ -4720,8 +4629,7 @@ fn airArg(func: *Func, inst: Air.Inst.Index) !void {
4720fn airTrap(func: *Func) !void {4629fn airTrap(func: *Func) !void {
4721 _ = try func.addInst(.{4630 _ = try func.addInst(.{
4722 .tag = .unimp,4631 .tag = .unimp,
4723 .ops = .none,4632 .data = .none,
4724 .data = undefined,
4725 });4633 });
4726 return func.finishAirBookkeeping();4634 return func.finishAirBookkeeping();
4727}4635}
...@@ -4729,8 +4637,7 @@ fn airTrap(func: *Func) !void {...@@ -4729,8 +4637,7 @@ fn airTrap(func: *Func) !void {
4729fn airBreakpoint(func: *Func) !void {4637fn airBreakpoint(func: *Func) !void {
4730 _ = try func.addInst(.{4638 _ = try func.addInst(.{
4731 .tag = .ebreak,4639 .tag = .ebreak,
4732 .ops = .none,4640 .data = .none,
4733 .data = undefined,
4734 });4641 });
4735 return func.finishAirBookkeeping();4642 return func.finishAirBookkeeping();
4736}4643}
...@@ -4758,8 +4665,7 @@ fn airFence(func: *Func, inst: Air.Inst.Index) !void {...@@ -4758,8 +4665,7 @@ fn airFence(func: *Func, inst: Air.Inst.Index) !void {
4758 };4665 };
47594666
4760 _ = try func.addInst(.{4667 _ = try func.addInst(.{
4761 .tag = .pseudo,4668 .tag = .pseudo_fence,
4762 .ops = .pseudo_fence,
4763 .data = .{4669 .data = .{
4764 .fence = .{4670 .fence = .{
4765 .pred = pred,4671 .pred = pred,
...@@ -4951,7 +4857,6 @@ fn genCall(...@@ -4951,7 +4857,6 @@ fn genCall(
4951 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });4857 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
4952 _ = try func.addInst(.{4858 _ = try func.addInst(.{
4953 .tag = .jalr,4859 .tag = .jalr,
4954 .ops = .rri,
4955 .data = .{ .i_type = .{4860 .data = .{ .i_type = .{
4956 .rd = .ra,4861 .rd = .ra,
4957 .rs1 = .ra,4862 .rs1 = .ra,
...@@ -4967,16 +4872,15 @@ fn genCall(...@@ -4967,16 +4872,15 @@ fn genCall(
4967 const decl_name = owner_decl.name.toSlice(&zcu.intern_pool);4872 const decl_name = owner_decl.name.toSlice(&zcu.intern_pool);
4968 const atom_index = try func.owner.getSymbolIndex(func);4873 const atom_index = try func.owner.getSymbolIndex(func);
49694874
4970 if (func.bin_file.cast(link.File.Elf)) |elf_file| {4875 const elf_file = func.bin_file.cast(link.File.Elf).?;
4971 _ = try func.addInst(.{4876 _ = try func.addInst(.{
4972 .tag = .pseudo,4877 .tag = .pseudo_extern_fn_reloc,
4973 .ops = .pseudo_extern_fn_reloc,4878 .data = .{ .reloc = .{
4974 .data = .{ .reloc = .{4879 .register = .ra,
4975 .atom_index = atom_index,4880 .atom_index = atom_index,
4976 .sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name),4881 .sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name),
4977 } },4882 } },
4978 });4883 });
4979 } else unreachable; // not a valid riscv64 format
4980 },4884 },
4981 else => return func.fail("TODO implement calling bitcasted functions", .{}),4885 else => return func.fail("TODO implement calling bitcasted functions", .{}),
4982 }4886 }
...@@ -4988,7 +4892,6 @@ fn genCall(...@@ -4988,7 +4892,6 @@ fn genCall(
49884892
4989 _ = try func.addInst(.{4893 _ = try func.addInst(.{
4990 .tag = .jalr,4894 .tag = .jalr,
4991 .ops = .rri,
4992 .data = .{ .i_type = .{4895 .data = .{ .i_type = .{
4993 .rd = .ra,4896 .rd = .ra,
4994 .rs1 = addr_reg,4897 .rs1 = addr_reg,
...@@ -5065,9 +4968,11 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {...@@ -5065,9 +4968,11 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void {
50654968
5066 // Just add space for an instruction, reloced this later4969 // Just add space for an instruction, reloced this later
5067 const index = try func.addInst(.{4970 const index = try func.addInst(.{
5068 .tag = .pseudo,4971 .tag = .pseudo_j,
5069 .ops = .pseudo_j,4972 .data = .{ .j_type = .{
5070 .data = .{ .inst = undefined },4973 .rd = .zero,
4974 .inst = undefined,
4975 } },
5071 });4976 });
50724977
5073 try func.exitlude_jump_relocs.append(func.gpa, index);4978 try func.exitlude_jump_relocs.append(func.gpa, index);
...@@ -5089,9 +4994,11 @@ fn airRetLoad(func: *Func, inst: Air.Inst.Index) !void {...@@ -5089,9 +4994,11 @@ fn airRetLoad(func: *Func, inst: Air.Inst.Index) !void {
50894994
5090 // Just add space for an instruction, reloced this later4995 // Just add space for an instruction, reloced this later
5091 const index = try func.addInst(.{4996 const index = try func.addInst(.{
5092 .tag = .pseudo,4997 .tag = .pseudo_j,
5093 .ops = .pseudo_j,4998 .data = .{ .j_type = .{
5094 .data = .{ .inst = undefined },4999 .rd = .zero,
5000 .inst = undefined,
5001 } },
5095 });5002 });
50965003
5097 try func.exitlude_jump_relocs.append(func.gpa, index);5004 try func.exitlude_jump_relocs.append(func.gpa, index);
...@@ -5171,8 +5078,7 @@ fn airDbgStmt(func: *Func, inst: Air.Inst.Index) !void {...@@ -5171,8 +5078,7 @@ fn airDbgStmt(func: *Func, inst: Air.Inst.Index) !void {
5171 const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;5078 const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt;
51725079
5173 _ = try func.addInst(.{5080 _ = try func.addInst(.{
5174 .tag = .pseudo,5081 .tag = .pseudo_dbg_line_column,
5175 .ops = .pseudo_dbg_line_column,
5176 .data = .{ .pseudo_dbg_line_column = .{5082 .data = .{ .pseudo_dbg_line_column = .{
5177 .line = dbg_stmt.line,5083 .line = dbg_stmt.line,
5178 .column = dbg_stmt.column,5084 .column = dbg_stmt.column,
...@@ -5290,7 +5196,6 @@ fn condBr(func: *Func, cond_ty: Type, condition: MCValue) !Mir.Inst.Index {...@@ -5290,7 +5196,6 @@ fn condBr(func: *Func, cond_ty: Type, condition: MCValue) !Mir.Inst.Index {
52905196
5291 return try func.addInst(.{5197 return try func.addInst(.{
5292 .tag = .beq,5198 .tag = .beq,
5293 .ops = .rr_inst,
5294 .data = .{5199 .data = .{
5295 .b_type = .{5200 .b_type = .{
5296 .rs1 = cond_reg,5201 .rs1 = cond_reg,
...@@ -5332,8 +5237,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -5332,8 +5237,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
5332 .register => |opt_reg| {5237 .register => |opt_reg| {
5333 if (some_info.off == 0) {5238 if (some_info.off == 0) {
5334 _ = try func.addInst(.{5239 _ = try func.addInst(.{
5335 .tag = .pseudo,5240 .tag = .pseudo_compare,
5336 .ops = .pseudo_compare,
5337 .data = .{5241 .data = .{
5338 .compare = .{5242 .compare = .{
5339 .op = .eq,5243 .op = .eq,
...@@ -5382,8 +5286,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC...@@ -5382,8 +5286,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC
5382 defer func.register_manager.unlockReg(opt_reg_lock);5286 defer func.register_manager.unlockReg(opt_reg_lock);
53835287
5384 _ = try func.addInst(.{5288 _ = try func.addInst(.{
5385 .tag = .pseudo,5289 .tag = .pseudo_compare,
5386 .ops = .pseudo_compare,
5387 .data = .{5290 .data = .{
5388 .compare = .{5291 .compare = .{
5389 .op = .eq,5292 .op = .eq,
...@@ -5432,8 +5335,7 @@ fn airIsNonNull(func: *Func, inst: Air.Inst.Index) !void {...@@ -5432,8 +5335,7 @@ fn airIsNonNull(func: *Func, inst: Air.Inst.Index) !void {
5432 assert(result == .register);5335 assert(result == .register);
54335336
5434 _ = try func.addInst(.{5337 _ = try func.addInst(.{
5435 .tag = .pseudo,5338 .tag = .pseudo_not,
5436 .ops = .pseudo_not,
5437 .data = .{5339 .data = .{
5438 .rr = .{5340 .rr = .{
5439 .rd = result.register,5341 .rd = result.register,
...@@ -5565,8 +5467,7 @@ fn isNonErr(func: *Func, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC...@@ -5565,8 +5467,7 @@ fn isNonErr(func: *Func, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC
5565 switch (is_err_res) {5467 switch (is_err_res) {
5566 .register => |reg| {5468 .register => |reg| {
5567 _ = try func.addInst(.{5469 _ = try func.addInst(.{
5568 .tag = .pseudo,5470 .tag = .pseudo_not,
5569 .ops = .pseudo_not,
5570 .data = .{5471 .data = .{
5571 .rr = .{5472 .rr = .{
5572 .rd = reg,5473 .rd = reg,
...@@ -5633,11 +5534,11 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void {...@@ -5633,11 +5534,11 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void {
5633/// Send control flow to the `index` of `func.code`.5534/// Send control flow to the `index` of `func.code`.
5634fn jump(func: *Func, index: Mir.Inst.Index) !Mir.Inst.Index {5535fn jump(func: *Func, index: Mir.Inst.Index) !Mir.Inst.Index {
5635 return func.addInst(.{5536 return func.addInst(.{
5636 .tag = .pseudo,5537 .tag = .pseudo_j,
5637 .ops = .pseudo_j,5538 .data = .{ .j_type = .{
5638 .data = .{5539 .rd = .zero,
5639 .inst = index,5540 .inst = index,
5640 },5541 } },
5641 });5542 });
5642}5543}
56435544
...@@ -5727,8 +5628,7 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {...@@ -5727,8 +5628,7 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
57275628
5728 if (!(i < relocs.len - 1)) {5629 if (!(i < relocs.len - 1)) {
5729 _ = try func.addInst(.{5630 _ = try func.addInst(.{
5730 .tag = .pseudo,5631 .tag = .pseudo_not,
5731 .ops = .pseudo_not,
5732 .data = .{ .rr = .{5632 .data = .{ .rr = .{
5733 .rd = cmp_reg,5633 .rd = cmp_reg,
5734 .rs = cmp_reg,5634 .rs = cmp_reg,
...@@ -5775,18 +5675,13 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {...@@ -5775,18 +5675,13 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void {
57755675
5776fn performReloc(func: *Func, inst: Mir.Inst.Index) void {5676fn performReloc(func: *Func, inst: Mir.Inst.Index) void {
5777 const tag = func.mir_instructions.items(.tag)[inst];5677 const tag = func.mir_instructions.items(.tag)[inst];
5778 const ops = func.mir_instructions.items(.ops)[inst];
5779 const target: Mir.Inst.Index = @intCast(func.mir_instructions.len);5678 const target: Mir.Inst.Index = @intCast(func.mir_instructions.len);
57805679
5781 switch (tag) {5680 switch (tag) {
5782 .bne,
5783 .beq,5681 .beq,
5784 => func.mir_instructions.items(.data)[inst].b_type.inst = target,5682 => func.mir_instructions.items(.data)[inst].b_type.inst = target,
5785 .jal => func.mir_instructions.items(.data)[inst].j_type.inst = target,5683 .jal => func.mir_instructions.items(.data)[inst].j_type.inst = target,
5786 .pseudo => switch (ops) {5684 .pseudo_j => func.mir_instructions.items(.data)[inst].j_type.inst = target,
5787 .pseudo_j => func.mir_instructions.items(.data)[inst].inst = target,
5788 else => std.debug.panic("TODO: performReloc {s}", .{@tagName(ops)}),
5789 },
5790 else => std.debug.panic("TODO: performReloc {s}", .{@tagName(tag)}),5685 else => std.debug.panic("TODO: performReloc {s}", .{@tagName(tag)}),
5791 }5686 }
5792}5687}
...@@ -5873,7 +5768,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {...@@ -5873,7 +5768,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
58735768
5874 _ = try func.addInst(.{5769 _ = try func.addInst(.{
5875 .tag = if (tag == .bool_or) .@"or" else .@"and",5770 .tag = if (tag == .bool_or) .@"or" else .@"and",
5876 .ops = .rrr,
5877 .data = .{ .r_type = .{5771 .data = .{ .r_type = .{
5878 .rd = result_reg,5772 .rd = result_reg,
5879 .rs1 = lhs_reg,5773 .rs1 = lhs_reg,
...@@ -5885,7 +5779,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {...@@ -5885,7 +5779,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void {
5885 if (func.wantSafety()) {5779 if (func.wantSafety()) {
5886 _ = try func.addInst(.{5780 _ = try func.addInst(.{
5887 .tag = .andi,5781 .tag = .andi,
5888 .ops = .rri,
5889 .data = .{ .i_type = .{5782 .data = .{ .i_type = .{
5890 .rd = result_reg,5783 .rd = result_reg,
5891 .rs1 = result_reg,5784 .rs1 = result_reg,
...@@ -5970,11 +5863,10 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {...@@ -5970,11 +5863,10 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void {
59705863
5971 const asm_source = std.mem.sliceAsBytes(func.air.extra[extra_i..])[0..extra.data.source_len];5864 const asm_source = std.mem.sliceAsBytes(func.air.extra[extra_i..])[0..extra.data.source_len];
59725865
5973 if (std.meta.stringToEnum(Mir.Inst.Tag, asm_source)) |tag| {5866 if (std.meta.stringToEnum(Mnemonic, asm_source)) |tag| {
5974 _ = try func.addInst(.{5867 _ = try func.addInst(.{
5975 .tag = tag,5868 .tag = tag,
5976 .ops = .none,5869 .data = .none,
5977 .data = undefined,
5978 });5870 });
5979 } else {5871 } else {
5980 return func.fail("TODO: asm_source {s}", .{asm_source});5872 return func.fail("TODO: asm_source {s}", .{asm_source});
...@@ -6116,7 +6008,6 @@ fn genInlineMemcpy(...@@ -6116,7 +6008,6 @@ fn genInlineMemcpy(
6116 // if count is 0, there's nothing to copy6008 // if count is 0, there's nothing to copy
6117 _ = try func.addInst(.{6009 _ = try func.addInst(.{
6118 .tag = .beq,6010 .tag = .beq,
6119 .ops = .rr_inst,
6120 .data = .{ .b_type = .{6011 .data = .{ .b_type = .{
6121 .rs1 = count,6012 .rs1 = count,
6122 .rs2 = .zero,6013 .rs2 = .zero,
...@@ -6127,7 +6018,6 @@ fn genInlineMemcpy(...@@ -6127,7 +6018,6 @@ fn genInlineMemcpy(
6127 // lb tmp, 0(src)6018 // lb tmp, 0(src)
6128 const first_inst = try func.addInst(.{6019 const first_inst = try func.addInst(.{
6129 .tag = .lb,6020 .tag = .lb,
6130 .ops = .rri,
6131 .data = .{6021 .data = .{
6132 .i_type = .{6022 .i_type = .{
6133 .rd = tmp,6023 .rd = tmp,
...@@ -6140,7 +6030,6 @@ fn genInlineMemcpy(...@@ -6140,7 +6030,6 @@ fn genInlineMemcpy(
6140 // sb tmp, 0(dst)6030 // sb tmp, 0(dst)
6141 _ = try func.addInst(.{6031 _ = try func.addInst(.{
6142 .tag = .sb,6032 .tag = .sb,
6143 .ops = .rri,
6144 .data = .{6033 .data = .{
6145 .i_type = .{6034 .i_type = .{
6146 .rd = dst,6035 .rd = dst,
...@@ -6153,7 +6042,6 @@ fn genInlineMemcpy(...@@ -6153,7 +6042,6 @@ fn genInlineMemcpy(
6153 // dec count by 16042 // dec count by 1
6154 _ = try func.addInst(.{6043 _ = try func.addInst(.{
6155 .tag = .addi,6044 .tag = .addi,
6156 .ops = .rri,
6157 .data = .{6045 .data = .{
6158 .i_type = .{6046 .i_type = .{
6159 .rd = count,6047 .rd = count,
...@@ -6166,7 +6054,6 @@ fn genInlineMemcpy(...@@ -6166,7 +6054,6 @@ fn genInlineMemcpy(
6166 // branch if count is 06054 // branch if count is 0
6167 _ = try func.addInst(.{6055 _ = try func.addInst(.{
6168 .tag = .beq,6056 .tag = .beq,
6169 .ops = .rr_inst,
6170 .data = .{6057 .data = .{
6171 .b_type = .{6058 .b_type = .{
6172 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst6059 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst
...@@ -6179,7 +6066,6 @@ fn genInlineMemcpy(...@@ -6179,7 +6066,6 @@ fn genInlineMemcpy(
6179 // increment the pointers6066 // increment the pointers
6180 _ = try func.addInst(.{6067 _ = try func.addInst(.{
6181 .tag = .addi,6068 .tag = .addi,
6182 .ops = .rri,
6183 .data = .{6069 .data = .{
6184 .i_type = .{6070 .i_type = .{
6185 .rd = src,6071 .rd = src,
...@@ -6191,7 +6077,6 @@ fn genInlineMemcpy(...@@ -6191,7 +6077,6 @@ fn genInlineMemcpy(
61916077
6192 _ = try func.addInst(.{6078 _ = try func.addInst(.{
6193 .tag = .addi,6079 .tag = .addi,
6194 .ops = .rri,
6195 .data = .{6080 .data = .{
6196 .i_type = .{6081 .i_type = .{
6197 .rd = dst,6082 .rd = dst,
...@@ -6203,9 +6088,11 @@ fn genInlineMemcpy(...@@ -6203,9 +6088,11 @@ fn genInlineMemcpy(
62036088
6204 // jump back to start of loop6089 // jump back to start of loop
6205 _ = try func.addInst(.{6090 _ = try func.addInst(.{
6206 .tag = .pseudo,6091 .tag = .pseudo_j,
6207 .ops = .pseudo_j,6092 .data = .{ .j_type = .{
6208 .data = .{ .inst = first_inst },6093 .rd = .zero,
6094 .inst = first_inst,
6095 } },
6209 });6096 });
6210}6097}
62116098
...@@ -6230,7 +6117,6 @@ fn genInlineMemset(...@@ -6230,7 +6117,6 @@ fn genInlineMemset(
6230 // sb src, 0(dst)6117 // sb src, 0(dst)
6231 const first_inst = try func.addInst(.{6118 const first_inst = try func.addInst(.{
6232 .tag = .sb,6119 .tag = .sb,
6233 .ops = .rri,
6234 .data = .{6120 .data = .{
6235 .i_type = .{6121 .i_type = .{
6236 .rd = dst,6122 .rd = dst,
...@@ -6243,7 +6129,6 @@ fn genInlineMemset(...@@ -6243,7 +6129,6 @@ fn genInlineMemset(
6243 // dec count by 16129 // dec count by 1
6244 _ = try func.addInst(.{6130 _ = try func.addInst(.{
6245 .tag = .addi,6131 .tag = .addi,
6246 .ops = .rri,
6247 .data = .{6132 .data = .{
6248 .i_type = .{6133 .i_type = .{
6249 .rd = count,6134 .rd = count,
...@@ -6256,7 +6141,6 @@ fn genInlineMemset(...@@ -6256,7 +6141,6 @@ fn genInlineMemset(
6256 // branch if count is 06141 // branch if count is 0
6257 _ = try func.addInst(.{6142 _ = try func.addInst(.{
6258 .tag = .beq,6143 .tag = .beq,
6259 .ops = .rr_inst,
6260 .data = .{6144 .data = .{
6261 .b_type = .{6145 .b_type = .{
6262 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst6146 .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst
...@@ -6269,7 +6153,6 @@ fn genInlineMemset(...@@ -6269,7 +6153,6 @@ fn genInlineMemset(
6269 // increment the pointers6153 // increment the pointers
6270 _ = try func.addInst(.{6154 _ = try func.addInst(.{
6271 .tag = .addi,6155 .tag = .addi,
6272 .ops = .rri,
6273 .data = .{6156 .data = .{
6274 .i_type = .{6157 .i_type = .{
6275 .rd = dst,6158 .rd = dst,
...@@ -6281,11 +6164,11 @@ fn genInlineMemset(...@@ -6281,11 +6164,11 @@ fn genInlineMemset(
62816164
6282 // jump back to start of loop6165 // jump back to start of loop
6283 _ = try func.addInst(.{6166 _ = try func.addInst(.{
6284 .tag = .pseudo,6167 .tag = .pseudo_j,
6285 .ops = .pseudo_j,6168 .data = .{ .j_type = .{
6286 .data = .{6169 .rd = .zero,
6287 .inst = first_inst,6170 .inst = first_inst,
6288 },6171 } },
6289 });6172 });
6290}6173}
62916174
...@@ -6331,7 +6214,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6331,7 +6214,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6331 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {6214 if (math.minInt(i12) <= x and x <= math.maxInt(i12)) {
6332 _ = try func.addInst(.{6215 _ = try func.addInst(.{
6333 .tag = .addi,6216 .tag = .addi,
6334 .ops = .rri,
6335 .data = .{ .i_type = .{6217 .data = .{ .i_type = .{
6336 .rd = reg,6218 .rd = reg,
6337 .rs1 = .zero,6219 .rs1 = .zero,
...@@ -6345,7 +6227,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6345,7 +6227,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
63456227
6346 _ = try func.addInst(.{6228 _ = try func.addInst(.{
6347 .tag = .lui,6229 .tag = .lui,
6348 .ops = .ri,
6349 .data = .{ .u_type = .{6230 .data = .{ .u_type = .{
6350 .rd = reg,6231 .rd = reg,
6351 .imm20 = Immediate.s(hi20),6232 .imm20 = Immediate.s(hi20),
...@@ -6353,7 +6234,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6353,7 +6234,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6353 });6234 });
6354 _ = try func.addInst(.{6235 _ = try func.addInst(.{
6355 .tag = .addi,6236 .tag = .addi,
6356 .ops = .rri,
6357 .data = .{ .i_type = .{6237 .data = .{ .i_type = .{
6358 .rd = reg,6238 .rd = reg,
6359 .rs1 = reg,6239 .rs1 = reg,
...@@ -6376,7 +6256,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6376,7 +6256,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
63766256
6377 _ = try func.addInst(.{6257 _ = try func.addInst(.{
6378 .tag = .slli,6258 .tag = .slli,
6379 .ops = .rri,
6380 .data = .{ .i_type = .{6259 .data = .{ .i_type = .{
6381 .rd = reg,6260 .rd = reg,
6382 .rs1 = reg,6261 .rs1 = reg,
...@@ -6386,7 +6265,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6386,7 +6265,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
63866265
6387 _ = try func.addInst(.{6266 _ = try func.addInst(.{
6388 .tag = .add,6267 .tag = .add,
6389 .ops = .rrr,
6390 .data = .{ .r_type = .{6268 .data = .{ .r_type = .{
6391 .rd = reg,6269 .rd = reg,
6392 .rs1 = reg,6270 .rs1 = reg,
...@@ -6423,8 +6301,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6423,8 +6301,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
64236301
6424 // mv reg, src_reg6302 // mv reg, src_reg
6425 _ = try func.addInst(.{6303 _ = try func.addInst(.{
6426 .tag = .pseudo,6304 .tag = .pseudo_mv,
6427 .ops = .pseudo_mv,
6428 .data = .{ .rr = .{6305 .data = .{ .rr = .{
6429 .rd = reg,6306 .rd = reg,
6430 .rs = src_reg,6307 .rs = src_reg,
...@@ -6445,8 +6322,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6445,8 +6322,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6445 try func.genCopy(ty, .{ .register = reg }, .{ .indirect = .{ .reg = addr_reg } });6322 try func.genCopy(ty, .{ .register = reg }, .{ .indirect = .{ .reg = addr_reg } });
6446 } else {6323 } else {
6447 _ = try func.addInst(.{6324 _ = try func.addInst(.{
6448 .tag = .pseudo,6325 .tag = .pseudo_load_rm,
6449 .ops = .pseudo_load_rm,
6450 .data = .{ .rm = .{6326 .data = .{ .rm = .{
6451 .r = reg,6327 .r = reg,
6452 .m = .{6328 .m = .{
...@@ -6466,7 +6342,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6466,7 +6342,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
64666342
6467 _ = try func.addInst(.{6343 _ = try func.addInst(.{
6468 .tag = .ld,6344 .tag = .ld,
6469 .ops = .rri,
6470 .data = .{ .i_type = .{6345 .data = .{ .i_type = .{
6471 .rd = reg,6346 .rd = reg,
6472 .rs1 = reg,6347 .rs1 = reg,
...@@ -6476,8 +6351,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6476,8 +6351,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6476 },6351 },
6477 .lea_frame, .register_offset => {6352 .lea_frame, .register_offset => {
6478 _ = try func.addInst(.{6353 _ = try func.addInst(.{
6479 .tag = .pseudo,6354 .tag = .pseudo_lea_rm,
6480 .ops = .pseudo_lea_rm,
6481 .data = .{6355 .data = .{
6482 .rm = .{6356 .rm = .{
6483 .r = reg,6357 .r = reg,
...@@ -6505,7 +6379,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6505,7 +6379,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6505 });6379 });
6506 },6380 },
6507 .indirect => |reg_off| {6381 .indirect => |reg_off| {
6508 const load_tag: Mir.Inst.Tag = switch (reg.class()) {6382 const load_tag: Mnemonic = switch (reg.class()) {
6509 .float => switch (abi_size) {6383 .float => switch (abi_size) {
6510 1 => unreachable, // Zig does not support 8-bit floats6384 1 => unreachable, // Zig does not support 8-bit floats
6511 2 => return func.fail("TODO: genSetReg indirect 16-bit float", .{}),6385 2 => return func.fail("TODO: genSetReg indirect 16-bit float", .{}),
...@@ -6544,8 +6418,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6544,8 +6418,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6544 });6418 });
65456419
6546 _ = try func.addInst(.{6420 _ = try func.addInst(.{
6547 .tag = .pseudo,6421 .tag = .pseudo_load_rm,
6548 .ops = .pseudo_load_rm,
6549 .data = .{ .rm = .{6422 .data = .{ .rm = .{
6550 .r = reg,6423 .r = reg,
6551 .m = .{6424 .m = .{
...@@ -6565,7 +6438,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6565,7 +6438,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
65656438
6566 _ = try func.addInst(.{6439 _ = try func.addInst(.{
6567 .tag = load_tag,6440 .tag = load_tag,
6568 .ops = .rri,
6569 .data = .{ .i_type = .{6441 .data = .{ .i_type = .{
6570 .rd = reg,6442 .rd = reg,
6571 .rs1 = reg_off.reg,6443 .rs1 = reg_off.reg,
...@@ -6578,13 +6450,12 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!...@@ -6578,13 +6450,12 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError!
6578 const atom_index = try func.owner.getSymbolIndex(func);6450 const atom_index = try func.owner.getSymbolIndex(func);
65796451
6580 _ = try func.addInst(.{6452 _ = try func.addInst(.{
6581 .tag = .pseudo,6453 .tag = .pseudo_load_symbol,
6582 .ops = .pseudo_load_symbol,6454 .data = .{ .reloc = .{
6583 .data = .{ .payload = try func.addExtra(Mir.LoadSymbolPayload{6455 .register = reg,
6584 .register = reg.encodeId(),
6585 .atom_index = atom_index,6456 .atom_index = atom_index,
6586 .sym_index = sym_off.sym,6457 .sym_index = sym_off.sym,
6587 }) },6458 } },
6588 });6459 });
6589 },6460 },
6590 .load_symbol => {6461 .load_symbol => {
...@@ -6676,8 +6547,7 @@ fn genSetMem(...@@ -6676,8 +6547,7 @@ fn genSetMem(
6676 });6547 });
66776548
6678 _ = try func.addInst(.{6549 _ = try func.addInst(.{
6679 .tag = .pseudo,6550 .tag = .pseudo_store_rm,
6680 .ops = .pseudo_store_rm,
6681 .data = .{ .rm = .{6551 .data = .{ .rm = .{
6682 .r = reg,6552 .r = reg,
6683 .m = .{6553 .m = .{
...@@ -6716,8 +6586,7 @@ fn genSetMem(...@@ -6716,8 +6586,7 @@ fn genSetMem(
6716 }));6586 }));
6717 const frame_mcv: MCValue = .{ .load_frame = .{ .index = frame_index } };6587 const frame_mcv: MCValue = .{ .load_frame = .{ .index = frame_index } };
6718 _ = try func.addInst(.{6588 _ = try func.addInst(.{
6719 .tag = .pseudo,6589 .tag = .pseudo_store_rm,
6720 .ops = .pseudo_store_rm,
6721 .data = .{ .rm = .{6590 .data = .{ .rm = .{
6722 .r = reg,6591 .r = reg,
6723 .m = .{6592 .m = .{
...@@ -6732,8 +6601,7 @@ fn genSetMem(...@@ -6732,8 +6601,7 @@ fn genSetMem(
6732 try func.genSetMem(base, disp, ty, frame_mcv);6601 try func.genSetMem(base, disp, ty, frame_mcv);
6733 try func.freeValue(frame_mcv);6602 try func.freeValue(frame_mcv);
6734 } else _ = try func.addInst(.{6603 } else _ = try func.addInst(.{
6735 .tag = .pseudo,6604 .tag = .pseudo_store_rm,
6736 .ops = .pseudo_store_rm,
6737 .data = .{ .rm = .{6605 .data = .{ .rm = .{
6738 .r = reg,6606 .r = reg,
6739 .m = .{6607 .m = .{
...@@ -6852,9 +6720,59 @@ fn airFloatFromInt(func: *Func, inst: Air.Inst.Index) !void {...@@ -6852,9 +6720,59 @@ fn airFloatFromInt(func: *Func, inst: Air.Inst.Index) !void {
68526720
6853fn airIntFromFloat(func: *Func, inst: Air.Inst.Index) !void {6721fn airIntFromFloat(func: *Func, inst: Air.Inst.Index) !void {
6854 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;6722 const ty_op = func.air.instructions.items(.data)[@intFromEnum(inst)].ty_op;
6855 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else return func.fail("TODO implement airIntFromFloat for {}", .{6723 const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: {
6856 func.target.cpu.arch,6724 const pt = func.pt;
6857 });6725 const zcu = pt.zcu;
6726
6727 const operand = try func.resolveInst(ty_op.operand);
6728 const src_ty = func.typeOf(ty_op.operand);
6729 const dst_ty = func.typeOfIndex(inst);
6730
6731 const is_unsigned = dst_ty.isUnsignedInt(zcu);
6732 const src_bits = src_ty.bitSize(pt);
6733 const dst_bits = dst_ty.bitSize(pt);
6734
6735 const float_mod: enum { s, d } = switch (src_bits) {
6736 32 => .s,
6737 64 => .d,
6738 else => return func.fail("TODO: airIntFromFloat src size {d}", .{src_bits}),
6739 };
6740
6741 const int_mod: Mir.FcvtOp = switch (dst_bits) {
6742 32 => if (is_unsigned) .wu else .w,
6743 64 => if (is_unsigned) .lu else .l,
6744 else => return func.fail("TODO: airIntFromFloat dst size: {d}", .{dst_bits}),
6745 };
6746
6747 const src_reg, const src_lock = try func.promoteReg(src_ty, operand);
6748 defer if (src_lock) |lock| func.register_manager.unlockReg(lock);
6749
6750 const dst_reg, const dst_lock = try func.allocReg(.int);
6751 defer func.register_manager.unlockReg(dst_lock);
6752
6753 _ = try func.addInst(.{
6754 .tag = switch (float_mod) {
6755 .s => switch (int_mod) {
6756 .l => .fcvtls,
6757 .lu => .fcvtlus,
6758 .w => .fcvtws,
6759 .wu => .fcvtwus,
6760 },
6761 .d => switch (int_mod) {
6762 .l => .fcvtld,
6763 .lu => .fcvtlud,
6764 .w => .fcvtwd,
6765 .wu => .fcvtwud,
6766 },
6767 },
6768 .data = .{ .rr = .{
6769 .rd = dst_reg,
6770 .rs = src_reg,
6771 } },
6772 });
6773
6774 break :result .{ .register = dst_reg };
6775 };
6858 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });6776 return func.finishAir(inst, result, .{ ty_op.operand, .none, .none });
6859}6777}
68606778
...@@ -6917,8 +6835,7 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {...@@ -6917,8 +6835,7 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void {
6917 };6835 };
69186836
6919 _ = try func.addInst(.{6837 _ = try func.addInst(.{
6920 .tag = .pseudo,6838 .tag = .pseudo_amo,
6921 .ops = .pseudo_amo,
6922 .data = .{ .amo = .{6839 .data = .{ .amo = .{
6923 .rd = result_mcv.register,6840 .rd = result_mcv.register,
6924 .rs1 = ptr_register,6841 .rs1 = ptr_register,
...@@ -6961,15 +6878,12 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {...@@ -6961,15 +6878,12 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
69616878
6962 if (order == .seq_cst) {6879 if (order == .seq_cst) {
6963 _ = try func.addInst(.{6880 _ = try func.addInst(.{
6964 .tag = .pseudo,6881 .tag = .pseudo_fence,
6965 .ops = .pseudo_fence,6882 .data = .{ .fence = .{
6966 .data = .{6883 .pred = .rw,
6967 .fence = .{6884 .succ = .rw,
6968 .pred = .rw,6885 .fm = .none,
6969 .succ = .rw,6886 } },
6970 .fm = .none,
6971 },
6972 },
6973 });6887 });
6974 }6888 }
69756889
...@@ -6982,8 +6896,7 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {...@@ -6982,8 +6896,7 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void {
6982 // Make sure all previous reads happen before any reading or writing accurs.6896 // Make sure all previous reads happen before any reading or writing accurs.
6983 .seq_cst, .acquire => {6897 .seq_cst, .acquire => {
6984 _ = try func.addInst(.{6898 _ = try func.addInst(.{
6985 .tag = .pseudo,6899 .tag = .pseudo_fence,
6986 .ops = .pseudo_fence,
6987 .data = .{6900 .data = .{
6988 .fence = .{6901 .fence = .{
6989 .pred = .r,6902 .pred = .r,
...@@ -7015,8 +6928,7 @@ fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOr...@@ -7015,8 +6928,7 @@ fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOr
7015 .unordered, .monotonic => {},6928 .unordered, .monotonic => {},
7016 .release, .seq_cst => {6929 .release, .seq_cst => {
7017 _ = try func.addInst(.{6930 _ = try func.addInst(.{
7018 .tag = .pseudo,6931 .tag = .pseudo_fence,
7019 .ops = .pseudo_fence,
7020 .data = .{6932 .data = .{
7021 .fence = .{6933 .fence = .{
7022 .pred = .rw,6934 .pred = .rw,
...@@ -7183,7 +7095,6 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void {...@@ -7183,7 +7095,6 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void {
7183 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });7095 try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } });
7184 _ = try func.addInst(.{7096 _ = try func.addInst(.{
7185 .tag = .jalr,7097 .tag = .jalr,
7186 .ops = .rri,
7187 .data = .{ .i_type = .{7098 .data = .{ .i_type = .{
7188 .rd = .ra,7099 .rd = .ra,
7189 .rs1 = .ra,7100 .rs1 = .ra,
src/arch/riscv64/Emit.zig+71-77
...@@ -40,7 +40,7 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -40,7 +40,7 @@ pub fn emitMir(emit: *Emit) Error!void {
40 .source = start_offset,40 .source = start_offset,
41 .target = target,41 .target = target,
42 .offset = 0,42 .offset = 0,
43 .enc = std.meta.activeTag(lowered_inst.encoding.data),43 .fmt = std.meta.activeTag(lowered_inst),
44 }),44 }),
45 .load_symbol_reloc => |symbol| {45 .load_symbol_reloc => |symbol| {
46 const is_obj_or_static_lib = switch (emit.lower.output_mode) {46 const is_obj_or_static_lib = switch (emit.lower.output_mode) {
...@@ -49,46 +49,45 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -49,46 +49,45 @@ pub fn emitMir(emit: *Emit) Error!void {
49 .Lib => emit.lower.link_mode == .static,49 .Lib => emit.lower.link_mode == .static,
50 };50 };
5151
52 if (emit.bin_file.cast(link.File.Elf)) |elf_file| {52 const elf_file = emit.bin_file.cast(link.File.Elf).?;
53 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;53
54 const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index);54 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
55 const sym = elf_file.symbol(sym_index);55 const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index);
5656 const sym = elf_file.symbol(sym_index);
57 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);57
58 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);58 var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20);
5959 var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I);
60 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {60
61 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);61 if (sym.flags.needs_zig_got and !is_obj_or_static_lib) {
6262 _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file);
63 hi_r_type = Elf.R_ZIG_GOT_HI20;63
64 lo_r_type = Elf.R_ZIG_GOT_LO12;64 hi_r_type = Elf.R_ZIG_GOT_HI20;
65 }65 lo_r_type = Elf.R_ZIG_GOT_LO12;
6666 }
67 try atom_ptr.addReloc(elf_file, .{67
68 .r_offset = start_offset,68 try atom_ptr.addReloc(elf_file, .{
69 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,69 .r_offset = start_offset,
70 .r_addend = 0,70 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type,
71 });71 .r_addend = 0,
7272 });
73 try atom_ptr.addReloc(elf_file, .{73
74 .r_offset = start_offset + 4,74 try atom_ptr.addReloc(elf_file, .{
75 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,75 .r_offset = start_offset + 4,
76 .r_addend = 0,76 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type,
77 });77 .r_addend = 0,
78 } else unreachable;78 });
79 },79 },
80 .call_extern_fn_reloc => |symbol| {80 .call_extern_fn_reloc => |symbol| {
81 if (emit.bin_file.cast(link.File.Elf)) |elf_file| {81 const elf_file = emit.bin_file.cast(link.File.Elf).?;
82 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;82 const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?;
8383
84 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);84 const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT);
8585
86 try atom_ptr.addReloc(elf_file, .{86 try atom_ptr.addReloc(elf_file, .{
87 .r_offset = start_offset,87 .r_offset = start_offset,
88 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,88 .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type,
89 .r_addend = 0,89 .r_addend = 0,
90 });90 });
91 } else return emit.fail("TODO: call_extern_fn_reloc non-ELF", .{});
92 },91 },
93 };92 };
94 }93 }
...@@ -98,40 +97,37 @@ pub fn emitMir(emit: *Emit) Error!void {...@@ -98,40 +97,37 @@ pub fn emitMir(emit: *Emit) Error!void {
98 const mir_inst = emit.lower.mir.instructions.get(mir_index);97 const mir_inst = emit.lower.mir.instructions.get(mir_index);
99 switch (mir_inst.tag) {98 switch (mir_inst.tag) {
100 else => unreachable,99 else => unreachable,
101 .pseudo => switch (mir_inst.ops) {100 .pseudo_dbg_prologue_end => {
102 else => unreachable,101 switch (emit.debug_output) {
103 .pseudo_dbg_prologue_end => {102 .dwarf => |dw| {
104 switch (emit.debug_output) {103 try dw.setPrologueEnd();
105 .dwarf => |dw| {104 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{
106 try dw.setPrologueEnd();105 emit.prev_di_line, emit.prev_di_column,
107 log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{106 });
108 emit.prev_di_line, emit.prev_di_column,107 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
109 });108 },
110 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);109 .plan9 => {},
111 },110 .none => {},
112 .plan9 => {},111 }
113 .none => {},
114 }
115 },
116 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(
117 mir_inst.data.pseudo_dbg_line_column.line,
118 mir_inst.data.pseudo_dbg_line_column.column,
119 ),
120 .pseudo_dbg_epilogue_begin => {
121 switch (emit.debug_output) {
122 .dwarf => |dw| {
123 try dw.setEpilogueBegin();
124 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
125 emit.prev_di_line, emit.prev_di_column,
126 });
127 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
128 },
129 .plan9 => {},
130 .none => {},
131 }
132 },
133 .pseudo_dead => {},
134 },112 },
113 .pseudo_dbg_line_column => try emit.dbgAdvancePCAndLine(
114 mir_inst.data.pseudo_dbg_line_column.line,
115 mir_inst.data.pseudo_dbg_line_column.column,
116 ),
117 .pseudo_dbg_epilogue_begin => {
118 switch (emit.debug_output) {
119 .dwarf => |dw| {
120 try dw.setEpilogueBegin();
121 log.debug("mirDbgEpilogueBegin (line={d}, col={d})", .{
122 emit.prev_di_line, emit.prev_di_column,
123 });
124 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
125 },
126 .plan9 => {},
127 .none => {},
128 }
129 },
130 .pseudo_dead => {},
135 }131 }
136 }132 }
137 }133 }
...@@ -151,8 +147,8 @@ const Reloc = struct {...@@ -151,8 +147,8 @@ const Reloc = struct {
151 target: Mir.Inst.Index,147 target: Mir.Inst.Index,
152 /// Offset of the relocation within the instruction.148 /// Offset of the relocation within the instruction.
153 offset: u32,149 offset: u32,
154 /// Encoding of the instruction, used to determine how to modify it.150 /// Format of the instruction, used to determine how to modify it.
155 enc: Encoding.InstEnc,151 fmt: encoding.Lir.Format,
156};152};
157153
158fn fixupRelocs(emit: *Emit) Error!void {154fn fixupRelocs(emit: *Emit) Error!void {
...@@ -164,12 +160,10 @@ fn fixupRelocs(emit: *Emit) Error!void {...@@ -164,12 +160,10 @@ fn fixupRelocs(emit: *Emit) Error!void {
164 const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source));160 const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source));
165 const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4];161 const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4];
166162
167 log.debug("disp: {x}", .{disp});163 switch (reloc.fmt) {
168
169 switch (reloc.enc) {
170 .J => riscv_util.writeInstJ(code, @bitCast(disp)),164 .J => riscv_util.writeInstJ(code, @bitCast(disp)),
171 .B => riscv_util.writeInstB(code, @bitCast(disp)),165 .B => riscv_util.writeInstB(code, @bitCast(disp)),
172 else => return emit.fail("tried to reloc encoding type {s}", .{@tagName(reloc.enc)}),166 else => return emit.fail("tried to reloc format type {s}", .{@tagName(reloc.fmt)}),
173 }167 }
174 }168 }
175}169}
...@@ -209,5 +203,5 @@ const Emit = @This();...@@ -209,5 +203,5 @@ const Emit = @This();
209const Lower = @import("Lower.zig");203const Lower = @import("Lower.zig");
210const Mir = @import("Mir.zig");204const Mir = @import("Mir.zig");
211const riscv_util = @import("../../link/riscv.zig");205const riscv_util = @import("../../link/riscv.zig");
212const Encoding = @import("Encoding.zig");
213const Elf = @import("../../link/Elf.zig");206const Elf = @import("../../link/Elf.zig");
207const encoding = @import("encoding.zig");
src/arch/riscv64/Encoding.zig deleted-1136
...@@ -1,1136 +0,0 @@
1mnemonic: Mnemonic,
2data: Data,
3
4const OpCode = enum(u7) {
5 LOAD = 0b0000011,
6 LOAD_FP = 0b0000111,
7 MISC_MEM = 0b0001111,
8 OP_IMM = 0b0010011,
9 AUIPC = 0b0010111,
10 OP_IMM_32 = 0b0011011,
11 STORE = 0b0100011,
12 STORE_FP = 0b0100111,
13 AMO = 0b0101111,
14 OP_V = 0b1010111,
15 OP = 0b0110011,
16 OP_32 = 0b0111011,
17 LUI = 0b0110111,
18 MADD = 0b1000011,
19 MSUB = 0b1000111,
20 NMSUB = 0b1001011,
21 NMADD = 0b1001111,
22 OP_FP = 0b1010011,
23 OP_IMM_64 = 0b1011011,
24 BRANCH = 0b1100011,
25 JALR = 0b1100111,
26 JAL = 0b1101111,
27 SYSTEM = 0b1110011,
28 OP_64 = 0b1111011,
29 NONE = 0b00000000,
30};
31
32const FpFmt = enum(u2) {
33 /// 32-bit single-precision
34 S = 0b00,
35 /// 64-bit double-precision
36 D = 0b01,
37
38 // H = 0b10, unused in the G extension
39
40 /// 128-bit quad-precision
41 Q = 0b11,
42};
43
44const AmoWidth = enum(u3) {
45 W = 0b010,
46 D = 0b011,
47};
48
49const FenceMode = enum(u4) {
50 none = 0b0000,
51 tso = 0b1000,
52};
53
54const Enc = struct {
55 opcode: OpCode,
56
57 data: union(enum) {
58 /// funct3 + funct7
59 ff: struct {
60 funct3: u3,
61 funct7: u7,
62 },
63 amo: struct {
64 funct5: u5,
65 width: AmoWidth,
66 },
67 fence: struct {
68 funct3: u3,
69 fm: FenceMode,
70 },
71 /// funct5 + rm + fmt
72 fmt: struct {
73 funct5: u5,
74 rm: u3,
75 fmt: FpFmt,
76 },
77 /// funct3
78 f: struct {
79 funct3: u3,
80 },
81 /// typ + funct3 + has_5
82 sh: struct {
83 typ: u6,
84 funct3: u3,
85 has_5: bool,
86 },
87 vecls: struct {
88 width: VecWidth,
89 umop: Umop,
90 vm: bool,
91 mop: Mop,
92 mew: bool,
93 nf: u3,
94 },
95 vecmath: struct {
96 vm: bool,
97 funct6: u6,
98 funct3: VecType,
99 },
100 /// U-type
101 none,
102 },
103
104 const Mop = enum(u2) {
105 unit = 0b00,
106 unord = 0b01,
107 stride = 0b10,
108 ord = 0b11,
109 };
110
111 const Umop = enum(u5) {
112 unit = 0b00000,
113 whole = 0b01000,
114 mask = 0b01011,
115 fault = 0b10000,
116 };
117
118 const VecWidth = enum(u3) {
119 // zig fmt: off
120 @"8" = 0b000,
121 @"16" = 0b101,
122 @"32" = 0b110,
123 @"64" = 0b111,
124 // zig fmt: on
125 };
126
127 const VecType = enum(u3) {
128 OPIVV = 0b000,
129 OPFVV = 0b001,
130 OPMVV = 0b010,
131 OPIVI = 0b011,
132 OPIVX = 0b100,
133 OPFVF = 0b101,
134 OPMVX = 0b110,
135 };
136};
137
138// TODO: this is basically a copy of the MIR table, we should be able to de-dupe them somehow.
139pub const Mnemonic = enum {
140 // base mnemonics
141
142 // I Type
143 ld,
144 lw,
145 lwu,
146 lh,
147 lhu,
148 lb,
149 lbu,
150
151 sltiu,
152 xori,
153 andi,
154
155 slli,
156 srli,
157 srai,
158
159 slliw,
160 srliw,
161 sraiw,
162
163 addi,
164 jalr,
165
166 vsetivli,
167 vsetvli,
168
169 // U Type
170 lui,
171 auipc,
172
173 // S Type
174 sd,
175 sw,
176 sh,
177 sb,
178
179 // J Type
180 jal,
181
182 // B Type
183 beq,
184
185 // R Type
186 add,
187 addw,
188 sub,
189 subw,
190 @"and",
191 @"or",
192 slt,
193 sltu,
194 xor,
195
196 sll,
197 srl,
198 sra,
199
200 sllw,
201 srlw,
202 sraw,
203
204 // System
205 ecall,
206 ebreak,
207 unimp,
208
209 csrrs,
210
211 // M extension
212 mul,
213 mulw,
214
215 mulh,
216 mulhu,
217 mulhsu,
218
219 div,
220 divu,
221
222 divw,
223 divuw,
224
225 rem,
226 remu,
227
228 remw,
229 remuw,
230
231 // F extension (32-bit float)
232 fadds,
233 fsubs,
234 fmuls,
235 fdivs,
236
237 fmins,
238 fmaxs,
239
240 fsqrts,
241
242 flw,
243 fsw,
244
245 feqs,
246 flts,
247 fles,
248
249 fsgnjns,
250 fsgnjxs,
251
252 // D extension (64-bit float)
253 faddd,
254 fsubd,
255 fmuld,
256 fdivd,
257
258 fmind,
259 fmaxd,
260
261 fsqrtd,
262
263 fld,
264 fsd,
265
266 feqd,
267 fltd,
268 fled,
269
270 fsgnjnd,
271 fsgnjxd,
272
273 // V Extension
274 vle8v,
275 vle16v,
276 vle32v,
277 vle64v,
278
279 vse8v,
280 vse16v,
281 vse32v,
282 vse64v,
283
284 vsoxei8v,
285
286 vaddvv,
287 vsubvv,
288
289 vfaddvv,
290 vfsubvv,
291
292 vmulvv,
293 vfmulvv,
294
295 vadcvv,
296
297 vmvvx,
298
299 vslidedownvx,
300
301 // MISC
302 fence,
303 fencetso,
304
305 // AMO
306 amoswapw,
307 amoaddw,
308 amoandw,
309 amoorw,
310 amoxorw,
311 amomaxw,
312 amominw,
313 amomaxuw,
314 amominuw,
315
316 amoswapd,
317 amoaddd,
318 amoandd,
319 amoord,
320 amoxord,
321 amomaxd,
322 amomind,
323 amomaxud,
324 amominud,
325
326 // TODO: Q extension
327
328 // Zbb Extension
329 clz,
330 clzw,
331
332 pub fn encoding(mnem: Mnemonic) Enc {
333 return switch (mnem) {
334 // zig fmt: off
335
336 // OP
337
338 .add => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
339 .sub => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
340
341 .@"and" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
342 .@"or" => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
343 .xor => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
344
345 .sltu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
346 .slt => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
347
348 .mul => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
349 .mulh => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000001 } } },
350 .mulhsu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000001 } } },
351 .mulhu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000001 } } },
352
353 .div => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
354 .divu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
355
356 .rem => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
357 .remu => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
358
359 .sll => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
360 .srl => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
361 .sra => .{ .opcode = .OP, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
362
363
364 // OP_IMM
365
366 .addi => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b000 } } },
367 .andi => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b111 } } },
368 .xori => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b100 } } },
369
370 .sltiu => .{ .opcode = .OP_IMM, .data = .{ .f = .{ .funct3 = 0b011 } } },
371
372 .slli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = true } } },
373 .srli => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = true } } },
374 .srai => .{ .opcode = .OP_IMM, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = true } } },
375
376 .clz => .{ .opcode = .OP_IMM, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
377
378 // OP_IMM_32
379
380 .slliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = false } } },
381 .srliw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = false } } },
382 .sraiw => .{ .opcode = .OP_IMM_32, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = false } } },
383
384 .clzw => .{ .opcode = .OP_IMM_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
385
386 // OP_32
387
388 .addw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
389 .subw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
390 .mulw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
391
392 .divw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
393 .divuw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
394
395 .remw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
396 .remuw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
397
398 .sllw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
399 .srlw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
400 .sraw => .{ .opcode = .OP_32, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
401
402
403 // OP_FP
404
405 .fadds => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
406 .faddd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
407
408 .fsubs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .S, .rm = 0b111 } } },
409 .fsubd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .D, .rm = 0b111 } } },
410
411 .fmuls => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .S, .rm = 0b111 } } },
412 .fmuld => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .D, .rm = 0b111 } } },
413
414 .fdivs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .S, .rm = 0b111 } } },
415 .fdivd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .D, .rm = 0b111 } } },
416
417 .fmins => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b000 } } },
418 .fmind => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b000 } } },
419
420 .fmaxs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b001 } } },
421 .fmaxd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b001 } } },
422
423 .fsqrts => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .S, .rm = 0b111 } } },
424 .fsqrtd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .D, .rm = 0b111 } } },
425
426 .fles => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b000 } } },
427 .fled => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b000 } } },
428
429 .flts => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b001 } } },
430 .fltd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b001 } } },
431
432 .feqs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
433 .feqd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
434
435 .fsgnjns => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
436 .fsgnjnd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b000 } } },
437
438 .fsgnjxs => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b0010} } },
439 .fsgnjxd => .{ .opcode = .OP_FP, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b0010} } },
440
441
442 // LOAD
443
444 .lb => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b000 } } },
445 .lh => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b001 } } },
446 .lw => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b010 } } },
447 .ld => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b011 } } },
448 .lbu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b100 } } },
449 .lhu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b101 } } },
450 .lwu => .{ .opcode = .LOAD, .data = .{ .f = .{ .funct3 = 0b110 } } },
451
452
453 // STORE
454
455 .sb => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b000 } } },
456 .sh => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b001 } } },
457 .sw => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b010 } } },
458 .sd => .{ .opcode = .STORE, .data = .{ .f = .{ .funct3 = 0b011 } } },
459
460
461 // LOAD_FP
462
463 .flw => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
464 .fld => .{ .opcode = .LOAD_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
465
466 .vle8v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
467 .vle16v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
468 .vle32v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
469 .vle64v => .{ .opcode = .LOAD_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
470
471
472 // STORE_FP
473
474 .fsw => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b010 } } },
475 .fsd => .{ .opcode = .STORE_FP, .data = .{ .f = .{ .funct3 = 0b011 } } },
476
477 .vse8v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
478 .vse16v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
479 .vse32v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
480 .vse64v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
481
482 .vsoxei8v => .{ .opcode = .STORE_FP, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .ord, .mew = false, .nf = 0b000 } } },
483
484 // JALR
485
486 .jalr => .{ .opcode = .JALR, .data = .{ .f = .{ .funct3 = 0b000 } } },
487
488
489 // LUI
490
491 .lui => .{ .opcode = .LUI, .data = .{ .none = {} } },
492
493
494 // AUIPC
495
496 .auipc => .{ .opcode = .AUIPC, .data = .{ .none = {} } },
497
498
499 // JAL
500
501 .jal => .{ .opcode = .JAL, .data = .{ .none = {} } },
502
503
504 // BRANCH
505
506 .beq => .{ .opcode = .BRANCH, .data = .{ .f = .{ .funct3 = 0b000 } } },
507
508
509 // SYSTEM
510
511 .ecall => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
512 .ebreak => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b000 } } },
513
514 .csrrs => .{ .opcode = .SYSTEM, .data = .{ .f = .{ .funct3 = 0b010 } } },
515
516
517 // NONE
518
519 .unimp => .{ .opcode = .NONE, .data = .{ .f = .{ .funct3 = 0b000 } } },
520
521
522 // MISC_MEM
523
524 .fence => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .none } } },
525 .fencetso => .{ .opcode = .MISC_MEM, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .tso } } },
526
527
528 // AMO
529
530 .amoaddw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00000 } } },
531 .amoswapw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00001 } } },
532 // LR.W
533 // SC.W
534 .amoxorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00100 } } },
535 .amoandw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01100 } } },
536 .amoorw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01000 } } },
537 .amominw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10000 } } },
538 .amomaxw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10100 } } },
539 .amominuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11000 } } },
540 .amomaxuw => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11100 } } },
541
542 .amoaddd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00000 } } },
543 .amoswapd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00001 } } },
544 // LR.D
545 // SC.D
546 .amoxord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00100 } } },
547 .amoandd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01100 } } },
548 .amoord => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01000 } } },
549 .amomind => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10000 } } },
550 .amomaxd => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10100 } } },
551 .amominud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } },
552 .amomaxud => .{ .opcode = .AMO, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } },
553
554 // OP_V
555 .vsetivli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } },
556 .vsetvli => .{ .opcode = .OP_V, .data = .{ .f = .{ .funct3 = 0b111 } } },
557 .vaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } },
558 .vsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPIVV } } },
559 .vmulvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b100101, .funct3 = .OPIVV } } },
560
561 .vfaddvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPFVV } } },
562 .vfsubvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPFVV } } },
563 .vfmulvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b100100, .funct3 = .OPFVV } } },
564
565 .vadcvv => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } },
566 .vmvvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010111, .funct3 = .OPIVX } } },
567
568 .vslidedownvx => .{ .opcode = .OP_V, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b001111, .funct3 = .OPIVX } } },
569
570 // zig fmt: on
571 };
572 }
573};
574
575pub const InstEnc = enum {
576 R,
577 R4,
578 I,
579 S,
580 B,
581 U,
582 J,
583 fence,
584 amo,
585 system,
586
587 pub fn fromMnemonic(mnem: Mnemonic) InstEnc {
588 return switch (mnem) {
589 .addi,
590 .jalr,
591 .sltiu,
592 .xori,
593 .andi,
594
595 .slli,
596 .srli,
597 .srai,
598
599 .slliw,
600 .srliw,
601 .sraiw,
602
603 .ld,
604 .lw,
605 .lwu,
606 .lh,
607 .lhu,
608 .lb,
609 .lbu,
610
611 .flw,
612 .fld,
613
614 .csrrs,
615 .vsetivli,
616 .vsetvli,
617 => .I,
618
619 .lui,
620 .auipc,
621 => .U,
622
623 .sd,
624 .sw,
625 .sh,
626 .sb,
627
628 .fsd,
629 .fsw,
630 => .S,
631
632 .jal,
633 => .J,
634
635 .beq,
636 => .B,
637
638 .slt,
639 .sltu,
640
641 .sll,
642 .srl,
643 .sra,
644
645 .sllw,
646 .srlw,
647 .sraw,
648
649 .div,
650 .divu,
651 .divw,
652 .divuw,
653
654 .rem,
655 .remu,
656 .remw,
657 .remuw,
658
659 .xor,
660 .@"and",
661 .@"or",
662
663 .add,
664 .addw,
665
666 .sub,
667 .subw,
668
669 .mul,
670 .mulw,
671 .mulh,
672 .mulhu,
673 .mulhsu,
674
675 .fadds,
676 .faddd,
677
678 .fsubs,
679 .fsubd,
680
681 .fmuls,
682 .fmuld,
683
684 .fdivs,
685 .fdivd,
686
687 .fmins,
688 .fmind,
689
690 .fmaxs,
691 .fmaxd,
692
693 .fsqrts,
694 .fsqrtd,
695
696 .fles,
697 .fled,
698
699 .flts,
700 .fltd,
701
702 .feqs,
703 .feqd,
704
705 .fsgnjns,
706 .fsgnjnd,
707
708 .fsgnjxs,
709 .fsgnjxd,
710
711 .vle8v,
712 .vle16v,
713 .vle32v,
714 .vle64v,
715
716 .vse8v,
717 .vse16v,
718 .vse32v,
719 .vse64v,
720
721 .vsoxei8v,
722
723 .vaddvv,
724 .vsubvv,
725 .vmulvv,
726 .vfaddvv,
727 .vfsubvv,
728 .vfmulvv,
729 .vadcvv,
730 .vmvvx,
731 .vslidedownvx,
732
733 .clz,
734 .clzw,
735 => .R,
736
737 .ecall,
738 .ebreak,
739 .unimp,
740 => .system,
741
742 .fence,
743 .fencetso,
744 => .fence,
745
746 .amoswapw,
747 .amoaddw,
748 .amoandw,
749 .amoorw,
750 .amoxorw,
751 .amomaxw,
752 .amominw,
753 .amomaxuw,
754 .amominuw,
755
756 .amoswapd,
757 .amoaddd,
758 .amoandd,
759 .amoord,
760 .amoxord,
761 .amomaxd,
762 .amomind,
763 .amomaxud,
764 .amominud,
765 => .amo,
766 };
767 }
768
769 pub fn opsList(enc: InstEnc) [5]std.meta.FieldEnum(Operand) {
770 return switch (enc) {
771 // zig fmt: off
772 .R => .{ .reg, .reg, .reg, .none, .none, },
773 .R4 => .{ .reg, .reg, .reg, .reg, .none, },
774 .I => .{ .reg, .reg, .imm, .none, .none, },
775 .S => .{ .reg, .reg, .imm, .none, .none, },
776 .B => .{ .reg, .reg, .imm, .none, .none, },
777 .U => .{ .reg, .imm, .none, .none, .none, },
778 .J => .{ .reg, .imm, .none, .none, .none, },
779 .system => .{ .none, .none, .none, .none, .none, },
780 .fence => .{ .barrier, .barrier, .none, .none, .none, },
781 .amo => .{ .reg, .reg, .reg, .barrier, .barrier },
782 // zig fmt: on
783 };
784 }
785};
786
787pub const Data = union(InstEnc) {
788 R: packed struct {
789 opcode: u7,
790 rd: u5,
791 funct3: u3,
792 rs1: u5,
793 rs2: u5,
794 funct7: u7,
795 },
796 R4: packed struct {
797 opcode: u7,
798 rd: u5,
799 funct3: u3,
800 rs1: u5,
801 rs2: u5,
802 funct2: u2,
803 rs3: u5,
804 },
805 I: packed struct {
806 opcode: u7,
807 rd: u5,
808 funct3: u3,
809 rs1: u5,
810 imm0_11: u12,
811 },
812 S: packed struct {
813 opcode: u7,
814 imm0_4: u5,
815 funct3: u3,
816 rs1: u5,
817 rs2: u5,
818 imm5_11: u7,
819 },
820 B: packed struct {
821 opcode: u7,
822 imm11: u1,
823 imm1_4: u4,
824 funct3: u3,
825 rs1: u5,
826 rs2: u5,
827 imm5_10: u6,
828 imm12: u1,
829 },
830 U: packed struct {
831 opcode: u7,
832 rd: u5,
833 imm12_31: u20,
834 },
835 J: packed struct {
836 opcode: u7,
837 rd: u5,
838 imm12_19: u8,
839 imm11: u1,
840 imm1_10: u10,
841 imm20: u1,
842 },
843 fence: packed struct {
844 opcode: u7,
845 rd: u5 = 0,
846 funct3: u3,
847 rs1: u5 = 0,
848 succ: u4,
849 pred: u4,
850 fm: u4,
851 },
852 amo: packed struct {
853 opcode: u7,
854 rd: u5,
855 funct3: u3,
856 rs1: u5,
857 rs2: u5,
858 rl: bool,
859 aq: bool,
860 funct5: u5,
861 },
862 system: u32,
863
864 comptime {
865 for (std.meta.fields(Data)) |field| {
866 assert(@bitSizeOf(field.type) == 32);
867 }
868 }
869
870 pub fn toU32(self: Data) u32 {
871 return switch (self) {
872 .fence => |v| @as(u32, @intCast(v.opcode)) + (@as(u32, @intCast(v.rd)) << 7) + (@as(u32, @intCast(v.funct3)) << 12) + (@as(u32, @intCast(v.rs1)) << 15) + (@as(u32, @intCast(v.succ)) << 20) + (@as(u32, @intCast(v.pred)) << 24) + (@as(u32, @intCast(v.fm)) << 28),
873 inline else => |v| @bitCast(v),
874 .system => unreachable,
875 };
876 }
877
878 pub fn construct(mnem: Mnemonic, ops: []const Operand) !Data {
879 const inst_enc = InstEnc.fromMnemonic(mnem);
880 const enc = mnem.encoding();
881
882 // special mnemonics
883 switch (mnem) {
884 .ecall,
885 .ebreak,
886 .unimp,
887 => {
888 assert(ops.len == 0);
889 return .{
890 .I = .{
891 .rd = Register.zero.encodeId(),
892 .rs1 = Register.zero.encodeId(),
893 .imm0_11 = switch (mnem) {
894 .ecall => 0x000,
895 .ebreak => 0x001,
896 .unimp => 0x000,
897 else => unreachable,
898 },
899
900 .opcode = @intFromEnum(enc.opcode),
901 .funct3 = enc.data.f.funct3,
902 },
903 };
904 },
905 .csrrs => {
906 assert(ops.len == 3);
907
908 const csr = ops[0].csr;
909 const rs1 = ops[1].reg;
910 const rd = ops[2].reg;
911
912 return .{
913 .I = .{
914 .rd = rd.encodeId(),
915 .rs1 = rs1.encodeId(),
916
917 .imm0_11 = @intFromEnum(csr),
918
919 .opcode = @intFromEnum(enc.opcode),
920 .funct3 = enc.data.f.funct3,
921 },
922 };
923 },
924 else => {},
925 }
926
927 switch (inst_enc) {
928 .R => {
929 assert(ops.len == 3);
930 return .{
931 .R = switch (enc.data) {
932 .ff => |ff| .{
933 .rd = ops[0].reg.encodeId(),
934 .rs1 = ops[1].reg.encodeId(),
935 .rs2 = ops[2].reg.encodeId(),
936
937 .opcode = @intFromEnum(enc.opcode),
938 .funct3 = ff.funct3,
939 .funct7 = ff.funct7,
940 },
941 .fmt => |fmt| .{
942 .rd = ops[0].reg.encodeId(),
943 .rs1 = ops[1].reg.encodeId(),
944 .rs2 = ops[2].reg.encodeId(),
945
946 .opcode = @intFromEnum(enc.opcode),
947 .funct3 = fmt.rm,
948 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
949 },
950 .vecls => |vec| .{
951 .rd = ops[0].reg.encodeId(),
952 .rs1 = ops[1].reg.encodeId(),
953
954 .rs2 = @intFromEnum(vec.umop),
955
956 .opcode = @intFromEnum(enc.opcode),
957 .funct3 = @intFromEnum(vec.width),
958 .funct7 = (@as(u7, vec.nf) << 4) | (@as(u7, @intFromBool(vec.mew)) << 3) | (@as(u7, @intFromEnum(vec.mop)) << 1) | @intFromBool(vec.vm),
959 },
960 .vecmath => |vec| .{
961 .rd = ops[0].reg.encodeId(),
962 .rs1 = ops[1].reg.encodeId(),
963 .rs2 = ops[2].reg.encodeId(),
964
965 .opcode = @intFromEnum(enc.opcode),
966 .funct3 = @intFromEnum(vec.funct3),
967 .funct7 = (@as(u7, vec.funct6) << 1) | @intFromBool(vec.vm),
968 },
969 else => unreachable,
970 },
971 };
972 },
973 .S => {
974 assert(ops.len == 3);
975 const umm = ops[2].imm.asBits(u12);
976
977 return .{
978 .S = .{
979 .imm0_4 = @truncate(umm),
980 .rs1 = ops[0].reg.encodeId(),
981 .rs2 = ops[1].reg.encodeId(),
982 .imm5_11 = @truncate(umm >> 5),
983
984 .opcode = @intFromEnum(enc.opcode),
985 .funct3 = enc.data.f.funct3,
986 },
987 };
988 },
989 .I => {
990 assert(ops.len == 3);
991 return .{
992 .I = switch (enc.data) {
993 .f => |f| .{
994 .rd = ops[0].reg.encodeId(),
995 .rs1 = ops[1].reg.encodeId(),
996 .imm0_11 = ops[2].imm.asBits(u12),
997
998 .opcode = @intFromEnum(enc.opcode),
999 .funct3 = f.funct3,
1000 },
1001 .sh => |sh| .{
1002 .rd = ops[0].reg.encodeId(),
1003 .rs1 = ops[1].reg.encodeId(),
1004 .imm0_11 = (@as(u12, sh.typ) << 6) |
1005 if (sh.has_5) ops[2].imm.asBits(u6) else (@as(u6, 0) | ops[2].imm.asBits(u5)),
1006
1007 .opcode = @intFromEnum(enc.opcode),
1008 .funct3 = sh.funct3,
1009 },
1010 else => unreachable,
1011 },
1012 };
1013 },
1014 .U => {
1015 assert(ops.len == 2);
1016 return .{
1017 .U = .{
1018 .rd = ops[0].reg.encodeId(),
1019 .imm12_31 = ops[1].imm.asBits(u20),
1020
1021 .opcode = @intFromEnum(enc.opcode),
1022 },
1023 };
1024 },
1025 .J => {
1026 assert(ops.len == 2);
1027
1028 const umm = ops[1].imm.asBits(u21);
1029 assert(umm % 4 == 0); // misaligned jump target
1030
1031 return .{
1032 .J = .{
1033 .rd = ops[0].reg.encodeId(),
1034 .imm1_10 = @truncate(umm >> 1),
1035 .imm11 = @truncate(umm >> 11),
1036 .imm12_19 = @truncate(umm >> 12),
1037 .imm20 = @truncate(umm >> 20),
1038
1039 .opcode = @intFromEnum(enc.opcode),
1040 },
1041 };
1042 },
1043 .B => {
1044 assert(ops.len == 3);
1045
1046 const umm = ops[2].imm.asBits(u13);
1047 assert(umm % 4 == 0); // misaligned branch target
1048
1049 return .{
1050 .B = .{
1051 .rs1 = ops[0].reg.encodeId(),
1052 .rs2 = ops[1].reg.encodeId(),
1053 .imm1_4 = @truncate(umm >> 1),
1054 .imm5_10 = @truncate(umm >> 5),
1055 .imm11 = @truncate(umm >> 11),
1056 .imm12 = @truncate(umm >> 12),
1057
1058 .opcode = @intFromEnum(enc.opcode),
1059 .funct3 = enc.data.f.funct3,
1060 },
1061 };
1062 },
1063 .fence => {
1064 assert(ops.len == 2);
1065
1066 const succ = ops[0].barrier;
1067 const pred = ops[1].barrier;
1068
1069 return .{
1070 .fence = .{
1071 .succ = @intFromEnum(succ),
1072 .pred = @intFromEnum(pred),
1073
1074 .opcode = @intFromEnum(enc.opcode),
1075 .funct3 = enc.data.fence.funct3,
1076 .fm = @intFromEnum(enc.data.fence.fm),
1077 },
1078 };
1079 },
1080 .amo => {
1081 assert(ops.len == 5);
1082
1083 const rd = ops[0].reg;
1084 const rs1 = ops[1].reg;
1085 const rs2 = ops[2].reg;
1086 const rl = ops[3].barrier;
1087 const aq = ops[4].barrier;
1088
1089 return .{
1090 .amo = .{
1091 .rd = rd.encodeId(),
1092 .rs1 = rs1.encodeId(),
1093 .rs2 = rs2.encodeId(),
1094
1095 // TODO: https://github.com/ziglang/zig/issues/20113
1096 .rl = if (rl == .rl) true else false,
1097 .aq = if (aq == .aq) true else false,
1098
1099 .opcode = @intFromEnum(enc.opcode),
1100 .funct3 = @intFromEnum(enc.data.amo.width),
1101 .funct5 = enc.data.amo.funct5,
1102 },
1103 };
1104 },
1105 else => std.debug.panic("TODO: construct {s}", .{@tagName(inst_enc)}),
1106 }
1107 }
1108};
1109
1110pub fn findByMnemonic(mnem: Mnemonic, ops: []const Operand) !?Encoding {
1111 if (!verifyOps(mnem, ops)) return null;
1112
1113 return .{
1114 .mnemonic = mnem,
1115 .data = try Data.construct(mnem, ops),
1116 };
1117}
1118
1119fn verifyOps(mnem: Mnemonic, ops: []const Operand) bool {
1120 const inst_enc = InstEnc.fromMnemonic(mnem);
1121 const list = std.mem.sliceTo(&inst_enc.opsList(), .none);
1122 for (list, ops) |l, o| if (l != std.meta.activeTag(o)) return false;
1123 return true;
1124}
1125
1126const std = @import("std");
1127const assert = std.debug.assert;
1128const log = std.log.scoped(.encoding);
1129
1130const Encoding = @This();
1131const bits = @import("bits.zig");
1132const Register = bits.Register;
1133const encoder = @import("encoder.zig");
1134const Instruction = encoder.Instruction;
1135const Operand = Instruction.Operand;
1136const OperandEnum = std.meta.FieldEnum(Operand);
src/arch/riscv64/Lower.zig+447-472
...@@ -61,451 +61,427 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {...@@ -61,451 +61,427 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
61 log.debug("lowerMir {}", .{inst});61 log.debug("lowerMir {}", .{inst});
62 switch (inst.tag) {62 switch (inst.tag) {
63 else => try lower.generic(inst),63 else => try lower.generic(inst),
64 .pseudo => switch (inst.ops) {64 .pseudo_dbg_line_column,
65 .pseudo_dbg_line_column,65 .pseudo_dbg_epilogue_begin,
66 .pseudo_dbg_epilogue_begin,66 .pseudo_dbg_prologue_end,
67 .pseudo_dbg_prologue_end,67 .pseudo_dead,
68 .pseudo_dead,68 => {},
69 => {},69
7070 .pseudo_load_rm, .pseudo_store_rm => {
71 .pseudo_load_rm, .pseudo_store_rm => {71 const rm = inst.data.rm;
72 const rm = inst.data.rm;72
7373 const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs)
74 const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs)74 rm.m.toFrameLoc(lower.mir)
75 rm.m.toFrameLoc(lower.mir)75 else
76 else76 .{ .base = .s0, .disp = 0 };
77 .{ .base = .s0, .disp = 0 };77
7878 switch (inst.tag) {
79 switch (inst.ops) {79 .pseudo_load_rm => {
80 .pseudo_load_rm => {80 const dest_reg = rm.r;
81 const dest_reg = rm.r;81 const dest_reg_class = dest_reg.class();
82 const dest_reg_class = dest_reg.class();82
8383 const src_size = rm.m.mod.size;
84 const src_size = rm.m.mod.size;84 const unsigned = rm.m.mod.unsigned;
85 const unsigned = rm.m.mod.unsigned;85
8686 const mnem: Mnemonic = switch (dest_reg_class) {
87 const tag: Encoding.Mnemonic = switch (dest_reg_class) {87 .int => switch (src_size) {
88 .int => switch (src_size) {88 .byte => if (unsigned) .lbu else .lb,
89 .byte => if (unsigned) .lbu else .lb,89 .hword => if (unsigned) .lhu else .lh,
90 .hword => if (unsigned) .lhu else .lh,90 .word => if (unsigned) .lwu else .lw,
91 .word => if (unsigned) .lwu else .lw,91 .dword => .ld,
92 .dword => .ld,
93 },
94 .float => switch (src_size) {
95 .byte => unreachable, // Zig does not support 8-bit floats
96 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
97 .word => .flw,
98 .dword => .fld,
99 },
100 .vector => switch (src_size) {
101 .byte => .vle8v,
102 .hword => .vle32v,
103 .word => .vle32v,
104 .dword => .vle64v,
105 },
106 };
107
108 switch (dest_reg_class) {
109 .int, .float => {
110 try lower.emit(tag, &.{
111 .{ .reg = rm.r },
112 .{ .reg = frame_loc.base },
113 .{ .imm = Immediate.s(frame_loc.disp) },
114 });
115 },
116 .vector => {
117 assert(frame_loc.disp == 0);
118 try lower.emit(tag, &.{
119 .{ .reg = rm.r },
120 .{ .reg = frame_loc.base },
121 .{ .reg = .zero },
122 });
123 },
124 }
125 },
126 .pseudo_store_rm => {
127 const src_reg = rm.r;
128 const src_reg_class = src_reg.class();
129
130 const dest_size = rm.m.mod.size;
131
132 const tag: Encoding.Mnemonic = switch (src_reg_class) {
133 .int => switch (dest_size) {
134 .byte => .sb,
135 .hword => .sh,
136 .word => .sw,
137 .dword => .sd,
138 },
139 .float => switch (dest_size) {
140 .byte => unreachable, // Zig does not support 8-bit floats
141 .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}),
142 .word => .fsw,
143 .dword => .fsd,
144 },
145 .vector => switch (dest_size) {
146 .byte => .vse8v,
147 .hword => .vse16v,
148 .word => .vse32v,
149 .dword => .vse64v,
150 },
151 };
152
153 switch (src_reg_class) {
154 .int, .float => {
155 try lower.emit(tag, &.{
156 .{ .reg = frame_loc.base },
157 .{ .reg = rm.r },
158 .{ .imm = Immediate.s(frame_loc.disp) },
159 });
160 },
161 .vector => {
162 assert(frame_loc.disp == 0);
163 try lower.emit(tag, &.{
164 .{ .reg = rm.r },
165 .{ .reg = frame_loc.base },
166 .{ .reg = .zero },
167 });
168 },
169 }
170 },
171 else => unreachable,
172 }
173 },
174
175 .pseudo_mv => {
176 const rr = inst.data.rr;
177
178 const dst_class = rr.rd.class();
179 const src_class = rr.rs.class();
180
181 switch (src_class) {
182 .float => switch (dst_class) {
183 .float => {
184 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
185 .{ .reg = rr.rd },
186 .{ .reg = rr.rs },
187 .{ .reg = rr.rs },
188 });
189 },92 },
190 .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}),93 .float => switch (src_size) {
191 },94 .byte => unreachable, // Zig does not support 8-bit floats
192 .int => switch (dst_class) {95 .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}),
193 .int => {96 .word => .flw,
194 try lower.emit(.addi, &.{97 .dword => .fld,
195 .{ .reg = rr.rd },
196 .{ .reg = rr.rs },
197 .{ .imm = Immediate.s(0) },
198 });
199 },98 },
200 .vector => {99 .vector => switch (src_size) {
201 try lower.emit(.vmvvx, &.{100 .byte => .vle8v,
202 .{ .reg = rr.rd },101 .hword => .vle32v,
203 .{ .reg = rr.rs },102 .word => .vle32v,
204 .{ .reg = .x0 },103 .dword => .vle64v,
104 },
105 };
106
107 switch (dest_reg_class) {
108 .int, .float => {
109 try lower.emit(mnem, &.{
110 .{ .reg = rm.r },
111 .{ .reg = frame_loc.base },
112 .{ .imm = Immediate.s(frame_loc.disp) },
205 });113 });
206 },114 },
207 .float => return lower.fail("TODO: lowerMir pseudo_mv int -> {s}", .{@tagName(dst_class)}),115 .vector => {
208 },116 assert(frame_loc.disp == 0);
209 .vector => switch (dst_class) {117 try lower.emit(mnem, &.{
210 .int => {118 .{ .reg = rm.r },
211 try lower.emit(.vadcvv, &.{119 .{ .reg = frame_loc.base },
212 .{ .reg = rr.rd },
213 .{ .reg = .zero },120 .{ .reg = .zero },
214 .{ .reg = rr.rs },
215 });121 });
216 },122 },
217 .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}),123 }
218 },124 },
219 }125 .pseudo_store_rm => {
220 },126 const src_reg = rm.r;
221127 const src_reg_class = src_reg.class();
222 .pseudo_j => {128
223 try lower.emit(.jal, &.{129 const dest_size = rm.m.mod.size;
224 .{ .reg = .zero },130
225 .{ .imm = lower.reloc(.{ .inst = inst.data.inst }) },131 const mnem: Mnemonic = switch (src_reg_class) {
226 });132 .int => switch (dest_size) {
227 },133 .byte => .sb,
228134 .hword => .sh,
229 .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list),135 .word => .sw,
230 .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list),136 .dword => .sd,
231
232 .pseudo_load_symbol => {
233 const payload = inst.data.payload;
234 const data = lower.mir.extraData(Mir.LoadSymbolPayload, payload).data;
235 const dst_reg: bits.Register = @enumFromInt(data.register);
236 assert(dst_reg.class() == .int);
237
238 try lower.emit(.lui, &.{
239 .{ .reg = dst_reg },
240 .{ .imm = lower.reloc(.{
241 .load_symbol_reloc = .{
242 .atom_index = data.atom_index,
243 .sym_index = data.sym_index,
244 },
245 }) },
246 });
247
248 // the above reloc implies this one
249 try lower.emit(.addi, &.{
250 .{ .reg = dst_reg },
251 .{ .reg = dst_reg },
252 .{ .imm = Immediate.s(0) },
253 });
254 },
255
256 .pseudo_lea_rm => {
257 const rm = inst.data.rm;
258 assert(rm.r.class() == .int);
259
260 const frame: Mir.FrameLoc = if (options.allow_frame_locs)
261 rm.m.toFrameLoc(lower.mir)
262 else
263 .{ .base = .s0, .disp = 0 };
264
265 try lower.emit(.addi, &.{
266 .{ .reg = rm.r },
267 .{ .reg = frame.base },
268 .{ .imm = Immediate.s(frame.disp) },
269 });
270 },
271
272 .pseudo_fabs => {
273 const fabs = inst.data.fabs;
274 assert(fabs.rs.class() == .float and fabs.rd.class() == .float);
275
276 const mnem: Encoding.Mnemonic = switch (fabs.bits) {
277 16 => return lower.fail("TODO: airAbs Float 16", .{}),
278 32 => .fsgnjxs,
279 64 => .fsgnjxd,
280 80 => return lower.fail("TODO: airAbs Float 80", .{}),
281 128 => return lower.fail("TODO: airAbs Float 128", .{}),
282 else => unreachable,
283 };
284
285 try lower.emit(mnem, &.{
286 .{ .reg = fabs.rs },
287 .{ .reg = fabs.rd },
288 .{ .reg = fabs.rd },
289 });
290 },
291
292 .pseudo_compare => {
293 const compare = inst.data.compare;
294 const op = compare.op;
295
296 const rd = compare.rd;
297 const rs1 = compare.rs1;
298 const rs2 = compare.rs2;
299
300 const class = rs1.class();
301 const ty = compare.ty;
302 const size = std.math.ceilPowerOfTwo(u64, ty.bitSize(pt)) catch {
303 return lower.fail("pseudo_compare size {}", .{ty.bitSize(pt)});
304 };
305
306 const is_unsigned = ty.isUnsignedInt(pt.zcu);
307 const less_than: Encoding.Mnemonic = if (is_unsigned) .sltu else .slt;
308
309 switch (class) {
310 .int => switch (op) {
311 .eq => {
312 try lower.emit(.xor, &.{
313 .{ .reg = rd },
314 .{ .reg = rs1 },
315 .{ .reg = rs2 },
316 });
317
318 try lower.emit(.sltiu, &.{
319 .{ .reg = rd },
320 .{ .reg = rd },
321 .{ .imm = Immediate.s(1) },
322 });
323 },137 },
324 .neq => {138 .float => switch (dest_size) {
325 try lower.emit(.xor, &.{139 .byte => unreachable, // Zig does not support 8-bit floats
326 .{ .reg = rd },140 .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}),
327 .{ .reg = rs1 },141 .word => .fsw,
328 .{ .reg = rs2 },142 .dword => .fsd,
329 });
330
331 try lower.emit(.sltu, &.{
332 .{ .reg = rd },
333 .{ .reg = .zero },
334 .{ .reg = rd },
335 });
336 },143 },
337 .gt => {144 .vector => switch (dest_size) {
338 try lower.emit(less_than, &.{145 .byte => .vse8v,
339 .{ .reg = rd },146 .hword => .vse16v,
340 .{ .reg = rs2 },147 .word => .vse32v,
341 .{ .reg = rs1 },148 .dword => .vse64v,
342 });
343 },149 },
344 .gte => {150 };
345 try lower.emit(less_than, &.{151
346 .{ .reg = rd },152 switch (src_reg_class) {
347 .{ .reg = rs1 },153 .int, .float => {
348 .{ .reg = rs2 },154 try lower.emit(mnem, &.{
349 });155 .{ .reg = frame_loc.base },
350 try lower.emit(.xori, &.{156 .{ .reg = rm.r },
351 .{ .reg = rd },157 .{ .imm = Immediate.s(frame_loc.disp) },
352 .{ .reg = rd },
353 .{ .imm = Immediate.s(1) },
354 });158 });
355 },159 },
356 .lt => {160 .vector => {
357 try lower.emit(less_than, &.{161 assert(frame_loc.disp == 0);
358 .{ .reg = rd },162 try lower.emit(mnem, &.{
359 .{ .reg = rs1 },163 .{ .reg = rm.r },
360 .{ .reg = rs2 },164 .{ .reg = frame_loc.base },
165 .{ .reg = .zero },
361 });166 });
362 },167 },
363 .lte => {168 }
364 try lower.emit(less_than, &.{169 },
365 .{ .reg = rd },170 else => unreachable,
366 .{ .reg = rs2 },171 }
367 .{ .reg = rs1 },172 },
368 });
369173
370 try lower.emit(.xori, &.{174 .pseudo_mv => {
371 .{ .reg = rd },175 const rr = inst.data.rr;
372 .{ .reg = rd },176
373 .{ .imm = Immediate.s(1) },177 const dst_class = rr.rd.class();
374 });178 const src_class = rr.rs.class();
375 },179
180 switch (src_class) {
181 .float => switch (dst_class) {
182 .float => {
183 try lower.emit(if (lower.hasFeature(.d)) .fsgnjnd else .fsgnjns, &.{
184 .{ .reg = rr.rd },
185 .{ .reg = rr.rs },
186 .{ .reg = rr.rs },
187 });
376 },188 },
377 .float => switch (op) {189 .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}),
378 // eq190 },
379 .eq => {191 .int => switch (dst_class) {
380 try lower.emit(if (size == 64) .feqd else .feqs, &.{192 .int => {
381 .{ .reg = rd },193 try lower.emit(.addi, &.{
382 .{ .reg = rs1 },194 .{ .reg = rr.rd },
383 .{ .reg = rs2 },195 .{ .reg = rr.rs },
384 });196 .{ .imm = Immediate.s(0) },
385 },197 });
386 // !(eq)198 },
387 .neq => {199 .vector => {
388 try lower.emit(if (size == 64) .feqd else .feqs, &.{200 try lower.emit(.vmvvx, &.{
389 .{ .reg = rd },201 .{ .reg = rr.rd },
390 .{ .reg = rs1 },202 .{ .reg = rr.rs },
391 .{ .reg = rs2 },203 .{ .reg = .x0 },
392 });204 });
393 try lower.emit(.xori, &.{205 },
394 .{ .reg = rd },206 .float => return lower.fail("TODO: lowerMir pseudo_mv int -> {s}", .{@tagName(dst_class)}),
395 .{ .reg = rd },207 },
396 .{ .imm = Immediate.s(1) },208 .vector => switch (dst_class) {
397 });209 .int => {
398 },210 try lower.emit(.vadcvv, &.{
399 .lt => {211 .{ .reg = rr.rd },
400 try lower.emit(if (size == 64) .fltd else .flts, &.{212 .{ .reg = .zero },
401 .{ .reg = rd },213 .{ .reg = rr.rs },
402 .{ .reg = rs1 },214 });
403 .{ .reg = rs2 },215 },
404 });216 .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}),
405 },217 },
406 .lte => {218 }
407 try lower.emit(if (size == 64) .fled else .fles, &.{219 },
408 .{ .reg = rd },220
409 .{ .reg = rs1 },221 .pseudo_j => {
410 .{ .reg = rs2 },222 const j_type = inst.data.j_type;
411 });223 try lower.emit(.jal, &.{
412 },224 .{ .reg = j_type.rd },
413 .gt => {225 .{ .imm = lower.reloc(.{ .inst = j_type.inst }) },
414 try lower.emit(if (size == 64) .fltd else .flts, &.{226 });
415 .{ .reg = rd },227 },
416 .{ .reg = rs2 },228
417 .{ .reg = rs1 },229 .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list),
418 });230 .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list),
419 },231
420 .gte => {232 .pseudo_load_symbol => {
421 try lower.emit(if (size == 64) .fled else .fles, &.{233 const payload = inst.data.reloc;
422 .{ .reg = rd },234 const dst_reg = payload.register;
423 .{ .reg = rs2 },235 assert(dst_reg.class() == .int);
424 .{ .reg = rs1 },236
425 });237 try lower.emit(.lui, &.{
426 },238 .{ .reg = dst_reg },
239 .{ .imm = lower.reloc(.{
240 .load_symbol_reloc = .{
241 .atom_index = payload.atom_index,
242 .sym_index = payload.sym_index,
243 },
244 }) },
245 });
246
247 // the reloc above implies this one
248 try lower.emit(.addi, &.{
249 .{ .reg = dst_reg },
250 .{ .reg = dst_reg },
251 .{ .imm = Immediate.s(0) },
252 });
253 },
254
255 .pseudo_lea_rm => {
256 const rm = inst.data.rm;
257 assert(rm.r.class() == .int);
258
259 const frame: Mir.FrameLoc = if (options.allow_frame_locs)
260 rm.m.toFrameLoc(lower.mir)
261 else
262 .{ .base = .s0, .disp = 0 };
263
264 try lower.emit(.addi, &.{
265 .{ .reg = rm.r },
266 .{ .reg = frame.base },
267 .{ .imm = Immediate.s(frame.disp) },
268 });
269 },
270
271 .pseudo_compare => {
272 const compare = inst.data.compare;
273 const op = compare.op;
274
275 const rd = compare.rd;
276 const rs1 = compare.rs1;
277 const rs2 = compare.rs2;
278
279 const class = rs1.class();
280 const ty = compare.ty;
281 const size = std.math.ceilPowerOfTwo(u64, ty.bitSize(pt)) catch {
282 return lower.fail("pseudo_compare size {}", .{ty.bitSize(pt)});
283 };
284
285 const is_unsigned = ty.isUnsignedInt(pt.zcu);
286 const less_than: Mnemonic = if (is_unsigned) .sltu else .slt;
287
288 switch (class) {
289 .int => switch (op) {
290 .eq => {
291 try lower.emit(.xor, &.{
292 .{ .reg = rd },
293 .{ .reg = rs1 },
294 .{ .reg = rs2 },
295 });
296
297 try lower.emit(.sltiu, &.{
298 .{ .reg = rd },
299 .{ .reg = rd },
300 .{ .imm = Immediate.s(1) },
301 });
302 },
303 .neq => {
304 try lower.emit(.xor, &.{
305 .{ .reg = rd },
306 .{ .reg = rs1 },
307 .{ .reg = rs2 },
308 });
309
310 try lower.emit(.sltu, &.{
311 .{ .reg = rd },
312 .{ .reg = .zero },
313 .{ .reg = rd },
314 });
315 },
316 .gt => {
317 try lower.emit(less_than, &.{
318 .{ .reg = rd },
319 .{ .reg = rs2 },
320 .{ .reg = rs1 },
321 });
322 },
323 .gte => {
324 try lower.emit(less_than, &.{
325 .{ .reg = rd },
326 .{ .reg = rs1 },
327 .{ .reg = rs2 },
328 });
329 try lower.emit(.xori, &.{
330 .{ .reg = rd },
331 .{ .reg = rd },
332 .{ .imm = Immediate.s(1) },
333 });
334 },
335 .lt => {
336 try lower.emit(less_than, &.{
337 .{ .reg = rd },
338 .{ .reg = rs1 },
339 .{ .reg = rs2 },
340 });
341 },
342 .lte => {
343 try lower.emit(less_than, &.{
344 .{ .reg = rd },
345 .{ .reg = rs2 },
346 .{ .reg = rs1 },
347 });
348
349 try lower.emit(.xori, &.{
350 .{ .reg = rd },
351 .{ .reg = rd },
352 .{ .imm = Immediate.s(1) },
353 });
354 },
355 },
356 .float => switch (op) {
357 // eq
358 .eq => {
359 try lower.emit(if (size == 64) .feqd else .feqs, &.{
360 .{ .reg = rd },
361 .{ .reg = rs1 },
362 .{ .reg = rs2 },
363 });
427 },364 },
428 .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}),365 // !(eq)
429 }366 .neq => {
430 },367 try lower.emit(if (size == 64) .feqd else .feqs, &.{
431368 .{ .reg = rd },
432 .pseudo_not => {369 .{ .reg = rs1 },
433 const rr = inst.data.rr;370 .{ .reg = rs2 },
434 assert(rr.rs.class() == .int and rr.rd.class() == .int);371 });
435372 try lower.emit(.xori, &.{
436 // mask out any other bits that aren't the boolean373 .{ .reg = rd },
437 try lower.emit(.andi, &.{374 .{ .reg = rd },
438 .{ .reg = rr.rs },375 .{ .imm = Immediate.s(1) },
439 .{ .reg = rr.rs },376 });
440 .{ .imm = Immediate.s(1) },377 },
441 });378 .lt => {
442379 try lower.emit(if (size == 64) .fltd else .flts, &.{
443 try lower.emit(.sltiu, &.{380 .{ .reg = rd },
444 .{ .reg = rr.rd },381 .{ .reg = rs1 },
445 .{ .reg = rr.rs },382 .{ .reg = rs2 },
446 .{ .imm = Immediate.s(1) },383 });
447 });384 },
448 },385 .lte => {
449386 try lower.emit(if (size == 64) .fled else .fles, &.{
450 .pseudo_extern_fn_reloc => {387 .{ .reg = rd },
451 const inst_reloc = inst.data.reloc;388 .{ .reg = rs1 },
452389 .{ .reg = rs2 },
453 try lower.emit(.auipc, &.{390 });
454 .{ .reg = .ra },391 },
455 .{ .imm = lower.reloc(392 .gt => {
456 .{ .call_extern_fn_reloc = .{393 try lower.emit(if (size == 64) .fltd else .flts, &.{
457 .atom_index = inst_reloc.atom_index,394 .{ .reg = rd },
458 .sym_index = inst_reloc.sym_index,395 .{ .reg = rs2 },
459 } },396 .{ .reg = rs1 },
460 ) },397 });
461 });398 },
462399 .gte => {
463 try lower.emit(.jalr, &.{400 try lower.emit(if (size == 64) .fled else .fles, &.{
464 .{ .reg = .ra },401 .{ .reg = rd },
465 .{ .reg = .ra },402 .{ .reg = rs2 },
466 .{ .imm = Immediate.s(0) },403 .{ .reg = rs1 },
467 });404 });
468 },405 },
469406 },
470 .pseudo_amo => {407 .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}),
471 const amo = inst.data.amo;408 }
472 const is_d = amo.ty.abiSize(pt) == 8;409 },
473 const is_un = amo.ty.isUnsignedInt(pt.zcu);410
474411 .pseudo_not => {
475 const mnem: Encoding.Mnemonic = switch (amo.op) {412 const rr = inst.data.rr;
476 // zig fmt: off413 assert(rr.rs.class() == .int and rr.rd.class() == .int);
477 .SWAP => if (is_d) .amoswapd else .amoswapw,414
478 .ADD => if (is_d) .amoaddd else .amoaddw,415 // mask out any other bits that aren't the boolean
479 .AND => if (is_d) .amoandd else .amoandw,416 try lower.emit(.andi, &.{
480 .OR => if (is_d) .amoord else .amoorw,417 .{ .reg = rr.rs },
481 .XOR => if (is_d) .amoxord else .amoxorw,418 .{ .reg = rr.rs },
482 .MAX => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw,419 .{ .imm = Immediate.s(1) },
483 .MIN => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw,420 });
484 // zig fmt: on421
485 };422 try lower.emit(.sltiu, &.{
486423 .{ .reg = rr.rd },
487 try lower.emit(mnem, &.{424 .{ .reg = rr.rs },
488 .{ .reg = inst.data.amo.rd },425 .{ .imm = Immediate.s(1) },
489 .{ .reg = inst.data.amo.rs1 },426 });
490 .{ .reg = inst.data.amo.rs2 },427 },
491 .{ .barrier = inst.data.amo.rl },428
492 .{ .barrier = inst.data.amo.aq },429 .pseudo_extern_fn_reloc => {
493 });430 const inst_reloc = inst.data.reloc;
494 },431
495432 try lower.emit(.auipc, &.{
496 .pseudo_fence => {433 .{ .reg = .ra },
497 const fence = inst.data.fence;434 .{ .imm = lower.reloc(
498435 .{ .call_extern_fn_reloc = .{
499 try lower.emit(switch (fence.fm) {436 .atom_index = inst_reloc.atom_index,
500 .tso => .fencetso,437 .sym_index = inst_reloc.sym_index,
501 .none => .fence,438 } },
502 }, &.{439 ) },
503 .{ .barrier = fence.succ },440 });
504 .{ .barrier = fence.pred },441
505 });442 try lower.emit(.jalr, &.{
506 },443 .{ .reg = .ra },
507444 .{ .reg = .ra },
508 else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}),445 .{ .imm = Immediate.s(0) },
446 });
447 },
448
449 .pseudo_amo => {
450 const amo = inst.data.amo;
451 const is_d = amo.ty.abiSize(pt) == 8;
452 const is_un = amo.ty.isUnsignedInt(pt.zcu);
453
454 const mnem: Mnemonic = switch (amo.op) {
455 // zig fmt: off
456 .SWAP => if (is_d) .amoswapd else .amoswapw,
457 .ADD => if (is_d) .amoaddd else .amoaddw,
458 .AND => if (is_d) .amoandd else .amoandw,
459 .OR => if (is_d) .amoord else .amoorw,
460 .XOR => if (is_d) .amoxord else .amoxorw,
461 .MAX => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw,
462 .MIN => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw,
463 // zig fmt: on
464 };
465
466 try lower.emit(mnem, &.{
467 .{ .reg = inst.data.amo.rd },
468 .{ .reg = inst.data.amo.rs1 },
469 .{ .reg = inst.data.amo.rs2 },
470 .{ .barrier = inst.data.amo.rl },
471 .{ .barrier = inst.data.amo.aq },
472 });
473 },
474
475 .pseudo_fence => {
476 const fence = inst.data.fence;
477
478 try lower.emit(switch (fence.fm) {
479 .tso => .fencetso,
480 .none => .fence,
481 }, &.{
482 .{ .barrier = fence.succ },
483 .{ .barrier = fence.pred },
484 });
509 },485 },
510 }486 }
511487
...@@ -516,49 +492,46 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {...@@ -516,49 +492,46 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct {
516}492}
517493
518fn generic(lower: *Lower, inst: Mir.Inst) Error!void {494fn generic(lower: *Lower, inst: Mir.Inst) Error!void {
519 const mnemonic = std.meta.stringToEnum(Encoding.Mnemonic, @tagName(inst.tag)) orelse {495 const mnemonic = inst.tag;
520 return lower.fail("generic inst name '{s}' with op {s} doesn't match with a mnemonic", .{496 try lower.emit(mnemonic, switch (inst.data) {
521 @tagName(inst.tag),
522 @tagName(inst.ops),
523 });
524 };
525 try lower.emit(mnemonic, switch (inst.ops) {
526 .none => &.{},497 .none => &.{},
527 .ri => &.{498 .u_type => |u| &.{
528 .{ .reg = inst.data.u_type.rd },499 .{ .reg = u.rd },
529 .{ .imm = inst.data.u_type.imm20 },500 .{ .imm = u.imm20 },
530 },501 },
531 .rr => &.{502 .i_type => |i| &.{
532 .{ .reg = inst.data.rr.rd },503 .{ .reg = i.rd },
533 .{ .reg = inst.data.rr.rs },504 .{ .reg = i.rs1 },
505 .{ .imm = i.imm12 },
534 },506 },
535 .rri => &.{507 .rr => |rr| &.{
536 .{ .reg = inst.data.i_type.rd },508 .{ .reg = rr.rd },
537 .{ .reg = inst.data.i_type.rs1 },509 .{ .reg = rr.rs },
538 .{ .imm = inst.data.i_type.imm12 },
539 },510 },
540 .rr_inst => &.{511 .b_type => |b| &.{
541 .{ .reg = inst.data.b_type.rs1 },512 .{ .reg = b.rs1 },
542 .{ .reg = inst.data.b_type.rs2 },513 .{ .reg = b.rs2 },
543 .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) },514 .{ .imm = lower.reloc(.{ .inst = b.inst }) },
544 },515 },
545 .rrr => &.{516 .r_type => |r| &.{
546 .{ .reg = inst.data.r_type.rd },517 .{ .reg = r.rd },
547 .{ .reg = inst.data.r_type.rs1 },518 .{ .reg = r.rs1 },
548 .{ .reg = inst.data.r_type.rs2 },519 .{ .reg = r.rs2 },
549 },520 },
550 .csr => &.{521 .csr => |csr| &.{
551 .{ .csr = inst.data.csr.csr },522 .{ .csr = csr.csr },
552 .{ .reg = inst.data.csr.rs1 },523 .{ .reg = csr.rs1 },
553 .{ .reg = inst.data.csr.rd },524 .{ .reg = csr.rd },
554 },525 },
555 else => return lower.fail("TODO: generic lower ops {s}", .{@tagName(inst.ops)}),526 else => return lower.fail("TODO: generic lower {s}", .{@tagName(mnemonic)}),
556 });527 });
557}528}
558529
559fn emit(lower: *Lower, mnemonic: Encoding.Mnemonic, ops: []const Instruction.Operand) !void {530fn emit(lower: *Lower, mnemonic: Mnemonic, ops: []const Instruction.Operand) !void {
560 lower.result_insts[lower.result_insts_len] =531 const lir = encoding.Lir.fromMnem(mnemonic);
561 try Instruction.new(mnemonic, ops);532 const inst = Instruction.fromLir(lir, ops);
533
534 lower.result_insts[lower.result_insts_len] = inst;
562 lower.result_insts_len += 1;535 lower.result_insts_len += 1;
563}536}
564537
...@@ -580,7 +553,7 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register...@@ -580,7 +553,7 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register
580 const reg = abi.Registers.all_preserved[i];553 const reg = abi.Registers.all_preserved[i];
581554
582 const reg_class = reg.class();555 const reg_class = reg.class();
583 const load_inst: Encoding.Mnemonic, const store_inst: Encoding.Mnemonic = switch (reg_class) {556 const load_inst: Mnemonic, const store_inst: Mnemonic = switch (reg_class) {
584 .int => .{ .ld, .sd },557 .int => .{ .ld, .sd },
585 .float => .{ .fld, .fsd },558 .float => .{ .fld, .fsd },
586 .vector => unreachable,559 .vector => unreachable,
...@@ -618,20 +591,22 @@ fn hasFeature(lower: *Lower, feature: std.Target.riscv.Feature) bool {...@@ -618,20 +591,22 @@ fn hasFeature(lower: *Lower, feature: std.Target.riscv.Feature) bool {
618}591}
619592
620const Lower = @This();593const Lower = @This();
621
622const abi = @import("abi.zig");
623const assert = std.debug.assert;
624const bits = @import("bits.zig");
625const encoder = @import("encoder.zig");
626const link = @import("../../link.zig");
627const Encoding = @import("Encoding.zig");
628const std = @import("std");594const std = @import("std");
595const assert = std.debug.assert;
629const log = std.log.scoped(.lower);596const log = std.log.scoped(.lower);
630597
631const Air = @import("../../Air.zig");
632const Allocator = std.mem.Allocator;598const Allocator = std.mem.Allocator;
633const ErrorMsg = Zcu.ErrorMsg;599const ErrorMsg = Zcu.ErrorMsg;
634const Mir = @import("Mir.zig");600
601const link = @import("../../link.zig");
602const Air = @import("../../Air.zig");
635const Zcu = @import("../../Zcu.zig");603const Zcu = @import("../../Zcu.zig");
636const Instruction = encoder.Instruction;604
605const Mir = @import("Mir.zig");
606const abi = @import("abi.zig");
607const bits = @import("bits.zig");
608const encoding = @import("encoding.zig");
609
610const Mnemonic = @import("mnem.zig").Mnemonic;
637const Immediate = bits.Immediate;611const Immediate = bits.Immediate;
612const Instruction = encoding.Instruction;
src/arch/riscv64/Mir.zig+19-281
...@@ -1,170 +1,17 @@...@@ -1,170 +1,17 @@
1//! Machine Intermediate Representation.1//! Machine Intermediate Representation.
2//! This data is produced by RISCV64 Codegen or RISCV64 assembly parsing2//! This data is produced by CodeGen.zig
3//! These instructions have a 1:1 correspondence with machine code instructions
4//! for the target. MIR can be lowered to source-annotated textual assembly code
5//! instructions, or it can be lowered to machine code.
6//! The main purpose of MIR is to postpone the assignment of offsets until Isel,
7//! so that, for example, the smaller encodings of jump instructions can be used.
83
9instructions: std.MultiArrayList(Inst).Slice,4instructions: std.MultiArrayList(Inst).Slice,
10/// The meaning of this data is determined by `Inst.Tag` value.
11extra: []const u32,
12frame_locs: std.MultiArrayList(FrameLoc).Slice,5frame_locs: std.MultiArrayList(FrameLoc).Slice,
136
14pub const Inst = struct {7pub const Inst = struct {
15 tag: Tag,8 tag: Mnemonic,
16 data: Data,9 data: Data,
17 ops: Ops,
1810
19 /// The position of an MIR instruction within the `Mir` instructions array.
20 pub const Index = u32;11 pub const Index = u32;
2112
22 pub const Tag = enum(u16) {13 pub const Data = union(enum) {
2314 none: void,
24 // base extension
25 addi,
26 addiw,
27
28 jalr,
29 lui,
30
31 @"and",
32 andi,
33
34 xori,
35 xor,
36 @"or",
37
38 ebreak,
39 ecall,
40 unimp,
41
42 add,
43 addw,
44 sub,
45 subw,
46
47 sltu,
48 slt,
49
50 slli,
51 srli,
52 srai,
53
54 slliw,
55 srliw,
56 sraiw,
57
58 sll,
59 srl,
60 sra,
61
62 sllw,
63 srlw,
64 sraw,
65
66 jal,
67
68 beq,
69 bne,
70
71 nop,
72
73 ld,
74 lw,
75 lh,
76 lb,
77
78 sd,
79 sw,
80 sh,
81 sb,
82
83 // M extension
84 mul,
85 mulw,
86
87 div,
88 divu,
89 divw,
90 divuw,
91
92 rem,
93 remu,
94 remw,
95 remuw,
96
97 // F extension (32-bit float)
98 fadds,
99 fsubs,
100 fmuls,
101 fdivs,
102
103 fabss,
104
105 fmins,
106 fmaxs,
107
108 fsqrts,
109
110 flw,
111 fsw,
112
113 feqs,
114 flts,
115 fles,
116
117 // D extension (64-bit float)
118 faddd,
119 fsubd,
120 fmuld,
121 fdivd,
122
123 fabsd,
124
125 fmind,
126 fmaxd,
127
128 fsqrtd,
129
130 fld,
131 fsd,
132
133 feqd,
134 fltd,
135 fled,
136
137 // Zicsr Extension Instructions
138 csrrs,
139
140 // V Extension Instructions
141 vsetvli,
142 vsetivli,
143 vsetvl,
144 vaddvv,
145 vfaddvv,
146 vsubvv,
147 vfsubvv,
148 vmulvv,
149 vfmulvv,
150 vslidedownvx,
151
152 // Zbb Extension Instructions
153 clz,
154 clzw,
155
156 /// A pseudo-instruction. Used for anything that isn't 1:1 with an
157 /// assembly instruction.
158 pseudo,
159 };
160
161 /// All instructions have a 4-byte payload, which is contained within
162 /// this union. `Ops` determines which union field is active, as well as
163 /// how to interpret the data within.
164 pub const Data = union {
165 nop: void,
166 inst: Index,
167 payload: u32,
168 r_type: struct {15 r_type: struct {
169 rd: Register,16 rd: Register,
170 rs1: Register,17 rs1: Register,
...@@ -194,10 +41,6 @@ pub const Inst = struct {...@@ -194,10 +41,6 @@ pub const Inst = struct {
194 rd: Register,41 rd: Register,
195 inst: Inst.Index,42 inst: Inst.Index,
196 },43 },
197 pseudo_dbg_line_column: struct {
198 line: u32,
199 column: u32,
200 },
201 rm: struct {44 rm: struct {
202 r: Register,45 r: Register,
203 m: Memory,46 m: Memory,
...@@ -208,11 +51,6 @@ pub const Inst = struct {...@@ -208,11 +51,6 @@ pub const Inst = struct {
208 rd: Register,51 rd: Register,
209 rs: Register,52 rs: Register,
210 },53 },
211 fabs: struct {
212 rd: Register,
213 rs: Register,
214 bits: u16,
215 },
216 compare: struct {54 compare: struct {
217 rd: Register,55 rd: Register,
218 rs1: Register,56 rs1: Register,
...@@ -228,6 +66,7 @@ pub const Inst = struct {...@@ -228,6 +66,7 @@ pub const Inst = struct {
228 ty: Type,66 ty: Type,
229 },67 },
230 reloc: struct {68 reloc: struct {
69 register: Register,
231 atom_index: u32,70 atom_index: u32,
232 sym_index: u32,71 sym_index: u32,
233 },72 },
...@@ -253,115 +92,26 @@ pub const Inst = struct {...@@ -253,115 +92,26 @@ pub const Inst = struct {
253 rs1: Register,92 rs1: Register,
254 rd: Register,93 rd: Register,
255 },94 },
256 };95 pseudo_dbg_line_column: struct {
25796 line: u32,
258 pub const Ops = enum {97 column: u32,
259 /// No data associated with this instruction (only mnemonic is used).98 },
260 none,
261 /// Two registers
262 rr,
263 /// Three registers
264 rrr,
265
266 /// Two registers + immediate, uses the i_type payload.
267 rri,
268 //extern_fn_reloc/ Two registers + another instruction.
269 rr_inst,
270
271 /// Register + Memory
272 rm,
273
274 /// Register + Immediate
275 ri,
276
277 /// Another instruction.
278 inst,
279
280 /// Control and Status Register Instruction.
281 csr,
282
283 /// Pseudo-instruction that will generate a backpatched
284 /// function prologue.
285 pseudo_prologue,
286 /// Pseudo-instruction that will generate a backpatched
287 /// function epilogue
288 pseudo_epilogue,
289
290 /// Pseudo-instruction: End of prologue
291 pseudo_dbg_prologue_end,
292 /// Pseudo-instruction: Beginning of epilogue
293 pseudo_dbg_epilogue_begin,
294 /// Pseudo-instruction: Update debug line
295 pseudo_dbg_line_column,
296
297 /// Pseudo-instruction that loads from memory into a register.
298 ///
299 /// Uses `rm` payload.
300 pseudo_load_rm,
301 /// Pseudo-instruction that stores from a register into memory
302 ///
303 /// Uses `rm` payload.
304 pseudo_store_rm,
305
306 /// Pseudo-instruction that loads the address of memory into a register.
307 ///
308 /// Uses `rm` payload.
309 pseudo_lea_rm,
310
311 /// Jumps. Uses `inst` payload.
312 pseudo_j,
313
314 /// Floating point absolute value.
315 pseudo_fabs,
316
317 /// Dead inst, ignored by the emitter.
318 pseudo_dead,
319
320 /// Loads the address of a value that hasn't yet been allocated in memory.
321 ///
322 /// uses the Mir.LoadSymbolPayload payload.
323 pseudo_load_symbol,
324
325 /// Moves the value of rs1 to rd.
326 ///
327 /// uses the `rr` payload.
328 pseudo_mv,
329
330 pseudo_restore_regs,
331 pseudo_spill_regs,
332
333 pseudo_compare,
334
335 /// NOT operation on booleans. Does an `andi reg, reg, 1` to mask out any other bits from the boolean.
336 pseudo_not,
337
338 /// Generates an auipc + jalr pair, with a R_RISCV_CALL_PLT reloc
339 pseudo_extern_fn_reloc,
340
341 /// IORW, IORW
342 pseudo_fence,
343
344 /// Ordering, Src, Addr, Dest
345 pseudo_amo,
346 };99 };
347100
348 pub fn format(101 pub fn format(
349 inst: Inst,102 inst: Inst,
350 comptime fmt: []const u8,103 comptime fmt: []const u8,
351 options: std.fmt.FormatOptions,104 _: std.fmt.FormatOptions,
352 writer: anytype,105 writer: anytype,
353 ) !void {106 ) !void {
354 assert(fmt.len == 0);107 assert(fmt.len == 0);
355 _ = options;108 try writer.print("Tag: {s}, Data: {s}", .{ @tagName(inst.tag), @tagName(inst.data) });
356
357 try writer.print("Tag: {s}, Ops: {s}", .{ @tagName(inst.tag), @tagName(inst.ops) });
358 }109 }
359};110};
360111
361pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {112pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
362 mir.instructions.deinit(gpa);113 mir.instructions.deinit(gpa);
363 mir.frame_locs.deinit(gpa);114 mir.frame_locs.deinit(gpa);
364 gpa.free(mir.extra);
365 mir.* = undefined;115 mir.* = undefined;
366}116}
367117
...@@ -392,25 +142,12 @@ pub const AmoOp = enum(u5) {...@@ -392,25 +142,12 @@ pub const AmoOp = enum(u5) {
392 MIN,142 MIN,
393};143};
394144
395/// Returns the requested data, as well as the new index which is at the start of the145pub const FcvtOp = enum(u5) {
396/// trailers for the object.146 w = 0b00000,
397pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } {147 wu = 0b00001,
398 const fields = std.meta.fields(T);148 l = 0b00010,
399 var i: usize = index;149 lu = 0b00011,
400 var result: T = undefined;150};
401 inline for (fields) |field| {
402 @field(result, field.name) = switch (field.type) {
403 u32 => mir.extra[i],
404 i32 => @as(i32, @bitCast(mir.extra[i])),
405 else => @compileError("bad field type"),
406 };
407 i += 1;
408 }
409 return .{
410 .data = result,
411 .end = i,
412 };
413}
414151
415pub const LoadSymbolPayload = struct {152pub const LoadSymbolPayload = struct {
416 register: u32,153 register: u32,
...@@ -459,10 +196,10 @@ const Mir = @This();...@@ -459,10 +196,10 @@ const Mir = @This();
459const std = @import("std");196const std = @import("std");
460const builtin = @import("builtin");197const builtin = @import("builtin");
461const Type = @import("../../Type.zig");198const Type = @import("../../Type.zig");
199const bits = @import("bits.zig");
462200
463const assert = std.debug.assert;201const assert = std.debug.assert;
464202
465const bits = @import("bits.zig");
466const Register = bits.Register;203const Register = bits.Register;
467const CSR = bits.CSR;204const CSR = bits.CSR;
468const Immediate = bits.Immediate;205const Immediate = bits.Immediate;
...@@ -470,3 +207,4 @@ const Memory = bits.Memory;...@@ -470,3 +207,4 @@ const Memory = bits.Memory;
470const FrameIndex = bits.FrameIndex;207const FrameIndex = bits.FrameIndex;
471const FrameAddr = @import("CodeGen.zig").FrameAddr;208const FrameAddr = @import("CodeGen.zig").FrameAddr;
472const IntegerBitSet = std.bit_set.IntegerBitSet;209const IntegerBitSet = std.bit_set.IntegerBitSet;
210const Mnemonic = @import("mnem.zig").Mnemonic;
src/arch/riscv64/bits.zig+1-2
...@@ -5,7 +5,6 @@ const testing = std.testing;...@@ -5,7 +5,6 @@ const testing = std.testing;
5const Target = std.Target;5const Target = std.Target;
66
7const Zcu = @import("../../Zcu.zig");7const Zcu = @import("../../Zcu.zig");
8const Encoding = @import("Encoding.zig");
9const Mir = @import("Mir.zig");8const Mir = @import("Mir.zig");
10const abi = @import("abi.zig");9const abi = @import("abi.zig");
1110
...@@ -193,7 +192,7 @@ pub const Register = enum(u8) {...@@ -193,7 +192,7 @@ pub const Register = enum(u8) {
193 /// The goal of this function is to return the same ID for `zero` and `x0` but two192 /// The goal of this function is to return the same ID for `zero` and `x0` but two
194 /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers193 /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers
195 /// and is repeated twice, once for the named version, once for the number version.194 /// and is repeated twice, once for the named version, once for the number version.
196 pub fn id(reg: Register) u8 {195 pub fn id(reg: Register) std.math.IntFittingRange(0, @typeInfo(Register).Enum.fields.len) {
197 const base = switch (@intFromEnum(reg)) {196 const base = switch (@intFromEnum(reg)) {
198 // zig fmt: off197 // zig fmt: off
199 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero),198 @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero),
src/arch/riscv64/encoder.zig deleted-80
...@@ -1,80 +0,0 @@
1pub const Instruction = struct {
2 encoding: Encoding,
3 ops: [5]Operand = .{.none} ** 5,
4
5 pub const Operand = union(enum) {
6 none,
7 reg: Register,
8 csr: CSR,
9 mem: Memory,
10 imm: Immediate,
11 barrier: Mir.Barrier,
12 };
13
14 pub fn new(mnemonic: Encoding.Mnemonic, ops: []const Operand) !Instruction {
15 const encoding = (try Encoding.findByMnemonic(mnemonic, ops)) orelse {
16 std.log.err("no encoding found for: {s} [{s} {s} {s} {s} {s}]", .{
17 @tagName(mnemonic),
18 @tagName(if (ops.len > 0) ops[0] else .none),
19 @tagName(if (ops.len > 1) ops[1] else .none),
20 @tagName(if (ops.len > 2) ops[2] else .none),
21 @tagName(if (ops.len > 3) ops[3] else .none),
22 @tagName(if (ops.len > 4) ops[4] else .none),
23 });
24 return error.InvalidInstruction;
25 };
26
27 var result_ops: [5]Operand = .{.none} ** 5;
28 @memcpy(result_ops[0..ops.len], ops);
29
30 return .{
31 .encoding = encoding,
32 .ops = result_ops,
33 };
34 }
35
36 pub fn encode(inst: Instruction, writer: anytype) !void {
37 try writer.writeInt(u32, inst.encoding.data.toU32(), .little);
38 }
39
40 pub fn format(
41 inst: Instruction,
42 comptime fmt: []const u8,
43 _: std.fmt.FormatOptions,
44 writer: anytype,
45 ) !void {
46 std.debug.assert(fmt.len == 0);
47
48 const encoding = inst.encoding;
49
50 try writer.print("{s} ", .{@tagName(encoding.mnemonic)});
51
52 var i: u32 = 0;
53 while (i < inst.ops.len and inst.ops[i] != .none) : (i += 1) {
54 if (i != inst.ops.len and i != 0) try writer.writeAll(", ");
55
56 switch (@as(Instruction.Operand, inst.ops[i])) {
57 .none => unreachable, // it's sliced out above
58 .reg => |reg| try writer.writeAll(@tagName(reg)),
59 .imm => |imm| try writer.print("{d}", .{imm.asSigned(64)}),
60 .mem => try writer.writeAll("mem"),
61 .barrier => |barrier| try writer.writeAll(@tagName(barrier)),
62 .csr => |csr| try writer.writeAll(@tagName(csr)),
63 }
64 }
65 }
66};
67
68const std = @import("std");
69
70const Lower = @import("Lower.zig");
71const Mir = @import("Mir.zig");
72const bits = @import("bits.zig");
73const Encoding = @import("Encoding.zig");
74
75const Register = bits.Register;
76const CSR = bits.CSR;
77const Memory = bits.Memory;
78const Immediate = bits.Immediate;
79
80const log = std.log.scoped(.encode);
src/arch/riscv64/encoding.zig created+716
...@@ -0,0 +1,716 @@
1//! This file is responsible for going from MIR, which is emitted by CodeGen
2//! and converting it into Instructions, which can be used as needed.
3//!
4//! Here we encode how mnemonics relate to opcodes and where their operands go.
5
6/// Lower Instruction Representation
7///
8/// This format encodes a specific instruction, however it's still abstracted
9/// away from the true encoding it'll be in. It's meant to make the process of
10/// indicating unique encoding data easier.
11pub const Lir = struct {
12 opcode: OpCode,
13 format: Format,
14 data: Data,
15
16 pub const Format = enum {
17 R,
18 I,
19 S,
20 B,
21 U,
22 J,
23 extra,
24 };
25
26 const Data = union(enum) {
27 none,
28 f: struct { funct3: u3 },
29 ff: struct {
30 funct3: u3,
31 funct7: u7,
32 },
33 sh: struct {
34 typ: u6,
35 funct3: u3,
36 has_5: bool,
37 },
38
39 fmt: struct {
40 funct5: u5,
41 rm: u3,
42 fmt: FpFmt,
43 },
44 fcvt: struct {
45 funct5: u5,
46 rm: u3,
47 fmt: FpFmt,
48 width: Mir.FcvtOp,
49 },
50
51 vecls: struct {
52 width: VecWidth,
53 umop: Umop,
54 vm: bool,
55 mop: Mop,
56 mew: bool,
57 nf: u3,
58 },
59 vecmath: struct {
60 vm: bool,
61 funct6: u6,
62 funct3: VecType,
63 },
64
65 amo: struct {
66 funct5: u5,
67 width: AmoWidth,
68 },
69 fence: struct {
70 funct3: u3,
71 fm: FenceMode,
72 },
73
74 /// the mnemonic has some special properities that can't be handled in a generic fashion
75 extra: Mnemonic,
76 };
77
78 const OpCode = enum(u7) {
79 LOAD = 0b0000011,
80 LOAD_FP = 0b0000111,
81 MISC_MEM = 0b0001111,
82 OP_IMM = 0b0010011,
83 AUIPC = 0b0010111,
84 OP_IMM_32 = 0b0011011,
85 STORE = 0b0100011,
86 STORE_FP = 0b0100111,
87 AMO = 0b0101111,
88 OP_V = 0b1010111,
89 OP = 0b0110011,
90 OP_32 = 0b0111011,
91 LUI = 0b0110111,
92 MADD = 0b1000011,
93 MSUB = 0b1000111,
94 NMSUB = 0b1001011,
95 NMADD = 0b1001111,
96 OP_FP = 0b1010011,
97 OP_IMM_64 = 0b1011011,
98 BRANCH = 0b1100011,
99 JALR = 0b1100111,
100 JAL = 0b1101111,
101 SYSTEM = 0b1110011,
102 OP_64 = 0b1111011,
103 NONE = 0b00000000,
104 };
105
106 const FpFmt = enum(u2) {
107 /// 32-bit single-precision
108 S = 0b00,
109 /// 64-bit double-precision
110 D = 0b01,
111
112 // H = 0b10, unused in the G extension
113
114 /// 128-bit quad-precision
115 Q = 0b11,
116 };
117
118 const AmoWidth = enum(u3) {
119 W = 0b010,
120 D = 0b011,
121 };
122
123 const FenceMode = enum(u4) {
124 none = 0b0000,
125 tso = 0b1000,
126 };
127
128 const Mop = enum(u2) {
129 // zig fmt: off
130 unit = 0b00,
131 unord = 0b01,
132 stride = 0b10,
133 ord = 0b11,
134 // zig fmt: on
135 };
136
137 const Umop = enum(u5) {
138 // zig fmt: off
139 unit = 0b00000,
140 whole = 0b01000,
141 mask = 0b01011,
142 fault = 0b10000,
143 // zig fmt: on
144 };
145
146 const VecWidth = enum(u3) {
147 // zig fmt: off
148 @"8" = 0b000,
149 @"16" = 0b101,
150 @"32" = 0b110,
151 @"64" = 0b111,
152 // zig fmt: on
153 };
154
155 const VecType = enum(u3) {
156 OPIVV = 0b000,
157 OPFVV = 0b001,
158 OPMVV = 0b010,
159 OPIVI = 0b011,
160 OPIVX = 0b100,
161 OPFVF = 0b101,
162 OPMVX = 0b110,
163 };
164
165 pub fn fromMnem(mnem: Mnemonic) Lir {
166 return switch (mnem) {
167 // zig fmt: off
168
169 // OP
170 .add => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
171 .sub => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
172
173 .@"and" => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000000 } } },
174 .@"or" => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000000 } } },
175 .xor => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000000 } } },
176
177 .sltu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000000 } } },
178 .slt => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000000 } } },
179
180 .mul => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
181 .mulh => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000001 } } },
182 .mulhsu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b010, .funct7 = 0b0000001 } } },
183 .mulhu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b011, .funct7 = 0b0000001 } } },
184
185 .div => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
186 .divu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
187
188 .rem => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
189 .remu => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
190
191 .sll => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
192 .srl => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
193 .sra => .{ .opcode = .OP, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
194
195
196 // OP_IMM
197
198 .addi => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .f = .{ .funct3 = 0b000 } } },
199 .andi => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .f = .{ .funct3 = 0b111 } } },
200 .xori => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .f = .{ .funct3 = 0b100 } } },
201
202 .sltiu => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .f = .{ .funct3 = 0b011 } } },
203
204 .slli => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = true } } },
205 .srli => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = true } } },
206 .srai => .{ .opcode = .OP_IMM, .format = .I, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = true } } },
207
208 .clz => .{ .opcode = .OP_IMM, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
209
210 // OP_IMM_32
211
212 .slliw => .{ .opcode = .OP_IMM_32, .format = .I, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b001, .has_5 = false } } },
213 .srliw => .{ .opcode = .OP_IMM_32, .format = .I, .data = .{ .sh = .{ .typ = 0b000000, .funct3 = 0b101, .has_5 = false } } },
214 .sraiw => .{ .opcode = .OP_IMM_32, .format = .I, .data = .{ .sh = .{ .typ = 0b010000, .funct3 = 0b101, .has_5 = false } } },
215
216 .clzw => .{ .opcode = .OP_IMM_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0110000 } } },
217
218 // OP_32
219
220 .addw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000000 } } },
221 .subw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0100000 } } },
222 .mulw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b000, .funct7 = 0b0000001 } } },
223
224 .divw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b100, .funct7 = 0b0000001 } } },
225 .divuw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000001 } } },
226
227 .remw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b110, .funct7 = 0b0000001 } } },
228 .remuw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b111, .funct7 = 0b0000001 } } },
229
230 .sllw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b001, .funct7 = 0b0000000 } } },
231 .srlw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0000000 } } },
232 .sraw => .{ .opcode = .OP_32, .format = .R, .data = .{ .ff = .{ .funct3 = 0b101, .funct7 = 0b0100000 } } },
233
234
235 // OP_FP
236
237 .fadds => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .S, .rm = 0b111 } } },
238 .faddd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00000, .fmt = .D, .rm = 0b111 } } },
239
240 .fsubs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .S, .rm = 0b111 } } },
241 .fsubd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00001, .fmt = .D, .rm = 0b111 } } },
242
243 .fmuls => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .S, .rm = 0b111 } } },
244 .fmuld => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00010, .fmt = .D, .rm = 0b111 } } },
245
246 .fdivs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .S, .rm = 0b111 } } },
247 .fdivd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00011, .fmt = .D, .rm = 0b111 } } },
248
249 .fmins => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b000 } } },
250 .fmind => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b000 } } },
251
252 .fmaxs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .S, .rm = 0b001 } } },
253 .fmaxd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00101, .fmt = .D, .rm = 0b001 } } },
254
255 .fsqrts => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .S, .rm = 0b111 } } },
256 .fsqrtd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b01011, .fmt = .D, .rm = 0b111 } } },
257
258 .fles => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b000 } } },
259 .fled => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b000 } } },
260
261 .flts => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b001 } } },
262 .fltd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b001 } } },
263
264 .feqs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .S, .rm = 0b010 } } },
265 .feqd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b10100, .fmt = .D, .rm = 0b010 } } },
266
267 .fsgnjns => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b000 } } },
268 .fsgnjnd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b000 } } },
269
270 .fsgnjxs => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .S, .rm = 0b010 } } },
271 .fsgnjxd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fmt = .{ .funct5 = 0b00100, .fmt = .D, .rm = 0b010 } } },
272
273 .fcvtws => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .S, .rm = 0b111, .width = .w } } },
274 .fcvtwus => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .S, .rm = 0b111, .width = .wu } } },
275 .fcvtls => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .S, .rm = 0b111, .width = .l } } },
276 .fcvtlus => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .S, .rm = 0b111, .width = .lu } } },
277
278 .fcvtwd => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .w } } },
279 .fcvtwud => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .wu } } },
280 .fcvtld => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .l } } },
281 .fcvtlud => .{ .opcode = .OP_FP, .format = .R, .data = .{ .fcvt = .{ .funct5 = 0b11000, .fmt = .D, .rm = 0b111, .width = .lu } } },
282
283 // LOAD
284
285 .lb => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b000 } } },
286 .lh => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b001 } } },
287 .lw => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b010 } } },
288 .ld => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b011 } } },
289 .lbu => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b100 } } },
290 .lhu => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b101 } } },
291 .lwu => .{ .opcode = .LOAD, .format = .I, .data = .{ .f = .{ .funct3 = 0b110 } } },
292
293
294 // STORE
295
296 .sb => .{ .opcode = .STORE, .format = .S, .data = .{ .f = .{ .funct3 = 0b000 } } },
297 .sh => .{ .opcode = .STORE, .format = .S, .data = .{ .f = .{ .funct3 = 0b001 } } },
298 .sw => .{ .opcode = .STORE, .format = .S, .data = .{ .f = .{ .funct3 = 0b010 } } },
299 .sd => .{ .opcode = .STORE, .format = .S, .data = .{ .f = .{ .funct3 = 0b011 } } },
300
301
302 // LOAD_FP
303
304 .flw => .{ .opcode = .LOAD_FP, .format = .I, .data = .{ .f = .{ .funct3 = 0b010 } } },
305 .fld => .{ .opcode = .LOAD_FP, .format = .I, .data = .{ .f = .{ .funct3 = 0b011 } } },
306
307 .vle8v => .{ .opcode = .LOAD_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
308 .vle16v => .{ .opcode = .LOAD_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
309 .vle32v => .{ .opcode = .LOAD_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
310 .vle64v => .{ .opcode = .LOAD_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
311
312
313 // STORE_FP
314
315 .fsw => .{ .opcode = .STORE_FP, .format = .S, .data = .{ .f = .{ .funct3 = 0b010 } } },
316 .fsd => .{ .opcode = .STORE_FP, .format = .S, .data = .{ .f = .{ .funct3 = 0b011 } } },
317
318 .vse8v => .{ .opcode = .STORE_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"8", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
319 .vse16v => .{ .opcode = .STORE_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"16", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
320 .vse32v => .{ .opcode = .STORE_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"32", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
321 .vse64v => .{ .opcode = .STORE_FP, .format = .R, .data = .{ .vecls = .{ .width = .@"64", .umop = .unit, .vm = true, .mop = .unit, .mew = false, .nf = 0b000 } } },
322
323 // JALR
324
325 .jalr => .{ .opcode = .JALR, .format = .I, .data = .{ .f = .{ .funct3 = 0b000 } } },
326
327
328 // LUI
329
330 .lui => .{ .opcode = .LUI, .format = .U, .data = .{ .none = {} } },
331
332
333 // AUIPC
334
335 .auipc => .{ .opcode = .AUIPC, .format = .U, .data = .{ .none = {} } },
336
337
338 // JAL
339
340 .jal => .{ .opcode = .JAL, .format = .J, .data = .{ .none = {} } },
341
342
343 // BRANCH
344
345 .beq => .{ .opcode = .BRANCH, .format = .B, .data = .{ .f = .{ .funct3 = 0b000 } } },
346
347
348 // SYSTEM
349
350 .ecall => .{ .opcode = .SYSTEM, .format = .extra, .data = .{ .extra = .ecall } },
351 .ebreak => .{ .opcode = .SYSTEM, .format = .extra, .data = .{ .extra = .ebreak } },
352
353 .csrrs => .{ .opcode = .SYSTEM, .format = .I, .data = .{ .f = .{ .funct3 = 0b010 } } },
354
355
356 // NONE
357
358 .unimp => .{ .opcode = .NONE, .format = .extra, .data = .{ .extra = .unimp } },
359
360
361 // MISC_MEM
362
363 .fence => .{ .opcode = .MISC_MEM, .format = .I, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .none } } },
364 .fencetso => .{ .opcode = .MISC_MEM, .format = .I, .data = .{ .fence = .{ .funct3 = 0b000, .fm = .tso } } },
365
366
367 // AMO
368
369 .amoaddw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00000 } } },
370 .amoswapw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00001 } } },
371 // LR.W
372 // SC.W
373 .amoxorw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b00100 } } },
374 .amoandw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01100 } } },
375 .amoorw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b01000 } } },
376 .amominw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10000 } } },
377 .amomaxw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b10100 } } },
378 .amominuw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11000 } } },
379 .amomaxuw => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .W, .funct5 = 0b11100 } } },
380
381 .amoaddd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00000 } } },
382 .amoswapd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00001 } } },
383 // LR.D
384 // SC.D
385 .amoxord => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b00100 } } },
386 .amoandd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01100 } } },
387 .amoord => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b01000 } } },
388 .amomind => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10000 } } },
389 .amomaxd => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b10100 } } },
390 .amominud => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11000 } } },
391 .amomaxud => .{ .opcode = .AMO, .format = .R, .data = .{ .amo = .{ .width = .D, .funct5 = 0b11100 } } },
392
393 // OP_V
394 .vsetivli => .{ .opcode = .OP_V, .format = .I, .data = .{ .f = .{ .funct3 = 0b111 } } },
395 .vsetvli => .{ .opcode = .OP_V, .format = .I, .data = .{ .f = .{ .funct3 = 0b111 } } },
396 .vaddvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPIVV } } },
397 .vsubvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPIVV } } },
398 .vmulvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b100101, .funct3 = .OPIVV } } },
399
400 .vfaddvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000000, .funct3 = .OPFVV } } },
401 .vfsubvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b000010, .funct3 = .OPFVV } } },
402 .vfmulvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b100100, .funct3 = .OPFVV } } },
403
404 .vadcvv => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010000, .funct3 = .OPMVV } } },
405 .vmvvx => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b010111, .funct3 = .OPIVX } } },
406
407 .vslidedownvx => .{ .opcode = .OP_V, .format = .R, .data = .{ .vecmath = .{ .vm = true, .funct6 = 0b001111, .funct3 = .OPIVX } } },
408
409
410 .pseudo_prologue,
411 .pseudo_epilogue,
412 .pseudo_dbg_prologue_end,
413 .pseudo_dbg_epilogue_begin,
414 .pseudo_dbg_line_column,
415 .pseudo_load_rm,
416 .pseudo_store_rm,
417 .pseudo_lea_rm,
418 .pseudo_j,
419 .pseudo_dead,
420 .pseudo_load_symbol,
421 .pseudo_mv,
422 .pseudo_restore_regs,
423 .pseudo_spill_regs,
424 .pseudo_compare,
425 .pseudo_not,
426 .pseudo_extern_fn_reloc,
427 .pseudo_fence,
428 .pseudo_amo,
429 .nop,
430 => std.debug.panic("lir: didn't catch pseudo {s}", .{@tagName(mnem)}),
431 // zig fmt: on
432 };
433 }
434};
435
436/// This is the final form of the instruction. Lir is transformed into
437/// this, which is then bitcast into a u32.
438pub const Instruction = union(Lir.Format) {
439 R: packed struct(u32) {
440 opcode: u7,
441 rd: u5,
442 funct3: u3,
443 rs1: u5,
444 rs2: u5,
445 funct7: u7,
446 },
447 I: packed struct(u32) {
448 opcode: u7,
449 rd: u5,
450 funct3: u3,
451 rs1: u5,
452 imm0_11: u12,
453 },
454 S: packed struct(u32) {
455 opcode: u7,
456 imm0_4: u5,
457 funct3: u3,
458 rs1: u5,
459 rs2: u5,
460 imm5_11: u7,
461 },
462 B: packed struct(u32) {
463 opcode: u7,
464 imm11: u1,
465 imm1_4: u4,
466 funct3: u3,
467 rs1: u5,
468 rs2: u5,
469 imm5_10: u6,
470 imm12: u1,
471 },
472 U: packed struct(u32) {
473 opcode: u7,
474 rd: u5,
475 imm12_31: u20,
476 },
477 J: packed struct(u32) {
478 opcode: u7,
479 rd: u5,
480 imm12_19: u8,
481 imm11: u1,
482 imm1_10: u10,
483 imm20: u1,
484 },
485 extra: u32,
486
487 comptime {
488 for (std.meta.fields(Instruction)) |field| {
489 assert(@bitSizeOf(field.type) == 32);
490 }
491 }
492
493 pub const Operand = union(enum) {
494 none,
495 reg: Register,
496 csr: CSR,
497 mem: Memory,
498 imm: Immediate,
499 barrier: Mir.Barrier,
500 };
501
502 pub fn toU32(inst: Instruction) u32 {
503 return switch (inst) {
504 inline else => |v| @bitCast(v),
505 };
506 }
507
508 pub fn encode(inst: Instruction, writer: anytype) !void {
509 try writer.writeInt(u32, inst.toU32(), .little);
510 }
511
512 pub fn fromLir(lir: Lir, ops: []const Operand) Instruction {
513 const opcode: u7 = @intFromEnum(lir.opcode);
514
515 switch (lir.format) {
516 .R => {
517 return .{
518 .R = switch (lir.data) {
519 .ff => |ff| .{
520 .rd = ops[0].reg.encodeId(),
521 .rs1 = ops[1].reg.encodeId(),
522 .rs2 = ops[2].reg.encodeId(),
523
524 .opcode = opcode,
525 .funct3 = ff.funct3,
526 .funct7 = ff.funct7,
527 },
528 .fmt => |fmt| .{
529 .rd = ops[0].reg.encodeId(),
530 .rs1 = ops[1].reg.encodeId(),
531 .rs2 = ops[2].reg.encodeId(),
532
533 .opcode = opcode,
534 .funct3 = fmt.rm,
535 .funct7 = (@as(u7, fmt.funct5) << 2) | @intFromEnum(fmt.fmt),
536 },
537 .fcvt => |fcvt| .{
538 .rd = ops[0].reg.encodeId(),
539 .rs1 = ops[1].reg.encodeId(),
540 .rs2 = @intFromEnum(fcvt.width),
541
542 .opcode = opcode,
543 .funct3 = fcvt.rm,
544 .funct7 = (@as(u7, fcvt.funct5) << 2) | @intFromEnum(fcvt.fmt),
545 },
546 .vecls => |vec| .{
547 .rd = ops[0].reg.encodeId(),
548 .rs1 = ops[1].reg.encodeId(),
549
550 .rs2 = @intFromEnum(vec.umop),
551
552 .opcode = opcode,
553 .funct3 = @intFromEnum(vec.width),
554 .funct7 = (@as(u7, vec.nf) << 4) | (@as(u7, @intFromBool(vec.mew)) << 3) | (@as(u7, @intFromEnum(vec.mop)) << 1) | @intFromBool(vec.vm),
555 },
556 .vecmath => |vec| .{
557 .rd = ops[0].reg.encodeId(),
558 .rs1 = ops[1].reg.encodeId(),
559 .rs2 = ops[2].reg.encodeId(),
560
561 .opcode = opcode,
562 .funct3 = @intFromEnum(vec.funct3),
563 .funct7 = (@as(u7, vec.funct6) << 1) | @intFromBool(vec.vm),
564 },
565 .amo => |amo| .{
566 .rd = ops[0].reg.encodeId(),
567 .rs1 = ops[1].reg.encodeId(),
568 .rs2 = ops[2].reg.encodeId(),
569
570 .opcode = opcode,
571 .funct3 = @intFromEnum(amo.width),
572 .funct7 = @as(u7, amo.funct5) << 2 |
573 @as(u7, @intFromBool(ops[3].barrier == .rl)) << 1 |
574 @as(u7, @intFromBool(ops[4].barrier == .aq)),
575 },
576 else => unreachable,
577 },
578 };
579 },
580 .S => {
581 assert(ops.len == 3);
582 const umm = ops[2].imm.asBits(u12);
583 return .{
584 .S = .{
585 .imm0_4 = @truncate(umm),
586 .rs1 = ops[0].reg.encodeId(),
587 .rs2 = ops[1].reg.encodeId(),
588 .imm5_11 = @truncate(umm >> 5),
589
590 .opcode = opcode,
591 .funct3 = lir.data.f.funct3,
592 },
593 };
594 },
595 .I => {
596 return .{
597 .I = switch (lir.data) {
598 .f => |f| .{
599 .rd = ops[0].reg.encodeId(),
600 .rs1 = ops[1].reg.encodeId(),
601 .imm0_11 = ops[2].imm.asBits(u12),
602
603 .opcode = opcode,
604 .funct3 = f.funct3,
605 },
606 .sh => |sh| .{
607 .rd = ops[0].reg.encodeId(),
608 .rs1 = ops[1].reg.encodeId(),
609 .imm0_11 = (@as(u12, sh.typ) << 6) |
610 if (sh.has_5) ops[2].imm.asBits(u6) else (@as(u6, 0) | ops[2].imm.asBits(u5)),
611
612 .opcode = opcode,
613 .funct3 = sh.funct3,
614 },
615 .fence => |fence| .{
616 .rd = 0,
617 .rs1 = 0,
618 .funct3 = 0,
619 .imm0_11 = (@as(u12, @intFromEnum(fence.fm)) << 8) |
620 (@as(u12, @intFromEnum(ops[1].barrier)) << 4) |
621 @as(u12, @intFromEnum(ops[0].barrier)),
622 .opcode = opcode,
623 },
624 else => unreachable,
625 },
626 };
627 },
628 .U => {
629 assert(ops.len == 2);
630 return .{
631 .U = .{
632 .rd = ops[0].reg.encodeId(),
633 .imm12_31 = ops[1].imm.asBits(u20),
634
635 .opcode = opcode,
636 },
637 };
638 },
639 .J => {
640 assert(ops.len == 2);
641
642 const umm = ops[1].imm.asBits(u21);
643 // the RISC-V spec says the target index of a jump
644 // must be a multiple of 2
645 assert(umm % 2 == 0);
646
647 return .{
648 .J = .{
649 .rd = ops[0].reg.encodeId(),
650 .imm1_10 = @truncate(umm >> 1),
651 .imm11 = @truncate(umm >> 11),
652 .imm12_19 = @truncate(umm >> 12),
653 .imm20 = @truncate(umm >> 20),
654
655 .opcode = opcode,
656 },
657 };
658 },
659 .B => {
660 assert(ops.len == 3);
661
662 const umm = ops[2].imm.asBits(u13);
663 // the RISC-V spec says the target index of a branch
664 // must be a multiple of 2
665 assert(umm % 2 == 0);
666
667 return .{
668 .B = .{
669 .rs1 = ops[0].reg.encodeId(),
670 .rs2 = ops[1].reg.encodeId(),
671 .imm1_4 = @truncate(umm >> 1),
672 .imm5_10 = @truncate(umm >> 5),
673 .imm11 = @truncate(umm >> 11),
674 .imm12 = @truncate(umm >> 12),
675
676 .opcode = opcode,
677 .funct3 = lir.data.f.funct3,
678 },
679 };
680 },
681 .extra => {
682 assert(ops.len == 0);
683
684 return .{
685 .I = .{
686 .rd = Register.zero.encodeId(),
687 .rs1 = Register.zero.encodeId(),
688 .imm0_11 = switch (lir.data.extra) {
689 .ecall => 0x000,
690 .ebreak => 0x001,
691 .unimp => 0x000,
692 else => unreachable,
693 },
694
695 .opcode = opcode,
696 .funct3 = 0b000,
697 },
698 };
699 },
700 }
701 }
702};
703
704const std = @import("std");
705const assert = std.debug.assert;
706const log = std.log.scoped(.format);
707
708const bits = @import("bits.zig");
709const Mir = @import("Mir.zig");
710const Mnemonic = @import("mnem.zig").Mnemonic;
711const Lower = @import("Lower.zig");
712
713const Register = bits.Register;
714const CSR = bits.CSR;
715const Memory = bits.Memory;
716const Immediate = bits.Immediate;
src/arch/riscv64/mnem.zig created+232
...@@ -0,0 +1,232 @@
1pub const Mnemonic = enum(u16) {
2 // Arithmetics
3 addi,
4 add,
5 addw,
6
7 sub,
8 subw,
9
10 // Bits
11 xori,
12 xor,
13 @"or",
14
15 @"and",
16 andi,
17
18 slt,
19 sltu,
20 sltiu,
21
22 slli,
23 srli,
24 srai,
25
26 slliw,
27 srliw,
28 sraiw,
29
30 sll,
31 srl,
32 sra,
33
34 sllw,
35 srlw,
36 sraw,
37
38 // Control Flow
39 jalr,
40 jal,
41
42 beq,
43
44 // Memory
45 lui,
46 auipc,
47
48 ld,
49 lw,
50 lh,
51 lb,
52 lbu,
53 lhu,
54 lwu,
55
56 sd,
57 sw,
58 sh,
59 sb,
60
61 // System
62 ebreak,
63 ecall,
64 unimp,
65 nop,
66
67 // M extension
68 mul,
69 mulh,
70 mulhu,
71 mulhsu,
72 mulw,
73
74 div,
75 divu,
76 divw,
77 divuw,
78
79 rem,
80 remu,
81 remw,
82 remuw,
83
84 // F extension (32-bit float)
85 fadds,
86 fsubs,
87 fmuls,
88 fdivs,
89
90 fmins,
91 fmaxs,
92
93 fsqrts,
94
95 flw,
96 fsw,
97
98 feqs,
99 flts,
100 fles,
101
102 // D extension (64-bit float)
103 faddd,
104 fsubd,
105 fmuld,
106 fdivd,
107
108 fmind,
109 fmaxd,
110
111 fsqrtd,
112
113 fld,
114 fsd,
115
116 feqd,
117 fltd,
118 fled,
119
120 fcvtws,
121 fcvtwus,
122 fcvtls,
123 fcvtlus,
124
125 fcvtwd,
126 fcvtwud,
127 fcvtld,
128 fcvtlud,
129
130 fsgnjns,
131 fsgnjnd,
132
133 fsgnjxs,
134 fsgnjxd,
135
136 // Zicsr Extension Instructions
137 csrrs,
138
139 // V Extension Instructions
140 vsetvli,
141 vsetivli,
142 vaddvv,
143 vfaddvv,
144 vsubvv,
145 vfsubvv,
146 vmulvv,
147 vfmulvv,
148 vslidedownvx,
149
150 vle8v,
151 vle16v,
152 vle32v,
153 vle64v,
154
155 vse8v,
156 vse16v,
157 vse32v,
158 vse64v,
159
160 vadcvv,
161 vmvvx,
162
163 // Zbb Extension Instructions
164 clz,
165 clzw,
166
167 // A Extension Instructions
168 fence,
169 fencetso,
170
171 amoswapw,
172 amoaddw,
173 amoandw,
174 amoorw,
175 amoxorw,
176 amomaxw,
177 amominw,
178 amomaxuw,
179 amominuw,
180
181 amoswapd,
182 amoaddd,
183 amoandd,
184 amoord,
185 amoxord,
186 amomaxd,
187 amomind,
188 amomaxud,
189 amominud,
190
191 // Pseudo-instructions. Used for anything that isn't 1:1 with an
192 // assembly instruction.
193
194 /// Pseudo-instruction that will generate a backpatched
195 /// function prologue.
196 pseudo_prologue,
197 /// Pseudo-instruction that will generate a backpatched
198 /// function epilogue
199 pseudo_epilogue,
200
201 /// Pseudo-instruction: End of prologue
202 pseudo_dbg_prologue_end,
203 /// Pseudo-instruction: Beginning of epilogue
204 pseudo_dbg_epilogue_begin,
205 /// Pseudo-instruction: Update debug line
206 pseudo_dbg_line_column,
207
208 /// Pseudo-instruction that loads from memory into a register.
209 pseudo_load_rm,
210 /// Pseudo-instruction that stores from a register into memory
211 pseudo_store_rm,
212 /// Pseudo-instruction that loads the address of memory into a register.
213 pseudo_lea_rm,
214 /// Jumps. Uses `inst` payload.
215 pseudo_j,
216 /// Dead inst, ignored by the emitter.
217 pseudo_dead,
218 /// Loads the address of a value that hasn't yet been allocated in memory.
219 pseudo_load_symbol,
220
221 /// Moves the value of rs1 to rd.
222 pseudo_mv,
223
224 pseudo_restore_regs,
225 pseudo_spill_regs,
226
227 pseudo_compare,
228 pseudo_not,
229 pseudo_extern_fn_reloc,
230 pseudo_fence,
231 pseudo_amo,
232};
src/link/riscv.zig+7-33
...@@ -25,47 +25,27 @@ pub fn writeAddend(...@@ -25,47 +25,27 @@ pub fn writeAddend(
25}25}
2626
27pub fn writeInstU(code: *[4]u8, value: u32) void {27pub fn writeInstU(code: *[4]u8, value: u32) void {
28 var data = Encoding.Data{28 var data: Instruction = .{ .U = mem.bytesToValue(std.meta.TagPayload(Instruction, .U), code) };
29 .U = mem.bytesToValue(std.meta.TagPayload(
30 Encoding.Data,
31 Encoding.Data.U,
32 ), code),
33 };
34 const compensated: u32 = @bitCast(@as(i32, @bitCast(value)) + 0x800);29 const compensated: u32 = @bitCast(@as(i32, @bitCast(value)) + 0x800);
35 data.U.imm12_31 = bitSlice(compensated, 31, 12);30 data.U.imm12_31 = bitSlice(compensated, 31, 12);
36 mem.writeInt(u32, code, data.toU32(), .little);31 mem.writeInt(u32, code, data.toU32(), .little);
37}32}
3833
39pub fn writeInstI(code: *[4]u8, value: u32) void {34pub fn writeInstI(code: *[4]u8, value: u32) void {
40 var data = Encoding.Data{35 var data: Instruction = .{ .I = mem.bytesToValue(std.meta.TagPayload(Instruction, .I), code) };
41 .I = mem.bytesToValue(std.meta.TagPayload(
42 Encoding.Data,
43 Encoding.Data.I,
44 ), code),
45 };
46 data.I.imm0_11 = bitSlice(value, 11, 0);36 data.I.imm0_11 = bitSlice(value, 11, 0);
47 mem.writeInt(u32, code, data.toU32(), .little);37 mem.writeInt(u32, code, data.toU32(), .little);
48}38}
4939
50pub fn writeInstS(code: *[4]u8, value: u32) void {40pub fn writeInstS(code: *[4]u8, value: u32) void {
51 var data = Encoding.Data{41 var data: Instruction = .{ .S = mem.bytesToValue(std.meta.TagPayload(Instruction, .S), code) };
52 .S = mem.bytesToValue(std.meta.TagPayload(
53 Encoding.Data,
54 Encoding.Data.S,
55 ), code),
56 };
57 data.S.imm0_4 = bitSlice(value, 4, 0);42 data.S.imm0_4 = bitSlice(value, 4, 0);
58 data.S.imm5_11 = bitSlice(value, 11, 5);43 data.S.imm5_11 = bitSlice(value, 11, 5);
59 mem.writeInt(u32, code, data.toU32(), .little);44 mem.writeInt(u32, code, data.toU32(), .little);
60}45}
6146
62pub fn writeInstJ(code: *[4]u8, value: u32) void {47pub fn writeInstJ(code: *[4]u8, value: u32) void {
63 var data = Encoding.Data{48 var data: Instruction = .{ .J = mem.bytesToValue(std.meta.TagPayload(Instruction, .J), code) };
64 .J = mem.bytesToValue(std.meta.TagPayload(
65 Encoding.Data,
66 Encoding.Data.J,
67 ), code),
68 };
69 data.J.imm1_10 = bitSlice(value, 10, 1);49 data.J.imm1_10 = bitSlice(value, 10, 1);
70 data.J.imm11 = bitSlice(value, 11, 11);50 data.J.imm11 = bitSlice(value, 11, 11);
71 data.J.imm12_19 = bitSlice(value, 19, 12);51 data.J.imm12_19 = bitSlice(value, 19, 12);
...@@ -74,12 +54,7 @@ pub fn writeInstJ(code: *[4]u8, value: u32) void {...@@ -74,12 +54,7 @@ pub fn writeInstJ(code: *[4]u8, value: u32) void {
74}54}
7555
76pub fn writeInstB(code: *[4]u8, value: u32) void {56pub fn writeInstB(code: *[4]u8, value: u32) void {
77 var data = Encoding.Data{57 var data: Instruction = .{ .B = mem.bytesToValue(std.meta.TagPayload(Instruction, .B), code) };
78 .B = mem.bytesToValue(std.meta.TagPayload(
79 Encoding.Data,
80 Encoding.Data.B,
81 ), code),
82 };
83 data.B.imm1_4 = bitSlice(value, 4, 1);58 data.B.imm1_4 = bitSlice(value, 4, 1);
84 data.B.imm5_10 = bitSlice(value, 10, 5);59 data.B.imm5_10 = bitSlice(value, 10, 5);
85 data.B.imm11 = bitSlice(value, 11, 11);60 data.B.imm11 = bitSlice(value, 11, 11);
...@@ -109,9 +84,8 @@ pub const RiscvEflags = packed struct(u32) {...@@ -109,9 +84,8 @@ pub const RiscvEflags = packed struct(u32) {
109 _unused: u8,84 _unused: u8,
110};85};
11186
112const encoder = @import("../arch/riscv64/encoder.zig");
113const Encoding = @import("../arch/riscv64/Encoding.zig");
114const mem = std.mem;87const mem = std.mem;
115const std = @import("std");88const std = @import("std");
11689
117pub const Instruction = encoder.Instruction;90const encoding = @import("../arch/riscv64/encoding.zig");
91const Instruction = encoding.Instruction;
test/behavior/align.zig-1
...@@ -510,7 +510,6 @@ test "read 128-bit field from default aligned struct in global memory" {...@@ -510,7 +510,6 @@ test "read 128-bit field from default aligned struct in global memory" {
510}510}
511511
512test "struct field explicit alignment" {512test "struct field explicit alignment" {
513 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO
514 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;513 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
515 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;514 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
516 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO515 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
test/behavior/byteswap.zig+1
...@@ -100,6 +100,7 @@ test "@byteSwap vectors u8" {...@@ -100,6 +100,7 @@ test "@byteSwap vectors u8" {
100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO101 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;102 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
103 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
103104
104 try comptime vector8();105 try comptime vector8();
105 try vector8();106 try vector8();
test/behavior/defer.zig+2
...@@ -116,6 +116,7 @@ test "errdefer with payload" {...@@ -116,6 +116,7 @@ test "errdefer with payload" {
116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO116 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO117 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
118 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;118 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
119 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
119120
120 const S = struct {121 const S = struct {
121 fn foo() !i32 {122 fn foo() !i32 {
...@@ -138,6 +139,7 @@ test "reference to errdefer payload" {...@@ -138,6 +139,7 @@ test "reference to errdefer payload" {
138 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO139 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
139 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO140 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
140 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO141 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO
142 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
141143
142 const S = struct {144 const S = struct {
143 fn foo() !i32 {145 fn foo() !i32 {
test/behavior/optional.zig+1
...@@ -591,6 +591,7 @@ test "cast slice to const slice nested in error union and optional" {...@@ -591,6 +591,7 @@ test "cast slice to const slice nested in error union and optional" {
591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;591 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
592 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;592 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
593 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;593 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
594 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
594595
595 const S = struct {596 const S = struct {
596 fn inner() !?[]u8 {597 fn inner() !?[]u8 {
test/behavior/pointers.zig+1
...@@ -228,6 +228,7 @@ test "implicit cast error unions with non-optional to optional pointer" {...@@ -228,6 +228,7 @@ test "implicit cast error unions with non-optional to optional pointer" {
228 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO228 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO229 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
230 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;230 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
231 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
231232
232 const S = struct {233 const S = struct {
233 fn doTheTest() !void {234 fn doTheTest() !void {
test/behavior/switch.zig+2
...@@ -427,6 +427,7 @@ test "else prong of switch on error set excludes other cases" {...@@ -427,6 +427,7 @@ test "else prong of switch on error set excludes other cases" {
427 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO427 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
428 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO428 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
429 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;429 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
430 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
430431
431 const S = struct {432 const S = struct {
432 fn doTheTest() !void {433 fn doTheTest() !void {
...@@ -462,6 +463,7 @@ test "switch prongs with error set cases make a new error set type for capture v...@@ -462,6 +463,7 @@ test "switch prongs with error set cases make a new error set type for capture v
462 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO463 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
463 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO464 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
464 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;465 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
466 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
465467
466 const S = struct {468 const S = struct {
467 fn doTheTest() !void {469 fn doTheTest() !void {
test/behavior/try.zig+1
...@@ -51,6 +51,7 @@ test "`try`ing an if/else expression" {...@@ -51,6 +51,7 @@ test "`try`ing an if/else expression" {
51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO51 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO52 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
53 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;53 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
54 if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest;
5455
55 const S = struct {56 const S = struct {
56 fn getError() !void {57 fn getError() !void {