Commit d9d9fea6ae
Changed files (6)
src
arch
test
behavior
src/arch/aarch64/bits.zig
@@ -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);
}
src/arch/aarch64/CodeGen.zig
@@ -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),
} },
});
src/arch/aarch64/Emit.zig
@@ -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)),
src/arch/aarch64/Mir.zig
@@ -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)
test/behavior/basic.zig
@@ -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);
test/behavior/truncate.zig
@@ -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);