Skip to content

Commit

Permalink
LLVM: work around @floatFromInt bug
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewrk committed Oct 14, 2023
1 parent 2d7d037 commit ab4d6bf
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 5 deletions.
29 changes: 24 additions & 5 deletions src/codegen/llvm.zig
Original file line number Diff line number Diff line change
Expand Up @@ -4917,7 +4917,7 @@ pub const FuncGen = struct {
.int_from_float_optimized => try self.airIntFromFloat(inst, .fast),

.array_to_slice => try self.airArrayToSlice(inst),
.float_from_int => try self.airFloatFromInt(inst),
.float_from_int => try self.airFloatFromInt(inst),
.cmpxchg_weak => try self.airCmpxchg(inst, .weak),
.cmpxchg_strong => try self.airCmpxchg(inst, .strong),
.fence => try self.airFence(inst),
Expand Down Expand Up @@ -5955,17 +5955,36 @@ pub const FuncGen = struct {
const mod = o.module;
const ty_op = self.air.instructions.items(.data)[inst].ty_op;

const operand = try self.resolveInst(ty_op.operand);
const workaround_operand = try self.resolveInst(ty_op.operand);
const operand_ty = self.typeOf(ty_op.operand);
const operand_scalar_ty = operand_ty.scalarType(mod);
const is_signed_int = operand_scalar_ty.isSignedInt(mod);

const operand = o: {
// Work around LLVM bug. See https://github.com/ziglang/zig/issues/17381.
const bit_size = operand_scalar_ty.bitSize(mod);
for ([_]u8{ 8, 16, 32, 64, 128 }) |b| {
if (bit_size < b) {
break :o try self.wip.cast(
if (is_signed_int) .sext else .zext,
workaround_operand,
try o.builder.intType(b),
"",
);
} else if (bit_size == b) {
break :o workaround_operand;
}
}
break :o workaround_operand;
};

const dest_ty = self.typeOfIndex(inst);
const dest_scalar_ty = dest_ty.scalarType(mod);
const dest_llvm_ty = try o.lowerType(dest_ty);
const target = mod.getTarget();

if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv(
if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
if (is_signed_int) .signed else .unsigned,
operand,
dest_llvm_ty,
"",
Expand All @@ -5974,15 +5993,15 @@ pub const FuncGen = struct {
const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(mod)));
const rt_int_ty = try o.builder.intType(rt_int_bits);
var extended = try self.wip.conv(
if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,
if (is_signed_int) .signed else .unsigned,
operand,
rt_int_ty,
"",
);
const dest_bits = dest_scalar_ty.floatBits(target);
const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);
const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);
const sign_prefix = if (operand_scalar_ty.isSignedInt(mod)) "" else "un";
const sign_prefix = if (is_signed_int) "" else "un";
const fn_name = try o.builder.fmt("__float{s}{s}i{s}f", .{
sign_prefix,
compiler_rt_operand_abbrev,
Expand Down
10 changes: 10 additions & 0 deletions test/behavior/cast.zig
Original file line number Diff line number Diff line change
Expand Up @@ -2454,6 +2454,16 @@ test "numeric coercions with undefined" {
try expectEqual(@as(f32, 42.0), to);
}

test "15-bit int to float" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;

var a: u15 = 42;
var b: f32 = @floatFromInt(a);
try expect(b == 42.0);
}

test "@as does not corrupt values with incompatible representations" {
if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
Expand Down

0 comments on commit ab4d6bf

Please sign in to comment.