Commit ee6b4fad47

Jakub Konka <kubkon@jakubkonka.com>
2023-04-11 22:17:04
x86_64: remove loadMemPtrIntoRegister in genSetReg
Add two emit helpers for linker reloc based `lea` and `mov` instructions: `asmMovLinker` and `asmLeaLinker`.
1 parent 382de7b
Changed files (4)
src/arch/x86_64/CodeGen.zig
@@ -731,6 +731,40 @@ fn asmMemoryRegisterImmediate(
     });
 }
 
+fn asmMovLinker(self: *Self, reg: Register, atom_index: u32, linker_load: codegen.LinkerLoad) !void {
+    const ops: Mir.Inst.Ops = switch (linker_load.type) {
+        .got => .got_reloc,
+        .direct => .direct_reloc,
+        .import => .import_reloc,
+    };
+    _ = try self.addInst(.{
+        .tag = .mov_linker,
+        .ops = ops,
+        .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
+            .reg = @enumToInt(reg),
+            .atom_index = atom_index,
+            .sym_index = linker_load.sym_index,
+        }) },
+    });
+}
+
+fn asmLeaLinker(self: *Self, reg: Register, atom_index: u32, linker_load: codegen.LinkerLoad) !void {
+    const ops: Mir.Inst.Ops = switch (linker_load.type) {
+        .got => .got_reloc,
+        .direct => .direct_reloc,
+        .import => .import_reloc,
+    };
+    _ = try self.addInst(.{
+        .tag = .lea_linker,
+        .ops = ops,
+        .data = .{ .payload = try self.addExtra(Mir.LeaRegisterReloc{
+            .reg = @enumToInt(reg),
+            .atom_index = atom_index,
+            .sym_index = linker_load.sym_index,
+        }) },
+    });
+}
+
 fn gen(self: *Self) InnerError!void {
     const cc = self.fn_type.fnCallingConvention();
     if (cc != .Naked) {
@@ -7454,10 +7488,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
 
             try self.asmRegisterRegister(.mov, registerAlias(reg, abi_size), registerAlias(src_reg, abi_size));
         },
-        .memory, .linker_load => switch (ty.zigTypeTag()) {
+        .memory => |addr| switch (ty.zigTypeTag()) {
             .Float => {
-                const base_reg = try self.register_manager.allocReg(null, gp);
-                try self.loadMemPtrIntoRegister(base_reg, Type.usize, mcv);
+                const base_reg = (try self.register_manager.allocReg(null, gp)).to64();
+                try self.genSetReg(Type.usize, base_reg, .{ .immediate = addr });
 
                 if (intrinsicsAllowed(self.target.*, ty)) {
                     return self.asmRegisterMemory(
@@ -7469,29 +7503,20 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
                             }),
                         },
                         reg.to128(),
-                        Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg.to64() }),
+                        Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg }),
                     );
                 }
 
                 return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});
             },
-            else => switch (mcv) {
-                else => unreachable,
-                .linker_load => {
-                    try self.loadMemPtrIntoRegister(reg, Type.usize, mcv);
-                    try self.asmRegisterMemory(
-                        .mov,
-                        registerAlias(reg, abi_size),
-                        Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
-                    );
-                },
-                .memory => |x| if (x <= math.maxInt(i32)) {
+            else => {
+                if (addr <= math.maxInt(i32)) {
                     try self.asmRegisterMemory(
                         .mov,
                         registerAlias(reg, abi_size),
                         Memory.sib(Memory.PtrSize.fromSize(abi_size), .{
                             .base = .ds,
-                            .disp = @intCast(i32, x),
+                            .disp = @intCast(i32, addr),
                         }),
                     );
                 } else {
@@ -7501,20 +7526,53 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
                         _ = try self.addInst(.{
                             .tag = .mov_moffs,
                             .ops = .rax_moffs,
-                            .data = .{ .payload = try self.addExtra(Mir.MemoryMoffs.encode(.ds, x)) },
+                            .data = .{ .payload = try self.addExtra(Mir.MemoryMoffs.encode(.ds, addr)) },
                         });
                     } else {
                         // Rather than duplicate the logic used for the move, we just use a self-call with a new MCValue.
-                        try self.genSetReg(ty, reg, MCValue{ .immediate = x });
+                        try self.genSetReg(Type.usize, reg, MCValue{ .immediate = addr });
                         try self.asmRegisterMemory(
                             .mov,
                             registerAlias(reg, abi_size),
                             Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = reg.to64() }),
                         );
                     }
-                },
+                }
             },
         },
