commit fff887874e917e2955002c323fb0286cedfbfd84 (tree)
parent df79ea941bc3c355dfcb51c1de3d2d4fd186dd46
Author: Pavel Verigo <paul.verigo@gmail.com>
Date: Tue, 7 Apr 2026 01:05:53 +0200
stage2-wasm: @intFromFloat and @floatFromInt
Diffstat:
3 files changed, 116 insertions(+), 6 deletions(-)
diff --git a/src/codegen/wasm/CodeGen.zig b/src/codegen/wasm/CodeGen.zig
@@ -4413,7 +4413,34 @@ fn intFromFloat(cg: *CodeGen, dest_ty: IntType, src_ty: FloatType, operand: WVal
return cg.callIntrinsic(intrinsic, &.{.f128_type}, Type.u128, &.{operand});
},
},
- else => return cg.fail("TODO: Support intFromFloat for integer bitsize: {d}", .{dest_ty.bits}),
+ else => {
+ const result = try cg.allocInt(dest_ty);
+
+ switch (src_ty) {
+ .f16 => {
+ const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixhfei else .__fixunshfei;
+ _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f16_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
+ },
+ .f32 => {
+ const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixsfei else .__fixunssfei;
+ _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f32_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
+ },
+ .f64 => {
+ const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixdfei else .__fixunsdfei;
+ _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f64_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
+ },
+ .f80 => {
+ const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixxfei else .__fixunsxfei;
+ _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f80_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
+ },
+ .f128 => {
+ const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixtfei else .__fixunstfei;
+ _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f128_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
+ },
+ }
+
+ return result;
+ },
}
}
@@ -4433,7 +4460,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattihf else .__floatuntihf;
return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f16, &.{operand});
},
- else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 16-bit float", .{src_ty.bits}),
+ else => {
+ const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateihf else .__floatuneihf;
+ return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f16, &.{ operand, .{ .imm32 = src_ty.bits }});
+ },
},
.f32 => switch (src_ty.bits) {
0 => unreachable,
@@ -4451,7 +4481,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattisf else .__floatuntisf;
return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f32, &.{operand});
},
- else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 32-bit float", .{src_ty.bits}),
+ else => {
+ const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateisf else .__floatuneisf;
+ return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f32, &.{ operand, .{ .imm32 = src_ty.bits }});
+ },
},
.f64 => switch (src_ty.bits) {
0 => unreachable,
@@ -4469,7 +4502,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattidf else .__floatuntidf;
return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f64, &.{operand});
},
- else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 64-bit float", .{src_ty.bits}),
+ else => {
+ const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateidf else .__floatuneidf;
+ return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f64, &.{ operand, .{ .imm32 = src_ty.bits }});
+ },
},
.f80 => switch (src_ty.bits) {
0 => unreachable,
@@ -4485,7 +4521,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattixf else .__floatuntixf;
return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f80, &.{operand});
},
- else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 80-bit float", .{src_ty.bits}),
+ else => {
+ const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateixf else .__floatuneixf;
+ return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f80, &.{ operand, .{ .imm32 = src_ty.bits }});
+ },
},
.f128 => switch (src_ty.bits) {
0 => unreachable,
@@ -4501,7 +4540,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattitf else .__floatuntitf;
return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f128, &.{operand});
},
- else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 128-bit float", .{src_ty.bits}),
+ else => {
+ const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateitf else .__floatuneitf;
+ return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f128, &.{ operand, .{ .imm32 = src_ty.bits }});
+ },
},
}
}
diff --git a/src/codegen/wasm/Mir.zig b/src/codegen/wasm/Mir.zig
@@ -846,33 +846,43 @@ pub const Intrinsic = enum(u32) {
__fabsh,
__fabsx,
__fixdfdi,
+ __fixdfei,
__fixdfsi,
__fixdfti,
__fixhfdi,
+ __fixhfei,
__fixhfsi,
__fixhfti,
__fixsfdi,
+ __fixsfei,
__fixsfsi,
__fixsfti,
__fixtfdi,
+ __fixtfei,
__fixtfsi,
__fixtfti,
__fixunsdfdi,
+ __fixunsdfei,
__fixunsdfsi,
__fixunsdfti,
__fixunshfdi,
+ __fixunshfei,
__fixunshfsi,
__fixunshfti,
__fixunssfdi,
+ __fixunssfei,
__fixunssfsi,
__fixunssfti,
__fixunstfdi,
+ __fixunstfei,
__fixunstfsi,
__fixunstfti,
__fixunsxfdi,
+ __fixunsxfei,
__fixunsxfsi,
__fixunsxfti,
__fixxfdi,
+ __fixxfei,
__fixxfsi,
__fixxfti,
__floatdidf,
@@ -880,6 +890,11 @@ pub const Intrinsic = enum(u32) {
__floatdisf,
__floatditf,
__floatdixf,
+ __floateidf,
+ __floateihf,
+ __floateisf,
+ __floateitf,
+ __floateixf,
__floatsidf,
__floatsihf,
__floatsisf,
@@ -895,6 +910,11 @@ pub const Intrinsic = enum(u32) {
__floatundisf,
__floatunditf,
__floatundixf,
+ __floatuneidf,
+ __floatuneihf,
+ __floatuneisf,
+ __floatuneitf,
+ __floatuneixf,
__floatunsidf,
__floatunsihf,
__floatunsisf,
diff --git a/test/behavior/cast.zig b/test/behavior/cast.zig
@@ -122,6 +122,54 @@ test "@floatFromInt" {
try comptime S.doTheTest();
}
+fn testIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
+ try expect(@as(I, @intFromFloat(f)) == i);
+}
+
+test "@intFromFloat > 128 bits" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+
+ try testIntFromFloat(f16, 1024, u140, 1024);
+ try testIntFromFloat(f16, -1024, i140, -1024);
+
+ try testIntFromFloat(f32, 1 << 24, u140, 1 << 24);
+ try testIntFromFloat(f32, -1 << 24, i140, -1 << 24);
+
+ try testIntFromFloat(f64, 1 << 53, u200, 1 << 53);
+ try testIntFromFloat(f64, -1 << 53, i200, -1 << 53);
+
+ try testIntFromFloat(f80, 1 << 63, u200, 1 << 63);
+ try testIntFromFloat(f80, -1 << 63, i200, -1 << 63);
+
+ try testIntFromFloat(f128, 1 << 100, u200, 1 << 100);
+ try testIntFromFloat(f128, -1 << 100, i200, -1 << 100);
+}
+
+fn testFloatFromInt(comptime I: type, i: I, comptime F: type, expected: F) !void {
+ try expect(@as(F, @floatFromInt(i)) == expected);
+}
+
+test "@floatFromInt > 128 bits" {
+ if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
+ if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
+
+ try testFloatFromInt(u140, 1024, f16, 1024);
+ try testFloatFromInt(i140, -1024, f16, -1024);
+
+ try testFloatFromInt(u140, 1 << 24, f32, 1 << 24);
+ try testFloatFromInt(i140, -1 << 24, f32, -1 << 24);
+
+ try testFloatFromInt(u200, 1 << 53, f64, 1 << 53);
+ try testFloatFromInt(i200, -1 << 53, f64, -1 << 53);
+
+ try testFloatFromInt(u200, 1 << 63, f80, 1 << 63);
+ try testFloatFromInt(i200, -1 << 63, f80, -1 << 63);
+
+ try testFloatFromInt(u200, 1 << 100, f128, 1 << 100);
+ try testFloatFromInt(i200, -1 << 100, f128, -1 << 100);
+}
+
test "@floatFromInt(f80)" {
if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO