Commit 97c25fb8d0

Jakub Konka <kubkon@jakubkonka.com>
2022-02-17 18:10:02
x64: implement array_elem_val when array is stored in memory
1 parent abfaf83
Changed files (2)
src
arch
test
behavior
src/arch/x86_64/CodeGen.zig
@@ -1604,6 +1604,12 @@ fn airArrayElemVal(self: *Self, inst: Air.Inst.Index) !void {
                     .stack_offset => |off| {
                         break :inner off;
                     },
+                    .memory,
+                    .got_load,
+                    .direct_load,
+                    => {
+                        break :blk try self.loadMemPtrIntoRegister(Type.usize, array);
+                    },
                     else => return self.fail("TODO implement array_elem_val when array is {}", .{array}),
                 }
             };
@@ -1845,6 +1851,42 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
     return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
 }
 
+fn loadMemPtrIntoRegister(self: *Self, ptr_ty: Type, ptr: MCValue) InnerError!Register {
+    switch (ptr) {
+        .got_load,
+        .direct_load,
+        => |sym_index| {
+            const flags: u2 = switch (ptr) {
+                .got_load => 0b00,
+                .direct_load => 0b01,
+                else => unreachable,
+            };
+            const reg = try self.register_manager.allocReg(null);
+            _ = try self.addInst(.{
+                .tag = .lea_pie,
+                .ops = (Mir.Ops{
+                    .reg1 = reg.to64(),
+                    .flags = flags,
+                }).encode(),
+                .data = .{
+                    .load_reloc = .{
+                        .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
+                        .sym_index = sym_index,
+                    },
+                },
+            });
+            return reg.to64();
+        },
+        .memory => |addr| {
+            // TODO: in case the address fits in an imm32 we can use [ds:imm32]
+            // instead of wasting an instruction copying the address to a register
+            const reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr });
+            return reg.to64();
+        },
+        else => unreachable,
+    }
+}
+
 fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
     _ = ptr_ty;
     const abi_size = value_ty.abiSize(self.target.*);
@@ -1955,41 +1997,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
             value.freezeIfRegister(&self.register_manager);
             defer value.unfreezeIfRegister(&self.register_manager);
 
-            const addr_reg: Register = blk: {
-                switch (ptr) {
-                    .got_load,
-                    .direct_load,
-                    => |sym_index| {
-                        const flags: u2 = switch (ptr) {
-                            .got_load => 0b00,
-                            .direct_load => 0b01,
-                            else => unreachable,
-                        };
-                        const addr_reg = try self.register_manager.allocReg(null);
-                        _ = try self.addInst(.{
-                            .tag = .lea_pie,
-                            .ops = (Mir.Ops{
-                                .reg1 = addr_reg.to64(),
-                                .flags = flags,
-                            }).encode(),
-                            .data = .{
-                                .load_reloc = .{
-                                    .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
-                                    .sym_index = sym_index,
-                                },
-                            },
-                        });
-                        break :blk addr_reg;
-                    },
-                    .memory => |addr| {
-                        // TODO: in case the address fits in an imm32 we can use [ds:imm32]
-                        // instead of wasting an instruction copying the address to a register
-                        const addr_reg = try self.copyToTmpRegister(ptr_ty, .{ .immediate = addr });
-                        break :blk addr_reg;
-                    },
-                    else => unreachable,
-                }
-            };
+            const addr_reg = try self.loadMemPtrIntoRegister(ptr_ty, ptr);
 
             // to get the actual address of the value we want to modify we have to go through the GOT
             // mov reg, [reg]
@@ -3831,33 +3839,11 @@ fn genInlineMemcpy(self: *Self, stack_offset: i32, stack_reg: Register, ty: Type
 
     const addr_reg: Register = blk: {
         switch (val) {
-            .memory => |addr| {
-                const reg = try self.copyToTmpRegister(Type.usize, .{ .immediate = addr });
-                break :blk reg;
-            },
+            .memory,
             .direct_load,
             .got_load,
-            => |sym_index| {
-                const flags: u2 = switch (val) {
-                    .got_load => 0b00,
-                    .direct_load => 0b01,
-                    else => unreachable,
-                };
-                const addr_reg = (try self.register_manager.allocReg(null)).to64();
-                _ = try self.addInst(.{
-                    .tag = .lea_pie,
-                    .ops = (Mir.Ops{
-                        .reg1 = addr_reg,
-                        .flags = flags,
-                    }).encode(),
-                    .data = .{
-                        .load_reloc = .{
-                            .atom_index = self.mod_fn.owner_decl.link.macho.local_sym_index,
-                            .sym_index = sym_index,
-                        },
-                    },
-                });
-                break :blk addr_reg;
+            => {
+                break :blk try self.loadMemPtrIntoRegister(Type.usize, val);
             },
             .stack_offset => |off| {
                 const addr_reg = (try self.register_manager.allocReg(null)).to64();
test/behavior/array.zig
@@ -153,7 +153,7 @@ test "void arrays" {
 
 test "nested arrays" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
-    if (builtin.zig_backend == .stage2_x86_64 or builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
+    if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
 
     const array_of_strings = [_][]const u8{ "hello", "this", "is", "my", "thing" };
     for (array_of_strings) |s, i| {
@@ -525,8 +525,8 @@ test "zero-sized array with recursive type definition" {
 test "type coercion of anon struct literal to array" {
     if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
     if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
-    if (builtin.zig_backend == .stage2_x86_64) 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
 
     const S = struct {
         const U = union {
@@ -543,8 +543,8 @@ test "type coercion of anon struct literal to array" {
             try expect(arr1[1] == 56);
             try expect(arr1[2] == 54);
 
-            if (@import("builtin").zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
-            if (@import("builtin").zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
+            if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
+            if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
 
             var x2: U = .{ .a = 42 };
             const t2 = .{ x2, .{ .b = true }, .{ .c = "hello" } };