authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-05-26 12:06:11+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-05-26 12:06:11+02:00
log90f12a9186c5495800ef70b3d2d9f51065111aab
tree4719f0f81b032898c49bcd7be8b9a7c9175e1a53
parent0e0b00fd48ea680f2d69207297e877f54dd9ec89
parentc5b99267c0580b166d7ccc2bbf77e9c92566962f
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11723 from koachan/sparc64-codegen

stage2: sparc64: Small refactorings and stack pointer accounting fixes

4 files changed, 65 insertions(+), 34 deletions(-)

src/arch/sparc64/CodeGen.zig+33-24
...@@ -352,7 +352,7 @@ fn gen(self: *Self) !void {...@@ -352,7 +352,7 @@ fn gen(self: *Self) !void {
352 if (cc != .Naked) {352 if (cc != .Naked) {
353 // TODO Finish function prologue and epilogue for sparc64.353 // TODO Finish function prologue and epilogue for sparc64.
354354
355 // save %sp, stack_save_area, %sp355 // save %sp, stack_reserved_area, %sp
356 const save_inst = try self.addInst(.{356 const save_inst = try self.addInst(.{
357 .tag = .save,357 .tag = .save,
358 .data = .{358 .data = .{
...@@ -360,7 +360,7 @@ fn gen(self: *Self) !void {...@@ -360,7 +360,7 @@ fn gen(self: *Self) !void {
360 .is_imm = true,360 .is_imm = true,
361 .rd = .sp,361 .rd = .sp,
362 .rs1 = .sp,362 .rs1 = .sp,
363 .rs2_or_imm = .{ .imm = -abi.stack_save_area },363 .rs2_or_imm = .{ .imm = -abi.stack_reserved_area },
364 },364 },
365 },365 },
366 });366 });
...@@ -407,7 +407,7 @@ fn gen(self: *Self) !void {...@@ -407,7 +407,7 @@ fn gen(self: *Self) !void {
407 }407 }
408408
409 // Backpatch stack offset409 // Backpatch stack offset
410 const total_stack_size = self.max_end_stack + abi.stack_save_area; // TODO + self.saved_regs_stack_space;410 const total_stack_size = self.max_end_stack + abi.stack_reserved_area;
411 const stack_size = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);411 const stack_size = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
412 if (math.cast(i13, stack_size)) |size| {412 if (math.cast(i13, stack_size)) |size| {
413 self.mir_instructions.set(save_inst, .{413 self.mir_instructions.set(save_inst, .{
...@@ -1677,7 +1677,7 @@ fn binOp(...@@ -1677,7 +1677,7 @@ fn binOp(
16771677
1678 const mir_tag: Mir.Inst.Tag = switch (tag) {1678 const mir_tag: Mir.Inst.Tag = switch (tag) {
1679 .add => .add,1679 .add => .add,
1680 .cmp_eq => .subcc,1680 .cmp_eq => .cmp,
1681 else => unreachable,1681 else => unreachable,
1682 };1682 };
16831683
...@@ -1891,7 +1891,7 @@ fn binOpImmediate(...@@ -1891,7 +1891,7 @@ fn binOpImmediate(
1891 .is_imm = true,1891 .is_imm = true,
1892 .rd = dest_reg,1892 .rd = dest_reg,
1893 .rs1 = lhs_reg,1893 .rs1 = lhs_reg,
1894 .rs2_or_imm = .{ .imm = @intCast(i13, rhs.immediate) },1894 .rs2_or_imm = .{ .imm = @intCast(u12, rhs.immediate) },
1895 },1895 },
1896 },1896 },
1897 .sllx => .{1897 .sllx => .{
...@@ -1903,6 +1903,13 @@ fn binOpImmediate(...@@ -1903,6 +1903,13 @@ fn binOpImmediate(
1903 .rs2_or_imm = .{ .imm = @intCast(u6, rhs.immediate) },1903 .rs2_or_imm = .{ .imm = @intCast(u6, rhs.immediate) },
1904 },1904 },
1905 },1905 },
1906 .cmp => .{
1907 .arithmetic_2op = .{
1908 .is_imm = true,
1909 .rs1 = lhs_reg,
1910 .rs2_or_imm = .{ .imm = @intCast(u12, rhs.immediate) },
1911 },
1912 },
1906 else => unreachable,1913 else => unreachable,
1907 };1914 };
19081915
...@@ -2012,6 +2019,13 @@ fn binOpRegister(...@@ -2012,6 +2019,13 @@ fn binOpRegister(
2012 .rs2_or_imm = .{ .rs2 = rhs_reg },2019 .rs2_or_imm = .{ .rs2 = rhs_reg },
2013 },2020 },
2014 },2021 },
2022 .cmp => .{
2023 .arithmetic_2op = .{
2024 .is_imm = false,
2025 .rs1 = lhs_reg,
2026 .rs2_or_imm = .{ .rs2 = rhs_reg },
2027 },
2028 },
2015 else => unreachable,2029 else => unreachable,
2016 };2030 };
20172031
...@@ -2285,7 +2299,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2285,7 +2299,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2285 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });2299 return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
2286 },2300 },
2287 .ptr_stack_offset => |off| {2301 .ptr_stack_offset => |off| {
2288 const simm13 = math.cast(u12, off) catch2302 const simm13 = math.cast(u12, off + abi.stack_bias + abi.stack_reserved_area) catch
2289 return self.fail("TODO larger stack offsets", .{});2303 return self.fail("TODO larger stack offsets", .{});
22902304
2291 _ = try self.addInst(.{2305 _ = try self.addInst(.{
...@@ -2303,12 +2317,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2303,12 +2317,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2303 .immediate => |x| {2317 .immediate => |x| {
2304 if (x <= math.maxInt(u12)) {2318 if (x <= math.maxInt(u12)) {
2305 _ = try self.addInst(.{2319 _ = try self.addInst(.{
2306 .tag = .@"or",2320 .tag = .mov,
2307 .data = .{2321 .data = .{
2308 .arithmetic_3op = .{2322 .arithmetic_2op = .{
2309 .is_imm = true,2323 .is_imm = true,
2310 .rd = reg,2324 .rs1 = reg,
2311 .rs1 = .g0,
2312 .rs2_or_imm = .{ .imm = @truncate(u12, x) },2325 .rs2_or_imm = .{ .imm = @truncate(u12, x) },
2313 },2326 },
2314 },2327 },
...@@ -2400,14 +2413,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2400,14 +2413,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2400 if (src_reg.id() == reg.id())2413 if (src_reg.id() == reg.id())
2401 return;2414 return;
24022415
2403 // or %g0, src, dst (aka mov src, dst)
2404 _ = try self.addInst(.{2416 _ = try self.addInst(.{
2405 .tag = .@"or",2417 .tag = .mov,
2406 .data = .{2418 .data = .{
2407 .arithmetic_3op = .{2419 .arithmetic_2op = .{
2408 .is_imm = false,2420 .is_imm = false,
2409 .rd = reg,2421 .rs1 = reg,
2410 .rs1 = .g0,
2411 .rs2_or_imm = .{ .rs2 = src_reg },2422 .rs2_or_imm = .{ .rs2 = src_reg },
2412 },2423 },
2413 },2424 },
...@@ -2420,7 +2431,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void...@@ -2420,7 +2431,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
2420 try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*));2431 try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*));
2421 },2432 },
2422 .stack_offset => |off| {2433 .stack_offset => |off| {
2423 const real_offset = off + abi.stack_bias + abi.stack_save_area;2434 const real_offset = off + abi.stack_bias + abi.stack_reserved_area;
2424 const simm13 = math.cast(i13, real_offset) catch2435 const simm13 = math.cast(i13, real_offset) catch
2425 return self.fail("TODO larger stack offsets", .{});2436 return self.fail("TODO larger stack offsets", .{});
2426 try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*));2437 try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*));
...@@ -2454,7 +2465,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro...@@ -2454,7 +2465,7 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
2454 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });2465 return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
2455 },2466 },
2456 .register => |reg| {2467 .register => |reg| {
2457 const real_offset = stack_offset + abi.stack_bias + abi.stack_save_area;2468 const real_offset = stack_offset + abi.stack_bias + abi.stack_reserved_area;
2458 const simm13 = math.cast(i13, real_offset) catch2469 const simm13 = math.cast(i13, real_offset) catch
2459 return self.fail("TODO larger stack offsets", .{});2470 return self.fail("TODO larger stack offsets", .{});
2460 return self.genStore(reg, .sp, i13, simm13, abi_size);2471 return self.genStore(reg, .sp, i13, simm13, abi_size);
...@@ -2625,12 +2636,11 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {...@@ -2625,12 +2636,11 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
2625 };2636 };
26262637
2627 _ = try self.addInst(.{2638 _ = try self.addInst(.{
2628 .tag = .subcc,2639 .tag = .cmp,
2629 .data = .{ .arithmetic_3op = .{2640 .data = .{ .arithmetic_2op = .{
2630 .is_imm = true,2641 .is_imm = true,
2631 .rs1 = reg_mcv.register,2642 .rs1 = reg_mcv.register,
2632 .rs2_or_imm = .{ .imm = 0 },2643 .rs2_or_imm = .{ .imm = 0 },
2633 .rd = .g0,
2634 } },2644 } },
2635 });2645 });
26362646
...@@ -3163,12 +3173,11 @@ fn truncRegister(...@@ -3163,12 +3173,11 @@ fn truncRegister(
3163 },3173 },
3164 64 => {3174 64 => {
3165 _ = try self.addInst(.{3175 _ = try self.addInst(.{
3166 .tag = .@"or",3176 .tag = .mov,
3167 .data = .{3177 .data = .{
3168 .arithmetic_3op = .{3178 .arithmetic_2op = .{
3169 .is_imm = true,3179 .is_imm = true,
3170 .rd = dest_reg,3180 .rs1 = dest_reg,
3171 .rs1 = .g0,
3172 .rs2_or_imm = .{ .rs2 = operand_reg },3181 .rs2_or_imm = .{ .rs2 = operand_reg },
3173 },3182 },
3174 },3183 },
src/arch/sparc64/Emit.zig+8
...@@ -121,6 +121,10 @@ pub fn emitMir(...@@ -121,6 +121,10 @@ pub fn emitMir(
121 .subcc => try emit.mirArithmetic3Op(inst),121 .subcc => try emit.mirArithmetic3Op(inst),
122122
123 .tcc => try emit.mirTrap(inst),123 .tcc => try emit.mirTrap(inst),
124
125 .cmp => try emit.mirArithmetic2Op(inst),
126
127 .mov => try emit.mirArithmetic2Op(inst),
124 }128 }
125 }129 }
126}130}
...@@ -179,12 +183,16 @@ fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void {...@@ -179,12 +183,16 @@ fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void {
179 const imm = data.rs2_or_imm.imm;183 const imm = data.rs2_or_imm.imm;
180 switch (tag) {184 switch (tag) {
181 .@"return" => try emit.writeInstruction(Instruction.@"return"(i13, rs1, imm)),185 .@"return" => try emit.writeInstruction(Instruction.@"return"(i13, rs1, imm)),
186 .cmp => try emit.writeInstruction(Instruction.subcc(i13, rs1, imm, .g0)),
187 .mov => try emit.writeInstruction(Instruction.@"or"(i13, .g0, imm, rs1)),
182 else => unreachable,188 else => unreachable,
183 }189 }
184 } else {190 } else {
185 const rs2 = data.rs2_or_imm.rs2;191 const rs2 = data.rs2_or_imm.rs2;
186 switch (tag) {192 switch (tag) {
187 .@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)),193 .@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)),
194 .cmp => try emit.writeInstruction(Instruction.subcc(Register, rs1, rs2, .g0)),
195 .mov => try emit.writeInstruction(Instruction.@"or"(Register, .g0, rs2, rs1)),
188 else => unreachable,196 else => unreachable,
189 }197 }
190 }198 }
src/arch/sparc64/Mir.zig+17-3
...@@ -125,9 +125,23 @@ pub const Inst = struct {...@@ -125,9 +125,23 @@ pub const Inst = struct {
125 /// This uses the trap field.125 /// This uses the trap field.
126 tcc,126 tcc,
127127
128 // TODO add synthetic instructions128 // SPARCv9 synthetic instructions
129 // TODO add cmp synthetic instruction to avoid wasting a register when129 // Note that the instructions that is added here are only those that
130 // comparing with subcc130 // will simplify backend development. Synthetic instructions that is
131 // only used to provide syntactic sugar in, e.g. inline assembly should
132 // be deconstructed inside the parser instead.
133 // See also: G.3 Synthetic Instructions
134 // TODO add more synthetic instructions
135
136 /// Comparison
137 /// This uses the arithmetic_2op field.
138 cmp, // cmp rs1, rs2/imm -> subcc rs1, rs2/imm, %g0
139
140 /// Copy register/immediate contents to another register
141 /// This uses the arithmetic_2op field, with rs1
142 /// being the *destination* register.
143 // TODO is it okay to abuse rs1 in this way?
144 mov, // mov rs2/imm, rs1 -> or %g0, rs2/imm, rs1
131 };145 };
132146
133 /// The position of an MIR instruction within the `Mir` instructions array.147 /// The position of an MIR instruction within the `Mir` instructions array.
src/arch/sparc64/abi.zig+7-7
...@@ -3,17 +3,17 @@ const bits = @import("bits.zig");...@@ -3,17 +3,17 @@ const bits = @import("bits.zig");
3const Register = bits.Register;3const Register = bits.Register;
4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
55
6// SPARCv9 stack constants.6// SPARCv9 SysV ABI stack constants.
7// See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1.7// See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1.
88
9// On SPARCv9, %sp points to top of stack + stack bias,9// The ABI specifies that %sp points to top of stack - stack bias,
10// and %fp points to top of previous frame + stack bias.10// and %fp points to top of previous frame - stack bias.
11pub const stack_bias = 2047;11pub const stack_bias = 2047;
1212
13// The first 176 bytes of the stack is reserved for register saving purposes.13// The first 128 bytes of the stack is reserved for register saving purposes.
14// SPARCv9 requires to reserve space in the stack for the first six arguments,14// The ABI also requires to reserve space in the stack for the first six
15// even though they are usually passed in registers.15// outgoing arguments, even though they are usually passed in registers.
16pub const stack_save_area = 176;16pub const stack_reserved_area = 128 + 48;
1717
18// There are no callee-preserved registers since the windowing18// There are no callee-preserved registers since the windowing
19// mechanism already takes care of them.19// mechanism already takes care of them.