From 7e76aab98abe94e01cfd8b01ce288360ed67dbc7 Mon Sep 17 00:00:00 2001 From: joachimschmidt557 Date: Thu, 13 Jan 2022 17:45:19 +0100 Subject: [PATCH] stage2 AArch64: split ldr/str into {ldr,str}_register and _immediate --- src/arch/aarch64/Emit.zig | 80 ++++++++++++++++---------------- src/arch/aarch64/Mir.zig | 66 ++++++++++++++++----------- src/arch/aarch64/bits.zig | 96 ++++++++++++++++++++------------------- 3 files changed, 132 insertions(+), 110 deletions(-) diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index d51618b2f0..3528bae709 100644 --- a/src/arch/aarch64/Emit.zig +++ b/src/arch/aarch64/Emit.zig @@ -112,12 +112,19 @@ pub fn emitMir( .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), - .str => try emit.mirLoadStoreRegister(inst), - .strb => try emit.mirLoadStoreRegister(inst), - .strh => try emit.mirLoadStoreRegister(inst), + .ldr_register => try emit.mirLoadStoreRegisterRegister(inst), + .ldrb_register => try emit.mirLoadStoreRegisterRegister(inst), + .ldrh_register => try emit.mirLoadStoreRegisterRegister(inst), + .str_register => try emit.mirLoadStoreRegisterRegister(inst), + .strb_register => try emit.mirLoadStoreRegisterRegister(inst), + .strh_register => try emit.mirLoadStoreRegisterRegister(inst), + + .ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst), + .ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst), + .ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst), + .str_immediate => try emit.mirLoadStoreRegisterImmediate(inst), + .strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst), + .strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst), .mov_register => try emit.mirMoveRegister(inst), .mov_to_from_sp => try emit.mirMoveRegister(inst), @@ -737,41 +744,38 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void { } } -fn mirLoadStoreRegister(emit: *Emit, inst: Mir.Inst.Index) !void { +fn mirLoadStoreRegisterImmediate(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; + const load_store_register_immediate = emit.mir.instructions.items(.data)[inst].load_store_register_immediate; + const rt = load_store_register_immediate.rt; + const rn = load_store_register_immediate.rn; + const offset = Instruction.LoadStoreOffset{ .immediate = load_store_register_immediate.offset }; switch (tag) { - .ldr => try emit.writeInstruction(Instruction.ldr( - load_store_register.rt, - load_store_register.rn, - load_store_register.offset, - )), - .ldrb => try emit.writeInstruction(Instruction.ldrb( - load_store_register.rt, - load_store_register.rn, - load_store_register.offset, - )), - .ldrh => try emit.writeInstruction(Instruction.ldrh( - load_store_register.rt, - load_store_register.rn, - load_store_register.offset, - )), - .str => try emit.writeInstruction(Instruction.str( - load_store_register.rt, - load_store_register.rn, - load_store_register.offset, - )), - .strb => try emit.writeInstruction(Instruction.strb( - load_store_register.rt, - load_store_register.rn, - load_store_register.offset, - )), - .strh => try emit.writeInstruction(Instruction.strh( - load_store_register.rt, - load_store_register.rn, - load_store_register.offset, - )), + .ldr_immediate => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)), + .ldrb_immediate => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)), + .ldrh_immediate => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)), + .str_immediate => try emit.writeInstruction(Instruction.str(rt, rn, offset)), + .strb_immediate => try emit.writeInstruction(Instruction.strb(rt, rn, offset)), + .strh_immediate => try emit.writeInstruction(Instruction.strh(rt, rn, offset)), + else => unreachable, + } +} + +fn mirLoadStoreRegisterRegister(emit: *Emit, inst: Mir.Inst.Index) !void { + const tag = emit.mir.instructions.items(.tag)[inst]; + const load_store_register_register = emit.mir.instructions.items(.data)[inst].load_store_register_register; + const rt = load_store_register_register.rt; + const rn = load_store_register_register.rn; + const offset = Instruction.LoadStoreOffset{ .register = load_store_register_register.offset }; + + switch (tag) { + .ldr_register => try emit.writeInstruction(Instruction.ldr(rt, rn, offset)), + .ldrb_register => try emit.writeInstruction(Instruction.ldrb(rt, rn, offset)), + .ldrh_register => try emit.writeInstruction(Instruction.ldrh(rt, rn, offset)), + .str_register => try emit.writeInstruction(Instruction.str(rt, rn, offset)), + .strb_register => try emit.writeInstruction(Instruction.strb(rt, rn, offset)), + .strh_register => try emit.writeInstruction(Instruction.strh(rt, rn, offset)), else => unreachable, } } diff --git a/src/arch/aarch64/Mir.zig b/src/arch/aarch64/Mir.zig index 213dfa7716..5b232a08c0 100644 --- a/src/arch/aarch64/Mir.zig +++ b/src/arch/aarch64/Mir.zig @@ -58,19 +58,22 @@ pub const Inst = struct { ldp, /// Pseudo-instruction: Load from stack ldr_stack, - /// Load Register - // TODO: split into ldr_immediate and ldr_register - ldr, + /// Load Register (immediate) + ldr_immediate, + /// Load Register (register) + ldr_register, /// Pseudo-instruction: Load byte from stack ldrb_stack, - /// Load Register Byte - // TODO: split into ldrb_immediate and ldrb_register - ldrb, + /// Load Register Byte (immediate) + ldrb_immediate, + /// Load Register Byte (register) + ldrb_register, /// Pseudo-instruction: Load halfword from stack ldrh_stack, - /// Load Register Halfword - // TODO: split into ldrh_immediate and ldrh_register - ldrh, + /// Load Register Halfword (immediate) + ldrh_immediate, + /// Load Register Halfword (register) + ldrh_register, /// Move (to/from SP) mov_to_from_sp, /// Move (register) @@ -91,19 +94,22 @@ pub const Inst = struct { stp, /// Pseudo-instruction: Store to stack str_stack, - /// Store Register - // TODO: split into str_immediate and str_register - str, + /// Store Register (immediate) + str_immediate, + /// Store Register (register) + str_register, /// Pseudo-instruction: Store byte to stack strb_stack, - /// Store Register Byte - // TODO: split into strb_immediate and strb_register - strb, + /// Store Register Byte (immediate) + strb_immediate, + /// Store Register Byte (register) + strb_register, /// Pseudo-instruction: Store halfword to stack strh_stack, - /// Store Register Halfword - // TODO: split into strh_immediate and strh_register - strh, + /// Store Register Halfword (immediate) + strh_immediate, + /// Store Register Halfword (register) + strh_register, /// Subtract (immediate) sub_immediate, /// Supervisor Call @@ -195,13 +201,21 @@ pub const Inst = struct { rm: Register, cond: bits.Instruction.Condition, }, - /// Two registers and a LoadStoreOffset + /// Two registers and a LoadStoreOffsetImmediate /// /// Used by e.g. str_register - load_store_register: struct { + load_store_register_immediate: struct { rt: Register, rn: Register, - offset: bits.Instruction.LoadStoreOffset, + offset: bits.Instruction.LoadStoreOffsetImmediate, + }, + /// Two registers and a LoadStoreOffsetRegister + /// + /// Used by e.g. str_register + load_store_register_register: struct { + rt: Register, + rn: Register, + offset: bits.Instruction.LoadStoreOffsetRegister, }, /// A registers and a stack offset /// @@ -230,11 +244,11 @@ pub const Inst = struct { // Make sure we don't accidentally make instructions bigger than expected. // Note that in Debug builds, Zig is allowed to insert a secret field for safety checks. - // comptime { - // if (builtin.mode != .Debug) { - // assert(@sizeOf(Inst) == 8); - // } - // } + comptime { + if (builtin.mode != .Debug) { + assert(@sizeOf(Data) == 8); + } + } }; pub fn deinit(mir: *Mir, gpa: std.mem.Allocator) void { diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig index 97c84f538a..10eb919cb9 100644 --- a/src/arch/aarch64/bits.zig +++ b/src/arch/aarch64/bits.zig @@ -521,69 +521,73 @@ pub const Instruction = union(enum) { }; } + pub const LoadStoreOffsetImmediate = union(enum) { + post_index: i9, + pre_index: i9, + unsigned: u12, + }; + + pub const LoadStoreOffsetRegister = struct { + rm: u5, + shift: union(enum) { + uxtw: u2, + lsl: u2, + sxtw: u2, + sxtx: u2, + }, + }; + /// Represents the offset operand of a load or store instruction. /// Data can be loaded from memory with either an immediate offset /// or an offset that is stored in some register. pub const LoadStoreOffset = union(enum) { - Immediate: union(enum) { - PostIndex: i9, - PreIndex: i9, - Unsigned: u12, - }, - Register: struct { - rm: u5, - shift: union(enum) { - Uxtw: u2, - Lsl: u2, - Sxtw: u2, - Sxtx: u2, - }, - }, + immediate: LoadStoreOffsetImmediate, + register: LoadStoreOffsetRegister, pub const none = LoadStoreOffset{ - .Immediate = .{ .Unsigned = 0 }, + .immediate = .{ .unsigned = 0 }, }; pub fn toU12(self: LoadStoreOffset) u12 { return switch (self) { - .Immediate => |imm_type| switch (imm_type) { - .PostIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1, - .PreIndex => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3, - .Unsigned => |v| v, + .immediate => |imm_type| switch (imm_type) { + .post_index => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 1, + .pre_index => |v| (@intCast(u12, @bitCast(u9, v)) << 2) + 3, + .unsigned => |v| v, }, - .Register => |r| switch (r.shift) { - .Uxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 16 + 2050, - .Lsl => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 24 + 2050, - .Sxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 48 + 2050, - .Sxtx => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 56 + 2050, + .register => |r| switch (r.shift) { + .uxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 16 + 2050, + .lsl => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 24 + 2050, + .sxtw => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 48 + 2050, + .sxtx => |v| (@intCast(u12, r.rm) << 6) + (@intCast(u12, v) << 2) + 56 + 2050, }, }; } pub fn imm(offset: u12) LoadStoreOffset { return .{ - .Immediate = .{ .Unsigned = offset }, + .immediate = .{ .unsigned = offset }, }; } pub fn imm_post_index(offset: i9) LoadStoreOffset { return .{ - .Immediate = .{ .PostIndex = offset }, + .immediate = .{ .post_index = offset }, }; } pub fn imm_pre_index(offset: i9) LoadStoreOffset { return .{ - .Immediate = .{ .PreIndex = offset }, + .immediate = .{ .pre_index = offset }, }; } pub fn reg(rm: Register) LoadStoreOffset { return .{ - .Register = .{ + .register = .{ .rm = rm.id(), .shift = .{ - .Lsl = 0, + .lsl = 0, }, }, }; @@ -592,10 +596,10 @@ pub const Instruction = union(enum) { pub fn reg_uxtw(rm: Register, shift: u2) LoadStoreOffset { assert(rm.size() == 32 and (shift == 0 or shift == 2)); return .{ - .Register = .{ + .register = .{ .rm = rm.id(), .shift = .{ - .Uxtw = shift, + .uxtw = shift, }, }, }; @@ -604,10 +608,10 @@ pub const Instruction = union(enum) { pub fn reg_lsl(rm: Register, shift: u2) LoadStoreOffset { assert(rm.size() == 64 and (shift == 0 or shift == 3)); return .{ - .Register = .{ + .register = .{ .rm = rm.id(), .shift = .{ - .Lsl = shift, + .lsl = shift, }, }, }; @@ -616,10 +620,10 @@ pub const Instruction = union(enum) { pub fn reg_sxtw(rm: Register, shift: u2) LoadStoreOffset { assert(rm.size() == 32 and (shift == 0 or shift == 2)); return .{ - .Register = .{ + .register = .{ .rm = rm.id(), .shift = .{ - .Sxtw = shift, + .sxtw = shift, }, }, }; @@ -628,10 +632,10 @@ pub const Instruction = union(enum) { pub fn reg_sxtx(rm: Register, shift: u2) LoadStoreOffset { assert(rm.size() == 64 and (shift == 0 or shift == 3)); return .{ - .Register = .{ + .register = .{ .rm = rm.id(), .shift = .{ - .Sxtx = shift, + .sxtx = shift, }, }, }; @@ -663,8 +667,8 @@ pub const Instruction = union(enum) { const off = offset.toU12(); const op1: u2 = blk: { switch (offset) { - .Immediate => |imm| switch (imm) { - .Unsigned => break :blk 0b01, + .immediate => |imm| switch (imm) { + .unsigned => break :blk 0b01, else => {}, }, else => {}, @@ -1023,26 +1027,26 @@ pub const Instruction = union(enum) { pub const LoadStorePairOffset = struct { encoding: enum(u2) { - PostIndex = 0b01, - Signed = 0b10, - PreIndex = 0b11, + post_index = 0b01, + signed = 0b10, + pre_index = 0b11, }, offset: i9, pub fn none() LoadStorePairOffset { - return .{ .encoding = .Signed, .offset = 0 }; + return .{ .encoding = .signed, .offset = 0 }; } pub fn post_index(imm: i9) LoadStorePairOffset { - return .{ .encoding = .PostIndex, .offset = imm }; + return .{ .encoding = .post_index, .offset = imm }; } pub fn pre_index(imm: i9) LoadStorePairOffset { - return .{ .encoding = .PreIndex, .offset = imm }; + return .{ .encoding = .pre_index, .offset = imm }; } pub fn signed(imm: i9) LoadStorePairOffset { - return .{ .encoding = .Signed, .offset = imm }; + return .{ .encoding = .signed, .offset = imm }; } };