ArmPl cblas_sdot results seem wrong with large sizes

When running some tests for onemath armpl, we noticed a probable issue with cblas_sdot function, which returns wrong values when input size is large. The failure is reproducible and deterministic, and was seen with armpl 24.10 to 26.7 versions on several SVE and Neon platforms (grace, ampere altra, cix p1)

Threads  Elements  `cblas_sdot` result  Expected result Status 
1 268 435 456 32768.000000 ~65504.0 FAIL
2 268 435 456 65535.949219 ~65504.0 PASS 
1 536 870 912 16384.000000 ~65504.0 FAIL
2 536 870 912 32768.000000 ~65504.0 FAIL

The same failure also occurs with the **single-threaded** library (`-larmpl`, not just `-larmpl_mp`), so this is not an OpenMP threading issue, even if OpenMP variant is also impacted in the same way (with 2 threads, results fails the same as sequential when size is twice larger, so size/thread is the same). 

`cblas_ddot` and `cblas_dsdot` are unaffected.

Reproducer :

g++ repro.cpp -I /path/to/armpl_26.07_gcc/include/ -L /path/to/armpl_26.07_gcc/lib/ -larmpl_mp -fopenmp -o repro

 

// repro.cpp
#include <stdio.h>
#include <stdlib.h>
#include <cmath>
#include <cstdint>
#include "armpl.h"

template <typename T>
void run_dot(const int64_t iNumElements)
{
  const size_t src_size_bytes = (size_t)iNumElements * sizeof(T);
  T* srcA = (T*) malloc(src_size_bytes);
  T* srcB = (T*) malloc(src_size_bytes);
  if (!srcA || !srcB) {
    printf("> ERROR: malloc failed for %zu bytes\n", src_size_bytes);
    exit(EXIT_FAILURE);
  }

  double sum = 0.0;
  for (int64_t i = 0; i < iNumElements; ++i) {
    T v = (T)(sqrt(65504.0 / (double)iNumElements));
    srcA[i] = v;
    srcB[i] = v;
    sum += (double)v * (double)v;
  }

  T result;
  const int n = (int)iNumElements;
  if constexpr (std::is_same<T, float>::value) {
    result = cblas_sdot(n, srcA, 1, srcB, 1);
  } else {
    result = cblas_ddot(n, srcA, 1, srcB, 1);
  }

  printf("Host (double accum): %lf   ArmPL cblas_%cdot: %lf\n",
         sum, std::is_same<T, float>::value ? 's' : 'd', (double)result);
  printf("%s\n\n", (fabs((double)result - sum) < 1e-2 * sum + 1e-3) ? "PASS" : "FAIL");

  free(srcA);
  free(srcB);
}

int main(int argc, char** argv)
{
  if (argc != 2) {
    printf("Usage: %s <number of elements>\n", argv[0]);
    printf("Example: %s 268435456\n", argv[0]);
    return 1;
  }
  const int64_t iNumElements = atoll(argv[1]);

  printf("Elements: %lld\n", (long long)iNumElements);
  printf("OMP_NUM_THREADS should be set in the environment before running.\n\n");

  printf("FP64 dot (cblas_ddot)\n");
  run_dot<double>(iNumElements);

  printf("FP32 dot (cblas_sdot)\n");
  run_dot<float>(iNumElements);

  return EXIT_SUCCESS;
}

Fails
OMP_NUM_THREADS=1 ./repro 268435456

Elements: 268435456
Host (double accum): 65504.000000 ArmPL cblas_ddot: 65504.000000
PASS

FP32 dot (cblas_sdot)
Host (double accum): 65503.996094 ArmPL cblas_sdot: 32768.000000
FAIL

Passes
OMP_NUM_THREADS=2 ./repro 268435456

Elements: 268435456
Host (double accum): 65504.000000 ArmPL cblas_ddot: 65504.000000
PASS

FP32 dot (cblas_sdot)
Host (double accum): 65503.996094 ArmPL cblas_sdot: 65535.949219
PASS

Fails with OpenMP
OMP_NUM_THREADS=2 ./repro 128000000

Elements: 128000000
Host (double accum): 65503.999820 ArmPL cblas_ddot: 65503.999998
PASS

FP32 dot (cblas_sdot)
Host (double accum): 65504.002156 ArmPL cblas_sdot: 62726.730469
FAIL