| author | |
| committer | |
| log | 09d2b6c4e1b2edd1d011ef4f947cdd835313a2e5 |
| tree | a0d9836cd8d0d81ec5e441b80938f3bf3a99e53f |
| parent | 13d1798ea0c2665f09508ac505259e761f8b4e22 |
| parent | 9985699943edb4bf4f3dae9b57e0e2017c23c4bf |
| signature | Signed by PGP key 4AEE18F83AFDEB23 |
7 files changed, 285 insertions(+), 167 deletions(-)
lib/std/zig/system/NativeTargetInfo.zig+1| ... | @@ -931,6 +931,7 @@ pub fn getExternalExecutor( | ... | @@ -931,6 +931,7 @@ pub fn getExternalExecutor( |
| 931 | .riscv64 => Executor{ .qemu = "qemu-riscv64" }, | 931 | .riscv64 => Executor{ .qemu = "qemu-riscv64" }, |
| 932 | .s390x => Executor{ .qemu = "qemu-s390x" }, | 932 | .s390x => Executor{ .qemu = "qemu-s390x" }, |
| 933 | .sparc => Executor{ .qemu = "qemu-sparc" }, | 933 | .sparc => Executor{ .qemu = "qemu-sparc" }, |
| 934 | .sparcv9 => Executor{ .qemu = "qemu-sparc64" }, | ||
| 934 | .x86_64 => Executor{ .qemu = "qemu-x86_64" }, | 935 | .x86_64 => Executor{ .qemu = "qemu-x86_64" }, |
| 935 | else => return bad_result, | 936 | else => return bad_result, |
| 936 | }; | 937 | }; |
src/arch/sparcv9/CodeGen.zig+166-61| ... | @@ -1,5 +1,7 @@ | ... | @@ -1,5 +1,7 @@ |
| 1 | //! SPARCv9 codegen. | 1 | //! SPARCv9 codegen. |
| 2 | //! This lowers AIR into MIR. | 2 | //! 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. | ||
| 3 | const std = @import("std"); | 5 | const std = @import("std"); |
| 4 | const assert = std.debug.assert; | 6 | const assert = std.debug.assert; |
| 5 | const log = std.log.scoped(.codegen); | 7 | const log = std.log.scoped(.codegen); |
| ... | @@ -338,16 +340,15 @@ fn gen(self: *Self) !void { | ... | @@ -338,16 +340,15 @@ fn gen(self: *Self) !void { |
| 338 | if (cc != .Naked) { | 340 | if (cc != .Naked) { |
| 339 | // TODO Finish function prologue and epilogue for sparcv9. | 341 | // TODO Finish function prologue and epilogue for sparcv9. |
| 340 | 342 | ||
| 341 | // TODO Backpatch stack offset | 343 | // save %sp, stack_save_area, %sp |
| 342 | // save %sp, -176, %sp | 344 | const save_inst = try self.addInst(.{ |
| 343 | _ = try self.addInst(.{ | ||
| 344 | .tag = .save, | 345 | .tag = .save, |
| 345 | .data = .{ | 346 | .data = .{ |
| 346 | .arithmetic_3op = .{ | 347 | .arithmetic_3op = .{ |
| 347 | .is_imm = true, | 348 | .is_imm = true, |
| 348 | .rd = .sp, | 349 | .rd = .sp, |
| 349 | .rs1 = .sp, | 350 | .rs1 = .sp, |
| 350 | .rs2_or_imm = .{ .imm = -176 }, | 351 | .rs2_or_imm = .{ .imm = -abi.stack_save_area }, |
| 351 | }, | 352 | }, |
| 352 | }, | 353 | }, |
| 353 | }); | 354 | }); |
| ... | @@ -380,6 +381,28 @@ fn gen(self: *Self) !void { | ... | @@ -380,6 +381,28 @@ fn gen(self: *Self) !void { |
| 380 | return self.fail("TODO add branches in sparcv9", .{}); | 381 | return self.fail("TODO add branches in sparcv9", .{}); |
| 381 | } | 382 | } |
| 382 | 383 | ||
| 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 | |||
| 383 | // return %i7 + 8 | 406 | // return %i7 + 8 |
| 384 | _ = try self.addInst(.{ | 407 | _ = try self.addInst(.{ |
| 385 | .tag = .@"return", | 408 | .tag = .@"return", |
| ... | @@ -392,7 +415,11 @@ fn gen(self: *Self) !void { | ... | @@ -392,7 +415,11 @@ fn gen(self: *Self) !void { |
| 392 | }, | 415 | }, |
| 393 | }); | 416 | }); |
| 394 | 417 | ||
| 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 | ||
| 396 | // nop | 423 | // nop |
| 397 | _ = try self.addInst(.{ | 424 | _ = try self.addInst(.{ |
| 398 | .tag = .nop, | 425 | .tag = .nop, |
| ... | @@ -753,15 +780,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -753,15 +780,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { |
| 753 | // TODO Copy registers to the stack | 780 | // TODO Copy registers to the stack |
| 754 | const mcv = result; | 781 | const mcv = result; |
| 755 | 782 | ||
| 756 | _ = try self.addInst(.{ | 783 | try self.genArgDbgInfo(inst, mcv, @intCast(u32, arg_index)); |
| 757 | .tag = .dbg_arg, | ||
| 758 | .data = .{ | ||
| 759 | .dbg_arg_info = .{ | ||
| 760 | .air_inst = inst, | ||
| 761 | .arg_index = arg_index, | ||
| 762 | }, | ||
| 763 | }, | ||
| 764 | }); | ||
| 765 | 784 | ||
| 766 | if (self.liveness.isUnused(inst)) | 785 | if (self.liveness.isUnused(inst)) |
| 767 | return self.finishAirBookkeeping(); | 786 | return self.finishAirBookkeeping(); |
| ... | @@ -884,7 +903,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -884,7 +903,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 884 | 903 | ||
| 885 | _ = try self.addInst(.{ | 904 | _ = try self.addInst(.{ |
| 886 | .tag = .jmpl, | 905 | .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 = {} }, | ||
| 888 | }); | 920 | }); |
| 889 | } else if (func_value.castTag(.extern_fn)) |_| { | 921 | } else if (func_value.castTag(.extern_fn)) |_| { |
| 890 | return self.fail("TODO implement calling extern functions", .{}); | 922 | return self.fail("TODO implement calling extern functions", .{}); |
| ... | @@ -899,7 +931,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. | ... | @@ -899,7 +931,20 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallOptions. |
| 899 | 931 | ||
| 900 | _ = try self.addInst(.{ | 932 | _ = try self.addInst(.{ |
| 901 | .tag = .jmpl, | 933 | .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 = {} }, | ||
| 903 | }); | 948 | }); |
| 904 | } | 949 | } |
| 905 | 950 | ||
| ... | @@ -995,11 +1040,29 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { | ... | @@ -995,11 +1040,29 @@ fn airSwitch(self: *Self, inst: Air.Inst.Index) !void { |
| 995 | 1040 | ||
| 996 | // Common helper functions | 1041 | // Common helper functions |
| 997 | 1042 | ||
| 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. | ||
| 1045 | fn 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 | |||
| 998 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { | 1063 | fn addInst(self: *Self, inst: Mir.Inst) error{OutOfMemory}!Mir.Inst.Index { |
| 999 | const gpa = self.gpa; | 1064 | const gpa = self.gpa; |
| 1000 | |||
| 1001 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); | 1065 | try self.mir_instructions.ensureUnusedCapacity(gpa, 1); |
| 1002 | |||
| 1003 | const result_index = @intCast(Air.Inst.Index, self.mir_instructions.len); | 1066 | const result_index = @intCast(Air.Inst.Index, self.mir_instructions.len); |
| 1004 | self.mir_instructions.appendAssumeCapacity(inst); | 1067 | self.mir_instructions.appendAssumeCapacity(inst); |
| 1005 | return result_index; | 1068 | return result_index; |
| ... | @@ -1125,6 +1188,40 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live | ... | @@ -1125,6 +1188,40 @@ fn finishAir(self: *Self, inst: Air.Inst.Index, result: MCValue, operands: [Live |
| 1125 | self.finishAirBookkeeping(); | 1188 | self.finishAirBookkeeping(); |
| 1126 | } | 1189 | } |
| 1127 | 1190 | ||
| 1191 | fn 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 | |||
| 1128 | fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void { | 1225 | fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void { |
| 1129 | assert(off_type == Register or off_type == i13); | 1226 | assert(off_type == Register or off_type == i13); |
| 1130 | 1227 | ||
| ... | @@ -1132,48 +1229,17 @@ fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_ty | ... | @@ -1132,48 +1229,17 @@ fn genLoad(self: *Self, value_reg: Register, addr_reg: Register, comptime off_ty |
| 1132 | const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off }; | 1229 | const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off }; |
| 1133 | 1230 | ||
| 1134 | switch (abi_size) { | 1231 | switch (abi_size) { |
| 1135 | 1 => { | 1232 | 1, 2, 4, 8 => { |
| 1136 | _ = try self.addInst(.{ | 1233 | const tag: Mir.Inst.Tag = switch (abi_size) { |
| 1137 | .tag = .ldub, | 1234 | 1 => .ldub, |
| 1138 | .data = .{ | 1235 | 2 => .lduh, |
| 1139 | .arithmetic_3op = .{ | 1236 | 4 => .lduw, |
| 1140 | .is_imm = is_imm, | 1237 | 8 => .ldx, |
| 1141 | .rd = value_reg, | 1238 | else => unreachable, // unexpected abi size |
| 1142 | .rs1 = addr_reg, | 1239 | }; |
| 1143 | .rs2_or_imm = rs2_or_imm, | 1240 | |
| 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 => { | ||
| 1175 | _ = try self.addInst(.{ | 1241 | _ = try self.addInst(.{ |
| 1176 | .tag = .ldx, | 1242 | .tag = tag, |
| 1177 | .data = .{ | 1243 | .data = .{ |
| 1178 | .arithmetic_3op = .{ | 1244 | .arithmetic_3op = .{ |
| 1179 | .is_imm = is_imm, | 1245 | .is_imm = is_imm, |
| ... | @@ -1335,7 +1401,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void | ... | @@ -1335,7 +1401,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void |
| 1335 | try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*)); | 1401 | try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*)); |
| 1336 | }, | 1402 | }, |
| 1337 | .stack_offset => |off| { | 1403 | .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 | ||
| 1339 | return self.fail("TODO larger stack offsets", .{}); | 1406 | return self.fail("TODO larger stack offsets", .{}); |
| 1340 | try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); | 1407 | try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); |
| 1341 | }, | 1408 | }, |
| ... | @@ -1365,11 +1432,49 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro | ... | @@ -1365,11 +1432,49 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro |
| 1365 | const reg = try self.copyToTmpRegister(ty, mcv); | 1432 | const reg = try self.copyToTmpRegister(ty, mcv); |
| 1366 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); | 1433 | return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); |
| 1367 | }, | 1434 | }, |
| 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 | }, | ||
| 1369 | .memory, .stack_offset => return self.fail("TODO implement memcpy", .{}), | 1441 | .memory, .stack_offset => return self.fail("TODO implement memcpy", .{}), |
| 1370 | } | 1442 | } |
| 1371 | } | 1443 | } |
| 1372 | 1444 | ||
| 1445 | fn 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 | |||
| 1373 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { | 1478 | fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { |
| 1374 | if (typed_value.val.isUndef()) | 1479 | if (typed_value.val.isUndef()) |
| 1375 | return MCValue{ .undef = {} }; | 1480 | return MCValue{ .undef = {} }; |
src/arch/sparcv9/Emit.zig+31-55| ... | @@ -45,7 +45,6 @@ pub fn emitMir( | ... | @@ -45,7 +45,6 @@ pub fn emitMir( |
| 45 | for (mir_tags) |tag, index| { | 45 | for (mir_tags) |tag, index| { |
| 46 | const inst = @intCast(u32, index); | 46 | const inst = @intCast(u32, index); |
| 47 | switch (tag) { | 47 | switch (tag) { |
| 48 | .dbg_arg => try emit.mirDbgArg(inst), | ||
| 49 | .dbg_line => try emit.mirDbgLine(inst), | 48 | .dbg_line => try emit.mirDbgLine(inst), |
| 50 | .dbg_prologue_end => try emit.mirDebugPrologueEnd(), | 49 | .dbg_prologue_end => try emit.mirDebugPrologueEnd(), |
| 51 | .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(), | 50 | .dbg_epilogue_begin => try emit.mirDebugEpilogueBegin(), |
| ... | @@ -56,8 +55,7 @@ pub fn emitMir( | ... | @@ -56,8 +55,7 @@ pub fn emitMir( |
| 56 | 55 | ||
| 57 | .call => @panic("TODO implement sparcv9 call"), | 56 | .call => @panic("TODO implement sparcv9 call"), |
| 58 | 57 | ||
| 59 | .jmpl => @panic("TODO implement sparcv9 jmpl"), | 58 | .jmpl => try emit.mirArithmetic3Op(inst), |
| 60 | .jmpl_i => @panic("TODO implement sparcv9 jmpl to reg"), | ||
| 61 | 59 | ||
| 62 | .ldub => try emit.mirArithmetic3Op(inst), | 60 | .ldub => try emit.mirArithmetic3Op(inst), |
| 63 | .lduh => try emit.mirArithmetic3Op(inst), | 61 | .lduh => try emit.mirArithmetic3Op(inst), |
| ... | @@ -77,6 +75,11 @@ pub fn emitMir( | ... | @@ -77,6 +75,11 @@ pub fn emitMir( |
| 77 | 75 | ||
| 78 | .sllx => @panic("TODO implement sparcv9 sllx"), | 76 | .sllx => @panic("TODO implement sparcv9 sllx"), |
| 79 | 77 | ||
| 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 | |||
| 80 | .sub => try emit.mirArithmetic3Op(inst), | 83 | .sub => try emit.mirArithmetic3Op(inst), |
| 81 | 84 | ||
| 82 | .tcc => try emit.mirTrap(inst), | 85 | .tcc => try emit.mirTrap(inst), |
| ... | @@ -88,17 +91,6 @@ pub fn deinit(emit: *Emit) void { | ... | @@ -88,17 +91,6 @@ pub fn deinit(emit: *Emit) void { |
| 88 | emit.* = undefined; | 91 | emit.* = undefined; |
| 89 | } | 92 | } |
| 90 | 93 | ||
| 91 | fn 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 | |||
| 102 | fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { | 94 | fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 103 | const tag = emit.mir.instructions.items(.tag)[inst]; | 95 | const tag = emit.mir.instructions.items(.tag)[inst]; |
| 104 | const dbg_line_column = emit.mir.instructions.items(.data)[inst].dbg_line_column; | 96 | 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 { | ... | @@ -109,22 +101,22 @@ fn mirDbgLine(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 109 | } | 101 | } |
| 110 | } | 102 | } |
| 111 | 103 | ||
| 112 | fn mirDebugPrologueEnd(self: *Emit) !void { | 104 | fn mirDebugPrologueEnd(emit: *Emit) !void { |
| 113 | switch (self.debug_output) { | 105 | switch (emit.debug_output) { |
| 114 | .dwarf => |dbg_out| { | 106 | .dwarf => |dbg_out| { |
| 115 | try dbg_out.dbg_line.append(DW.LNS.set_prologue_end); | 107 | 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); |
| 117 | }, | 109 | }, |
| 118 | .plan9 => {}, | 110 | .plan9 => {}, |
| 119 | .none => {}, | 111 | .none => {}, |
| 120 | } | 112 | } |
| 121 | } | 113 | } |
| 122 | 114 | ||
| 123 | fn mirDebugEpilogueBegin(self: *Emit) !void { | 115 | fn mirDebugEpilogueBegin(emit: *Emit) !void { |
| 124 | switch (self.debug_output) { | 116 | switch (emit.debug_output) { |
| 125 | .dwarf => |dbg_out| { | 117 | .dwarf => |dbg_out| { |
| 126 | try dbg_out.dbg_line.append(DW.LNS.set_epilogue_begin); | 118 | 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); |
| 128 | }, | 120 | }, |
| 129 | .plan9 => {}, | 121 | .plan9 => {}, |
| 130 | .none => {}, | 122 | .none => {}, |
| ... | @@ -163,6 +155,7 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -163,6 +155,7 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 163 | const imm = data.rs2_or_imm.imm; | 155 | const imm = data.rs2_or_imm.imm; |
| 164 | switch (tag) { | 156 | switch (tag) { |
| 165 | .add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)), | 157 | .add => try emit.writeInstruction(Instruction.add(i13, rs1, imm, rd)), |
| 158 | .jmpl => try emit.writeInstruction(Instruction.jmpl(i13, rs1, imm, rd)), | ||
| 166 | .ldub => try emit.writeInstruction(Instruction.ldub(i13, rs1, imm, rd)), | 159 | .ldub => try emit.writeInstruction(Instruction.ldub(i13, rs1, imm, rd)), |
| 167 | .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)), | 160 | .lduh => try emit.writeInstruction(Instruction.lduh(i13, rs1, imm, rd)), |
| 168 | .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)), | 161 | .lduw => try emit.writeInstruction(Instruction.lduw(i13, rs1, imm, rd)), |
| ... | @@ -170,6 +163,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -170,6 +163,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 170 | .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)), | 163 | .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)), |
| 171 | .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)), | 164 | .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)), |
| 172 | .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)), | 165 | .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)), | ||
| 173 | .sub => try emit.writeInstruction(Instruction.sub(i13, rs1, imm, rd)), | 170 | .sub => try emit.writeInstruction(Instruction.sub(i13, rs1, imm, rd)), |
| 174 | else => unreachable, | 171 | else => unreachable, |
| 175 | } | 172 | } |
| ... | @@ -177,6 +174,7 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -177,6 +174,7 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 177 | const rs2 = data.rs2_or_imm.rs2; | 174 | const rs2 = data.rs2_or_imm.rs2; |
| 178 | switch (tag) { | 175 | switch (tag) { |
| 179 | .add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)), | 176 | .add => try emit.writeInstruction(Instruction.add(Register, rs1, rs2, rd)), |
| 177 | .jmpl => try emit.writeInstruction(Instruction.jmpl(Register, rs1, rs2, rd)), | ||
| 180 | .ldub => try emit.writeInstruction(Instruction.ldub(Register, rs1, rs2, rd)), | 178 | .ldub => try emit.writeInstruction(Instruction.ldub(Register, rs1, rs2, rd)), |
| 181 | .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)), | 179 | .lduh => try emit.writeInstruction(Instruction.lduh(Register, rs1, rs2, rd)), |
| 182 | .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)), | 180 | .lduw => try emit.writeInstruction(Instruction.lduw(Register, rs1, rs2, rd)), |
| ... | @@ -184,6 +182,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -184,6 +182,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 184 | .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)), | 182 | .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)), |
| 185 | .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)), | 183 | .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)), |
| 186 | .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)), | 184 | .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)), | ||
| 187 | .sub => try emit.writeInstruction(Instruction.sub(Register, rs1, rs2, rd)), | 189 | .sub => try emit.writeInstruction(Instruction.sub(Register, rs1, rs2, rd)), |
| 188 | else => unreachable, | 190 | else => unreachable, |
| 189 | } | 191 | } |
| ... | @@ -230,10 +232,10 @@ fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void { | ... | @@ -230,10 +232,10 @@ fn mirTrap(emit: *Emit, inst: Mir.Inst.Index) !void { |
| 230 | 232 | ||
| 231 | // Common helper functions | 233 | // Common helper functions |
| 232 | 234 | ||
| 233 | fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { | 235 | fn dbgAdvancePCAndLine(emit: *Emit, line: u32, column: u32) !void { |
| 234 | const delta_line = @intCast(i32, line) - @intCast(i32, self.prev_di_line); | 236 | const delta_line = @intCast(i32, line) - @intCast(i32, emit.prev_di_line); |
| 235 | const delta_pc: usize = self.code.items.len - self.prev_di_pc; | 237 | const delta_pc: usize = emit.code.items.len - emit.prev_di_pc; |
| 236 | switch (self.debug_output) { | 238 | switch (emit.debug_output) { |
| 237 | .dwarf => |dbg_out| { | 239 | .dwarf => |dbg_out| { |
| 238 | // TODO Look into using the DWARF special opcodes to compress this data. | 240 | // TODO Look into using the DWARF special opcodes to compress this data. |
| 239 | // It lets you emit single-byte opcodes that add different numbers to | 241 | // 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 { | ... | @@ -246,38 +248,12 @@ fn dbgAdvancePCAndLine(self: *Emit, line: u32, column: u32) !void { |
| 246 | leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; | 248 | leb128.writeILEB128(dbg_out.dbg_line.writer(), delta_line) catch unreachable; |
| 247 | } | 249 | } |
| 248 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy); | 250 | dbg_out.dbg_line.appendAssumeCapacity(DW.LNS.copy); |
| 249 | self.prev_di_pc = self.code.items.len; | 251 | emit.prev_di_pc = emit.code.items.len; |
| 250 | self.prev_di_line = line; | 252 | emit.prev_di_line = line; |
| 251 | self.prev_di_column = column; | 253 | emit.prev_di_column = column; |
| 252 | self.prev_di_pc = self.code.items.len; | 254 | emit.prev_di_pc = emit.code.items.len; |
| 253 | }, | 255 | }, |
| 254 | .plan9 => |dbg_out| { | 256 | else => {}, |
| 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 => {}, | ||
| 281 | } | 257 | } |
| 282 | } | 258 | } |
| 283 | 259 |
src/arch/sparcv9/Mir.zig+24-37| ... | @@ -28,8 +28,6 @@ pub const Inst = struct { | ... | @@ -28,8 +28,6 @@ pub const Inst = struct { |
| 28 | data: Data, | 28 | data: Data, |
| 29 | 29 | ||
| 30 | pub const Tag = enum(u16) { | 30 | pub const Tag = enum(u16) { |
| 31 | /// Pseudo-instruction: Argument | ||
| 32 | dbg_arg, | ||
| 33 | /// Pseudo-instruction: End of prologue | 31 | /// Pseudo-instruction: End of prologue |
| 34 | dbg_prologue_end, | 32 | dbg_prologue_end, |
| 35 | /// Pseudo-instruction: Beginning of epilogue | 33 | /// Pseudo-instruction: Beginning of epilogue |
| ... | @@ -41,27 +39,24 @@ pub const Inst = struct { | ... | @@ -41,27 +39,24 @@ pub const Inst = struct { |
| 41 | // in The SPARC Architecture Manual, Version 9. | 39 | // in The SPARC Architecture Manual, Version 9. |
| 42 | 40 | ||
| 43 | /// A.2 Add | 41 | /// A.2 Add |
| 44 | /// Those uses the arithmetic_3op field. | 42 | /// This uses the arithmetic_3op field. |
| 45 | // TODO add other operations. | 43 | // TODO add other operations. |
| 46 | add, | 44 | add, |
| 47 | 45 | ||
| 48 | /// A.7 Branch on Integer Condition Codes with Prediction (BPcc) | 46 | /// A.7 Branch on Integer Condition Codes with Prediction (BPcc) |
| 49 | /// It uses the branch_predict field. | 47 | /// This uses the branch_predict field. |
| 50 | bpcc, | 48 | bpcc, |
| 51 | 49 | ||
| 52 | /// A.8 Call and Link | 50 | /// A.8 Call and Link |
| 53 | /// It uses the branch_link field. | 51 | /// This uses the branch_link field. |
| 54 | call, | 52 | call, |
| 55 | 53 | ||
| 56 | /// A.24 Jump and Link | 54 | /// A.24 Jump and Link |
| 57 | /// jmpl (far direct jump) uses the branch_link field, | 55 | /// This uses the arithmetic_3op 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. | ||
| 60 | jmpl, | 56 | jmpl, |
| 61 | jmpl_i, | ||
| 62 | 57 | ||
| 63 | /// A.27 Load Integer | 58 | /// A.27 Load Integer |
| 64 | /// Those uses the arithmetic_3op field. | 59 | /// This uses the arithmetic_3op field. |
| 65 | /// Note that the ldd variant of this instruction is deprecated, so do not emit | 60 | /// Note that the ldd variant of this instruction is deprecated, so do not emit |
| 66 | /// it unless specifically requested (e.g. by inline assembly). | 61 | /// it unless specifically requested (e.g. by inline assembly). |
| 67 | // TODO add other operations. | 62 | // TODO add other operations. |
| ... | @@ -71,39 +66,49 @@ pub const Inst = struct { | ... | @@ -71,39 +66,49 @@ pub const Inst = struct { |
| 71 | ldx, | 66 | ldx, |
| 72 | 67 | ||
| 73 | /// A.31 Logical Operations | 68 | /// A.31 Logical Operations |
| 74 | /// Those uses the arithmetic_3op field. | 69 | /// This uses the arithmetic_3op field. |
| 75 | // TODO add other operations. | 70 | // TODO add other operations. |
| 76 | @"or", | 71 | @"or", |
| 77 | 72 | ||
| 78 | /// A.40 No Operation | 73 | /// A.40 No Operation |
| 79 | /// It uses the nop field. | 74 | /// This uses the nop field. |
| 80 | nop, | 75 | nop, |
| 81 | 76 | ||
| 82 | /// A.45 RETURN | 77 | /// A.45 RETURN |
| 83 | /// It uses the arithmetic_2op field. | 78 | /// This uses the arithmetic_2op field. |
| 84 | @"return", | 79 | @"return", |
| 85 | 80 | ||
| 86 | /// A.46 SAVE and RESTORE | 81 | /// A.46 SAVE and RESTORE |
| 87 | /// Those uses the arithmetic_3op field. | 82 | /// This uses the arithmetic_3op field. |
| 88 | save, | 83 | save, |
| 89 | restore, | 84 | restore, |
| 90 | 85 | ||
| 91 | /// A.48 SETHI | 86 | /// A.48 SETHI |
| 92 | /// It uses the sethi field. | 87 | /// This uses the sethi field. |
| 93 | sethi, | 88 | sethi, |
| 94 | 89 | ||
| 95 | /// A.49 Shift | 90 | /// A.49 Shift |
| 96 | /// Those uses the shift field. | 91 | /// This uses the shift field. |
| 97 | // TODO add other operations. | 92 | // TODO add other operations. |
| 98 | sllx, | 93 | sllx, |
| 99 | 94 | ||
| 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 | |||
| 100 | /// A.56 Subtract | 105 | /// A.56 Subtract |
| 101 | /// Those uses the arithmetic_3op field. | 106 | /// This uses the arithmetic_3op field. |
| 102 | // TODO add other operations. | 107 | // TODO add other operations. |
| 103 | sub, | 108 | sub, |
| 104 | 109 | ||
| 105 | /// A.61 Trap on Integer Condition Codes (Tcc) | 110 | /// A.61 Trap on Integer Condition Codes (Tcc) |
| 106 | /// It uses the trap field. | 111 | /// This uses the trap field. |
| 107 | tcc, | 112 | tcc, |
| 108 | }; | 113 | }; |
| 109 | 114 | ||
| ... | @@ -115,14 +120,6 @@ pub const Inst = struct { | ... | @@ -115,14 +120,6 @@ pub const Inst = struct { |
| 115 | /// how to interpret the data within. | 120 | /// how to interpret the data within. |
| 116 | // TODO this is a quick-n-dirty solution that needs to be cleaned up. | 121 | // TODO this is a quick-n-dirty solution that needs to be cleaned up. |
| 117 | pub const Data = union { | 122 | 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 | |||
| 126 | /// Debug info: line and column | 123 | /// Debug info: line and column |
| 127 | /// | 124 | /// |
| 128 | /// Used by e.g. dbg_line | 125 | /// Used by e.g. dbg_line |
| ... | @@ -167,13 +164,6 @@ pub const Inst = struct { | ... | @@ -167,13 +164,6 @@ pub const Inst = struct { |
| 167 | link: Register = .o7, | 164 | link: Register = .o7, |
| 168 | }, | 165 | }, |
| 169 | 166 | ||
| 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 | |||
| 177 | /// Branch with prediction. | 167 | /// Branch with prediction. |
| 178 | /// Used by e.g. bpcc | 168 | /// Used by e.g. bpcc |
| 179 | branch_predict: struct { | 169 | branch_predict: struct { |
| ... | @@ -234,10 +224,7 @@ pub const Inst = struct { | ... | @@ -234,10 +224,7 @@ pub const Inst = struct { |
| 234 | // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks. | 224 | // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks. |
| 235 | comptime { | 225 | comptime { |
| 236 | if (builtin.mode != .Debug) { | 226 | if (builtin.mode != .Debug) { |
| 237 | // TODO clean up the definition of Data before enabling this. | 227 | assert(@sizeOf(Data) == 8); |
| 238 | // I'll do that after the PoC backend can produce usable binaries. | ||
| 239 | |||
| 240 | // assert(@sizeOf(Data) == 8); | ||
| 241 | } | 228 | } |
| 242 | } | 229 | } |
| 243 | }; | 230 | }; |
src/arch/sparcv9/abi.zig+12| ... | @@ -1,6 +1,18 @@ | ... | @@ -1,6 +1,18 @@ |
| 1 | const bits = @import("bits.zig"); | 1 | const bits = @import("bits.zig"); |
| 2 | const Register = bits.Register; | 2 | const Register = bits.Register; |
| 3 | 3 | ||
| 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. | ||
| 9 | pub 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. | ||
| 14 | pub const stack_save_area = 176; | ||
| 15 | |||
| 4 | // There are no callee-preserved registers since the windowing | 16 | // There are no callee-preserved registers since the windowing |
| 5 | // mechanism already takes care of them. | 17 | // mechanism already takes care of them. |
| 6 | // We still need to preserve %o0-%o5, %g1, %g4, and %g5 before calling | 18 | // 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) { | ... | @@ -271,6 +271,8 @@ pub const Instruction = union(enum) { |
| 271 | rd: u5, | 271 | rd: u5, |
| 272 | op3: u6, | 272 | op3: u6, |
| 273 | rs1: u5, | 273 | rs1: u5, |
| 274 | // See Errata 58 of SPARCv9 specification | ||
| 275 | // https://sparc.org/errata-for-v9/#58 | ||
| 274 | i: u1 = 0b1, | 276 | i: u1 = 0b1, |
| 275 | reserved: u8 = 0b00000000, | 277 | reserved: u8 = 0b00000000, |
| 276 | rs2: u5, | 278 | rs2: u5, |
| ... | @@ -977,10 +979,10 @@ pub const Instruction = union(enum) { | ... | @@ -977,10 +979,10 @@ pub const Instruction = union(enum) { |
| 977 | }; | 979 | }; |
| 978 | } | 980 | } |
| 979 | 981 | ||
| 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 { |
| 981 | return switch (s2) { | 983 | return switch (s2) { |
| 982 | Register => format3a(0b10, 0b00_0010, rs1, rs2, rd), | 984 | Register => format3a(0b10, 0b11_1000, rs1, rs2, rd), |
| 983 | i13 => format3b(0b10, 0b00_0010, rs1, rs2, rd), | 985 | i13 => format3b(0b10, 0b11_1000, rs1, rs2, rd), |
| 984 | else => unreachable, | 986 | else => unreachable, |
| 985 | }; | 987 | }; |
| 986 | } | 988 | } |
| ... | @@ -1017,6 +1019,14 @@ pub const Instruction = union(enum) { | ... | @@ -1017,6 +1019,14 @@ pub const Instruction = union(enum) { |
| 1017 | }; | 1019 | }; |
| 1018 | } | 1020 | } |
| 1019 | 1021 | ||
| 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 | |||
| 1020 | pub fn nop() Instruction { | 1030 | pub fn nop() Instruction { |
| 1021 | return sethi(0, .g0); | 1031 | return sethi(0, .g0); |
| 1022 | } | 1032 | } |
| ... | @@ -1049,6 +1059,38 @@ pub const Instruction = union(enum) { | ... | @@ -1049,6 +1059,38 @@ pub const Instruction = union(enum) { |
| 1049 | return format2a(0b100, imm, rd); | 1059 | return format2a(0b100, imm, rd); |
| 1050 | } | 1060 | } |
| 1051 | 1061 | ||
| 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 | |||
| 1052 | pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { | 1094 | pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { |
| 1053 | return switch (s2) { | 1095 | return switch (s2) { |
| 1054 | Register => format3a(0b10, 0b00_0100, rs1, rs2, rd), | 1096 | Register => format3a(0b10, 0b00_0100, rs1, rs2, rd), |
test/cases/sparcv9-linux/hello_world.zig+6-11| ... | @@ -1,23 +1,18 @@ | ... | @@ -1,23 +1,18 @@ |
| 1 | const msg = "Hello, World!\n"; | 1 | const msg = "Hello, World!\n"; |
| 2 | 2 | ||
| 3 | pub export fn _start() noreturn { | 3 | fn length() usize { |
| 4 | return msg.len; | ||
| 5 | } | ||
| 6 | |||
| 7 | pub fn main() void { | ||
| 4 | asm volatile ("ta 0x6d" | 8 | asm volatile ("ta 0x6d" |
| 5 | : | 9 | : |
| 6 | : [number] "{g1}" (4), | 10 | : [number] "{g1}" (4), |
| 7 | [arg1] "{o0}" (1), | 11 | [arg1] "{o0}" (1), |
| 8 | [arg2] "{o1}" (@ptrToInt(msg)), | 12 | [arg2] "{o1}" (@ptrToInt(msg)), |
| 9 | [arg3] "{o2}" (msg.len), | 13 | [arg3] "{o2}" (length()), |
| 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), | ||
| 17 | : "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "memory" | 14 | : "o0", "o1", "o2", "o3", "o4", "o5", "o6", "o7", "memory" |
| 18 | ); | 15 | ); |
| 19 | |||
| 20 | unreachable; | ||
| 21 | } | 16 | } |
| 22 | 17 | ||
| 23 | // run | 18 | // run |