stage2: sparcv9: Implement basic stack load/stores

This commit is contained in:
Koakuma 2022-04-21 04:52:50 +07:00 committed by Jakub Konka
parent b6d7f63f34
commit a00d69ea4a
5 changed files with 132 additions and 2 deletions

View File

@ -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 = {} };

View File

@ -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,
}

View File

@ -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.

View File

@ -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

View File

@ -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),