Commit f48f4baf67
Changed files (6)
src
test
behavior
src/arch/arm/bits.zig
@@ -1123,11 +1123,19 @@ pub const Instruction = union(enum) {
};
pub fn strh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
- return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0, 0b01, rn, rt, args.offset);
+ return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b0, 0b01, rn, rt, args.offset);
}
pub fn ldrh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
- return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 1, 0b01, rn, rt, args.offset);
+ return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b01, rn, rt, args.offset);
+ }
+
+ pub fn ldrsh(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
+ return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b11, rn, rt, args.offset);
+ }
+
+ pub fn ldrsb(cond: Condition, rt: Register, rn: Register, args: ExtraLoadStoreOffsetArgs) Instruction {
+ return extraLoadStore(cond, args.pre_index, args.positive, args.write_back, 0b1, 0b10, rn, rt, args.offset);
}
// Block data transfer
src/arch/arm/CodeGen.zig
@@ -1575,7 +1575,7 @@ fn load(self: *Self, dst_mcv: MCValue, ptr: MCValue, ptr_ty: Type) InnerError!vo
.compare_flags_signed, .compare_flags_unsigned => unreachable,
.embedded_in_code => unreachable,
.register => |dst_reg| {
- try self.genLdrRegister(dst_reg, reg, elem_size);
+ try self.genLdrRegister(dst_reg, reg, elem_ty);
},
.stack_offset => |off| {
if (elem_size <= 4) {
@@ -1676,7 +1676,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, @intCast(u32, value_ty.abiSize(self.target.*)));
+ try self.genStrRegister(value_reg, addr_reg, value_ty);
},
else => {
if (value_ty.abiSize(self.target.*) <= 4) {
@@ -2241,68 +2241,71 @@ fn binOp(
}
}
-fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, abi_size: u32) !void {
- switch (abi_size) {
- 1, 3, 4 => {
- const tag: Mir.Inst.Tag = switch (abi_size) {
- 1 => .ldrb,
- 3, 4 => .ldr,
- else => unreachable,
- };
+fn genLdrRegister(self: *Self, dest_reg: Register, addr_reg: Register, ty: Type) !void {
+ const abi_size = ty.abiSize(self.target.*);
- _ = try self.addInst(.{
- .tag = tag,
- .data = .{ .rr_offset = .{
- .rt = dest_reg,
- .rn = addr_reg,
- .offset = .{ .offset = Instruction.Offset.none },
- } },
- });
- },
- 2 => {
- _ = try self.addInst(.{
- .tag = .ldrh,
- .data = .{ .rr_extra_offset = .{
- .rt = dest_reg,
- .rn = addr_reg,
- .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
- } },
- });
- },
- else => unreachable, // invalid abi_size for a register
- }
+ const tag: Mir.Inst.Tag = switch (abi_size) {
+ 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
+ 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
+ 3, 4 => .ldr,
+ else => unreachable,
+ };
+
+ const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
+ .rt = dest_reg,
+ .rn = addr_reg,
+ .offset = .{ .offset = Instruction.Offset.none },
+ } };
+ const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
+ .rt = dest_reg,
+ .rn = addr_reg,
+ .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
+ } };
+
+ const data: Mir.Inst.Data = switch (abi_size) {
+ 1 => if (ty.isSignedInt()) rr_extra_offset else rr_offset,
+ 2 => rr_extra_offset,
+ 3, 4 => rr_offset,
+ else => unreachable,
+ };
+
+ _ = try self.addInst(.{
+ .tag = tag,
+ .data = data,
+ });
}
-fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, abi_size: u32) !void {
- switch (abi_size) {
- 1, 3, 4 => {
- const tag: Mir.Inst.Tag = switch (abi_size) {
- 1 => .strb,
- 3, 4 => .str,
- else => unreachable,
- };
+fn genStrRegister(self: *Self, source_reg: Register, addr_reg: Register, ty: Type) !void {
+ const abi_size = ty.abiSize(self.target.*);
- _ = try self.addInst(.{
- .tag = tag,
- .data = .{ .rr_offset = .{
- .rt = source_reg,
- .rn = addr_reg,
- .offset = .{ .offset = Instruction.Offset.none },
- } },
- });
- },
- 2 => {
- _ = try self.addInst(.{
- .tag = .strh,
- .data = .{ .rr_extra_offset = .{
- .rt = source_reg,
- .rn = addr_reg,
- .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
- } },
- });
- },
- else => unreachable, // invalid abi_size for a register
- }
+ const tag: Mir.Inst.Tag = switch (abi_size) {
+ 1 => .strb,
+ 2 => .strh,
+ 3, 4 => .str,
+ else => unreachable,
+ };
+
+ const rr_offset: Mir.Inst.Data = .{ .rr_offset = .{
+ .rt = source_reg,
+ .rn = addr_reg,
+ .offset = .{ .offset = Instruction.Offset.none },
+ } };
+ const rr_extra_offset: Mir.Inst.Data = .{ .rr_extra_offset = .{
+ .rt = source_reg,
+ .rn = addr_reg,
+ .offset = .{ .offset = Instruction.ExtraLoadStoreOffset.none },
+ } };
+
+ const data: Mir.Inst.Data = switch (abi_size) {
+ 1, 3, 4 => rr_offset,
+ 2 => rr_extra_offset,
+ else => unreachable,
+ };
+
+ _ = try self.addInst(.{
+ .tag = tag,
+ .data = data,
+ });
}
fn genInlineMemcpy(
@@ -2895,8 +2898,6 @@ fn isNonNull(self: *Self, ty: Type, operand: MCValue) !MCValue {
}
fn isErr(self: *Self, ty: Type, operand: MCValue) !MCValue {
- _ = operand;
-
const error_type = ty.errorUnionSet();
const payload_type = ty.errorUnionPayload();
@@ -3630,55 +3631,59 @@ 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, .{ .immediate = @intCast(u32, addr) });
- try self.genLdrRegister(reg, reg, @intCast(u32, ty.abiSize(self.target.*)));
+ try self.genLdrRegister(reg, reg, ty);
},
.stack_offset => |unadjusted_off| {
// TODO: maybe addressing from sp instead of fp
const abi_size = @intCast(u32, ty.abiSize(self.target.*));
const adj_off = unadjusted_off + abi_size;
- switch (abi_size) {
- 1, 4 => {
- const offset = if (adj_off <= math.maxInt(u12)) blk: {
- break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
- } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
+ const tag: Mir.Inst.Tag = switch (abi_size) {
+ 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb else .ldrb,
+ 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh else .ldrh,
+ 3, 4 => .ldr,
+ else => unreachable,
+ };
- const tag: Mir.Inst.Tag = switch (abi_size) {
- 1 => .ldrb,
- 4 => .ldr,
- else => unreachable,
- };
+ const extra_offset = switch (abi_size) {
+ 1 => ty.isSignedInt(),
+ 2 => true,
+ 3, 4 => false,
+ else => unreachable,
+ };
- _ = try self.addInst(.{
- .tag = tag,
- .data = .{ .rr_offset = .{
- .rt = reg,
- .rn = .fp,
- .offset = .{
- .offset = offset,
- .positive = false,
- },
- } },
- });
- },
- 2 => {
- const offset = if (adj_off <= math.maxInt(u8)) blk: {
- break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
- } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
+ if (extra_offset) {
+ const offset = if (adj_off <= math.maxInt(u8)) blk: {
+ break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, adj_off));
+ } else Instruction.ExtraLoadStoreOffset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }));
- _ = try self.addInst(.{
- .tag = .ldrh,
- .data = .{ .rr_extra_offset = .{
- .rt = reg,
- .rn = .fp,
- .offset = .{
- .offset = offset,
- .positive = false,
- },
- } },
- });
- },
- else => return self.fail("TODO a type of size {} is not allowed in a register", .{abi_size}),
+ _ = try self.addInst(.{
+ .tag = tag,
+ .data = .{ .rr_extra_offset = .{
+ .rt = reg,
+ .rn = .fp,
+ .offset = .{
+ .offset = offset,
+ .positive = false,
+ },
+ } },
+ });
+ } else {
+ const offset = if (adj_off <= math.maxInt(u12)) blk: {
+ break :blk Instruction.Offset.imm(@intCast(u12, adj_off));
+ } else Instruction.Offset.reg(try self.copyToTmpRegister(Type.initTag(.u32), MCValue{ .immediate = adj_off }), .none);
+
+ _ = try self.addInst(.{
+ .tag = tag,
+ .data = .{ .rr_offset = .{
+ .rt = reg,
+ .rn = .fp,
+ .offset = .{
+ .offset = offset,
+ .positive = false,
+ },
+ } },
+ });
}
},
.stack_argument_offset => |unadjusted_off| {
@@ -3686,9 +3691,9 @@ fn genSetReg(self: *Self, ty: Type, reg: Register, mcv: MCValue) InnerError!void
const adj_off = unadjusted_off + abi_size;
const tag: Mir.Inst.Tag = switch (abi_size) {
- 1 => .ldrb_stack_argument,
- 2 => .ldrh_stack_argument,
- 4 => .ldr_stack_argument,
+ 1 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsb_stack_argument else .ldrb_stack_argument,
+ 2 => if (ty.isSignedInt()) Mir.Inst.Tag.ldrsh_stack_argument else .ldrh_stack_argument,
+ 3, 4 => .ldr_stack_argument,
else => unreachable,
};
src/arch/arm/Emit.zig
@@ -115,8 +115,12 @@ pub fn emitMir(
.ldr_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrb_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrh_stack_argument => try emit.mirLoadStackArgument(inst),
+ .ldrsb_stack_argument => try emit.mirLoadStackArgument(inst),
+ .ldrsh_stack_argument => try emit.mirLoadStackArgument(inst),
.ldrh => try emit.mirLoadStoreExtra(inst),
+ .ldrsb => try emit.mirLoadStore(inst),
+ .ldrsh => try emit.mirLoadStoreExtra(inst),
.strh => try emit.mirLoadStoreExtra(inst),
.movw => try emit.mirSpecialMove(inst),
@@ -593,36 +597,42 @@ fn mirLoadStackArgument(emit: *Emit, inst: Mir.Inst.Index) !void {
const raw_offset = emit.prologue_stack_space - r_stack_offset.stack_offset;
switch (tag) {
- .ldr_stack_argument => {
+ .ldr_stack_argument,
+ .ldrb_stack_argument,
+ => {
const offset = if (raw_offset <= math.maxInt(u12)) blk: {
break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
} else return emit.fail("TODO mirLoadStack larger offsets", .{});
- try emit.writeInstruction(Instruction.ldr(
- cond,
- r_stack_offset.rt,
- .fp,
- .{ .offset = offset },
- ));
- },
- .ldrb_stack_argument => {
- const offset = if (raw_offset <= math.maxInt(u12)) blk: {
- break :blk Instruction.Offset.imm(@intCast(u12, raw_offset));
- } else return emit.fail("TODO mirLoadStack larger offsets", .{});
+ const ldr = switch (tag) {
+ .ldr_stack_argument => Instruction.ldr,
+ .ldrb_stack_argument => Instruction.ldrb,
+ else => unreachable,
+ };
- try emit.writeInstruction(Instruction.ldrb(
+ try emit.writeInstruction(ldr(
cond,
r_stack_offset.rt,
.fp,
.{ .offset = offset },
));
},
- .ldrh_stack_argument => {
+ .ldrh_stack_argument,
+ .ldrsb_stack_argument,
+ .ldrsh_stack_argument,
+ => {
const offset = if (raw_offset <= math.maxInt(u8)) blk: {
break :blk Instruction.ExtraLoadStoreOffset.imm(@intCast(u8, raw_offset));
} else return emit.fail("TODO mirLoadStack larger offsets", .{});
- try emit.writeInstruction(Instruction.ldrh(
+ const ldr = switch (tag) {
+ .ldrh_stack_argument => Instruction.ldrh,
+ .ldrsb_stack_argument => Instruction.ldrsb,
+ .ldrsh_stack_argument => Instruction.ldrsh,
+ else => unreachable,
+ };
+
+ try emit.writeInstruction(ldr(
cond,
r_stack_offset.rt,
.fp,
@@ -640,6 +650,8 @@ fn mirLoadStoreExtra(emit: *Emit, inst: Mir.Inst.Index) !void {
switch (tag) {
.ldrh => try emit.writeInstruction(Instruction.ldrh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
+ .ldrsb => try emit.writeInstruction(Instruction.ldrsb(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
+ .ldrsh => try emit.writeInstruction(Instruction.ldrsh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
.strh => try emit.writeInstruction(Instruction.strh(cond, rr_extra_offset.rt, rr_extra_offset.rn, rr_extra_offset.offset)),
else => unreachable,
}
src/arch/arm/Mir.zig
@@ -64,6 +64,14 @@ pub const Inst = struct {
ldrh,
/// Load Register Halfword
ldrh_stack_argument,
+ /// Load Register Signed Byte
+ ldrsb,
+ /// Load Register Signed Byte
+ ldrsb_stack_argument,
+ /// Load Register Signed Halfword
+ ldrsh,
+ /// Load Register Signed Halfword
+ ldrsh_stack_argument,
/// Logical Shift Left
lsl,
/// Logical Shift Right
test/behavior/basic.zig
@@ -26,7 +26,6 @@ fn testTruncate(x: u32) u8 {
test "truncate to non-power-of-two integers" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
try testTrunc(u32, u1, 0b10101, 0b1);
try testTrunc(u32, u1, 0b10110, 0b0);
test/behavior/truncate.zig
@@ -66,7 +66,6 @@ test "truncate.i0.var" {
test "truncate on comptime integer" {
if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
- if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
var x = @truncate(u16, 9999);
try expect(x == 9999);