authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-11 12:09:39+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2020-11-11 14:34:53+01:00
loga6bc19ea2a2fb99ee7f09dd451b889b6a5d7f388
tree21db839a2cfa74adf67c1cacf05ac59d20a6bbfe
parent993eb22a772323bfeef87cf783672c33b6a2cfa2

stage2 aarch64: add genCall for aarch64 MachO


1 files changed, 50 insertions(+), 47 deletions(-)

src/codegen.zig+50-47
......@@ -1643,61 +1643,64 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
16431643 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.target.cpu.arch}),
16441644 }
16451645 } else if (self.bin_file.cast(link.File.MachO)) |macho_file| {
1646 switch (arch) {
1647 .x86_64 => {
1648 for (info.args) |mc_arg, arg_i| {
1649 const arg = inst.args[arg_i];
1650 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
1651 // Here we do not use setRegOrMem even though the logic is similar, because
1652 // the function call will move the stack pointer, so the offsets are different.
1653 switch (mc_arg) {
1654 .none => continue,
1655 .register => |reg| {
1656 try self.genSetReg(arg.src, reg, arg_mcv);
1657 // TODO interact with the register allocator to mark the instruction as moved.
1658 },
1659 .stack_offset => {
1660 // Here we need to emit instructions like this:
1661 // mov qword ptr [rsp + stack_offset], x
1662 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
1663 },
1664 .ptr_stack_offset => {
1665 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1666 },
1667 .ptr_embedded_in_code => {
1668 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1669 },
1670 .undef => unreachable,
1671 .immediate => unreachable,
1672 .unreach => unreachable,
1673 .dead => unreachable,
1674 .embedded_in_code => unreachable,
1675 .memory => unreachable,
1676 .compare_flags_signed => unreachable,
1677 .compare_flags_unsigned => unreachable,
1678 }
1679 }
1646 for (info.args) |mc_arg, arg_i| {
1647 const arg = inst.args[arg_i];
1648 const arg_mcv = try self.resolveInst(inst.args[arg_i]);
1649 // Here we do not use setRegOrMem even though the logic is similar, because
1650 // the function call will move the stack pointer, so the offsets are different.
1651 switch (mc_arg) {
1652 .none => continue,
1653 .register => |reg| {
1654 try self.genSetReg(arg.src, reg, arg_mcv);
1655 // TODO interact with the register allocator to mark the instruction as moved.
1656 },
1657 .stack_offset => {
1658 // Here we need to emit instructions like this:
1659 // mov qword ptr [rsp + stack_offset], x
1660 return self.fail(inst.base.src, "TODO implement calling with parameters in memory", .{});
1661 },
1662 .ptr_stack_offset => {
1663 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_stack_offset arg", .{});
1664 },
1665 .ptr_embedded_in_code => {
1666 return self.fail(inst.base.src, "TODO implement calling with MCValue.ptr_embedded_in_code arg", .{});
1667 },
1668 .undef => unreachable,
1669 .immediate => unreachable,
1670 .unreach => unreachable,
1671 .dead => unreachable,
1672 .embedded_in_code => unreachable,
1673 .memory => unreachable,
1674 .compare_flags_signed => unreachable,
1675 .compare_flags_unsigned => unreachable,
1676 }
1677 }
16801678
1681 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1682 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
1683 const func = func_val.func;
1684 const got = &macho_file.sections.items[macho_file.got_section_index.?];
1685 const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
1679 if (inst.func.cast(ir.Inst.Constant)) |func_inst| {
1680 if (func_inst.val.cast(Value.Payload.Function)) |func_val| {
1681 const func = func_val.func;
1682 const got = &macho_file.sections.items[macho_file.got_section_index.?];
1683 const got_addr = got.addr + func.owner_decl.link.macho.offset_table_index * @sizeOf(u64);
1684 switch (arch) {
1685 .x86_64 => {
16861686 // Here, we store the got address in %rax, and then call %rax
16871687 // movabsq [addr], %rax
16881688 try self.genSetReg(inst.base.src, .rax, .{ .memory = got_addr });
16891689 // callq *%rax
16901690 try self.code.ensureCapacity(self.code.items.len + 2);
16911691 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
1692 } else {
1693 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
1694 }
1695 } else {
1696 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
1692 },
1693 .aarch64 => {
1694 try self.genSetReg(inst.base.src, .x30, .{ .memory = got_addr });
1695 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
1696 },
1697 else => unreachable, // unsupported architecture on MachO
16971698 }
1698 },
1699 .aarch64 => return self.fail(inst.base.src, "TODO implement codegen for call when linking with MachO for aarch64 arch", .{}),
1700 else => unreachable,
1699 } else {
1700 return self.fail(inst.base.src, "TODO implement calling bitcasted functions", .{});
1701 }
1702 } else {
1703 return self.fail(inst.base.src, "TODO implement calling runtime known function pointer", .{});
17011704 }
17021705 } else {
17031706 unreachable;