stage2 AArch64: split ldr/str into {ldr,str}_register and _immediate

This commit is contained in:
joachimschmidt557 2022-01-13 17:45:19 +01:00 committed by Jakub Konka
parent e945619728
commit 7e76aab98a
3 changed files with 132 additions and 110 deletions

View File

@ -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,
}
}

View File

@ -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 {

View File

@ -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 };
}
};