zig

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

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:
Msrc/codegen/wasm/CodeGen.zig | 54++++++++++++++++++++++++++++++++++++++++++++++++------
Msrc/codegen/wasm/Mir.zig | 20++++++++++++++++++++
Mtest/behavior/cast.zig | 48++++++++++++++++++++++++++++++++++++++++++++++++
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