Commit f91fe9afb9

joachimschmidt557 <joachim.schmidt557@outlook.com>
2022-02-23 21:32:25
stage2 AArch64: more support for MCValue.got_load and direct_load
1 parent 4683f94
Changed files (9)
src/arch/aarch64/CodeGen.zig
@@ -1717,6 +1717,8 @@ fn reuseOperand(self: *Self, inst: Air.Inst.Index, operand: Air.Inst.Ref, op_ind
 
 fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!void {
     const elem_ty = ptr_ty.elemType();
+    const elem_size = elem_ty.abiSize(self.target.*);
+
     switch (ptr) {
         .none => unreachable,
         .undef => unreachable,
@@ -1736,17 +1738,16 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
             self.register_manager.freezeRegs(&.{addr_reg});
             defer self.register_manager.unfreezeRegs(&.{addr_reg});
 
-            const abi_size = elem_ty.abiSize(self.target.*);
             switch (dst_mcv) {
                 .dead => unreachable,
                 .undef => unreachable,
                 .compare_flags_signed, .compare_flags_unsigned => unreachable,
                 .embedded_in_code => unreachable,
                 .register => |dst_reg| {
-                    try self.genLdrRegister(dst_reg, addr_reg, abi_size);
+                    try self.genLdrRegister(dst_reg, addr_reg, elem_size);
                 },
                 .stack_offset => |off| {
-                    if (abi_size <= 8) {
+                    if (elem_size <= 8) {
                         const tmp_reg = try self.register_manager.allocReg(null);
                         self.register_manager.freezeRegs(&.{tmp_reg});
                         defer self.register_manager.unfreezeRegs(&.{tmp_reg});
@@ -1766,17 +1767,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
                         const tmp_reg = regs[3];
 
                         // sub dst_reg, fp, #off
-                        const elem_size = @intCast(u32, elem_ty.abiSize(self.target.*));
-                        const adj_off = off + elem_size;
-                        const offset = math.cast(u12, adj_off) catch return self.fail("TODO load: larger stack offsets", .{});
-                        _ = try self.addInst(.{
-                            .tag = .sub_immediate,
-                            .data = .{ .rr_imm12_sh = .{
-                                .rd = dst_reg,
-                                .rn = .x29,
-                                .imm12 = offset,
-                            } },
-                        });
+                        try self.genSetReg(ptr_ty, dst_reg, .{ .ptr_stack_offset = off });
 
                         // mov len, #elem_size
                         try self.genSetReg(Type.usize, len_reg, .{ .immediate = elem_size });
@@ -2046,14 +2037,11 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
         },
         .memory,
         .stack_offset,
-        => {
-            const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);
-            try self.store(.{ .register = addr_reg }, value, ptr_ty, value_ty);
-        },
         .got_load,
         .direct_load,
         => {
-            return self.fail("TODO implement storing to {}", .{ptr});
+            const addr_reg = try self.copyToTmpRegister(ptr_ty, ptr);
+            try self.store(.{ .register = addr_reg }, value, ptr_ty, value_ty);
         },
     }
 }
@@ -3142,10 +3130,6 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
         },
         .got_load,
         .direct_load,
-        => |sym_index| {
-            _ = sym_index;
-            return self.fail("TODO implement set stack variable from {}", .{mcv});
-        },
         .memory,
         .stack_offset,
         => {
@@ -3187,6 +3171,25 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro
                         });
                     },
                     .memory => |addr| try self.genSetReg(Type.usize, src_reg, .{ .immediate = addr }),
+                    .got_load,
+                    .direct_load,
+                    => |sym_index| {
+                        const tag: Mir.Inst.Tag = switch (mcv) {
+                            .got_load => .load_memory_ptr_got,
+                            .direct_load => .load_memory_ptr_direct,
+                            else => unreachable,
+                        };
+                        _ = try self.addInst(.{
+                            .tag = tag,
+                            .data = .{
+                                .payload = try self.addExtra(Mir.LoadMemoryPie{
+                                    .register = @enumToInt(src_reg),
+                                    .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
+                                    .sym_index = sym_index,
+                                }),
+                            },
+                        });
+                    },
                     else => unreachable,
                 }
 
