stage2 AArch64: Add ldrsb, ldrsh instructions
This commit is contained in:
parent
f95a8ddafa
commit
d9d9fea6ae
|
@ -2056,7 +2056,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
|
|||
.undef => unreachable,
|
||||
.compare_flags_signed, .compare_flags_unsigned => unreachable,
|
||||
.register => |dst_reg| {
|
||||
try self.genLdrRegister(dst_reg, addr_reg, elem_size);
|
||||
try self.genLdrRegister(dst_reg, addr_reg, elem_ty);
|
||||
},
|
||||
.stack_offset => |off| {
|
||||
if (elem_size <= 8) {
|
||||
|
@ -2210,98 +2210,47 @@ fn airLoad(self: *Self, inst: Air.Inst.Index) !void {
|
|||
return self.finishAir(inst, result, .{ ty_op.operand, .none, .none });
|
||||
}
|
||||
|
||||
fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
|
||||
switch (abi_size) {
|
||||
1 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .ldrb_immediate,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg.to32(),
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
},
|
||||
2 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .ldrh_immediate,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg.to32(),
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
},
|
||||
4 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .ldr_immediate,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg.to32(),
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
},
|
||||
8 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .ldr_immediate,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg.to64(),
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
},
|
||||
fn genLdrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void {
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
|
||||
const tag: Mir.Inst.Tag = switch (abi_size) {
|
||||
1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_immediate else .ldrb_immediate,
|
||||
2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_immediate else .ldrh_immediate,
|
||||
4 => .ldr_immediate,
|
||||
8 => .ldr_immediate,
|
||||
3, 5, 6, 7 => return self.fail("TODO: genLdrRegister for more abi_sizes", .{}),
|
||||
else => unreachable,
|
||||
}
|
||||
};
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = tag,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg,
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, abi_size: u64) !void {
|
||||
switch (abi_size) {
|
||||
1 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .strb_immediate,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg.to32(),
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
},
|
||||
2 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .strh_immediate,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg.to32(),
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
},
|
||||
4 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .str_immediate,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg.to32(),
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
},
|
||||
8 => {
|
||||
_ = try self.addInst(.{
|
||||
.tag = .str_immediate,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg.to64(),
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
},
|
||||
fn genStrRegister(self: *Self, value_reg: Register, addr_reg: Register, ty: Type) !void {
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
|
||||
const tag: Mir.Inst.Tag = switch (abi_size) {
|
||||
1 => .strb_immediate,
|
||||
2 => .strh_immediate,
|
||||
4, 8 => .str_immediate,
|
||||
3, 5, 6, 7 => return self.fail("TODO: genStrRegister for more abi_sizes", .{}),
|
||||
else => unreachable,
|
||||
}
|
||||
};
|
||||
|
||||
_ = try self.addInst(.{
|
||||
.tag = tag,
|
||||
.data = .{ .load_store_register_immediate = .{
|
||||
.rt = value_reg,
|
||||
.rn = addr_reg,
|
||||
.offset = Instruction.LoadStoreOffset.none.immediate,
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type) InnerError!void {
|
||||
|
@ -2326,7 +2275,7 @@ fn store(self: *Self, ptr: MCValue, value: MCValue, ptr_ty: Type, value_ty: Type
|
|||
|
||||
switch (value) {
|
||||
.register => |value_reg| {
|
||||
try self.genStrRegister(value_reg, addr_reg, abi_size);
|
||||
try self.genStrRegister(value_reg, addr_reg, value_ty);
|
||||
},
|
||||
else => {
|
||||
if (abi_size <= 8) {
|
||||
|
@ -3624,7 +3573,7 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
|||
// 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.to64(), .{ .immediate = addr });
|
||||
try self.genLdrRegister(reg, reg.to64(), ty.abiSize(self.target.*));
|
||||
try self.genLdrRegister(reg, reg.to64(), ty);
|
||||
},
|
||||
.stack_offset => |off| {
|
||||
const abi_size = ty.abiSize(self.target.*);
|
||||
|
@ -3632,21 +3581,16 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
|
|||
switch (abi_size) {
|
||||
1, 2, 4, 8 => {
|
||||
const tag: Mir.Inst.Tag = switch (abi_size) {
|
||||
1 => .ldrb_stack,
|
||||
2 => .ldrh_stack,
|
||||
1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack else .ldrb_stack,
|
||||
2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack else .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_stack = .{
|
||||
.rt = rt,
|
||||
.rt = reg,
|
||||
.offset = @intCast(u32, off),
|
||||
} },
|
||||
});
|
||||
|
|
|
@ -131,6 +131,8 @@ pub fn emitMir(
|
|||
.ldr_stack => try emit.mirLoadStoreStack(inst),
|
||||
.ldrb_stack => try emit.mirLoadStoreStack(inst),
|
||||
.ldrh_stack => try emit.mirLoadStoreStack(inst),
|
||||
.ldrsb_stack => try emit.mirLoadStoreStack(inst),
|
||||
.ldrsh_stack => try emit.mirLoadStoreStack(inst),
|
||||
.str_stack => try emit.mirLoadStoreStack(inst),
|
||||
.strb_stack => try emit.mirLoadStoreStack(inst),
|
||||
.strh_stack => try emit.mirLoadStoreStack(inst),
|
||||
|
@ -145,6 +147,9 @@ pub fn emitMir(
|
|||
.ldr_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
.ldrb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
.ldrh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
.ldrsb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
.ldrsh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
.ldrsw_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
.str_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
.strb_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
.strh_immediate => try emit.mirLoadStoreRegisterImmediate(inst),
|
||||
|
@ -847,14 +852,14 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
|
|||
|
||||
const raw_offset = emit.stack_size - load_store_stack.offset;
|
||||
const offset = switch (tag) {
|
||||
.ldrb_stack, .strb_stack => blk: {
|
||||
.ldrb_stack, .ldrsb_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: {
|
||||
.ldrh_stack, .ldrsh_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);
|
||||
|
@ -883,6 +888,8 @@ fn mirLoadStoreStack(emit: *Emit, inst: Mir.Inst.Index) !void {
|
|||
.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)),
|
||||
.ldrsb_stack => try emit.writeInstruction(Instruction.ldrsb(rt, .sp, offset)),
|
||||
.ldrsh_stack => try emit.writeInstruction(Instruction.ldrsh(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)),
|
||||
|
@ -901,6 +908,9 @@ fn mirLoadStoreRegisterImmediate(emit: *Emit, inst: Mir.Inst.Index) !void {
|
|||
.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)),
|
||||
.ldrsb_immediate => try emit.writeInstruction(Instruction.ldrsb(rt, rn, offset)),
|
||||
.ldrsh_immediate => try emit.writeInstruction(Instruction.ldrsh(rt, rn, offset)),
|
||||
.ldrsw_immediate => try emit.writeInstruction(Instruction.ldrsw(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)),
|
||||
|
|
|
@ -100,6 +100,16 @@ pub const Inst = struct {
|
|||
ldrh_immediate,
|
||||
/// Load Register Halfword (register)
|
||||
ldrh_register,
|
||||
/// Load Register Signed Byte (immediate)
|
||||
ldrsb_immediate,
|
||||
/// Pseudo-instruction: Load signed byte from stack
|
||||
ldrsb_stack,
|
||||
/// Load Register Signed Halfword (immediate)
|
||||
ldrsh_immediate,
|
||||
/// Pseudo-instruction: Load signed halfword from stack
|
||||
ldrsh_stack,
|
||||
/// Load Register Signed Word (immediate)
|
||||
ldrsw_immediate,
|
||||
/// Logical Shift Left (immediate)
|
||||
lsl_immediate,
|
||||
/// Logical Shift Left (register)
|
||||
|
|
|
@ -665,18 +665,24 @@ pub const Instruction = union(enum) {
|
|||
|
||||
/// Which kind of load/store to perform
|
||||
const LoadStoreVariant = enum {
|
||||
/// 32-bit or 64-bit
|
||||
/// 32 bits or 64 bits
|
||||
str,
|
||||
/// 16-bit, zero-extended
|
||||
strh,
|
||||
/// 8-bit, zero-extended
|
||||
/// 8 bits, zero-extended
|
||||
strb,
|
||||
/// 32-bit or 64-bit
|
||||
/// 16 bits, zero-extended
|
||||
strh,
|
||||
/// 32 bits or 64 bits
|
||||
ldr,
|
||||
/// 16-bit, zero-extended
|
||||
ldrh,
|
||||
/// 8-bit, zero-extended
|
||||
/// 8 bits, zero-extended
|
||||
ldrb,
|
||||
/// 16 bits, zero-extended
|
||||
ldrh,
|
||||
/// 8 bits, sign extended
|
||||
ldrsb,
|
||||
/// 16 bits, sign extended
|
||||
ldrsh,
|
||||
/// 32 bits, sign extended
|
||||
ldrsw,
|
||||
};
|
||||
|
||||
fn loadStoreRegister(
|
||||
|
@ -689,6 +695,7 @@ pub const Instruction = union(enum) {
|
|||
assert(rn.id() != Register.xzr.id());
|
||||
|
||||
const off = offset.toU12();
|
||||
|
||||
const op1: u2 = blk: {
|
||||
switch (offset) {
|
||||
.immediate => |imm| switch (imm) {
|
||||
|
@ -699,10 +706,35 @@ pub const Instruction = union(enum) {
|
|||
}
|
||||
break :blk 0b00;
|
||||
};
|
||||
const opc: u2 = switch (variant) {
|
||||
.ldr, .ldrh, .ldrb => 0b01,
|
||||
.str, .strh, .strb => 0b00,
|
||||
|
||||
const opc: u2 = blk: {
|
||||
switch (variant) {
|
||||
.ldr, .ldrh, .ldrb => break :blk 0b01,
|
||||
.str, .strh, .strb => break :blk 0b00,
|
||||
.ldrsb,
|
||||
.ldrsh,
|
||||
=> switch (rt.size()) {
|
||||
32 => break :blk 0b11,
|
||||
64 => break :blk 0b10,
|
||||
else => unreachable, // unexpected register size
|
||||
},
|
||||
.ldrsw => break :blk 0b10,
|
||||
}
|
||||
};
|
||||
|
||||
const size: u2 = blk: {
|
||||
switch (variant) {
|
||||
.ldr, .str => switch (rt.size()) {
|
||||
32 => break :blk 0b10,
|
||||
64 => break :blk 0b11,
|
||||
else => unreachable, // unexpected register size
|
||||
},
|
||||
.ldrsw => break :blk 0b10,
|
||||
.ldrh, .ldrsh, .strh => break :blk 0b01,
|
||||
.ldrb, .ldrsb, .strb => break :blk 0b00,
|
||||
}
|
||||
};
|
||||
|
||||
return Instruction{
|
||||
.load_store_register = .{
|
||||
.rt = rt.enc(),
|
||||
|
@ -711,17 +743,7 @@ pub const Instruction = union(enum) {
|
|||
.opc = opc,
|
||||
.op1 = op1,
|
||||
.v = 0,
|
||||
.size = blk: {
|
||||
switch (variant) {
|
||||
.ldr, .str => switch (rt.size()) {
|
||||
32 => break :blk 0b10,
|
||||
64 => break :blk 0b11,
|
||||
else => unreachable, // unexpected register size
|
||||
},
|
||||
.ldrh, .strh => break :blk 0b01,
|
||||
.ldrb, .strb => break :blk 0b00,
|
||||
}
|
||||
},
|
||||
.size = size,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
@ -1150,6 +1172,18 @@ pub const Instruction = union(enum) {
|
|||
return loadStoreRegister(rt, rn, offset, .ldrb);
|
||||
}
|
||||
|
||||
pub fn ldrsb(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
|
||||
return loadStoreRegister(rt, rn, offset, .ldrsb);
|
||||
}
|
||||
|
||||
pub fn ldrsh(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
|
||||
return loadStoreRegister(rt, rn, offset, .ldrsh);
|
||||
}
|
||||
|
||||
pub fn ldrsw(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
|
||||
return loadStoreRegister(rt, rn, offset, .ldrsw);
|
||||
}
|
||||
|
||||
pub fn str(rt: Register, rn: Register, offset: LoadStoreOffset) Instruction {
|
||||
return loadStoreRegister(rt, rn, offset, .str);
|
||||
}
|
||||
|
|
|
@ -23,8 +23,6 @@ fn testTruncate(x: u32) u8 {
|
|||
}
|
||||
|
||||
test "truncate to non-power-of-two integers" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
try testTrunc(u32, u1, 0b10101, 0b1);
|
||||
try testTrunc(u32, u1, 0b10110, 0b0);
|
||||
try testTrunc(u32, u2, 0b10101, 0b01);
|
||||
|
|
|
@ -49,8 +49,6 @@ test "truncate.i0.var" {
|
|||
}
|
||||
|
||||
test "truncate on comptime integer" {
|
||||
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
|
||||
|
||||
var x = @truncate(u16, 9999);
|
||||
try expect(x == 9999);
|
||||
var y = @truncate(u16, -21555);
|
||||
|
|
Loading…
Reference in New Issue
Block a user