Commit a00d69ea4a

Koakuma <koachan@protonmail.com>
2022-04-20 23:52:50
stage2: sparcv9: Implement basic stack load/stores
1 parent b6d7f63
Changed files (5)
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
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),
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 = {} };
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,
         }
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.