mirror of
https://github.com/ziglang/zig.git
synced 2025-12-25 15:43:06 +00:00
stage2 AArch64: split ldr/str into {ldr,str}_register and _immediate
This commit is contained in:
parent
e945619728
commit
7e76aab98a
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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 };
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user