From 97c25fb8d049ebcced9f29241516c51e480fb8a0 Mon Sep 17 00:00:00 2001 From: Jakub Konka Date: Thu, 17 Feb 2022 18:10:02 +0100 Subject: [PATCH] x64: implement array_elem_val when array is stored in memory --- src/arch/x86_64/CodeGen.zig | 106 ++++++++++++++++-------------------- test/behavior/array.zig | 8 +-- 2 files changed, 50 insertions(+), 64 deletions(-) diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index cc3953e57b..6b27627825 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/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(); diff --git a/test/behavior/array.zig b/test/behavior/array.zig index b4a4c37d95..ba478fef93 100644 --- a/test/behavior/array.zig +++ b/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" } };