authorgravatar for pawalamde@gmail.comzenith391 <pawalamde@gmail.com> 2021-11-10 00:52:30+01:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-11-09 18:52:30-05:00
log0d7359ca9b7e1c88d62ce3ecc6542584fe5df489
tree259335fd862ce44db56c716e5de3080e26cbe80a
parentc77698d69ea5c3e09b1b9404f634e512627ad321
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

stage2: Implement Sema.floatToInt (#10097)


4 files changed, 105 insertions(+), 27 deletions(-)

src/Sema.zig+30-4
...@@ -9642,9 +9642,29 @@ fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -9642,9 +9642,29 @@ fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
96429642
9643fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9643fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
9644 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;9644 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
9645 const src = inst_data.src();9645 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
9646 // TODO don't forget the safety check!9646 const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
9647 return sema.fail(block, src, "TODO: Sema.zirFloatToInt", .{});9647 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
9648 const dest_ty = try sema.resolveType(block, ty_src, extra.lhs);
9649 const operand = sema.resolveInst(extra.rhs);
9650 const operand_ty = sema.typeOf(operand);
9651
9652 _ = try sema.checkIntType(block, ty_src, dest_ty);
9653 try sema.checkFloatType(block, operand_src, operand_ty);
9654
9655 if (try sema.resolveMaybeUndefVal(block, operand_src, operand)) |val| {
9656 const target = sema.mod.getTarget();
9657 const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {
9658 error.FloatCannotFit => {
9659 return sema.fail(block, operand_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
9660 },
9661 else => |e| return e,
9662 };
9663 return sema.addConstant(dest_ty, result_val);
9664 }
9665
9666 try sema.requireRuntimeBlock(block, operand_src);
9667 return block.addTyOp(.float_to_int, dest_ty, operand);
9648}9668}
96499669
9650fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9670fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -12434,7 +12454,13 @@ fn coerceNum(...@@ -12434,7 +12454,13 @@ fn coerceNum(
12434 if (val.floatHasFraction()) {12454 if (val.floatHasFraction()) {
12435 return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_ty });12455 return sema.fail(block, inst_src, "fractional component prevents float value {} from coercion to type '{}'", .{ val, dest_ty });
12436 }12456 }
12437 return sema.fail(block, inst_src, "TODO float to int", .{});12457 const result_val = val.floatToInt(sema.arena, dest_ty, target) catch |err| switch (err) {
12458 error.FloatCannotFit => {
12459 return sema.fail(block, inst_src, "integer value {d} cannot be stored in type '{}'", .{ std.math.floor(val.toFloat(f64)), dest_ty });
12460 },
12461 else => |e| return e,
12462 };
12463 return try sema.addConstant(dest_ty, result_val);
12438 },12464 },
12439 .Int, .ComptimeInt => {12465 .Int, .ComptimeInt => {
12440 if (!val.intFitsInType(dest_ty, target)) {12466 if (!val.intFitsInType(dest_ty, target)) {
src/value.zig+46
...@@ -1929,6 +1929,52 @@ pub const Value = extern union {...@@ -1929,6 +1929,52 @@ pub const Value = extern union {
1929 }1929 }
1930 }1930 }
19311931
1932 pub fn floatToInt(val: Value, arena: *Allocator, dest_ty: Type, target: Target) error{ FloatCannotFit, OutOfMemory }!Value {
1933 const Limb = std.math.big.Limb;
1934
1935 var value = val.toFloat(f64); // TODO: f128 ?
1936 if (std.math.isNan(value) or std.math.isInf(value)) {
1937 return error.FloatCannotFit;
1938 }
1939
1940 const isNegative = std.math.signbit(value);
1941 value = std.math.fabs(value);
1942
1943 const floored = std.math.floor(value);
1944
1945 var rational = try std.math.big.Rational.init(arena);
1946 defer rational.deinit();
1947 rational.setFloat(f64, floored) catch |err| switch (err) {
1948 error.NonFiniteFloat => unreachable,
1949 error.OutOfMemory => return error.OutOfMemory,
1950 };
1951
1952 // The float is reduced in rational.setFloat, so we assert that denominator is equal to one
1953 const bigOne = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
1954 assert(rational.q.toConst().eqAbs(bigOne));
1955
1956 const result_limbs = try arena.dupe(Limb, rational.p.toConst().limbs);
1957 const result = if (isNegative)
1958 try Value.Tag.int_big_negative.create(arena, result_limbs)
1959 else
1960 try Value.Tag.int_big_positive.create(arena, result_limbs);
1961
1962 if (result.intFitsInType(dest_ty, target)) {
1963 return result;
1964 } else {
1965 return error.FloatCannotFit;
1966 }
1967 }
1968
1969 fn calcLimbLenFloat(scalar: anytype) usize {
1970 if (scalar == 0) {
1971 return 1;
1972 }
1973
1974 const w_value = std.math.fabs(scalar);
1975 return @divFloor(@floatToInt(std.math.big.Limb, std.math.log2(w_value)), @typeInfo(std.math.big.Limb).Int.bits) + 1;
1976 }
1977
1932 /// Supports both floats and ints; handles undefined.1978 /// Supports both floats and ints; handles undefined.
1933 pub fn numberAddWrap(1979 pub fn numberAddWrap(
1934 lhs: Value,1980 lhs: Value,
test/behavior/cast.zig+22
...@@ -107,6 +107,28 @@ test "comptime_int @intToFloat" {...@@ -107,6 +107,28 @@ test "comptime_int @intToFloat" {
107 }107 }
108}108}
109109
110test "@floatToInt" {
111 try testFloatToInts();
112 comptime try testFloatToInts();
113}
114
115fn testFloatToInts() !void {
116 const x = @as(i32, 1e4);
117 try expect(x == 10000);
118 const y = @floatToInt(i32, @as(f32, 1e4));
119 try expect(y == 10000);
120 try expectFloatToInt(f16, 255.1, u8, 255);
121 try expectFloatToInt(f16, 127.2, i8, 127);
122 try expectFloatToInt(f16, -128.2, i8, -128);
123 try expectFloatToInt(f32, 255.1, u8, 255);
124 try expectFloatToInt(f32, 127.2, i8, 127);
125 try expectFloatToInt(f32, -128.2, i8, -128);
126}
127
128fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void {
129 try expect(@floatToInt(I, f) == i);
130}
131
110test "implicit cast from [*]T to ?*c_void" {132test "implicit cast from [*]T to ?*c_void" {
111 var a = [_]u8{ 3, 2, 1 };133 var a = [_]u8{ 3, 2, 1 };
112 var runtime_zero: usize = 0;134 var runtime_zero: usize = 0;
test/behavior/cast_stage1.zig+7-23
...@@ -191,29 +191,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {...@@ -191,29 +191,6 @@ fn testPeerErrorAndArray2(x: u8) anyerror![]const u8 {
191 };191 };
192}192}
193193
194test "@floatToInt" {
195 try testFloatToInts();
196 comptime try testFloatToInts();
197}
198
199fn testFloatToInts() !void {
200 const x = @as(i32, 1e4);
201 try expect(x == 10000);
202 const y = @floatToInt(i32, @as(f32, 1e4));
203 try expect(y == 10000);
204 try expectFloatToInt(f16, 255.1, u8, 255);
205 try expectFloatToInt(f16, 127.2, i8, 127);
206 try expectFloatToInt(f16, -128.2, i8, -128);
207 try expectFloatToInt(f32, 255.1, u8, 255);
208 try expectFloatToInt(f32, 127.2, i8, 127);
209 try expectFloatToInt(f32, -128.2, i8, -128);
210 try expectFloatToInt(comptime_int, 1234, i16, 1234);
211}
212
213fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void {
214 try expect(@floatToInt(I, f) == i);
215}
216
217test "cast u128 to f128 and back" {194test "cast u128 to f128 and back" {
218 comptime try testCast128();195 comptime try testCast128();
219 try testCast128();196 try testCast128();
...@@ -664,6 +641,13 @@ test "comptime float casts" {...@@ -664,6 +641,13 @@ test "comptime float casts" {
664 const b = @floatToInt(comptime_int, 2);641 const b = @floatToInt(comptime_int, 2);
665 try expect(b == 2);642 try expect(b == 2);
666 try expect(@TypeOf(b) == comptime_int);643 try expect(@TypeOf(b) == comptime_int);
644
645 try expectFloatToInt(comptime_int, 1234, i16, 1234);
646 try expectFloatToInt(comptime_float, 12.3, comptime_int, 12);
647}
648
649fn expectFloatToInt(comptime F: type, f: F, comptime I: type, i: I) !void {
650 try expect(@floatToInt(I, f) == i);
667}651}
668652
669test "cast from ?[*]T to ??[*]T" {653test "cast from ?[*]T to ??[*]T" {