authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-04-10 14:29:06+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-04-14 22:18:06+07:00
log7051970ad7e277d93c8bffee7221e3e8c45c8eab
tree9a991d03359ef1d4bab8404bbba5bc825afe4d4d
parent5e2045cbe549c9020ebbbecc763699fc4a68c818

stage2: sparcv9: implement basic instruction lowering


4 files changed, 231 insertions(+), 57 deletions(-)

src/arch/sparcv9/CodeGen.zig+2-2
......@@ -1270,12 +1270,12 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
12701270
12711271 if (typed_value.val.castTag(.decl_ref)) |payload| {
12721272 _ = payload;
1273 return self.fail("TODO implement lowerDeclRef", .{});
1273 return self.fail("TODO implement lowerDeclRef non-mut", .{});
12741274 // return self.lowerDeclRef(typed_value, payload.data);
12751275 }
12761276 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
12771277 _ = payload;
1278 return self.fail("TODO implement lowerDeclRef", .{});
1278 return self.fail("TODO implement lowerDeclRef mut", .{});
12791279 // return self.lowerDeclRef(typed_value, payload.data.decl);
12801280 }
12811281 const target = self.target.*;
src/arch/sparcv9/Emit.zig+143-51
......@@ -2,6 +2,7 @@
22//! machine code
33
44const std = @import("std");
5const Endian = std.builtin.Endian;
56const assert = std.debug.assert;
67const link = @import("../../link.zig");
78const Module = @import("../../Module.zig");
......@@ -14,6 +15,8 @@ const leb128 = std.leb;
1415const Emit = @This();
1516const Mir = @import("Mir.zig");
1617const bits = @import("bits.zig");
18const Instruction = bits.Instruction;
19const Register = bits.Register;
1720
1821mir: Mir,
1922bin_file: *link.File,
......@@ -47,7 +50,7 @@ pub fn emitMir(
4750 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
4851 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
4952
50 .add => @panic("TODO implement sparcv9 add"),
53 .add => try emit.mirArithmetic3Op(inst),
5154
5255 .bpcc => @panic("TODO implement sparcv9 bpcc"),
5356
......@@ -56,22 +59,22 @@ pub fn emitMir(
5659 .jmpl => @panic("TODO implement sparcv9 jmpl"),
5760 .jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"),
5861
59 .@"or" => @panic("TODO implement sparcv9 or"),
62 .@"or" => try emit.mirArithmetic3Op(inst),
6063
61 .nop => @panic("TODO implement sparcv9 nop"),
64 .nop => try emit.mirNop(),
6265
63 .@"return" => @panic("TODO implement sparcv9 return"),
66 .@"return" => try emit.mirArithmetic2Op(inst),
6467
65 .save => @panic("TODO implement sparcv9 save"),
66 .restore => @panic("TODO implement sparcv9 restore"),
68 .save => try emit.mirArithmetic3Op(inst),
69 .restore => try emit.mirArithmetic3Op(inst),
6770
6871 .sethi => @panic("TODO implement sparcv9 sethi"),
6972
7073 .sllx => @panic("TODO implement sparcv9 sllx"),
7174
72 .sub => @panic("TODO implement sparcv9 sub"),
75 .sub => try emit.mirArithmetic3Op(inst),
7376
74 .tcc => @panic("TODO implement sparcv9 tcc"),
77 .tcc => try emit.mirTrap(inst),
7578 }
7679 }
7780}
......@@ -80,6 +83,129 @@ pub fn deinit(emit: *Emit) void {
8083 emit.* = undefined;
8184}
8285
86fn mirDbgArg(emit: *Emit, inst: Mir.Inst.Index) !void {
87 const tag = emit.mir.instructions.items(.tag)[inst];
88 const dbg_arg_info = emit.mir.instructions.items(.data)[inst].dbg_arg_info;
89 _ = dbg_arg_info;
90
91 switch (tag) {
92 .dbg_arg => {}, // TODO try emit.genArgDbgInfo(dbg_arg_info.air_inst, dbg_arg_info.arg_index),
93 else => unreachable,
94 }
95}
96
97fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
98 const tag = emit.mir.instructions.items(.tag)[inst];
99 const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column;
100
101 switch (tag) {
102 .dbg_line => try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column),
103 else => unreachable,
104 }
105}
106
107fn mirDebugPrologueEnd(self: *Emit) !void {
108 switch (self.debug_output) {
109 .dwarf => |dbg_out| {
110 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
111 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
112 },
113 .plan9 => {},
114 .none => {},
115 }
116}
117
118fn mirDebugEpilogueBegin(self: *Emit) !void {
119 switch (self.debug_output) {
120 .dwarf => |dbg_out| {
121 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
122 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
123 },
124 .plan9 => {},
125 .none => {},
126 }
127}
128
129fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void {
130 const tag = emit.mir.instructions.items(.tag)[inst];
131 const data = emit.mir.instructions.items(.data)[inst].arithmetic_2op;
132
133 const rs1 = data.rs1;
134
135 if (data.is_imm) {
136 const imm = data.rs2_or_imm.imm;
137 switch (tag) {
138 .@"return" => try emit.writeInstruction(Instruction.@"return"(i13, rs1, imm)),
139 else => unreachable,
140 }
141 } else {
142 const rs2 = data.rs2_or_imm.rs2;
143 switch (tag) {
144 .@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)),
145 else => unreachable,
146 }
147 }
148}
149
150fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
151 const tag = emit.mir.instructions.items(.tag)[inst];
152 const data = emit.mir.instructions.items(.data)[inst].arithmetic_3op;
153
154 const rd = data.rd;
155 const rs1 = data.rs1;
156
157 if (data.is_imm) {
158 const imm = data.rs2_or_imm.imm;
159 switch (tag) {
160 .add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)),
161 .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)),
162 .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),
163 .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),
164 .sub => try emit.writeInstruction(Instruction.sub(i13, rs1, imm, rd)),
165 else => unreachable,
166 }
167 } else {
168 const rs2 = data.rs2_or_imm.rs2;
169 switch (tag) {
170 .add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)),
171 .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)),
172 .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),
173 .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),
174 .sub => try emit.writeInstruction(Instruction.sub(Register, rs1, rs2, rd)),
175 else => unreachable,
176 }
177 }
178}
179
180fn mirNop(emit: *Emit) !void {
181 try emit.writeInstruction(Instruction.nop());
182}
183
184fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void {
185 const tag = emit.mir.instructions.items(.tag)[inst];
186 const data = emit.mir.instructions.items(.data)[inst].trap;
187
188 const cond = data.cond;
189 const ccr = data.ccr;
190 const rs1 = data.rs1;
191
192 if (data.is_imm) {
193 const imm = data.rs2_or_imm.imm;
194 switch (tag) {
195 .tcc => try emit.writeInstruction(Instruction.trap(u7, cond, ccr, rs1, imm)),
196 else => unreachable,
197 }
198 } else {
199 const rs2 = data.rs2_or_imm.rs2;
200 switch (tag) {
201 .tcc => try emit.writeInstruction(Instruction.trap(Register, cond, ccr, rs1, rs2)),
202 else => unreachable,
203 }
204 }
205}
206
207// Common helper functions
208
83209fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
84210 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
85211 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
......@@ -131,52 +257,18 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
131257 }
132258}
133259
134fn mirDbgArg(emit: *Emit, inst: Mir.Inst.Index) !void {
135 const tag = emit.mir.instructions.items(.tag)[inst];
136 const dbg_arg_info = emit.mir.instructions.items(.data)[inst].dbg_arg_info;
137 _ = dbg_arg_info;
138
139 switch (tag) {
140 .dbg_arg => {}, // TODO try emit.genArgDbgInfo(dbg_arg_info.air_inst, dbg_arg_info.arg_index),
141 else => unreachable,
142 }
143}
144
145fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
146 const tag = emit.mir.instructions.items(.tag)[inst];
147 const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column;
148
149 switch (tag) {
150 .dbg_line => try emit.dbgAdvancePCAndLine(dbg_line_column.line, dbg_line_column.column),
151 else => unreachable,
152 }
153}
154
155fn mirDebugPrologueEnd(self: *Emit) !void {
156 switch (self.debug_output) {
157 .dwarf => |dbg_out| {
158 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
159 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
160 },
161 .plan9 => {},
162 .none => {},
163 }
164}
165
166fn mirDebugEpilogueBegin(self: *Emit) !void {
167 switch (self.debug_output) {
168 .dwarf => |dbg_out| {
169 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
170 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
171 },
172 .plan9 => {},
173 .none => {},
174 }
175}
176
177260fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
178261 @setCold(true);
179262 assert(emit.err_msg == null);
180263 emit.err_msg = try ErrorMsg.create(emit.bin_file.allocator, emit.src_loc, format, args);
181264 return error.EmitFail;
182265}
266
267fn writeInstruction(emit: *Emit, instruction: Instruction) !void {
268 // SPARCv9 instructions are always arranged in BE regardless of the
269 // endianness mode the CPU is running in.
270 // This is to ease porting in case someone wants to do a LE SPARCv9 backend.
271 const endian = Endian.Big;
272
273 std.mem.writeInt(u32, try emit.code.addManyAsArray(4), instruction.toU32(), endian);
274}
src/arch/sparcv9/Mir.zig+13-2
......@@ -167,7 +167,7 @@ pub const Inst = struct {
167167 /// Branch with prediction.
168168 /// Used by e.g. bpcc
169169 branch_predict: struct {
170 annul: bool,
170 annul: bool = false,
171171 pt: bool = true,
172172 ccr: Instruction.CCR,
173173 cond: Instruction.Condition,
......@@ -215,10 +215,21 @@ pub const Inst = struct {
215215 rs1: Register = .g0,
216216 rs2_or_imm: union {
217217 rs2: Register,
218 imm: u8,
218 imm: u7,
219219 },
220220 },
221221 };
222
223 // Make sure we don't accidentally make instructions bigger than expected.
224 // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
225 comptime {
226 if (builtin.mode != .Debug) {
227 // TODO clean up the definition of Data before enabling this.
228 // I'll do that after the PoC backend can produce usable binaries.
229
230 // assert(@sizeOf(Data) == 8);
231 }
232 }
222233};
223234
224235pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void {
src/arch/sparcv9/bits.zig+73-2
......@@ -546,6 +546,9 @@ pub const Instruction = union(enum) {
546546 };
547547 }
548548
549 // SPARCv9 Instruction formats.
550 // See section 6.2 of the SPARCv9 ISA manual.
551
549552 fn format1(disp: i32) Instruction {
550553 const udisp = @bitCast(u32, disp);
551554
......@@ -561,7 +564,7 @@ pub const Instruction = union(enum) {
561564 };
562565 }
563566
564 fn format2a(op2: u3, rd: Register, imm: u22) Instruction {
567 fn format2a(op2: u3, imm: u22, rd: Register) Instruction {
565568 return Instruction{
566569 .format_2a = .{
567570 .rd = rd.enc(),
......@@ -956,6 +959,74 @@ pub const Instruction = union(enum) {
956959 },
957960 };
958961 }
962
963 // SPARCv9 Instruction definition.
964 // See appendix A of the SPARCv9 ISA manual.
965
966 pub fn add(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
967 return switch(s2) {
968 Register => format3a(0b10, 0b00_0000, rs1, rs2, rd),
969 i13 => format3b(0b10, 0b00_0000, rs1, rs2, rd),
970 else => unreachable,
971 };
972 }
973
974 pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
975 return switch(s2) {
976 Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),
977 i13 => format3b(0b10, 0b00_0010, rs1, rs2, rd),
978 else => unreachable,
979 };
980 }
981
982 pub fn nop() Instruction {
983 return sethi(0, .g0);
984 }
985
986 pub fn @"return"(comptime s2: type, rs1: Register, rs2: s2) Instruction {
987 return switch(s2) {
988 Register => format3c(0b10, 0b11_1001, rs1, rs2),
989 i13 => format3d(0b10, 0b11_1001, rs1, rs2),
990 else => unreachable,
991 };
992 }
993
994 pub fn save(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
995 return switch(s2) {
996 Register => format3a(0b10, 0b11_1100, rs1, rs2, rd),
997 i13 => format3b(0b10, 0b11_1100, rs1, rs2, rd),
998 else => unreachable,
999 };
1000 }
1001
1002 pub fn restore(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1003 return switch(s2) {
1004 Register => format3a(0b10, 0b11_1101, rs1, rs2, rd),
1005 i13 => format3b(0b10, 0b11_1101, rs1, rs2, rd),
1006 else => unreachable,
1007 };
1008 }
1009
1010 pub fn sethi(imm: u22, rd: Register) Instruction {
1011 return format2a(0b100, imm, rd);
1012 }
1013
1014 pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1015 return switch(s2) {
1016 Register => format3a(0b10, 0b00_0100, rs1, rs2, rd),
1017 i13 => format3b(0b10, 0b00_0100, rs1, rs2, rd),
1018 else => unreachable,
1019 };
1020 }
1021
1022 pub fn trap(comptime s2: type, cond: Condition, ccr: CCR, rs1: Register, rs2: s2) Instruction {
1023 // Tcc instructions abuse the rd field to store the conditionals.
1024 return switch(s2) {
1025 Register => format4a(0b11_1010, ccr, rs1, rs2, @intToEnum(Register, cond)),
1026 u7 => format4e(0b00_0100, ccr, rs1, @intToEnum(Register, cond), rs2),
1027 else => unreachable,
1028 };
1029 }
9591030};
9601031
9611032test "Serialize formats" {
......@@ -973,7 +1044,7 @@ test "Serialize formats" {
9731044 .expected = 0b01_000000000000000000000000000001,
9741045 },
9751046 .{
976 .inst = Instruction.format2a(4, .g0, 0),
1047 .inst = Instruction.format2a(4, 0, .g0),
9771048 .expected = 0b00_00000_100_0000000000000000000000,
9781049 },
9791050 .{