+        .linker_load => |load_struct| {
+            const atom_index = if (self.bin_file.cast(link.File.MachO)) |macho_file| blk: {
+                const atom = try macho_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
+                break :blk macho_file.getAtom(atom).getSymbolIndex().?;
+            } else if (self.bin_file.cast(link.File.Coff)) |coff_file| blk: {
+                const atom = try coff_file.getOrCreateAtomForDecl(self.mod_fn.owner_decl);
+                break :blk coff_file.getAtom(atom).getSymbolIndex().?;
+            } else unreachable;
+
+            switch (ty.zigTypeTag()) {
+                .Float => {
+                    const base_reg = (try self.register_manager.allocReg(null, gp)).to64();
+                    try self.asmLeaLinker(base_reg, atom_index, load_struct);
+
+                    if (intrinsicsAllowed(self.target.*, ty)) {
+                        return self.asmRegisterMemory(
+                            switch (ty.tag()) {
+                                .f32 => .movss,
+                                .f64 => .movsd,
+                                else => return self.fail("TODO genSetReg from memory for {}", .{
+                                    ty.fmt(self.bin_file.options.module.?),
+                                }),
+                            },
+                            reg.to128(),
+                            Memory.sib(Memory.PtrSize.fromSize(abi_size), .{ .base = base_reg.to64() }),
+                        );
+                    }
+
+                    return self.fail("TODO genSetReg from memory for float with no intrinsics", .{});
+                },
+                else => try self.asmMovLinker(registerAlias(reg, abi_size), atom_index, load_struct),
+            }
+        },
         .stack_offset => |off| {
             switch (ty.zigTypeTag()) {
                 .Int => switch (ty.intInfo(self.target.*).signedness) {
src/arch/x86_64/Emit.zig
@@ -65,7 +65,7 @@ pub fn emitMir(emit: *Emit) Error!void {
                 });
             } else return emit.fail("TODO implement {} for {}", .{ inst.tag, emit.bin_file.tag }),
 
-            .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
+            .mov_linker, .lea_linker => if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
                 const metadata =
                     emit.lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
                 const reloc_type = switch (inst.ops) {
src/arch/x86_64/Lower.zig
@@ -127,6 +127,7 @@ pub fn lowerMir(lower: *Lower, inst: Mir.Inst) Error![]const Instruction {
         .call_extern => try lower.emit(.none, .call, &.{.{ .imm = Immediate.s(0) }}),
 
         .lea_linker => try lower.mirLeaLinker(inst),
+        .mov_linker => try lower.mirMovLinker(inst),
 
         .mov_moffs => try lower.mirMovMoffs(inst),
 
@@ -444,6 +445,15 @@ fn mirLeaLinker(lower: *Lower, inst: Mir.Inst) Error!void {
     });
 }
 
+fn mirMovLinker(lower: *Lower, inst: Mir.Inst) Error!void {
+    const metadata = lower.mir.extraData(Mir.LeaRegisterReloc, inst.data.payload).data;
+    const reg = @intToEnum(Register, metadata.reg);
+    try lower.emit(.none, .mov, &.{
+        .{ .reg = reg },
+        .{ .mem = Memory.rip(Memory.PtrSize.fromBitSize(reg.bitSize()), 0) },
+    });
+}
+
 const abi = @import("abi.zig");
 const assert = std.debug.assert;
 const bits = @import("bits.zig");
src/arch/x86_64/Mir.zig
@@ -233,6 +233,8 @@ pub const Inst = struct {
 
         /// Load effective address of a symbol not yet allocated in VM.
         lea_linker,
+        /// Move address of a symbol not yet allocated in VM.
+        mov_linker,
 
         /// End of prologue
         dbg_prologue_end,