2

I am trying to create an identifier for my methods. This identifier is important for my work as it is in fact hardware synthesis.

I have the following template class:

        template <int FF_COUNT, int FB_COUNT, int NEXT_COUNT>
        class Core{
        public:
        ...
            template<int id> void consume_fb_events (hls::stream<event>  feedback_stream [FB_COUNT] [FB_COUNT], weight w_mem [128*128]);
        }
    


template <int FF_COUNT, int FB_COUNT, int NEXT_COUNT>
    template <int id>
    void Core<FF_COUNT, FB_COUNT, NEXT_COUNT>::consume_fb_events (hls::stream<event> feedback_stream [FB_COUNT] [FB_COUNT], weight w_mem [128*128]){
    #pragma HLS INLINE off
    event e;   
            for(int i = 0 ; i < FB_COUNT ; i++) {
                while (!feedback_stream[id][i].empty()) {
                    feedback_stream[id][i].read(e);
                    ap_uint<16> mem_offset = e << size_exp;
                    consume_event (e, mem_offset, w_mem);    
            }
    }
    }

and this is my function call

    #define sth 8
for int i = 0 ; i < sth; i++
    core[i].consume_fb_events<i>(....);

I get the compilation error:

ERROR: [HLS 200-70] Compilation errors found: In file included from c1/srnn.cpp:1:
c1/srnn.cpp:197:14: error: no matching member function for call to 'consume_fb_events'
   core_1[i].consume_fb_events<i>(buffer_layer1_1, w1[i]);
   ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
c1/core.h:52:24: note: candidate template ignored: invalid explicitly-specified argument for template parameter 'id'
 template<int id> void consume_fb_events (hls::stream<event> feedback_stream [FB_COUNT] [FB_COUNT], weight w_mem [128*128]);
                   ^
  • 1
    You can't use `i` as template parameter, since it's not known at compile time. Why not just make it a normal parameter? – Lukas-T Oct 22 '21 at 08:40
  • Making it a normal parameter means it is unknown at compile time. I need it known for my hardware synthesis. – Sherif Badawy Oct 22 '21 at 08:52
  • 1
    Is `sth` known at compile time? If so, you need a _constexpr_ kind-of-loop - if it's not known, neither can `i` be. – Ted Lyngmo Oct 22 '21 at 08:53
  • Yes, sth is indeed a constant value. Could you please tell me how to specify so? – Sherif Badawy Oct 22 '21 at 08:59
  • It is defined as so: #define C1_UNROLL 8 for (int i = 0 ; i < C1_UNROLL; i++) core[i].consume_fb_events(...) – Sherif Badawy Oct 22 '21 at 08:59
  • If `sth` constant and as low as 8 I would just manually unroll the loop and explicitly write all 8 lines. You could probably write a recursive `constexpr` function for this too. – Lukas-T Oct 22 '21 at 09:30

1 Answers1

4

What your looking for is a for loop at compile time. Because the template parameter must be a constexpr. I usually do it this way since you can't have for loops in constexpr functions:

template<int i>
struct MyFunc
{
    MyFunc()
    {
        // do something with i
        core[i].consume_fb_events<i>(....);
    }
};

template<int end, template <int I> class func, int i = 0>
struct ForLoop
{
    ForLoop()
    {
        func<i>{};
        ForLoop<end, func, i+1>{};
    }
};

template<int end, template <int I> class func>
struct ForLoop<end, func, end>
{
    ForLoop()
    {
    }
};

You can run any code in the constructor of MyFunc.

You can then execute it like that:

ForLoop<8, MyFunc>{};

where 8 is the number you would usually but at the i < ... part of the for loop

You have to be careful with this, because this will only work for end up to about 900 (depending on the max template recursion depth). Or else you will get a compile time error.

live example with std::cout

EDIT:


Since @SherifBadawy asked in a comment, you don't have to declare a struct/class MyFunc to do this, but I went with this approach because it makes the ForLoop more dynamic and you can reuse it multiple times.

But if you'd like to this would also work:

template<int i>
void foo()
{
    // code here
}

template<int end, int i = 0>
struct ForLoop
{
    ForLoop()
    {
        core[i].consume_fb_events<i>(....);
        // more code

        // or ...

        foo<i>();

        ForLoop<end, func, i+1>{};
    }
};

template<int end>
struct ForLoop<end, end>
{
    ForLoop()
    {
    }
};

To run ForLoop you would again do:

ForLoop<8>{}; // without passing a class or function
Gian Laager
  • 474
  • 4
  • 14
  • Thanks for your answer Could you please recheck for typos? What is func{};? Did you mean MyFunc? – Sherif Badawy Oct 22 '21 at 09:41
  • template class Core{ public: template struct consume_function { void consume_ff_events (hls::stream input_stream [FB_COUNT] [FF_COUNT] , weight w_mem [128 * 128]); void consume_fb_events (hls::stream feedback_stream [FB_COUNT] [FB_COUNT], weight w_mem [128*128]){ }; This is how im implementing it so far...is it right? – Sherif Badawy Oct 22 '21 at 09:42
  • @SherifBadawy No, `func` is the template parameter, it's used kinda like a lambda but you can also directly call `MyFunc` if you wanted to. With the template parameter it gets more dynamic and reusable. – Gian Laager Oct 22 '21 at 09:44
  • @SherifBadawy Should be, of course you can also use a templated function instead of a class constructor in the constructor of `ForLoop` – Gian Laager Oct 22 '21 at 09:47
  • 1
    So I dont need struct "consume function"? I can just have the normal template function declaration, and instead call the function in in the constructor of ForLoop? – Sherif Badawy Oct 22 '21 at 11:52
  • @SherifBadawy Yes. just as a reminder if my answer solved your question could you please mark it as Solution. – Gian Laager Oct 22 '21 at 12:41
  • Ofcourse! If you may, could you please tell me if it is possible to pass some parameters in the call in the main function (ForLoop<8>{} to pass the arguments of consume_ff_events – Sherif Badawy Oct 22 '21 at 13:11
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/238435/discussion-between-gian-laager-and-sherif-badawy). – Gian Laager Oct 22 '21 at 13:13