diff --git a/src/codegen.zig b/src/codegen.zig index 2cc85a7cd2..01ebbe85ae 100644 --- a/src/codegen.zig +++ b/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}), } } diff --git a/src/codegen/arm.zig b/src/codegen/arm.zig index c2d66f9309..296edabbb2 100644 --- a/src/codegen/arm.zig +++ b/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),