diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 8c7d0a67b4..39d7f6fd8a 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/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, } @@ -3318,15 +3321,10 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void }); }, .memory => |addr| { - _ = try self.addInst(.{ - .tag = .load_memory, - .data = .{ - .load_memory = .{ - .register = @enumToInt(reg), - .addr = @intCast(u32, addr), - }, - }, - }); + // The value is in memory at a hard-coded address. + // If the type is a pointer, it means the pointer address is at this memory location. + try self.genSetReg(ty, reg, .{ .immediate = addr }); + try self.genLdrRegister(reg, reg, ty.abiSize(self.target.*)); }, .stack_offset => |unadjusted_off| { const abi_size = ty.abiSize(self.target.*); diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index dd297d048d..31e7ea81c8 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -108,9 +108,10 @@ pub fn emitMir( .eor_shifted_register => try emit.mirLogicalShiftedRegister(inst), - .load_memory => try emit.mirLoadMemory(inst), .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), @@ -209,17 +210,9 @@ 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, - .load_memory => { - const load_memory = emit.mir.instructions.items(.data)[inst].load_memory; - const addr = load_memory.addr; - - // movz, [movk, ...], ldr - if (addr <= math.maxInt(u16)) return 2 * 4; - if (addr <= math.maxInt(u32)) return 3 * 4; - if (addr <= math.maxInt(u48)) return 4 * 4; - return 5 * 4; - }, .pop_regs, .push_regs => { const reg_list = emit.mir.instructions.items(.data)[inst].reg_list; const number_of_regs = @popCount(u32, reg_list); @@ -655,21 +648,6 @@ fn mirLogicalShiftedRegister(emit: *Emit, inst: Mir.Inst.Index) !void { } } -fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { - assert(emit.mir.instructions.items(.tag)[inst] == .load_memory); - const load_memory = emit.mir.instructions.items(.data)[inst].load_memory; - const reg = @intToEnum(Register, load_memory.register); - const addr = load_memory.addr; - // The value is in memory at a hard-coded address. - // If the type is a pointer, it means the pointer address is at this memory location. - try emit.moveImmediate(reg, addr); - try emit.writeInstruction(Instruction.ldr( - reg, - reg, - Instruction.LoadStoreOffset.none, - )); -} - fn mirLoadMemoryPie(emit: *Emit, inst: Mir.Inst.Index) !void { const tag = emit.mir.instructions.items(.tag)[inst]; const payload = emit.mir.instructions.items(.data)[inst].payload; @@ -681,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).?; @@ -699,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, }, }); @@ -713,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, }, }); @@ -741,6 +740,7 @@ fn mirLoadStoreRegisterPair(emit: *Emit, inst: Mir.Inst.Index) !void { fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void { const tag = emit.mir.instructions.items(.tag)[inst]; const load_store_stack = emit.mir.instructions.items(.data)[inst].load_store_stack; + const rt = load_store_stack.rt; const raw_offset = emit.stack_size - load_store_stack.offset; const offset = switch (tag) { @@ -760,7 +760,7 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void { } }, .ldr_stack, .str_stack => blk: { - const alignment: u32 = switch (load_store_stack.rt.size()) { + const alignment: u32 = switch (rt.size()) { 32 => 4, 64 => 8, else => unreachable, @@ -777,36 +777,12 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void { }; switch (tag) { - .ldr_stack => try emit.writeInstruction(Instruction.ldr( - load_store_stack.rt, - Register.sp, - offset, - )), - .ldrb_stack => try emit.writeInstruction(Instruction.ldrb( - load_store_stack.rt, - Register.sp, - offset, - )), - .ldrh_stack => try emit.writeInstruction(Instruction.ldrh( - load_store_stack.rt, - Register.sp, - offset, - )), - .str_stack => try emit.writeInstruction(Instruction.str( - load_store_stack.rt, - Register.sp, - offset, - )), - .strb_stack => try emit.writeInstruction(Instruction.strb( - load_store_stack.rt, - Register.sp, - offset, - )), - .strh_stack => try emit.writeInstruction(Instruction.strh( - load_store_stack.rt, - Register.sp, - offset, - )), + .ldr_stack => try emit.writeInstruction(Instruction.ldr(rt, .sp, offset)), + .ldrb_stack => try emit.writeInstruction(Instruction.ldrb(rt, .sp, offset)), + .ldrh_stack => try emit.writeInstruction(Instruction.ldrh(rt, .sp, offset)), + .str_stack => try emit.writeInstruction(Instruction.str(rt, .sp, offset)), + .strb_stack => try emit.writeInstruction(Instruction.strb(rt, .sp, offset)), + .strh_stack => try emit.writeInstruction(Instruction.strh(rt, .sp, offset)), else => unreachable, } } @@ -914,7 +890,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void { if (count == number_of_regs - 1) { try emit.writeInstruction(Instruction.ldr( reg, - Register.sp, + .sp, Instruction.LoadStoreOffset.imm_post_index(16), )); } else { @@ -924,7 +900,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void { try emit.writeInstruction(Instruction.ldp( reg, other_reg, - Register.sp, + .sp, Instruction.LoadStorePairOffset.post_index(16), )); } @@ -944,7 +920,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void { if (count == number_of_regs - 1) { try emit.writeInstruction(Instruction.str( reg, - Register.sp, + .sp, Instruction.LoadStoreOffset.imm_pre_index(-16), )); } else { @@ -954,7 +930,7 @@ fn mirPushPopRegs(emit: *Emit, inst: Mir.Inst.Index) !void { try emit.writeInstruction(Instruction.stp( other_reg, reg, - Register.sp, + .sp, Instruction.LoadStorePairOffset.pre_index(-16), )); } diff --git a/src/arch/aarch64/Mir.zig b/src/arch/aarch64/Mir.zig index 62693f01d7..c2ffbad422 100644 --- a/src/arch/aarch64/Mir.zig +++ b/src/arch/aarch64/Mir.zig @@ -56,14 +56,22 @@ pub const Inst = struct { dbg_line, /// Bitwise Exclusive OR (shifted register) eor_shifted_register, - /// Pseudo-instruction: Load memory + /// Loads the contents into a register /// - /// Payload is `load_memory` - load_memory, /// 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 diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig index 1670f88c76..c427f86472 100644 --- a/src/arch/aarch64/bits.zig +++ b/src/arch/aarch64/bits.zig @@ -1486,19 +1486,19 @@ test "serialize instructions" { .expected = 0b1_00_10000_1111111111111111110_00010, }, .{ // stp x1, x2, [sp, #8] - .inst = Instruction.stp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.signed(8)), + .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)), .expected = 0b10_101_0_010_0_0000001_00010_11111_00001, }, .{ // ldp x1, x2, [sp, #8] - .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.signed(8)), + .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.signed(8)), .expected = 0b10_101_0_010_1_0000001_00010_11111_00001, }, .{ // stp x1, x2, [sp, #-16]! - .inst = Instruction.stp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.pre_index(-16)), + .inst = Instruction.stp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.pre_index(-16)), .expected = 0b10_101_0_011_0_1111110_00010_11111_00001, }, .{ // ldp x1, x2, [sp], #16 - .inst = Instruction.ldp(.x1, .x2, Register.sp, Instruction.LoadStorePairOffset.post_index(16)), + .inst = Instruction.ldp(.x1, .x2, .sp, Instruction.LoadStorePairOffset.post_index(16)), .expected = 0b10_101_0_001_1_0000010_00010_11111_00001, }, .{ // and x0, x4, x2 diff --git a/test/behavior/align.zig b/test/behavior/align.zig index 5518d40756..5a617b84d5 100644 --- a/test/behavior/align.zig +++ b/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 = ¬hing; diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 6c0fbd028a..024e24e400 100644 --- a/test/behavior/basic.zig +++ b/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; diff --git a/test/behavior/bugs/2006.zig b/test/behavior/bugs/2006.zig index 03cef375fe..4d76230c88 100644 --- a/test/behavior/bugs/2006.zig +++ b/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 }; diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig index f5758a3466..980044ebfb 100644 --- a/test/behavior/cast.zig +++ b/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 diff --git a/test/behavior/slice.zig b/test/behavior/slice.zig index d6ab46e757..01d132df54 100644 --- a/test/behavior/slice.zig +++ b/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 { diff --git a/test/behavior/struct.zig b/test/behavior/struct.zig index 99dec11bf9..5f46894fda 100644 --- a/test/behavior/struct.zig +++ b/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);