Commit 35b228630c

joachimschmidt557 <joachim.schmidt557@outlook.com>
2020-09-24 19:10:12
stage2 ARM: Add stm, ldm variants and misc. additions
1 parent 0a54f04
Changed files (2)
src
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| {
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) {