authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-01-21 10:43:05+01:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-01-29 16:37:55-05:00
logfe4ef7b461bec5370169063ccf889873161f8c46
tree62e89820a4f2161cbc65d199b74609bd8a3e933b
parentd448c3d38af9f8f70daaa2817a5834e30da4b8ca
signature Commit is signed but in an unrecognized format.

Fix comptime float-int comparisons

Closes #4259

2 files changed, 81 insertions(+), 32 deletions(-)

src/ir.cpp+39-20
...@@ -15815,33 +15815,52 @@ never_mind_just_calculate_it_normally:...@@ -15815,33 +15815,52 @@ never_mind_just_calculate_it_normally:
15815 bool op1_is_int = op1_val->type->id == ZigTypeIdInt || op1_val->type->id == ZigTypeIdComptimeInt;15815 bool op1_is_int = op1_val->type->id == ZigTypeIdInt || op1_val->type->id == ZigTypeIdComptimeInt;
15816 bool op2_is_int = op2_val->type->id == ZigTypeIdInt || op2_val->type->id == ZigTypeIdComptimeInt;15816 bool op2_is_int = op2_val->type->id == ZigTypeIdInt || op2_val->type->id == ZigTypeIdComptimeInt;
1581715817
15818 BigInt *op1_bigint;15818 if (op1_is_int && op2_is_int) {
15819 BigInt *op2_bigint;15819 Cmp cmp_result = bigint_cmp(&op1_val->data.x_bigint, &op2_val->data.x_bigint);
15820 bool need_to_free_op1_bigint = false;15820 out_val->special = ConstValSpecialStatic;
15821 bool need_to_free_op2_bigint = false;15821 out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result);
15822 if (op1_is_float) {15822
15823 op1_bigint = allocate<BigInt>(1, "BigInt");15823 return nullptr;
15824 need_to_free_op1_bigint = true;
15825 float_init_bigint(op1_bigint, op1_val);
15826 } else {
15827 assert(op1_is_int);
15828 op1_bigint = &op1_val->data.x_bigint;
15829 }15824 }
15830 if (op2_is_float) {15825
15831 op2_bigint = allocate<BigInt>(1, "BigInt");15826 // Handle the case where one of the two operands is a fp value and the other
15832 need_to_free_op2_bigint = true;15827 // is an integer value
15833 float_init_bigint(op2_bigint, op2_val);15828 ZigValue **int_val, **float_val;
15829
15830 if (op1_is_int && op2_is_float) {
15831 int_val = &op1_val;
15832 float_val = &op2_val;
15833 } else if (op1_is_float && op2_is_int) {
15834 int_val = &op2_val;
15835 float_val = &op1_val;
15834 } else {15836 } else {
15835 assert(op2_is_int);15837 zig_unreachable();
15836 op2_bigint = &op2_val->data.x_bigint;15838 }
15839
15840 // They can never be equal if the fp value has a non-zero decimal part
15841 if (op_id == IrBinOpCmpEq || op_id == IrBinOpCmpNotEq) {
15842 if (float_has_fraction(*float_val)) {
15843 out_val->special = ConstValSpecialStatic;
15844 out_val->data.x_bool = op_id == IrBinOpCmpNotEq;
15845
15846 return nullptr;
15847 }
15848 }
15849
15850 // Cast the integer operand into a fp value to perform the comparison
15851 {
15852 IrInstruction *tmp = ir_const_noval(ira, source_instr);
15853 tmp->value = *int_val;
15854 IrInstruction *casted = ir_implicit_cast(ira, tmp, (*float_val)->type);
15855 if (casted == ira->codegen->invalid_instruction)
15856 return ira->codegen->trace_err;
15857 *int_val = casted->value;
15837 }15858 }
1583815859
15839 Cmp cmp_result = bigint_cmp(op1_bigint, op2_bigint);15860 Cmp cmp_result = bigfloat_cmp(&op1_val->data.x_bigfloat, &op2_val->data.x_bigfloat);
15840 out_val->special = ConstValSpecialStatic;15861 out_val->special = ConstValSpecialStatic;
15841 out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result);15862 out_val->data.x_bool = resolve_cmp_op_id(op_id, cmp_result);
1584215863
15843 if (need_to_free_op1_bigint) destroy(op1_bigint, "BigInt");
15844 if (need_to_free_op2_bigint) destroy(op2_bigint, "BigInt");
15845 return nullptr;15864 return nullptr;
15846}15865}
1584715866
test/stage1/behavior/floatop.zig+42-12
...@@ -36,7 +36,7 @@ fn testSqrt() void {...@@ -36,7 +36,7 @@ fn testSqrt() void {
36 // expect(@sqrt(a) == 7);36 // expect(@sqrt(a) == 7);
37 //}37 //}
38 {38 {
39 var v: @Vector(4, f32) = [_]f32{1.1, 2.2, 3.3, 4.4};39 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
40 var result = @sqrt(v);40 var result = @sqrt(v);
41 expect(math.approxEq(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));41 expect(math.approxEq(f32, @sqrt(@as(f32, 1.1)), result[0], epsilon));
42 expect(math.approxEq(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));42 expect(math.approxEq(f32, @sqrt(@as(f32, 2.2)), result[1], epsilon));
...@@ -86,7 +86,7 @@ fn testSin() void {...@@ -86,7 +86,7 @@ fn testSin() void {
86 expect(@sin(a) == 0);86 expect(@sin(a) == 0);
87 }87 }
88 {88 {
89 var v: @Vector(4, f32) = [_]f32{1.1, 2.2, 3.3, 4.4};89 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
90 var result = @sin(v);90 var result = @sin(v);
91 expect(math.approxEq(f32, @sin(@as(f32, 1.1)), result[0], epsilon));91 expect(math.approxEq(f32, @sin(@as(f32, 1.1)), result[0], epsilon));
92 expect(math.approxEq(f32, @sin(@as(f32, 2.2)), result[1], epsilon));92 expect(math.approxEq(f32, @sin(@as(f32, 2.2)), result[1], epsilon));
...@@ -116,7 +116,7 @@ fn testCos() void {...@@ -116,7 +116,7 @@ fn testCos() void {
116 expect(@cos(a) == 1);116 expect(@cos(a) == 1);
117 }117 }
118 {118 {
119 var v: @Vector(4, f32) = [_]f32{1.1, 2.2, 3.3, 4.4};119 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 3.3, 4.4 };
120 var result = @cos(v);120 var result = @cos(v);
121 expect(math.approxEq(f32, @cos(@as(f32, 1.1)), result[0], epsilon));121 expect(math.approxEq(f32, @cos(@as(f32, 1.1)), result[0], epsilon));
122 expect(math.approxEq(f32, @cos(@as(f32, 2.2)), result[1], epsilon));122 expect(math.approxEq(f32, @cos(@as(f32, 2.2)), result[1], epsilon));
...@@ -146,7 +146,7 @@ fn testExp() void {...@@ -146,7 +146,7 @@ fn testExp() void {
146 expect(@exp(a) == 1);146 expect(@exp(a) == 1);
147 }147 }
148 {148 {
149 var v: @Vector(4, f32) = [_]f32{1.1, 2.2, 0.3, 0.4};149 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
150 var result = @exp(v);150 var result = @exp(v);
151 expect(math.approxEq(f32, @exp(@as(f32, 1.1)), result[0], epsilon));151 expect(math.approxEq(f32, @exp(@as(f32, 1.1)), result[0], epsilon));
152 expect(math.approxEq(f32, @exp(@as(f32, 2.2)), result[1], epsilon));152 expect(math.approxEq(f32, @exp(@as(f32, 2.2)), result[1], epsilon));
...@@ -176,7 +176,7 @@ fn testExp2() void {...@@ -176,7 +176,7 @@ fn testExp2() void {
176 expect(@exp2(a) == 4);176 expect(@exp2(a) == 4);
177 }177 }
178 {178 {
179 var v: @Vector(4, f32) = [_]f32{1.1, 2.2, 0.3, 0.4};179 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
180 var result = @exp2(v);180 var result = @exp2(v);
181 expect(math.approxEq(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));181 expect(math.approxEq(f32, @exp2(@as(f32, 1.1)), result[0], epsilon));
182 expect(math.approxEq(f32, @exp2(@as(f32, 2.2)), result[1], epsilon));182 expect(math.approxEq(f32, @exp2(@as(f32, 2.2)), result[1], epsilon));
...@@ -208,7 +208,7 @@ fn testLog() void {...@@ -208,7 +208,7 @@ fn testLog() void {
208 expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));208 expect(@log(a) == 1 or @log(a) == @bitCast(f64, @as(u64, 0x3ff0000000000000)));
209 }209 }
210 {210 {
211 var v: @Vector(4, f32) = [_]f32{1.1, 2.2, 0.3, 0.4};211 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
212 var result = @log(v);212 var result = @log(v);
213 expect(math.approxEq(f32, @log(@as(f32, 1.1)), result[0], epsilon));213 expect(math.approxEq(f32, @log(@as(f32, 1.1)), result[0], epsilon));
214 expect(math.approxEq(f32, @log(@as(f32, 2.2)), result[1], epsilon));214 expect(math.approxEq(f32, @log(@as(f32, 2.2)), result[1], epsilon));
...@@ -238,7 +238,7 @@ fn testLog2() void {...@@ -238,7 +238,7 @@ fn testLog2() void {
238 expect(@log2(a) == 2);238 expect(@log2(a) == 2);
239 }239 }
240 {240 {
241 var v: @Vector(4, f32) = [_]f32{1.1, 2.2, 0.3, 0.4};241 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
242 var result = @log2(v);242 var result = @log2(v);
243 expect(math.approxEq(f32, @log2(@as(f32, 1.1)), result[0], epsilon));243 expect(math.approxEq(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
244 expect(math.approxEq(f32, @log2(@as(f32, 2.2)), result[1], epsilon));244 expect(math.approxEq(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
...@@ -268,7 +268,7 @@ fn testLog10() void {...@@ -268,7 +268,7 @@ fn testLog10() void {
268 expect(@log10(a) == 3);268 expect(@log10(a) == 3);
269 }269 }
270 {270 {
271 var v: @Vector(4, f32) = [_]f32{1.1, 2.2, 0.3, 0.4};271 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
272 var result = @log10(v);272 var result = @log10(v);
273 expect(math.approxEq(f32, @log10(@as(f32, 1.1)), result[0], epsilon));273 expect(math.approxEq(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
274 expect(math.approxEq(f32, @log10(@as(f32, 2.2)), result[1], epsilon));274 expect(math.approxEq(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
...@@ -304,7 +304,7 @@ fn testFabs() void {...@@ -304,7 +304,7 @@ fn testFabs() void {
304 expect(@fabs(b) == 2.5);304 expect(@fabs(b) == 2.5);
305 }305 }
306 {306 {
307 var v: @Vector(4, f32) = [_]f32{1.1, -2.2, 0.3, -0.4};307 var v: @Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
308 var result = @fabs(v);308 var result = @fabs(v);
309 expect(math.approxEq(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));309 expect(math.approxEq(f32, @fabs(@as(f32, 1.1)), result[0], epsilon));
310 expect(math.approxEq(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));310 expect(math.approxEq(f32, @fabs(@as(f32, -2.2)), result[1], epsilon));
...@@ -334,7 +334,7 @@ fn testFloor() void {...@@ -334,7 +334,7 @@ fn testFloor() void {
334 expect(@floor(a) == 3);334 expect(@floor(a) == 3);
335 }335 }
336 {336 {
337 var v: @Vector(4, f32) = [_]f32{1.1, -2.2, 0.3, -0.4};337 var v: @Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
338 var result = @floor(v);338 var result = @floor(v);
339 expect(math.approxEq(f32, @floor(@as(f32, 1.1)), result[0], epsilon));339 expect(math.approxEq(f32, @floor(@as(f32, 1.1)), result[0], epsilon));
340 expect(math.approxEq(f32, @floor(@as(f32, -2.2)), result[1], epsilon));340 expect(math.approxEq(f32, @floor(@as(f32, -2.2)), result[1], epsilon));
...@@ -364,7 +364,7 @@ fn testCeil() void {...@@ -364,7 +364,7 @@ fn testCeil() void {
364 expect(@ceil(a) == 4);364 expect(@ceil(a) == 4);
365 }365 }
366 {366 {
367 var v: @Vector(4, f32) = [_]f32{1.1, -2.2, 0.3, -0.4};367 var v: @Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
368 var result = @ceil(v);368 var result = @ceil(v);
369 expect(math.approxEq(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));369 expect(math.approxEq(f32, @ceil(@as(f32, 1.1)), result[0], epsilon));
370 expect(math.approxEq(f32, @ceil(@as(f32, -2.2)), result[1], epsilon));370 expect(math.approxEq(f32, @ceil(@as(f32, -2.2)), result[1], epsilon));
...@@ -394,7 +394,7 @@ fn testTrunc() void {...@@ -394,7 +394,7 @@ fn testTrunc() void {
394 expect(@trunc(a) == -3);394 expect(@trunc(a) == -3);
395 }395 }
396 {396 {
397 var v: @Vector(4, f32) = [_]f32{1.1, -2.2, 0.3, -0.4};397 var v: @Vector(4, f32) = [_]f32{ 1.1, -2.2, 0.3, -0.4 };
398 var result = @trunc(v);398 var result = @trunc(v);
399 expect(math.approxEq(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));399 expect(math.approxEq(f32, @trunc(@as(f32, 1.1)), result[0], epsilon));
400 expect(math.approxEq(f32, @trunc(@as(f32, -2.2)), result[1], epsilon));400 expect(math.approxEq(f32, @trunc(@as(f32, -2.2)), result[1], epsilon));
...@@ -403,6 +403,36 @@ fn testTrunc() void {...@@ -403,6 +403,36 @@ fn testTrunc() void {
403 }403 }
404}404}
405405
406test "floating point comparisons" {
407 testFloatComparisons();
408 comptime testFloatComparisons();
409}
410
411fn testFloatComparisons() void {
412 inline for ([_]type{ f16, f32, f64, f128 }) |ty| {
413 // No decimal part
414 {
415 const x: ty = 1.0;
416 expect(x == 1);
417 expect(x != 0);
418 expect(x > 0);
419 expect(x < 2);
420 expect(x >= 1);
421 expect(x <= 1);
422 }
423 // Non-zero decimal part
424 {
425 const x: ty = 1.5;
426 expect(x != 1);
427 expect(x != 2);
428 expect(x > 1);
429 expect(x < 2);
430 expect(x >= 1);
431 expect(x <= 2);
432 }
433 }
434}
435
406// TODO This is waiting on library support for the Windows build (not sure why the other's don't need it)436// TODO This is waiting on library support for the Windows build (not sure why the other's don't need it)
407//test "@nearbyint" {437//test "@nearbyint" {
408// comptime testNearbyInt();438// comptime testNearbyInt();