authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-14 00:10:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-14 00:11:46-07:00
logb2a1b4c085b93d508c51307f40444252b8cd4d52
tree307c504b85c9aee16602e667db1a5db5c25e1fff
parenteee989d2a00f99d95900515b48f981f2ea6bbe78

Sema: improve lowering of stores to bitcasted vector pointers

Detect if we are storing an array operand to a bitcasted vector pointer. If so, we instead reach through the bitcasted pointer to the vector pointer, bitcast the array operand to a vector, and then lower this as a store of a vector value to a vector pointer. This generally results in better code, as well as working around an LLVM bug. See #11154

5 files changed, 324 insertions(+), 86 deletions(-)

src/Sema.zig+50-2
......@@ -13276,7 +13276,7 @@ fn checkFloatType(
1327613276 ty: Type,
1327713277) CompileError!void {
1327813278 switch (ty.zigTypeTag()) {
13279 .ComptimeFloat, .Float => {},
13279 .ComptimeInt, .ComptimeFloat, .Float => {},
1328013280 else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty}),
1328113281 }
1328213282}
......@@ -17177,10 +17177,25 @@ fn storePtr2(
1717717177 return;
1717817178 }
1717917179
17180 // TODO do the same thing for anon structs as for tuples above.
17181
17182 // Detect if we are storing an array operand to a bitcasted vector pointer.
17183 // If so, we instead reach through the bitcasted pointer to the vector pointer,
17184 // bitcast the array operand to a vector, and then lower this as a store of
17185 // a vector value to a vector pointer. This generally results in better code,
17186 // as well as working around an LLVM bug:
17187 // https://github.com/ziglang/zig/issues/11154
17188 if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| {
17189 const vector_ty = sema.typeOf(vector_ptr).childType();
17190 const vector = try sema.coerce(block, vector_ty, uncasted_operand, operand_src);
17191 try sema.storePtr2(block, src, vector_ptr, ptr_src, vector, operand_src, .store);
17192 return;
17193 }
17194
1718017195 const operand = try sema.coerce(block, elem_ty, uncasted_operand, operand_src);
17196 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand);
1718117197
1718217198 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
17183 const maybe_operand_val = try sema.resolveMaybeUndefVal(block, operand_src, operand);
1718417199 const operand_val = maybe_operand_val orelse {
1718517200 try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
1718617201 break :rs operand_src;
......@@ -17203,6 +17218,39 @@ fn storePtr2(
1720317218 _ = try block.addBinOp(air_tag, ptr, operand);
1720417219}
1720517220
17221/// Traverse an arbitrary number of bitcasted pointers and return the underyling vector
17222/// pointer. Only if the final element type matches the vector element type, and the
17223/// lengths match.
17224fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref {
17225 const array_ty = sema.typeOf(ptr).childType();
17226 if (array_ty.zigTypeTag() != .Array) return null;
17227 var ptr_inst = Air.refToIndex(ptr) orelse return null;
17228 const air_datas = sema.air_instructions.items(.data);
17229 const air_tags = sema.air_instructions.items(.tag);
17230 const prev_ptr = while (air_tags[ptr_inst] == .bitcast) {
17231 const prev_ptr = air_datas[ptr_inst].ty_op.operand;
17232 const prev_ptr_ty = sema.typeOf(prev_ptr);
17233 const prev_ptr_child_ty = switch (prev_ptr_ty.tag()) {
17234 .single_mut_pointer => prev_ptr_ty.castTag(.single_mut_pointer).?.data,
17235 .pointer => prev_ptr_ty.castTag(.pointer).?.data.pointee_type,
17236 else => return null,
17237 };
17238 if (prev_ptr_child_ty.zigTypeTag() == .Vector) break prev_ptr;
17239 ptr_inst = Air.refToIndex(prev_ptr) orelse return null;
17240 } else return null;
17241
17242 // We have a pointer-to-array and a pointer-to-vector. If the elements and
17243 // lengths match, return the result.
17244 const vector_ty = sema.typeOf(prev_ptr).childType();
17245 if (array_ty.childType().eql(vector_ty.childType()) and
17246 array_ty.arrayLen() == vector_ty.vectorLen())
17247 {
17248 return prev_ptr;
17249 } else {
17250 return null;
17251 }
17252}
17253
1720617254/// Call when you have Value objects rather than Air instructions, and you want to
1720717255/// assert the store must be done at comptime.
1720817256fn storePtrVal(
src/value.zig+2-17
......@@ -3931,15 +3931,12 @@ pub const Value = extern union {
39313931 },
39323932 80 => {
39333933 if (true) {
3934 @panic("TODO implement compiler_rt fabs for f80");
3934 @panic("TODO implement compiler_rt fabs for f80 (__fabsx)");
39353935 }
39363936 const f = val.toFloat(f80);
39373937 return Value.Tag.float_80.create(arena, @fabs(f));
39383938 },
39393939 128 => {
3940 if (true) {
3941 @panic("TODO implement compiler_rt fabs for f128");
3942 }
39433940 const f = val.toFloat(f128);
39443941 return Value.Tag.float_128.create(arena, @fabs(f));
39453942 },
......@@ -3963,15 +3960,12 @@ pub const Value = extern union {
39633960 },
39643961 80 => {
39653962 if (true) {
3966 @panic("TODO implement compiler_rt floor for f80");
3963 @panic("TODO implement compiler_rt floor for f80 (__floorx)");
39673964 }
39683965 const f = val.toFloat(f80);
39693966 return Value.Tag.float_80.create(arena, @floor(f));
39703967 },
39713968 128 => {
3972 if (true) {
3973 @panic("TODO implement compiler_rt floor for f128");
3974 }
39753969 const f = val.toFloat(f128);
39763970 return Value.Tag.float_128.create(arena, @floor(f));
39773971 },
......@@ -4001,9 +3995,6 @@ pub const Value = extern union {
40013995 return Value.Tag.float_80.create(arena, @ceil(f));
40023996 },
40033997 128 => {
4004 if (true) {
4005 @panic("TODO implement compiler_rt ceil for f128");
4006 }
40073998 const f = val.toFloat(f128);
40083999 return Value.Tag.float_128.create(arena, @ceil(f));
40094000 },
......@@ -4033,9 +4024,6 @@ pub const Value = extern union {
40334024 return Value.Tag.float_80.create(arena, @round(f));
40344025 },
40354026 128 => {
4036 if (true) {
4037 @panic("TODO implement compiler_rt round for f128");
4038 }
40394027 const f = val.toFloat(f128);
40404028 return Value.Tag.float_128.create(arena, @round(f));
40414029 },
......@@ -4065,9 +4053,6 @@ pub const Value = extern union {
40654053 return Value.Tag.float_80.create(arena, @trunc(f));
40664054 },
40674055 128 => {
4068 if (true) {
4069 @panic("TODO implement compiler_rt trunc for f128");
4070 }
40714056 const f = val.toFloat(f128);
40724057 return Value.Tag.float_128.create(arena, @trunc(f));
40734058 },
test/behavior/cast.zig+22-3
......@@ -95,8 +95,29 @@ test "comptime_int @intToFloat" {
9595 }
9696}
9797
98test "@intToFloat" {
99 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
100 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
101 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
102 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
103
104 const S = struct {
105 fn doTheTest() !void {
106 try testIntToFloat(-2);
107 }
108
109 fn testIntToFloat(k: i32) !void {
110 const f = @intToFloat(f32, k);
111 const i = @floatToInt(i32, f);
112 try expect(i == k);
113 }
114 };
115 try S.doTheTest();
116 comptime try S.doTheTest();
117}
118
98119test "@floatToInt" {
99 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
120 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
100121 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
101122 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
102123
......@@ -1007,8 +1028,6 @@ test "peer type resolve array pointer and unknown pointer" {
10071028}
10081029
10091030test "comptime float casts" {
1010 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1011
10121031 const a = @intToFloat(comptime_float, 1);
10131032 try expect(a == 1);
10141033 try expect(@TypeOf(a) == comptime_float);
test/behavior/floatop.zig+124-21
......@@ -333,7 +333,6 @@ fn testLog() !void {
333333}
334334
335335test "@log with vectors" {
336 if (builtin.zig_backend == .stage2_llvm) return error.SkipZigTest; // TODO
337336 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
338337 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
339338 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
......@@ -343,15 +342,19 @@ test "@log with vectors" {
343342 {
344343 var v: @Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
345344 var result = @log(v);
346 try expect(math.approxEqAbs(f32, @log(@as(f32, 1.1)), result[0], epsilon));
347 try expect(math.approxEqAbs(f32, @log(@as(f32, 2.2)), result[1], epsilon));
345 try expect(@log(@as(f32, 1.1)) == result[0]);
346 try expect(@log(@as(f32, 2.2)) == result[1]);
348347 try expect(@log(@as(f32, 0.3)) == result[2]);
349 try expect(math.approxEqAbs(f32, @log(@as(f32, 0.4)), result[3], epsilon));
348 try expect(@log(@as(f32, 0.4)) == result[3]);
350349 }
351350}
352351
353352test "@log2" {
354 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
353 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
354 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
355 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
356 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
357 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
355358
356359 comptime try testLog2();
357360 try testLog2();
......@@ -368,15 +371,19 @@ fn testLog2() !void {
368371 {
369372 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
370373 var result = @log2(v);
371 try expect(math.approxEqAbs(f32, @log2(@as(f32, 1.1)), result[0], epsilon));
372 try expect(math.approxEqAbs(f32, @log2(@as(f32, 2.2)), result[1], epsilon));
373 try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.3)), result[2], epsilon));
374 try expect(math.approxEqAbs(f32, @log2(@as(f32, 0.4)), result[3], epsilon));
374 try expect(@log2(@as(f32, 1.1)) == result[0]);
375 try expect(@log2(@as(f32, 2.2)) == result[1]);
376 try expect(@log2(@as(f32, 0.3)) == result[2]);
377 try expect(@log2(@as(f32, 0.4)) == result[3]);
375378 }
376379}
377380
378381test "@log10" {
379 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
382 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
383 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
384 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
385 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
386 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
380387
381388 comptime try testLog10();
382389 try testLog10();
......@@ -393,10 +400,10 @@ fn testLog10() !void {
393400 {
394401 var v: Vector(4, f32) = [_]f32{ 1.1, 2.2, 0.3, 0.4 };
395402 var result = @log10(v);
396 try expect(math.approxEqAbs(f32, @log10(@as(f32, 1.1)), result[0], epsilon));
397 try expect(math.approxEqAbs(f32, @log10(@as(f32, 2.2)), result[1], epsilon));
398 try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.3)), result[2], epsilon));
399 try expect(math.approxEqAbs(f32, @log10(@as(f32, 0.4)), result[3], epsilon));
403 try expect(@log10(@as(f32, 1.1)) == result[0]);
404 try expect(@log10(@as(f32, 2.2)) == result[1]);
405 try expect(@log10(@as(f32, 0.3)) == result[2]);
406 try expect(@log10(@as(f32, 0.4)) == result[3]);
400407 }
401408}
402409
......@@ -537,7 +544,71 @@ fn testTrunc() !void {
537544 }
538545}
539546
540test "negation" {
547test "negation f16" {
548 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
549 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
550 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
551 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
552
553 if (builtin.os.tag == .freebsd) {
554 // TODO file issue to track this failure
555 return error.SkipZigTest;
556 }
557
558 const S = struct {
559 fn doTheTest() !void {
560 var a: f16 = 1;
561 a = -a;
562 try expect(a == -1);
563 a = -a;
564 try expect(a == 1);
565 }
566 };
567
568 try S.doTheTest();
569 comptime try S.doTheTest();
570}
571
572test "negation f32" {
573 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
574 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
575 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
576 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
577
578 const S = struct {
579 fn doTheTest() !void {
580 var a: f32 = 1;
581 a = -a;
582 try expect(a == -1);
583 a = -a;
584 try expect(a == 1);
585 }
586 };
587
588 try S.doTheTest();
589 comptime try S.doTheTest();
590}
591
592test "negation f64" {
593 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
594 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
595 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
596
597 const S = struct {
598 fn doTheTest() !void {
599 var a: f64 = 1;
600 a = -a;
601 try expect(a == -1);
602 a = -a;
603 try expect(a == 1);
604 }
605 };
606
607 try S.doTheTest();
608 comptime try S.doTheTest();
609}
610
611test "negation f80" {
541612 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
542613
543614 if (builtin.os.tag == .freebsd) {
......@@ -547,11 +618,37 @@ test "negation" {
547618
548619 const S = struct {
549620 fn doTheTest() !void {
550 inline for ([_]type{ f16, f32, f64, f80, f128 }) |T| {
551 var a: T = 1;
552 a = -a;
553 try expect(a == -1);
554 }
621 var a: f80 = 1;
622 a = -a;
623 try expect(a == -1);
624 a = -a;
625 try expect(a == 1);
626 }
627 };
628
629 try S.doTheTest();
630 comptime try S.doTheTest();
631}
632
633test "negation f128" {
634 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
635 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
636 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
637 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
638 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
639
640 if (builtin.os.tag == .freebsd) {
641 // TODO file issue to track this failure
642 return error.SkipZigTest;
643 }
644
645 const S = struct {
646 fn doTheTest() !void {
647 var a: f128 = 1;
648 a = -a;
649 try expect(a == -1);
650 a = -a;
651 try expect(a == 1);
555652 }
556653 };
557654
......@@ -583,7 +680,13 @@ test "float literal at compile time not lossy" {
583680}
584681
585682test "f128 at compile time is lossy" {
586 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
683 if (builtin.zig_backend != .stage1) {
684 // this one is happening because we represent comptime-known f128 integers with
685 // Value.Tag.bigint and only convert to f128 representation if it stops being an
686 // integer. Is this something we want? need to have a lang spec discussion on this
687 // topic.
688 return error.SkipZigTest; // TODO
689 }
587690
588691 try expect(@as(f128, 10384593717069655257060992658440192.0) + 1 == 10384593717069655257060992658440192.0);
589692}
test/behavior/math.zig+126-43
......@@ -6,7 +6,6 @@ const expectEqualSlices = std.testing.expectEqualSlices;
66const maxInt = std.math.maxInt;
77const minInt = std.math.minInt;
88const mem = std.mem;
9const has_f80_rt = builtin.cpu.arch == .x86_64;
109
1110test "assignment operators" {
1211 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
......@@ -1046,12 +1045,14 @@ fn testSqrt(comptime T: type, x: T) !void {
10461045}
10471046
10481047test "@fabs" {
1049 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1048 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
1049 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
1050 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
1051 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
1052 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
10501053
10511054 try testFabs(f128, 12.0);
10521055 comptime try testFabs(f128, 12.0);
1053 if (has_f80_rt) try testFabs(f80, 12.0);
1054 // comptime try testFabs(f80, 12.0);
10551056 try testFabs(f64, 12.0);
10561057 comptime try testFabs(f64, 12.0);
10571058 try testFabs(f32, 12.0);
......@@ -1065,20 +1066,25 @@ test "@fabs" {
10651066 comptime try expectEqual(x, z);
10661067}
10671068
1069test "@fabs f80" {
1070 if (true) {
1071 // https://github.com/ziglang/zig/issues/11030
1072 return error.SkipZigTest;
1073 }
1074
1075 try testFabs(f80, 12.0);
1076 comptime try testFabs(f80, 12.0);
1077}
1078
10681079fn testFabs(comptime T: type, x: T) !void {
10691080 const y = -x;
10701081 const z = @fabs(y);
1071 try expectEqual(x, z);
1082 try expect(x == z);
10721083}
10731084
10741085test "@floor" {
10751086 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
10761087
1077 // FIXME: Generates a floorl function call
1078 // testFloor(f128, 12.0);
1079 comptime try testFloor(f128, 12.0);
1080 // try testFloor(f80, 12.0);
1081 comptime try testFloor(f80, 12.0);
10821088 try testFloor(f64, 12.0);
10831089 comptime try testFloor(f64, 12.0);
10841090 try testFloor(f32, 12.0);
......@@ -1089,23 +1095,39 @@ test "@floor" {
10891095 const x = 14.0;
10901096 const y = x + 0.7;
10911097 const z = @floor(y);
1092 comptime try expectEqual(x, z);
1098 comptime try expect(x == z);
1099}
1100
1101test "@floor f80" {
1102 if (true) {
1103 // https://github.com/ziglang/zig/issues/11030
1104 return error.SkipZigTest;
1105 }
1106 try testFloor(f80, 12.0);
1107 comptime try testFloor(f80, 12.0);
1108}
1109
1110test "@floor f128" {
1111 if (builtin.zig_backend == .stage1) {
1112 // Fails because it incorrectly lowers to a floorl function call.
1113 return error.SkipZigTest;
1114 }
1115
1116 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1117
1118 testFloor(f128, 12.0);
1119 comptime try testFloor(f128, 12.0);
10931120}
10941121
10951122fn testFloor(comptime T: type, x: T) !void {
10961123 const y = x + 0.6;
10971124 const z = @floor(y);
1098 try expectEqual(x, z);
1125 try expect(x == z);
10991126}
11001127
11011128test "@ceil" {
11021129 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
11031130
1104 // FIXME: Generates a ceill function call
1105 //testCeil(f128, 12.0);
1106 comptime try testCeil(f128, 12.0);
1107 // try testCeil(f80, 12.0);
1108 comptime try testCeil(f80, 12.0);
11091131 try testCeil(f64, 12.0);
11101132 comptime try testCeil(f64, 12.0);
11111133 try testCeil(f32, 12.0);
......@@ -1116,29 +1138,40 @@ test "@ceil" {
11161138 const x = 14.0;
11171139 const y = x - 0.7;
11181140 const z = @ceil(y);
1119 comptime try expectEqual(x, z);
1141 comptime try expect(x == z);
1142}
1143
1144test "@ceil f80" {
1145 if (true) {
1146 // https://github.com/ziglang/zig/issues/11030
1147 return error.SkipZigTest;
1148 }
1149
1150 try testCeil(f80, 12.0);
1151 comptime try testCeil(f80, 12.0);
1152}
1153
1154test "@ceil f128" {
1155 if (builtin.zig_backend == .stage1) {
1156 // Fails because it incorrectly lowers to a ceill function call.
1157 return error.SkipZigTest;
1158 }
1159
1160 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1161
1162 testCeil(f128, 12.0);
1163 comptime try testCeil(f128, 12.0);
11201164}
11211165
11221166fn testCeil(comptime T: type, x: T) !void {
11231167 const y = x - 0.8;
11241168 const z = @ceil(y);
1125 try expectEqual(x, z);
1169 try expect(x == z);
11261170}
11271171
11281172test "@trunc" {
11291173 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
11301174
1131 // FIXME: Generates a truncl function call
1132 //testTrunc(f128, 12.0);
1133 comptime try testTrunc(f128, 12.0);
1134 // try testTrunc(f80, 12.0);
1135 // comptime try testTrunc(f80, 12.0);
1136 comptime {
1137 const x: f80 = 12.0;
1138 const y = x + 0.8;
1139 const z = @trunc(y);
1140 try expectEqual(x, z);
1141 }
11421175 try testTrunc(f64, 12.0);
11431176 comptime try testTrunc(f64, 12.0);
11441177 try testTrunc(f32, 12.0);
......@@ -1149,31 +1182,54 @@ test "@trunc" {
11491182 const x = 14.0;
11501183 const y = x + 0.7;
11511184 const z = @trunc(y);
1152 comptime try expectEqual(x, z);
1185 comptime try expect(x == z);
1186}
1187
1188test "@trunc f80" {
1189 if (true) {
1190 // https://github.com/ziglang/zig/issues/11030
1191 return error.SkipZigTest;
1192 }
1193
1194 try testTrunc(f80, 12.0);
1195 comptime try testTrunc(f80, 12.0);
1196 comptime {
1197 const x: f80 = 12.0;
1198 const y = x + 0.8;
1199 const z = @trunc(y);
1200 try expect(x == z);
1201 }
1202}
1203
1204test "@trunc f128" {
1205 if (builtin.zig_backend == .stage1) {
1206 // Fails because it incorrectly lowers to a truncl function call.
1207 return error.SkipZigTest;
1208 }
1209
1210 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1211
1212 testTrunc(f128, 12.0);
1213 comptime try testTrunc(f128, 12.0);
11531214}
11541215
11551216fn testTrunc(comptime T: type, x: T) !void {
11561217 {
11571218 const y = x + 0.8;
11581219 const z = @trunc(y);
1159 try expectEqual(x, z);
1220 try expect(x == z);
11601221 }
11611222
11621223 {
11631224 const y = -x - 0.8;
11641225 const z = @trunc(y);
1165 try expectEqual(-x, z);
1226 try expect(-x == z);
11661227 }
11671228}
11681229
11691230test "@round" {
11701231 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
11711232
1172 // FIXME: Generates a roundl function call
1173 //testRound(f128, 12.0);
1174 comptime try testRound(f128, 12.0);
1175 // try testRound(f80, 12.0);
1176 comptime try testRound(f80, 12.0);
11771233 try testRound(f64, 12.0);
11781234 comptime try testRound(f64, 12.0);
11791235 try testRound(f32, 12.0);
......@@ -1184,13 +1240,35 @@ test "@round" {
11841240 const x = 14.0;
11851241 const y = x + 0.4;
11861242 const z = @round(y);
1187 comptime try expectEqual(x, z);
1243 comptime try expect(x == z);
1244}
1245
1246test "@round f80" {
1247 if (true) {
1248 // https://github.com/ziglang/zig/issues/11030
1249 return error.SkipZigTest;
1250 }
1251
1252 try testRound(f80, 12.0);
1253 comptime try testRound(f80, 12.0);
1254}
1255
1256test "@round f128" {
1257 if (builtin.zig_backend == .stage1) {
1258 // Fails because it incorrectly lowers to a roundl function call.
1259 return error.SkipZigTest;
1260 }
1261
1262 if (builtin.zig_backend != .stage1) return error.SkipZigTest; // TODO
1263
1264 testRound(f128, 12.0);
1265 comptime try testRound(f128, 12.0);
11881266}
11891267
11901268fn testRound(comptime T: type, x: T) !void {
11911269 const y = x - 0.5;
11921270 const z = @round(y);
1193 try expectEqual(x, z);
1271 try expect(x == z);
11941272}
11951273
11961274test "vector integer addition" {
......@@ -1225,10 +1303,15 @@ test "NaN comparison" {
12251303 comptime try testNanEqNan(f32);
12261304 comptime try testNanEqNan(f64);
12271305 comptime try testNanEqNan(f128);
1306}
12281307
1229 // TODO https://github.com/ziglang/zig/issues/11030
1230 // try testNanEqNan(f80);
1231 // comptime try testNanEqNan(f80);
1308test "NaN comparison f80" {
1309 if (true) {
1310 // https://github.com/ziglang/zig/issues/11030
1311 return error.SkipZigTest;
1312 }
1313 try testNanEqNan(f80);
1314 comptime try testNanEqNan(f80);
12321315}
12331316
12341317fn testNanEqNan(comptime F: type) !void {