src/arch/aarch64/Emit.zig
@@ -110,6 +110,8 @@ pub fn emitMir(
 
             .load_memory_got => try emit.mirLoadMemoryPie(inst),
             .load_memory_direct => try emit.mirLoadMemoryPie(inst),
+            .load_memory_ptr_got => try emit.mirLoadMemoryPie(inst),
+            .load_memory_ptr_direct => try emit.mirLoadMemoryPie(inst),
 
             .ldp => try emit.mirLoadStoreRegisterPair(inst),
             .stp => try emit.mirLoadStoreRegisterPair(inst),
@@ -208,6 +210,8 @@ fn instructionSize(emit: *Emit, inst: Mir.Inst.Index) usize {
     switch (tag) {
         .load_memory_got,
         .load_memory_direct,
+        .load_memory_ptr_got,
+        .load_memory_ptr_direct,
         => return 2 * 4,
         .pop_regs, .push_regs => {
             const reg_list = emit.mir.instructions.items(.data)[inst].reg_list;
@@ -655,12 +659,25 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
     const offset = @intCast(u32, emit.code.items.len);
     try emit.writeInstruction(Instruction.adrp(reg, 0));
 
-    // ldr reg, reg, offset
-    try emit.writeInstruction(Instruction.ldr(
-        reg,
-        reg,
-        Instruction.LoadStoreOffset.imm(0),
-    ));
+    switch (tag) {
+        .load_memory_got,
+        .load_memory_direct,
+        => {
+            // ldr reg, reg, offset
+            try emit.writeInstruction(Instruction.ldr(
+                reg,
+                reg,
+                Instruction.LoadStoreOffset.imm(0),
+            ));
+        },
+        .load_memory_ptr_got,
+        .load_memory_ptr_direct,
+        => {
+            // add reg, reg, offset
+            try emit.writeInstruction(Instruction.add(reg, reg, 0, false));
+        },
+        else => unreachable,
+    }
 
     if (emit.bin_file.cast(link.File.MachO)) |macho_file| {
         const atom = macho_file.atom_by_index_table.get(data.atom_index).?;
@@ -673,8 +690,12 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
             .pcrel = true,
             .length = 2,
             .@"type" = switch (tag) {
-                .load_memory_got => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),
-                .load_memory_direct => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
+                .load_memory_got,
+                .load_memory_ptr_got,
+                => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21),
+                .load_memory_direct,
+                .load_memory_ptr_direct,
+                => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_PAGE21),
                 else => unreachable,
             },
         });
@@ -687,8 +708,12 @@ fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void {
             .pcrel = false,
             .length = 2,
             .@"type" = switch (tag) {
-                .load_memory_got => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12),
-                .load_memory_direct => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),
+                .load_memory_got,
+                .load_memory_ptr_got,
+                => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGEOFF12),
+                .load_memory_direct,
+                .load_memory_ptr_direct,
+                => @enumToInt(std.macho.reloc_type_arm64.ARM64_RELOC_PAGEOFF12),
                 else => unreachable,
             },
         });
src/arch/aarch64/Mir.zig
@@ -56,10 +56,22 @@ pub const Inst = struct {
         dbg_line,
         /// Bitwise Exclusive OR (shifted register)
         eor_shifted_register,
+        /// Loads the contents into a register
+        ///
         /// Payload is `LoadMemoryPie`
         load_memory_got,
+        /// Loads the contents into a register
+        ///
         /// Payload is `LoadMemoryPie`
         load_memory_direct,
+        /// Loads the address into a register
+        ///
+        /// Payload is `LoadMemoryPie`
+        load_memory_ptr_got,
+        /// Loads the address into a register
+        ///
+        /// Payload is `LoadMemoryPie`
+        load_memory_ptr_direct,
         /// Load Pair of Registers
         ldp,
         /// Pseudo-instruction: Load from stack
test/behavior/bugs/2006.zig
@@ -6,7 +6,6 @@ const S = struct {
     p: *S,
 };
 test "bug 2006" {
-    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
     var a: S = undefined;
     a = S{ .p = undefined };
test/behavior/align.zig
@@ -305,7 +305,6 @@ fn testIndex2(ptr: [*]align(4) u8, index: usize, comptime T: type) !void {
 }
 
 test "alignment of function with c calling convention" {
-    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
 
     var runtime_nothing = &nothing;
test/behavior/basic.zig
@@ -48,7 +48,6 @@ const g1: i32 = 1233 + 1;
 var g2: i32 = 0;
 
 test "global variables" {
-    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
     try expect(g2 == 0);
     g2 = g1;
     try expect(g2 == 1234);
@@ -604,7 +603,6 @@ test "comptime cast fn to ptr" {
 }
 
 test "equality compare fn ptrs" {
-    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
 
     var a = &emptyFn;
@@ -612,7 +610,6 @@ test "equality compare fn ptrs" {
 }
 
 test "self reference through fn ptr field" {
-    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
     if (builtin.zig_backend == .stage1) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest;
 
test/behavior/cast.zig
@@ -1013,7 +1013,6 @@ test "cast from array reference to fn: comptime fn ptr" {
     try expect(@ptrToInt(f) == @ptrToInt(&global_array));
 }
 test "cast from array reference to fn: runtime fn ptr" {
-    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
     if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
test/behavior/slice.zig
@@ -81,7 +81,6 @@ fn assertLenIsZero(msg: []const u8) !void {
 }
 
 test "access len index of sentinel-terminated slice" {
-    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
 
     const S = struct {
test/behavior/struct.zig
@@ -66,7 +66,6 @@ const SmallStruct = struct {
 };
 
 test "lower unnamed constants" {
-    if (builtin.zig_backend == .stage2_aarch64 and builtin.os.tag == .macos) return error.SkipZigTest;
     var foo = SmallStruct{ .a = 1, .b = 255 };
     try expect(foo.first() == 1);
     try expect(foo.second() == 255);