diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig index 467e560687..8f1d3e8be4 100644 --- a/src/arch/arm/CodeGen.zig +++ b/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, }; diff --git a/src/arch/arm/Emit.zig b/src/arch/arm/Emit.zig index d4561553c4..7ffd6de2dd 100644 --- a/src/arch/arm/Emit.zig +++ b/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( + const ldr = switch (tag) { + .ldr_stack_argument => Instruction.ldr, + .ldrb_stack_argument => Instruction.ldrb, + else => unreachable, + }; + + try emit.writeInstruction(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", .{}); - - try emit.writeInstruction(Instruction.ldrb( - 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, } diff --git a/src/arch/arm/Mir.zig b/src/arch/arm/Mir.zig index c85acae085..7852a39885 100644 --- a/src/arch/arm/Mir.zig +++ b/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 diff --git a/src/arch/arm/bits.zig b/src/arch/arm/bits.zig index a8866ac5c9..568b7580c8 100644 --- a/src/arch/arm/bits.zig +++ b/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 diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index db83393634..d6447862cf 100644 --- a/test/behavior/basic.zig +++ b/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); diff --git a/test/behavior/truncate.zig b/test/behavior/truncate.zig index a16e54e25b..26205d56b6 100644 --- a/test/behavior/truncate.zig +++ b/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);