diff --git a/src/arch/sparcv9/CodeGen.zig b/src/arch/sparcv9/CodeGen.zig index ffd1dfde86..ca31297888 100644 --- a/src/arch/sparcv9/CodeGen.zig +++ b/src/arch/sparcv9/CodeGen.zig @@ -1351,7 +1351,8 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void try self.genLoad(reg, reg, i13, 0, ty.abiSize(self.target.*)); }, .stack_offset => |off| { - const simm13 = math.cast(u12, off) catch + const biased_offset = off + abi.stack_bias; + const simm13 = math.cast(i13, biased_offset) catch return self.fail("TODO larger stack offsets", .{}); try self.genLoad(reg, .sp, i13, simm13, ty.abiSize(self.target.*)); }, @@ -1381,11 +1382,80 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro const reg = try self.copyToTmpRegister(ty, mcv); return self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); }, - .register => return self.fail("TODO implement storing types abi_size={}", .{abi_size}), + .register => |reg| { + const biased_offset = stack_offset + abi.stack_bias; + const simm13 = math.cast(i13, biased_offset) catch + return self.fail("TODO larger stack offsets", .{}); + return self.genStore(reg, .sp, i13, simm13, abi_size); + }, .memory, .stack_offset => return self.fail("TODO implement memcpy", .{}), } } +fn genStore(self: *Self, value_reg: Register, addr_reg: Register, comptime off_type: type, off: off_type, abi_size: u64) !void { + assert(off_type == Register or off_type == i13); + + const is_imm = (off_type == i13); + const rs2_or_imm = if (is_imm) .{ .imm = off } else .{ .rs2 = off }; + + switch (abi_size) { + 1 => { + _ = try self.addInst(.{ + .tag = .stb, + .data = .{ + .arithmetic_3op = .{ + .is_imm = is_imm, + .rd = value_reg, + .rs1 = addr_reg, + .rs2_or_imm = rs2_or_imm, + }, + }, + }); + }, + 2 => { + _ = try self.addInst(.{ + .tag = .sth, + .data = .{ + .arithmetic_3op = .{ + .is_imm = is_imm, + .rd = value_reg, + .rs1 = addr_reg, + .rs2_or_imm = rs2_or_imm, + }, + }, + }); + }, + 4 => { + _ = try self.addInst(.{ + .tag = .stw, + .data = .{ + .arithmetic_3op = .{ + .is_imm = is_imm, + .rd = value_reg, + .rs1 = addr_reg, + .rs2_or_imm = rs2_or_imm, + }, + }, + }); + }, + 8 => { + _ = try self.addInst(.{ + .tag = .stx, + .data = .{ + .arithmetic_3op = .{ + .is_imm = is_imm, + .rd = value_reg, + .rs1 = addr_reg, + .rs2_or_imm = rs2_or_imm, + }, + }, + }); + }, + 3, 5, 6, 7 => return self.fail("TODO: genLoad for more abi_sizes", .{}), + else => unreachable, + } +} + fn genTypedValue(self: *Self, typed_value: TypedValue) InnerError!MCValue { if (typed_value.val.isUndef()) return MCValue{ .undef = {} }; diff --git a/src/arch/sparcv9/Emit.zig b/src/arch/sparcv9/Emit.zig index a136c622e7..91dcb4fd5f 100644 --- a/src/arch/sparcv9/Emit.zig +++ b/src/arch/sparcv9/Emit.zig @@ -76,6 +76,11 @@ pub fn emitMir( .sllx => @panic("TODO implement sparcv9 sllx"), + .stb => try emit.mirArithmetic3Op(inst), + .sth => try emit.mirArithmetic3Op(inst), + .stw => try emit.mirArithmetic3Op(inst), + .stx => try emit.mirArithmetic3Op(inst), + .sub => try emit.mirArithmetic3Op(inst), .tcc => try emit.mirTrap(inst), @@ -170,6 +175,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { .@"or" => try emit.writeInstruction(Instruction.@"or"(i13, rs1, imm, rd)), .save => try emit.writeInstruction(Instruction.save(i13, rs1, imm, rd)), .restore => try emit.writeInstruction(Instruction.restore(i13, rs1, imm, rd)), + .stb => try emit.writeInstruction(Instruction.stb(i13, rs1, imm, rd)), + .sth => try emit.writeInstruction(Instruction.sth(i13, rs1, imm, rd)), + .stw => try emit.writeInstruction(Instruction.stw(i13, rs1, imm, rd)), + .stx => try emit.writeInstruction(Instruction.stx(i13, rs1, imm, rd)), .sub => try emit.writeInstruction(Instruction.sub(i13, rs1, imm, rd)), else => unreachable, } @@ -185,6 +194,10 @@ fn mirArithmetic3Op(emit: *Emit, inst: Mir.Inst.Index) !void { .@"or" => try emit.writeInstruction(Instruction.@"or"(Register, rs1, rs2, rd)), .save => try emit.writeInstruction(Instruction.save(Register, rs1, rs2, rd)), .restore => try emit.writeInstruction(Instruction.restore(Register, rs1, rs2, rd)), + .stb => try emit.writeInstruction(Instruction.stb(Register, rs1, rs2, rd)), + .sth => try emit.writeInstruction(Instruction.sth(Register, rs1, rs2, rd)), + .stw => try emit.writeInstruction(Instruction.stw(Register, rs1, rs2, rd)), + .stx => try emit.writeInstruction(Instruction.stx(Register, rs1, rs2, rd)), .sub => try emit.writeInstruction(Instruction.sub(Register, rs1, rs2, rd)), else => unreachable, } diff --git a/src/arch/sparcv9/Mir.zig b/src/arch/sparcv9/Mir.zig index 21f59322cd..54f147f415 100644 --- a/src/arch/sparcv9/Mir.zig +++ b/src/arch/sparcv9/Mir.zig @@ -94,6 +94,16 @@ pub const Inst = struct { // TODO add other operations. sllx, + /// A.54 Store Integer + /// This uses the arithmetic_3op field. + /// Note that the std variant of this instruction is deprecated, so do not emit + /// it unless specifically requested (e.g. by inline assembly). + // TODO add other operations. + stb, + sth, + stw, + stx, + /// A.56 Subtract /// Those uses the arithmetic_3op field. // TODO add other operations. diff --git a/src/arch/sparcv9/abi.zig b/src/arch/sparcv9/abi.zig index 4cb10a99ea..ae72f270be 100644 --- a/src/arch/sparcv9/abi.zig +++ b/src/arch/sparcv9/abi.zig @@ -1,6 +1,11 @@ const bits = @import("bits.zig"); const Register = bits.Register; +// On SPARCv9, %sp points to top of stack + stack bias, +// and %fp points to top of previous frame + stack bias. +// See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1. +pub const stack_bias = 2047; + // There are no callee-preserved registers since the windowing // mechanism already takes care of them. // We still need to preserve %o0-%o5, %g1, %g4, and %g5 before calling diff --git a/src/arch/sparcv9/bits.zig b/src/arch/sparcv9/bits.zig index 2b50e68d32..e66b24f617 100644 --- a/src/arch/sparcv9/bits.zig +++ b/src/arch/sparcv9/bits.zig @@ -1059,6 +1059,38 @@ pub const Instruction = union(enum) { return format2a(0b100, imm, rd); } + pub fn stb(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { + return switch (s2) { + Register => format3a(0b11, 0b00_0101, rs1, rs2, rd), + i13 => format3b(0b11, 0b00_0101, rs1, rs2, rd), + else => unreachable, + }; + } + + pub fn sth(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { + return switch (s2) { + Register => format3a(0b11, 0b00_0110, rs1, rs2, rd), + i13 => format3b(0b11, 0b00_0110, rs1, rs2, rd), + else => unreachable, + }; + } + + pub fn stw(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { + return switch (s2) { + Register => format3a(0b11, 0b00_0100, rs1, rs2, rd), + i13 => format3b(0b11, 0b00_0100, rs1, rs2, rd), + else => unreachable, + }; + } + + pub fn stx(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { + return switch (s2) { + Register => format3a(0b11, 0b00_1110, rs1, rs2, rd), + i13 => format3b(0b11, 0b00_1110, rs1, rs2, rd), + else => unreachable, + }; + } + pub fn sub(comptime s2: type, rs1: Register, rs2: s2, rd: Register) Instruction { return switch (s2) { Register => format3a(0b10, 0b00_0100, rs1, rs2, rd),