stage2 ARM: support larger function stacks

This is done by introducing a new Mir pseudo-instruction
This commit is contained in:
joachimschmidt557 2022-09-04 22:28:59 +02:00
parent 3794f2c493
commit a0a7d15142
No known key found for this signature in database
GPG Key ID: E0B575BE2884ACC5
4 changed files with 65 additions and 9 deletions

View File

@ -488,14 +488,10 @@ fn gen(self: *Self) !void {
const aligned_total_stack_end = mem.alignForwardGeneric(u32, total_stack_size, self.stack_align);
const stack_size = aligned_total_stack_end - self.saved_regs_stack_space;
self.max_end_stack = stack_size;
if (Instruction.Operand.fromU32(stack_size)) |op| {
self.mir_instructions.set(sub_reloc, .{
.tag = .sub,
.data = .{ .rr_op = .{ .rd = .sp, .rn = .sp, .op = op } },
});
} else {
return self.failSymbol("TODO ARM: allow larger stacks", .{});
}
self.mir_instructions.set(sub_reloc, .{
.tag = .sub_sp_scratch_r0,
.data = .{ .imm32 = stack_size },
});
_ = try self.addInst(.{
.tag = .dbg_epilogue_begin,

View File

@ -11,6 +11,7 @@ const link = @import("../../link.zig");
const Module = @import("../../Module.zig");
const Type = @import("../../type.zig").Type;
const ErrorMsg = Module.ErrorMsg;
const Target = std.Target;
const assert = std.debug.assert;
const DW = std.dwarf;
const leb128 = std.leb;
@ -93,6 +94,8 @@ pub fn emitMir(
.sub => try emit.mirDataProcessing(inst),
.subs => try emit.mirDataProcessing(inst),
.sub_sp_scratch_r0 => try emit.mirSubStackPointer(inst),
.asr => try emit.mirShift(inst),
.lsl => try emit.mirShift(inst),
.lsr => try emit.mirShift(inst),
@ -190,6 +193,24 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
.dbg_epilogue_begin,
.dbg_prologue_end,
=> return 0,
.sub_sp_scratch_r0 => {
const imm32 = emit.mir.instructions.items(.data)[inst].imm32;
if (imm32 == 0) {
return 0 * 4;
} else if (Instruction.Operand.fromU32(imm32) != null) {
// sub
return 1 * 4;
} else if (Target.arm.featureSetHas(emit.target.cpu.features, .has_v7)) {
// movw; movt; sub
return 3 * 4;
} else {
// mov; orr; orr; orr; sub
return 5 * 4;
}
},
else => return 4,
}
}
@ -427,6 +448,37 @@ fn mirDataProcessing(emit: *Emit, inst: Mir.Inst.Index) !void {
}
}
fn mirSubStackPointer(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const cond = emit.mir.instructions.items(.cond)[inst];
const imm32 = emit.mir.instructions.items(.data)[inst].imm32;
switch (tag) {
.sub_sp_scratch_r0 => {
if (imm32 == 0) return;
const operand = Instruction.Operand.fromU32(imm32) orelse blk: {
const scratch: Register = .r0;
if (Target.arm.featureSetHas(emit.target.cpu.features, .has_v7)) {
try emit.writeInstruction(Instruction.movw(cond, scratch, @truncate(u16, imm32)));
try emit.writeInstruction(Instruction.movt(cond, scratch, @truncate(u16, imm32 >> 16)));
} else {
try emit.writeInstruction(Instruction.mov(cond, scratch, Instruction.Operand.imm(@truncate(u8, imm32), 0)));
try emit.writeInstruction(Instruction.orr(cond, scratch, scratch, Instruction.Operand.imm(@truncate(u8, imm32 >> 8), 12)));
try emit.writeInstruction(Instruction.orr(cond, scratch, scratch, Instruction.Operand.imm(@truncate(u8, imm32 >> 16), 8)));
try emit.writeInstruction(Instruction.orr(cond, scratch, scratch, Instruction.Operand.imm(@truncate(u8, imm32 >> 24), 4)));
}
break :blk Instruction.Operand.reg(scratch, Instruction.Operand.Shift.none);
};
try emit.writeInstruction(Instruction.sub(cond, .sp, .sp, operand));
},
else => unreachable,
}
}
fn mirShift(emit: *Emit, inst: Mir.Inst.Index) !void {
const tag = emit.mir.instructions.items(.tag)[inst];
const cond = emit.mir.instructions.items(.cond)[inst];

View File

@ -111,6 +111,11 @@ pub const Inst = struct {
strh,
/// Subtract
sub,
/// Pseudo-instruction: Subtract 32-bit immediate from stack
///
/// r0 can be used by Emit as a scratch register for loading
/// the immediate
sub_sp_scratch_r0,
/// Subtract, update condition flags
subs,
/// Supervisor Call
@ -144,6 +149,10 @@ pub const Inst = struct {
///
/// Used by e.g. svc
imm24: u24,
/// A 32-bit immediate value.
///
/// Used by e.g. sub_sp_scratch_r0
imm32: u32,
/// Index into `extra`. Meaning of what can be found there is context-dependent.
///
/// Used by e.g. load_memory

View File

@ -1333,7 +1333,6 @@ test "lazy sizeof is resolved in division" {
}
test "lazy value is resolved as slice operand" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
const A = struct { a: u32 };