diff options
| author | Jakub Konka <kubkon@jakubkonka.com> | 2021-11-13 06:17:08 -0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-11-13 06:17:08 -0800 |
| commit | d3a099c14fe9b7b575a0cd7bb9cd05b49625a71e (patch) | |
| tree | a7ba0e0d9771c6a83493dd0feb931723a1ad2256 /src | |
| parent | 71388b980bfc4c7eb267ed7c168c2395098f6db2 (diff) | |
| parent | 96e715d5a3a5e75e691bedd6a2dcebffc09639bb (diff) | |
| download | zig-d3a099c14fe9b7b575a0cd7bb9cd05b49625a71e.tar.gz zig-d3a099c14fe9b7b575a0cd7bb9cd05b49625a71e.zip | |
Merge pull request #10142 from joachimschmidt557/stage2-aarch64
stage2 AArch64: fix loading/storing to/from stack
Diffstat (limited to 'src')
| -rw-r--r-- | src/arch/aarch64/CodeGen.zig | 62 | ||||
| -rw-r--r-- | src/arch/aarch64/Emit.zig | 109 | ||||
| -rw-r--r-- | src/arch/aarch64/Mir.zig | 21 | ||||
| -rw-r--r-- | src/arch/aarch64/bits.zig | 93 | ||||
| -rw-r--r-- | src/link/MachO.zig | 29 |
5 files changed, 190 insertions, 124 deletions
diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 994b9a9939..010588f6cf 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -302,6 +302,7 @@ pub fn generate( .prev_di_pc = 0, .prev_di_line = module_fn.lbrace_line, .prev_di_column = module_fn.lbrace_column, + .stack_size = mem.alignForwardGeneric(u32, function.max_end_stack, function.stack_align), }; defer emit.deinit(); @@ -1346,9 +1347,7 @@ fn airArg(self: *Self, inst: Air.Inst.Index) !void { const stack_offset = try self.allocMem(inst, abi_size, abi_align); try self.genSetStack(ty, stack_offset, MCValue{ .register = reg }); - // TODO correct loading and storing from memory - // break :blk MCValue{ .stack_offset = stack_offset }; - break :blk result; + break :blk MCValue{ .stack_offset = stack_offset }; }, else => result, }; @@ -2261,28 +2260,23 @@ fn genSetStack(self: *Self, ty: Type, stack_offset: u32, mcv: MCValue) InnerErro switch (abi_size) { 1, 2, 4, 8 => { - const offset = if (math.cast(i9, adj_off)) |imm| - Instruction.LoadStoreOffset.imm_post_index(-imm) - else |_| - Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u64), MCValue{ .immediate = adj_off })); - const rn: Register = switch (self.target.cpu.arch) { - .aarch64, .aarch64_be => .x29, - .aarch64_32 => .w29, - else => unreachable, - }; const tag: Mir.Inst.Tag = switch (abi_size) { - 1 => .strb, - 2 => .strh, - 4, 8 => .str, + 1 => .strb_stack, + 2 => .strh_stack, + 4, 8 => .str_stack, + else => unreachable, // unexpected abi size + }; + const rt: Register = switch (abi_size) { + 1, 2, 4 => reg.to32(), + 8 => reg.to64(), else => unreachable, // unexpected abi size }; _ = try self.addInst(.{ .tag = tag, - .data = .{ .load_store_register = .{ - .rt = reg, - .rn = rn, - .offset = offset, + .data = .{ .load_store_stack = .{ + .rt = rt, + .offset = @intCast(u32, adj_off), } }, }); }, @@ -2384,36 +2378,28 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void }); }, .stack_offset => |unadjusted_off| { - // TODO: maybe addressing from sp instead of fp const abi_size = ty.abiSize(self.target.*); const adj_off = unadjusted_off + abi_size; - const rn: Register = switch (self.target.cpu.arch) { - .aarch64, .aarch64_be => .x29, - .aarch64_32 => .w29, - else => unreachable, - }; - - const offset = if (math.cast(i9, adj_off)) |imm| - Instruction.LoadStoreOffset.imm_post_index(-imm) - else |_| - Instruction.LoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u64), MCValue{ .immediate = adj_off })); - switch (abi_size) { 1, 2, 4, 8 => { const tag: Mir.Inst.Tag = switch (abi_size) { - 1 => .ldrb, - 2 => .ldrh, - 4, 8 => .ldr, + 1 => .ldrb_stack, + 2 => .ldrh_stack, + 4, 8 => .ldr_stack, + else => unreachable, // unexpected abi size + }; + const rt: Register = switch (abi_size) { + 1, 2, 4 => reg.to32(), + 8 => reg.to64(), else => unreachable, // unexpected abi size }; _ = try self.addInst(.{ .tag = tag, - .data = .{ .load_store_register = .{ - .rt = reg, - .rn = rn, - .offset = offset, + .data = .{ .load_store_stack = .{ + .rt = rt, + .offset = @intCast(u32, adj_off), } }, }); }, diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index ff619cd71c..a470cefc64 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -42,6 +42,8 @@ branch_forward_origins: std.AutoHashMapUnmanaged(Mir.Inst.Index, std.ArrayListUn /// instruction code_offset_mapping: std.AutoHashMapUnmanaged(Mir.Inst.Index, usize) = .{}, +stack_size: u32, + const InnerError = error{ OutOfMemory, EmitFail, @@ -103,6 +105,13 @@ pub fn emitMir( .ldp => try emit.mirLoadStoreRegisterPair(inst), .stp => try emit.mirLoadStoreRegisterPair(inst), + .ldr_stack => try emit.mirLoadStoreStack(inst), + .ldrb_stack => try emit.mirLoadStoreStack(inst), + .ldrh_stack => try emit.mirLoadStoreStack(inst), + .str_stack => try emit.mirLoadStoreStack(inst), + .strb_stack => try emit.mirLoadStoreStack(inst), + .strh_stack => try emit.mirLoadStoreStack(inst), + .ldr => try emit.mirLoadStoreRegister(inst), .ldrb => try emit.mirLoadStoreRegister(inst), .ldrh => try emit.mirLoadStoreRegister(inst), @@ -587,12 +596,11 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { try emit.writeInstruction(Instruction.adrp(reg, 0)); // ldr reg, reg, offset - try emit.writeInstruction(Instruction.ldr(reg, .{ - .register = .{ - .rn = reg, - .offset = Instruction.LoadStoreOffset.imm(0), - }, - })); + try emit.writeInstruction(Instruction.ldr( + reg, + reg, + Instruction.LoadStoreOffset.imm(0), + )); if (emit.bin_file.cast(link.File.MachO)) |macho_file| { // TODO I think the reloc might be in the wrong place. @@ -626,7 +634,8 @@ fn mirLoadMemory(emit: *Emit, inst: Mir.Inst.Index) !void { try emit.moveImmediate(reg, addr); try emit.writeInstruction(Instruction.ldr( reg, - .{ .register = .{ .rn = reg, .offset = Instruction.LoadStoreOffset.none } }, + reg, + Instruction.LoadStoreOffset.none, )); } } @@ -652,6 +661,79 @@ 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 raw_offset = emit.stack_size - load_store_stack.offset; + const offset = switch (tag) { + .ldrb_stack, .strb_stack => blk: { + if (math.cast(u12, raw_offset)) |imm| { + break :blk Instruction.LoadStoreOffset.imm(imm); + } else |_| { + return emit.fail("TODO load/store stack byte with larger offset", .{}); + } + }, + .ldrh_stack, .strh_stack => blk: { + assert(std.mem.isAlignedGeneric(u32, raw_offset, 2)); // misaligned stack entry + if (math.cast(u12, @divExact(raw_offset, 2))) |imm| { + break :blk Instruction.LoadStoreOffset.imm(imm); + } else |_| { + return emit.fail("TODO load/store stack halfword with larger offset", .{}); + } + }, + .ldr_stack, .str_stack => blk: { + const alignment: u32 = switch (load_store_stack.rt.size()) { + 32 => 4, + 64 => 8, + else => unreachable, + }; + + assert(std.mem.isAlignedGeneric(u32, raw_offset, alignment)); // misaligned stack entry + if (math.cast(u12, @divExact(raw_offset, alignment))) |imm| { + break :blk Instruction.LoadStoreOffset.imm(imm); + } else |_| { + return emit.fail("TODO load/store stack with larger offset", .{}); + } + }, + else => unreachable, + }; + + 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, + )), + else => unreachable, + } +} + fn mirLoadStoreRegister(emit: *Emit, inst: Mir.Inst.Index) !void { const tag = emit.mir.instructions.items(.tag)[inst]; const load_store_register = emit.mir.instructions.items(.data)[inst].load_store_register; @@ -659,32 +741,33 @@ fn mirLoadStoreRegister(emit: *Emit, inst: Mir.Inst.Index) !void { switch (tag) { .ldr => try emit.writeInstruction(Instruction.ldr( load_store_register.rt, - .{ .register = .{ .rn = load_store_register.rn, .offset = load_store_register.offset } }, + load_store_register.rn, + load_store_register.offset, )), .ldrb => try emit.writeInstruction(Instruction.ldrb( load_store_register.rt, load_store_register.rn, - .{ .offset = load_store_register.offset }, + load_store_register.offset, )), .ldrh => try emit.writeInstruction(Instruction.ldrh( load_store_register.rt, load_store_register.rn, - .{ .offset = load_store_register.offset }, + load_store_register.offset, )), .str => try emit.writeInstruction(Instruction.str( load_store_register.rt, load_store_register.rn, - .{ .offset = load_store_register.offset }, + load_store_register.offset, )), .strb => try emit.writeInstruction(Instruction.strb( load_store_register.rt, load_store_register.rn, - .{ .offset = load_store_register.offset }, + load_store_register.offset, )), .strh => try emit.writeInstruction(Instruction.strh( load_store_register.rt, load_store_register.rn, - .{ .offset = load_store_register.offset }, + load_store_register.offset, )), else => unreachable, } diff --git a/src/arch/aarch64/Mir.zig b/src/arch/aarch64/Mir.zig index de8415c1e8..5035b80304 100644 --- a/src/arch/aarch64/Mir.zig +++ b/src/arch/aarch64/Mir.zig @@ -56,12 +56,18 @@ pub const Inst = struct { load_memory, /// Load Pair of Registers ldp, + /// Pseudo-instruction: Load from stack + ldr_stack, /// Load Register // TODO: split into ldr_immediate and ldr_register ldr, + /// Pseudo-instruction: Load byte from stack + ldrb_stack, /// Load Register Byte // TODO: split into ldrb_immediate and ldrb_register ldrb, + /// Pseudo-instruction: Load halfword from stack + ldrh_stack, /// Load Register Halfword // TODO: split into ldrh_immediate and ldrh_register ldrh, @@ -79,12 +85,18 @@ pub const Inst = struct { ret, /// Store Pair of Registers stp, + /// Pseudo-instruction: Store to stack + str_stack, /// Store Register // TODO: split into str_immediate and str_register str, + /// Pseudo-instruction: Store byte to stack + strb_stack, /// Store Register Byte // TODO: split into strb_immediate and strb_register strb, + /// Pseudo-instruction: Store halfword to stack + strh_stack, /// Store Register Halfword // TODO: split into strh_immediate and strh_register strh, @@ -175,7 +187,7 @@ pub const Inst = struct { rm: Register, cond: bits.Instruction.Condition, }, - /// Three registers and a LoadStoreOffset + /// Two registers and a LoadStoreOffset /// /// Used by e.g. str_register load_store_register: struct { @@ -183,6 +195,13 @@ pub const Inst = struct { rn: Register, offset: bits.Instruction.LoadStoreOffset, }, + /// A registers and a stack offset + /// + /// Used by e.g. str_register + load_store_stack: struct { + rt: Register, + offset: u32, + }, /// Three registers and a LoadStorePairOffset /// /// Used by e.g. stp diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig index 26974a3b6a..97c84f538a 100644 --- a/src/arch/aarch64/bits.zig +++ b/src/arch/aarch64/bits.zig @@ -742,27 +742,17 @@ pub const Instruction = union(enum) { } fn loadLiteral(rt: Register, imm19: u19) Instruction { - switch (rt.size()) { - 32 => { - return Instruction{ - .load_literal = .{ - .rt = rt.id(), - .imm19 = imm19, - .opc = 0b00, - }, - }; - }, - 64 => { - return Instruction{ - .load_literal = .{ - .rt = rt.id(), - .imm19 = imm19, - .opc = 0b01, - }, - }; + return Instruction{ + .load_literal = .{ + .rt = rt.id(), + .imm19 = imm19, + .opc = switch (rt.size()) { + 32 => 0b00, + 64 => 0b01, + else => unreachable, // unexpected register size + }, }, - else => unreachable, // unexpected register size - } + }; } fn exceptionGeneration( @@ -1001,43 +991,32 @@ pub const Instruction = union(enum) { // Load or store register - pub const LdrArgs = union(enum) { - register: struct { - rn: Register, - offset: LoadStoreOffset = LoadStoreOffset.none, - }, - literal: u19, - }; - - pub fn ldr(rt: Register, args: LdrArgs) Instruction { - switch (args) { - .register => |info| return loadStoreRegister(rt, info.rn, info.offset, .ldr), - .literal => |literal| return loadLiteral(rt, literal), - } + pub fn ldrLiteral(rt: Register, literal: u19) Instruction { + return loadLiteral(rt, literal); } - pub fn ldrh(rt: Register, rn: Register, args: StrArgs) Instruction { - return loadStoreRegister(rt, rn, args.offset, .ldrh); + pub fn ldr(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { + return loadStoreRegister(rt, rn, offset, .ldr); } - pub fn ldrb(rt: Register, rn: Register, args: StrArgs) Instruction { - return loadStoreRegister(rt, rn, args.offset, .ldrb); + pub fn ldrh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { + return loadStoreRegister(rt, rn, offset, .ldrh); } - pub const StrArgs = struct { - offset: LoadStoreOffset = LoadStoreOffset.none, - }; + pub fn ldrb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { + return loadStoreRegister(rt, rn, offset, .ldrb); + } - pub fn str(rt: Register, rn: Register, args: StrArgs) Instruction { - return loadStoreRegister(rt, rn, args.offset, .str); + pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { + return loadStoreRegister(rt, rn, offset, .str); } - pub fn strh(rt: Register, rn: Register, args: StrArgs) Instruction { - return loadStoreRegister(rt, rn, args.offset, .strh); + pub fn strh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { + return loadStoreRegister(rt, rn, offset, .strh); } - pub fn strb(rt: Register, rn: Register, args: StrArgs) Instruction { - return loadStoreRegister(rt, rn, args.offset, .strb); + pub fn strb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction { + return loadStoreRegister(rt, rn, offset, .strb); } // Load or store pair of registers @@ -1324,47 +1303,47 @@ test "serialize instructions" { .expected = 0b1_00101_00_0000_0000_0000_0000_0000_0100, }, .{ // ldr x2, [x1] - .inst = Instruction.ldr(.x2, .{ .register = .{ .rn = .x1 } }), + .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.none), .expected = 0b11_111_0_01_01_000000000000_00001_00010, }, .{ // ldr x2, [x1, #1]! - .inst = Instruction.ldr(.x2, .{ .register = .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.imm_pre_index(1) } }), + .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_pre_index(1)), .expected = 0b11_111_0_00_01_0_000000001_11_00001_00010, }, .{ // ldr x2, [x1], #-1 - .inst = Instruction.ldr(.x2, .{ .register = .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.imm_post_index(-1) } }), + .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.imm_post_index(-1)), .expected = 0b11_111_0_00_01_0_111111111_01_00001_00010, }, .{ // ldr x2, [x1], (x3) - .inst = Instruction.ldr(.x2, .{ .register = .{ .rn = .x1, .offset = Instruction.LoadStoreOffset.reg(.x3) } }), + .inst = Instruction.ldr(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)), .expected = 0b11_111_0_00_01_1_00011_011_0_10_00001_00010, }, .{ // ldr x2, label - .inst = Instruction.ldr(.x2, .{ .literal = 0x1 }), + .inst = Instruction.ldrLiteral(.x2, 0x1), .expected = 0b01_011_0_00_0000000000000000001_00010, }, .{ // ldrh x7, [x4], #0xaa - .inst = Instruction.ldrh(.x7, .x4, .{ .offset = Instruction.LoadStoreOffset.imm_post_index(0xaa) }), + .inst = Instruction.ldrh(.x7, .x4, Instruction.LoadStoreOffset.imm_post_index(0xaa)), .expected = 0b01_111_0_00_01_0_010101010_01_00100_00111, }, .{ // ldrb x9, [x15, #0xff]! - .inst = Instruction.ldrb(.x9, .x15, .{ .offset = Instruction.LoadStoreOffset.imm_pre_index(0xff) }), + .inst = Instruction.ldrb(.x9, .x15, Instruction.LoadStoreOffset.imm_pre_index(0xff)), .expected = 0b00_111_0_00_01_0_011111111_11_01111_01001, }, .{ // str x2, [x1] - .inst = Instruction.str(.x2, .x1, .{}), + .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.none), .expected = 0b11_111_0_01_00_000000000000_00001_00010, }, .{ // str x2, [x1], (x3) - .inst = Instruction.str(.x2, .x1, .{ .offset = Instruction.LoadStoreOffset.reg(.x3) }), + .inst = Instruction.str(.x2, .x1, Instruction.LoadStoreOffset.reg(.x3)), .expected = 0b11_111_0_00_00_1_00011_011_0_10_00001_00010, }, .{ // strh w0, [x1] - .inst = Instruction.strh(.w0, .x1, .{}), + .inst = Instruction.strh(.w0, .x1, Instruction.LoadStoreOffset.none), .expected = 0b01_111_0_01_00_000000000000_00001_00000, }, .{ // strb w8, [x9] - .inst = Instruction.strb(.w8, .x9, .{}), + .inst = Instruction.strb(.w8, .x9, Instruction.LoadStoreOffset.none), .expected = 0b00_111_0_01_00_000000000000_01001_01000, }, .{ // adr x2, #0x8 diff --git a/src/link/MachO.zig b/src/link/MachO.zig index 93db2b81eb..1f690d1985 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -2041,12 +2041,11 @@ fn createStubHelperPreambleAtom(self: *MachO) !void { .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_GOT_LOAD_PAGE21), }); // ldr x16, [x16, 0] - mem.writeIntLittle(u32, atom.code.items[16..][0..4], aarch64.Instruction.ldr(.x16, .{ - .register = .{ - .rn = .x16, - .offset = aarch64.Instruction.LoadStoreOffset.imm(0), - }, - }).toU32()); + mem.writeIntLittle(u32, atom.code.items[16..][0..4], aarch64.Instruction.ldr( + .x16, + .x16, + aarch64.Instruction.LoadStoreOffset.imm(0), + ).toU32()); atom.relocs.appendAssumeCapacity(.{ .offset = 16, .target = .{ .global = self.undefs.items[self.dyld_stub_binder_index.?].n_strx }, @@ -2119,9 +2118,10 @@ pub fn createStubHelperAtom(self: *MachO) !*Atom { break :blk try math.cast(u18, div_res); }; // ldr w16, literal - mem.writeIntLittle(u32, atom.code.items[0..4], aarch64.Instruction.ldr(.w16, .{ - .literal = literal, - }).toU32()); + mem.writeIntLittle(u32, atom.code.items[0..4], aarch64.Instruction.ldrLiteral( + .w16, + literal, + ).toU32()); // b disp mem.writeIntLittle(u32, atom.code.items[4..8], aarch64.Instruction.b(0).toU32()); atom.relocs.appendAssumeCapacity(.{ @@ -2222,12 +2222,11 @@ pub fn createStubAtom(self: *MachO, laptr_sym_index: u32) !*Atom { .@"type" = @enumToInt(macho.reloc_type_arm64.ARM64_RELOC_PAGE21), }); // ldr x16, x16, offset - mem.writeIntLittle(u32, atom.code.items[4..8], aarch64.Instruction.ldr(.x16, .{ - .register = .{ - .rn = .x16, - .offset = aarch64.Instruction.LoadStoreOffset.imm(0), - }, - }).toU32()); + mem.writeIntLittle(u32, atom.code.items[4..8], aarch64.Instruction.ldr( + .x16, + .x16, + aarch64.Instruction.LoadStoreOffset.imm(0), + ).toU32()); atom.relocs.appendAssumeCapacity(.{ .offset = 4, .target = .{ .local = laptr_sym_index }, |
