authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-01 14:39:56-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-11-01 14:39:56-07:00
log2e1cef75086a0b606fd8f1f7a0cda4ab2f0b7a49
treef7c21db843acab17d344a7dfa2bf4be21d5facb1
parentd530e7f9c7e19b2c9d9117c3120cd75855f4023b
parentf4ed5d7d480db29d5b3142bacb9d0b98eee0fa2b

Merge branch 'LemonBoy-morereduce'


11 files changed, 211 insertions(+), 13 deletions(-)

doc/langref.html.in+43
...@@ -8209,6 +8209,49 @@ test "vector @splat" {...@@ -8209,6 +8209,49 @@ test "vector @splat" {
8209 </p>8209 </p>
8210 {#see_also|Vectors|@shuffle#}8210 {#see_also|Vectors|@shuffle#}
8211 {#header_close#}8211 {#header_close#}
8212
8213 {#header_open|@reduce#}
8214 <pre>{#syntax#}@reduce(comptime op: builtin.ReduceOp, value: anytype) std.meta.Child(value){#endsyntax#}</pre>
8215 <p>
8216 Transforms a {#link|vector|Vectors#} into a scalar value by performing a
8217 sequential horizontal reduction of its elements using the specified
8218 specified operator {#syntax#}op{#endsyntax#}.
8219 </p>
8220 <p>
8221 Not every operator is available for every vector element type:
8222 </p>
8223 <ul>
8224 <li>{#syntax#}.And{#endsyntax#}, {#syntax#}.Or{#endsyntax#},
8225 {#syntax#}.Xor{#endsyntax#} are available for
8226 {#syntax#}bool{#endsyntax#} vectors,</li>
8227 <li>{#syntax#}.Min{#endsyntax#}, {#syntax#}.Max{#endsyntax#},
8228 {#syntax#}.Add{#endsyntax#}, {#syntax#}.Mul{#endsyntax#} are
8229 available for {#link|floating point|Floats#} vectors,</li>
8230 <li>Every operator is available for {#link|integer|Integers#} vectors.
8231 </ul>
8232 <p>
8233 Note that {#syntax#}.Add{#endsyntax#} and {#syntax#}.Mul{#endsyntax#}
8234 reductions on integral types are wrapping; when applied on floating point
8235 types the operation associativity is preserved, unless the float mode is
8236 set to {#syntax#}Optimized{#endsyntax#}.
8237 </p>
8238 {#code_begin|test#}
8239const std = @import("std");
8240const expect = std.testing.expect;
8241
8242test "vector @reduce" {
8243 const value: std.meta.Vector(4, i32) = [_]i32{ 1, -1, 1, -1 };
8244 const result = value > @splat(4, @as(i32, 0));
8245 // result is { true, false, true, false };
8246 comptime expect(@TypeOf(result) == std.meta.Vector(4, bool));
8247 const is_all_true = @reduce(.And, result);
8248 comptime expect(@TypeOf(is_all_true) == bool);
8249 expect(is_all_true == false);
8250}
8251 {#code_end#}
8252 {#see_also|Vectors|@setFloatMode#}
8253 {#header_close#}
8254
8212 {#header_open|@src#}8255 {#header_open|@src#}
8213 <pre>{#syntax#}@src() std.builtin.SourceLocation{#endsyntax#}</pre>8256 <pre>{#syntax#}@src() std.builtin.SourceLocation{#endsyntax#}</pre>
8214 <p>8257 <p>
lib/std/builtin.zig+2
...@@ -106,6 +106,8 @@ pub const ReduceOp = enum {...@@ -106,6 +106,8 @@ pub const ReduceOp = enum {
106 Xor,106 Xor,
107 Min,107 Min,
108 Max,108 Max,
109 Add,
110 Mul,
109};111};
110112
111/// This data structure is used by the Zig language code generation and113/// This data structure is used by the Zig language code generation and
lib/std/testing.zig+21-9
...@@ -4,6 +4,7 @@...@@ -4,6 +4,7 @@
4// The MIT license requires this copyright notice to be included in all copies4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.5// and substantial portions of the software.
6const std = @import("std.zig");6const std = @import("std.zig");
7const math = std.math;
7const print = std.debug.print;8const print = std.debug.print;
89
9pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator;10pub const FailingAllocator = @import("testing/failing_allocator.zig").FailingAllocator;
...@@ -198,11 +199,16 @@ pub fn expectWithinMargin(expected: anytype, actual: @TypeOf(expected), margin:...@@ -198,11 +199,16 @@ pub fn expectWithinMargin(expected: anytype, actual: @TypeOf(expected), margin:
198 }199 }
199}200}
200201
201test "expectWithinMargin.f32" {202test "expectWithinMargin" {
202 const x: f32 = 12.0;203 inline for ([_]type{ f16, f32, f64, f128 }) |T| {
203 const y: f32 = 12.06;204 const pos_x: T = 12.0;
205 const pos_y: T = 12.06;
206 const neg_x: T = -12.0;
207 const neg_y: T = -12.06;
204208
205 expectWithinMargin(x, y, 0.1);209 expectWithinMargin(pos_x, pos_y, 0.1);
210 expectWithinMargin(neg_x, neg_y, 0.1);
211 }
206}212}
207213
208/// This function is intended to be used only in tests. When the actual value is not214/// This function is intended to be used only in tests. When the actual value is not
...@@ -212,7 +218,8 @@ test "expectWithinMargin.f32" {...@@ -212,7 +218,8 @@ test "expectWithinMargin.f32" {
212pub fn expectWithinEpsilon(expected: anytype, actual: @TypeOf(expected), epsilon: @TypeOf(expected)) void {218pub fn expectWithinEpsilon(expected: anytype, actual: @TypeOf(expected), epsilon: @TypeOf(expected)) void {
213 std.debug.assert(epsilon >= 0.0 and epsilon <= 1.0);219 std.debug.assert(epsilon >= 0.0 and epsilon <= 1.0);
214220
215 const margin = epsilon * expected;221 // Relative epsilon test.
222 const margin = math.max(math.fabs(expected), math.fabs(actual)) * epsilon;
216 switch (@typeInfo(@TypeOf(actual))) {223 switch (@typeInfo(@TypeOf(actual))) {
217 .Float,224 .Float,
218 .ComptimeFloat,225 .ComptimeFloat,
...@@ -225,11 +232,16 @@ pub fn expectWithinEpsilon(expected: anytype, actual: @TypeOf(expected), epsilon...@@ -225,11 +232,16 @@ pub fn expectWithinEpsilon(expected: anytype, actual: @TypeOf(expected), epsilon
225 }232 }
226}233}
227234
228test "expectWithinEpsilon.f32" {235test "expectWithinEpsilon" {
229 const x: f32 = 12.0;236 inline for ([_]type{ f16, f32, f64, f128 }) |T| {
230 const y: f32 = 13.2;237 const pos_x: T = 12.0;
238 const pos_y: T = 13.2;
239 const neg_x: T = -12.0;
240 const neg_y: T = -13.2;
231241
232 expectWithinEpsilon(x, y, 0.1);242 expectWithinEpsilon(pos_x, pos_y, 0.1);
243 expectWithinEpsilon(neg_x, neg_y, 0.1);
244 }
233}245}
234246
235/// This function is intended to be used only in tests. When the two slices are not247/// This function is intended to be used only in tests. When the two slices are not
src/stage1/all_types.hpp+2
...@@ -2447,6 +2447,8 @@ enum ReduceOp {...@@ -2447,6 +2447,8 @@ enum ReduceOp {
2447 ReduceOp_xor,2447 ReduceOp_xor,
2448 ReduceOp_min,2448 ReduceOp_min,
2449 ReduceOp_max,2449 ReduceOp_max,
2450 ReduceOp_add,
2451 ReduceOp_mul,
2450};2452};
24512453
2452// synchronized with the code in define_builtin_compile_vars2454// synchronized with the code in define_builtin_compile_vars
src/stage1/codegen.cpp+20
...@@ -5460,6 +5460,8 @@ static LLVMValueRef ir_render_reduce(CodeGen *g, IrExecutableGen *executable, Ir...@@ -5460,6 +5460,8 @@ static LLVMValueRef ir_render_reduce(CodeGen *g, IrExecutableGen *executable, Ir
5460 assert(value_type->id == ZigTypeIdVector);5460 assert(value_type->id == ZigTypeIdVector);
5461 ZigType *scalar_type = value_type->data.vector.elem_type;5461 ZigType *scalar_type = value_type->data.vector.elem_type;
54625462
5463 ZigLLVMSetFastMath(g->builder, ir_want_fast_math(g, &instruction->base));
5464
5463 LLVMValueRef result_val;5465 LLVMValueRef result_val;
5464 switch (instruction->op) {5466 switch (instruction->op) {
5465 case ReduceOp_and:5467 case ReduceOp_and:
...@@ -5490,6 +5492,24 @@ static LLVMValueRef ir_render_reduce(CodeGen *g, IrExecutableGen *executable, Ir...@@ -5490,6 +5492,24 @@ static LLVMValueRef ir_render_reduce(CodeGen *g, IrExecutableGen *executable, Ir
5490 result_val = ZigLLVMBuildFPMaxReduce(g->builder, value);5492 result_val = ZigLLVMBuildFPMaxReduce(g->builder, value);
5491 } else zig_unreachable();5493 } else zig_unreachable();
5492 } break;5494 } break;
5495 case ReduceOp_add: {
5496 if (scalar_type->id == ZigTypeIdInt) {
5497 result_val = ZigLLVMBuildAddReduce(g->builder, value);
5498 } else if (scalar_type->id == ZigTypeIdFloat) {
5499 LLVMValueRef neutral_value = LLVMConstReal(
5500 get_llvm_type(g, scalar_type), -0.0);
5501 result_val = ZigLLVMBuildFPAddReduce(g->builder, neutral_value, value);
5502 } else zig_unreachable();
5503 } break;
5504 case ReduceOp_mul: {
5505 if (scalar_type->id == ZigTypeIdInt) {
5506 result_val = ZigLLVMBuildMulReduce(g->builder, value);
5507 } else if (scalar_type->id == ZigTypeIdFloat) {
5508 LLVMValueRef neutral_value = LLVMConstReal(
5509 get_llvm_type(g, scalar_type), 1.0);
5510 result_val = ZigLLVMBuildFPMulReduce(g->builder, neutral_value, value);
5511 } else zig_unreachable();
5512 } break;
5493 default:5513 default:
5494 zig_unreachable();5514 zig_unreachable();
5495 }5515 }
src/stage1/ir.cpp+41-3
...@@ -10953,13 +10953,13 @@ static bool float_is_nan(ZigValue *op) {...@@ -10953,13 +10953,13 @@ static bool float_is_nan(ZigValue *op) {
10953 } else if (op->type->id == ZigTypeIdFloat) {10953 } else if (op->type->id == ZigTypeIdFloat) {
10954 switch (op->type->data.floating.bit_count) {10954 switch (op->type->data.floating.bit_count) {
10955 case 16:10955 case 16:
10956 return f16_isSignalingNaN(op->data.x_f16);10956 return zig_f16_isNaN(op->data.x_f16);
10957 case 32:10957 case 32:
10958 return op->data.x_f32 != op->data.x_f32;10958 return op->data.x_f32 != op->data.x_f32;
10959 case 64:10959 case 64:
10960 return op->data.x_f64 != op->data.x_f64;10960 return op->data.x_f64 != op->data.x_f64;
10961 case 128:10961 case 128:
10962 return f128M_isSignalingNaN(&op->data.x_f128);10962 return zig_f128_isNaN(&op->data.x_f128);
10963 default:10963 default:
10964 zig_unreachable();10964 zig_unreachable();
10965 }10965 }
...@@ -27046,7 +27046,8 @@ static ErrorMsg *ir_eval_reduce(IrAnalyze *ira, IrInst *source_instr, ReduceOp o...@@ -27046,7 +27046,8 @@ static ErrorMsg *ir_eval_reduce(IrAnalyze *ira, IrInst *source_instr, ReduceOp o
27046 return nullptr;27046 return nullptr;
27047 }27047 }
2704827048
27049 if (op != ReduceOp_min && op != ReduceOp_max) {27049 // Evaluate and/or/xor.
27050 if (op == ReduceOp_and || op == ReduceOp_or || op == ReduceOp_xor) {
27050 ZigValue *first_elem_val = &value->data.x_array.data.s_none.elements[0];27051 ZigValue *first_elem_val = &value->data.x_array.data.s_none.elements[0];
2705127052
27052 copy_const_val(ira->codegen, out_value, first_elem_val);27053 copy_const_val(ira->codegen, out_value, first_elem_val);
...@@ -27071,6 +27072,43 @@ static ErrorMsg *ir_eval_reduce(IrAnalyze *ira, IrInst *source_instr, ReduceOp o...@@ -27071,6 +27072,43 @@ static ErrorMsg *ir_eval_reduce(IrAnalyze *ira, IrInst *source_instr, ReduceOp o
27071 return nullptr;27072 return nullptr;
27072 }27073 }
2707327074
27075 // Evaluate add/sub.
27076 // Perform the reduction sequentially, starting from the neutral value.
27077 if (op == ReduceOp_add || op == ReduceOp_mul) {
27078 if (scalar_type->id == ZigTypeIdInt) {
27079 if (op == ReduceOp_add) {
27080 bigint_init_unsigned(&out_value->data.x_bigint, 0);
27081 } else {
27082 bigint_init_unsigned(&out_value->data.x_bigint, 1);
27083 }
27084 } else {
27085 if (op == ReduceOp_add) {
27086 float_init_f64(out_value, -0.0);
27087 } else {
27088 float_init_f64(out_value, 1.0);
27089 }
27090 }
27091
27092 for (size_t i = 0; i < len; i++) {
27093 ZigValue *elem_val = &value->data.x_array.data.s_none.elements[i];
27094
27095 IrBinOp bin_op;
27096 switch (op) {
27097 case ReduceOp_add: bin_op = IrBinOpAdd; break;
27098 case ReduceOp_mul: bin_op = IrBinOpMult; break;
27099 default: zig_unreachable();
27100 }
27101
27102 ErrorMsg *msg = ir_eval_math_op_scalar(ira, source_instr, scalar_type,
27103 out_value, bin_op, elem_val, out_value);
27104 if (msg != nullptr)
27105 return msg;
27106 }
27107
27108 return nullptr;
27109 }
27110
27111 // Evaluate min/max.
27074 ZigValue *candidate_elem_val = &value->data.x_array.data.s_none.elements[0];27112 ZigValue *candidate_elem_val = &value->data.x_array.data.s_none.elements[0];
2707527113
27076 ZigValue *dummy_cmp_value = ira->codegen->pass1_arena->create<ZigValue>();27114 ZigValue *dummy_cmp_value = ira->codegen->pass1_arena->create<ZigValue>();
src/stage1/ir_print.cpp+2
...@@ -1611,6 +1611,8 @@ static const char *reduce_op_str(ReduceOp op) {...@@ -1611,6 +1611,8 @@ static const char *reduce_op_str(ReduceOp op) {
1611 case ReduceOp_xor: return "Xor";1611 case ReduceOp_xor: return "Xor";
1612 case ReduceOp_min: return "Min";1612 case ReduceOp_min: return "Min";
1613 case ReduceOp_max: return "Max";1613 case ReduceOp_max: return "Max";
1614 case ReduceOp_add: return "Add";
1615 case ReduceOp_mul: return "Mul";
1614 }1616 }
1615 zig_unreachable();1617 zig_unreachable();
1616}1618}
src/stage1/softfloat.hpp+13
...@@ -29,4 +29,17 @@ static inline double zig_f16_to_double(float16_t x) {...@@ -29,4 +29,17 @@ static inline double zig_f16_to_double(float16_t x) {
29 return z;29 return z;
30}30}
3131
32static inline bool zig_f16_isNaN(float16_t a) {
33 union { uint16_t ui; float16_t f; } uA;
34 uA.f = a;
35 return 0x7C00 < (uA.ui & 0x7FFF);
36}
37
38static inline bool zig_f128_isNaN(float128_t *aPtr) {
39 uint64_t absA64 = aPtr->v[1] & UINT64_C(0x7FFFFFFFFFFFFFFF);
40 return
41 (UINT64_C(0x7FFF000000000000) < absA64)
42 || ((absA64 == UINT64_C(0x7FFF000000000000)) && aPtr->v[0]);
43}
44
32#endif45#endif
src/zig_llvm.cpp+16
...@@ -1156,6 +1156,22 @@ LLVMValueRef ZigLLVMBuildFPMinReduce(LLVMBuilderRef B, LLVMValueRef Val) {...@@ -1156,6 +1156,22 @@ LLVMValueRef ZigLLVMBuildFPMinReduce(LLVMBuilderRef B, LLVMValueRef Val) {
1156 return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Val)));1156 return wrap(unwrap(B)->CreateFPMinReduce(unwrap(Val)));
1157}1157}
11581158
1159LLVMValueRef ZigLLVMBuildAddReduce(LLVMBuilderRef B, LLVMValueRef Val) {
1160 return wrap(unwrap(B)->CreateAddReduce(unwrap(Val)));
1161}
1162
1163LLVMValueRef ZigLLVMBuildMulReduce(LLVMBuilderRef B, LLVMValueRef Val) {
1164 return wrap(unwrap(B)->CreateMulReduce(unwrap(Val)));
1165}
1166
1167LLVMValueRef ZigLLVMBuildFPAddReduce(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Val) {
1168 return wrap(unwrap(B)->CreateFAddReduce(unwrap(Acc), unwrap(Val)));
1169}
1170
1171LLVMValueRef ZigLLVMBuildFPMulReduce(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Val) {
1172 return wrap(unwrap(B)->CreateFMulReduce(unwrap(Acc), unwrap(Val)));
1173}
1174
1159static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, "");1175static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, "");
1160static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, "");1176static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, "");
1161static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, "");1177static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, "");
src/zig_llvm.h+4
...@@ -462,6 +462,10 @@ LLVMValueRef ZigLLVMBuildIntMaxReduce(LLVMBuilderRef B, LLVMValueRef Val, bool i...@@ -462,6 +462,10 @@ LLVMValueRef ZigLLVMBuildIntMaxReduce(LLVMBuilderRef B, LLVMValueRef Val, bool i
462LLVMValueRef ZigLLVMBuildIntMinReduce(LLVMBuilderRef B, LLVMValueRef Val, bool is_signed);462LLVMValueRef ZigLLVMBuildIntMinReduce(LLVMBuilderRef B, LLVMValueRef Val, bool is_signed);
463LLVMValueRef ZigLLVMBuildFPMaxReduce(LLVMBuilderRef B, LLVMValueRef Val);463LLVMValueRef ZigLLVMBuildFPMaxReduce(LLVMBuilderRef B, LLVMValueRef Val);
464LLVMValueRef ZigLLVMBuildFPMinReduce(LLVMBuilderRef B, LLVMValueRef Val);464LLVMValueRef ZigLLVMBuildFPMinReduce(LLVMBuilderRef B, LLVMValueRef Val);
465LLVMValueRef ZigLLVMBuildAddReduce(LLVMBuilderRef B, LLVMValueRef Val);
466LLVMValueRef ZigLLVMBuildMulReduce(LLVMBuilderRef B, LLVMValueRef Val);
467LLVMValueRef ZigLLVMBuildFPAddReduce(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Val);
468LLVMValueRef ZigLLVMBuildFPMulReduce(LLVMBuilderRef B, LLVMValueRef Acc, LLVMValueRef Val);
465469
466#define ZigLLVM_DIFlags_Zero 0U470#define ZigLLVM_DIFlags_Zero 0U
467#define ZigLLVM_DIFlags_Private 1U471#define ZigLLVM_DIFlags_Private 1U
test/stage1/behavior/vector.zig+47-1
...@@ -4,6 +4,7 @@ const mem = std.mem;...@@ -4,6 +4,7 @@ const mem = std.mem;
4const math = std.math;4const math = std.math;
5const expect = std.testing.expect;5const expect = std.testing.expect;
6const expectEqual = std.testing.expectEqual;6const expectEqual = std.testing.expectEqual;
7const expectWithinEpsilon = std.testing.expectWithinEpsilon;
7const Vector = std.meta.Vector;8const Vector = std.meta.Vector;
89
9test "implicit cast vector to array - bool" {10test "implicit cast vector to array - bool" {
...@@ -492,7 +493,17 @@ test "vector reduce operation" {...@@ -492,7 +493,17 @@ test "vector reduce operation" {
492 const TX = @typeInfo(@TypeOf(x)).Array.child;493 const TX = @typeInfo(@TypeOf(x)).Array.child;
493494
494 var r = @reduce(op, @as(Vector(N, TX), x));495 var r = @reduce(op, @as(Vector(N, TX), x));
495 expectEqual(expected, r);496 switch (@typeInfo(TX)) {
497 .Int, .Bool => expectEqual(expected, r),
498 .Float => {
499 if (math.isNan(expected) != math.isNan(r)) {
500 std.debug.panic("unexpected NaN value!", .{});
501 } else {
502 expectWithinEpsilon(expected, r, 0.0001);
503 }
504 },
505 else => unreachable,
506 }
496 }507 }
497 fn doTheTest() void {508 fn doTheTest() void {
498 doTheTestReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false));509 doTheTestReduce(.And, [4]bool{ true, false, true, true }, @as(bool, false));
...@@ -510,14 +521,49 @@ test "vector reduce operation" {...@@ -510,14 +521,49 @@ test "vector reduce operation" {
510 doTheTestReduce(.Min, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, -386));521 doTheTestReduce(.Min, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, -386));
511 doTheTestReduce(.Max, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, 1234567));522 doTheTestReduce(.Max, [4]i32{ 1234567, -386, 0, 3 }, @as(i32, 1234567));
512523
524 doTheTestReduce(.Add, [4]i32{ -9, -99, -999, -9999 }, @as(i32, -11106));
525 doTheTestReduce(.Add, [4]i64{ 9, 99, 999, 9999 }, @as(i64, 11106));
526
513 doTheTestReduce(.Min, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 9));527 doTheTestReduce(.Min, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 9));
514 doTheTestReduce(.Max, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 99999));528 doTheTestReduce(.Max, [4]u32{ 99, 9999, 9, 99999 }, @as(u32, 99999));
515529
530 doTheTestReduce(.Mul, [4]i32{ -9, -99, -999, 999 }, @as(i32, -889218891));
531 doTheTestReduce(.Mul, [4]i64{ 9, 99, 999, 9999 }, @as(i64, 8900199891));
532
516 doTheTestReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0));533 doTheTestReduce(.Min, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, -100.0));
517 doTheTestReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9));534 doTheTestReduce(.Max, [4]f32{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f32, 10.0e9));
518535
519 doTheTestReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0));536 doTheTestReduce(.Min, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, -100.0));
520 doTheTestReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9));537 doTheTestReduce(.Max, [4]f64{ -10.3, 10.0e9, 13.0, -100.0 }, @as(f64, 10.0e9));
538
539 doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 42.9));
540 doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 42.9));
541
542 doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, -60.3, 100.0 }, @as(f32, 58430.7));
543 doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, -60.3, 100.0 }, @as(f64, 58430.7));
544
545 // Test the reduction on vectors containing NaNs.
546 const f16_nan = math.nan(f16);
547 const f32_nan = math.nan(f32);
548 const f64_nan = math.nan(f64);
549
550 doTheTestReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
551 doTheTestReduce(.Add, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
552
553 doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
554 doTheTestReduce(.Add, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
555
556 doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
557 doTheTestReduce(.Add, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
558
559 doTheTestReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
560 doTheTestReduce(.Mul, [4]f16{ -1.9, 5.1, f16_nan, 100.0 }, f16_nan);
561
562 doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
563 doTheTestReduce(.Mul, [4]f32{ -1.9, 5.1, f32_nan, 100.0 }, f32_nan);
564
565 doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
566 doTheTestReduce(.Mul, [4]f64{ -1.9, 5.1, f64_nan, 100.0 }, f64_nan);
521 }567 }
522 };568 };
523569