authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-06 07:27:30+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-06 07:27:30+02:00
log09d2b6c4e1b2edd1d011ef4f947cdd835313a2e5
treea0d9836cd8d0d81ec5e441b80938f3bf3a99e53f
parent13d1798ea0c2665f09508ac505259e761f8b4e22
parent9985699943edb4bf4f3dae9b57e0e2017c23c4bf
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11487 from koachan/sparc64-codegen


7 files changed, 285 insertions(+), 167 deletions(-)

lib/std/zig/system/NativeTargetInfo.zig+1
......@@ -931,6 +931,7 @@ pub fn getExternalExecutor(
931931 .riscv64 => Executor{ .qemu = "qemu-riscv64" },
932932 .s390x => Executor{ .qemu = "qemu-s390x" },
933933 .sparc => Executor{ .qemu = "qemu-sparc" },
934 .sparcv9 => Executor{ .qemu = "qemu-sparc64" },
934935 .x86_64 => Executor{ .qemu = "qemu-x86_64" },
935936 else => return bad_result,
936937 };
src/arch/sparcv9/CodeGen.zig+166-61
......@@ -1,5 +1,7 @@
11//! SPARCv9 codegen.
22//! This lowers AIR into MIR.
3//! For now this only implements medium/low code model with absolute addressing.
4//! TODO add support for other code models.
35const std = @import("std");
46const assert = std.debug.assert;
57const log = std.log.scoped(.codegen);
......@@ -338,16 +340,15 @@ fn gen(self: *Self) !void {
338340 if (cc != .Naked) {
339341 // TODO Finish function prologue and epilogue for sparcv9.
340342
341 // TODO Backpatch stack offset
342 // save %sp, -176, %sp
343 _ = try self.addInst(.{
343 // save %sp, stack_save_area, %sp
344 const save_inst = try self.addInst(.{
344345 .tag = .save,
345346 .data = .{
346347 .arithmetic_3op = .{
347348 .is_imm = true,
348349 .rd = .sp,
349350 .rs1 = .sp,
350 .rs2_or_imm = .{ .imm = -176 },
351 .rs2_or_imm = .{ .imm = -abi.stack_save_area },
351352 },
352353 },
353354 });
......@@ -380,6 +381,28 @@ fn gen(self: *Self) !void {
380381 return self.fail("TODO add branches in sparcv9", .{});
381382 }
382383
384 // Backpatch stack offset
385 const total_stack_size = self.max_end_stack + abi.stack_save_area; // TODO + self.saved_regs_stack_space;
386 const stack_size = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
387 if (math.cast(i13, stack_size)) |size| {
388 self.mir_instructions.set(save_inst, .{
389 .tag = .save,
390 .data = .{
391 .arithmetic_3op = .{
392 .is_imm = true,
393 .rd = .sp,
394 .rs1 = .sp,
395 .rs2_or_imm = .{ .imm = -size },
396 },
397 },
398 });
399 } else |_| {
400 // TODO for large stacks, replace the prologue with:
401 // setx stack_size, %g1
402 // save %sp, %g1, %sp
403 return self.fail("TODO SPARCv9: allow larger stacks", .{});
404 }
405
383406 // return %i7 + 8
384407 _ = try self.addInst(.{
385408 .tag = .@"return",
......@@ -392,7 +415,11 @@ fn gen(self: *Self) !void {
392415 },
393416 });
394417
395 // TODO Find a way to fill this slot
418 // Branches in SPARC have a delay slot, that is, the instruction
419 // following it will unconditionally be executed.
420 // See: Section 3.2.3 Control Transfer in SPARCv9 manual.
421 // See also: https://arcb.csc.ncsu.edu/~mueller/codeopt/codeopt00/notes/delaybra.html
422 // TODO Find a way to fill this delay slot
396423 // nop
397424 _ = try self.addInst(.{
398425 .tag = .nop,
......@@ -753,15 +780,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void {
753780 // TODO Copy registers to the stack
754781 const mcv = result;
755782
756 _ = try self.addInst(.{
757 .tag = .dbg_arg,
758 .data = .{
759 .dbg_arg_info = .{
760 .air_inst = inst,
761 .arg_index = arg_index,
762 },
763 },
764 });
783 try self.genArgDbgInfo(inst, mcv, @intCast(u32, arg_index));
765784
766785 if (self.liveness.isUnused(inst))
767786 return self.finishAirBookkeeping();
......@@ -884,7 +903,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
884903
885904 _ = try self.addInst(.{
886905 .tag = .jmpl,
887 .data = .{ .branch_link_indirect = .{ .reg = .o7 } },
906 .data = .{
907 .arithmetic_3op = .{
908 .is_imm = false,
909 .rd = .o7,
910 .rs1 = .o7,
911 .rs2_or_imm = .{ .rs2 = .g0 },
912 },
913 },
914 });
915
916 // TODO Find a way to fill this delay slot
917 _ = try self.addInst(.{
918 .tag = .nop,
919 .data = .{ .nop = {} },
888920 });
889921 } else if (func_value.castTag(.extern_fn)) |_| {
890922 return self.fail("TODO implement calling extern functions", .{});
......@@ -899,7 +931,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions.
899931
900932 _ = try self.addInst(.{
901933 .tag = .jmpl,
902 .data = .{ .branch_link_indirect = .{ .reg = .o7 } },
934 .data = .{
935 .arithmetic_3op = .{
936 .is_imm = false,
937 .rd = .o7,
938 .rs1 = .o7,
939 .rs2_or_imm = .{ .rs2 = .g0 },
940 },
941 },
942 });
943
944 // TODO Find a way to fill this delay slot
945 _ = try self.addInst(.{
946 .tag = .nop,
947 .data = .{ .nop = {} },
903948 });
904949 }
905950
......@@ -995,11 +1040,29 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void {
9951040
9961041// Common helper functions
9971042
1043/// Adds a Type to the .debug_info at the current position. The bytes will be populated later,
1044/// after codegen for this symbol is done.
1045fn addDbgInfoTypeReloc(self: *Self, ty: Type) !void {
1046 switch (self.debug_output) {
1047 .dwarf => |dw| {
1048 assert(ty.hasRuntimeBits());
1049 const dbg_info = &dw.dbg_info;
1050 const index = dbg_info.items.len;
1051 try dbg_info.resize(index + 4); // DW.AT.type, DW.FORM.ref4
1052 const mod = self.bin_file.options.module.?;
1053 const atom = switch (self.bin_file.tag) {
1054 .elf => &mod.declPtr(self.mod_fn.owner_decl).link.elf.dbg_info_atom,
1055 else => unreachable,
1056 };
1057 try dw.addTypeReloc(atom, ty, @intCast(u32, index), null);
1058 },
1059 else => {},
1060 }
1061}
1062
9981063fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index {
9991064 const gpa = self.gpa;
1000
10011065 try self.mir_instructions.ensureUnusedCapacity(gpa, 1);
1002
10031066 const result_index = @intCast(Air.Inst.Index, self.mir_instructions.len);
10041067 self.mir_instructions.appendAssumeCapacity(inst);
10051068 return result_index;
......@@ -1125,6 +1188,40 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live
11251188 self.finishAirBookkeeping();
11261189}
11271190
1191fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, mcv: MCValue, arg_index: u32) !void {
1192 const ty = self.air.instructions.items(.data)[inst].ty;
1193 const name = self.mod_fn.getParamName(arg_index);
1194 const name_with_null = name.ptr[0 .. name.len + 1];
1195
1196 switch (mcv) {
1197 .register => |reg| {
1198 switch (self.debug_output) {
1199 .dwarf => |dw| {
1200 const dbg_info = &dw.dbg_info;
1201 try dbg_info.ensureUnusedCapacity(3);
1202 dbg_info.appendAssumeCapacity(@enumToInt(link.File.Dwarf.AbbrevKind.parameter));
1203 dbg_info.appendSliceAssumeCapacity(&[2]u8{ // DW.AT.location, DW.FORM.exprloc
1204 1, // ULEB128 dwarf expression length
1205 reg.dwarfLocOp(),
1206 });
1207 try dbg_info.ensureUnusedCapacity(5 + name_with_null.len);
1208 try self.addDbgInfoTypeReloc(ty); // DW.AT.type, DW.FORM.ref4
1209 dbg_info.appendSliceAssumeCapacity(name_with_null); // DW.AT.name, DW.FORM.string
1210 },
1211 else => {},
1212 }
1213 },
1214 .stack_offset => |offset| {
1215 _ = offset;
1216 switch (self.debug_output) {
1217 .dwarf => {},
1218 else => {},
1219 }
1220 },
1221 else => {},
1222 }
1223}
1224
11281225fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void {
11291226 assert(off_type == Register or off_type == i13);
11301227
......@@ -1132,48 +1229,17 @@ fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_ty
11321229 const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off };
11331230
11341231 switch (abi_size) {
1135 1 => {
1136 _ = try self.addInst(.{
1137 .tag = .ldub,
1138 .data = .{
1139 .arithmetic_3op = .{
1140 .is_imm = is_imm,
1141 .rd = value_reg,
1142 .rs1 = addr_reg,
1143 .rs2_or_imm = rs2_or_imm,
1144 },
1145 },
1146 });
1147 },
1148 2 => {
1149 _ = try self.addInst(.{
1150 .tag = .lduh,
1151 .data = .{
1152 .arithmetic_3op = .{
1153 .is_imm = is_imm,
1154 .rd = value_reg,
1155 .rs1 = addr_reg,
1156 .rs2_or_imm = rs2_or_imm,
1157 },
1158 },
1159 });
1160 },
1161 4 => {
1162 _ = try self.addInst(.{
1163 .tag = .lduw,
1164 .data = .{
1165 .arithmetic_3op = .{
1166 .is_imm = is_imm,
1167 .rd = value_reg,
1168 .rs1 = addr_reg,
1169 .rs2_or_imm = rs2_or_imm,
1170 },
1171 },
1172 });
1173 },
1174 8 => {
1232 1, 2, 4, 8 => {
1233 const tag: Mir.Inst.Tag = switch (abi_size) {
1234 1 => .ldub,
1235 2 => .lduh,
1236 4 => .lduw,
1237 8 => .ldx,
1238 else => unreachable, // unexpected abi size
1239 };
1240
11751241 _ = try self.addInst(.{
1176 .tag = .ldx,
1242 .tag = tag,
11771243 .data = .{
11781244 .arithmetic_3op = .{
11791245 .is_imm = is_imm,
......@@ -1335,7 +1401,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
13351401 try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*));
13361402 },
13371403 .stack_offset => |off| {
1338 const simm13 = math.cast(u12, off) catch
1404 const real_offset = off + abi.stack_bias + abi.stack_save_area;
1405 const simm13 = math.cast(i13, real_offset) catch
13391406 return self.fail("TODO larger stack offsets", .{});
13401407 try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*));
13411408 },
......@@ -1365,11 +1432,49 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
13651432 const reg = try self.copyToTmpRegister(ty, mcv);
13661433 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
13671434 },
1368 .register => return self.fail("TODO implement storing types abi_size={}", .{abi_size}),
1435 .register => |reg| {
1436 const real_offset = stack_offset + abi.stack_bias + abi.stack_save_area;
1437 const simm13 = math.cast(i13, real_offset) catch
1438 return self.fail("TODO larger stack offsets", .{});
1439 return self.genStore(reg, .sp, i13, simm13, abi_size);
1440 },
13691441 .memory, .stack_offset => return self.fail("TODO implement memcpy", .{}),
13701442 }
13711443}
13721444
1445fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void {
1446 assert(off_type == Register or off_type == i13);
1447
1448 const is_imm = (off_type == i13);
1449 const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off };
1450
1451 switch (abi_size) {
1452 1, 2, 4, 8 => {
1453 const tag: Mir.Inst.Tag = switch (abi_size) {
1454 1 => .stb,
1455 2 => .sth,
1456 4 => .stw,
1457 8 => .stx,
1458 else => unreachable, // unexpected abi size
1459 };
1460
1461 _ = try self.addInst(.{
1462 .tag = tag,
1463 .data = .{
1464 .arithmetic_3op = .{
1465 .is_imm = is_imm,
1466 .rd = value_reg,
1467 .rs1 = addr_reg,
1468 .rs2_or_imm = rs2_or_imm,
1469 },
1470 },
1471 });
1472 },
1473 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}),
1474 else => unreachable,
1475 }
1476}
1477
13731478fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue {
13741479 if (typed_value.val.isUndef())
13751480 return MCValue{ .undef = {} };
src/arch/sparcv9/Emit.zig+31-55
......@@ -45,7 +45,6 @@ pub fn emitMir(
4545 for (mir_tags) |tag, index| {
4646 const inst = @intCast(u32, index);
4747 switch (tag) {
48 .dbg_arg => try emit.mirDbgArg(inst),
4948 .dbg_line => try emit.mirDbgLine(inst),
5049 .dbg_prologue_end => try emit.mirDebugPrologueEnd(),
5150 .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(),
......@@ -56,8 +55,7 @@ pub fn emitMir(
5655
5756 .call => @panic("TODO implement sparcv9 call"),
5857
59 .jmpl => @panic("TODO implement sparcv9 jmpl"),
60 .jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"),
58 .jmpl => try emit.mirArithmetic3Op(inst),
6159
6260 .ldub => try emit.mirArithmetic3Op(inst),
6361 .lduh => try emit.mirArithmetic3Op(inst),
......@@ -77,6 +75,11 @@ pub fn emitMir(
7775
7876 .sllx => @panic("TODO implement sparcv9 sllx"),
7977
78 .stb => try emit.mirArithmetic3Op(inst),
79 .sth => try emit.mirArithmetic3Op(inst),
80 .stw => try emit.mirArithmetic3Op(inst),
81 .stx => try emit.mirArithmetic3Op(inst),
82
8083 .sub => try emit.mirArithmetic3Op(inst),
8184
8285 .tcc => try emit.mirTrap(inst),
......@@ -88,17 +91,6 @@ pub fn deinit(emit: *Emit) void {
8891 emit.* = undefined;
8992}
9093
91fn mirDbgArg(emit: *Emit, inst: Mir.Inst.Index) !void {
92 const tag = emit.mir.instructions.items(.tag)[inst];
93 const dbg_arg_info = emit.mir.instructions.items(.data)[inst].dbg_arg_info;
94 _ = dbg_arg_info;
95
96 switch (tag) {
97 .dbg_arg => {}, // TODO try emit.genArgDbgInfo(dbg_arg_info.air_inst, dbg_arg_info.arg_index),
98 else => unreachable,
99 }
100}
101
10294fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
10395 const tag = emit.mir.instructions.items(.tag)[inst];
10496 const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column;
......@@ -109,22 +101,22 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void {
109101 }
110102}
111103
112fn mirDebugPrologueEnd(self: *Emit) !void {
113 switch (self.debug_output) {
104fn mirDebugPrologueEnd(emit: *Emit) !void {
105 switch (emit.debug_output) {
114106 .dwarf => |dbg_out| {
115107 try dbg_out.dbg_line.append(DW.LNS.set_prologue_end);
116 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
108 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
117109 },
118110 .plan9 => {},
119111 .none => {},
120112 }
121113}
122114
123fn mirDebugEpilogueBegin(self: *Emit) !void {
124 switch (self.debug_output) {
115fn mirDebugEpilogueBegin(emit: *Emit) !void {
116 switch (emit.debug_output) {
125117 .dwarf => |dbg_out| {
126118 try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin);
127 try self.dbgAdvancePCAndLine(self.prev_di_line, self.prev_di_column);
119 try emit.dbgAdvancePCAndLine(emit.prev_di_line, emit.prev_di_column);
128120 },
129121 .plan9 => {},
130122 .none => {},
......@@ -163,6 +155,7 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
163155 const imm = data.rs2_or_imm.imm;
164156 switch (tag) {
165157 .add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)),
158 .jmpl => try emit.writeInstruction(Instruction.jmpl(i13, rs1, imm, rd)),
166159 .ldub => try emit.writeInstruction(Instruction.ldub(i13, rs1, imm, rd)),
167160 .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)),
168161 .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)),
......@@ -170,6 +163,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
170163 .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)),
171164 .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)),
172165 .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)),
166 .stb => try emit.writeInstruction(Instruction.stb(i13, rs1, imm, rd)),
167 .sth => try emit.writeInstruction(Instruction.sth(i13, rs1, imm, rd)),
168 .stw => try emit.writeInstruction(Instruction.stw(i13, rs1, imm, rd)),
169 .stx => try emit.writeInstruction(Instruction.stx(i13, rs1, imm, rd)),
173170 .sub => try emit.writeInstruction(Instruction.sub(i13, rs1, imm, rd)),
174171 else => unreachable,
175172 }
......@@ -177,6 +174,7 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
177174 const rs2 = data.rs2_or_imm.rs2;
178175 switch (tag) {
179176 .add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)),
177 .jmpl => try emit.writeInstruction(Instruction.jmpl(Register, rs1, rs2, rd)),
180178 .ldub => try emit.writeInstruction(Instruction.ldub(Register, rs1, rs2, rd)),
181179 .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)),
182180 .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)),
......@@ -184,6 +182,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void {
184182 .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)),
185183 .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)),
186184 .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)),
185 .stb => try emit.writeInstruction(Instruction.stb(Register, rs1, rs2, rd)),
186 .sth => try emit.writeInstruction(Instruction.sth(Register, rs1, rs2, rd)),
187 .stw => try emit.writeInstruction(Instruction.stw(Register, rs1, rs2, rd)),
188 .stx => try emit.writeInstruction(Instruction.stx(Register, rs1, rs2, rd)),
187189 .sub => try emit.writeInstruction(Instruction.sub(Register, rs1, rs2, rd)),
188190 else => unreachable,
189191 }
......@@ -230,10 +232,10 @@ fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void {
230232
231233// Common helper functions
232234
233fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
234 const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line);
235 const delta_pc: usize = self.code.items.len - self.prev_di_pc;
236 switch (self.debug_output) {
235fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void {
236 const delta_line = @intCast(i32, line) - @intCast(i32, emit.prev_di_line);
237 const delta_pc: usize = emit.code.items.len - emit.prev_di_pc;
238 switch (emit.debug_output) {
237239 .dwarf => |dbg_out| {
238240 // TODO Look into using the DWARF special opcodes to compress this data.
239241 // It lets you emit single-byte opcodes that add different numbers to
......@@ -246,38 +248,12 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void {
246248 leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable;
247249 }
248250 dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy);
249 self.prev_di_pc = self.code.items.len;
250 self.prev_di_line = line;
251 self.prev_di_column = column;
252 self.prev_di_pc = self.code.items.len;
251 emit.prev_di_pc = emit.code.items.len;
252 emit.prev_di_line = line;
253 emit.prev_di_column = column;
254 emit.prev_di_pc = emit.code.items.len;
253255 },
254 .plan9 => |dbg_out| {
255 if (delta_pc <= 0) return; // only do this when the pc changes
256 // we have already checked the target in the linker to make sure it is compatable
257 const quant = @import("../../link/Plan9/aout.zig").getPCQuant(self.target.cpu.arch) catch unreachable;
258
259 // increasing the line number
260 try @import("../../link/Plan9.zig").changeLine(dbg_out.dbg_line, delta_line);
261 // increasing the pc
262 const d_pc_p9 = @intCast(i64, delta_pc) - quant;
263 if (d_pc_p9 > 0) {
264 // minus one because if its the last one, we want to leave space to change the line which is one quanta
265 try dbg_out.dbg_line.append(@intCast(u8, @divExact(d_pc_p9, quant) + 128) - quant);
266 if (dbg_out.pcop_change_index.*) |pci|
267 dbg_out.dbg_line.items[pci] += 1;
268 dbg_out.pcop_change_index.* = @intCast(u32, dbg_out.dbg_line.items.len - 1);
269 } else if (d_pc_p9 == 0) {
270 // we don't need to do anything, because adding the quant does it for us
271 } else unreachable;
272 if (dbg_out.start_line.* == null)
273 dbg_out.start_line.* = self.prev_di_line;
274 dbg_out.end_line.* = line;
275 // only do this if the pc changed
276 self.prev_di_line = line;
277 self.prev_di_column = column;
278 self.prev_di_pc = self.code.items.len;
279 },
280 .none => {},
256 else => {},
281257 }
282258}
283259
src/arch/sparcv9/Mir.zig+24-37
......@@ -28,8 +28,6 @@ pub const Inst = struct {
2828 data: Data,
2929
3030 pub const Tag = enum(u16) {
31 /// Pseudo-instruction: Argument
32 dbg_arg,
3331 /// Pseudo-instruction: End of prologue
3432 dbg_prologue_end,
3533 /// Pseudo-instruction: Beginning of epilogue
......@@ -41,27 +39,24 @@ pub const Inst = struct {
4139 // in The SPARC Architecture Manual, Version 9.
4240
4341 /// A.2 Add
44 /// Those uses the arithmetic_3op field.
42 /// This uses the arithmetic_3op field.
4543 // TODO add other operations.
4644 add,
4745
4846 /// A.7 Branch on Integer Condition Codes with Prediction (BPcc)
49 /// It uses the branch_predict field.
47 /// This uses the branch_predict field.
5048 bpcc,
5149
5250 /// A.8 Call and Link
53 /// It uses the branch_link field.
51 /// This uses the branch_link field.
5452 call,
5553
5654 /// A.24 Jump and Link
57 /// jmpl (far direct jump) uses the branch_link field,
58 /// while jmpl_i (indirect jump) uses the branch_link_indirect field.
59 /// Those two MIR instructions will be lowered into SPARCv9 jmpl instruction.
55 /// This uses the arithmetic_3op field.
6056 jmpl,
61 jmpl_i,
6257
6358 /// A.27 Load Integer
64 /// Those uses the arithmetic_3op field.
59 /// This uses the arithmetic_3op field.
6560 /// Note that the ldd variant of this instruction is deprecated, so do not emit
6661 /// it unless specifically requested (e.g. by inline assembly).
6762 // TODO add other operations.
......@@ -71,39 +66,49 @@ pub const Inst = struct {
7166 ldx,
7267
7368 /// A.31 Logical Operations
74 /// Those uses the arithmetic_3op field.
69 /// This uses the arithmetic_3op field.
7570 // TODO add other operations.
7671 @"or",
7772
7873 /// A.40 No Operation
79 /// It uses the nop field.
74 /// This uses the nop field.
8075 nop,
8176
8277 /// A.45 RETURN
83 /// It uses the arithmetic_2op field.
78 /// This uses the arithmetic_2op field.
8479 @"return",
8580
8681 /// A.46 SAVE and RESTORE
87 /// Those uses the arithmetic_3op field.
82 /// This uses the arithmetic_3op field.
8883 save,
8984 restore,
9085
9186 /// A.48 SETHI
92 /// It uses the sethi field.
87 /// This uses the sethi field.
9388 sethi,
9489
9590 /// A.49 Shift
96 /// Those uses the shift field.
91 /// This uses the shift field.
9792 // TODO add other operations.
9893 sllx,
9994
95 /// A.54 Store Integer
96 /// This uses the arithmetic_3op field.
97 /// Note that the std variant of this instruction is deprecated, so do not emit
98 /// it unless specifically requested (e.g. by inline assembly).
99 // TODO add other operations.
100 stb,
101 sth,
102 stw,
103 stx,
104
100105 /// A.56 Subtract
101 /// Those uses the arithmetic_3op field.
106 /// This uses the arithmetic_3op field.
102107 // TODO add other operations.
103108 sub,
104109
105110 /// A.61 Trap on Integer Condition Codes (Tcc)
106 /// It uses the trap field.
111 /// This uses the trap field.
107112 tcc,
108113 };
109114
......@@ -115,14 +120,6 @@ pub const Inst = struct {
115120 /// how to interpret the data within.
116121 // TODO this is a quick-n-dirty solution that needs to be cleaned up.
117122 pub const Data = union {
118 /// Debug info: argument
119 ///
120 /// Used by e.g. dbg_arg
121 dbg_arg_info: struct {
122 air_inst: Air.Inst.Index,
123 arg_index: usize,
124 },
125
126123 /// Debug info: line and column
127124 ///
128125 /// Used by e.g. dbg_line
......@@ -167,13 +164,6 @@ pub const Inst = struct {
167164 link: Register = .o7,
168165 },
169166
170 /// Indirect branch and link (always unconditional).
171 /// Used by e.g. jmpl_i
172 branch_link_indirect: struct {
173 reg: Register,
174 link: Register = .o7,
175 },
176
177167 /// Branch with prediction.
178168 /// Used by e.g. bpcc
179169 branch_predict: struct {
......@@ -234,10 +224,7 @@ pub const Inst = struct {
234224 // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks.
235225 comptime {
236226 if (builtin.mode != .Debug) {
237 // TODO clean up the definition of Data before enabling this.
238 // I'll do that after the PoC backend can produce usable binaries.
239
240 // assert(@sizeOf(Data) == 8);
227 assert(@sizeOf(Data) == 8);
241228 }
242229 }
243230};
src/arch/sparcv9/abi.zig+12
......@@ -1,6 +1,18 @@
11const bits = @import("bits.zig");
22const Register = bits.Register;
33
4// SPARCv9 stack constants.
5// See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1.
6
7// On SPARCv9, %sp points to top of stack + stack bias,
8// and %fp points to top of previous frame + stack bias.
9pub const stack_bias = 2047;
10
11// The first 176 bytes of the stack is reserved for register saving purposes.
12// SPARCv9 requires to reserve space in the stack for the first six arguments,
13// even though they are usually passed in registers.
14pub const stack_save_area = 176;
15
416// There are no callee-preserved registers since the windowing
517// mechanism already takes care of them.
618// We still need to preserve %o0-%o5, %g1, %g4, and %g5 before calling
src/arch/sparcv9/bits.zig+45-3
......@@ -271,6 +271,8 @@ pub const Instruction = union(enum) {
271271 rd: u5,
272272 op3: u6,
273273 rs1: u5,
274 // See Errata 58 of SPARCv9 specification
275 // https://sparc.org/errata-for-v9/#58
274276 i: u1 = 0b1,
275277 reserved: u8 = 0b00000000,
276278 rs2: u5,
......@@ -977,10 +979,10 @@ pub const Instruction = union(enum) {
977979 };
978980 }
979981
980 pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
982 pub fn jmpl(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
981983 return switch (s2) {
982 Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),
983 i13 => format3b(0b10, 0b00_0010, rs1, rs2, rd),
984 Register => format3a(0b10, 0b11_1000, rs1, rs2, rd),
985 i13 => format3b(0b10, 0b11_1000, rs1, rs2, rd),
984986 else => unreachable,
985987 };
986988 }
......@@ -1017,6 +1019,14 @@ pub const Instruction = union(enum) {
10171019 };
10181020 }
10191021
1022 pub fn @"or"(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1023 return switch (s2) {
1024 Register => format3a(0b10, 0b00_0010, rs1, rs2, rd),
1025 i13 => format3b(0b10, 0b00_0010, rs1, rs2, rd),
1026 else => unreachable,
1027 };
1028 }
1029
10201030 pub fn nop() Instruction {
10211031 return sethi(0, .g0);
10221032 }
......@@ -1049,6 +1059,38 @@ pub const Instruction = union(enum) {
10491059 return format2a(0b100, imm, rd);
10501060 }
10511061
1062 pub fn stb(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1063 return switch (s2) {
1064 Register => format3a(0b11, 0b00_0101, rs1, rs2, rd),
1065 i13 => format3b(0b11, 0b00_0101, rs1, rs2, rd),
1066 else => unreachable,
1067 };
1068 }
1069
1070 pub fn sth(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1071 return switch (s2) {
1072 Register => format3a(0b11, 0b00_0110, rs1, rs2, rd),
1073 i13 => format3b(0b11, 0b00_0110, rs1, rs2, rd),
1074 else => unreachable,
1075 };
1076 }
1077
1078 pub fn stw(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1079 return switch (s2) {
1080 Register => format3a(0b11, 0b00_0100, rs1, rs2, rd),
1081 i13 => format3b(0b11, 0b00_0100, rs1, rs2, rd),
1082 else => unreachable,
1083 };
1084 }
1085
1086 pub fn stx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
1087 return switch (s2) {
1088 Register => format3a(0b11, 0b00_1110, rs1, rs2, rd),
1089 i13 => format3b(0b11, 0b00_1110, rs1, rs2, rd),
1090 else => unreachable,
1091 };
1092 }
1093
10521094 pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction {
10531095 return switch (s2) {
10541096 Register => format3a(0b10, 0b00_0100, rs1, rs2, rd),
test/cases/sparcv9-linux/hello_world.zig+6-11
......@@ -1,23 +1,18 @@
11const msg = "Hello, World!\n";
22
3pub export fn _start() noreturn {
3fn length() usize {
4 return msg.len;
5}
6
7pub fn main() void {
48 asm volatile ("ta 0x6d"
59 :
610 : [number] "{g1}" (4),
711 [arg1] "{o0}" (1),
812 [arg2] "{o1}" (@ptrToInt(msg)),
9 [arg3] "{o2}" (msg.len),
10 : "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "memory"
11 );
12
13 asm volatile ("ta 0x6d"
14 :
15 : [number] "{g1}" (1),
16 [arg1] "{o0}" (0),
13 [arg3] "{o2}" (length()),
1714 : "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "memory"
1815 );
19
20 unreachable;
2116}
2217
2318// run