authorgravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-19 20:44:57+01:00
committergravatar for joachim.schmidt557@outlook.comJoachim Schmidt <joachim.schmidt557@outlook.com> 2022-03-19 20:44:57+01:00
loga153732d5a86f7d8c5ca5bc91cfad1ccf0f8f573
tree97f065f4df0b8b6f94ed3a2dc2ebed01152757af
parent7cdc47a4e08cd32e1f68ca4aad3ca22b11e4e7b2
signature Commit is signed but in an unrecognized format.

stage2 RISCV64: implement add, sub for registers


3 files changed, 212 insertions(+), 18 deletions(-)

src/arch/riscv64/CodeGen.zig+188-18
...@@ -409,14 +409,17 @@ fn gen(self: *Self) !void {...@@ -409,14 +409,17 @@ fn gen(self: *Self) !void {
409 });409 });
410410
411 // exitlude jumps411 // exitlude jumps
412 if (self.exitlude_jump_relocs.items.len == 1) {412 if (self.exitlude_jump_relocs.items.len > 0 and
413 // There is only one relocation. Hence,413 self.exitlude_jump_relocs.items[self.exitlude_jump_relocs.items.len - 1] == self.mir_instructions.len - 2)
414 // this relocation must be at the end of414 {
415 // the code. Therefore, we can just delete415 // If the last Mir instruction (apart from the
416 // the space initially reserved for the416 // dbg_epilogue_begin) is the last exitlude jump
417 // jump417 // relocation (which would just jump one instruction
418 self.mir_instructions.len -= 1;418 // further), it can be safely removed
419 } 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| {
420 _ = jmp_reloc;423 _ = jmp_reloc;
421 return self.fail("TODO add branches in RISCV64", .{});424 return self.fail("TODO add branches in RISCV64", .{});
422 }425 }
...@@ -489,10 +492,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {...@@ -489,10 +492,10 @@ fn genBody(self: *Self, body: []const Air.Inst.Index) InnerError!void {
489492
490 switch (air_tags[inst]) {493 switch (air_tags[inst]) {
491 // zig fmt: off494 // zig fmt: off
492 .add, .ptr_add => try self.airAdd(inst),495 .add, .ptr_add => try self.airBinOp(inst),
493 .addwrap => try self.airAddWrap(inst),496 .addwrap => try self.airAddWrap(inst),
494 .add_sat => try self.airAddSat(inst),497 .add_sat => try self.airAddSat(inst),
495 .sub, .ptr_sub => try self.airSub(inst),498 .sub, .ptr_sub => try self.airBinOp(inst),
496 .subwrap => try self.airSubWrap(inst),499 .subwrap => try self.airSubWrap(inst),
497 .sub_sat => try self.airSubSat(inst),500 .sub_sat => try self.airSubSat(inst),
498 .mul => try self.airMul(inst),501 .mul => try self.airMul(inst),
...@@ -916,9 +919,182 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {...@@ -916,9 +919,182 @@ fn airSlice(self: *Self, inst: Air.Inst.Index) !void {
916 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });919 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
917}920}
918921
919fn airAdd(self: *Self, inst: Air.Inst.Index) !void {922/// Don't call this function directly. Use binOp instead.
923///
924/// Calling this function signals an intention to generate a Mir
925/// instruction of the form
926///
927/// op dest, lhs, rhs
928///
929/// Asserts that generating an instruction of that form is possible.
930fn binOpRegister(
931 self: *Self,
932 tag: Air.Inst.Tag,
933 maybe_inst: ?Air.Inst.Index,
934 lhs: MCValue,
935 rhs: MCValue,
936 lhs_ty: Type,
937 rhs_ty: Type,
938) !MCValue {
939 const lhs_is_register = lhs == .register;
940 const rhs_is_register = rhs == .register;
941
942 if (lhs_is_register) self.register_manager.freezeRegs(&.{lhs.register});
943 if (rhs_is_register) self.register_manager.freezeRegs(&.{rhs.register});
944
945 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
946
947 const lhs_reg = if (lhs_is_register) lhs.register else blk: {
948 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
949 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
950 break :inst Air.refToIndex(bin_op.lhs).?;
951 } else null;
952
953 const reg = try self.register_manager.allocReg(track_inst);
954 self.register_manager.freezeRegs(&.{reg});
955
956 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
957
958 break :blk reg;
959 };
960 defer self.register_manager.unfreezeRegs(&.{lhs_reg});
961
962 const rhs_reg = if (rhs_is_register) rhs.register else blk: {
963 const track_inst: ?Air.Inst.Index = if (maybe_inst) |inst| inst: {
964 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
965 break :inst Air.refToIndex(bin_op.rhs).?;
966 } else null;
967
968 const reg = try self.register_manager.allocReg(track_inst);
969 self.register_manager.freezeRegs(&.{reg});
970
971 if (track_inst) |inst| branch.inst_table.putAssumeCapacity(inst, .{ .register = reg });
972
973 break :blk reg;
974 };
975 defer self.register_manager.unfreezeRegs(&.{rhs_reg});
976
977 const dest_reg = if (maybe_inst) |inst| blk: {
978 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
979
980 if (lhs_is_register and self.reuseOperand(inst, bin_op.lhs, 0, lhs)) {
981 break :blk lhs_reg;
982 } else if (rhs_is_register and self.reuseOperand(inst, bin_op.rhs, 1, rhs)) {
983 break :blk rhs_reg;
984 } else {
985 break :blk try self.register_manager.allocReg(inst);
986 }
987 } else try self.register_manager.allocReg(null);
988
989 if (!lhs_is_register) try self.genSetReg(lhs_ty, lhs_reg, lhs);
990 if (!rhs_is_register) try self.genSetReg(rhs_ty, rhs_reg, rhs);
991
992 const mir_tag: Mir.Inst.Tag = switch (tag) {
993 .add => .add,
994 .sub => .sub,
995 else => unreachable,
996 };
997 const mir_data: Mir.Inst.Data = switch (tag) {
998 .add,
999 .sub,
1000 => .{ .r_type = .{
1001 .rd = dest_reg,
1002 .rs1 = lhs_reg,
1003 .rs2 = rhs_reg,
1004 } },
1005 else => unreachable,
1006 };
1007
1008 _ = try self.addInst(.{
1009 .tag = mir_tag,
1010 .data = mir_data,
1011 });
1012
1013 return MCValue{ .register = dest_reg };
1014}
1015
1016/// For all your binary operation needs, this function will generate
1017/// the corresponding Mir instruction(s). Returns the location of the
1018/// result.
1019///
1020/// If the binary operation itself happens to be an Air instruction,
1021/// pass the corresponding index in the inst parameter. That helps
1022/// this function do stuff like reusing operands.
1023///
1024/// This function does not do any lowering to Mir itself, but instead
1025/// looks at the lhs and rhs and determines which kind of lowering
1026/// would be best suitable and then delegates the lowering to other
1027/// functions.
1028fn binOp(
1029 self: *Self,
1030 tag: Air.Inst.Tag,
1031 maybe_inst: ?Air.Inst.Index,
1032 lhs: MCValue,
1033 rhs: MCValue,
1034 lhs_ty: Type,
1035 rhs_ty: Type,
1036) InnerError!MCValue {
1037 switch (tag) {
1038 // Arithmetic operations on integers and floats
1039 .add,
1040 .sub,
1041 => {
1042 switch (lhs_ty.zigTypeTag()) {
1043 .Float => return self.fail("TODO binary operations on floats", .{}),
1044 .Vector => return self.fail("TODO binary operations on vectors", .{}),
1045 .Int => {
1046 assert(lhs_ty.eql(rhs_ty));
1047 const int_info = lhs_ty.intInfo(self.target.*);
1048 if (int_info.bits <= 64) {
1049 // TODO immediate operands
1050 return try self.binOpRegister(tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1051 } else {
1052 return self.fail("TODO binary operations on int with bits > 64", .{});
1053 }
1054 },
1055 else => unreachable,
1056 }
1057 },
1058 .ptr_add,
1059 .ptr_sub,
1060 => {
1061 switch (lhs_ty.zigTypeTag()) {
1062 .Pointer => {
1063 const ptr_ty = lhs_ty;
1064 const elem_ty = switch (ptr_ty.ptrSize()) {
1065 .One => ptr_ty.childType().childType(), // ptr to array, so get array element type
1066 else => ptr_ty.childType(),
1067 };
1068 const elem_size = elem_ty.abiSize(self.target.*);
1069
1070 if (elem_size == 1) {
1071 const base_tag: Air.Inst.Tag = switch (tag) {
1072 .ptr_add => .add,
1073 .ptr_sub => .sub,
1074 else => unreachable,
1075 };
1076
1077 return try self.binOpRegister(base_tag, maybe_inst, lhs, rhs, lhs_ty, rhs_ty);
1078 } else {
1079 return self.fail("TODO ptr_add with elem_size > 1", .{});
1080 }
1081 },
1082 else => unreachable,
1083 }
1084 },
1085 else => unreachable,
1086 }
1087}
1088
1089fn airBinOp(self: *Self, inst: Air.Inst.Index) !void {
1090 const tag = self.air.instructions.items(.tag)[inst];
920 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1091 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
921 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement add for {}", .{self.target.cpu.arch});1092 const lhs = try self.resolveInst(bin_op.lhs);
1093 const rhs = try self.resolveInst(bin_op.rhs);
1094 const lhs_ty = self.air.typeOf(bin_op.lhs);
1095 const rhs_ty = self.air.typeOf(bin_op.rhs);
1096
1097 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else try self.binOp(tag, inst, lhs, rhs, lhs_ty, rhs_ty);
922 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1098 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
923}1099}
9241100
...@@ -934,12 +1110,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {...@@ -934,12 +1110,6 @@ fn airAddSat(self: *Self, inst: Air.Inst.Index) !void {
934 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });1110 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
935}1111}
9361112
937fn airSub(self: *Self, inst: Air.Inst.Index) !void {
938 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
939 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement sub for {}", .{self.target.cpu.arch});
940 return self.finishAir(inst, result, .{ bin_op.lhs, bin_op.rhs, .none });
941}
942
943fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {1113fn airSubWrap(self: *Self, inst: Air.Inst.Index) !void {
944 const bin_op = self.air.instructions.items(.data)[inst].bin_op;1114 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
945 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch});1115 const result: MCValue = if (self.liveness.isUnused(inst)) .dead else return self.fail("TODO implement subwrap for {}", .{self.target.cpu.arch});
src/arch/riscv64/Emit.zig+14
...@@ -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),
...@@ -133,6 +136,17 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {...@@ -133,6 +136,17 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
133 }136 }
134}137}
135138
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
136fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {150fn mirIType(emit: *Emit, inst: Mir.Inst.Index) !void {
137 const tag = emit.mir.instructions.items(.tag)[inst];151 const tag = emit.mir.instructions.items(.tag)[inst];
138 const i_type = emit.mir.instructions.items(.data)[inst].i_type;152 const i_type = emit.mir.instructions.items(.data)[inst].i_type;
src/arch/riscv64/Mir.zig+10
...@@ -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,
...@@ -40,6 +41,7 @@ pub const Inst = struct {...@@ -40,6 +41,7 @@ pub const Inst = struct {
40 nop,41 nop,
41 ret,42 ret,
42 sd,43 sd,
44 sub,
43 };45 };
4446
45 /// The position of an MIR instruction within the `Mir` instructions array.47 /// The position of an MIR instruction within the `Mir` instructions array.
...@@ -84,6 +86,14 @@ pub const Inst = struct {...@@ -84,6 +86,14 @@ pub const Inst = struct {
84 rs1: Register,86 rs1: Register,
85 imm12: i12,87 imm12: i12,
86 },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 },
87 /// U-Type97 /// U-Type
88 ///98 ///
89 /// Used by e.g. lui99 /// Used by e.g. lui