authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-13 15:41:03-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-14 00:33:46-07:00
logab4d6bf468bd8cba4ffd2d700d83e9707f5307b1
treeb54b85796e9d79a35ab853b928898ec227889e4f
parent2d7d037c4855681c8a27d98f1f29a63badb55658

LLVM: work around `@floatFromInt` bug

see #17381

2 files changed, 34 insertions(+), 5 deletions(-)

src/codegen/llvm.zig+24-5
...@@ -4917,7 +4917,7 @@ pub const FuncGen = struct {...@@ -4917,7 +4917,7 @@ pub const FuncGen = struct {
4917 .int_from_float_optimized => try self.airIntFromFloat(inst, .fast),4917 .int_from_float_optimized => try self.airIntFromFloat(inst, .fast),
49184918
4919 .array_to_slice => try self.airArrayToSlice(inst),4919 .array_to_slice => try self.airArrayToSlice(inst),
4920 .float_from_int => try self.airFloatFromInt(inst),4920 .float_from_int => try self.airFloatFromInt(inst),
4921 .cmpxchg_weak => try self.airCmpxchg(inst, .weak),4921 .cmpxchg_weak => try self.airCmpxchg(inst, .weak),
4922 .cmpxchg_strong => try self.airCmpxchg(inst, .strong),4922 .cmpxchg_strong => try self.airCmpxchg(inst, .strong),
4923 .fence => try self.airFence(inst),4923 .fence => try self.airFence(inst),
...@@ -5955,9 +5955,28 @@ pub const FuncGen = struct {...@@ -5955,9 +5955,28 @@ pub const FuncGen = struct {
5955 const mod = o.module;5955 const mod = o.module;
5956 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5956 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
59575957
5958 const operand = try self.resolveInst(ty_op.operand);5958 const workaround_operand = try self.resolveInst(ty_op.operand);
5959 const operand_ty = self.typeOf(ty_op.operand);5959 const operand_ty = self.typeOf(ty_op.operand);
5960 const operand_scalar_ty = operand_ty.scalarType(mod);5960 const operand_scalar_ty = operand_ty.scalarType(mod);
5961 const is_signed_int = operand_scalar_ty.isSignedInt(mod);
5962
5963 const operand = o: {
5964 // Work around LLVM bug. See https://github.com/ziglang/zig/issues/17381.
5965 const bit_size = operand_scalar_ty.bitSize(mod);
5966 for ([_]u8{ 8, 16, 32, 64, 128 }) |b| {
5967 if (bit_size < b) {
5968 break :o try self.wip.cast(
5969 if (is_signed_int) .sext else .zext,
5970 workaround_operand,
5971 try o.builder.intType(b),
5972 "",
5973 );
5974 } else if (bit_size == b) {
5975 break :o workaround_operand;
5976 }
5977 }
5978 break :o workaround_operand;
5979 };
59615980
5962 const dest_ty = self.typeOfIndex(inst);5981 const dest_ty = self.typeOfIndex(inst);
5963 const dest_scalar_ty = dest_ty.scalarType(mod);5982 const dest_scalar_ty = dest_ty.scalarType(mod);
...@@ -5965,7 +5984,7 @@ pub const FuncGen = struct {...@@ -5965,7 +5984,7 @@ pub const FuncGen = struct {
5965 const target = mod.getTarget();5984 const target = mod.getTarget();
59665985
5967 if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv(5986 if (intrinsicsAllowed(dest_scalar_ty, target)) return self.wip.conv(
5968 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,5987 if (is_signed_int) .signed else .unsigned,
5969 operand,5988 operand,
5970 dest_llvm_ty,5989 dest_llvm_ty,
5971 "",5990 "",
...@@ -5974,7 +5993,7 @@ pub const FuncGen = struct {...@@ -5974,7 +5993,7 @@ pub const FuncGen = struct {
5974 const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(mod)));5993 const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(mod)));
5975 const rt_int_ty = try o.builder.intType(rt_int_bits);5994 const rt_int_ty = try o.builder.intType(rt_int_bits);
5976 var extended = try self.wip.conv(5995 var extended = try self.wip.conv(
5977 if (operand_scalar_ty.isSignedInt(mod)) .signed else .unsigned,5996 if (is_signed_int) .signed else .unsigned,
5978 operand,5997 operand,
5979 rt_int_ty,5998 rt_int_ty,
5980 "",5999 "",
...@@ -5982,7 +6001,7 @@ pub const FuncGen = struct {...@@ -5982,7 +6001,7 @@ pub const FuncGen = struct {
5982 const dest_bits = dest_scalar_ty.floatBits(target);6001 const dest_bits = dest_scalar_ty.floatBits(target);
5983 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);6002 const compiler_rt_operand_abbrev = compilerRtIntAbbrev(rt_int_bits);
5984 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);6003 const compiler_rt_dest_abbrev = compilerRtFloatAbbrev(dest_bits);
5985 const sign_prefix = if (operand_scalar_ty.isSignedInt(mod)) "" else "un";6004 const sign_prefix = if (is_signed_int) "" else "un";
5986 const fn_name = try o.builder.fmt("__float{s}{s}i{s}f", .{6005 const fn_name = try o.builder.fmt("__float{s}{s}i{s}f", .{
5987 sign_prefix,6006 sign_prefix,
5988 compiler_rt_operand_abbrev,6007 compiler_rt_operand_abbrev,
test/behavior/cast.zig+10
...@@ -2454,6 +2454,16 @@ test "numeric coercions with undefined" {...@@ -2454,6 +2454,16 @@ test "numeric coercions with undefined" {
2454 try expectEqual(@as(f32, 42.0), to);2454 try expectEqual(@as(f32, 42.0), to);
2455}2455}
24562456
2457test "15-bit int to float" {
2458 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest;
2459 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest;
2460 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
2461
2462 var a: u15 = 42;
2463 var b: f32 = @floatFromInt(a);
2464 try expect(b == 42.0);
2465}
2466
2457test "@as does not corrupt values with incompatible representations" {2467test "@as does not corrupt values with incompatible representations" {
2458 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO2468 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
2459 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO2469 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO