src/InsertHWBuffers.cpp
// IR for hardware buffers
// A buffer is instantiated to buffer the stencil_update.stream and
// to generate the stencil.stream
// The former is smaller, which only consists of the new pixels
// sided in each shift of the stencil window.
IR for hardware buffers
A buffer is instantiated to buffer the stencil_update.stream and
to generate the stencil.stream
The former is smaller, which only consists of the new pixels
sided in each shift of the stencil window.
IR for hardware buffers A buffer is instantiated to buffer the stencil_update . stream and to generate the stencil . stream The former is smaller which only consists of the new pixels sided in each shift of the stencil window .
Stmt add_hwbuffer(Stmt s, const HWBuffer &kernel, const HWXcel &xcel, const Scope<Expr> &scope) {
    Stmt ret;
    if (need_hwbuffer(kernel)) {
         After mutation:
               realize func.stencil.stream {
                 hwbuffer(...)
                 dispatch(...)
                 stmt...
               }
        string stream_name = kernel.name + ".stencil.stream";
        string update_stream_name = kernel.name + ".stencil_update.stream";
        Expr stream_var = Variable::make(Handle(), stream_name);
        Expr update_stream_var = Variable::make(Handle(), update_stream_name);
        vector<Expr> hwbuffer_args({update_stream_var, stream_var});
        hwbuffer_args.push_back(Expr(kernel.dims.size()));
        int num_logical_pixels = 1;
         extract the buffer size, and put it into args
        for (size_t i = 0; i < kernel.dims.size(); i++) {
          Expr store_extent = simplify(kernel.dims[i].store_bound.max -
                                       kernel.dims[i].store_bound.min + 1);
          Expr store_extent = kernel.dims[i].logical_size;
          Expr store_extent = kernel.ldims[i].logical_size;
          num_logical_pixels *= to_int(store_extent);
          hwbuffer_args.push_back(store_extent);
        }
        for (size_t i = 0; i < kernel.dims.size(); i++) {
          hwbuffer_args.push_back(kernel.dims.at(i).input_chunk);
          hwbuffer_args.push_back(kernel.dims.at(i).input_block);
        }
        for (size_t i = 0; i < kernel.dims.size(); i++) {
          hwbuffer_args.push_back(kernel.dims.at(i).input_block);
        }
         we should push the output stencil for each consumer
        int num_ostreams = 0;
        int num_updates = 0;
        hwbuffer_args.push_back(Expr((int)kernel.ostreams.size() - kernel.ostreams.count(kernel.name)));  number of ostreams
        hwbuffer_args.push_back(Expr(1));  number of ostreams
        for (const auto& ostream_p : kernel.ostreams) {
          if (ostream_p.first != kernel.name) {  skip updates for now
            std::cout << "doing stream called " << ostream_p.first << std::endl;
            hwbuffer_args.push_back(ostream_p.first);
            const auto& ostream = ostream_p.second;
            for (size_t i = 0; i < ostream.odims.size(); i++) {
              hwbuffer_args.push_back(ostream.odims.at(i).output_stencil);
            }
            for (size_t i = 0; i < ostream.odims.size(); i++) {
              std::cout << "output_blk" << i << " = " << ostream.odims.at(i).output_block << "\n";
              hwbuffer_args.push_back(ostream.odims.at(i).output_block);
            }
            const auto& out_lin_acc = ostream_p.second.linear_access;
            hwbuffer_args.push_back(Expr(out_lin_acc.size()));
            for (size_t i = 0; i < out_lin_acc.size(); i++) {
              std::cout << "dim" << i << ": range=" << out_lin_acc.at(i).range
                        << " dim_ref=" << out_lin_acc.at(i).dim_ref
                        << " stride=" << out_lin_acc.at(i).stride
                        << "\n";
            }
            int num_iter=1;
            for (size_t i = 0; i < out_lin_acc.size(); i++) {
              std::cout << "range" << i << " = " << out_lin_acc.at(i).range << "\n";
              num_iter *= to_int(out_lin_acc.at(i).range);
              hwbuffer_args.push_back(out_lin_acc.at(i).range);
            }
            for (size_t i = 0; i < out_lin_acc.size(); i++) {
              hwbuffer_args.push_back(out_lin_acc.at(i).dim_ref);
            }
            for (size_t i = 0; i < out_lin_acc.size(); i++) {
              hwbuffer_args.push_back(out_lin_acc.at(i).stride);
            }
            auto num_accum_iter = num_iter / num_logical_pixels;
            (void) num_accum_iter;
            num_ostreams += 1;
          } else {
            num_updates += 1;
          }
          if (num_ostreams == 1) { break; }
        }
        internal_assert(num_ostreams < 2);
        hwbuffer_args.push_back(num_updates);
        for (const auto& ostream_p : kernel.ostreams) {
          if (ostream_p.first == kernel.name) {  let's do the updates
            hwbuffer_args.push_back(ostream_p.first);
            const auto& ostream = ostream_p.second;
            for (size_t i = 0; i < ostream.odims.size(); i++) {
              hwbuffer_args.push_back(ostream.odims.at(i).output_stencil);
            }
            for (size_t i = 0; i < ostream.odims.size(); i++) {
              hwbuffer_args.push_back(ostream.odims.at(i).output_block);
            }
          }
        }
        std::cout << hwbuffer_args << std::endl;
        Stmt hwbuffer_call = Evaluate::make(Call::make(Handle(), "hwbuffer", hwbuffer_args, Call::Intrinsic));
        Stmt dispatch_call = create_hwbuffer_dispatch_call(kernel);
        Stmt buffer_calls = Block::make(hwbuffer_call, dispatch_call);
         create a realization of the stencil of the window-size
        Region window_bounds;
        for (const auto& dim: kernel.dims) {
            window_bounds.push_back(Range(0, dim.output_stencil));
        }
        ret = Realize::make(stream_name, kernel.func.output_types(), MemoryType::Auto, window_bounds, const_true(), Block::make(hwbuffer_call, Block::make(dispatch_call, s)));
    } else {
        user_warning << "No hwbuffer inserted after function " << kernel.name
                     << ".\n";
         After mutation:
               dispatch(...)
         Ad-hoc fix: place a fifo buffer at the inputs if the inputs is not hwbuffered.
         This works around the issue that read stencil call from a interface stream
         in the compute kernel cannot fully unrolled
        int force_buffer_depth = 0;
        if (kernel.input_streams.empty() && kernel.ostreams.size() == 1)
        if (kernel.istreams.size() == 0 && kernel.ostreams.size() == 1)
            force_buffer_depth = 1;
        Stmt dispatch_call = create_hwbuffer_dispatch_call(kernel, force_buffer_depth);
        ret = Block::make(dispatch_call, s);
    }
    return ret;
}
Stmt add_hwbuffer ( Stmt s , const HWBuffer & kernel , const HWXcel & xcel , const Scope < Expr > & scope ) { Stmt ret ; if ( need_hwbuffer ( kernel ) ) { string stream_name = kernel . name + " " ; string update_stream_name = kernel . name + " " ; Expr stream_var = Variable :: make ( Handle ( ) , stream_name ) ; Expr update_stream_var = Variable :: make ( Handle ( ) , update_stream_name ) ; vector < Expr > hwbuffer_args ( { update_stream_var , stream_var } ) ; hwbuffer_args . push_back ( Expr ( kernel . dims . size ( ) ) ) ; int num_logical_pixels = 1 ; for ( size_t i = 0 ; i < kernel . dims . size ( ) ; i ++ ) { Expr store_extent = kernel . ldims [ i ] . logical_size ; num_logical_pixels *= to_int ( store_extent ) ; hwbuffer_args . push_back ( store_extent ) ; } for ( size_t i = 0 ; i < kernel . dims . size ( ) ; i ++ ) { hwbuffer_args . push_back ( kernel . dims . at ( i ) . input_chunk ) ; } for ( size_t i = 0 ; i < kernel . dims . size ( ) ; i ++ ) { hwbuffer_args . push_back ( kernel . dims . at ( i ) . input_block ) ; } int num_ostreams = 0 ; int num_updates = 0 ; hwbuffer_args . push_back ( Expr ( ( int ) kernel . ostreams . size ( ) - kernel . ostreams . count ( kernel . name ) ) ) ; for ( const auto & ostream_p : kernel . ostreams ) { if ( ostream_p . first != kernel . name ) { hwbuffer_args . push_back ( ostream_p . first ) ; const auto & ostream = ostream_p . second ; for ( size_t i = 0 ; i < ostream . odims . size ( ) ; i ++ ) { hwbuffer_args . push_back ( ostream . odims . at ( i ) . output_stencil ) ; } for ( size_t i = 0 ; i < ostream . odims . size ( ) ; i ++ ) { hwbuffer_args . push_back ( ostream . odims . at ( i ) . output_block ) ; } const auto & out_lin_acc = ostream_p . second . linear_access ; hwbuffer_args . push_back ( Expr ( out_lin_acc . size ( ) ) ) ; for ( size_t i = 0 ; i < out_lin_acc . size ( ) ; i ++ ) { } int num_iter = 1 ; for ( size_t i = 0 ; i < out_lin_acc . size ( ) ; i ++ ) { num_iter *= to_int ( out_lin_acc . at ( i ) . range ) ; hwbuffer_args . push_back ( out_lin_acc . at ( i ) . range ) ; } for ( size_t i = 0 ; i < out_lin_acc . size ( ) ; i ++ ) { hwbuffer_args . push_back ( out_lin_acc . at ( i ) . dim_ref ) ; } for ( size_t i = 0 ; i < out_lin_acc . size ( ) ; i ++ ) { hwbuffer_args . push_back ( out_lin_acc . at ( i ) . stride ) ; } auto num_accum_iter = num_iter / num_logical_pixels ; ( void ) num_accum_iter ; num_ostreams += 1 ; } else { num_updates += 1 ; } } hwbuffer_args . push_back ( num_updates ) ; Stmt hwbuffer_call = Evaluate :: make ( Call :: make ( Handle ( ) , " " , hwbuffer_args , Call :: Intrinsic ) ) ; Stmt dispatch_call = create_hwbuffer_dispatch_call ( kernel ) ; Stmt buffer_calls = Block :: make ( hwbuffer_call , dispatch_call ) ; Region window_bounds ; for ( const auto & dim : kernel . dims ) { window_bounds . push_back ( Range ( 0 , dim . output_stencil ) ) ; } ret = Realize :: make ( stream_name , kernel . func . output_types ( ) , MemoryType :: Auto , window_bounds , const_true ( ) , Block :: make ( hwbuffer_call , Block :: make ( dispatch_call , s ) ) ) ; } else { user_warning << " " << kernel . name << " \n " ; int force_buffer_depth = 0 ; if ( kernel . istreams . size ( ) == 0 && kernel . ostreams . size ( ) == 1 ) force_buffer_depth = 1 ; Stmt dispatch_call = create_hwbuffer_dispatch_call ( kernel , force_buffer_depth ) ; ret = Block :: make ( dispatch_call , s ) ; } return ret ; }
IR for hardware buffers
A buffer is instantiated to buffer the stencil_update.stream and
to generate the stencil.stream
The former is smaller, which only consists of the new pixels
sided in each shift of the stencil window.
IR for hardware buffers A buffer is instantiated to buffer the stencil_update . stream and to generate the stencil . stream The former is smaller which only consists of the new pixels sided in each shift of the stencil window .
//std::cout << "considering a hwbuffer for " << kernel.name << std::endl; //std::cout << "creating a hwbuffer for " << kernel.name << std::endl; // Before mutation: //       stmt... // // After mutation: //       realize func.stencil.stream { //         hwbuffer(...) //         dispatch(...) //         stmt... //       } // extract the buffer size, and put it into args //Expr store_extent = simplify(kernel.dims[i].store_bound.max - //                             kernel.dims[i].store_bound.min + 1); //Expr store_extent = kernel.dims[i].logical_size; //hwbuffer_args.push_back(kernel.dims.at(i).input_block); // we should push the output stencil for each consumer // number of ostreams //hwbuffer_args.push_back(Expr(1)); // number of ostreams // skip updates for now //std::cout << "doing stream called " << ostream_p.first << std::endl; //std::cout << "output_blk" << i << " = " << ostream.odims.at(i).output_block << "\n"; //std::cout << "dim" << i << ": range=" << out_lin_acc.at(i).range //          << " dim_ref=" << out_lin_acc.at(i).dim_ref //          << " stride=" << out_lin_acc.at(i).stride //          << "\n"; //std::cout << "range" << i << " = " << out_lin_acc.at(i).range << "\n"; //if (num_ostreams == 1) { break; } //internal_assert(num_ostreams < 2); //for (const auto& ostream_p : kernel.ostreams) { //  if (ostream_p.first == kernel.name) { // let's do the updates //    hwbuffer_args.push_back(ostream_p.first); //    const auto& ostream = ostream_p.second; //    for (size_t i = 0; i < ostream.odims.size(); i++) { //      hwbuffer_args.push_back(ostream.odims.at(i).output_stencil); //    } //    for (size_t i = 0; i < ostream.odims.size(); i++) { //      hwbuffer_args.push_back(ostream.odims.at(i).output_block); //    } //  } //} //std::cout << hwbuffer_args << std::endl; // create a realization of the stencil of the window-size // Before mutation: //       stmt... // // After mutation: //       dispatch(...) //       stmt... // Ad-hoc fix: place a fifo buffer at the inputs if the inputs is not hwbuffered. // This works around the issue that read stencil call from a interface stream // in the compute kernel cannot fully unrolled //if (kernel.input_streams.empty() && kernel.ostreams.size() == 1)