675 lines · cpp
1//===-- unittests/Runtime/Reduction.cpp -------------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "flang/Runtime/reduction.h"10#include "tools.h"11#include "gtest/gtest.h"12#include "flang-rt/runtime/descriptor.h"13#include "flang-rt/runtime/type-code.h"14#include "flang/Common/float128.h"15#include "flang/Runtime/allocatable.h"16#include "flang/Runtime/cpp-type.h"17#include "flang/Runtime/reduce.h"18#include <cstdint>19#include <cstring>20#include <string>21#include <vector>22 23using namespace Fortran::runtime;24using Fortran::common::TypeCategory;25 26TEST(Reductions, Int4Ops) {27 auto array{MakeArray<TypeCategory::Integer, 4>(28 std::vector<int>{2, 3}, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};29 std::int32_t sum{RTNAME(SumInteger4)(*array, __FILE__, __LINE__)};30 EXPECT_EQ(sum, 21) << sum;31 std::int32_t all{RTNAME(IAll4)(*array, __FILE__, __LINE__)};32 EXPECT_EQ(all, 0) << all;33 std::int32_t any{RTNAME(IAny4)(*array, __FILE__, __LINE__)};34 EXPECT_EQ(any, 7) << any;35 std::int32_t eor{RTNAME(IParity4)(*array, __FILE__, __LINE__)};36 EXPECT_EQ(eor, 7) << eor;37}38 39TEST(Reductions, DimMaskProductInt4) {40 std::vector<int> shape{2, 3};41 auto array{MakeArray<TypeCategory::Integer, 4>(42 shape, std::vector<std::int32_t>{1, 2, 3, 4, 5, 6})};43 auto mask{MakeArray<TypeCategory::Logical, 1>(44 shape, std::vector<bool>{true, false, false, true, true, true})};45 StaticDescriptor<maxRank, true> statDesc;46 Descriptor &prod{statDesc.descriptor()};47 RTNAME(ProductDim)(prod, *array, 1, __FILE__, __LINE__, &*mask);48 EXPECT_EQ(prod.rank(), 1);49 EXPECT_EQ(prod.GetDimension(0).LowerBound(), 1);50 EXPECT_EQ(prod.GetDimension(0).Extent(), 3);51 EXPECT_EQ(*prod.ZeroBasedIndexedElement<std::int32_t>(0), 1);52 EXPECT_EQ(*prod.ZeroBasedIndexedElement<std::int32_t>(1), 4);53 EXPECT_EQ(*prod.ZeroBasedIndexedElement<std::int32_t>(2), 30);54 EXPECT_EQ(RTNAME(SumInteger4)(prod, __FILE__, __LINE__), 35);55 prod.Destroy();56}57 58TEST(Reductions, DoubleMaxMinNorm2) {59 std::vector<int> shape{3, 4, 2}; // rows, columns, planes60 // 0 -3 6 -9 12 -15 18 -2161 // -1 4 -7 10 -13 16 -19 2262 // 2 -5 8 -11 14 -17 20 22 <- note last two are equal to test63 // BACK=64 std::vector<double> rawData{0, -1, 2, -3, 4, -5, 6, -7, 8, -9, 10, -11, 12,65 -13, 14, -15, 16, -17, 18, -19, 20, -21, 22, 22};66 auto array{MakeArray<TypeCategory::Real, 8>(shape, rawData)};67 EXPECT_EQ(RTNAME(MaxvalReal8)(*array, __FILE__, __LINE__), 22.0);68 EXPECT_EQ(RTNAME(MinvalReal8)(*array, __FILE__, __LINE__), -21.0);69 double naiveNorm2{0};70 for (auto x : rawData) {71 naiveNorm2 += x * x;72 }73 naiveNorm2 = std::sqrt(naiveNorm2);74 double norm2Error{75 std::abs(naiveNorm2 - RTNAME(Norm2_8)(*array, __FILE__, __LINE__))};76 EXPECT_LE(norm2Error, 0.000001 * naiveNorm2);77 StaticDescriptor<2, true> statDesc;78 Descriptor &loc{statDesc.descriptor()};79 RTNAME(MaxlocReal8)80 (loc, *array, /*KIND=*/8, __FILE__, __LINE__, /*MASK=*/nullptr,81 /*BACK=*/false);82 EXPECT_EQ(loc.rank(), 1);83 EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));84 EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1);85 EXPECT_EQ(loc.GetDimension(0).Extent(), 3);86 EXPECT_EQ(87 *array->Element<double>(loc.ZeroBasedIndexedElement<SubscriptValue>(0)),88 22.0);89 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(0), 2);90 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(1), 4);91 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(2), 2);92 loc.Destroy();93 RTNAME(MaxlocReal8)94 (loc, *array, /*KIND=*/8, __FILE__, __LINE__, /*MASK=*/nullptr,95 /*BACK=*/true);96 EXPECT_EQ(loc.rank(), 1);97 EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));98 EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1);99 EXPECT_EQ(loc.GetDimension(0).Extent(), 3);100 EXPECT_EQ(101 *array->Element<double>(loc.ZeroBasedIndexedElement<SubscriptValue>(0)),102 22.0);103 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(0), 3);104 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(1), 4);105 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int64_t>(2), 2);106 loc.Destroy();107 RTNAME(MinlocDim)108 (loc, *array, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr,109 /*BACK=*/false);110 EXPECT_EQ(loc.rank(), 2);111 EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 2}.raw()));112 EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1);113 EXPECT_EQ(loc.GetDimension(0).Extent(), 4);114 EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1);115 EXPECT_EQ(loc.GetDimension(1).Extent(), 2);116 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(0), 2); // -1117 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(1), 3); // -5118 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(2), 2); // -2119 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(3), 3); // -11120 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(4), 2); // -13121 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(5), 3); // -17122 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(6), 2); // -19123 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(7), 1); // -21124 loc.Destroy();125 auto mask{MakeArray<TypeCategory::Logical, 1>(shape,126 std::vector<bool>{false, false, false, false, false, true, false, true,127 false, false, true, true, true, false, false, true, false, true, true,128 true, false, true, true, true})};129 RTNAME(MaxlocDim)130 (loc, *array, /*KIND=*/2, /*DIM=*/3, __FILE__, __LINE__, /*MASK=*/&*mask,131 false);132 EXPECT_EQ(loc.rank(), 2);133 EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 2}.raw()));134 EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1);135 EXPECT_EQ(loc.GetDimension(0).Extent(), 3);136 EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1);137 EXPECT_EQ(loc.GetDimension(1).Extent(), 4);138 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(0), 2); // 12139 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(1), 0);140 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(2), 0);141 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(3), 2); // -15142 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(4), 0);143 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(5), 1); // -5144 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(6), 2); // 18145 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(7), 1); // -7146 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(8), 0);147 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(9), 2); // -21148 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(10), 2); // 22149 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int16_t>(11), 2); // 22150 loc.Destroy();151 // Test scalar result for MaxlocDim, MinlocDim, MaxvalDim, MinvalDim.152 // A scalar result occurs when you have a rank 1 array and dim == 1.153 std::vector<int> shape1{24};154 auto array1{MakeArray<TypeCategory::Real, 8>(shape1, rawData)};155 StaticDescriptor<2, true> statDesc0[1];156 Descriptor &scalarResult{statDesc0[0].descriptor()};157 RTNAME(MaxlocDim)158 (scalarResult, *array1, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__,159 /*MASK=*/nullptr, /*BACK=*/false);160 EXPECT_EQ(scalarResult.rank(), 0);161 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int16_t>(0), 23);162 scalarResult.Destroy();163 164 // Test .FALSE. scalar MASK argument165 auto falseMask{MakeArray<TypeCategory::Logical, 4>(166 std::vector<int>{}, std::vector<std::int32_t>{0})};167 RTNAME(MaxlocDim)168 (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__,169 /*MASK=*/&*falseMask, /*BACK=*/false);170 EXPECT_EQ(loc.rank(), 2);171 EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));172 EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1);173 EXPECT_EQ(loc.GetDimension(0).Extent(), 3);174 EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1);175 EXPECT_EQ(loc.GetDimension(1).Extent(), 2);176 for (int i{0}; i < 6; ++i) {177 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(0), 0);178 }179 loc.Destroy();180 181 // Test .TRUE. scalar MASK argument182 auto trueMask{MakeArray<TypeCategory::Logical, 4>(183 std::vector<int>{}, std::vector<std::int32_t>{1})};184 RTNAME(MaxlocDim)185 (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__,186 /*MASK=*/&*trueMask, /*BACK=*/false);187 EXPECT_EQ(loc.rank(), 2);188 EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));189 EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1);190 EXPECT_EQ(loc.GetDimension(0).Extent(), 3);191 EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1);192 EXPECT_EQ(loc.GetDimension(1).Extent(), 2);193 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(0), 3);194 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(1), 4);195 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(2), 3);196 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(3), 3);197 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(4), 4);198 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(5), 4);199 loc.Destroy();200 201 RTNAME(MinlocDim)202 (scalarResult, *array1, /*KIND=*/2, /*DIM=*/1, __FILE__, __LINE__,203 /*MASK=*/nullptr, /*BACK=*/true);204 EXPECT_EQ(scalarResult.rank(), 0);205 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int16_t>(0), 22);206 scalarResult.Destroy();207 208 // Test .FALSE. scalar MASK argument209 RTNAME(MinlocDim)210 (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__,211 /*MASK=*/&*falseMask, /*BACK=*/false);212 EXPECT_EQ(loc.rank(), 2);213 EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));214 EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1);215 EXPECT_EQ(loc.GetDimension(0).Extent(), 3);216 EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1);217 EXPECT_EQ(loc.GetDimension(1).Extent(), 2);218 for (int i{0}; i < 6; ++i) {219 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(0), 0);220 }221 loc.Destroy();222 223 // Test .TRUE. scalar MASK argument224 RTNAME(MinlocDim)225 (loc, *array, /*KIND=*/4, /*DIM=*/2, __FILE__, __LINE__,226 /*MASK=*/&*trueMask, /*BACK=*/false);227 EXPECT_EQ(loc.rank(), 2);228 EXPECT_EQ(loc.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));229 EXPECT_EQ(loc.GetDimension(0).LowerBound(), 1);230 EXPECT_EQ(loc.GetDimension(0).Extent(), 3);231 EXPECT_EQ(loc.GetDimension(1).LowerBound(), 1);232 EXPECT_EQ(loc.GetDimension(1).Extent(), 2);233 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(0), 4);234 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(1), 3);235 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(2), 4);236 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(3), 4);237 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(4), 3);238 EXPECT_EQ(*loc.ZeroBasedIndexedElement<std::int32_t>(5), 2);239 loc.Destroy();240 241 RTNAME(MaxvalDim)242 (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr);243 EXPECT_EQ(scalarResult.rank(), 0);244 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<double>(0), 22.0);245 scalarResult.Destroy();246 RTNAME(MinvalDim)247 (scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__, /*MASK=*/nullptr);248 EXPECT_EQ(scalarResult.rank(), 0);249 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<double>(0), -21.0);250 scalarResult.Destroy();251}252 253TEST(Reductions, Character) {254 std::vector<int> shape{2, 3};255 auto array{MakeArray<TypeCategory::Character, 1>(shape,256 std::vector<std::string>{"abc", "def", "ghi", "jkl", "mno", "abc"}, 3)};257 StaticDescriptor<1, true> statDesc[2];258 Descriptor &res{statDesc[0].descriptor()};259 RTNAME(MaxvalCharacter)(res, *array, __FILE__, __LINE__);260 EXPECT_EQ(res.rank(), 0);261 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Character, 1}.raw()));262 EXPECT_EQ(std::memcmp(res.OffsetElement<char>(), "mno", 3), 0);263 res.Destroy();264 RTNAME(MinvalCharacter)(res, *array, __FILE__, __LINE__);265 EXPECT_EQ(res.rank(), 0);266 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Character, 1}.raw()));267 EXPECT_EQ(std::memcmp(res.OffsetElement<char>(), "abc", 3), 0);268 res.Destroy();269 RTNAME(MaxlocCharacter)270 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr,271 /*BACK=*/false);272 EXPECT_EQ(res.rank(), 1);273 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));274 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);275 EXPECT_EQ(res.GetDimension(0).Extent(), 2);276 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1);277 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3);278 res.Destroy();279 auto mask{MakeArray<TypeCategory::Logical, 1>(280 shape, std::vector<bool>{false, true, false, true, false, true})};281 RTNAME(MaxlocCharacter)282 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/&*mask,283 /*BACK=*/false);284 EXPECT_EQ(res.rank(), 1);285 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));286 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);287 EXPECT_EQ(res.GetDimension(0).Extent(), 2);288 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2);289 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2);290 res.Destroy();291 RTNAME(MinlocCharacter)292 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr,293 /*BACK=*/false);294 EXPECT_EQ(res.rank(), 1);295 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));296 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);297 EXPECT_EQ(res.GetDimension(0).Extent(), 2);298 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1);299 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1);300 res.Destroy();301 RTNAME(MinlocCharacter)302 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/nullptr,303 /*BACK=*/true);304 EXPECT_EQ(res.rank(), 1);305 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));306 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);307 EXPECT_EQ(res.GetDimension(0).Extent(), 2);308 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2);309 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3);310 res.Destroy();311 RTNAME(MinlocCharacter)312 (res, *array, /*KIND=*/4, __FILE__, __LINE__, /*MASK=*/&*mask,313 /*BACK=*/true);314 EXPECT_EQ(res.rank(), 1);315 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));316 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);317 EXPECT_EQ(res.GetDimension(0).Extent(), 2);318 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2);319 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3);320 res.Destroy();321 static const char targetChar[]{"abc"};322 Descriptor &target{statDesc[1].descriptor()};323 target.Establish(1, std::strlen(targetChar),324 const_cast<void *>(static_cast<const void *>(&targetChar)), 0, nullptr,325 CFI_attribute_pointer);326 RTNAME(Findloc)327 (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr,328 /*BACK=*/false);329 EXPECT_EQ(res.rank(), 1);330 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));331 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);332 EXPECT_EQ(res.GetDimension(0).Extent(), 2);333 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1);334 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1);335 res.Destroy();336 RTNAME(Findloc)337 (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, /*BACK=*/true);338 EXPECT_EQ(res.rank(), 1);339 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));340 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);341 EXPECT_EQ(res.GetDimension(0).Extent(), 2);342 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2);343 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 3);344 res.Destroy();345}346 347TEST(Reductions, Logical) {348 std::vector<int> shape{2, 2};349 auto array{MakeArray<TypeCategory::Logical, 4>(350 shape, std::vector<std::int32_t>{false, false, true, true})};351 ASSERT_EQ(array->ElementBytes(), std::size_t{4});352 EXPECT_EQ(RTNAME(All)(*array, __FILE__, __LINE__), false);353 EXPECT_EQ(RTNAME(Any)(*array, __FILE__, __LINE__), true);354 EXPECT_EQ(RTNAME(Parity)(*array, __FILE__, __LINE__), false);355 EXPECT_EQ(RTNAME(Count)(*array, __FILE__, __LINE__), 2);356 StaticDescriptor<2, true> statDesc[2];357 Descriptor &res{statDesc[0].descriptor()};358 RTNAME(AllDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__);359 EXPECT_EQ(res.rank(), 1);360 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw()));361 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);362 EXPECT_EQ(res.GetDimension(0).Extent(), 2);363 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0);364 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1);365 res.Destroy();366 RTNAME(AllDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__);367 EXPECT_EQ(res.rank(), 1);368 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw()));369 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);370 EXPECT_EQ(res.GetDimension(0).Extent(), 2);371 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0);372 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 0);373 res.Destroy();374 // Test scalar result for AllDim.375 // A scalar result occurs when you have a rank 1 array.376 std::vector<int> shape1{4};377 auto array1{MakeArray<TypeCategory::Logical, 4>(378 shape1, std::vector<std::int32_t>{false, false, true, true})};379 StaticDescriptor<1, true> statDesc0[1];380 Descriptor &scalarResult{statDesc0[0].descriptor()};381 RTNAME(AllDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__);382 EXPECT_EQ(scalarResult.rank(), 0);383 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 0);384 scalarResult.Destroy();385 RTNAME(AnyDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__);386 EXPECT_EQ(res.rank(), 1);387 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw()));388 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);389 EXPECT_EQ(res.GetDimension(0).Extent(), 2);390 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0);391 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1);392 res.Destroy();393 RTNAME(AnyDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__);394 EXPECT_EQ(res.rank(), 1);395 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw()));396 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);397 EXPECT_EQ(res.GetDimension(0).Extent(), 2);398 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1);399 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1);400 res.Destroy();401 // Test scalar result for AnyDim.402 // A scalar result occurs when you have a rank 1 array.403 RTNAME(AnyDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__);404 EXPECT_EQ(scalarResult.rank(), 0);405 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 1);406 scalarResult.Destroy();407 RTNAME(ParityDim)(res, *array, /*DIM=*/1, __FILE__, __LINE__);408 EXPECT_EQ(res.rank(), 1);409 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw()));410 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);411 EXPECT_EQ(res.GetDimension(0).Extent(), 2);412 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0);413 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 0);414 res.Destroy();415 RTNAME(ParityDim)(res, *array, /*DIM=*/2, __FILE__, __LINE__);416 EXPECT_EQ(res.rank(), 1);417 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Logical, 4}.raw()));418 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);419 EXPECT_EQ(res.GetDimension(0).Extent(), 2);420 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1);421 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1);422 res.Destroy();423 // Test scalar result for ParityDim.424 // A scalar result occurs when you have a rank 1 array.425 RTNAME(ParityDim)(scalarResult, *array1, /*DIM=*/1, __FILE__, __LINE__);426 EXPECT_EQ(scalarResult.rank(), 0);427 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int32_t>(0), 0);428 scalarResult.Destroy();429 RTNAME(CountDim)(res, *array, /*DIM=*/1, /*KIND=*/4, __FILE__, __LINE__);430 EXPECT_EQ(res.rank(), 1);431 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));432 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);433 EXPECT_EQ(res.GetDimension(0).Extent(), 2);434 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 0);435 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2);436 res.Destroy();437 RTNAME(CountDim)(res, *array, /*DIM=*/2, /*KIND=*/8, __FILE__, __LINE__);438 EXPECT_EQ(res.rank(), 1);439 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));440 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);441 EXPECT_EQ(res.GetDimension(0).Extent(), 2);442 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int64_t>(0), 1);443 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int64_t>(1), 1);444 res.Destroy();445 // Test scalar result for CountDim.446 // A scalar result occurs when you have a rank 1 array and dim == 1.447 RTNAME(CountDim)448 (scalarResult, *array1, /*DIM=*/1, /*KIND=*/8, __FILE__, __LINE__);449 EXPECT_EQ(scalarResult.rank(), 0);450 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<std::int64_t>(0), 2);451 scalarResult.Destroy();452 bool boolValue{false};453 Descriptor &target{statDesc[1].descriptor()};454 target.Establish(TypeCategory::Logical, 1, static_cast<void *>(&boolValue), 0,455 nullptr, CFI_attribute_pointer);456 RTNAME(Findloc)457 (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr,458 /*BACK=*/false);459 EXPECT_EQ(res.rank(), 1);460 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));461 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);462 EXPECT_EQ(res.GetDimension(0).Extent(), 2);463 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 1);464 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 1);465 res.Destroy();466 boolValue = true;467 RTNAME(Findloc)468 (res, *array, target, /*KIND=*/4, __FILE__, __LINE__, nullptr, /*BACK=*/true);469 EXPECT_EQ(res.rank(), 1);470 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 4}.raw()));471 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);472 EXPECT_EQ(res.GetDimension(0).Extent(), 2);473 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(0), 2);474 EXPECT_EQ(*res.ZeroBasedIndexedElement<std::int32_t>(1), 2);475 res.Destroy();476}477 478TEST(Reductions, FindlocNumeric) {479 std::vector<int> shape{2, 3};480 auto realArray{MakeArray<TypeCategory::Real, 8>(shape,481 std::vector<double>{0.0, -0.0, 1.0, 3.14,482 std::numeric_limits<double>::quiet_NaN(),483 std::numeric_limits<double>::infinity()})};484 ASSERT_EQ(realArray->ElementBytes(), sizeof(double));485 StaticDescriptor<2, true> statDesc[2];486 Descriptor &res{statDesc[0].descriptor()};487 // Find the first zero488 Descriptor &target{statDesc[1].descriptor()};489 double value{0.0};490 target.Establish(TypeCategory::Real, 8, static_cast<void *>(&value), 0,491 nullptr, CFI_attribute_pointer);492 RTNAME(Findloc)493 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false);494 EXPECT_EQ(res.rank(), 1);495 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));496 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);497 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2);498 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 1);499 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1);500 res.Destroy();501 // Find last zero (even though it's negative)502 RTNAME(Findloc)503 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/true);504 EXPECT_EQ(res.rank(), 1);505 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));506 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);507 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2);508 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2);509 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1);510 res.Destroy();511 // Find the +Inf512 value = std::numeric_limits<double>::infinity();513 RTNAME(Findloc)514 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false);515 EXPECT_EQ(res.rank(), 1);516 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));517 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);518 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2);519 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2);520 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 3);521 res.Destroy();522 // Ensure that we can't find a NaN523 value = std::numeric_limits<double>::quiet_NaN();524 RTNAME(Findloc)525 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false);526 EXPECT_EQ(res.rank(), 1);527 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));528 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);529 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2);530 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 0);531 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 0);532 res.Destroy();533 // Find a value of a distinct type534 int intValue{1};535 target.Establish(TypeCategory::Integer, 4, static_cast<void *>(&intValue), 0,536 nullptr, CFI_attribute_pointer);537 RTNAME(Findloc)538 (res, *realArray, target, 8, __FILE__, __LINE__, nullptr, /*BACK=*/false);539 EXPECT_EQ(res.rank(), 1);540 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));541 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);542 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2);543 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 1);544 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 2);545 res.Destroy();546 // Partial reductions547 value = 1.0;548 target.Establish(TypeCategory::Real, 8, static_cast<void *>(&value), 0,549 nullptr, CFI_attribute_pointer);550 RTNAME(FindlocDim)551 (res, *realArray, target, 8, /*DIM=*/1, __FILE__, __LINE__, nullptr,552 /*BACK=*/false);553 EXPECT_EQ(res.rank(), 1);554 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));555 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);556 EXPECT_EQ(res.GetDimension(0).UpperBound(), 3);557 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 0);558 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 1);559 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(2), 0);560 res.Destroy();561 RTNAME(FindlocDim)562 (res, *realArray, target, 8, /*DIM=*/2, __FILE__, __LINE__, nullptr,563 /*BACK=*/true);564 EXPECT_EQ(res.rank(), 1);565 EXPECT_EQ(res.type().raw(), (TypeCode{TypeCategory::Integer, 8}.raw()));566 EXPECT_EQ(res.GetDimension(0).LowerBound(), 1);567 EXPECT_EQ(res.GetDimension(0).UpperBound(), 2);568 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(0), 2);569 EXPECT_EQ(*res.ZeroBasedIndexedElement<SubscriptValue>(1), 0);570 res.Destroy();571 // Test scalar result for FindlocDim.572 // A scalar result occurs when you have a rank 1 array, value, and dim == 1.573 std::vector<int> shape1{6};574 auto realArray1{MakeArray<TypeCategory::Real, 8>(shape1,575 std::vector<double>{0.0, -0.0, 1.0, 3.14,576 std::numeric_limits<double>::quiet_NaN(),577 std::numeric_limits<double>::infinity()})};578 StaticDescriptor<1, true> statDesc0[1];579 Descriptor &scalarResult{statDesc0[0].descriptor()};580 RTNAME(FindlocDim)581 (scalarResult, *realArray1, target, 8, /*DIM=*/1, __FILE__, __LINE__, nullptr,582 /*BACK=*/false);583 EXPECT_EQ(scalarResult.rank(), 0);584 EXPECT_EQ(*scalarResult.ZeroBasedIndexedElement<SubscriptValue>(0), 3);585 scalarResult.Destroy();586}587 588TEST(Reductions, DotProduct) {589 auto realVector{MakeArray<TypeCategory::Real, 8>(590 std::vector<int>{4}, std::vector<double>{0.0, -0.0, 1.0, -2.0})};591 EXPECT_EQ(592 RTNAME(DotProductReal8)(*realVector, *realVector, __FILE__, __LINE__),593 5.0);594 auto complexVector{MakeArray<TypeCategory::Complex, 4>(std::vector<int>{4},595 std::vector<std::complex<float>>{596 {0.0}, {-0.0, -0.0}, {1.0, -2.0}, {-2.0, 4.0}})};597 std::complex<double> result8;598 RTNAME(CppDotProductComplex8)599 (result8, *realVector, *complexVector, __FILE__, __LINE__);600 EXPECT_EQ(result8, (std::complex<double>{5.0, -10.0}));601 RTNAME(CppDotProductComplex8)602 (result8, *complexVector, *realVector, __FILE__, __LINE__);603 EXPECT_EQ(result8, (std::complex<double>{5.0, 10.0}));604 std::complex<float> result4;605 RTNAME(CppDotProductComplex4)606 (result4, *complexVector, *complexVector, __FILE__, __LINE__);607 EXPECT_EQ(result4, (std::complex<float>{25.0, 0.0}));608 auto logicalVector1{MakeArray<TypeCategory::Logical, 1>(609 std::vector<int>{4}, std::vector<bool>{false, false, true, true})};610 EXPECT_TRUE(RTNAME(DotProductLogical)(611 *logicalVector1, *logicalVector1, __FILE__, __LINE__));612 auto logicalVector2{MakeArray<TypeCategory::Logical, 1>(613 std::vector<int>{4}, std::vector<bool>{true, true, false, false})};614 EXPECT_TRUE(RTNAME(DotProductLogical)(615 *logicalVector2, *logicalVector2, __FILE__, __LINE__));616 EXPECT_FALSE(RTNAME(DotProductLogical)(617 *logicalVector1, *logicalVector2, __FILE__, __LINE__));618 EXPECT_FALSE(RTNAME(DotProductLogical)(619 *logicalVector2, *logicalVector1, __FILE__, __LINE__));620}621 622#if HAS_LDBL128 || HAS_FLOAT128623TEST(Reductions, ExtremaReal16) {624 // The identity value for Min/Maxval for REAL(16) was mistakenly625 // set to 0.0.626 using ElemType = CppTypeFor<TypeCategory::Real, 16>;627 std::vector<int> shape{3};628 // 1.0 2.0 3.0629 std::vector<ElemType> rawMinData{1.0, 2.0, 3.0};630 auto minArray{MakeArray<TypeCategory::Real, 16>(shape, rawMinData)};631 EXPECT_EQ(RTNAME(MinvalReal16)(*minArray, __FILE__, __LINE__), 1.0);632 // -1.0 -2.0 -3.0633 std::vector<ElemType> rawMaxData{-1.0, -2.0, -3.0};634 auto maxArray{MakeArray<TypeCategory::Real, 16>(shape, rawMaxData)};635 EXPECT_EQ(RTNAME(MaxvalReal16)(*maxArray, __FILE__, __LINE__), -1.0);636}637#endif // HAS_LDBL128 || HAS_FLOAT128638 639static std::int32_t IAdd(const std::int32_t *x, const std::int32_t *y) {640 return *x + *y;641}642 643static std::int32_t IMultiply(const std::int32_t *x, const std::int32_t *y) {644 return *x * *y;645}646 647TEST(Reductions, ReduceInt4) {648 auto intVector{MakeArray<TypeCategory::Integer, 4>(649 std::vector<int>{4}, std::vector<std::int32_t>{1, 2, 3, 4})};650 EXPECT_EQ(651 RTNAME(ReduceInteger4Ref)(*intVector, IAdd, __FILE__, __LINE__), 10);652 EXPECT_EQ(653 RTNAME(ReduceInteger4Ref)(*intVector, IMultiply, __FILE__, __LINE__), 24);654}655TEST(Reductions, ReduceInt4Dim) {656 auto intMatrix{MakeArray<TypeCategory::Integer, 4>(657 std::vector<int>{2, 2}, std::vector<std::int32_t>{1, 2, 3, 4})};658 StaticDescriptor<2, true> statDesc;659 Descriptor &sums{statDesc.descriptor()};660 RTNAME(ReduceInteger4DimRef)(sums, *intMatrix, IAdd, __FILE__, __LINE__, 1);661 EXPECT_EQ(sums.rank(), 1);662 EXPECT_EQ(sums.GetDimension(0).LowerBound(), 1);663 EXPECT_EQ(sums.GetDimension(0).Extent(), 2);664 EXPECT_EQ(*sums.ZeroBasedIndexedElement<std::int32_t>(0), 3);665 EXPECT_EQ(*sums.ZeroBasedIndexedElement<std::int32_t>(1), 7);666 sums.Destroy();667 RTNAME(ReduceInteger4DimRef)(sums, *intMatrix, IAdd, __FILE__, __LINE__, 2);668 EXPECT_EQ(sums.rank(), 1);669 EXPECT_EQ(sums.GetDimension(0).LowerBound(), 1);670 EXPECT_EQ(sums.GetDimension(0).Extent(), 2);671 EXPECT_EQ(*sums.ZeroBasedIndexedElement<std::int32_t>(0), 4);672 EXPECT_EQ(*sums.ZeroBasedIndexedElement<std::int32_t>(1), 6);673 sums.Destroy();674}675