authorgravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-04-07 01:05:53+02:00
committergravatar for paul.verigo@gmail.comPavel Verigo <paul.verigo@gmail.com> 2026-04-09 00:14:09+02:00
logfff887874e917e2955002c323fb0286cedfbfd84
treef8ecc364dda29f2f6c2fd793f8ec7e989194ab36
parentdf79ea941bc3c355dfcb51c1de3d2d4fd186dd46

stage2-wasm: @intFromFloat and @floatFromInt


3 files changed, 116 insertions(+), 6 deletions(-)

src/codegen/wasm/CodeGen.zig+48-6
......@@ -4413,7 +4413,34 @@ fn intFromFloat(cg: *CodeGen, dest_ty: IntType, src_ty: FloatType, operand: WVal
44134413 return cg.callIntrinsic(intrinsic, &.{.f128_type}, Type.u128, &.{operand});
44144414 },
44154415 },
4416 else => return cg.fail("TODO: Support intFromFloat for integer bitsize: {d}", .{dest_ty.bits}),
4416 else => {
4417 const result = try cg.allocInt(dest_ty);
4418
4419 switch (src_ty) {
4420 .f16 => {
4421 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixhfei else .__fixunshfei;
4422 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f16_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4423 },
4424 .f32 => {
4425 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixsfei else .__fixunssfei;
4426 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f32_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4427 },
4428 .f64 => {
4429 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixdfei else .__fixunsdfei;
4430 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f64_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4431 },
4432 .f80 => {
4433 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixxfei else .__fixunsxfei;
4434 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f80_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4435 },
4436 .f128 => {
4437 const intrinsic: Mir.Intrinsic = if (dest_ty.is_signed) .__fixtfei else .__fixunstfei;
4438 _ = try cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type, .f128_type }, .void, &.{ result, .{ .imm32 = dest_ty.bits }, operand });
4439 },
4440 }
4441
4442 return result;
4443 },
44174444 }
44184445}
44194446
......@@ -4433,7 +4460,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
44334460 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattihf else .__floatuntihf;
44344461 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f16, &.{operand});
44354462 },
4436 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 16-bit float", .{src_ty.bits}),
4463 else => {
4464 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateihf else .__floatuneihf;
4465 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f16, &.{ operand, .{ .imm32 = src_ty.bits }});
4466 },
44374467 },
44384468 .f32 => switch (src_ty.bits) {
44394469 0 => unreachable,
......@@ -4451,7 +4481,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
44514481 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattisf else .__floatuntisf;
44524482 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f32, &.{operand});
44534483 },
4454 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 32-bit float", .{src_ty.bits}),
4484 else => {
4485 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateisf else .__floatuneisf;
4486 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f32, &.{ operand, .{ .imm32 = src_ty.bits }});
4487 },
44554488 },
44564489 .f64 => switch (src_ty.bits) {
44574490 0 => unreachable,
......@@ -4469,7 +4502,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
44694502 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattidf else .__floatuntidf;
44704503 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f64, &.{operand});
44714504 },
4472 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 64-bit float", .{src_ty.bits}),
4505 else => {
4506 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateidf else .__floatuneidf;
4507 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f64, &.{ operand, .{ .imm32 = src_ty.bits }});
4508 },
44734509 },
44744510 .f80 => switch (src_ty.bits) {
44754511 0 => unreachable,
......@@ -4485,7 +4521,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
44854521 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattixf else .__floatuntixf;
44864522 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f80, &.{operand});
44874523 },
4488 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 80-bit float", .{src_ty.bits}),
4524 else => {
4525 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateixf else .__floatuneixf;
4526 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f80, &.{ operand, .{ .imm32 = src_ty.bits }});
4527 },
44894528 },
44904529 .f128 => switch (src_ty.bits) {
44914530 0 => unreachable,
......@@ -4501,7 +4540,10 @@ fn floatFromInt(cg: *CodeGen, dest_ty: FloatType, src_ty: IntType, operand: WVal
45014540 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floattitf else .__floatuntitf;
45024541 return cg.callIntrinsic(intrinsic, &.{.i128_type}, Type.f128, &.{operand});
45034542 },
4504 else => return cg.fail("TODO: Support floatFromInt for {d}-bit int to 128-bit float", .{src_ty.bits}),
4543 else => {
4544 const intrinsic: Mir.Intrinsic = if (src_ty.is_signed) .__floateitf else .__floatuneitf;
4545 return cg.callIntrinsic(intrinsic, &.{ .usize_type, .usize_type }, Type.f128, &.{ operand, .{ .imm32 = src_ty.bits }});
4546 },
45054547 },
45064548 }
45074549}
src/codegen/wasm/Mir.zig+20
......@@ -846,33 +846,43 @@ pub const Intrinsic = enum(u32) {
846846 __fabsh,
847847 __fabsx,
848848 __fixdfdi,
849 __fixdfei,
849850 __fixdfsi,
850851 __fixdfti,
851852 __fixhfdi,
853 __fixhfei,
852854 __fixhfsi,
853855 __fixhfti,
854856 __fixsfdi,
857 __fixsfei,
855858 __fixsfsi,
856859 __fixsfti,
857860 __fixtfdi,
861 __fixtfei,
858862 __fixtfsi,
859863 __fixtfti,
860864 __fixunsdfdi,
865 __fixunsdfei,
861866 __fixunsdfsi,
862867 __fixunsdfti,
863868 __fixunshfdi,
869 __fixunshfei,
864870 __fixunshfsi,
865871 __fixunshfti,
866872 __fixunssfdi,
873 __fixunssfei,
867874 __fixunssfsi,
868875 __fixunssfti,
869876 __fixunstfdi,
877 __fixunstfei,
870878 __fixunstfsi,
871879 __fixunstfti,
872880 __fixunsxfdi,
881 __fixunsxfei,
873882 __fixunsxfsi,
874883 __fixunsxfti,
875884 __fixxfdi,
885 __fixxfei,
876886 __fixxfsi,
877887 __fixxfti,
878888 __floatdidf,
......@@ -880,6 +890,11 @@ pub const Intrinsic = enum(u32) {
880890 __floatdisf,
881891 __floatditf,
882892 __floatdixf,
893 __floateidf,
894 __floateihf,
895 __floateisf,
896 __floateitf,
897 __floateixf,
883898 __floatsidf,
884899 __floatsihf,
885900 __floatsisf,
......@@ -895,6 +910,11 @@ pub const Intrinsic = enum(u32) {
895910 __floatundisf,
896911 __floatunditf,
897912 __floatundixf,
913 __floatuneidf,
914 __floatuneihf,
915 __floatuneisf,
916 __floatuneitf,
917 __floatuneixf,
898918 __floatunsidf,
899919 __floatunsihf,
900920 __floatunsisf,
test/behavior/cast.zig+48
......@@ -122,6 +122,54 @@ test "@floatFromInt" {
122122 try comptime S.doTheTest();
123123}
124124
125fn testIntFromFloat(comptime F: type, f: F, comptime I: type, i: I) !void {
126 try expect(@as(I, @intFromFloat(f)) == i);
127}
128
129test "@intFromFloat > 128 bits" {
130 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
131 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
132
133 try testIntFromFloat(f16, 1024, u140, 1024);
134 try testIntFromFloat(f16, -1024, i140, -1024);
135
136 try testIntFromFloat(f32, 1 << 24, u140, 1 << 24);
137 try testIntFromFloat(f32, -1 << 24, i140, -1 << 24);
138
139 try testIntFromFloat(f64, 1 << 53, u200, 1 << 53);
140 try testIntFromFloat(f64, -1 << 53, i200, -1 << 53);
141
142 try testIntFromFloat(f80, 1 << 63, u200, 1 << 63);
143 try testIntFromFloat(f80, -1 << 63, i200, -1 << 63);
144
145 try testIntFromFloat(f128, 1 << 100, u200, 1 << 100);
146 try testIntFromFloat(f128, -1 << 100, i200, -1 << 100);
147}
148
149fn testFloatFromInt(comptime I: type, i: I, comptime F: type, expected: F) !void {
150 try expect(@as(F, @floatFromInt(i)) == expected);
151}
152
153test "@floatFromInt > 128 bits" {
154 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
155 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest;
156
157 try testFloatFromInt(u140, 1024, f16, 1024);
158 try testFloatFromInt(i140, -1024, f16, -1024);
159
160 try testFloatFromInt(u140, 1 << 24, f32, 1 << 24);
161 try testFloatFromInt(i140, -1 << 24, f32, -1 << 24);
162
163 try testFloatFromInt(u200, 1 << 53, f64, 1 << 53);
164 try testFloatFromInt(i200, -1 << 53, f64, -1 << 53);
165
166 try testFloatFromInt(u200, 1 << 63, f80, 1 << 63);
167 try testFloatFromInt(i200, -1 << 63, f80, -1 << 63);
168
169 try testFloatFromInt(u200, 1 << 100, f128, 1 << 100);
170 try testFloatFromInt(i200, -1 << 100, f128, -1 << 100);
171}
172
125173test "@floatFromInt(f80)" {
126174 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
127175 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO