mirror of
https://github.com/ziglang/zig.git
synced 2026-02-12 20:37:54 +00:00
stage2 ARM: fix bitwise negation of ints with bits < 32
This commit is contained in:
parent
ca1ffb0951
commit
0eebdfcad3
@ -939,63 +939,85 @@ fn airIntCast(self: *Self, inst: Air.Inst.Index) !void {
|
||||
// return self.finishAir(inst, result, .{ 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),
|
||||
} },
|
||||
});
|
||||
}
|
||||
|
||||
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 = 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});
|
||||
|
||||
const dest_reg = if (maybe_inst) |inst| blk: {
|
||||
const ty_op = self.air.instructions.items(.data)[inst].ty_op;
|
||||
|
||||
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 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;
|
||||
if (self.liveness.isUnused(inst))
|
||||
return self.finishAir(inst, .dead, .{ ty_op.operand, .none, .none });
|
||||
|
||||
const operand_ty = self.air.typeOf(ty_op.operand);
|
||||
const operand = try self.resolveInst(ty_op.operand);
|
||||
const info_a = operand_ty.intInfo(self.target.*);
|
||||
const info_b = self.air.typeOfIndex(inst).intInfo(self.target.*);
|
||||
const operand_ty = self.air.typeOf(ty_op.operand);
|
||||
const dest_ty = self.air.typeOfIndex(inst);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
break :dest_reg try self.register_manager.allocReg(null);
|
||||
};
|
||||
|
||||
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 };
|
||||
},
|
||||
}
|
||||
} else {
|
||||
return self.fail("TODO: truncate to ints > 32 bits", .{});
|
||||
}
|
||||
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", .{});
|
||||
|
||||
@ -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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user