| author | |
| committer | |
| log | 1a7d89a84d7fef87eb45da8207bbeb852e3f0c02 |
| tree | 1d7306a194386d23d2ddfa3611c07613f68dbece |
| parent | 574028ed5ec6ad455961ed46babdb7a5fe9f68bb |
| signature |
19 files changed, 1720 insertions(+), 2391 deletions(-)
CMakeLists.txt+2-2| ... | ... | @@ -539,10 +539,10 @@ set(ZIG_STAGE2_SOURCES |
| 539 | 539 | src/arch/riscv64/bits.zig |
| 540 | 540 | src/arch/riscv64/CodeGen.zig |
| 541 | 541 | src/arch/riscv64/Emit.zig |
| 542 | src/arch/riscv64/encoder.zig | |
| 543 | src/arch/riscv64/Encoding.zig | |
| 542 | src/arch/riscv64/encoding.zig | |
| 544 | 543 | src/arch/riscv64/Lower.zig |
| 545 | 544 | src/arch/riscv64/Mir.zig |
| 545 | src/arch/riscv64/mnem.zig | |
| 546 | 546 | src/arch/sparc64/CodeGen.zig |
| 547 | 547 | src/arch/sparc64/Emit.zig |
| 548 | 548 | src/arch/sparc64/Mir.zig |
lib/compiler/test_runner.zig-1| ... | ... | @@ -271,7 +271,6 @@ pub fn mainSimple() anyerror!void { |
| 271 | 271 | }; |
| 272 | 272 | // is the backend capable of using std.fmt.format to print a summary at the end? |
| 273 | 273 | const print_summary = switch (builtin.zig_backend) { |
| 274 | .stage2_riscv64 => true, | |
| 275 | 274 | else => false, |
| 276 | 275 | }; |
| 277 | 276 |
src/arch/riscv64/CodeGen.zig+217-306| ... | ... | @@ -20,6 +20,7 @@ const InternPool = @import("../../InternPool.zig"); |
| 20 | 20 | const Compilation = @import("../../Compilation.zig"); |
| 21 | 21 | const trace = @import("../../tracy.zig").trace; |
| 22 | 22 | const codegen = @import("../../codegen.zig"); |
| 23 | const Mnemonic = @import("mnem.zig").Mnemonic; | |
| 23 | 24 | |
| 24 | 25 | const ErrorMsg = Zcu.ErrorMsg; |
| 25 | 26 | const Target = std.Target; |
| ... | ... | @@ -65,7 +66,6 @@ arg_index: usize, |
| 65 | 66 | src_loc: Zcu.LazySrcLoc, |
| 66 | 67 | |
| 67 | 68 | mir_instructions: std.MultiArrayList(Mir.Inst) = .{}, |
| 68 | mir_extra: std.ArrayListUnmanaged(u32) = .{}, | |
| 69 | 69 | |
| 70 | 70 | owner: Owner, |
| 71 | 71 | |
| ... | ... | @@ -794,7 +794,6 @@ pub fn generate( |
| 794 | 794 | function.const_tracking.deinit(gpa); |
| 795 | 795 | function.exitlude_jump_relocs.deinit(gpa); |
| 796 | 796 | function.mir_instructions.deinit(gpa); |
| 797 | function.mir_extra.deinit(gpa); | |
| 798 | 797 | } |
| 799 | 798 | |
| 800 | 799 | wip_mir_log.debug("{}:", .{function.fmtDecl(func.owner_decl)}); |
| ... | ... | @@ -855,7 +854,6 @@ pub fn generate( |
| 855 | 854 | |
| 856 | 855 | var mir: Mir = .{ |
| 857 | 856 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 858 | .extra = try function.mir_extra.toOwnedSlice(gpa), | |
| 859 | 857 | .frame_locs = function.frame_locs.toOwnedSlice(), |
| 860 | 858 | }; |
| 861 | 859 | defer mir.deinit(gpa); |
| ... | ... | @@ -940,10 +938,7 @@ pub fn generateLazy( |
| 940 | 938 | .avl = null, |
| 941 | 939 | .vtype = null, |
| 942 | 940 | }; |
| 943 | defer { | |
| 944 | function.mir_instructions.deinit(gpa); | |
| 945 | function.mir_extra.deinit(gpa); | |
| 946 | } | |
| 941 | defer function.mir_instructions.deinit(gpa); | |
| 947 | 942 | |
| 948 | 943 | function.genLazy(lazy_sym) catch |err| switch (err) { |
| 949 | 944 | error.CodegenFail => return Result{ .fail = function.err_msg.? }, |
| ... | ... | @@ -955,7 +950,6 @@ pub fn generateLazy( |
| 955 | 950 | |
| 956 | 951 | var mir: Mir = .{ |
| 957 | 952 | .instructions = function.mir_instructions.toOwnedSlice(), |
| 958 | .extra = try function.mir_extra.toOwnedSlice(gpa), | |
| 959 | 953 | .frame_locs = function.frame_locs.toOwnedSlice(), |
| 960 | 954 | }; |
| 961 | 955 | defer mir.deinit(gpa); |
| ... | ... | @@ -1022,7 +1016,6 @@ fn formatWipMir( |
| 1022 | 1016 | .allocator = data.func.gpa, |
| 1023 | 1017 | .mir = .{ |
| 1024 | 1018 | .instructions = data.func.mir_instructions.slice(), |
| 1025 | .extra = data.func.mir_extra.items, | |
| 1026 | 1019 | .frame_locs = data.func.frame_locs.slice(), |
| 1027 | 1020 | }, |
| 1028 | 1021 | .cc = .Unspecified, |
| ... | ... | @@ -1120,7 +1113,7 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 1120 | 1113 | try func.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| 1121 | 1114 | const result_index: Mir.Inst.Index = @intCast(func.mir_instructions.len); |
| 1122 | 1115 | func.mir_instructions.appendAssumeCapacity(inst); |
| 1123 | if (inst.tag != .pseudo or switch (inst.ops) { | |
| 1116 | if (switch (inst.tag) { | |
| 1124 | 1117 | else => true, |
| 1125 | 1118 | .pseudo_dbg_prologue_end, |
| 1126 | 1119 | .pseudo_dbg_line_column, |
| ... | ... | @@ -1131,49 +1124,13 @@ fn addInst(func: *Func, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 1131 | 1124 | return result_index; |
| 1132 | 1125 | } |
| 1133 | 1126 | |
| 1134 | fn addNop(func: *Func) error{OutOfMemory}!Mir.Inst.Index { | |
| 1135 | return func.addInst(.{ | |
| 1136 | .tag = .nop, | |
| 1137 | .ops = .none, | |
| 1138 | .data = undefined, | |
| 1139 | }); | |
| 1140 | } | |
| 1141 | ||
| 1142 | fn addPseudoNone(func: *Func, ops: Mir.Inst.Ops) !void { | |
| 1143 | _ = try func.addInst(.{ | |
| 1144 | .tag = .pseudo, | |
| 1145 | .ops = ops, | |
| 1146 | .data = undefined, | |
| 1147 | }); | |
| 1148 | } | |
| 1149 | ||
| 1150 | fn addPseudo(func: *Func, ops: Mir.Inst.Ops) !Mir.Inst.Index { | |
| 1127 | fn addPseudo(func: *Func, mnem: Mnemonic) error{OutOfMemory}!Mir.Inst.Index { | |
| 1151 | 1128 | return func.addInst(.{ |
| 1152 | .tag = .pseudo, | |
| 1153 | .ops = ops, | |
| 1154 | .data = undefined, | |
| 1129 | .tag = mnem, | |
| 1130 | .data = .none, | |
| 1155 | 1131 | }); |
| 1156 | 1132 | } |
| 1157 | 1133 | |
| 1158 | pub 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 | ||
| 1164 | pub 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 | 1134 | /// Returns a temporary register that contains the value of the `reg` csr. |
| 1178 | 1135 | /// |
| 1179 | 1136 | /// Caller's duty to lock the return register is needed. |
| ... | ... | @@ -1182,14 +1139,11 @@ fn getCsr(func: *Func, csr: CSR) !Register { |
| 1182 | 1139 | const dst_reg = try func.register_manager.allocReg(null, func.regTempClassForType(Type.u64)); |
| 1183 | 1140 | _ = try func.addInst(.{ |
| 1184 | 1141 | .tag = .csrrs, |
| 1185 | .ops = .csr, | |
| 1186 | .data = .{ | |
| 1187 | .csr = .{ | |
| 1188 | .csr = csr, | |
| 1189 | .rd = dst_reg, | |
| 1190 | .rs1 = .x0, | |
| 1191 | }, | |
| 1192 | }, | |
| 1142 | .data = .{ .csr = .{ | |
| 1143 | .csr = csr, | |
| 1144 | .rd = dst_reg, | |
| 1145 | .rs1 = .x0, | |
| 1146 | } }, | |
| 1193 | 1147 | }); |
| 1194 | 1148 | return dst_reg; |
| 1195 | 1149 | } |
| ... | ... | @@ -1208,7 +1162,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void { |
| 1208 | 1162 | const options_int: u12 = @as(u12, 0) | @as(u8, @bitCast(options)); |
| 1209 | 1163 | _ = try func.addInst(.{ |
| 1210 | 1164 | .tag = .vsetvli, |
| 1211 | .ops = .rri, | |
| 1212 | 1165 | .data = .{ .i_type = .{ |
| 1213 | 1166 | .rd = dst_reg, |
| 1214 | 1167 | .rs1 = .zero, |
| ... | ... | @@ -1221,7 +1174,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void { |
| 1221 | 1174 | const options_int: u12 = (~@as(u12, 0) << 10) | @as(u8, @bitCast(options)); |
| 1222 | 1175 | _ = try func.addInst(.{ |
| 1223 | 1176 | .tag = .vsetivli, |
| 1224 | .ops = .rri, | |
| 1225 | 1177 | .data = .{ |
| 1226 | 1178 | .i_type = .{ |
| 1227 | 1179 | .rd = dst_reg, |
| ... | ... | @@ -1235,7 +1187,6 @@ fn setVl(func: *Func, dst_reg: Register, avl: u64, options: bits.VType) !void { |
| 1235 | 1187 | const temp_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = avl }); |
| 1236 | 1188 | _ = try func.addInst(.{ |
| 1237 | 1189 | .tag = .vsetvli, |
| 1238 | .ops = .rri, | |
| 1239 | 1190 | .data = .{ .i_type = .{ |
| 1240 | 1191 | .rd = dst_reg, |
| 1241 | 1192 | .rs1 = temp_reg, |
| ... | ... | @@ -1270,7 +1221,7 @@ fn gen(func: *Func) !void { |
| 1270 | 1221 | } |
| 1271 | 1222 | |
| 1272 | 1223 | if (fn_info.cc != .Naked) { |
| 1273 | try func.addPseudoNone(.pseudo_dbg_prologue_end); | |
| 1224 | _ = try func.addPseudo(.pseudo_dbg_prologue_end); | |
| 1274 | 1225 | |
| 1275 | 1226 | const backpatch_stack_alloc = try func.addPseudo(.pseudo_dead); |
| 1276 | 1227 | const backpatch_ra_spill = try func.addPseudo(.pseudo_dead); |
| ... | ... | @@ -1300,11 +1251,11 @@ fn gen(func: *Func) !void { |
| 1300 | 1251 | try func.genBody(func.air.getMainBody()); |
| 1301 | 1252 | |
| 1302 | 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 | 1255 | @intCast(func.mir_instructions.len); |
| 1305 | 1256 | } |
| 1306 | 1257 | |
| 1307 | try func.addPseudoNone(.pseudo_dbg_epilogue_begin); | |
| 1258 | _ = try func.addPseudo(.pseudo_dbg_epilogue_begin); | |
| 1308 | 1259 | |
| 1309 | 1260 | const backpatch_restore_callee_preserved_regs = try func.addPseudo(.pseudo_dead); |
| 1310 | 1261 | const backpatch_ra_restore = try func.addPseudo(.pseudo_dead); |
| ... | ... | @@ -1314,7 +1265,6 @@ fn gen(func: *Func) !void { |
| 1314 | 1265 | // ret |
| 1315 | 1266 | _ = try func.addInst(.{ |
| 1316 | 1267 | .tag = .jalr, |
| 1317 | .ops = .rri, | |
| 1318 | 1268 | .data = .{ |
| 1319 | 1269 | .i_type = .{ |
| 1320 | 1270 | .rd = .zero, |
| ... | ... | @@ -1329,7 +1279,6 @@ fn gen(func: *Func) !void { |
| 1329 | 1279 | |
| 1330 | 1280 | func.mir_instructions.set(backpatch_stack_alloc, .{ |
| 1331 | 1281 | .tag = .addi, |
| 1332 | .ops = .rri, | |
| 1333 | 1282 | .data = .{ .i_type = .{ |
| 1334 | 1283 | .rd = .sp, |
| 1335 | 1284 | .rs1 = .sp, |
| ... | ... | @@ -1337,8 +1286,7 @@ fn gen(func: *Func) !void { |
| 1337 | 1286 | } }, |
| 1338 | 1287 | }); |
| 1339 | 1288 | func.mir_instructions.set(backpatch_ra_spill, .{ |
| 1340 | .tag = .pseudo, | |
| 1341 | .ops = .pseudo_store_rm, | |
| 1289 | .tag = .pseudo_store_rm, | |
| 1342 | 1290 | .data = .{ .rm = .{ |
| 1343 | 1291 | .r = .ra, |
| 1344 | 1292 | .m = .{ |
| ... | ... | @@ -1348,8 +1296,7 @@ fn gen(func: *Func) !void { |
| 1348 | 1296 | } }, |
| 1349 | 1297 | }); |
| 1350 | 1298 | func.mir_instructions.set(backpatch_ra_restore, .{ |
| 1351 | .tag = .pseudo, | |
| 1352 | .ops = .pseudo_load_rm, | |
| 1299 | .tag = .pseudo_load_rm, | |
| 1353 | 1300 | .data = .{ .rm = .{ |
| 1354 | 1301 | .r = .ra, |
| 1355 | 1302 | .m = .{ |
| ... | ... | @@ -1359,8 +1306,7 @@ fn gen(func: *Func) !void { |
| 1359 | 1306 | } }, |
| 1360 | 1307 | }); |
| 1361 | 1308 | func.mir_instructions.set(backpatch_fp_spill, .{ |
| 1362 | .tag = .pseudo, | |
| 1363 | .ops = .pseudo_store_rm, | |
| 1309 | .tag = .pseudo_store_rm, | |
| 1364 | 1310 | .data = .{ .rm = .{ |
| 1365 | 1311 | .r = .s0, |
| 1366 | 1312 | .m = .{ |
| ... | ... | @@ -1370,8 +1316,7 @@ fn gen(func: *Func) !void { |
| 1370 | 1316 | } }, |
| 1371 | 1317 | }); |
| 1372 | 1318 | func.mir_instructions.set(backpatch_fp_restore, .{ |
| 1373 | .tag = .pseudo, | |
| 1374 | .ops = .pseudo_load_rm, | |
| 1319 | .tag = .pseudo_load_rm, | |
| 1375 | 1320 | .data = .{ .rm = .{ |
| 1376 | 1321 | .r = .s0, |
| 1377 | 1322 | .m = .{ |
| ... | ... | @@ -1382,7 +1327,6 @@ fn gen(func: *Func) !void { |
| 1382 | 1327 | }); |
| 1383 | 1328 | func.mir_instructions.set(backpatch_fp_add, .{ |
| 1384 | 1329 | .tag = .addi, |
| 1385 | .ops = .rri, | |
| 1386 | 1330 | .data = .{ .i_type = .{ |
| 1387 | 1331 | .rd = .s0, |
| 1388 | 1332 | .rs1 = .sp, |
| ... | ... | @@ -1391,7 +1335,6 @@ fn gen(func: *Func) !void { |
| 1391 | 1335 | }); |
| 1392 | 1336 | func.mir_instructions.set(backpatch_stack_alloc_restore, .{ |
| 1393 | 1337 | .tag = .addi, |
| 1394 | .ops = .rri, | |
| 1395 | 1338 | .data = .{ .i_type = .{ |
| 1396 | 1339 | .rd = .sp, |
| 1397 | 1340 | .rs1 = .sp, |
| ... | ... | @@ -1401,27 +1344,24 @@ fn gen(func: *Func) !void { |
| 1401 | 1344 | |
| 1402 | 1345 | if (need_save_reg) { |
| 1403 | 1346 | func.mir_instructions.set(backpatch_spill_callee_preserved_regs, .{ |
| 1404 | .tag = .pseudo, | |
| 1405 | .ops = .pseudo_spill_regs, | |
| 1347 | .tag = .pseudo_spill_regs, | |
| 1406 | 1348 | .data = .{ .reg_list = frame_layout.save_reg_list }, |
| 1407 | 1349 | }); |
| 1408 | 1350 | |
| 1409 | 1351 | func.mir_instructions.set(backpatch_restore_callee_preserved_regs, .{ |
| 1410 | .tag = .pseudo, | |
| 1411 | .ops = .pseudo_restore_regs, | |
| 1352 | .tag = .pseudo_restore_regs, | |
| 1412 | 1353 | .data = .{ .reg_list = frame_layout.save_reg_list }, |
| 1413 | 1354 | }); |
| 1414 | 1355 | } |
| 1415 | 1356 | } else { |
| 1416 | try func.addPseudoNone(.pseudo_dbg_prologue_end); | |
| 1357 | _ = try func.addPseudo(.pseudo_dbg_prologue_end); | |
| 1417 | 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 | } |
| 1420 | 1361 | |
| 1421 | 1362 | // Drop them off at the rbrace. |
| 1422 | 1363 | _ = try func.addInst(.{ |
| 1423 | .tag = .pseudo, | |
| 1424 | .ops = .pseudo_dbg_line_column, | |
| 1364 | .tag = .pseudo_dbg_line_column, | |
| 1425 | 1365 | .data = .{ .pseudo_dbg_line_column = .{ |
| 1426 | 1366 | .line = func.end_di_line, |
| 1427 | 1367 | .column = func.end_di_column, |
| ... | ... | @@ -1493,9 +1433,11 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 1493 | 1433 | ); |
| 1494 | 1434 | |
| 1495 | 1435 | exitlude_jump_reloc.* = try func.addInst(.{ |
| 1496 | .tag = .pseudo, | |
| 1497 | .ops = .pseudo_j, | |
| 1498 | .data = .{ .inst = undefined }, | |
| 1436 | .tag = .pseudo_j, | |
| 1437 | .data = .{ .j_type = .{ | |
| 1438 | .rd = .zero, | |
| 1439 | .inst = undefined, | |
| 1440 | } }, | |
| 1499 | 1441 | }); |
| 1500 | 1442 | func.performReloc(skip_reloc); |
| 1501 | 1443 | |
| ... | ... | @@ -1508,7 +1450,7 @@ fn genLazy(func: *Func, lazy_sym: link.File.LazySymbol) InnerError!void { |
| 1508 | 1450 | |
| 1509 | 1451 | _ = try func.addInst(.{ |
| 1510 | 1452 | .tag = .jalr, |
| 1511 | .ops = .rri, | |
| 1453 | ||
| 1512 | 1454 | .data = .{ |
| 1513 | 1455 | .i_type = .{ |
| 1514 | 1456 | .rd = .zero, |
| ... | ... | @@ -2041,7 +1983,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { |
| 2041 | 1983 | .signed => { |
| 2042 | 1984 | _ = try func.addInst(.{ |
| 2043 | 1985 | .tag = .slli, |
| 2044 | .ops = .rri, | |
| 1986 | ||
| 2045 | 1987 | .data = .{ |
| 2046 | 1988 | .i_type = .{ |
| 2047 | 1989 | .rd = reg, |
| ... | ... | @@ -2052,7 +1994,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { |
| 2052 | 1994 | }); |
| 2053 | 1995 | _ = try func.addInst(.{ |
| 2054 | 1996 | .tag = .srai, |
| 2055 | .ops = .rri, | |
| 1997 | ||
| 2056 | 1998 | .data = .{ |
| 2057 | 1999 | .i_type = .{ |
| 2058 | 2000 | .rd = reg, |
| ... | ... | @@ -2067,7 +2009,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { |
| 2067 | 2009 | if (mask < 256) { |
| 2068 | 2010 | _ = try func.addInst(.{ |
| 2069 | 2011 | .tag = .andi, |
| 2070 | .ops = .rri, | |
| 2012 | ||
| 2071 | 2013 | .data = .{ |
| 2072 | 2014 | .i_type = .{ |
| 2073 | 2015 | .rd = reg, |
| ... | ... | @@ -2079,7 +2021,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { |
| 2079 | 2021 | } else { |
| 2080 | 2022 | _ = try func.addInst(.{ |
| 2081 | 2023 | .tag = .slli, |
| 2082 | .ops = .rri, | |
| 2024 | ||
| 2083 | 2025 | .data = .{ |
| 2084 | 2026 | .i_type = .{ |
| 2085 | 2027 | .rd = reg, |
| ... | ... | @@ -2090,7 +2032,7 @@ fn truncateRegister(func: *Func, ty: Type, reg: Register) !void { |
| 2090 | 2032 | }); |
| 2091 | 2033 | _ = try func.addInst(.{ |
| 2092 | 2034 | .tag = .srli, |
| 2093 | .ops = .rri, | |
| 2035 | ||
| 2094 | 2036 | .data = .{ |
| 2095 | 2037 | .i_type = .{ |
| 2096 | 2038 | .rd = reg, |
| ... | ... | @@ -2411,8 +2353,7 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { |
| 2411 | 2353 | switch (ty.zigTypeTag(zcu)) { |
| 2412 | 2354 | .Bool => { |
| 2413 | 2355 | _ = try func.addInst(.{ |
| 2414 | .tag = .pseudo, | |
| 2415 | .ops = .pseudo_not, | |
| 2356 | .tag = .pseudo_not, | |
| 2416 | 2357 | .data = .{ |
| 2417 | 2358 | .rr = .{ |
| 2418 | 2359 | .rs = operand_reg, |
| ... | ... | @@ -2430,7 +2371,6 @@ fn airNot(func: *Func, inst: Air.Inst.Index) !void { |
| 2430 | 2371 | 32, 64 => { |
| 2431 | 2372 | _ = try func.addInst(.{ |
| 2432 | 2373 | .tag = .xori, |
| 2433 | .ops = .rri, | |
| 2434 | 2374 | .data = .{ |
| 2435 | 2375 | .i_type = .{ |
| 2436 | 2376 | .rd = dst_reg, |
| ... | ... | @@ -2628,7 +2568,7 @@ fn genBinOp( |
| 2628 | 2568 | |
| 2629 | 2569 | switch (lhs_ty.zigTypeTag(zcu)) { |
| 2630 | 2570 | .Int => { |
| 2631 | const mir_tag: Mir.Inst.Tag = switch (tag) { | |
| 2571 | const mnem: Mnemonic = switch (tag) { | |
| 2632 | 2572 | .add, .add_wrap => switch (bit_size) { |
| 2633 | 2573 | 8, 16, 64 => .add, |
| 2634 | 2574 | 32 => .addw, |
| ... | ... | @@ -2656,8 +2596,7 @@ fn genBinOp( |
| 2656 | 2596 | }; |
| 2657 | 2597 | |
| 2658 | 2598 | _ = try func.addInst(.{ |
| 2659 | .tag = mir_tag, | |
| 2660 | .ops = .rrr, | |
| 2599 | .tag = mnem, | |
| 2661 | 2600 | .data = .{ |
| 2662 | 2601 | .r_type = .{ |
| 2663 | 2602 | .rd = dst_reg, |
| ... | ... | @@ -2668,7 +2607,7 @@ fn genBinOp( |
| 2668 | 2607 | }); |
| 2669 | 2608 | }, |
| 2670 | 2609 | .Float => { |
| 2671 | const mir_tag: Mir.Inst.Tag = switch (tag) { | |
| 2610 | const mir_tag: Mnemonic = switch (tag) { | |
| 2672 | 2611 | .add => switch (bit_size) { |
| 2673 | 2612 | 32 => .fadds, |
| 2674 | 2613 | 64 => .faddd, |
| ... | ... | @@ -2689,7 +2628,6 @@ fn genBinOp( |
| 2689 | 2628 | |
| 2690 | 2629 | _ = try func.addInst(.{ |
| 2691 | 2630 | .tag = mir_tag, |
| 2692 | .ops = .rrr, | |
| 2693 | 2631 | .data = .{ |
| 2694 | 2632 | .r_type = .{ |
| 2695 | 2633 | .rd = dst_reg, |
| ... | ... | @@ -2705,7 +2643,7 @@ fn genBinOp( |
| 2705 | 2643 | |
| 2706 | 2644 | const child_ty = lhs_ty.childType(zcu); |
| 2707 | 2645 | |
| 2708 | const mir_tag: Mir.Inst.Tag = switch (tag) { | |
| 2646 | const mir_tag: Mnemonic = switch (tag) { | |
| 2709 | 2647 | .add => switch (child_ty.zigTypeTag(zcu)) { |
| 2710 | 2648 | .Int => .vaddvv, |
| 2711 | 2649 | .Float => .vfaddvv, |
| ... | ... | @@ -2739,7 +2677,6 @@ fn genBinOp( |
| 2739 | 2677 | |
| 2740 | 2678 | _ = try func.addInst(.{ |
| 2741 | 2679 | .tag = mir_tag, |
| 2742 | .ops = .rrr, | |
| 2743 | 2680 | .data = .{ |
| 2744 | 2681 | .r_type = .{ |
| 2745 | 2682 | .rd = dst_reg, |
| ... | ... | @@ -2764,7 +2701,6 @@ fn genBinOp( |
| 2764 | 2701 | |
| 2765 | 2702 | _ = try func.addInst(.{ |
| 2766 | 2703 | .tag = .add, |
| 2767 | .ops = .rrr, | |
| 2768 | 2704 | .data = .{ .r_type = .{ |
| 2769 | 2705 | .rd = tmp_reg, |
| 2770 | 2706 | .rs1 = rhs_reg, |
| ... | ... | @@ -2774,7 +2710,6 @@ fn genBinOp( |
| 2774 | 2710 | |
| 2775 | 2711 | _ = try func.addInst(.{ |
| 2776 | 2712 | .tag = .sltu, |
| 2777 | .ops = .rrr, | |
| 2778 | 2713 | .data = .{ .r_type = .{ |
| 2779 | 2714 | .rd = dst_reg, |
| 2780 | 2715 | .rs1 = tmp_reg, |
| ... | ... | @@ -2785,7 +2720,6 @@ fn genBinOp( |
| 2785 | 2720 | // neg dst_reg, dst_reg |
| 2786 | 2721 | _ = try func.addInst(.{ |
| 2787 | 2722 | .tag = .sub, |
| 2788 | .ops = .rrr, | |
| 2789 | 2723 | .data = .{ .r_type = .{ |
| 2790 | 2724 | .rd = dst_reg, |
| 2791 | 2725 | .rs1 = .zero, |
| ... | ... | @@ -2795,7 +2729,6 @@ fn genBinOp( |
| 2795 | 2729 | |
| 2796 | 2730 | _ = try func.addInst(.{ |
| 2797 | 2731 | .tag = .@"or", |
| 2798 | .ops = .rrr, | |
| 2799 | 2732 | .data = .{ .r_type = .{ |
| 2800 | 2733 | .rd = dst_reg, |
| 2801 | 2734 | .rs1 = dst_reg, |
| ... | ... | @@ -2850,7 +2783,6 @@ fn genBinOp( |
| 2850 | 2783 | .bit_or, .bool_or => .@"or", |
| 2851 | 2784 | else => unreachable, |
| 2852 | 2785 | }, |
| 2853 | .ops = .rrr, | |
| 2854 | 2786 | .data = .{ |
| 2855 | 2787 | .r_type = .{ |
| 2856 | 2788 | .rd = dst_reg, |
| ... | ... | @@ -2876,7 +2808,7 @@ fn genBinOp( |
| 2876 | 2808 | if (bit_size > 64) return func.fail("TODO: genBinOp shift > 64 bits, {}", .{bit_size}); |
| 2877 | 2809 | try func.truncateRegister(rhs_ty, rhs_reg); |
| 2878 | 2810 | |
| 2879 | const mir_tag: Mir.Inst.Tag = switch (tag) { | |
| 2811 | const mir_tag: Mnemonic = switch (tag) { | |
| 2880 | 2812 | .shl, .shl_exact => switch (bit_size) { |
| 2881 | 2813 | 1...31, 33...64 => .sll, |
| 2882 | 2814 | 32 => .sllw, |
| ... | ... | @@ -2892,7 +2824,6 @@ fn genBinOp( |
| 2892 | 2824 | |
| 2893 | 2825 | _ = try func.addInst(.{ |
| 2894 | 2826 | .tag = mir_tag, |
| 2895 | .ops = .rrr, | |
| 2896 | 2827 | .data = .{ .r_type = .{ |
| 2897 | 2828 | .rd = dst_reg, |
| 2898 | 2829 | .rs1 = lhs_reg, |
| ... | ... | @@ -2910,8 +2841,7 @@ fn genBinOp( |
| 2910 | 2841 | .cmp_gte, |
| 2911 | 2842 | => { |
| 2912 | 2843 | _ = try func.addInst(.{ |
| 2913 | .tag = .pseudo, | |
| 2914 | .ops = .pseudo_compare, | |
| 2844 | .tag = .pseudo_compare, | |
| 2915 | 2845 | .data = .{ |
| 2916 | 2846 | .compare = .{ |
| 2917 | 2847 | .op = switch (tag) { |
| ... | ... | @@ -2966,7 +2896,6 @@ fn genBinOp( |
| 2966 | 2896 | |
| 2967 | 2897 | _ = try func.addInst(.{ |
| 2968 | 2898 | .tag = if (int_info.signedness == .unsigned) .sltu else .slt, |
| 2969 | .ops = .rrr, | |
| 2970 | 2899 | .data = .{ .r_type = .{ |
| 2971 | 2900 | .rd = mask_reg, |
| 2972 | 2901 | .rs1 = lhs_reg, |
| ... | ... | @@ -2976,7 +2905,6 @@ fn genBinOp( |
| 2976 | 2905 | |
| 2977 | 2906 | _ = try func.addInst(.{ |
| 2978 | 2907 | .tag = .sub, |
| 2979 | .ops = .rrr, | |
| 2980 | 2908 | .data = .{ .r_type = .{ |
| 2981 | 2909 | .rd = mask_reg, |
| 2982 | 2910 | .rs1 = .zero, |
| ... | ... | @@ -2986,7 +2914,6 @@ fn genBinOp( |
| 2986 | 2914 | |
| 2987 | 2915 | _ = try func.addInst(.{ |
| 2988 | 2916 | .tag = .xor, |
| 2989 | .ops = .rrr, | |
| 2990 | 2917 | .data = .{ .r_type = .{ |
| 2991 | 2918 | .rd = dst_reg, |
| 2992 | 2919 | .rs1 = lhs_reg, |
| ... | ... | @@ -2996,7 +2923,6 @@ fn genBinOp( |
| 2996 | 2923 | |
| 2997 | 2924 | _ = try func.addInst(.{ |
| 2998 | 2925 | .tag = .@"and", |
| 2999 | .ops = .rrr, | |
| 3000 | 2926 | .data = .{ .r_type = .{ |
| 3001 | 2927 | .rd = mask_reg, |
| 3002 | 2928 | .rs1 = dst_reg, |
| ... | ... | @@ -3006,7 +2932,6 @@ fn genBinOp( |
| 3006 | 2932 | |
| 3007 | 2933 | _ = try func.addInst(.{ |
| 3008 | 2934 | .tag = .xor, |
| 3009 | .ops = .rrr, | |
| 3010 | 2935 | .data = .{ .r_type = .{ |
| 3011 | 2936 | .rd = dst_reg, |
| 3012 | 2937 | .rs1 = if (tag == .min) rhs_reg else lhs_reg, |
| ... | ... | @@ -3103,7 +3028,6 @@ fn airAddWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 3103 | 3028 | |
| 3104 | 3029 | _ = try func.addInst(.{ |
| 3105 | 3030 | .tag = .add, |
| 3106 | .ops = .rrr, | |
| 3107 | 3031 | .data = .{ .r_type = .{ |
| 3108 | 3032 | .rs1 = rhs_reg, |
| 3109 | 3033 | .rs2 = lhs_reg, |
| ... | ... | @@ -3209,7 +3133,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 3209 | 3133 | .unsigned => { |
| 3210 | 3134 | _ = try func.addInst(.{ |
| 3211 | 3135 | .tag = .sltu, |
| 3212 | .ops = .rrr, | |
| 3213 | 3136 | .data = .{ .r_type = .{ |
| 3214 | 3137 | .rd = overflow_reg, |
| 3215 | 3138 | .rs1 = lhs_reg, |
| ... | ... | @@ -3231,7 +3154,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 3231 | 3154 | 64 => { |
| 3232 | 3155 | _ = try func.addInst(.{ |
| 3233 | 3156 | .tag = .slt, |
| 3234 | .ops = .rrr, | |
| 3235 | 3157 | .data = .{ .r_type = .{ |
| 3236 | 3158 | .rd = overflow_reg, |
| 3237 | 3159 | .rs1 = overflow_reg, |
| ... | ... | @@ -3241,7 +3163,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 3241 | 3163 | |
| 3242 | 3164 | _ = try func.addInst(.{ |
| 3243 | 3165 | .tag = .slt, |
| 3244 | .ops = .rrr, | |
| 3245 | 3166 | .data = .{ .r_type = .{ |
| 3246 | 3167 | .rd = rhs_reg, |
| 3247 | 3168 | .rs1 = rhs_reg, |
| ... | ... | @@ -3251,7 +3172,6 @@ fn airSubWithOverflow(func: *Func, inst: Air.Inst.Index) !void { |
| 3251 | 3172 | |
| 3252 | 3173 | _ = try func.addInst(.{ |
| 3253 | 3174 | .tag = .xor, |
| 3254 | .ops = .rrr, | |
| 3255 | 3175 | .data = .{ .r_type = .{ |
| 3256 | 3176 | .rd = lhs_reg, |
| 3257 | 3177 | .rs1 = overflow_reg, |
| ... | ... | @@ -3843,7 +3763,6 @@ fn genSliceElemPtr(func: *Func, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref) !MCValue { |
| 3843 | 3763 | |
| 3844 | 3764 | _ = try func.addInst(.{ |
| 3845 | 3765 | .tag = .add, |
| 3846 | .ops = .rrr, | |
| 3847 | 3766 | .data = .{ .r_type = .{ |
| 3848 | 3767 | .rd = addr_reg, |
| 3849 | 3768 | .rs1 = addr_reg, |
| ... | ... | @@ -3907,7 +3826,6 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3907 | 3826 | |
| 3908 | 3827 | _ = try func.addInst(.{ |
| 3909 | 3828 | .tag = .vslidedownvx, |
| 3910 | .ops = .rrr, | |
| 3911 | 3829 | .data = .{ .r_type = .{ |
| 3912 | 3830 | .rd = src_reg, |
| 3913 | 3831 | .rs1 = index_reg, |
| ... | ... | @@ -3925,7 +3843,6 @@ fn airArrayElemVal(func: *Func, inst: Air.Inst.Index) !void { |
| 3925 | 3843 | defer func.register_manager.unlockReg(offset_lock); |
| 3926 | 3844 | _ = try func.addInst(.{ |
| 3927 | 3845 | .tag = .add, |
| 3928 | .ops = .rrr, | |
| 3929 | 3846 | .data = .{ .r_type = .{ |
| 3930 | 3847 | .rd = addr_reg, |
| 3931 | 3848 | .rs1 = addr_reg, |
| ... | ... | @@ -4080,7 +3997,6 @@ fn airClz(func: *Func, inst: Air.Inst.Index) !void { |
| 4080 | 3997 | 32 => .clzw, |
| 4081 | 3998 | else => .clz, |
| 4082 | 3999 | }, |
| 4083 | .ops = .rrr, | |
| 4084 | 4000 | .data = .{ |
| 4085 | 4001 | .r_type = .{ |
| 4086 | 4002 | .rs2 = .zero, // rs2 is 0 filled in the spec |
| ... | ... | @@ -4093,7 +4009,6 @@ fn airClz(func: *Func, inst: Air.Inst.Index) !void { |
| 4093 | 4009 | if (!(bit_size == 32 or bit_size == 64)) { |
| 4094 | 4010 | _ = try func.addInst(.{ |
| 4095 | 4011 | .tag = .addi, |
| 4096 | .ops = .rri, | |
| 4097 | 4012 | .data = .{ .i_type = .{ |
| 4098 | 4013 | .rd = dst_reg, |
| 4099 | 4014 | .rs1 = dst_reg, |
| ... | ... | @@ -4151,7 +4066,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { |
| 4151 | 4066 | 64 => .srai, |
| 4152 | 4067 | else => unreachable, |
| 4153 | 4068 | }, |
| 4154 | .ops = .rri, | |
| 4155 | 4069 | .data = .{ .i_type = .{ |
| 4156 | 4070 | .rd = temp_reg, |
| 4157 | 4071 | .rs1 = operand_reg, |
| ... | ... | @@ -4161,7 +4075,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { |
| 4161 | 4075 | |
| 4162 | 4076 | _ = try func.addInst(.{ |
| 4163 | 4077 | .tag = .xor, |
| 4164 | .ops = .rrr, | |
| 4165 | 4078 | .data = .{ .r_type = .{ |
| 4166 | 4079 | .rd = operand_reg, |
| 4167 | 4080 | .rs1 = operand_reg, |
| ... | ... | @@ -4175,7 +4088,6 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { |
| 4175 | 4088 | 64 => .sub, |
| 4176 | 4089 | else => unreachable, |
| 4177 | 4090 | }, |
| 4178 | .ops = .rrr, | |
| 4179 | 4091 | .data = .{ .r_type = .{ |
| 4180 | 4092 | .rd = operand_reg, |
| 4181 | 4093 | .rs1 = operand_reg, |
| ... | ... | @@ -4187,14 +4099,14 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { |
| 4187 | 4099 | }, |
| 4188 | 4100 | .Float => { |
| 4189 | 4101 | const float_bits = scalar_ty.floatBits(zcu.getTarget()); |
| 4190 | switch (float_bits) { | |
| 4102 | const mnem: Mnemonic = switch (float_bits) { | |
| 4191 | 4103 | 16 => return func.fail("TODO: airAbs 16-bit float", .{}), |
| 4192 | 32 => {}, | |
| 4193 | 64 => {}, | |
| 4104 | 32 => .fsgnjxs, | |
| 4105 | 64 => .fsgnjxd, | |
| 4194 | 4106 | 80 => return func.fail("TODO: airAbs 80-bit float", .{}), |
| 4195 | 4107 | 128 => return func.fail("TODO: airAbs 128-bit float", .{}), |
| 4196 | 4108 | else => unreachable, |
| 4197 | } | |
| 4109 | }; | |
| 4198 | 4110 | |
| 4199 | 4111 | const return_mcv = try func.copyToNewRegister(inst, operand); |
| 4200 | 4112 | const operand_reg = return_mcv.register; |
| ... | ... | @@ -4202,13 +4114,12 @@ fn airAbs(func: *Func, inst: Air.Inst.Index) !void { |
| 4202 | 4114 | assert(operand_reg.class() == .float); |
| 4203 | 4115 | |
| 4204 | 4116 | _ = try func.addInst(.{ |
| 4205 | .tag = .pseudo, | |
| 4206 | .ops = .pseudo_fabs, | |
| 4117 | .tag = mnem, | |
| 4207 | 4118 | .data = .{ |
| 4208 | .fabs = .{ | |
| 4119 | .r_type = .{ | |
| 4209 | 4120 | .rd = operand_reg, |
| 4210 | .rs = operand_reg, | |
| 4211 | .bits = float_bits, | |
| 4121 | .rs1 = operand_reg, | |
| 4122 | .rs2 = operand_reg, | |
| 4212 | 4123 | }, |
| 4213 | 4124 | }, |
| 4214 | 4125 | }); |
| ... | ... | @@ -4231,54 +4142,56 @@ fn airByteSwap(func: *Func, inst: Air.Inst.Index) !void { |
| 4231 | 4142 | const ty = func.typeOf(ty_op.operand); |
| 4232 | 4143 | const operand = try func.resolveInst(ty_op.operand); |
| 4233 | 4144 | |
| 4234 | const int_bits = ty.intInfo(zcu).bits; | |
| 4145 | switch (ty.zigTypeTag(zcu)) { | |
| 4146 | .Int => { | |
| 4147 | const int_bits = ty.intInfo(zcu).bits; | |
| 4235 | 4148 | |
| 4236 | // bytes are no-op | |
| 4237 | if (int_bits == 8 and func.reuseOperand(inst, ty_op.operand, 0, operand)) { | |
| 4238 | return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); | |
| 4239 | } | |
| 4149 | // bytes are no-op | |
| 4150 | if (int_bits == 8 and func.reuseOperand(inst, ty_op.operand, 0, operand)) { | |
| 4151 | return func.finishAir(inst, operand, .{ ty_op.operand, .none, .none }); | |
| 4152 | } | |
| 4240 | 4153 | |
| 4241 | const dest_mcv = try func.copyToNewRegister(inst, operand); | |
| 4242 | const dest_reg = dest_mcv.register; | |
| 4154 | const dest_mcv = try func.copyToNewRegister(inst, operand); | |
| 4155 | const dest_reg = dest_mcv.register; | |
| 4243 | 4156 | |
| 4244 | switch (int_bits) { | |
| 4245 | 16 => { | |
| 4246 | const temp_reg, const temp_lock = try func.allocReg(.int); | |
| 4247 | defer func.register_manager.unlockReg(temp_lock); | |
| 4157 | switch (int_bits) { | |
| 4158 | 16 => { | |
| 4159 | const temp_reg, const temp_lock = try func.allocReg(.int); | |
| 4160 | defer func.register_manager.unlockReg(temp_lock); | |
| 4248 | 4161 | |
| 4249 | _ = try func.addInst(.{ | |
| 4250 | .tag = .srli, | |
| 4251 | .ops = .rri, | |
| 4252 | .data = .{ .i_type = .{ | |
| 4253 | .imm12 = Immediate.s(8), | |
| 4254 | .rd = temp_reg, | |
| 4255 | .rs1 = dest_reg, | |
| 4256 | } }, | |
| 4257 | }); | |
| 4162 | _ = try func.addInst(.{ | |
| 4163 | .tag = .srli, | |
| 4164 | .data = .{ .i_type = .{ | |
| 4165 | .imm12 = Immediate.s(8), | |
| 4166 | .rd = temp_reg, | |
| 4167 | .rs1 = dest_reg, | |
| 4168 | } }, | |
| 4169 | }); | |
| 4258 | 4170 | |
| 4259 | _ = try func.addInst(.{ | |
| 4260 | .tag = .slli, | |
| 4261 | .ops = .rri, | |
| 4262 | .data = .{ .i_type = .{ | |
| 4263 | .imm12 = Immediate.s(8), | |
| 4264 | .rd = dest_reg, | |
| 4265 | .rs1 = dest_reg, | |
| 4266 | } }, | |
| 4267 | }); | |
| 4268 | _ = try func.addInst(.{ | |
| 4269 | .tag = .@"or", | |
| 4270 | .ops = .rri, | |
| 4271 | .data = .{ .r_type = .{ | |
| 4272 | .rd = dest_reg, | |
| 4273 | .rs1 = dest_reg, | |
| 4274 | .rs2 = temp_reg, | |
| 4275 | } }, | |
| 4276 | }); | |
| 4171 | _ = try func.addInst(.{ | |
| 4172 | .tag = .slli, | |
| 4173 | .data = .{ .i_type = .{ | |
| 4174 | .imm12 = Immediate.s(8), | |
| 4175 | .rd = dest_reg, | |
| 4176 | .rs1 = dest_reg, | |
| 4177 | } }, | |
| 4178 | }); | |
| 4179 | _ = try func.addInst(.{ | |
| 4180 | .tag = .@"or", | |
| 4181 | .data = .{ .r_type = .{ | |
| 4182 | .rd = dest_reg, | |
| 4183 | .rs1 = dest_reg, | |
| 4184 | .rs2 = temp_reg, | |
| 4185 | } }, | |
| 4186 | }); | |
| 4187 | }, | |
| 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 | 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 | 4235 | .sqrt => { |
| 4323 | 4236 | _ = try func.addInst(.{ |
| 4324 | 4237 | .tag = if (operand_bit_size == 64) .fsqrtd else .fsqrts, |
| 4325 | .ops = .rrr, | |
| 4326 | 4238 | .data = .{ |
| 4327 | 4239 | .r_type = .{ |
| 4328 | 4240 | .rd = dst_reg, |
| ... | ... | @@ -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 | 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 | 4451 | const zcu = pt.zcu; |
| 4539 | 4452 | const ptr_field_ty = func.typeOfIndex(inst); |
| 4540 | 4453 | const ptr_container_ty = func.typeOf(operand); |
| 4541 | const ptr_container_ty_info = ptr_container_ty.ptrInfo(zcu); | |
| 4542 | 4454 | const container_ty = ptr_container_ty.childType(zcu); |
| 4543 | 4455 | |
| 4544 | const field_offset: i32 = if (zcu.typeToPackedStruct(container_ty)) |struct_obj| | |
| 4545 | if (ptr_field_ty.ptrInfo(zcu).packed_offset.host_size == 0) | |
| 4546 | @divExact(pt.structPackedFieldBitOffset(struct_obj, index) + | |
| 4547 | ptr_container_ty_info.packed_offset.bit_offset, 8) | |
| 4548 | else | |
| 4549 | 0 | |
| 4550 | else | |
| 4551 | @intCast(container_ty.structFieldOffset(index, pt)); | |
| 4456 | const field_offset: i32 = switch (container_ty.containerLayout(zcu)) { | |
| 4457 | .auto, .@"extern" => @intCast(container_ty.structFieldOffset(index, pt)), | |
| 4458 | .@"packed" => @divExact(@as(i32, ptr_container_ty.ptrInfo(zcu).packed_offset.bit_offset) + | |
| 4459 | (if (zcu.typeToStruct(container_ty)) |struct_obj| pt.structPackedFieldBitOffset(struct_obj, index) else 0) - | |
| 4460 | ptr_field_ty.ptrInfo(zcu).packed_offset.bit_offset, 8), | |
| 4461 | }; | |
| 4552 | 4462 | |
| 4553 | 4463 | const src_mcv = try func.resolveInst(operand); |
| 4554 | 4464 | const dst_mcv = if (switch (src_mcv) { |
| ... | ... | @@ -4600,7 +4510,6 @@ fn airStructFieldVal(func: *Func, inst: Air.Inst.Index) !void { |
| 4600 | 4510 | if (field_off > 0) { |
| 4601 | 4511 | _ = try func.addInst(.{ |
| 4602 | 4512 | .tag = .srli, |
| 4603 | .ops = .rri, | |
| 4604 | 4513 | .data = .{ .i_type = .{ |
| 4605 | 4514 | .imm12 = Immediate.u(@intCast(field_off)), |
| 4606 | 4515 | .rd = dst_reg, |
| ... | ... | @@ -4720,8 +4629,7 @@ fn airArg(func: *Func, inst: Air.Inst.Index) !void { |
| 4720 | 4629 | fn airTrap(func: *Func) !void { |
| 4721 | 4630 | _ = try func.addInst(.{ |
| 4722 | 4631 | .tag = .unimp, |
| 4723 | .ops = .none, | |
| 4724 | .data = undefined, | |
| 4632 | .data = .none, | |
| 4725 | 4633 | }); |
| 4726 | 4634 | return func.finishAirBookkeeping(); |
| 4727 | 4635 | } |
| ... | ... | @@ -4729,8 +4637,7 @@ fn airTrap(func: *Func) !void { |
| 4729 | 4637 | fn airBreakpoint(func: *Func) !void { |
| 4730 | 4638 | _ = try func.addInst(.{ |
| 4731 | 4639 | .tag = .ebreak, |
| 4732 | .ops = .none, | |
| 4733 | .data = undefined, | |
| 4640 | .data = .none, | |
| 4734 | 4641 | }); |
| 4735 | 4642 | return func.finishAirBookkeeping(); |
| 4736 | 4643 | } |
| ... | ... | @@ -4758,8 +4665,7 @@ fn airFence(func: *Func, inst: Air.Inst.Index) !void { |
| 4758 | 4665 | }; |
| 4759 | 4666 | |
| 4760 | 4667 | _ = try func.addInst(.{ |
| 4761 | .tag = .pseudo, | |
| 4762 | .ops = .pseudo_fence, | |
| 4668 | .tag = .pseudo_fence, | |
| 4763 | 4669 | .data = .{ |
| 4764 | 4670 | .fence = .{ |
| 4765 | 4671 | .pred = pred, |
| ... | ... | @@ -4951,7 +4857,6 @@ fn genCall( |
| 4951 | 4857 | try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } }); |
| 4952 | 4858 | _ = try func.addInst(.{ |
| 4953 | 4859 | .tag = .jalr, |
| 4954 | .ops = .rri, | |
| 4955 | 4860 | .data = .{ .i_type = .{ |
| 4956 | 4861 | .rd = .ra, |
| 4957 | 4862 | .rs1 = .ra, |
| ... | ... | @@ -4967,16 +4872,15 @@ fn genCall( |
| 4967 | 4872 | const decl_name = owner_decl.name.toSlice(&zcu.intern_pool); |
| 4968 | 4873 | const atom_index = try func.owner.getSymbolIndex(func); |
| 4969 | 4874 | |
| 4970 | if (func.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 4971 | _ = try func.addInst(.{ | |
| 4972 | .tag = .pseudo, | |
| 4973 | .ops = .pseudo_extern_fn_reloc, | |
| 4974 | .data = .{ .reloc = .{ | |
| 4975 | .atom_index = atom_index, | |
| 4976 | .sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name), | |
| 4977 | } }, | |
| 4978 | }); | |
| 4979 | } else unreachable; // not a valid riscv64 format | |
| 4875 | const elf_file = func.bin_file.cast(link.File.Elf).?; | |
| 4876 | _ = try func.addInst(.{ | |
| 4877 | .tag = .pseudo_extern_fn_reloc, | |
| 4878 | .data = .{ .reloc = .{ | |
| 4879 | .register = .ra, | |
| 4880 | .atom_index = atom_index, | |
| 4881 | .sym_index = try elf_file.getGlobalSymbol(decl_name, lib_name), | |
| 4882 | } }, | |
| 4883 | }); | |
| 4980 | 4884 | }, |
| 4981 | 4885 | else => return func.fail("TODO implement calling bitcasted functions", .{}), |
| 4982 | 4886 | } |
| ... | ... | @@ -4988,7 +4892,6 @@ fn genCall( |
| 4988 | 4892 | |
| 4989 | 4893 | _ = try func.addInst(.{ |
| 4990 | 4894 | .tag = .jalr, |
| 4991 | .ops = .rri, | |
| 4992 | 4895 | .data = .{ .i_type = .{ |
| 4993 | 4896 | .rd = .ra, |
| 4994 | 4897 | .rs1 = addr_reg, |
| ... | ... | @@ -5065,9 +4968,11 @@ fn airRet(func: *Func, inst: Air.Inst.Index, safety: bool) !void { |
| 5065 | 4968 | |
| 5066 | 4969 | // Just add space for an instruction, reloced this later |
| 5067 | 4970 | const index = try func.addInst(.{ |
| 5068 | .tag = .pseudo, | |
| 5069 | .ops = .pseudo_j, | |
| 5070 | .data = .{ .inst = undefined }, | |
| 4971 | .tag = .pseudo_j, | |
| 4972 | .data = .{ .j_type = .{ | |
| 4973 | .rd = .zero, | |
| 4974 | .inst = undefined, | |
| 4975 | } }, | |
| 5071 | 4976 | }); |
| 5072 | 4977 | |
| 5073 | 4978 | try func.exitlude_jump_relocs.append(func.gpa, index); |
| ... | ... | @@ -5089,9 +4994,11 @@ fn airRetLoad(func: *Func, inst: Air.Inst.Index) !void { |
| 5089 | 4994 | |
| 5090 | 4995 | // Just add space for an instruction, reloced this later |
| 5091 | 4996 | const index = try func.addInst(.{ |
| 5092 | .tag = .pseudo, | |
| 5093 | .ops = .pseudo_j, | |
| 5094 | .data = .{ .inst = undefined }, | |
| 4997 | .tag = .pseudo_j, | |
| 4998 | .data = .{ .j_type = .{ | |
| 4999 | .rd = .zero, | |
| 5000 | .inst = undefined, | |
| 5001 | } }, | |
| 5095 | 5002 | }); |
| 5096 | 5003 | |
| 5097 | 5004 | try func.exitlude_jump_relocs.append(func.gpa, index); |
| ... | ... | @@ -5171,8 +5078,7 @@ fn airDbgStmt(func: *Func, inst: Air.Inst.Index) !void { |
| 5171 | 5078 | const dbg_stmt = func.air.instructions.items(.data)[@intFromEnum(inst)].dbg_stmt; |
| 5172 | 5079 | |
| 5173 | 5080 | _ = try func.addInst(.{ |
| 5174 | .tag = .pseudo, | |
| 5175 | .ops = .pseudo_dbg_line_column, | |
| 5081 | .tag = .pseudo_dbg_line_column, | |
| 5176 | 5082 | .data = .{ .pseudo_dbg_line_column = .{ |
| 5177 | 5083 | .line = dbg_stmt.line, |
| 5178 | 5084 | .column = dbg_stmt.column, |
| ... | ... | @@ -5290,7 +5196,6 @@ fn condBr(func: *Func, cond_ty: Type, condition: MCValue) !Mir.Inst.Index { |
| 5290 | 5196 | |
| 5291 | 5197 | return try func.addInst(.{ |
| 5292 | 5198 | .tag = .beq, |
| 5293 | .ops = .rr_inst, | |
| 5294 | 5199 | .data = .{ |
| 5295 | 5200 | .b_type = .{ |
| 5296 | 5201 | .rs1 = cond_reg, |
| ... | ... | @@ -5332,8 +5237,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 5332 | 5237 | .register => |opt_reg| { |
| 5333 | 5238 | if (some_info.off == 0) { |
| 5334 | 5239 | _ = try func.addInst(.{ |
| 5335 | .tag = .pseudo, | |
| 5336 | .ops = .pseudo_compare, | |
| 5240 | .tag = .pseudo_compare, | |
| 5337 | 5241 | .data = .{ |
| 5338 | 5242 | .compare = .{ |
| 5339 | 5243 | .op = .eq, |
| ... | ... | @@ -5382,8 +5286,7 @@ fn isNull(func: *Func, inst: Air.Inst.Index, opt_ty: Type, opt_mcv: MCValue) !MC |
| 5382 | 5286 | defer func.register_manager.unlockReg(opt_reg_lock); |
| 5383 | 5287 | |
| 5384 | 5288 | _ = try func.addInst(.{ |
| 5385 | .tag = .pseudo, | |
| 5386 | .ops = .pseudo_compare, | |
| 5289 | .tag = .pseudo_compare, | |
| 5387 | 5290 | .data = .{ |
| 5388 | 5291 | .compare = .{ |
| 5389 | 5292 | .op = .eq, |
| ... | ... | @@ -5432,8 +5335,7 @@ fn airIsNonNull(func: *Func, inst: Air.Inst.Index) !void { |
| 5432 | 5335 | assert(result == .register); |
| 5433 | 5336 | |
| 5434 | 5337 | _ = try func.addInst(.{ |
| 5435 | .tag = .pseudo, | |
| 5436 | .ops = .pseudo_not, | |
| 5338 | .tag = .pseudo_not, | |
| 5437 | 5339 | .data = .{ |
| 5438 | 5340 | .rr = .{ |
| 5439 | 5341 | .rd = result.register, |
| ... | ... | @@ -5565,8 +5467,7 @@ fn isNonErr(func: *Func, inst: Air.Inst.Index, eu_ty: Type, eu_mcv: MCValue) !MC |
| 5565 | 5467 | switch (is_err_res) { |
| 5566 | 5468 | .register => |reg| { |
| 5567 | 5469 | _ = try func.addInst(.{ |
| 5568 | .tag = .pseudo, | |
| 5569 | .ops = .pseudo_not, | |
| 5470 | .tag = .pseudo_not, | |
| 5570 | 5471 | .data = .{ |
| 5571 | 5472 | .rr = .{ |
| 5572 | 5473 | .rd = reg, |
| ... | ... | @@ -5633,11 +5534,11 @@ fn airLoop(func: *Func, inst: Air.Inst.Index) !void { |
| 5633 | 5534 | /// Send control flow to the `index` of `func.code`. |
| 5634 | 5535 | fn jump(func: *Func, index: Mir.Inst.Index) !Mir.Inst.Index { |
| 5635 | 5536 | return func.addInst(.{ |
| 5636 | .tag = .pseudo, | |
| 5637 | .ops = .pseudo_j, | |
| 5638 | .data = .{ | |
| 5537 | .tag = .pseudo_j, | |
| 5538 | .data = .{ .j_type = .{ | |
| 5539 | .rd = .zero, | |
| 5639 | 5540 | .inst = index, |
| 5640 | }, | |
| 5541 | } }, | |
| 5641 | 5542 | }); |
| 5642 | 5543 | } |
| 5643 | 5544 | |
| ... | ... | @@ -5727,8 +5628,7 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5727 | 5628 | |
| 5728 | 5629 | if (!(i < relocs.len - 1)) { |
| 5729 | 5630 | _ = try func.addInst(.{ |
| 5730 | .tag = .pseudo, | |
| 5731 | .ops = .pseudo_not, | |
| 5631 | .tag = .pseudo_not, | |
| 5732 | 5632 | .data = .{ .rr = .{ |
| 5733 | 5633 | .rd = cmp_reg, |
| 5734 | 5634 | .rs = cmp_reg, |
| ... | ... | @@ -5775,18 +5675,13 @@ fn airSwitchBr(func: *Func, inst: Air.Inst.Index) !void { |
| 5775 | 5675 | |
| 5776 | 5676 | fn performReloc(func: *Func, inst: Mir.Inst.Index) void { |
| 5777 | 5677 | const tag = func.mir_instructions.items(.tag)[inst]; |
| 5778 | const ops = func.mir_instructions.items(.ops)[inst]; | |
| 5779 | 5678 | const target: Mir.Inst.Index = @intCast(func.mir_instructions.len); |
| 5780 | 5679 | |
| 5781 | 5680 | switch (tag) { |
| 5782 | .bne, | |
| 5783 | 5681 | .beq, |
| 5784 | 5682 | => func.mir_instructions.items(.data)[inst].b_type.inst = target, |
| 5785 | 5683 | .jal => func.mir_instructions.items(.data)[inst].j_type.inst = target, |
| 5786 | .pseudo => switch (ops) { | |
| 5787 | .pseudo_j => func.mir_instructions.items(.data)[inst].inst = target, | |
| 5788 | else => std.debug.panic("TODO: performReloc {s}", .{@tagName(ops)}), | |
| 5789 | }, | |
| 5684 | .pseudo_j => func.mir_instructions.items(.data)[inst].j_type.inst = target, | |
| 5790 | 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 | 5768 | |
| 5874 | 5769 | _ = try func.addInst(.{ |
| 5875 | 5770 | .tag = if (tag == .bool_or) .@"or" else .@"and", |
| 5876 | .ops = .rrr, | |
| 5877 | 5771 | .data = .{ .r_type = .{ |
| 5878 | 5772 | .rd = result_reg, |
| 5879 | 5773 | .rs1 = lhs_reg, |
| ... | ... | @@ -5885,7 +5779,6 @@ fn airBoolOp(func: *Func, inst: Air.Inst.Index) !void { |
| 5885 | 5779 | if (func.wantSafety()) { |
| 5886 | 5780 | _ = try func.addInst(.{ |
| 5887 | 5781 | .tag = .andi, |
| 5888 | .ops = .rri, | |
| 5889 | 5782 | .data = .{ .i_type = .{ |
| 5890 | 5783 | .rd = result_reg, |
| 5891 | 5784 | .rs1 = result_reg, |
| ... | ... | @@ -5970,11 +5863,10 @@ fn airAsm(func: *Func, inst: Air.Inst.Index) !void { |
| 5970 | 5863 | |
| 5971 | 5864 | const asm_source = std.mem.sliceAsBytes(func.air.extra[extra_i..])[0..extra.data.source_len]; |
| 5972 | 5865 | |
| 5973 | if (std.meta.stringToEnum(Mir.Inst.Tag, asm_source)) |tag| { | |
| 5866 | if (std.meta.stringToEnum(Mnemonic, asm_source)) |tag| { | |
| 5974 | 5867 | _ = try func.addInst(.{ |
| 5975 | 5868 | .tag = tag, |
| 5976 | .ops = .none, | |
| 5977 | .data = undefined, | |
| 5869 | .data = .none, | |
| 5978 | 5870 | }); |
| 5979 | 5871 | } else { |
| 5980 | 5872 | return func.fail("TODO: asm_source {s}", .{asm_source}); |
| ... | ... | @@ -6116,7 +6008,6 @@ fn genInlineMemcpy( |
| 6116 | 6008 | // if count is 0, there's nothing to copy |
| 6117 | 6009 | _ = try func.addInst(.{ |
| 6118 | 6010 | .tag = .beq, |
| 6119 | .ops = .rr_inst, | |
| 6120 | 6011 | .data = .{ .b_type = .{ |
| 6121 | 6012 | .rs1 = count, |
| 6122 | 6013 | .rs2 = .zero, |
| ... | ... | @@ -6127,7 +6018,6 @@ fn genInlineMemcpy( |
| 6127 | 6018 | // lb tmp, 0(src) |
| 6128 | 6019 | const first_inst = try func.addInst(.{ |
| 6129 | 6020 | .tag = .lb, |
| 6130 | .ops = .rri, | |
| 6131 | 6021 | .data = .{ |
| 6132 | 6022 | .i_type = .{ |
| 6133 | 6023 | .rd = tmp, |
| ... | ... | @@ -6140,7 +6030,6 @@ fn genInlineMemcpy( |
| 6140 | 6030 | // sb tmp, 0(dst) |
| 6141 | 6031 | _ = try func.addInst(.{ |
| 6142 | 6032 | .tag = .sb, |
| 6143 | .ops = .rri, | |
| 6144 | 6033 | .data = .{ |
| 6145 | 6034 | .i_type = .{ |
| 6146 | 6035 | .rd = dst, |
| ... | ... | @@ -6153,7 +6042,6 @@ fn genInlineMemcpy( |
| 6153 | 6042 | // dec count by 1 |
| 6154 | 6043 | _ = try func.addInst(.{ |
| 6155 | 6044 | .tag = .addi, |
| 6156 | .ops = .rri, | |
| 6157 | 6045 | .data = .{ |
| 6158 | 6046 | .i_type = .{ |
| 6159 | 6047 | .rd = count, |
| ... | ... | @@ -6166,7 +6054,6 @@ fn genInlineMemcpy( |
| 6166 | 6054 | // branch if count is 0 |
| 6167 | 6055 | _ = try func.addInst(.{ |
| 6168 | 6056 | .tag = .beq, |
| 6169 | .ops = .rr_inst, | |
| 6170 | 6057 | .data = .{ |
| 6171 | 6058 | .b_type = .{ |
| 6172 | 6059 | .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst |
| ... | ... | @@ -6179,7 +6066,6 @@ fn genInlineMemcpy( |
| 6179 | 6066 | // increment the pointers |
| 6180 | 6067 | _ = try func.addInst(.{ |
| 6181 | 6068 | .tag = .addi, |
| 6182 | .ops = .rri, | |
| 6183 | 6069 | .data = .{ |
| 6184 | 6070 | .i_type = .{ |
| 6185 | 6071 | .rd = src, |
| ... | ... | @@ -6191,7 +6077,6 @@ fn genInlineMemcpy( |
| 6191 | 6077 | |
| 6192 | 6078 | _ = try func.addInst(.{ |
| 6193 | 6079 | .tag = .addi, |
| 6194 | .ops = .rri, | |
| 6195 | 6080 | .data = .{ |
| 6196 | 6081 | .i_type = .{ |
| 6197 | 6082 | .rd = dst, |
| ... | ... | @@ -6203,9 +6088,11 @@ fn genInlineMemcpy( |
| 6203 | 6088 | |
| 6204 | 6089 | // jump back to start of loop |
| 6205 | 6090 | _ = try func.addInst(.{ |
| 6206 | .tag = .pseudo, | |
| 6207 | .ops = .pseudo_j, | |
| 6208 | .data = .{ .inst = first_inst }, | |
| 6091 | .tag = .pseudo_j, | |
| 6092 | .data = .{ .j_type = .{ | |
| 6093 | .rd = .zero, | |
| 6094 | .inst = first_inst, | |
| 6095 | } }, | |
| 6209 | 6096 | }); |
| 6210 | 6097 | } |
| 6211 | 6098 | |
| ... | ... | @@ -6230,7 +6117,6 @@ fn genInlineMemset( |
| 6230 | 6117 | // sb src, 0(dst) |
| 6231 | 6118 | const first_inst = try func.addInst(.{ |
| 6232 | 6119 | .tag = .sb, |
| 6233 | .ops = .rri, | |
| 6234 | 6120 | .data = .{ |
| 6235 | 6121 | .i_type = .{ |
| 6236 | 6122 | .rd = dst, |
| ... | ... | @@ -6243,7 +6129,6 @@ fn genInlineMemset( |
| 6243 | 6129 | // dec count by 1 |
| 6244 | 6130 | _ = try func.addInst(.{ |
| 6245 | 6131 | .tag = .addi, |
| 6246 | .ops = .rri, | |
| 6247 | 6132 | .data = .{ |
| 6248 | 6133 | .i_type = .{ |
| 6249 | 6134 | .rd = count, |
| ... | ... | @@ -6256,7 +6141,6 @@ fn genInlineMemset( |
| 6256 | 6141 | // branch if count is 0 |
| 6257 | 6142 | _ = try func.addInst(.{ |
| 6258 | 6143 | .tag = .beq, |
| 6259 | .ops = .rr_inst, | |
| 6260 | 6144 | .data = .{ |
| 6261 | 6145 | .b_type = .{ |
| 6262 | 6146 | .inst = @intCast(func.mir_instructions.len + 4), // points after the last inst |
| ... | ... | @@ -6269,7 +6153,6 @@ fn genInlineMemset( |
| 6269 | 6153 | // increment the pointers |
| 6270 | 6154 | _ = try func.addInst(.{ |
| 6271 | 6155 | .tag = .addi, |
| 6272 | .ops = .rri, | |
| 6273 | 6156 | .data = .{ |
| 6274 | 6157 | .i_type = .{ |
| 6275 | 6158 | .rd = dst, |
| ... | ... | @@ -6281,11 +6164,11 @@ fn genInlineMemset( |
| 6281 | 6164 | |
| 6282 | 6165 | // jump back to start of loop |
| 6283 | 6166 | _ = try func.addInst(.{ |
| 6284 | .tag = .pseudo, | |
| 6285 | .ops = .pseudo_j, | |
| 6286 | .data = .{ | |
| 6167 | .tag = .pseudo_j, | |
| 6168 | .data = .{ .j_type = .{ | |
| 6169 | .rd = .zero, | |
| 6287 | 6170 | .inst = first_inst, |
| 6288 | }, | |
| 6171 | } }, | |
| 6289 | 6172 | }); |
| 6290 | 6173 | } |
| 6291 | 6174 | |
| ... | ... | @@ -6331,7 +6214,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6331 | 6214 | if (math.minInt(i12) <= x and x <= math.maxInt(i12)) { |
| 6332 | 6215 | _ = try func.addInst(.{ |
| 6333 | 6216 | .tag = .addi, |
| 6334 | .ops = .rri, | |
| 6335 | 6217 | .data = .{ .i_type = .{ |
| 6336 | 6218 | .rd = reg, |
| 6337 | 6219 | .rs1 = .zero, |
| ... | ... | @@ -6345,7 +6227,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6345 | 6227 | |
| 6346 | 6228 | _ = try func.addInst(.{ |
| 6347 | 6229 | .tag = .lui, |
| 6348 | .ops = .ri, | |
| 6349 | 6230 | .data = .{ .u_type = .{ |
| 6350 | 6231 | .rd = reg, |
| 6351 | 6232 | .imm20 = Immediate.s(hi20), |
| ... | ... | @@ -6353,7 +6234,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6353 | 6234 | }); |
| 6354 | 6235 | _ = try func.addInst(.{ |
| 6355 | 6236 | .tag = .addi, |
| 6356 | .ops = .rri, | |
| 6357 | 6237 | .data = .{ .i_type = .{ |
| 6358 | 6238 | .rd = reg, |
| 6359 | 6239 | .rs1 = reg, |
| ... | ... | @@ -6376,7 +6256,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6376 | 6256 | |
| 6377 | 6257 | _ = try func.addInst(.{ |
| 6378 | 6258 | .tag = .slli, |
| 6379 | .ops = .rri, | |
| 6380 | 6259 | .data = .{ .i_type = .{ |
| 6381 | 6260 | .rd = reg, |
| 6382 | 6261 | .rs1 = reg, |
| ... | ... | @@ -6386,7 +6265,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6386 | 6265 | |
| 6387 | 6266 | _ = try func.addInst(.{ |
| 6388 | 6267 | .tag = .add, |
| 6389 | .ops = .rrr, | |
| 6390 | 6268 | .data = .{ .r_type = .{ |
| 6391 | 6269 | .rd = reg, |
| 6392 | 6270 | .rs1 = reg, |
| ... | ... | @@ -6423,8 +6301,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6423 | 6301 | |
| 6424 | 6302 | // mv reg, src_reg |
| 6425 | 6303 | _ = try func.addInst(.{ |
| 6426 | .tag = .pseudo, | |
| 6427 | .ops = .pseudo_mv, | |
| 6304 | .tag = .pseudo_mv, | |
| 6428 | 6305 | .data = .{ .rr = .{ |
| 6429 | 6306 | .rd = reg, |
| 6430 | 6307 | .rs = src_reg, |
| ... | ... | @@ -6445,8 +6322,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6445 | 6322 | try func.genCopy(ty, .{ .register = reg }, .{ .indirect = .{ .reg = addr_reg } }); |
| 6446 | 6323 | } else { |
| 6447 | 6324 | _ = try func.addInst(.{ |
| 6448 | .tag = .pseudo, | |
| 6449 | .ops = .pseudo_load_rm, | |
| 6325 | .tag = .pseudo_load_rm, | |
| 6450 | 6326 | .data = .{ .rm = .{ |
| 6451 | 6327 | .r = reg, |
| 6452 | 6328 | .m = .{ |
| ... | ... | @@ -6466,7 +6342,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6466 | 6342 | |
| 6467 | 6343 | _ = try func.addInst(.{ |
| 6468 | 6344 | .tag = .ld, |
| 6469 | .ops = .rri, | |
| 6470 | 6345 | .data = .{ .i_type = .{ |
| 6471 | 6346 | .rd = reg, |
| 6472 | 6347 | .rs1 = reg, |
| ... | ... | @@ -6476,8 +6351,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6476 | 6351 | }, |
| 6477 | 6352 | .lea_frame, .register_offset => { |
| 6478 | 6353 | _ = try func.addInst(.{ |
| 6479 | .tag = .pseudo, | |
| 6480 | .ops = .pseudo_lea_rm, | |
| 6354 | .tag = .pseudo_lea_rm, | |
| 6481 | 6355 | .data = .{ |
| 6482 | 6356 | .rm = .{ |
| 6483 | 6357 | .r = reg, |
| ... | ... | @@ -6505,7 +6379,7 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6505 | 6379 | }); |
| 6506 | 6380 | }, |
| 6507 | 6381 | .indirect => |reg_off| { |
| 6508 | const load_tag: Mir.Inst.Tag = switch (reg.class()) { | |
| 6382 | const load_tag: Mnemonic = switch (reg.class()) { | |
| 6509 | 6383 | .float => switch (abi_size) { |
| 6510 | 6384 | 1 => unreachable, // Zig does not support 8-bit floats |
| 6511 | 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 | 6418 | }); |
| 6545 | 6419 | |
| 6546 | 6420 | _ = try func.addInst(.{ |
| 6547 | .tag = .pseudo, | |
| 6548 | .ops = .pseudo_load_rm, | |
| 6421 | .tag = .pseudo_load_rm, | |
| 6549 | 6422 | .data = .{ .rm = .{ |
| 6550 | 6423 | .r = reg, |
| 6551 | 6424 | .m = .{ |
| ... | ... | @@ -6565,7 +6438,6 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6565 | 6438 | |
| 6566 | 6439 | _ = try func.addInst(.{ |
| 6567 | 6440 | .tag = load_tag, |
| 6568 | .ops = .rri, | |
| 6569 | 6441 | .data = .{ .i_type = .{ |
| 6570 | 6442 | .rd = reg, |
| 6571 | 6443 | .rs1 = reg_off.reg, |
| ... | ... | @@ -6578,13 +6450,12 @@ fn genSetReg(func: *Func, ty: Type, reg: Register, src_mcv: MCValue) InnerError! |
| 6578 | 6450 | const atom_index = try func.owner.getSymbolIndex(func); |
| 6579 | 6451 | |
| 6580 | 6452 | _ = try func.addInst(.{ |
| 6581 | .tag = .pseudo, | |
| 6582 | .ops = .pseudo_load_symbol, | |
| 6583 | .data = .{ .payload = try func.addExtra(Mir.LoadSymbolPayload{ | |
| 6584 | .register = reg.encodeId(), | |
| 6453 | .tag = .pseudo_load_symbol, | |
| 6454 | .data = .{ .reloc = .{ | |
| 6455 | .register = reg, | |
| 6585 | 6456 | .atom_index = atom_index, |
| 6586 | 6457 | .sym_index = sym_off.sym, |
| 6587 | }) }, | |
| 6458 | } }, | |
| 6588 | 6459 | }); |
| 6589 | 6460 | }, |
| 6590 | 6461 | .load_symbol => { |
| ... | ... | @@ -6676,8 +6547,7 @@ fn genSetMem( |
| 6676 | 6547 | }); |
| 6677 | 6548 | |
| 6678 | 6549 | _ = try func.addInst(.{ |
| 6679 | .tag = .pseudo, | |
| 6680 | .ops = .pseudo_store_rm, | |
| 6550 | .tag = .pseudo_store_rm, | |
| 6681 | 6551 | .data = .{ .rm = .{ |
| 6682 | 6552 | .r = reg, |
| 6683 | 6553 | .m = .{ |
| ... | ... | @@ -6716,8 +6586,7 @@ fn genSetMem( |
| 6716 | 6586 | })); |
| 6717 | 6587 | const frame_mcv: MCValue = .{ .load_frame = .{ .index = frame_index } }; |
| 6718 | 6588 | _ = try func.addInst(.{ |
| 6719 | .tag = .pseudo, | |
| 6720 | .ops = .pseudo_store_rm, | |
| 6589 | .tag = .pseudo_store_rm, | |
| 6721 | 6590 | .data = .{ .rm = .{ |
| 6722 | 6591 | .r = reg, |
| 6723 | 6592 | .m = .{ |
| ... | ... | @@ -6732,8 +6601,7 @@ fn genSetMem( |
| 6732 | 6601 | try func.genSetMem(base, disp, ty, frame_mcv); |
| 6733 | 6602 | try func.freeValue(frame_mcv); |
| 6734 | 6603 | } else _ = try func.addInst(.{ |
| 6735 | .tag = .pseudo, | |
| 6736 | .ops = .pseudo_store_rm, | |
| 6604 | .tag = .pseudo_store_rm, | |
| 6737 | 6605 | .data = .{ .rm = .{ |
| 6738 | 6606 | .r = reg, |
| 6739 | 6607 | .m = .{ |
| ... | ... | @@ -6852,9 +6720,59 @@ fn airFloatFromInt(func: *Func, inst: Air.Inst.Index) !void { |
| 6852 | 6720 | |
| 6853 | 6721 | fn airIntFromFloat(func: *Func, inst: Air.Inst.Index) !void { |
| 6854 | 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 {}", .{ | |
| 6856 | func.target.cpu.arch, | |
| 6857 | }); | |
| 6723 | const result: MCValue = if (func.liveness.isUnused(inst)) .unreach else result: { | |
| 6724 | const pt = func.pt; | |
| 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 | 6776 | return func.finishAir(inst, result, .{ ty_op.operand, .none, .none }); |
| 6859 | 6777 | } |
| 6860 | 6778 | |
| ... | ... | @@ -6917,8 +6835,7 @@ fn airAtomicRmw(func: *Func, inst: Air.Inst.Index) !void { |
| 6917 | 6835 | }; |
| 6918 | 6836 | |
| 6919 | 6837 | _ = try func.addInst(.{ |
| 6920 | .tag = .pseudo, | |
| 6921 | .ops = .pseudo_amo, | |
| 6838 | .tag = .pseudo_amo, | |
| 6922 | 6839 | .data = .{ .amo = .{ |
| 6923 | 6840 | .rd = result_mcv.register, |
| 6924 | 6841 | .rs1 = ptr_register, |
| ... | ... | @@ -6961,15 +6878,12 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void { |
| 6961 | 6878 | |
| 6962 | 6879 | if (order == .seq_cst) { |
| 6963 | 6880 | _ = try func.addInst(.{ |
| 6964 | .tag = .pseudo, | |
| 6965 | .ops = .pseudo_fence, | |
| 6966 | .data = .{ | |
| 6967 | .fence = .{ | |
| 6968 | .pred = .rw, | |
| 6969 | .succ = .rw, | |
| 6970 | .fm = .none, | |
| 6971 | }, | |
| 6972 | }, | |
| 6881 | .tag = .pseudo_fence, | |
| 6882 | .data = .{ .fence = .{ | |
| 6883 | .pred = .rw, | |
| 6884 | .succ = .rw, | |
| 6885 | .fm = .none, | |
| 6886 | } }, | |
| 6973 | 6887 | }); |
| 6974 | 6888 | } |
| 6975 | 6889 | |
| ... | ... | @@ -6982,8 +6896,7 @@ fn airAtomicLoad(func: *Func, inst: Air.Inst.Index) !void { |
| 6982 | 6896 | // Make sure all previous reads happen before any reading or writing accurs. |
| 6983 | 6897 | .seq_cst, .acquire => { |
| 6984 | 6898 | _ = try func.addInst(.{ |
| 6985 | .tag = .pseudo, | |
| 6986 | .ops = .pseudo_fence, | |
| 6899 | .tag = .pseudo_fence, | |
| 6987 | 6900 | .data = .{ |
| 6988 | 6901 | .fence = .{ |
| 6989 | 6902 | .pred = .r, |
| ... | ... | @@ -7015,8 +6928,7 @@ fn airAtomicStore(func: *Func, inst: Air.Inst.Index, order: std.builtin.AtomicOr |
| 7015 | 6928 | .unordered, .monotonic => {}, |
| 7016 | 6929 | .release, .seq_cst => { |
| 7017 | 6930 | _ = try func.addInst(.{ |
| 7018 | .tag = .pseudo, | |
| 7019 | .ops = .pseudo_fence, | |
| 6931 | .tag = .pseudo_fence, | |
| 7020 | 6932 | .data = .{ |
| 7021 | 6933 | .fence = .{ |
| 7022 | 6934 | .pred = .rw, |
| ... | ... | @@ -7183,7 +7095,6 @@ fn airTagName(func: *Func, inst: Air.Inst.Index) !void { |
| 7183 | 7095 | try func.genSetReg(Type.u64, .ra, .{ .load_symbol = .{ .sym = sym.esym_index } }); |
| 7184 | 7096 | _ = try func.addInst(.{ |
| 7185 | 7097 | .tag = .jalr, |
| 7186 | .ops = .rri, | |
| 7187 | 7098 | .data = .{ .i_type = .{ |
| 7188 | 7099 | .rd = .ra, |
| 7189 | 7100 | .rs1 = .ra, |
src/arch/riscv64/Emit.zig+71-77| ... | ... | @@ -40,7 +40,7 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 40 | 40 | .source = start_offset, |
| 41 | 41 | .target = target, |
| 42 | 42 | .offset = 0, |
| 43 | .enc = std.meta.activeTag(lowered_inst.encoding.data), | |
| 43 | .fmt = std.meta.activeTag(lowered_inst), | |
| 44 | 44 | }), |
| 45 | 45 | .load_symbol_reloc => |symbol| { |
| 46 | 46 | const is_obj_or_static_lib = switch (emit.lower.output_mode) { |
| ... | ... | @@ -49,46 +49,45 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 49 | 49 | .Lib => emit.lower.link_mode == .static, |
| 50 | 50 | }; |
| 51 | 51 | |
| 52 | if (emit.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 53 | const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; | |
| 54 | const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index); | |
| 55 | const sym = elf_file.symbol(sym_index); | |
| 56 | ||
| 57 | var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); | |
| 58 | var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); | |
| 59 | ||
| 60 | if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { | |
| 61 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | |
| 62 | ||
| 63 | hi_r_type = Elf.R_ZIG_GOT_HI20; | |
| 64 | lo_r_type = Elf.R_ZIG_GOT_LO12; | |
| 65 | } | |
| 66 | ||
| 67 | try atom_ptr.addReloc(elf_file, .{ | |
| 68 | .r_offset = start_offset, | |
| 69 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, | |
| 70 | .r_addend = 0, | |
| 71 | }); | |
| 72 | ||
| 73 | try atom_ptr.addReloc(elf_file, .{ | |
| 74 | .r_offset = start_offset + 4, | |
| 75 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type, | |
| 76 | .r_addend = 0, | |
| 77 | }); | |
| 78 | } else unreachable; | |
| 52 | const elf_file = emit.bin_file.cast(link.File.Elf).?; | |
| 53 | ||
| 54 | const atom_ptr = elf_file.symbol(symbol.atom_index).atom(elf_file).?; | |
| 55 | const sym_index = elf_file.zigObjectPtr().?.symbol(symbol.sym_index); | |
| 56 | const sym = elf_file.symbol(sym_index); | |
| 57 | ||
| 58 | var hi_r_type: u32 = @intFromEnum(std.elf.R_RISCV.HI20); | |
| 59 | var lo_r_type: u32 = @intFromEnum(std.elf.R_RISCV.LO12_I); | |
| 60 | ||
| 61 | if (sym.flags.needs_zig_got and !is_obj_or_static_lib) { | |
| 62 | _ = try sym.getOrCreateZigGotEntry(sym_index, elf_file); | |
| 63 | ||
| 64 | hi_r_type = Elf.R_ZIG_GOT_HI20; | |
| 65 | lo_r_type = Elf.R_ZIG_GOT_LO12; | |
| 66 | } | |
| 67 | ||
| 68 | try atom_ptr.addReloc(elf_file, .{ | |
| 69 | .r_offset = start_offset, | |
| 70 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | hi_r_type, | |
| 71 | .r_addend = 0, | |
| 72 | }); | |
| 73 | ||
| 74 | try atom_ptr.addReloc(elf_file, .{ | |
| 75 | .r_offset = start_offset + 4, | |
| 76 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | lo_r_type, | |
| 77 | .r_addend = 0, | |
| 78 | }); | |
| 79 | 79 | }, |
| 80 | 80 | .call_extern_fn_reloc => |symbol| { |
| 81 | if (emit.bin_file.cast(link.File.Elf)) |elf_file| { | |
| 82 | const atom_ptr = elf_file.symbol(symbol.atom_index).atom(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).?; | |
| 83 | 83 | |
| 84 | const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT); | |
| 84 | const r_type: u32 = @intFromEnum(std.elf.R_RISCV.CALL_PLT); | |
| 85 | 85 | |
| 86 | try atom_ptr.addReloc(elf_file, .{ | |
| 87 | .r_offset = start_offset, | |
| 88 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type, | |
| 89 | .r_addend = 0, | |
| 90 | }); | |
| 91 | } else return emit.fail("TODO: call_extern_fn_reloc non-ELF", .{}); | |
| 86 | try atom_ptr.addReloc(elf_file, .{ | |
| 87 | .r_offset = start_offset, | |
| 88 | .r_info = (@as(u64, @intCast(symbol.sym_index)) << 32) | r_type, | |
| 89 | .r_addend = 0, | |
| 90 | }); | |
| 92 | 91 | }, |
| 93 | 92 | }; |
| 94 | 93 | } |
| ... | ... | @@ -98,40 +97,37 @@ pub fn emitMir(emit: *Emit) Error!void { |
| 98 | 97 | const mir_inst = emit.lower.mir.instructions.get(mir_index); |
| 99 | 98 | switch (mir_inst.tag) { |
| 100 | 99 | else => unreachable, |
| 101 | .pseudo => switch (mir_inst.ops) { | |
| 102 | else => unreachable, | |
| 103 | .pseudo_dbg_prologue_end => { | |
| 104 | switch (emit.debug_output) { | |
| 105 | .dwarf => |dw| { | |
| 106 | try dw.setPrologueEnd(); | |
| 107 | log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ | |
| 108 | emit.prev_di_line, emit.prev_di_column, | |
| 109 | }); | |
| 110 | try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); | |
| 111 | }, | |
| 112 | .plan9 => {}, | |
| 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 => {}, | |
| 100 | .pseudo_dbg_prologue_end => { | |
| 101 | switch (emit.debug_output) { | |
| 102 | .dwarf => |dw| { | |
| 103 | try dw.setPrologueEnd(); | |
| 104 | log.debug("mirDbgPrologueEnd (line={d}, col={d})", .{ | |
| 105 | emit.prev_di_line, emit.prev_di_column, | |
| 106 | }); | |
| 107 | try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column); | |
| 108 | }, | |
| 109 | .plan9 => {}, | |
| 110 | .none => {}, | |
| 111 | } | |
| 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 | 147 | target: Mir.Inst.Index, |
| 152 | 148 | /// Offset of the relocation within the instruction. |
| 153 | 149 | offset: u32, |
| 154 | /// Encoding of the instruction, used to determine how to modify it. | |
| 155 | enc: Encoding.InstEnc, | |
| 150 | /// Format of the instruction, used to determine how to modify it. | |
| 151 | fmt: encoding.Lir.Format, | |
| 156 | 152 | }; |
| 157 | 153 | |
| 158 | 154 | fn fixupRelocs(emit: *Emit) Error!void { |
| ... | ... | @@ -164,12 +160,10 @@ fn fixupRelocs(emit: *Emit) Error!void { |
| 164 | 160 | const disp = @as(i32, @intCast(target)) - @as(i32, @intCast(reloc.source)); |
| 165 | 161 | const code: *[4]u8 = emit.code.items[reloc.source + reloc.offset ..][0..4]; |
| 166 | 162 | |
| 167 | log.debug("disp: {x}", .{disp}); | |
| 168 | ||
| 169 | switch (reloc.enc) { | |
| 163 | switch (reloc.fmt) { | |
| 170 | 164 | .J => riscv_util.writeInstJ(code, @bitCast(disp)), |
| 171 | 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 | 203 | const Lower = @import("Lower.zig"); |
| 210 | 204 | const Mir = @import("Mir.zig"); |
| 211 | 205 | const riscv_util = @import("../../link/riscv.zig"); |
| 212 | const Encoding = @import("Encoding.zig"); | |
| 213 | 206 | const Elf = @import("../../link/Elf.zig"); |
| 207 | const encoding = @import("encoding.zig"); |
src/arch/riscv64/Encoding.zig deleted-1136| ... | ... | @@ -1,1136 +0,0 @@ |
| 1 | mnemonic: Mnemonic, | |
| 2 | data: Data, | |
| 3 | ||
| 4 | const 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 | ||
| 32 | const 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 | ||
| 44 | const AmoWidth = enum(u3) { | |
| 45 | W = 0b010, | |
| 46 | D = 0b011, | |
| 47 | }; | |
| 48 | ||
| 49 | const FenceMode = enum(u4) { | |
| 50 | none = 0b0000, | |
| 51 | tso = 0b1000, | |
| 52 | }; | |
| 53 | ||
| 54 | const 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. | |
| 139 | pub 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 | ||
| 575 | pub 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 | ||
| 787 | pub 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 | ||
| 1110 | pub 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 | ||
| 1119 | fn 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 | ||
| 1126 | const std = @import("std"); | |
| 1127 | const assert = std.debug.assert; | |
| 1128 | const log = std.log.scoped(.encoding); | |
| 1129 | ||
| 1130 | const Encoding = @This(); | |
| 1131 | const bits = @import("bits.zig"); | |
| 1132 | const Register = bits.Register; | |
| 1133 | const encoder = @import("encoder.zig"); | |
| 1134 | const Instruction = encoder.Instruction; | |
| 1135 | const Operand = Instruction.Operand; | |
| 1136 | const 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 | 61 | log.debug("lowerMir {}", .{inst}); |
| 62 | 62 | switch (inst.tag) { |
| 63 | 63 | else => try lower.generic(inst), |
| 64 | .pseudo => switch (inst.ops) { | |
| 65 | .pseudo_dbg_line_column, | |
| 66 | .pseudo_dbg_epilogue_begin, | |
| 67 | .pseudo_dbg_prologue_end, | |
| 68 | .pseudo_dead, | |
| 69 | => {}, | |
| 70 | ||
| 71 | .pseudo_load_rm, .pseudo_store_rm => { | |
| 72 | const rm = inst.data.rm; | |
| 73 | ||
| 74 | const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs) | |
| 75 | rm.m.toFrameLoc(lower.mir) | |
| 76 | else | |
| 77 | .{ .base = .s0, .disp = 0 }; | |
| 78 | ||
| 79 | switch (inst.ops) { | |
| 80 | .pseudo_load_rm => { | |
| 81 | const dest_reg = rm.r; | |
| 82 | const dest_reg_class = dest_reg.class(); | |
| 83 | ||
| 84 | const src_size = rm.m.mod.size; | |
| 85 | const unsigned = rm.m.mod.unsigned; | |
| 86 | ||
| 87 | const tag: Encoding.Mnemonic = switch (dest_reg_class) { | |
| 88 | .int => switch (src_size) { | |
| 89 | .byte => if (unsigned) .lbu else .lb, | |
| 90 | .hword => if (unsigned) .lhu else .lh, | |
| 91 | .word => if (unsigned) .lwu else .lw, | |
| 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 | }); | |
| 64 | .pseudo_dbg_line_column, | |
| 65 | .pseudo_dbg_epilogue_begin, | |
| 66 | .pseudo_dbg_prologue_end, | |
| 67 | .pseudo_dead, | |
| 68 | => {}, | |
| 69 | ||
| 70 | .pseudo_load_rm, .pseudo_store_rm => { | |
| 71 | const rm = inst.data.rm; | |
| 72 | ||
| 73 | const frame_loc: Mir.FrameLoc = if (options.allow_frame_locs) | |
| 74 | rm.m.toFrameLoc(lower.mir) | |
| 75 | else | |
| 76 | .{ .base = .s0, .disp = 0 }; | |
| 77 | ||
| 78 | switch (inst.tag) { | |
| 79 | .pseudo_load_rm => { | |
| 80 | const dest_reg = rm.r; | |
| 81 | const dest_reg_class = dest_reg.class(); | |
| 82 | ||
| 83 | const src_size = rm.m.mod.size; | |
| 84 | const unsigned = rm.m.mod.unsigned; | |
| 85 | ||
| 86 | const mnem: Mnemonic = switch (dest_reg_class) { | |
| 87 | .int => switch (src_size) { | |
| 88 | .byte => if (unsigned) .lbu else .lb, | |
| 89 | .hword => if (unsigned) .lhu else .lh, | |
| 90 | .word => if (unsigned) .lwu else .lw, | |
| 91 | .dword => .ld, | |
| 189 | 92 | }, |
| 190 | .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}), | |
| 191 | }, | |
| 192 | .int => switch (dst_class) { | |
| 193 | .int => { | |
| 194 | try lower.emit(.addi, &.{ | |
| 195 | .{ .reg = rr.rd }, | |
| 196 | .{ .reg = rr.rs }, | |
| 197 | .{ .imm = Immediate.s(0) }, | |
| 198 | }); | |
| 93 | .float => switch (src_size) { | |
| 94 | .byte => unreachable, // Zig does not support 8-bit floats | |
| 95 | .hword => return lower.fail("TODO: lowerMir pseudo_load_rm support 16-bit floats", .{}), | |
| 96 | .word => .flw, | |
| 97 | .dword => .fld, | |
| 199 | 98 | }, |
| 200 | .vector => { | |
| 201 | try lower.emit(.vmvvx, &.{ | |
| 202 | .{ .reg = rr.rd }, | |
| 203 | .{ .reg = rr.rs }, | |
| 204 | .{ .reg = .x0 }, | |
| 99 | .vector => switch (src_size) { | |
| 100 | .byte => .vle8v, | |
| 101 | .hword => .vle32v, | |
| 102 | .word => .vle32v, | |
| 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)}), | |
| 208 | }, | |
| 209 | .vector => switch (dst_class) { | |
| 210 | .int => { | |
| 211 | try lower.emit(.vadcvv, &.{ | |
| 212 | .{ .reg = rr.rd }, | |
| 115 | .vector => { | |
| 116 | assert(frame_loc.disp == 0); | |
| 117 | try lower.emit(mnem, &.{ | |
| 118 | .{ .reg = rm.r }, | |
| 119 | .{ .reg = frame_loc.base }, | |
| 213 | 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)}), | |
| 218 | }, | |
| 219 | } | |
| 220 | }, | |
| 221 | ||
| 222 | .pseudo_j => { | |
| 223 | try lower.emit(.jal, &.{ | |
| 224 | .{ .reg = .zero }, | |
| 225 | .{ .imm = lower.reloc(.{ .inst = inst.data.inst }) }, | |
| 226 | }); | |
| 227 | }, | |
| 228 | ||
| 229 | .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list), | |
| 230 | .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list), | |
| 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 | }); | |
| 123 | } | |
| 124 | }, | |
| 125 | .pseudo_store_rm => { | |
| 126 | const src_reg = rm.r; | |
| 127 | const src_reg_class = src_reg.class(); | |
| 128 | ||
| 129 | const dest_size = rm.m.mod.size; | |
| 130 | ||
| 131 | const mnem: Mnemonic = switch (src_reg_class) { | |
| 132 | .int => switch (dest_size) { | |
| 133 | .byte => .sb, | |
| 134 | .hword => .sh, | |
| 135 | .word => .sw, | |
| 136 | .dword => .sd, | |
| 323 | 137 | }, |
| 324 | .neq => { | |
| 325 | try lower.emit(.xor, &.{ | |
| 326 | .{ .reg = rd }, | |
| 327 | .{ .reg = rs1 }, | |
| 328 | .{ .reg = rs2 }, | |
| 329 | }); | |
| 330 | ||
| 331 | try lower.emit(.sltu, &.{ | |
| 332 | .{ .reg = rd }, | |
| 333 | .{ .reg = .zero }, | |
| 334 | .{ .reg = rd }, | |
| 335 | }); | |
| 138 | .float => switch (dest_size) { | |
| 139 | .byte => unreachable, // Zig does not support 8-bit floats | |
| 140 | .hword => return lower.fail("TODO: lowerMir pseudo_store_rm support 16-bit floats", .{}), | |
| 141 | .word => .fsw, | |
| 142 | .dword => .fsd, | |
| 336 | 143 | }, |
| 337 | .gt => { | |
| 338 | try lower.emit(less_than, &.{ | |
| 339 | .{ .reg = rd }, | |
| 340 | .{ .reg = rs2 }, | |
| 341 | .{ .reg = rs1 }, | |
| 342 | }); | |
| 144 | .vector => switch (dest_size) { | |
| 145 | .byte => .vse8v, | |
| 146 | .hword => .vse16v, | |
| 147 | .word => .vse32v, | |
| 148 | .dword => .vse64v, | |
| 343 | 149 | }, |
| 344 | .gte => { | |
| 345 | try lower.emit(less_than, &.{ | |
| 346 | .{ .reg = rd }, | |
| 347 | .{ .reg = rs1 }, | |
| 348 | .{ .reg = rs2 }, | |
| 349 | }); | |
| 350 | try lower.emit(.xori, &.{ | |
| 351 | .{ .reg = rd }, | |
| 352 | .{ .reg = rd }, | |
| 353 | .{ .imm = Immediate.s(1) }, | |
| 150 | }; | |
| 151 | ||
| 152 | switch (src_reg_class) { | |
| 153 | .int, .float => { | |
| 154 | try lower.emit(mnem, &.{ | |
| 155 | .{ .reg = frame_loc.base }, | |
| 156 | .{ .reg = rm.r }, | |
| 157 | .{ .imm = Immediate.s(frame_loc.disp) }, | |
| 354 | 158 | }); |
| 355 | 159 | }, |
| 356 | .lt => { | |
| 357 | try lower.emit(less_than, &.{ | |
| 358 | .{ .reg = rd }, | |
| 359 | .{ .reg = rs1 }, | |
| 360 | .{ .reg = rs2 }, | |
| 160 | .vector => { | |
| 161 | assert(frame_loc.disp == 0); | |
| 162 | try lower.emit(mnem, &.{ | |
| 163 | .{ .reg = rm.r }, | |
| 164 | .{ .reg = frame_loc.base }, | |
| 165 | .{ .reg = .zero }, | |
| 361 | 166 | }); |
| 362 | 167 | }, |
| 363 | .lte => { | |
| 364 | try lower.emit(less_than, &.{ | |
| 365 | .{ .reg = rd }, | |
| 366 | .{ .reg = rs2 }, | |
| 367 | .{ .reg = rs1 }, | |
| 368 | }); | |
| 168 | } | |
| 169 | }, | |
| 170 | else => unreachable, | |
| 171 | } | |
| 172 | }, | |
| 369 | 173 | |
| 370 | try lower.emit(.xori, &.{ | |
| 371 | .{ .reg = rd }, | |
| 372 | .{ .reg = rd }, | |
| 373 | .{ .imm = Immediate.s(1) }, | |
| 374 | }); | |
| 375 | }, | |
| 174 | .pseudo_mv => { | |
| 175 | const rr = inst.data.rr; | |
| 176 | ||
| 177 | const dst_class = rr.rd.class(); | |
| 178 | const src_class = rr.rs.class(); | |
| 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) { | |
| 378 | // eq | |
| 379 | .eq => { | |
| 380 | try lower.emit(if (size == 64) .feqd else .feqs, &.{ | |
| 381 | .{ .reg = rd }, | |
| 382 | .{ .reg = rs1 }, | |
| 383 | .{ .reg = rs2 }, | |
| 384 | }); | |
| 385 | }, | |
| 386 | // !(eq) | |
| 387 | .neq => { | |
| 388 | try lower.emit(if (size == 64) .feqd else .feqs, &.{ | |
| 389 | .{ .reg = rd }, | |
| 390 | .{ .reg = rs1 }, | |
| 391 | .{ .reg = rs2 }, | |
| 392 | }); | |
| 393 | try lower.emit(.xori, &.{ | |
| 394 | .{ .reg = rd }, | |
| 395 | .{ .reg = rd }, | |
| 396 | .{ .imm = Immediate.s(1) }, | |
| 397 | }); | |
| 398 | }, | |
| 399 | .lt => { | |
| 400 | try lower.emit(if (size == 64) .fltd else .flts, &.{ | |
| 401 | .{ .reg = rd }, | |
| 402 | .{ .reg = rs1 }, | |
| 403 | .{ .reg = rs2 }, | |
| 404 | }); | |
| 405 | }, | |
| 406 | .lte => { | |
| 407 | try lower.emit(if (size == 64) .fled else .fles, &.{ | |
| 408 | .{ .reg = rd }, | |
| 409 | .{ .reg = rs1 }, | |
| 410 | .{ .reg = rs2 }, | |
| 411 | }); | |
| 412 | }, | |
| 413 | .gt => { | |
| 414 | try lower.emit(if (size == 64) .fltd else .flts, &.{ | |
| 415 | .{ .reg = rd }, | |
| 416 | .{ .reg = rs2 }, | |
| 417 | .{ .reg = rs1 }, | |
| 418 | }); | |
| 419 | }, | |
| 420 | .gte => { | |
| 421 | try lower.emit(if (size == 64) .fled else .fles, &.{ | |
| 422 | .{ .reg = rd }, | |
| 423 | .{ .reg = rs2 }, | |
| 424 | .{ .reg = rs1 }, | |
| 425 | }); | |
| 426 | }, | |
| 189 | .int, .vector => return lower.fail("TODO: lowerMir pseudo_mv float -> {s}", .{@tagName(dst_class)}), | |
| 190 | }, | |
| 191 | .int => switch (dst_class) { | |
| 192 | .int => { | |
| 193 | try lower.emit(.addi, &.{ | |
| 194 | .{ .reg = rr.rd }, | |
| 195 | .{ .reg = rr.rs }, | |
| 196 | .{ .imm = Immediate.s(0) }, | |
| 197 | }); | |
| 198 | }, | |
| 199 | .vector => { | |
| 200 | try lower.emit(.vmvvx, &.{ | |
| 201 | .{ .reg = rr.rd }, | |
| 202 | .{ .reg = rr.rs }, | |
| 203 | .{ .reg = .x0 }, | |
| 204 | }); | |
| 205 | }, | |
| 206 | .float => return lower.fail("TODO: lowerMir pseudo_mv int -> {s}", .{@tagName(dst_class)}), | |
| 207 | }, | |
| 208 | .vector => switch (dst_class) { | |
| 209 | .int => { | |
| 210 | try lower.emit(.vadcvv, &.{ | |
| 211 | .{ .reg = rr.rd }, | |
| 212 | .{ .reg = .zero }, | |
| 213 | .{ .reg = rr.rs }, | |
| 214 | }); | |
| 215 | }, | |
| 216 | .float, .vector => return lower.fail("TODO: lowerMir pseudo_mv vector -> {s}", .{@tagName(dst_class)}), | |
| 217 | }, | |
| 218 | } | |
| 219 | }, | |
| 220 | ||
| 221 | .pseudo_j => { | |
| 222 | const j_type = inst.data.j_type; | |
| 223 | try lower.emit(.jal, &.{ | |
| 224 | .{ .reg = j_type.rd }, | |
| 225 | .{ .imm = lower.reloc(.{ .inst = j_type.inst }) }, | |
| 226 | }); | |
| 227 | }, | |
| 228 | ||
| 229 | .pseudo_spill_regs => try lower.pushPopRegList(true, inst.data.reg_list), | |
| 230 | .pseudo_restore_regs => try lower.pushPopRegList(false, inst.data.reg_list), | |
| 231 | ||
| 232 | .pseudo_load_symbol => { | |
| 233 | const payload = inst.data.reloc; | |
| 234 | const dst_reg = payload.register; | |
| 235 | assert(dst_reg.class() == .int); | |
| 236 | ||
| 237 | try lower.emit(.lui, &.{ | |
| 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", .{}), | |
| 429 | } | |
| 430 | }, | |
| 431 | ||
| 432 | .pseudo_not => { | |
| 433 | const rr = inst.data.rr; | |
| 434 | assert(rr.rs.class() == .int and rr.rd.class() == .int); | |
| 435 | ||
| 436 | // mask out any other bits that aren't the boolean | |
| 437 | try lower.emit(.andi, &.{ | |
| 438 | .{ .reg = rr.rs }, | |
| 439 | .{ .reg = rr.rs }, | |
| 440 | .{ .imm = Immediate.s(1) }, | |
| 441 | }); | |
| 442 | ||
| 443 | try lower.emit(.sltiu, &.{ | |
| 444 | .{ .reg = rr.rd }, | |
| 445 | .{ .reg = rr.rs }, | |
| 446 | .{ .imm = Immediate.s(1) }, | |
| 447 | }); | |
| 448 | }, | |
| 449 | ||
| 450 | .pseudo_extern_fn_reloc => { | |
| 451 | const inst_reloc = inst.data.reloc; | |
| 452 | ||
| 453 | try lower.emit(.auipc, &.{ | |
| 454 | .{ .reg = .ra }, | |
| 455 | .{ .imm = lower.reloc( | |
| 456 | .{ .call_extern_fn_reloc = .{ | |
| 457 | .atom_index = inst_reloc.atom_index, | |
| 458 | .sym_index = inst_reloc.sym_index, | |
| 459 | } }, | |
| 460 | ) }, | |
| 461 | }); | |
| 462 | ||
| 463 | try lower.emit(.jalr, &.{ | |
| 464 | .{ .reg = .ra }, | |
| 465 | .{ .reg = .ra }, | |
| 466 | .{ .imm = Immediate.s(0) }, | |
| 467 | }); | |
| 468 | }, | |
| 469 | ||
| 470 | .pseudo_amo => { | |
| 471 | const amo = inst.data.amo; | |
| 472 | const is_d = amo.ty.abiSize(pt) == 8; | |
| 473 | const is_un = amo.ty.isUnsignedInt(pt.zcu); | |
| 474 | ||
| 475 | const mnem: Encoding.Mnemonic = switch (amo.op) { | |
| 476 | // zig fmt: off | |
| 477 | .SWAP => if (is_d) .amoswapd else .amoswapw, | |
| 478 | .ADD => if (is_d) .amoaddd else .amoaddw, | |
| 479 | .AND => if (is_d) .amoandd else .amoandw, | |
| 480 | .OR => if (is_d) .amoord else .amoorw, | |
| 481 | .XOR => if (is_d) .amoxord else .amoxorw, | |
| 482 | .MAX => if (is_d) if (is_un) .amomaxud else .amomaxd else if (is_un) .amomaxuw else .amomaxw, | |
| 483 | .MIN => if (is_d) if (is_un) .amominud else .amomind else if (is_un) .amominuw else .amominw, | |
| 484 | // zig fmt: on | |
| 485 | }; | |
| 486 | ||
| 487 | try lower.emit(mnem, &.{ | |
| 488 | .{ .reg = inst.data.amo.rd }, | |
| 489 | .{ .reg = inst.data.amo.rs1 }, | |
| 490 | .{ .reg = inst.data.amo.rs2 }, | |
| 491 | .{ .barrier = inst.data.amo.rl }, | |
| 492 | .{ .barrier = inst.data.amo.aq }, | |
| 493 | }); | |
| 494 | }, | |
| 495 | ||
| 496 | .pseudo_fence => { | |
| 497 | const fence = inst.data.fence; | |
| 498 | ||
| 499 | try lower.emit(switch (fence.fm) { | |
| 500 | .tso => .fencetso, | |
| 501 | .none => .fence, | |
| 502 | }, &.{ | |
| 503 | .{ .barrier = fence.succ }, | |
| 504 | .{ .barrier = fence.pred }, | |
| 505 | }); | |
| 506 | }, | |
| 507 | ||
| 508 | else => return lower.fail("TODO lower: psuedo {s}", .{@tagName(inst.ops)}), | |
| 365 | // !(eq) | |
| 366 | .neq => { | |
| 367 | try lower.emit(if (size == 64) .feqd else .feqs, &.{ | |
| 368 | .{ .reg = rd }, | |
| 369 | .{ .reg = rs1 }, | |
| 370 | .{ .reg = rs2 }, | |
| 371 | }); | |
| 372 | try lower.emit(.xori, &.{ | |
| 373 | .{ .reg = rd }, | |
| 374 | .{ .reg = rd }, | |
| 375 | .{ .imm = Immediate.s(1) }, | |
| 376 | }); | |
| 377 | }, | |
| 378 | .lt => { | |
| 379 | try lower.emit(if (size == 64) .fltd else .flts, &.{ | |
| 380 | .{ .reg = rd }, | |
| 381 | .{ .reg = rs1 }, | |
| 382 | .{ .reg = rs2 }, | |
| 383 | }); | |
| 384 | }, | |
| 385 | .lte => { | |
| 386 | try lower.emit(if (size == 64) .fled else .fles, &.{ | |
| 387 | .{ .reg = rd }, | |
| 388 | .{ .reg = rs1 }, | |
| 389 | .{ .reg = rs2 }, | |
| 390 | }); | |
| 391 | }, | |
| 392 | .gt => { | |
| 393 | try lower.emit(if (size == 64) .fltd else .flts, &.{ | |
| 394 | .{ .reg = rd }, | |
| 395 | .{ .reg = rs2 }, | |
| 396 | .{ .reg = rs1 }, | |
| 397 | }); | |
| 398 | }, | |
| 399 | .gte => { | |
| 400 | try lower.emit(if (size == 64) .fled else .fles, &.{ | |
| 401 | .{ .reg = rd }, | |
| 402 | .{ .reg = rs2 }, | |
| 403 | .{ .reg = rs1 }, | |
| 404 | }); | |
| 405 | }, | |
| 406 | }, | |
| 407 | .vector => return lower.fail("TODO: lowerMir pseudo_cmp vector", .{}), | |
| 408 | } | |
| 409 | }, | |
| 410 | ||
| 411 | .pseudo_not => { | |
| 412 | const rr = inst.data.rr; | |
| 413 | assert(rr.rs.class() == .int and rr.rd.class() == .int); | |
| 414 | ||
| 415 | // mask out any other bits that aren't the boolean | |
| 416 | try lower.emit(.andi, &.{ | |
| 417 | .{ .reg = rr.rs }, | |
| 418 | .{ .reg = rr.rs }, | |
| 419 | .{ .imm = Immediate.s(1) }, | |
| 420 | }); | |
| 421 | ||
| 422 | try lower.emit(.sltiu, &.{ | |
| 423 | .{ .reg = rr.rd }, | |
| 424 | .{ .reg = rr.rs }, | |
| 425 | .{ .imm = Immediate.s(1) }, | |
| 426 | }); | |
| 427 | }, | |
| 428 | ||
| 429 | .pseudo_extern_fn_reloc => { | |
| 430 | const inst_reloc = inst.data.reloc; | |
| 431 | ||
| 432 | try lower.emit(.auipc, &.{ | |
| 433 | .{ .reg = .ra }, | |
| 434 | .{ .imm = lower.reloc( | |
| 435 | .{ .call_extern_fn_reloc = .{ | |
| 436 | .atom_index = inst_reloc.atom_index, | |
| 437 | .sym_index = inst_reloc.sym_index, | |
| 438 | } }, | |
| 439 | ) }, | |
| 440 | }); | |
| 441 | ||
| 442 | try lower.emit(.jalr, &.{ | |
| 443 | .{ .reg = .ra }, | |
| 444 | .{ .reg = .ra }, | |
| 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 | } |
| 511 | 487 | |
| ... | ... | @@ -516,49 +492,46 @@ pub fn lowerMir(lower: *Lower, index: Mir.Inst.Index, options: struct { |
| 516 | 492 | } |
| 517 | 493 | |
| 518 | 494 | fn generic(lower: *Lower, inst: Mir.Inst) Error!void { |
| 519 | const mnemonic = std.meta.stringToEnum(Encoding.Mnemonic, @tagName(inst.tag)) orelse { | |
| 520 | return lower.fail("generic inst name '{s}' with op {s} doesn't match with a mnemonic", .{ | |
| 521 | @tagName(inst.tag), | |
| 522 | @tagName(inst.ops), | |
| 523 | }); | |
| 524 | }; | |
| 525 | try lower.emit(mnemonic, switch (inst.ops) { | |
| 495 | const mnemonic = inst.tag; | |
| 496 | try lower.emit(mnemonic, switch (inst.data) { | |
| 526 | 497 | .none => &.{}, |
| 527 | .ri => &.{ | |
| 528 | .{ .reg = inst.data.u_type.rd }, | |
| 529 | .{ .imm = inst.data.u_type.imm20 }, | |
| 498 | .u_type => |u| &.{ | |
| 499 | .{ .reg = u.rd }, | |
| 500 | .{ .imm = u.imm20 }, | |
| 530 | 501 | }, |
| 531 | .rr => &.{ | |
| 532 | .{ .reg = inst.data.rr.rd }, | |
| 533 | .{ .reg = inst.data.rr.rs }, | |
| 502 | .i_type => |i| &.{ | |
| 503 | .{ .reg = i.rd }, | |
| 504 | .{ .reg = i.rs1 }, | |
| 505 | .{ .imm = i.imm12 }, | |
| 534 | 506 | }, |
| 535 | .rri => &.{ | |
| 536 | .{ .reg = inst.data.i_type.rd }, | |
| 537 | .{ .reg = inst.data.i_type.rs1 }, | |
| 538 | .{ .imm = inst.data.i_type.imm12 }, | |
| 507 | .rr => |rr| &.{ | |
| 508 | .{ .reg = rr.rd }, | |
| 509 | .{ .reg = rr.rs }, | |
| 539 | 510 | }, |
| 540 | .rr_inst => &.{ | |
| 541 | .{ .reg = inst.data.b_type.rs1 }, | |
| 542 | .{ .reg = inst.data.b_type.rs2 }, | |
| 543 | .{ .imm = lower.reloc(.{ .inst = inst.data.b_type.inst }) }, | |
| 511 | .b_type => |b| &.{ | |
| 512 | .{ .reg = b.rs1 }, | |
| 513 | .{ .reg = b.rs2 }, | |
| 514 | .{ .imm = lower.reloc(.{ .inst = b.inst }) }, | |
| 544 | 515 | }, |
| 545 | .rrr => &.{ | |
| 546 | .{ .reg = inst.data.r_type.rd }, | |
| 547 | .{ .reg = inst.data.r_type.rs1 }, | |
| 548 | .{ .reg = inst.data.r_type.rs2 }, | |
| 516 | .r_type => |r| &.{ | |
| 517 | .{ .reg = r.rd }, | |
| 518 | .{ .reg = r.rs1 }, | |
| 519 | .{ .reg = r.rs2 }, | |
| 549 | 520 | }, |
| 550 | .csr => &.{ | |
| 551 | .{ .csr = inst.data.csr.csr }, | |
| 552 | .{ .reg = inst.data.csr.rs1 }, | |
| 553 | .{ .reg = inst.data.csr.rd }, | |
| 521 | .csr => |csr| &.{ | |
| 522 | .{ .csr = csr.csr }, | |
| 523 | .{ .reg = csr.rs1 }, | |
| 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 | } |
| 558 | 529 | |
| 559 | fn emit(lower: *Lower, mnemonic: Encoding.Mnemonic, ops: []const Instruction.Operand) !void { | |
| 560 | lower.result_insts[lower.result_insts_len] = | |
| 561 | try Instruction.new(mnemonic, ops); | |
| 530 | fn emit(lower: *Lower, mnemonic: Mnemonic, ops: []const Instruction.Operand) !void { | |
| 531 | const lir = encoding.Lir.fromMnem(mnemonic); | |
| 532 | const inst = Instruction.fromLir(lir, ops); | |
| 533 | ||
| 534 | lower.result_insts[lower.result_insts_len] = inst; | |
| 562 | 535 | lower.result_insts_len += 1; |
| 563 | 536 | } |
| 564 | 537 | |
| ... | ... | @@ -580,7 +553,7 @@ fn pushPopRegList(lower: *Lower, comptime spilling: bool, reg_list: Mir.Register |
| 580 | 553 | const reg = abi.Registers.all_preserved[i]; |
| 581 | 554 | |
| 582 | 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 | 557 | .int => .{ .ld, .sd }, |
| 585 | 558 | .float => .{ .fld, .fsd }, |
| 586 | 559 | .vector => unreachable, |
| ... | ... | @@ -618,20 +591,22 @@ fn hasFeature(lower: *Lower, feature: std.Target.riscv.Feature) bool { |
| 618 | 591 | } |
| 619 | 592 | |
| 620 | 593 | const Lower = @This(); |
| 621 | ||
| 622 | const abi = @import("abi.zig"); | |
| 623 | const assert = std.debug.assert; | |
| 624 | const bits = @import("bits.zig"); | |
| 625 | const encoder = @import("encoder.zig"); | |
| 626 | const link = @import("../../link.zig"); | |
| 627 | const Encoding = @import("Encoding.zig"); | |
| 628 | 594 | const std = @import("std"); |
| 595 | const assert = std.debug.assert; | |
| 629 | 596 | const log = std.log.scoped(.lower); |
| 630 | 597 | |
| 631 | const Air = @import("../../Air.zig"); | |
| 632 | 598 | const Allocator = std.mem.Allocator; |
| 633 | 599 | const ErrorMsg = Zcu.ErrorMsg; |
| 634 | const Mir = @import("Mir.zig"); | |
| 600 | ||
| 601 | const link = @import("../../link.zig"); | |
| 602 | const Air = @import("../../Air.zig"); | |
| 635 | 603 | const Zcu = @import("../../Zcu.zig"); |
| 636 | const Instruction = encoder.Instruction; | |
| 604 | ||
| 605 | const Mir = @import("Mir.zig"); | |
| 606 | const abi = @import("abi.zig"); | |
| 607 | const bits = @import("bits.zig"); | |
| 608 | const encoding = @import("encoding.zig"); | |
| 609 | ||
| 610 | const Mnemonic = @import("mnem.zig").Mnemonic; | |
| 637 | 611 | const Immediate = bits.Immediate; |
| 612 | const Instruction = encoding.Instruction; |
src/arch/riscv64/Mir.zig+19-281| ... | ... | @@ -1,170 +1,17 @@ |
| 1 | 1 | //! Machine Intermediate Representation. |
| 2 | //! This data is produced by RISCV64 Codegen or RISCV64 assembly parsing | |
| 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. | |
| 2 | //! This data is produced by CodeGen.zig | |
| 8 | 3 | |
| 9 | 4 | instructions: std.MultiArrayList(Inst).Slice, |
| 10 | /// The meaning of this data is determined by `Inst.Tag` value. | |
| 11 | extra: []const u32, | |
| 12 | 5 | frame_locs: std.MultiArrayList(FrameLoc).Slice, |
| 13 | 6 | |
| 14 | 7 | pub const Inst = struct { |
| 15 | tag: Tag, | |
| 8 | tag: Mnemonic, | |
| 16 | 9 | data: Data, |
| 17 | ops: Ops, | |
| 18 | 10 | |
| 19 | /// The position of an MIR instruction within the `Mir` instructions array. | |
| 20 | 11 | pub const Index = u32; |
| 21 | 12 | |
| 22 | pub const Tag = enum(u16) { | |
| 23 | ||
| 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, | |
| 13 | pub const Data = union(enum) { | |
| 14 | none: void, | |
| 168 | 15 | r_type: struct { |
| 169 | 16 | rd: Register, |
| 170 | 17 | rs1: Register, |
| ... | ... | @@ -194,10 +41,6 @@ pub const Inst = struct { |
| 194 | 41 | rd: Register, |
| 195 | 42 | inst: Inst.Index, |
| 196 | 43 | }, |
| 197 | pseudo_dbg_line_column: struct { | |
| 198 | line: u32, | |
| 199 | column: u32, | |
| 200 | }, | |
| 201 | 44 | rm: struct { |
| 202 | 45 | r: Register, |
| 203 | 46 | m: Memory, |
| ... | ... | @@ -208,11 +51,6 @@ pub const Inst = struct { |
| 208 | 51 | rd: Register, |
| 209 | 52 | rs: Register, |
| 210 | 53 | }, |
| 211 | fabs: struct { | |
| 212 | rd: Register, | |
| 213 | rs: Register, | |
| 214 | bits: u16, | |
| 215 | }, | |
| 216 | 54 | compare: struct { |
| 217 | 55 | rd: Register, |
| 218 | 56 | rs1: Register, |
| ... | ... | @@ -228,6 +66,7 @@ pub const Inst = struct { |
| 228 | 66 | ty: Type, |
| 229 | 67 | }, |
| 230 | 68 | reloc: struct { |
| 69 | register: Register, | |
| 231 | 70 | atom_index: u32, |
| 232 | 71 | sym_index: u32, |
| 233 | 72 | }, |
| ... | ... | @@ -253,115 +92,26 @@ pub const Inst = struct { |
| 253 | 92 | rs1: Register, |
| 254 | 93 | rd: Register, |
| 255 | 94 | }, |
| 256 | }; | |
| 257 | ||
| 258 | pub const Ops = enum { | |
| 259 | /// No data associated with this instruction (only mnemonic is used). | |
| 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, | |
| 95 | pseudo_dbg_line_column: struct { | |
| 96 | line: u32, | |
| 97 | column: u32, | |
| 98 | }, | |
| 346 | 99 | }; |
| 347 | 100 | |
| 348 | 101 | pub fn format( |
| 349 | 102 | inst: Inst, |
| 350 | 103 | comptime fmt: []const u8, |
| 351 | options: std.fmt.FormatOptions, | |
| 104 | _: std.fmt.FormatOptions, | |
| 352 | 105 | writer: anytype, |
| 353 | 106 | ) !void { |
| 354 | 107 | assert(fmt.len == 0); |
| 355 | _ = options; | |
| 356 | ||
| 357 | try writer.print("Tag: {s}, Ops: {s}", .{ @tagName(inst.tag), @tagName(inst.ops) }); | |
| 108 | try writer.print("Tag: {s}, Data: {s}", .{ @tagName(inst.tag), @tagName(inst.data) }); | |
| 358 | 109 | } |
| 359 | 110 | }; |
| 360 | 111 | |
| 361 | 112 | pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { |
| 362 | 113 | mir.instructions.deinit(gpa); |
| 363 | 114 | mir.frame_locs.deinit(gpa); |
| 364 | gpa.free(mir.extra); | |
| 365 | 115 | mir.* = undefined; |
| 366 | 116 | } |
| 367 | 117 | |
| ... | ... | @@ -392,25 +142,12 @@ pub const AmoOp = enum(u5) { |
| 392 | 142 | MIN, |
| 393 | 143 | }; |
| 394 | 144 | |
| 395 | /// Returns the requested data, as well as the new index which is at the start of the | |
| 396 | /// trailers for the object. | |
| 397 | pub fn extraData(mir: Mir, comptime T: type, index: usize) struct { data: T, end: usize } { | |
| 398 | const fields = std.meta.fields(T); | |
| 399 | var i: usize = index; | |
| 400 | var result: T = undefined; | |
| 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 | } | |
| 145 | pub const FcvtOp = enum(u5) { | |
| 146 | w = 0b00000, | |
| 147 | wu = 0b00001, | |
| 148 | l = 0b00010, | |
| 149 | lu = 0b00011, | |
| 150 | }; | |
| 414 | 151 | |
| 415 | 152 | pub const LoadSymbolPayload = struct { |
| 416 | 153 | register: u32, |
| ... | ... | @@ -459,10 +196,10 @@ const Mir = @This(); |
| 459 | 196 | const std = @import("std"); |
| 460 | 197 | const builtin = @import("builtin"); |
| 461 | 198 | const Type = @import("../../Type.zig"); |
| 199 | const bits = @import("bits.zig"); | |
| 462 | 200 | |
| 463 | 201 | const assert = std.debug.assert; |
| 464 | 202 | |
| 465 | const bits = @import("bits.zig"); | |
| 466 | 203 | const Register = bits.Register; |
| 467 | 204 | const CSR = bits.CSR; |
| 468 | 205 | const Immediate = bits.Immediate; |
| ... | ... | @@ -470,3 +207,4 @@ const Memory = bits.Memory; |
| 470 | 207 | const FrameIndex = bits.FrameIndex; |
| 471 | 208 | const FrameAddr = @import("CodeGen.zig").FrameAddr; |
| 472 | 209 | const IntegerBitSet = std.bit_set.IntegerBitSet; |
| 210 | const Mnemonic = @import("mnem.zig").Mnemonic; |
src/arch/riscv64/bits.zig+1-2| ... | ... | @@ -5,7 +5,6 @@ const testing = std.testing; |
| 5 | 5 | const Target = std.Target; |
| 6 | 6 | |
| 7 | 7 | const Zcu = @import("../../Zcu.zig"); |
| 8 | const Encoding = @import("Encoding.zig"); | |
| 9 | 8 | const Mir = @import("Mir.zig"); |
| 10 | 9 | const abi = @import("abi.zig"); |
| 11 | 10 | |
| ... | ... | @@ -193,7 +192,7 @@ pub const Register = enum(u8) { |
| 193 | 192 | /// The goal of this function is to return the same ID for `zero` and `x0` but two |
| 194 | 193 | /// seperate IDs for `x0` and `f0`. We will assume that each register set has 32 registers |
| 195 | 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 | 196 | const base = switch (@intFromEnum(reg)) { |
| 198 | 197 | // zig fmt: off |
| 199 | 198 | @intFromEnum(Register.zero) ... @intFromEnum(Register.x31) => @intFromEnum(Register.zero), |
src/arch/riscv64/encoder.zig deleted-80| ... | ... | @@ -1,80 +0,0 @@ |
| 1 | pub 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 | ||
| 68 | const std = @import("std"); | |
| 69 | ||
| 70 | const Lower = @import("Lower.zig"); | |
| 71 | const Mir = @import("Mir.zig"); | |
| 72 | const bits = @import("bits.zig"); | |
| 73 | const Encoding = @import("Encoding.zig"); | |
| 74 | ||
| 75 | const Register = bits.Register; | |
| 76 | const CSR = bits.CSR; | |
| 77 | const Memory = bits.Memory; | |
| 78 | const Immediate = bits.Immediate; | |
| 79 | ||
| 80 | const 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. | |
| 11 | pub 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. | |
| 438 | pub 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 | ||
| 704 | const std = @import("std"); | |
| 705 | const assert = std.debug.assert; | |
| 706 | const log = std.log.scoped(.format); | |
| 707 | ||
| 708 | const bits = @import("bits.zig"); | |
| 709 | const Mir = @import("Mir.zig"); | |
| 710 | const Mnemonic = @import("mnem.zig").Mnemonic; | |
| 711 | const Lower = @import("Lower.zig"); | |
| 712 | ||
| 713 | const Register = bits.Register; | |
| 714 | const CSR = bits.CSR; | |
| 715 | const Memory = bits.Memory; | |
| 716 | const Immediate = bits.Immediate; |
src/arch/riscv64/mnem.zig created+232| ... | ... | @@ -0,0 +1,232 @@ |
| 1 | pub 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 | 25 | } |
| 26 | 26 | |
| 27 | 27 | pub fn writeInstU(code: *[4]u8, value: u32) void { |
| 28 | var data = Encoding.Data{ | |
| 29 | .U = mem.bytesToValue(std.meta.TagPayload( | |
| 30 | Encoding.Data, | |
| 31 | Encoding.Data.U, | |
| 32 | ), code), | |
| 33 | }; | |
| 28 | var data: Instruction = .{ .U = mem.bytesToValue(std.meta.TagPayload(Instruction, .U), code) }; | |
| 34 | 29 | const compensated: u32 = @bitCast(@as(i32, @bitCast(value)) + 0x800); |
| 35 | 30 | data.U.imm12_31 = bitSlice(compensated, 31, 12); |
| 36 | 31 | mem.writeInt(u32, code, data.toU32(), .little); |
| 37 | 32 | } |
| 38 | 33 | |
| 39 | 34 | pub fn writeInstI(code: *[4]u8, value: u32) void { |
| 40 | var data = Encoding.Data{ | |
| 41 | .I = mem.bytesToValue(std.meta.TagPayload( | |
| 42 | Encoding.Data, | |
| 43 | Encoding.Data.I, | |
| 44 | ), code), | |
| 45 | }; | |
| 35 | var data: Instruction = .{ .I = mem.bytesToValue(std.meta.TagPayload(Instruction, .I), code) }; | |
| 46 | 36 | data.I.imm0_11 = bitSlice(value, 11, 0); |
| 47 | 37 | mem.writeInt(u32, code, data.toU32(), .little); |
| 48 | 38 | } |
| 49 | 39 | |
| 50 | 40 | pub fn writeInstS(code: *[4]u8, value: u32) void { |
| 51 | var data = Encoding.Data{ | |
| 52 | .S = mem.bytesToValue(std.meta.TagPayload( | |
| 53 | Encoding.Data, | |
| 54 | Encoding.Data.S, | |
| 55 | ), code), | |
| 56 | }; | |
| 41 | var data: Instruction = .{ .S = mem.bytesToValue(std.meta.TagPayload(Instruction, .S), code) }; | |
| 57 | 42 | data.S.imm0_4 = bitSlice(value, 4, 0); |
| 58 | 43 | data.S.imm5_11 = bitSlice(value, 11, 5); |
| 59 | 44 | mem.writeInt(u32, code, data.toU32(), .little); |
| 60 | 45 | } |
| 61 | 46 | |
| 62 | 47 | pub fn writeInstJ(code: *[4]u8, value: u32) void { |
| 63 | var data = Encoding.Data{ | |
| 64 | .J = mem.bytesToValue(std.meta.TagPayload( | |
| 65 | Encoding.Data, | |
| 66 | Encoding.Data.J, | |
| 67 | ), code), | |
| 68 | }; | |
| 48 | var data: Instruction = .{ .J = mem.bytesToValue(std.meta.TagPayload(Instruction, .J), code) }; | |
| 69 | 49 | data.J.imm1_10 = bitSlice(value, 10, 1); |
| 70 | 50 | data.J.imm11 = bitSlice(value, 11, 11); |
| 71 | 51 | data.J.imm12_19 = bitSlice(value, 19, 12); |
| ... | ... | @@ -74,12 +54,7 @@ pub fn writeInstJ(code: *[4]u8, value: u32) void { |
| 74 | 54 | } |
| 75 | 55 | |
| 76 | 56 | pub fn writeInstB(code: *[4]u8, value: u32) void { |
| 77 | var data = Encoding.Data{ | |
| 78 | .B = mem.bytesToValue(std.meta.TagPayload( | |
| 79 | Encoding.Data, | |
| 80 | Encoding.Data.B, | |
| 81 | ), code), | |
| 82 | }; | |
| 57 | var data: Instruction = .{ .B = mem.bytesToValue(std.meta.TagPayload(Instruction, .B), code) }; | |
| 83 | 58 | data.B.imm1_4 = bitSlice(value, 4, 1); |
| 84 | 59 | data.B.imm5_10 = bitSlice(value, 10, 5); |
| 85 | 60 | data.B.imm11 = bitSlice(value, 11, 11); |
| ... | ... | @@ -109,9 +84,8 @@ pub const RiscvEflags = packed struct(u32) { |
| 109 | 84 | _unused: u8, |
| 110 | 85 | }; |
| 111 | 86 | |
| 112 | const encoder = @import("../arch/riscv64/encoder.zig"); | |
| 113 | const Encoding = @import("../arch/riscv64/Encoding.zig"); | |
| 114 | 87 | const mem = std.mem; |
| 115 | 88 | const std = @import("std"); |
| 116 | 89 | |
| 117 | pub const Instruction = encoder.Instruction; | |
| 90 | const encoding = @import("../arch/riscv64/encoding.zig"); | |
| 91 | const 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 | 510 | } |
| 511 | 511 | |
| 512 | 512 | test "struct field explicit alignment" { |
| 513 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; // TODO | |
| 514 | 513 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 515 | 514 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 516 | 515 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
test/behavior/byteswap.zig+1| ... | ... | @@ -100,6 +100,7 @@ test "@byteSwap vectors u8" { |
| 100 | 100 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 101 | 101 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 102 | 102 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 103 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 103 | 104 | |
| 104 | 105 | try comptime vector8(); |
| 105 | 106 | try vector8(); |
test/behavior/defer.zig+2| ... | ... | @@ -116,6 +116,7 @@ test "errdefer with payload" { |
| 116 | 116 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 117 | 117 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 118 | 118 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 119 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 119 | 120 | |
| 120 | 121 | const S = struct { |
| 121 | 122 | fn foo() !i32 { |
| ... | ... | @@ -138,6 +139,7 @@ test "reference to errdefer payload" { |
| 138 | 139 | if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO |
| 139 | 140 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 140 | 141 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; // TODO |
| 142 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 141 | 143 | |
| 142 | 144 | const S = struct { |
| 143 | 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 | 591 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; |
| 592 | 592 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; |
| 593 | 593 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 594 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 594 | 595 | |
| 595 | 596 | const S = struct { |
| 596 | 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 | 228 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 229 | 229 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 230 | 230 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 231 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 231 | 232 | |
| 232 | 233 | const S = struct { |
| 233 | 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 | 427 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 428 | 428 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 429 | 429 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 430 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 430 | 431 | |
| 431 | 432 | const S = struct { |
| 432 | 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 | 463 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 463 | 464 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 464 | 465 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 466 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 465 | 467 | |
| 466 | 468 | const S = struct { |
| 467 | 469 | fn doTheTest() !void { |
test/behavior/try.zig+1| ... | ... | @@ -51,6 +51,7 @@ test "`try`ing an if/else expression" { |
| 51 | 51 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO |
| 52 | 52 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO |
| 53 | 53 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
| 54 | if (builtin.zig_backend == .stage2_riscv64) return error.SkipZigTest; | |
| 54 | 55 | |
| 55 | 56 | const S = struct { |
| 56 | 57 | fn getError() !void { |