From 258b058eecb54e160ac60e72b0354f99f3202bdf Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Sat, 17 Sep 2022 12:26:21 +0200 Subject: [PATCH 1/2] stage2 ARM: make sub_sp_scratch MIR instruction use r4 r0 is used for argument passing, so this register is not available as a scratch register upon function entry. --- src/arch/arm/CodeGen.zig | 43 ++++++---------------------------------- src/arch/arm/Emit.zig | 8 ++++---- src/arch/arm/Mir.zig | 4 ++-- 3 files changed, 12 insertions(+), 43 deletions(-) diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index d3ec7606076ca01d8e2e6988b44e94c53d4c49fa..55cdcf841163635bc4272cb6a89175ed71c9d0e8 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -169,40 +169,6 @@ const MCValue = union(enum) { cpsr_flags: Condition, /// The value is a function argument passed via the stack. stack_argument_offset: u32, - - fn isMemory(mcv: MCValue) bool { - return switch (mcv) { - .memory, .stack_offset, .stack_argument_offset => true, - else => false, - }; - } - - fn isImmediate(mcv: MCValue) bool { - return switch (mcv) { - .immediate => true, - else => false, - }; - } - - fn isMutable(mcv: MCValue) bool { - return switch (mcv) { - .none => unreachable, - .unreach => unreachable, - .dead => unreachable, - - .immediate, - .memory, - .cpsr_flags, - .ptr_stack_offset, - .undef, - .stack_argument_offset, - => false, - - .register, - .stack_offset, - => true, - }; - } }; const Branch = struct { @@ -447,6 +413,11 @@ fn gen(self: *Self) !void { // sub sp, sp, #reloc const sub_reloc = try self.addNop(); + // The sub_sp_scratch_r4 instruction may use r4, so we mark r4 + // as allocated by this function. + const index = RegisterManager.indexOfRegIntoTracked(.r4).?; + self.register_manager.allocated_registers.set(index); + if (self.ret_mcv == .stack_offset) { // The address of where to store the return value is in // r0. As this register might get overwritten along the @@ -477,7 +448,6 @@ fn gen(self: *Self) !void { self.saved_regs_stack_space += 4; } } - self.mir_instructions.set(push_reloc, .{ .tag = .push, .data = .{ .register_list = saved_regs }, @@ -489,7 +459,7 @@ fn gen(self: *Self) !void { const stack_size = aligned_total_stack_end - self.saved_regs_stack_space; self.max_end_stack = stack_size; self.mir_instructions.set(sub_reloc, .{ - .tag = .sub_sp_scratch_r0, + .tag = .sub_sp_scratch_r4, .data = .{ .imm32 = stack_size }, }); @@ -4042,7 +4012,6 @@ fn genArgDbgInfo(self: *Self, inst: Air.Inst.Index, arg_index: u32) error{OutOfM => { switch (self.debug_output) { .dwarf => |dw| { - // const abi_size = @intCast(u32, ty.abiSize(self.target.*)); const adjusted_stack_offset = switch (mcv) { .stack_offset => |offset| -@intCast(i32, offset), .stack_argument_offset => |offset| @intCast(i32, self.saved_regs_stack_space + offset), diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index 188f5a5cfebe1637b6f704b0cb5400c841b145e8..91993f00d2cc189ba80b7d51f20ca8644e4c81f1 100644 --- a/src/arch/arm/Emit.zig +++ b/src/arch/arm/Emit.zig @@ -94,7 +94,7 @@ pub fn emitMir( .sub => try emit.mirDataProcessing(inst), .subs => try emit.mirDataProcessing(inst), - .sub_sp_scratch_r0 => try emit.mirSubStackPointer(inst), + .sub_sp_scratch_r4 => try emit.mirSubStackPointer(inst), .asr => try emit.mirShift(inst), .lsl => try emit.mirShift(inst), @@ -194,7 +194,7 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize { .dbg_prologue_end, => return 0, - .sub_sp_scratch_r0 => { + .sub_sp_scratch_r4 => { const imm32 = emit.mir.instructions.items(.data)[inst].imm32; if (imm32 == 0) { @@ -454,11 +454,11 @@ fn mirSubStackPointer(emit: *Emit, inst: Mir.Inst.Index) !void { const imm32 = emit.mir.instructions.items(.data)[inst].imm32; switch (tag) { - .sub_sp_scratch_r0 => { + .sub_sp_scratch_r4 => { if (imm32 == 0) return; const operand = Instruction.Operand.fromU32(imm32) orelse blk: { - const scratch: Register = .r0; + const scratch: Register = .r4; if (Target.arm.featureSetHas(emit.target.cpu.features, .has_v7)) { try emit.writeInstruction(Instruction.movw(cond, scratch, @truncate(u16, imm32))); diff --git a/src/arch/arm/Mir.zig b/src/arch/arm/Mir.zig index ab64dbf738eb1ceaf18a41d9c177fe3ab5ab30d1..3478d8dc58521ab892dd2a801af1ae8dcd74ae77 100644 --- a/src/arch/arm/Mir.zig +++ b/src/arch/arm/Mir.zig @@ -113,9 +113,9 @@ pub const Inst = struct { sub, /// Pseudo-instruction: Subtract 32-bit immediate from stack /// - /// r0 can be used by Emit as a scratch register for loading + /// r4 can be used by Emit as a scratch register for loading /// the immediate - sub_sp_scratch_r0, + sub_sp_scratch_r4, /// Subtract, update condition flags subs, /// Supervisor Call -- 2.54.0 From f014de6456f0cd56d692c2a93c441d83b01796a2 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Sun, 18 Sep 2022 19:50:06 +0200 Subject: [PATCH 2/2] stage2 ARM: fix debug info for arguments passed in registers --- src/arch/arm/CodeGen.zig | 56 +++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 55cdcf841163635bc4272cb6a89175ed71c9d0e8..95dfb2eea382987dd362101c2b971d3dccb244b2 100644 --- a/src/arch/arm/CodeGen.zig +++ b/src/arch/arm/CodeGen.zig @@ -428,6 +428,28 @@ fn gen(self: *Self) !void { self.ret_mcv = MCValue{ .stack_offset = stack_offset }; } + for (self.args) |*arg, arg_index| { + // Copy register arguments to the stack + switch (arg.*) { + .register => |reg| { + // The first AIR instructions of the main body are guaranteed + // to be the functions arguments + const inst = self.air.getMainBody()[arg_index]; + assert(self.air.instructions.items(.tag)[inst] == .arg); + + const ty = self.air.typeOfIndex(inst); + + const abi_size = @intCast(u32, ty.abiSize(self.target.*)); + const abi_align = ty.abiAlignment(self.target.*); + const stack_offset = try self.allocMem(abi_size, abi_align, inst); + try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); + + arg.* = MCValue{ .stack_offset = stack_offset }; + }, + else => {}, + } + } + _ = try self.addInst(.{ .tag = .dbg_prologue_end, .cond = undefined, @@ -3766,7 +3788,8 @@ fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Typ const tag: Mir.Inst.Tag = switch (abi_size) { 1 => .strb, 2 => .strh, - 3, 4 => .str, + 4 => .str, + 3 => return self.fail("TODO: genStrRegister for abi_size={}", .{abi_size}), else => unreachable, }; @@ -3782,7 +3805,7 @@ fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Typ } }; const data: Mir.Inst.Data = switch (abi_size) { - 1, 3, 4 => rr_offset, + 1, 4 => rr_offset, 2 => rr_extra_offset, else => unreachable, }; @@ -4047,38 +4070,13 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const arg_index = self.arg_index; self.arg_index += 1; - const ty = self.air.typeOfIndex(inst); - - const result = self.args[arg_index]; - const mcv = switch (result) { - // Copy registers to the stack - .register => |reg| blk: { - const abi_size = @intCast(u32, ty.abiSize(self.target.*)); - const abi_align = ty.abiAlignment(self.target.*); - const stack_offset = try self.allocMem(abi_size, abi_align, inst); - try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); - - break :blk MCValue{ .stack_offset = stack_offset }; - }, - else => result, - }; - try self.dbg_arg_relocs.append(self.gpa, .{ .inst = inst, .index = arg_index, }); - if (self.liveness.isUnused(inst)) - return self.finishAirBookkeeping(); - - switch (mcv) { - .register => |reg| { - self.register_manager.getRegAssumeFree(reg, inst); - }, - else => {}, - } - - return self.finishAir(inst, mcv, .{ .none, .none, .none }); + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else self.args[arg_index]; + return self.finishAir(inst, result, .{ .none, .none, .none }); } fn airBreakpoint(self: *Self) !void { -- 2.54.0