UPGRADE YOUR BROWSER

We have detected your current browser version is not the latest one. Xilinx.com uses the latest web technologies to bring you the best online experience possible. Please upgrade to a Xilinx.com supported browser:Chrome, Firefox, Internet Explorer 11, Safari. Thank you!

cancel
Showing results for 
Search instead for 
Did you mean: 
Participant haggaie
Participant
1,100 Views
Registered: ‎06-28-2016

Generic tuple manipulation in HLS

Hi, I was trying to use generic tuple manipulation code based on the examples in this blog, but using only C++11 code (HLS doesn't seem to support C++14). The code below causes HLS 2018.1 to crash with an Abnormal program termination (11) error.

 

#include <cassert>
#include <tuple>

// index_sequence from https://stackoverflow.com/questions/17424477/implementation-c14-make-integer-sequence/17426611#17426611

template<size_t...> struct index_sequence{ typedef index_sequence type; };

template<class S1, class S2> struct concat;

template<size_t... I1, size_t... I2>
struct concat<index_sequence<I1...>, index_sequence<I2...>>
  : index_sequence<I1..., (sizeof...(I1)+I2)...>
{};

template<size_t N> struct make_index_sequence;

template<size_t N>
struct make_index_sequence : concat<
    typename make_index_sequence<N/2>::type,
    typename make_index_sequence<N - N/2>::type
>
{};

template<> struct make_index_sequence<0> : index_sequence<>{};
template<> struct make_index_sequence<1> : index_sequence<0>{};

using namespace std;

template <typename Tuple, typename Seq>
struct tuple_map_type
{
    typedef tuple<> type;
};

template <typename Tuple, size_t... Is>
struct tuple_map_type<Tuple, index_sequence<Is...> >
{
    typedef tuple<typename tuple_element<Is, Tuple>::type...> type;
};

template <typename Tuple, size_t... Is>
constexpr typename tuple_map_type<Tuple, index_sequence<Is...> >::type
    take_front_impl(Tuple t, index_sequence<Is...>)
{
    return make_tuple(get<Is>(t)...);
}

template <size_t N, class Tuple>
constexpr typename tuple_map_type<Tuple, typename make_index_sequence<N>::type>::type take_front(Tuple t) {
    return take_front_impl(t, make_index_sequence<N>{});
}

tuple<int, int> top(int a, int b, int c)
{
    auto all = make_tuple(a, b, c);
    return take_front<2>(all);
}

int main()
{
    assert(top(1,2,3) == make_tuple(1, 2));
}

Does anyone have experience with this kind of code and can offer a workaround?

0 Kudos
6 Replies
Xilinx Employee
Xilinx Employee
1,063 Views
Registered: ‎05-06-2008

Re: Generic tuple manipulation in HLS

Hello @haggaie,

 

The FPGA has a hard time supporting the idea of the dynamic tuple concept.  The FPGA wants the memory to be initialized prior to the use of it, so the concept of dynamic memory is very difficult.   We recommend using an array to define the memories of the design or function.  

 

Good Luck,
Chris

0 Kudos
Participant haggaie
Participant
1,052 Views
Registered: ‎06-28-2016

Re: Generic tuple manipulation in HLS

Hi @chrisz, thanks for your reply. I don't think there are any dynamic memory allocations in the example I presented. With -O2 the g++ compiler can statically eliminate the assert altogether. With -O1, the resulting top function copies the generated tuple (with the first two arguments) onto the stack:

00000000004004ed <top(int, int, int)>:
constexpr typename tuple_map_type<Tuple, typename make_index_sequence<N>::type>::type take_front(Tuple t) {
    return take_front_impl(t, make_index_sequence<N>{});
}

tuple<int, int> top(int a, int b, int c)
{
  4004ed:       48 89 f8                mov    %rdi,%rax
      constexpr _Head_base(const _Head_base&) = default;
      constexpr _Head_base(_Head_base&&) = default;

      template<typename _UHead>
        constexpr _Head_base(_UHead&& __h)
        : _M_head_impl(std::forward<_UHead>(__h)) { }
  4004f0:       89 17                   mov    %edx,(%rdi)
  4004f2:       89 77 04                mov    %esi,0x4(%rdi)
    auto all = make_tuple(a, b, c);
    return take_front<2>(all);
}
  4004f5:       c3                      retq   

In general, as far as I understand, tuples of plain types do not use dynamic memory allocations. I've also tested the same program extended to have 16 ints in the tuple and it still did not use dynamic memory - only the stack.

 

Tuples are useful exactly for this reason: they provide similar semantics to structs, but with the ability to write generic code to process them.

 

 

0 Kudos
Xilinx Employee
Xilinx Employee
993 Views
Registered: ‎05-06-2008

Re: Generic tuple manipulation in HLS

Hello @haggaie,

 

The concept of a stack does not apply to the FPGA, since you must declare the memory prior to using it.  You can emulate the stack by declaring very large memories and hope you do not exceed them.

 

Good Luck,
Chris

0 Kudos
Participant haggaie
Participant
988 Views
Registered: ‎06-28-2016

Re: Generic tuple manipulation in HLS

Maybe I didn't explain myself correctly. I don't expect the HLS implementation to use a stack. I only said that the software implementation used a stack to emphasize the fact that tuples are passed by-value, and not by-reference, so I expect HLS to be able to handle them as if it were passing the same values as parameters or return values. I will try to provide a similar struct example that does work with HLS later on to explain what I mean.

0 Kudos
Participant haggaie
Participant
944 Views
Registered: ‎06-28-2016

Re: Generic tuple manipulation in HLS

Hi @chrisz,

 

Here is an example that does conceptually the same thing as the example in the original post, but using structs instead:

#include <cassert>

struct two {
    int a, b;
};

struct three {
    int a, b, c;
};

two top(three in)
{
    return two{in.a, in.b};
}

bool operator==(two l, two r)
{
    return l.a == r.a && l.b == r.b;
}

int main()
{
    assert((two{1,2} == top(three{1,2,3})));
}

In this case, HLS is able to generate Verilog code correctly, as you may expect. The only difference between the two examples is that the original one used tuples for generality, so it is easier to change the top function to work with other sizes than 3. Both this example's top function and the original example's take_front<> function receive their parameter by-value, and return the result by-value. Both cases do not use dynamic memory allocations or pointers. Therefore, I would expect both examples to generate the same Verilog code.

 

Regards,

Haggai

Xilinx Employee
Xilinx Employee
828 Views
Registered: ‎05-06-2008

Re: Generic tuple manipulation in HLS

Hello @haggaie,

 

I will talk to the developers about supporting this feature, but I am sorry it will not work at this time.

 

Thanks,

Chris