From 35b228630cf1972868fe820baeb41a09801f2fbb Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Thu, 24 Sep 2020 19:10:12 +0200 Subject: [PATCH] stage2 ARM: Add stm, ldm variants and misc. additions --- src/codegen.zig | 41 +++++++++++++++++++++++++++++---- src/codegen/arm.zig | 56 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 84 insertions(+), 13 deletions(-) diff --git a/src/codegen.zig b/src/codegen.zig index 9bb53c5cdc..541dced068 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -570,6 +570,35 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { try self.dbgSetEpilogueBegin(); } }, + .arm => { + const cc = self.fn_type.fnCallingConvention(); + if (cc != .Naked) { + // push {fp, lr} + // mov fp, sp + // sub sp, sp, #reloc + // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .fp, Instruction.Operand.reg(.sp, Instruction.Operand.Shift.none)).toU32()); + // const backpatch_reloc = try self.code.addManyAsArray(4); + + try self.dbgSetPrologueEnd(); + + try self.genBody(self.mod_fn.analysis.success); + + // Backpatch stack offset + // const stack_end = self.max_end_stack; + // const aligned_stack_end = mem.alignForward(stack_end, self.stack_align); + // mem.writeIntLittle(u32, backpatch_reloc, Instruction.sub(.al, .sp, .sp, Instruction.Operand.imm())); + + try self.dbgSetEpilogueBegin(); + + // mov sp, fp + // pop {fp, pc} + mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32()); + } else { + try self.dbgSetPrologueEnd(); + try self.genBody(self.mod_fn.analysis.success); + try self.dbgSetEpilogueBegin(); + } + }, else => { try self.dbgSetPrologueEnd(); try self.genBody(self.mod_fn.analysis.success); @@ -1504,13 +1533,10 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { else unreachable; - // TODO only works with leaf functions - // at the moment, which works fine for - // Hello World, but not for real code - // of course. Add pushing lr to stack - // and popping after call try self.genSetReg(inst.base.src, .lr, .{ .memory = got_addr }); + // TODO: add Instruction.supportedOn + // function for ARM if (Target.arm.featureSetHas(self.target.cpu.features, .has_v5t)) { mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.blx(.al, .lr).toU32()); } else { @@ -1636,6 +1662,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { }, .arm => { mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.bx(.al, .lr).toU32()); + // // Just add space for an instruction, patch this later + // try self.code.resize(self.code.items.len + 4); + // try self.exitlude_jump_relocs.append(self.gpa, self.code.items.len - 4); }, else => return self.fail(src, "TODO implement return for {}", .{self.target.cpu.arch}), } @@ -2771,6 +2800,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { } else { return self.fail(src, "TODO MCValues with multiple registers", .{}); } + } else if (ncrn < 4 and nsaa == 0) { + return self.fail(src, "TODO MCValues split between registers and stack", .{}); } else { ncrn = 4; if (ty.abiAlignment(self.target.*) == 8) { diff --git a/src/codegen/arm.zig b/src/codegen/arm.zig index 096012a1e8..5acc2ab431 100644 --- a/src/codegen/arm.zig +++ b/src/codegen/arm.zig @@ -446,7 +446,7 @@ pub const Instruction = union(enum) { pre_post: u1, up_down: u1, psr_or_user: u1, - write_back: u1, + write_back: bool, load_store: u1, ) Instruction { return Instruction{ @@ -454,7 +454,7 @@ pub const Instruction = union(enum) { .register_list = @bitCast(u16, reg_list), .rn = rn.id(), .load_store = load_store, - .write_back = write_back, + .write_back = if (write_back) 1 else 0, .psr_or_user = psr_or_user, .up_down = up_down, .pre_post = pre_post, @@ -644,14 +644,50 @@ pub const Instruction = union(enum) { // Block data transfer - pub fn ldm(cond: Condition, rn: Register, reg_list: RegisterList) Instruction { - return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, 0, 1); + pub fn ldmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { + return blockDataTransfer(cond, rn, reg_list, 0, 0, 0, write_back, 1); } - pub fn stm(cond: Condition, rn: Register, reg_list: RegisterList) Instruction { - return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, 0, 0); + pub fn ldmdb(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { + return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, write_back, 1); } + pub fn ldmib(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { + return blockDataTransfer(cond, rn, reg_list, 1, 1, 0, write_back, 1); + } + + pub fn ldmia(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { + return blockDataTransfer(cond, rn, reg_list, 0, 1, 0, write_back, 1); + } + + pub const ldmfa = ldmda; + pub const ldmea = ldmdb; + pub const ldmed = ldmib; + pub const ldmfd = ldmia; + pub const ldm = ldmia; + + pub fn stmda(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { + return blockDataTransfer(cond, rn, reg_list, 0, 0, 0, write_back, 0); + } + + pub fn stmdb(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { + return blockDataTransfer(cond, rn, reg_list, 1, 0, 0, write_back, 0); + } + + pub fn stmib(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { + return blockDataTransfer(cond, rn, reg_list, 1, 1, 0, write_back, 0); + } + + pub fn stmia(cond: Condition, rn: Register, write_back: bool, reg_list: RegisterList) Instruction { + return blockDataTransfer(cond, rn, reg_list, 0, 1, 0, write_back, 0); + } + + pub const stmed = stmda; + pub const stmfd = stmdb; + pub const stmfa = stmib; + pub const stmea = stmia; + pub const stm = stmia; + // Branch pub fn b(cond: Condition, offset: i24) Instruction { @@ -738,10 +774,14 @@ test "serialize instructions" { .inst = Instruction.bkpt(42), .expected = 0b1110_0001_0010_000000000010_0111_1010, }, - .{ // stmfd r9, {r0} - .inst = Instruction.stm(.al, .r9, .{ .r0 = true }), + .{ // stmdb r9, {r0} + .inst = Instruction.stmdb(.al, .r9, false, .{ .r0 = true }), .expected = 0b1110_100_1_0_0_0_0_1001_0000000000000001, }, + .{ // ldmea r4!, {r2, r5} + .inst = Instruction.ldmea(.al, .r4, true, .{ .r2 = true, .r5 = true }), + .expected = 0b1110_100_1_0_0_1_1_0100_0000000000100100, + }, }; for (testcases) |case| {