Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Vector expression templates bug - behaves like reference to expired temporary #127

Open
klecki opened this issue Oct 3, 2018 · 0 comments

Comments

@klecki
Copy link

klecki commented Oct 3, 2018

Hi,
I encountered problem when using simdpp with auto type deduction to allow usage of expression templates. The problem appears both on scalar fallback implementation and on SIMDPP_ARCH_X86_AVX2.

This is the minimal working example that I managed to write, that causes problems; rx and mrx have random values in each run. They should be all 0s and all 1s respectively.

    constexpr int N = SIMDPP_FAST_FLOAT32_SIZE;
    SIMDPP_ALIGN(simdpp::float32<N>::length_bytes) float x_idx[N];
    for (int i = 0; i < N; i++) {
        x_idx[i] = static_cast<float>(i);
    }
    auto x = simdpp::load<simdpp::float32<N>>(x_idx);
    auto xi = simdpp::to_int32(x);
    auto rx = x - simdpp::to_float32(xi);
    auto mrx = simdpp::splat<simdpp::float32<N>>(1.0f) - rx;

Here is the whole example with a to_string function used to store and display a vector:

#define SIMDPP_ARCH_X86_AVX2
#include <simdpp/simd.h>
#include <iostream>
#include <cstdint>
#include <sstream>

template <typename V>
std::string to_string(const V& v)  
{  
  using T = typename decltype(v.eval())::element_type;
  constexpr auto N = V::length;
  SIMDPP_ALIGN(V::length_bytes) T data[N];
  simdpp::store(data, v);
  std::ostringstream os;
  os << "[";
  for (size_t i = 0; i < N - 1; i++) {
    os << data[i] << ", ";
  }
  os << data[N - 1] << "]";
  return os.str();  
}  

int main() {
    constexpr int N = SIMDPP_FAST_FLOAT32_SIZE;
    SIMDPP_ALIGN(simdpp::float32<N>::length_bytes) float x_idx[N];
    for (int i = 0; i < N; i++) {
        x_idx[i] = static_cast<float>(i);
    }
    auto x = simdpp::load<simdpp::float32<N>>(x_idx);
    auto xi = simdpp::to_int32(x);
    auto rx = x - simdpp::to_float32(xi);
    auto mrx = simdpp::splat<simdpp::float32<N>>(1.0f) - rx;

    std::cout << "x: " << to_string(x) << std::endl;
    std::cout << "xi: " << to_string(xi) << std::endl;
    std::cout << "rx: " << to_string(rx) << std::endl;
    std::cout << "mrx: " << to_string(mrx) << std::endl;

    return 0;
}

Tested with master branch, commit: dbdb146.

Forcing the evaluation did not help (this does not work):

    auto x = simdpp::load<simdpp::float32<N>>(x_idx).eval();
    auto xi = simdpp::to_int32(x).eval();
    auto rx = x - simdpp::to_float32(xi).eval();
    auto mrx = (simdpp::splat<simdpp::float32<N>>(1.0f) - rx).eval();

The problem disappears when I use explicit Regular vector types, that is (this gives proper results):

    simdpp::float32<N> x = simdpp::load<simdpp::float32<N>>(x_idx);
    simdpp::int32<N> xi = simdpp::to_int32(x);
    simdpp::float32<N> rx = x - simdpp::to_float32(xi);
    simdpp::float32<N> mrx = simdpp::splat<simdpp::float32<N>>(1.0f) - rx;

Another fix that helped in this case was to modify libsimdpp/simdpp/expr.h and change all expression structures to use const values instead of const references for sub-expressions.
For example from

template<class E1, class E2>
struct expr_bit_and {
    const E1& a;
    const E2& b;
};

to

template<class E1, class E2>
struct expr_bit_and {
    const E1 a;
    const E2 b;
};

It looks a bit like somewhere the expression stores reference to temporary and uses it after it is expired.

Best regards,
Krzysztof.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant