zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit 0eebdfcad38e1348ca5fb8a26e722803664a3ebb (tree)
parent ca1ffb0951a0bd039ac435435a5c396f26c6d141
Author: joachimschmidt557 <joachim.schmidt557@outlook.com>
Date:   Sun, 13 Mar 2022 20:23:20 +0100

stage2 ARM: fix bitwise negation of ints with bits < 32

Diffstat:
Msrc/arch/arm/CodeGen.zig | 126++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Mtest/behavior/math.zig | 1-
2 files changed, 76 insertions(+), 51 deletions(-)

diff --git a/src/arch/arm/CodeGen.zig b/src/arch/arm/CodeGen.zig @@ -939,63 +939,85 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void { // return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); } -fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { - const ty_op = self.air.instructions.items(.data)[inst].ty_op; - if (self.liveness.isUnused(inst)) - return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none }); +fn truncRegister( + self: *Self, + operand_reg: Register, + dest_reg: Register, + int_signedness: std.builtin.Signedness, + int_bits: u16, +) !void { + // TODO check if sxtb/uxtb/sxth/uxth are more efficient + _ = try self.addInst(.{ + .tag = switch (int_signedness) { + .signed => .sbfx, + .unsigned => .ubfx, + }, + .data = .{ .rr_lsb_width = .{ + .rd = dest_reg, + .rn = operand_reg, + .lsb = 0, + .width = @intCast(u6, int_bits), + } }, + }); +} - const operand_ty = self.air.typeOf(ty_op.operand); - const operand = try self.resolveInst(ty_op.operand); +fn trunc( + self: *Self, + maybe_inst: ?Air.Inst.Index, + operand: MCValue, + operand_ty: Type, + dest_ty: Type, +) !MCValue { const info_a = operand_ty.intInfo(self.target.*); - const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*); - - const result: MCValue = blk: { - if (info_b.bits <= 32) { - const operand_reg = switch (operand) { - .register => |r| r, - else => operand_reg: { - if (info_a.bits <= 32) { - break :operand_reg try self.copyToTmpRegister(operand_ty, operand); - } else { - return self.fail("TODO load least significant word into register", .{}); - } - }, - }; - self.register_manager.freezeRegs(&.{operand_reg}); - defer self.register_manager.unfreezeRegs(&.{operand_reg}); - - const dest_reg = dest_reg: { - if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { - break :dest_reg operand_reg; + const info_b = dest_ty.intInfo(self.target.*); + + if (info_b.bits <= 32) { + const operand_reg = switch (operand) { + .register => |r| r, + else => operand_reg: { + if (info_a.bits <= 32) { + break :operand_reg try self.copyToTmpRegister(operand_ty, operand); + } else { + return self.fail("TODO load least significant word into register", .{}); } + }, + }; + self.register_manager.freezeRegs(&.{operand_reg}); + defer self.register_manager.unfreezeRegs(&.{operand_reg}); - break :dest_reg try self.register_manager.allocReg(null); - }; + const dest_reg = if (maybe_inst) |inst| blk: { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; - switch (info_b.bits) { - 32 => { - try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg }); - break :blk MCValue{ .register = dest_reg }; - }, - else => { - _ = try self.addInst(.{ - .tag = switch (info_b.signedness) { - .signed => .sbfx, - .unsigned => .ubfx, - }, - .data = .{ .rr_lsb_width = .{ - .rd = dest_reg, - .rn = operand_reg, - .lsb = 0, - .width = @intCast(u6, info_b.bits), - } }, - }); - break :blk MCValue{ .register = dest_reg }; - }, + if (operand == .register and self.reuseOperand(inst, ty_op.operand, 0, operand)) { + break :blk operand_reg; + } else { + break :blk try self.register_manager.allocReg(inst); } - } else { - return self.fail("TODO: truncate to ints > 32 bits", .{}); + } else try self.register_manager.allocReg(null); + + switch (info_b.bits) { + 32 => { + try self.genSetReg(operand_ty, dest_reg, .{ .register = operand_reg }); + return MCValue{ .register = dest_reg }; + }, + else => { + try self.truncRegister(operand_reg, dest_reg, info_b.signedness, info_b.bits); + return MCValue{ .register = dest_reg }; + }, } + } else { + return self.fail("TODO: truncate to ints > 32 bits", .{}); + } +} + +fn airTrunc(self: *Self, inst: Air.Inst.Index) !void { + const ty_op = self.air.instructions.items(.data)[inst].ty_op; + const operand = try self.resolveInst(ty_op.operand); + const operand_ty = self.air.typeOf(ty_op.operand); + const dest_ty = self.air.typeOfIndex(inst); + + const result: MCValue = if (self.liveness.isUnused(inst)) .dead else blk: { + break :blk try self.trunc(inst, operand, operand_ty, dest_ty); }; return self.finishAir(inst, result, .{ ty_op.operand, .none, .none }); @@ -1099,6 +1121,10 @@ fn airNot(self: *Self, inst: Air.Inst.Index) !void { } }, }); + if (int_info.bits < 32) { + try self.truncRegister(dest_reg, dest_reg, int_info.signedness, int_info.bits); + } + break :result MCValue{ .register = dest_reg }; } else { return self.fail("TODO ARM not on integers > u32/i32", .{}); diff --git a/test/behavior/math.zig b/test/behavior/math.zig @@ -367,7 +367,6 @@ test "binary not" { if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO try expect(comptime x: { break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;