authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-21 12:36:47+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-03-21 12:36:47+01:00
logb48d8cce52369e7625f9dab8a37efe9c3a33186b
tree1ff1d7af0c7a98a74f651dab3505be75e499438b
parent3d8d6c0a6d7a29396725467672023b5ec3adbce6
parenta153732d5a86f7d8c5ca5bc91cfad1ccf0f8f573
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11235 from joachimschmidt557/stage2-riscv

stage2 RISCV64: remove MCValue.embedded_in_code

3 files changed, 262 insertions(+), 71 deletions(-)

src/arch/riscv64/CodeGen.zig+219-71
...@@ -111,11 +111,6 @@ const MCValue = union(enum) {...@@ -111,11 +111,6 @@ const MCValue = union(enum) {
111 /// A pointer-sized integer that fits in a register.111 /// A pointer-sized integer that fits in a register.
112 /// If the type is a pointer, this is the pointer address in virtual address space.112 /// If the type is a pointer, this is the pointer address in virtual address space.
113 immediate: u64,113 immediate: u64,
114 /// The constant was emitted into the code, at this offset.
115 /// If the type is a pointer, it means the pointer address is embedded in the code.
116 embedded_in_code: usize,
117 /// The value is a pointer to a constant which was emitted into the code, at this offset.
118 ptr_embedded_in_code: usize,
119 /// The value is in a target-specific register.114 /// The value is in a target-specific register.
120 register: Register,115 register: Register,
121 /// The value is in memory at a hard-coded address.116 /// The value is in memory at a hard-coded address.
...@@ -129,7 +124,7 @@ const MCValue = union(enum) {...@@ -129,7 +124,7 @@ const MCValue = union(enum) {
129124
130 fn isMemory(mcv: MCValue) bool {125 fn isMemory(mcv: MCValue) bool {
131 return switch (mcv) {126 return switch (mcv) {
132 .embedded_in_code, .memory, .stack_offset => true,127 .memory, .stack_offset => true,
133 else => false,128 else => false,
134 };129 };
135 }130 }
...@@ -148,10 +143,8 @@ const MCValue = union(enum) {...@@ -148,10 +143,8 @@ const MCValue = union(enum) {
148 .dead => unreachable,143 .dead => unreachable,
149144
150 .immediate,145 .immediate,
151 .embedded_in_code,
152 .memory,146 .memory,
153 .ptr_stack_offset,147 .ptr_stack_offset,
154 .ptr_embedded_in_code,
155 .undef,148 .undef,
156 => false,149 => false,
157150
...@@ -416,14 +409,17 @@ fn gen(self: *Self) !void {...@@ -416,14 +409,17 @@ fn gen(self: *Self) !void {
416 });409 });
417410
418 // exitlude jumps411 // exitlude jumps
419 if (self.exitlude_jump_relocs.items.len == 1) {412 if (self.exitlude_jump_relocs.items.len > 0 and
420 // There is only one relocation. Hence,413 self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2)
421 // this relocation must be at the end of414 {
422 // the code. Therefore, we can just delete415 // If the last Mir instruction (apart from the
423 // the space initially reserved for the416 // dbg_epilogue_begin) is the last exitlude jump
424 // jump417 // relocation (which would just jump one instruction
425 self.mir_instructions.len -= 1;418 // further), it can be safely removed
426 } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {419 self.mir_instructions.orderedRemove(self.exitlude_jump_relocs.pop());
420 }
421
422 for (self.exitlude_jump_relocs.items) |jmp_reloc| {
427 _ = jmp_reloc;423 _ = jmp_reloc;
428 return self.fail("TODO add branches in RISCV64", .{});424 return self.fail("TODO add branches in RISCV64", .{});
429 }425 }
...@@ -496,10 +492,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -496,10 +492,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
496492
497 switch (air_tags[inst]) {493 switch (air_tags[inst]) {
498 // zig fmt: off494 // zig fmt: off
499 .add, .ptr_add => try self.airAdd(inst),495 .add, .ptr_add => try self.airBinOp(inst),
500 .addwrap => try self.airAddWrap(inst),496 .addwrap => try self.airAddWrap(inst),
501 .add_sat => try self.airAddSat(inst),497 .add_sat => try self.airAddSat(inst),
502 .sub, .ptr_sub => try self.airSub(inst),498 .sub, .ptr_sub => try self.airBinOp(inst),
503 .subwrap => try self.airSubWrap(inst),499 .subwrap => try self.airSubWrap(inst),
504 .sub_sat => try self.airSubSat(inst),500 .sub_sat => try self.airSubSat(inst),
505 .mul => try self.airMul(inst),501 .mul => try self.airMul(inst),
...@@ -927,9 +923,182 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -927,9 +923,182 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
927 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });923 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
928}924}
929925
930fn airAdd(self: *Self, inst: Air.Inst.Index) !void {926/// Don't call this function directly. Use binOp instead.
927///
928/// Calling this function signals an intention to generate a Mir
929/// instruction of the form
930///
931/// op dest, lhs, rhs
932///
933/// Asserts that generating an instruction of that form is possible.
934fn binOpRegister(
935 self: *Self,
936 tag: Air.Inst.Tag,
937 maybe_inst: ?Air.Inst.Index,
938 lhs: MCValue,
939 rhs: MCValue,
940 lhs_ty: Type,
941 rhs_ty: Type,
942) !MCValue {
943 const lhs_is_register = lhs == .register;
944 const rhs_is_register = rhs == .register;
945
946 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
947 if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register});
948
949 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
950
951 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
952 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
953 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
954 break :inst Air.refToIndex(bin_op.lhs).?;
955 } else null;
956
957 const reg = try self.register_manager.allocReg(track_inst);
958 self.register_manager.freezeRegs(&.{reg});
959
960 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
961
962 break :blk reg;
963 };
964 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
965
966 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
967 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
968 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
969 break :inst Air.refToIndex(bin_op.rhs).?;
970 } else null;
971
972 const reg = try self.register_manager.allocReg(track_inst);
973 self.register_manager.freezeRegs(&.{reg});
974
975 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
976
977 break :blk reg;
978 };
979 defer self.register_manager.unfreezeRegs(&.{rhs_reg});
980
981 const dest_reg = if (maybe_inst) |inst| blk: {
982 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
983
984 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
985 break :blk lhs_reg;
986 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
987 break :blk rhs_reg;
988 } else {
989 break :blk try self.register_manager.allocReg(inst);
990 }
991 } else try self.register_manager.allocReg(null);
992
993 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
994 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
995
996 const mir_tag: Mir.Inst.Tag = switch (tag) {
997 .add => .add,
998 .sub => .sub,
999 else => unreachable,
1000 };
1001 const mir_data: Mir.Inst.Data = switch (tag) {
1002 .add,
1003 .sub,
1004 => .{ .r_type = .{
1005 .rd = dest_reg,
1006 .rs1 = lhs_reg,
1007 .rs2 = rhs_reg,
1008 } },
1009 else => unreachable,
1010 };
1011
1012 _ = try self.addInst(.{
1013 .tag = mir_tag,
1014 .data = mir_data,
1015 });
1016
1017 return MCValue{ .register = dest_reg };
1018}
1019
1020/// For all your binary operation needs, this function will generate
1021/// the corresponding Mir instruction(s). Returns the location of the
1022/// result.
1023///
1024/// If the binary operation itself happens to be an Air instruction,
1025/// pass the corresponding index in the inst parameter. That helps
1026/// this function do stuff like reusing operands.
1027///
1028/// This function does not do any lowering to Mir itself, but instead
1029/// looks at the lhs and rhs and determines which kind of lowering
1030/// would be best suitable and then delegates the lowering to other
1031/// functions.
1032fn binOp(
1033 self: *Self,
1034 tag: Air.Inst.Tag,
1035 maybe_inst: ?Air.Inst.Index,
1036 lhs: MCValue,
1037 rhs: MCValue,
1038 lhs_ty: Type,
1039 rhs_ty: Type,
1040) InnerError!MCValue {
1041 switch (tag) {
1042 // Arithmetic operations on integers and floats
1043 .add,
1044 .sub,
1045 => {
1046 switch (lhs_ty.zigTypeTag()) {
1047 .Float => return self.fail("TODO binary operations on floats", .{}),
1048 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1049 .Int => {
1050 assert(lhs_ty.eql(rhs_ty));
1051 const int_info = lhs_ty.intInfo(self.target.*);
1052 if (int_info.bits <= 64) {
1053 // TODO immediate operands
1054 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1055 } else {
1056 return self.fail("TODO binary operations on int with bits > 64", .{});
1057 }
1058 },
1059 else => unreachable,
1060 }
1061 },
1062 .ptr_add,
1063 .ptr_sub,
1064 => {
1065 switch (lhs_ty.zigTypeTag()) {
1066 .Pointer => {
1067 const ptr_ty = lhs_ty;
1068 const elem_ty = switch (ptr_ty.ptrSize()) {
1069 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
1070 else => ptr_ty.childType(),
1071 };
1072 const elem_size = elem_ty.abiSize(self.target.*);
1073
1074 if (elem_size == 1) {
1075 const base_tag: Air.Inst.Tag = switch (tag) {
1076 .ptr_add => .add,
1077 .ptr_sub => .sub,
1078 else => unreachable,
1079 };
1080
1081 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1082 } else {
1083 return self.fail("TODO ptr_add with elem_size > 1", .{});
1084 }
1085 },
1086 else => unreachable,
1087 }
1088 },
1089 else => unreachable,
1090 }
1091}
1092
1093fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1094 const tag = self.air.instructions.items(.tag)[inst];
931 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1095 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
932 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add for {}", .{self.target.cpu.arch});1096 const lhs = try self.resolveInst(bin_op.lhs);
1097 const rhs = try self.resolveInst(bin_op.rhs);
1098 const lhs_ty = self.air.typeOf(bin_op.lhs);
1099 const rhs_ty = self.air.typeOf(bin_op.rhs);
1100
1101 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
933 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1102 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
934}1103}
9351104
...@@ -945,12 +1114,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -945,12 +1114,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
945 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1114 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
946}1115}
9471116
948fn airSub(self: *Self, inst: Air.Inst.Index) !void {
949 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
950 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub for {}", .{self.target.cpu.arch});
951 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
952}
953
954fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {1117fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
955 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1118 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
956 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch});1119 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch});
...@@ -1283,12 +1446,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo...@@ -1283,12 +1446,6 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
1283 .dead => unreachable,1446 .dead => unreachable,
1284 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),1447 .immediate => |imm| try self.setRegOrMem(elem_ty, dst_mcv, .{ .memory = imm }),
1285 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),1448 .ptr_stack_offset => |off| try self.setRegOrMem(elem_ty, dst_mcv, .{ .stack_offset = off }),
1286 .ptr_embedded_in_code => |off| {
1287 try self.setRegOrMem(elem_ty, dst_mcv, .{ .embedded_in_code = off });
1288 },
1289 .embedded_in_code => {
1290 return self.fail("TODO implement loading from MCValue.embedded_in_code", .{});
1291 },
1292 .register => {1449 .register => {
1293 return self.fail("TODO implement loading from MCValue.register", .{});1450 return self.fail("TODO implement loading from MCValue.register", .{});
1294 },1451 },
...@@ -1331,27 +1488,19 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {...@@ -1331,27 +1488,19 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
1331 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });1488 return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
1332}1489}
13331490
1334fn airStore(self: *Self, inst: Air.Inst.Index) !void {1491fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) !void {
1335 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1492 _ = ptr_ty;
1336 const ptr = try self.resolveInst(bin_op.lhs);1493
1337 const value = try self.resolveInst(bin_op.rhs);
1338 const elem_ty = self.air.typeOf(bin_op.rhs);
1339 switch (ptr) {1494 switch (ptr) {
1340 .none => unreachable,1495 .none => unreachable,
1341 .undef => unreachable,1496 .undef => unreachable,
1342 .unreach => unreachable,1497 .unreach => unreachable,
1343 .dead => unreachable,1498 .dead => unreachable,
1344 .immediate => |imm| {1499 .immediate => |imm| {
1345 try self.setRegOrMem(elem_ty, .{ .memory = imm }, value);1500 try self.setRegOrMem(value_ty, .{ .memory = imm }, value);
1346 },1501 },
1347 .ptr_stack_offset => |off| {1502 .ptr_stack_offset => |off| {
1348 try self.genSetStack(elem_ty, off, value);1503 try self.genSetStack(value_ty, off, value);
1349 },
1350 .ptr_embedded_in_code => |off| {
1351 try self.setRegOrMem(elem_ty, .{ .embedded_in_code = off }, value);
1352 },
1353 .embedded_in_code => {
1354 return self.fail("TODO implement storing to MCValue.embedded_in_code", .{});
1355 },1504 },
1356 .register => {1505 .register => {
1357 return self.fail("TODO implement storing to MCValue.register", .{});1506 return self.fail("TODO implement storing to MCValue.register", .{});
...@@ -1363,6 +1512,17 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {...@@ -1363,6 +1512,17 @@ fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1363 return self.fail("TODO implement storing to MCValue.stack_offset", .{});1512 return self.fail("TODO implement storing to MCValue.stack_offset", .{});
1364 },1513 },
1365 }1514 }
1515}
1516
1517fn airStore(self: *Self, inst: Air.Inst.Index) !void {
1518 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
1519 const ptr = try self.resolveInst(bin_op.lhs);
1520 const value = try self.resolveInst(bin_op.rhs);
1521 const ptr_ty = self.air.typeOf(bin_op.lhs);
1522 const value_ty = self.air.typeOf(bin_op.rhs);
1523
1524 try self.store(ptr, value, ptr_ty, value_ty);
1525
1366 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });1526 return self.finishAir(inst, .dead, .{ bin_op.lhs, bin_op.rhs, .none });
1367}1527}
13681528
...@@ -1508,7 +1668,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1508,7 +1668,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1508 .immediate => unreachable,1668 .immediate => unreachable,
1509 .unreach => unreachable,1669 .unreach => unreachable,
1510 .dead => unreachable,1670 .dead => unreachable,
1511 .embedded_in_code => unreachable,
1512 .memory => unreachable,1671 .memory => unreachable,
1513 .register => |reg| {1672 .register => |reg| {
1514 try self.register_manager.getReg(reg, null);1673 try self.register_manager.getReg(reg, null);
...@@ -1520,9 +1679,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions....@@ -1520,9 +1679,6 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
1520 .ptr_stack_offset => {1679 .ptr_stack_offset => {
1521 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});1680 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1522 },1681 },
1523 .ptr_embedded_in_code => {
1524 return self.fail("TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1525 },
1526 }1682 }
1527 }1683 }
15281684
...@@ -2052,7 +2208,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2052,7 +2208,6 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2052 switch (mcv) {2208 switch (mcv) {
2053 .dead => unreachable,2209 .dead => unreachable,
2054 .ptr_stack_offset => unreachable,2210 .ptr_stack_offset => unreachable,
2055 .ptr_embedded_in_code => unreachable,
2056 .unreach, .none => return, // Nothing to do.2211 .unreach, .none => return, // Nothing to do.
2057 .undef => {2212 .undef => {
2058 if (!self.wantSafety())2213 if (!self.wantSafety())
...@@ -2098,6 +2253,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2098,6 +2253,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2098 return self.fail("TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf2253 return self.fail("TODO genSetReg 33-64 bit immediates for riscv64", .{}); // glhf
2099 }2254 }
2100 },2255 },
2256 .register => |src_reg| {
2257 // If the registers are the same, nothing to do.
2258 if (src_reg.id() == reg.id())
2259 return;
2260
2261 // mov reg, src_reg
2262 _ = try self.addInst(.{
2263 .tag = .mv,
2264 .data = .{ .rr = .{
2265 .rd = reg,
2266 .rs = src_reg,
2267 } },
2268 });
2269 },
2101 .memory => |addr| {2270 .memory => |addr| {
2102 // The value is in memory at a hard-coded address.2271 // The value is in memory at a hard-coded address.
2103 // If the type is a pointer, it means the pointer address is at this memory location.2272 // If the type is a pointer, it means the pointer address is at this memory location.
...@@ -2321,27 +2490,6 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {...@@ -2321,27 +2490,6 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
2321 }2490 }
2322}2491}
23232492
2324/// If the MCValue is an immediate, and it does not fit within this type,
2325/// we put it in a register.
2326/// A potential opportunity for future optimization here would be keeping track
2327/// of the fact that the instruction is available both as an immediate
2328/// and as a register.
2329fn limitImmediateType(self: *Self, operand: Air.Inst.Ref, comptime T: type) !MCValue {
2330 const mcv = try self.resolveInst(operand);
2331 const ti = @typeInfo(T).Int;
2332 switch (mcv) {
2333 .immediate => |imm| {
2334 // This immediate is unsigned.
2335 const U = std.meta.Int(.unsigned, ti.bits - @boolToInt(ti.signedness == .signed));
2336 if (imm >= math.maxInt(U)) {
2337 return MCValue{ .register = try self.copyToTmpRegister(Type.initTag(.usize), mcv) };
2338 }
2339 },
2340 else => {},
2341 }
2342 return mcv;
2343}
2344
2345fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {2493fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
2346 const ptr_bits = self.target.cpu.arch.ptrBitWidth();2494 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2347 const ptr_bytes: u64 = @divExact(ptr_bits, 8);2495 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
src/arch/riscv64/Emit.zig+25
...@@ -43,6 +43,9 @@ pub fn emitMir(...@@ -43,6 +43,9 @@ pub fn emitMir(
43 for (mir_tags) |tag, index| {43 for (mir_tags) |tag, index| {
44 const inst = @intCast(u32, index);44 const inst = @intCast(u32, index);
45 switch (tag) {45 switch (tag) {
46 .add => try emit.mirRType(inst),
47 .sub => try emit.mirRType(inst),
48
46 .addi => try emit.mirIType(inst),49 .addi => try emit.mirIType(inst),
47 .jalr => try emit.mirIType(inst),50 .jalr => try emit.mirIType(inst),
48 .ld => try emit.mirIType(inst),51 .ld => try emit.mirIType(inst),
...@@ -56,6 +59,8 @@ pub fn emitMir(...@@ -56,6 +59,8 @@ pub fn emitMir(
56 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),59 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
57 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),60 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
5861
62 .mv => try emit.mirRR(inst),
63
59 .nop => try emit.mirNop(inst),64 .nop => try emit.mirNop(inst),
60 .ret => try emit.mirNop(inst),65 .ret => try emit.mirNop(inst),
6166
...@@ -131,6 +136,17 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -131,6 +136,17 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
131 }136 }
132}137}
133138
139fn mirRType(emit: *Emit, inst: Mir.Inst.Index) !void {
140 const tag = emit.mir.instructions.items(.tag)[inst];
141 const r_type = emit.mir.instructions.items(.data)[inst].r_type;
142
143 switch (tag) {
144 .add => try emit.writeInstruction(Instruction.add(r_type.rd, r_type.rs1, r_type.rs2)),
145 .sub => try emit.writeInstruction(Instruction.sub(r_type.rd, r_type.rs1, r_type.rs2)),
146 else => unreachable,
147 }
148}
149
134fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {150fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
135 const tag = emit.mir.instructions.items(.tag)[inst];151 const tag = emit.mir.instructions.items(.tag)[inst];
136 const i_type = emit.mir.instructions.items(.data)[inst].i_type;152 const i_type = emit.mir.instructions.items(.data)[inst].i_type;
...@@ -186,6 +202,15 @@ fn mirDebugEpilogueBegin(self: *Emit) !void {...@@ -186,6 +202,15 @@ fn mirDebugEpilogueBegin(self: *Emit) !void {
186 }202 }
187}203}
188204
205fn mirRR(emit: *Emit, inst: Mir.Inst.Index) !void {
206 const tag = emit.mir.instructions.items(.tag)[inst];
207 const rr = emit.mir.instructions.items(.data)[inst].rr;
208
209 switch (tag) {
210 .mv => try emit.writeInstruction(Instruction.addi(rr.rd, rr.rs, 0)),
211 else => unreachable,
212 }
213}
189fn mirUType(emit: *Emit, inst: Mir.Inst.Index) !void {214fn mirUType(emit: *Emit, inst: Mir.Inst.Index) !void {
190 const tag = emit.mir.instructions.items(.tag)[inst];215 const tag = emit.mir.instructions.items(.tag)[inst];
191 const u_type = emit.mir.instructions.items(.data)[inst].u_type;216 const u_type = emit.mir.instructions.items(.data)[inst].u_type;
src/arch/riscv64/Mir.zig+18
...@@ -24,6 +24,7 @@ pub const Inst = struct {...@@ -24,6 +24,7 @@ pub const Inst = struct {
24 data: Data,24 data: Data,
2525
26 pub const Tag = enum(u16) {26 pub const Tag = enum(u16) {
27 add,
27 addi,28 addi,
28 /// Pseudo-instruction: End of prologue29 /// Pseudo-instruction: End of prologue
29 dbg_prologue_end,30 dbg_prologue_end,
...@@ -36,9 +37,11 @@ pub const Inst = struct {...@@ -36,9 +37,11 @@ pub const Inst = struct {
36 jalr,37 jalr,
37 ld,38 ld,
38 lui,39 lui,
40 mv,
39 nop,41 nop,
40 ret,42 ret,
41 sd,43 sd,
44 sub,
42 };45 };
4346
44 /// The position of an MIR instruction within the `Mir` instructions array.47 /// The position of an MIR instruction within the `Mir` instructions array.
...@@ -68,6 +71,13 @@ pub const Inst = struct {...@@ -68,6 +71,13 @@ pub const Inst = struct {
68 ///71 ///
69 /// Used by e.g. blr72 /// Used by e.g. blr
70 reg: Register,73 reg: Register,
74 /// Two registers
75 ///
76 /// Used by e.g. mv
77 rr: struct {
78 rd: Register,
79 rs: Register,
80 },
71 /// I-Type81 /// I-Type
72 ///82 ///
73 /// Used by e.g. jalr83 /// Used by e.g. jalr
...@@ -76,6 +86,14 @@ pub const Inst = struct {...@@ -76,6 +86,14 @@ pub const Inst = struct {
76 rs1: Register,86 rs1: Register,
77 imm12: i12,87 imm12: i12,
78 },88 },
89 /// R-Type
90 ///
91 /// Used by e.g. add
92 r_type: struct {
93 rd: Register,
94 rs1: Register,
95 rs2: Register,
96 },
79 /// U-Type97 /// U-Type
80 ///98 ///
81 /// Used by e.g. lui99 /// Used by e.g. lui