Commit a0a7d15142
Changed files (4)
src
arch
test
behavior
src/arch/arm/CodeGen.zig
@@ -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,
src/arch/arm/Emit.zig
@@ -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];
src/arch/arm/Mir.zig
@@ -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
test/behavior/eval.zig
@@ -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 };