mirror of
https://github.com/ziglang/zig.git
synced 2026-02-14 05:20:34 +00:00
Merge pull request #11723 from koachan/sparc64-codegen
stage2: sparc64: Small refactorings and stack pointer accounting fixes
This commit is contained in:
commit
90f12a9186
@ -352,7 +352,7 @@ fn gen(self: *Self) !void {
|
||||
if (cc != .Naked) {
|
||||
// TODO Finish function prologue and epilogue for sparc64.
|
||||
|
||||
// save %sp, stack_save_area, %sp
|
||||
// save %sp, stack_reserved_area, %sp
|
||||
const save_inst = try self.addInst(.{
|
||||
.tag = .save,
|
||||
.data = .{
|
||||
@ -360,7 +360,7 @@ fn gen(self: *Self) !void {
|
||||
.is_imm = true,
|
||||
.rd = .sp,
|
||||
.rs1 = .sp,
|
||||
.rs2_or_imm = .{ .imm = -abi.stack_save_area },
|
||||
.rs2_or_imm = .{ .imm = -abi.stack_reserved_area },
|
||||
},
|
||||
},
|
||||
});
|
||||
@ -407,7 +407,7 @@ fn gen(self: *Self) !void {
|
||||
}
|
||||
|
||||
// Backpatch stack offset
|
||||
const total_stack_size = self.max_end_stack + abi.stack_save_area; // TODO + self.saved_regs_stack_space;
|
||||
const total_stack_size = self.max_end_stack + abi.stack_reserved_area;
|
||||
const stack_size = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
|
||||
if (math.cast(i13, stack_size)) |size| {
|
||||
self.mir_instructions.set(save_inst, .{
|
||||
@ -1677,7 +1677,7 @@ fn binOp(
|
||||
|
||||
const mir_tag: Mir.Inst.Tag = switch (tag) {
|
||||
.add => .add,
|
||||
.cmp_eq => .subcc,
|
||||
.cmp_eq => .cmp,
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
@ -1891,7 +1891,7 @@ fn binOpImmediate(
|
||||
.is_imm = true,
|
||||
.rd = dest_reg,
|
||||
.rs1 = lhs_reg,
|
||||
.rs2_or_imm = .{ .imm = @intCast(i13, rhs.immediate) },
|
||||
.rs2_or_imm = .{ .imm = @intCast(u12, rhs.immediate) },
|
||||
},
|
||||
},
|
||||
.sllx => .{
|
||||
@ -1903,6 +1903,13 @@ fn binOpImmediate(
|
||||
.rs2_or_imm = .{ .imm = @intCast(u6, rhs.immediate) },
|
||||
},
|
||||
},
|
||||
.cmp => .{
|
||||
.arithmetic_2op = .{
|
||||
.is_imm = true,
|
||||
.rs1 = lhs_reg,
|
||||
.rs2_or_imm = .{ .imm = @intCast(u12, rhs.immediate) },
|
||||
},
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
@ -2012,6 +2019,13 @@ fn binOpRegister(
|
||||
.rs2_or_imm = .{ .rs2 = rhs_reg },
|
||||
},
|
||||
},
|
||||
.cmp => .{
|
||||
.arithmetic_2op = .{
|
||||
.is_imm = false,
|
||||
.rs1 = lhs_reg,
|
||||
.rs2_or_imm = .{ .rs2 = rhs_reg },
|
||||
},
|
||||
},
|
||||
else => unreachable,
|
||||
};
|
||||
|
||||
@ -2285,7 +2299,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
return self.genSetReg(ty, reg, .{ .immediate = 0xaaaaaaaaaaaaaaaa });
|
||||
},
|
||||
.ptr_stack_offset => |off| {
|
||||
const simm13 = math.cast(u12, off) catch
|
||||
const simm13 = math.cast(u12, off + abi.stack_bias + abi.stack_reserved_area) catch
|
||||
return self.fail("TODO larger stack offsets", .{});
|
||||
|
||||
_ = try self.addInst(.{
|
||||
@ -2303,12 +2317,11 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
.immediate => |x| {
|
||||
if (x <= math.maxInt(u12)) {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .@"or",
|
||||
.tag = .mov,
|
||||
.data = .{
|
||||
.arithmetic_3op = .{
|
||||
.arithmetic_2op = .{
|
||||
.is_imm = true,
|
||||
.rd = reg,
|
||||
.rs1 = .g0,
|
||||
.rs1 = reg,
|
||||
.rs2_or_imm = .{ .imm = @truncate(u12, x) },
|
||||
},
|
||||
},
|
||||
@ -2400,14 +2413,12 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
||||
if (src_reg.id() == reg.id())
|
||||
return;
|
||||
|
||||
// or %g0, src, dst (aka mov src, dst)
|
||||
_ = try self.addInst(.{
|
||||
.tag = .@"or",
|
||||
.tag = .mov,
|
||||
.data = .{
|
||||
.arithmetic_3op = .{
|
||||
.arithmetic_2op = .{
|
||||
.is_imm = false,
|
||||
.rd = reg,
|
||||
.rs1 = .g0,
|
||||
.rs1 = reg,
|
||||
.rs2_or_imm = .{ .rs2 = src_reg },
|
||||
},
|
||||
},
|
||||
@ -2420,7 +2431,7 @@ 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 real_offset = off + abi.stack_bias + abi.stack_save_area;
|
||||
const real_offset = off + abi.stack_bias + abi.stack_reserved_area;
|
||||
const simm13 = math.cast(i13, real_offset) catch
|
||||
return self.fail("TODO larger stack offsets", .{});
|
||||
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
|
||||
return self.genSetStack(ty, stack_offset, MCValue{ .register = reg });
|
||||
},
|
||||
.register => |reg| {
|
||||
const real_offset = stack_offset + abi.stack_bias + abi.stack_save_area;
|
||||
const real_offset = stack_offset + abi.stack_bias + abi.stack_reserved_area;
|
||||
const simm13 = math.cast(i13, real_offset) catch
|
||||
return self.fail("TODO larger stack offsets", .{});
|
||||
return self.genStore(reg, .sp, i13, simm13, abi_size);
|
||||
@ -2625,12 +2636,11 @@ fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
|
||||
};
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = .subcc,
|
||||
.data = .{ .arithmetic_3op = .{
|
||||
.tag = .cmp,
|
||||
.data = .{ .arithmetic_2op = .{
|
||||
.is_imm = true,
|
||||
.rs1 = reg_mcv.register,
|
||||
.rs2_or_imm = .{ .imm = 0 },
|
||||
.rd = .g0,
|
||||
} },
|
||||
});
|
||||
|
||||
@ -3163,12 +3173,11 @@ fn truncRegister(
|
||||
},
|
||||
64 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .@"or",
|
||||
.tag = .mov,
|
||||
.data = .{
|
||||
.arithmetic_3op = .{
|
||||
.arithmetic_2op = .{
|
||||
.is_imm = true,
|
||||
.rd = dest_reg,
|
||||
.rs1 = .g0,
|
||||
.rs1 = dest_reg,
|
||||
.rs2_or_imm = .{ .rs2 = operand_reg },
|
||||
},
|
||||
},
|
||||
|
||||
@ -121,6 +121,10 @@ pub fn emitMir(
|
||||
.subcc => try emit.mirArithmetic3Op(inst),
|
||||
|
||||
.tcc => try emit.mirTrap(inst),
|
||||
|
||||
.cmp => try emit.mirArithmetic2Op(inst),
|
||||
|
||||
.mov => try emit.mirArithmetic2Op(inst),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,12 +183,16 @@ fn mirArithmetic2Op(emit: *Emit, inst: Mir.Inst.Index) !void {
|
||||
const imm = data.rs2_or_imm.imm;
|
||||
switch (tag) {
|
||||
.@"return" => try emit.writeInstruction(Instruction.@"return"(i13, rs1, imm)),
|
||||
.cmp => try emit.writeInstruction(Instruction.subcc(i13, rs1, imm, .g0)),
|
||||
.mov => try emit.writeInstruction(Instruction.@"or"(i13, .g0, imm, rs1)),
|
||||
else => unreachable,
|
||||
}
|
||||
} else {
|
||||
const rs2 = data.rs2_or_imm.rs2;
|
||||
switch (tag) {
|
||||
.@"return" => try emit.writeInstruction(Instruction.@"return"(Register, rs1, rs2)),
|
||||
.cmp => try emit.writeInstruction(Instruction.subcc(Register, rs1, rs2, .g0)),
|
||||
.mov => try emit.writeInstruction(Instruction.@"or"(Register, .g0, rs2, rs1)),
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,9 +125,23 @@ pub const Inst = struct {
|
||||
/// This uses the trap field.
|
||||
tcc,
|
||||
|
||||
// TODO add synthetic instructions
|
||||
// TODO add cmp synthetic instruction to avoid wasting a register when
|
||||
// comparing with subcc
|
||||
// SPARCv9 synthetic instructions
|
||||
// Note that the instructions that is added here are only those that
|
||||
// will simplify backend development. Synthetic instructions that is
|
||||
// only used to provide syntactic sugar in, e.g. inline assembly should
|
||||
// be deconstructed inside the parser instead.
|
||||
// See also: G.3 Synthetic Instructions
|
||||
// TODO add more synthetic instructions
|
||||
|
||||
/// Comparison
|
||||
/// This uses the arithmetic_2op field.
|
||||
cmp, // cmp rs1, rs2/imm -> subcc rs1, rs2/imm, %g0
|
||||
|
||||
/// Copy register/immediate contents to another register
|
||||
/// This uses the arithmetic_2op field, with rs1
|
||||
/// being the *destination* register.
|
||||
// TODO is it okay to abuse rs1 in this way?
|
||||
mov, // mov rs2/imm, rs1 -> or %g0, rs2/imm, rs1
|
||||
};
|
||||
|
||||
/// The position of an MIR instruction within the `Mir` instructions array.
|
||||
|
||||
@ -3,17 +3,17 @@ const bits = @import("bits.zig");
|
||||
const Register = bits.Register;
|
||||
const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
|
||||
|
||||
// SPARCv9 stack constants.
|
||||
// SPARCv9 SysV ABI stack constants.
|
||||
// See: Registers and the Stack Frame, page 3P-8, SCD 2.4.1.
|
||||
|
||||
// On SPARCv9, %sp points to top of stack + stack bias,
|
||||
// and %fp points to top of previous frame + stack bias.
|
||||
// The ABI specifies that %sp points to top of stack - stack bias,
|
||||
// and %fp points to top of previous frame - stack bias.
|
||||
pub const stack_bias = 2047;
|
||||
|
||||
// The first 176 bytes of the stack is reserved for register saving purposes.
|
||||
// SPARCv9 requires to reserve space in the stack for the first six arguments,
|
||||
// even though they are usually passed in registers.
|
||||
pub const stack_save_area = 176;
|
||||
// The first 128 bytes of the stack is reserved for register saving purposes.
|
||||
// The ABI also requires to reserve space in the stack for the first six
|
||||
// outgoing arguments, even though they are usually passed in registers.
|
||||
pub const stack_reserved_area = 128 + 48;
|
||||
|
||||
// There are no callee-preserved registers since the windowing
|
||||
// mechanism already takes care of them.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user