brintos

brintos / llvm-project-archived public Read only

0
0
Text · 30.2 KiB · 3701a32 Raw
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