Commit 7d14426da4

joachimschmidt557 <joachim.schmidt557@outlook.com>
2020-10-16 18:32:02
stage2 ARM: enable backpatching return statement
1 parent 0e16328
Changed files (2)
src
src/codegen/arm.zig
@@ -575,12 +575,12 @@ pub const Instruction = union(enum) {
         };
     }
 
-    fn branch(cond: Condition, offset: i24, link: u1) Instruction {
+    fn branch(cond: Condition, offset: i26, link: u1) Instruction {
         return Instruction{
             .Branch = .{
                 .cond = @enumToInt(cond),
                 .link = link,
-                .offset = @bitCast(u24, offset),
+                .offset = @bitCast(u24, @intCast(i24, offset >> 2)),
             },
         };
     }
@@ -895,11 +895,11 @@ pub const Instruction = union(enum) {
 
     // Branch
 
-    pub fn b(cond: Condition, offset: i24) Instruction {
+    pub fn b(cond: Condition, offset: i26) Instruction {
         return branch(cond, offset, 0);
     }
 
-    pub fn bl(cond: Condition, offset: i24) Instruction {
+    pub fn bl(cond: Condition, offset: i26) Instruction {
         return branch(cond, offset, 1);
     }
 
@@ -929,6 +929,10 @@ pub const Instruction = union(enum) {
 
     // Aliases
 
+    pub fn nop() Instruction {
+        return mov(.al, .r0, Instruction.Operand.reg(.r0, Instruction.Operand.Shift.none));
+    }
+
     pub fn pop(cond: Condition, args: anytype) Instruction {
         if (@typeInfo(@TypeOf(args)) != .Struct) {
             @compileError("Expected tuple or struct argument, found " ++ @typeName(@TypeOf(args)));
@@ -1025,11 +1029,11 @@ test "serialize instructions" {
         },
         .{ // b #12
             .inst = Instruction.b(.al, 12),
-            .expected = 0b1110_101_0_0000_0000_0000_0000_0000_1100,
+            .expected = 0b1110_101_0_0000_0000_0000_0000_0000_0011,
         },
         .{ // bl #-4
             .inst = Instruction.bl(.al, -4),
-            .expected = 0b1110_101_1_1111_1111_1111_1111_1111_1100,
+            .expected = 0b1110_101_1_1111_1111_1111_1111_1111_1111,
         },
         .{ // bx lr
             .inst = Instruction.bx(.al, .lr),
src/codegen.zig
@@ -587,11 +587,36 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
 
                         try self.dbgSetEpilogueBegin();
 
+                        // exitlude jumps
+                        if (self.exitlude_jump_relocs.items.len == 1) {
+                            // There is only one relocation. Hence,
+                            // this relocation must be at the end of
+                            // the code. Therefore, we can just delete
+                            // the space initially reserved for the
+                            // jump
+                            self.code.items.len -= 4;
+                        } else for (self.exitlude_jump_relocs.items) |jmp_reloc| {
+                            const amt = self.code.items.len - (jmp_reloc + 4);
+                            if (amt == 0) {
+                                // This return is at the end of the
+                                // code block. We can't just delete
+                                // the space because there may be
+                                // other jumps we already relocated to
+                                // the address. Instead, insert a nop
+                                mem.writeIntLittle(u32, self.code.items[jmp_reloc..][0..4], Instruction.nop().toU32());
+                            } else {
+                                if (math.cast(i26, amt)) |offset| {
+                                    mem.writeIntLittle(u32, self.code.items[jmp_reloc..][0..4], Instruction.b(.al, offset).toU32());
+                                } else |err| {
+                                    return self.fail(self.src, "exitlude jump is too large", .{});
+                                }
+                            }
+                        }
+
                         // mov sp, fp
                         // pop {fp, pc}
-                        // TODO: return by jumping to this code, use relocations
-                        // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());
-                        // mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
+                        mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());
+                        mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
                     } else {
                         try self.dbgSetPrologueEnd();
                         try self.genBody(self.mod_fn.analysis.success);
@@ -1661,12 +1686,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                     mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.jalr(.zero, 0, .ra).toU32());
                 },
                 .arm => {
-                    mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.mov(.al, .sp, Instruction.Operand.reg(.fp, Instruction.Operand.Shift.none)).toU32());
-                    mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.pop(.al, .{ .fp, .pc }).toU32());
-                    // TODO: jump to the end with relocation
-                    // // 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);
+                    // 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}),
             }
@@ -1932,6 +1954,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                         mem.writeIntLittle(i32, self.code.addManyAsArrayAssumeCapacity(4), delta);
                     }
                 },
+                .arm => {
+                    if (math.cast(i26, @intCast(i32, index) - @intCast(i32, self.code.items.len))) |delta| {
+                        mem.writeIntLittle(u32, try self.code.addManyAsArray(4), Instruction.b(.al, delta).toU32());
+                    } else |err| {
+                        return self.fail(src, "TODO: enable larger branch offset", .{});
+                    }
+                },
                 else => return self.fail(src, "TODO implement jump for {}", .{self.target.cpu.arch}),
             }
         }