diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index 3a73a54c5..31be0cbe6 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/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), } }, }); diff --git a/src/arch/aarch64/Emit.zig b/src/arch/aarch64/Emit.zig index ac731636b..d9dfbc6fa 100644 --- a/src/arch/aarch64/Emit.zig +++ b/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)), diff --git a/src/arch/aarch64/Mir.zig b/src/arch/aarch64/Mir.zig index dcde591a0..516ccca98 100644 --- a/src/arch/aarch64/Mir.zig +++ b/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) diff --git a/src/arch/aarch64/bits.zig b/src/arch/aarch64/bits.zig index f275776ac..0775ca1f7 100644 --- a/src/arch/aarch64/bits.zig +++ b/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); } diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 39e6322e2..d608cba98 100644 --- a/test/behavior/basic.zig +++ b/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); diff --git a/test/behavior/truncate.zig b/test/behavior/truncate.zig index 9971fd880..1543f9fef 100644 --- a/test/behavior/truncate.zig +++ b/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);