authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-04-10 20:52:16+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-04-14 22:18:06+07:00
log1467590e402b5b198ce7c81540263a8e08329e3c
tree739819d200ea549c77bcce629cae2d2cf8441549
parent1f63afa7c9f57a4d7657890841bdca10c3763534

stage2: sparcv9: Implement enough instruction to compile simple exes


4 files changed, 208 insertions(+), 16 deletions(-)

src/arch/sparcv9/CodeGen.zig+141-15
......@@ -193,6 +193,43 @@ const CallMCValues = struct {
193193 }
194194};
195195
196const BigTomb = struct {
197 function: *Self,
198 inst: Air.Inst.Index,
199 tomb_bits: Liveness.Bpi,
200 big_tomb_bits: u32,
201 bit_index: usize,
202
203 fn feed(bt: *BigTomb, op_ref: Air.Inst.Ref) void {
204 const this_bit_index = bt.bit_index;
205 bt.bit_index += 1;
206
207 const op_int = @enumToInt(op_ref);
208 if (op_int < Air.Inst.Ref.typed_value_map.len) return;
209 const op_index = @intCast(Air.Inst.Index, op_int - Air.Inst.Ref.typed_value_map.len);
210
211 if (this_bit_index < Liveness.bpi - 1) {
212 const dies = @truncate(u1, bt.tomb_bits >> @intCast(Liveness.OperandInt, this_bit_index)) != 0;
213 if (!dies) return;
214 } else {
215 const big_bit_index = @intCast(u5, this_bit_index - (Liveness.bpi - 1));
216 const dies = @truncate(u1, bt.big_tomb_bits >> big_bit_index) != 0;
217 if (!dies) return;
218 }
219 bt.function.processDeath(op_index);
220 }
221
222 fn finishAir(bt: *BigTomb, result: MCValue) void {
223 const is_used = !bt.function.liveness.isUnused(bt.inst);
224 if (is_used) {
225 log.debug("%{d} => {}", .{ bt.inst, result });
226 const branch = &bt.function.branch_stack.items[bt.function.branch_stack.items.len - 1];
227 branch.inst_table.putAssumeCapacityNoClobber(bt.inst, result);
228 }
229 bt.function.finishAirBookkeeping();
230 }
231};
232
196233pub fn generate(
197234 bin_file: *link.File,
198235 src_loc: Module.SrcLoc,
......@@ -684,8 +721,16 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
684721 return self.finishAir(inst, result, buf);
685722 }
686723
687 @panic("TODO implement asm return");
688 //return self.fail("TODO implement asm return for {}", .{self.target.cpu.arch});
724 var bt = try self.iterateBigTomb(inst, outputs.len + inputs.len);
725 for (outputs) |output| {
726 if (output == .none) continue;
727
728 bt.feed(output);
729 }
730 for (inputs) |input| {
731 bt.feed(input);
732 }
733 return bt.finishAir(result);
689734}
690735
691736fn airArg(self: *Self, inst: Air.Inst.Index) !void {
......@@ -1071,13 +1116,65 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
10711116 self.finishAirBookkeeping();
10721117}
10731118
1074fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, off: i13, abi_size: u64) !void {
1075 _ = value_reg;
1076 _ = addr_reg;
1077 _ = off;
1119fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void {
1120 assert(off_type == Register or off_type == i13);
1121
1122 const is_imm = (off_type == i13);
1123 const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off };
10781124
10791125 switch (abi_size) {
1080 1, 2, 4, 8 => return self.fail("TODO: A.27 Load Integer", .{}),
1126 1 => {
1127 _ = try self.addInst(.{
1128 .tag = .ldub,
1129 .data = .{
1130 .arithmetic_3op = .{
1131 .is_imm = is_imm,
1132 .rd = value_reg,
1133 .rs1 = addr_reg,
1134 .rs2_or_imm = rs2_or_imm,
1135 },
1136 },
1137 });
1138 },
1139 2 => {
1140 _ = try self.addInst(.{
1141 .tag = .lduh,
1142 .data = .{
1143 .arithmetic_3op = .{
1144 .is_imm = is_imm,
1145 .rd = value_reg,
1146 .rs1 = addr_reg,
1147 .rs2_or_imm = rs2_or_imm,
1148 },
1149 },
1150 });
1151 },
1152 4 => {
1153 _ = try self.addInst(.{
1154 .tag = .lduw,
1155 .data = .{
1156 .arithmetic_3op = .{
1157 .is_imm = is_imm,
1158 .rd = value_reg,
1159 .rs1 = addr_reg,
1160 .rs2_or_imm = rs2_or_imm,
1161 },
1162 },
1163 });
1164 },
1165 8 => {
1166 _ = try self.addInst(.{
1167 .tag = .ldx,
1168 .data = .{
1169 .arithmetic_3op = .{
1170 .is_imm = is_imm,
1171 .rd = value_reg,
1172 .rs1 = addr_reg,
1173 .rs2_or_imm = rs2_or_imm,
1174 },
1175 },
1176 });
1177 },
10811178 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}),
10821179 else => unreachable,
10831180 }
......@@ -1226,12 +1323,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
12261323 // The value is in memory at a hard-coded address.
12271324 // If the type is a pointer, it means the pointer address is at this memory location.
12281325 try self.genSetReg(ty, reg, .{ .immediate = addr });
1229 try self.genLoad(reg, reg, 0, ty.abiSize(self.target.*));
1326 try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*));
12301327 },
12311328 .stack_offset => |off| {
12321329 const simm13 = math.cast(u12, off) catch
12331330 return self.fail("TODO larger stack offsets", .{});
1234 try self.genLoad(reg, .sp, simm13, ty.abiSize(self.target.*));
1331 try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*));
12351332 },
12361333 }
12371334}
......@@ -1269,14 +1366,10 @@ fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
12691366 return MCValue{ .undef = {} };
12701367
12711368 if (typed_value.val.castTag(.decl_ref)) |payload| {
1272 _ = payload;
1273 return self.fail("TODO implement lowerDeclRef non-mut", .{});
1274 // return self.lowerDeclRef(typed_value, payload.data);
1369 return self.lowerDeclRef(typed_value, payload.data);
12751370 }
12761371 if (typed_value.val.castTag(.decl_ref_mut)) |payload| {
1277 _ = payload;
1278 return self.fail("TODO implement lowerDeclRef mut", .{});
1279 // return self.lowerDeclRef(typed_value, payload.data.decl);
1372 return self.lowerDeclRef(typed_value, payload.data.decl);
12801373 }
12811374 const target = self.target.*;
12821375
......@@ -1315,6 +1408,39 @@ fn getResolvedInstValue(self: *Self, inst: Air.Inst.Index) MCValue {
13151408 }
13161409}
13171410
1411fn iterateBigTomb(self: *Self, inst: Air.Inst.Index, operand_count: usize) !BigTomb {
1412 try self.ensureProcessDeathCapacity(operand_count + 1);
1413 return BigTomb{
1414 .function = self,
1415 .inst = inst,
1416 .tomb_bits = self.liveness.getTombBits(inst),
1417 .big_tomb_bits = self.liveness.special.get(inst) orelse 0,
1418 .bit_index = 0,
1419 };
1420}
1421
1422fn lowerDeclRef(self: *Self, tv: TypedValue, decl: *Module.Decl) InnerError!MCValue {
1423 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
1424 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
1425
1426 // TODO this feels clunky. Perhaps we should check for it in `genTypedValue`?
1427 if (tv.ty.zigTypeTag() == .Pointer) blk: {
1428 if (tv.ty.castPtrToFn()) |_| break :blk;
1429 if (!tv.ty.elemType2().hasRuntimeBits()) {
1430 return MCValue.none;
1431 }
1432 }
1433
1434 decl.alive = true;
1435 if (self.bin_file.cast(link.File.Elf)) |elf_file| {
1436 const got = &elf_file.program_headers.items[elf_file.phdr_got_index.?];
1437 const got_addr = got.p_vaddr + decl.link.elf.offset_table_index * ptr_bytes;
1438 return MCValue{ .memory = got_addr };
1439 } else {
1440 return self.fail("TODO codegen non-ELF const Decl pointer", .{});
1441 }
1442}
1443
13181444fn parseRegName(name: []const u8) ?Register {
13191445 if (@hasDecl(Register, "parseRegName")) {
13201446 return Register.parseRegName(name);
src/arch/sparcv9/Emit.zig+25-1
......@@ -59,6 +59,11 @@ pub fn emitMir(
5959 .jmpl => @panic("TODO implement sparcv9 jmpl"),
6060 .jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"),
6161
62 .ldub => try emit.mirArithmetic3Op(inst),
63 .lduh => try emit.mirArithmetic3Op(inst),
64 .lduw => try emit.mirArithmetic3Op(inst),
65 .ldx => try emit.mirArithmetic3Op(inst),
66
6267 .@"or" => try emit.mirArithmetic3Op(inst),
6368
6469 .nop => try emit.mirNop(),
......@@ -68,7 +73,7 @@ pub fn emitMir(
6873 .save => try emit.mirArithmetic3Op(inst),
6974 .restore => try emit.mirArithmetic3Op(inst),
7075
71 .sethi => @panic("TODO implement sparcv9 sethi"),
76 .sethi => try emit.mirSethi(inst),
7277
7378 .sllx => @panic("TODO implement sparcv9 sllx"),
7479
......@@ -158,6 +163,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
158163 const imm = data.rs2_or_imm.imm;
159164 switch (tag) {
160165 .add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)),
166 .ldub => try emit.writeInstruction(Instruction.ldub(i13, rs1, imm, rd)),
167 .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)),
168 .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)),
169 .ldx => try emit.writeInstruction(Instruction.ldx(i13, rs1, imm, rd)),
161170 .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)),
162171 .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),
163172 .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),
......@@ -168,6 +177,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
168177 const rs2 = data.rs2_or_imm.rs2;
169178 switch (tag) {
170179 .add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)),
180 .ldub => try emit.writeInstruction(Instruction.ldub(Register, rs1, rs2, rd)),
181 .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)),
182 .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)),
183 .ldx => try emit.writeInstruction(Instruction.ldx(Register, rs1, rs2, rd)),
171184 .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)),
172185 .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),
173186 .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),
......@@ -181,6 +194,17 @@ fn mirNop(emit: *Emit) !void {
181194 try emit.writeInstruction(Instruction.nop());
182195}
183196
197fn mirSethi(emit: *Emit, inst: Mir.Inst.Index) !void {
198 const tag = emit.mir.instructions.items(.tag)[inst];
199 const data = emit.mir.instructions.items(.data)[inst].sethi;
200
201 const imm = data.imm;
202 const rd = data.rd;
203
204 assert(tag == .sethi);
205 try emit.writeInstruction(Instruction.sethi(imm, rd));
206}
207
184208fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void {
185209 const tag = emit.mir.instructions.items(.tag)[inst];
186210 const data = emit.mir.instructions.items(.data)[inst].trap;
src/arch/sparcv9/Mir.zig+10
......@@ -60,6 +60,16 @@ pub const Inst = struct {
6060 jmpl,
6161 jmpl_i,
6262
63 /// A.27 Load Integer
64 /// Those uses the arithmetic_3op field.
65 /// Note that the ldd variant of this instruction is deprecated, do not emit
66 /// it unless specifically requested (e.g. by inline assembly).
67 // TODO add other operations.
68 ldub,
69 lduh,
70 lduw,
71 ldx,
72
6373 /// A.31 Logical Operations
6474 /// Those uses the arithmetic_3op field.
6575 // TODO add other operations.
src/arch/sparcv9/bits.zig+32
......@@ -979,6 +979,38 @@ pub const Instruction = union(enum) {
979979 };
980980 }
981981
982 pub fn ldub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
983 return switch (s2) {
984 Register => format3a(0b11, 0b00_0001, rs1, rs2, rd),
985 i13 => format3b(0b11, 0b00_0001, rs1, rs2, rd),
986 else => unreachable,
987 };
988 }
989
990 pub fn lduh(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
991 return switch (s2) {
992 Register => format3a(0b11, 0b00_0010, rs1, rs2, rd),
993 i13 => format3b(0b11, 0b00_0010, rs1, rs2, rd),
994 else => unreachable,
995 };
996 }
997
998 pub fn lduw(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
999 return switch (s2) {
1000 Register => format3a(0b11, 0b00_0000, rs1, rs2, rd),
1001 i13 => format3b(0b11, 0b00_0000, rs1, rs2, rd),
1002 else => unreachable,
1003 };
1004 }
1005
1006 pub fn ldx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1007 return switch (s2) {
1008 Register => format3a(0b11, 0b00_1011, rs1, rs2, rd),
1009 i13 => format3b(0b11, 0b00_1011, rs1, rs2, rd),
1010 else => unreachable,
1011 };
1012 }
1013
9821014 pub fn nop() Instruction {
9831015 return sethi(0, .g0);
9841016 }