Commit a6bc19ea2a

Jakub Konka <kubkon@jakubkonka.com>
2020-11-11 12:09:39
stage2 aarch64: add genCall for aarch64 MachO
1 parent 993eb22
Changed files (1)
src/codegen.zig
@@ -1643,61 +1643,64 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
                     else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
                 }
             } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
-                switch (arch) {
-                    .x86_64 => {
-                        for (info.args) |mc_arg, arg_i| {
-                            const arg = inst.args[arg_i];
-                            const arg_mcv = try self.resolveInst(inst.args[arg_i]);
-                            // Here we do not use setRegOrMem even though the logic is similar, because
-                            // the function call will move the stack pointer, so the offsets are different.
-                            switch (mc_arg) {
-                                .none => continue,
-                                .register => |reg| {
-                                    try self.genSetReg(arg.src, reg, arg_mcv);
-                                    // TODO interact with the register allocator to mark the instruction as moved.
-                                },
-                                .stack_offset => {
-                                    // Here we need to emit instructions like this:
-                                    // mov     qword ptr [rsp + stack_offset], x
-                                    return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
-                                },
-                                .ptr_stack_offset => {
-                                    return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
-                                },
-                                .ptr_embedded_in_code => {
-                                    return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
-                                },
-                                .undef => unreachable,
-                                .immediate => unreachable,
-                                .unreach => unreachable,
-                                .dead => unreachable,
-                                .embedded_in_code => unreachable,
-                                .memory => unreachable,
-                                .compare_flags_signed => unreachable,
-                                .compare_flags_unsigned => unreachable,
-                            }
-                        }
+                for (info.args) |mc_arg, arg_i| {
+                    const arg = inst.args[arg_i];
+                    const arg_mcv = try self.resolveInst(inst.args[arg_i]);
+                    // Here we do not use setRegOrMem even though the logic is similar, because
+                    // the function call will move the stack pointer, so the offsets are different.
+                    switch (mc_arg) {
+                        .none => continue,
+                        .register => |reg| {
+                            try self.genSetReg(arg.src, reg, arg_mcv);
+                            // TODO interact with the register allocator to mark the instruction as moved.
+                        },
+                        .stack_offset => {
+                            // Here we need to emit instructions like this:
+                            // mov     qword ptr [rsp + stack_offset], x
+                            return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
+                        },
+                        .ptr_stack_offset => {
+                            return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
+                        },
+                        .ptr_embedded_in_code => {
+                            return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
+                        },
+                        .undef => unreachable,
+                        .immediate => unreachable,
+                        .unreach => unreachable,
+                        .dead => unreachable,
+                        .embedded_in_code => unreachable,
+                        .memory => unreachable,
+                        .compare_flags_signed => unreachable,
+                        .compare_flags_unsigned => unreachable,
+                    }
+                }
 
-                        if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
-                            if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
-                                const func = func_val.func;
-                                const got = &macho_file.sections.items[macho_file.got_section_index.?];
-                                const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
+                if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
+                    if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
+                        const func = func_val.func;
+                        const got = &macho_file.sections.items[macho_file.got_section_index.?];
+                        const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
+                        switch (arch) {
+                            .x86_64 => {
                                 // Here, we store the got address in %rax, and then call %rax
                                 // movabsq [addr], %rax
                                 try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });
                                 // callq *%rax
                                 try self.code.ensureCapacity(self.code.items.len + 2);
                                 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
-                            } else {
-                                return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
-                            }
-                        } else {
-                            return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
+                            },
+                            .aarch64 => {
+                                try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr });
+                                writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
+                            },
+                            else => unreachable, // unsupported architecture on MachO
                         }
-                    },
-                    .aarch64 => return self.fail(inst.base.src, "TODO implement codegen for call when linking with MachO for aarch64 arch", .{}),
-                    else => unreachable,
+                    } else {
+                        return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
+                    }
+                } else {
+                    return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
                 }
             } else {
                 unreachable;