tc/core/polyhedral/cuda/memory_promotion_heuristic.cc
// Map global<->shared copy bands to threads, starting from the innermost
// loop as it iterates over the last subscript and will result in coalescing.
Map global<->shared copy bands to threads, starting from the innermost
loop as it iterates over the last subscript and will result in coalescing.
Map global< - > shared copy bands to threads starting from the innermost loop as it iterates over the last subscript and will result in coalescing .
void mapCopiesToThreads(MappedScop& mscop, bool unroll) {
  using namespace detail;
  auto matcher = filter(
      [](isl::union_set uset) {
        auto sets = isl::UnionAsVector<isl::union_set>(uset);
        return std::all_of(sets.begin(), sets.end(), [](isl::set s) {
          auto readId = isl::id(s.get_ctx(), std::string(kReadIdName));
          auto writeId = isl::id(s.get_ctx(), std::string(kWriteIdName));
          return s.get_tuple_id() == readId || s.get_tuple_id() == writeId;
        });
      },
      any());
  auto root = mscop.scop().scheduleRoot();
  for (auto constNode : match(matcher, root)) {
    auto node = const_cast<ScheduleTree*>(constNode);
    if (match(filter(band()), node).size() != 1) {
      std::stringstream ss;
      ss << "read/write filter not followed by a single band" << std::endl
         << *node;
      throw promotion::PromotionLogicError(ss.str());
    }
    auto bandNode = node->child({0});
    auto band = bandNode->elemAs<ScheduleTreeElemBand>();
    if (!band) {
      throw promotion::PromotionLogicError("no copy band");
    }
    std::unordered_set<mapping::ThreadId, mapping::ThreadId::Hash> usedThreads;
    for (auto n : node->ancestors(root)) {
      if (auto filterNode = n->elemAs<ScheduleTreeElemMappingFilter>()) {
        for (auto id : filterNode->mappingIds) {
          if (id.isThreadId()) {
            throw promotion::PromotionBelowThreadsException(
                "attempted to map memory copies to threads below "
                "another thread mapping");
          }
        }
      }
    }
    auto filter = node->elemAs<ScheduleTreeElemFilter>()->filter_;
    auto filterSets = isl::UnionAsVector<isl::union_set>(filter);
    int t = 0;
    for (int i = band->nMember() - 1;
         i >= 0 && t < mscop.numThreads.view.size();
         --i) {
      auto skip = std::all_of(
          filterSets.begin(), filterSets.end(), [&mscop, i](isl::set s) {
            auto groupId =
                s.get_space().unwrap().get_tuple_id(isl::dim_type::out);
            if (mscop.scop().promotedDecls().count(groupId) != 1) {
              std::stringstream ss;
              ss << "promoted group " << groupId << " has no declaration";
              throw promotion::PromotionLogicError(ss.str());
            }
            auto decl = mscop.scop().promotedDecls().at(groupId);
            return i >= decl.sizes.size() || decl.sizes[i] == 1;
          });
      if (skip) {
        continue;
      }
      mapToParameterWithExtent(
          root,
          bandNode,
          i,
          mapping::ThreadId::makeId(t),
          mscop.numThreads.view[t]);
      ++t;
    }
    mscop.mapRemaining<mapping::ThreadId>(
        bandNode, t, mscop.numThreads.view.size());
    if (unroll) {
      markUnroll(root, bandNode, mscop.unroll);
    }
  }
}
void mapCopiesToThreads ( MappedScop & mscop , bool unroll ) { using namespace detail ; auto matcher = filter ( [ ] ( isl :: union_set uset ) { auto sets = isl :: UnionAsVector < isl :: union_set > ( uset ) ; return std :: all_of ( sets . begin ( ) , sets . end ( ) , [ ] ( isl :: set s ) { auto readId = isl :: id ( s . get_ctx ( ) , std :: string ( kReadIdName ) ) ; auto writeId = isl :: id ( s . get_ctx ( ) , std :: string ( kWriteIdName ) ) ; return s . get_tuple_id ( ) == readId || s . get_tuple_id ( ) == writeId ; } ) ; } , any ( ) ) ; auto root = mscop . scop ( ) . scheduleRoot ( ) ; for ( auto constNode : match ( matcher , root ) ) { auto node = const_cast < ScheduleTree * > ( constNode ) ; if ( match ( filter ( band ( ) ) , node ) . size ( ) != 1 ) { std :: stringstream ss ; ss << " " << std :: endl << * node ; throw promotion :: PromotionLogicError ( ss . str ( ) ) ; } auto bandNode = node -> child ( { 0 } ) ; auto band = bandNode -> elemAs < ScheduleTreeElemBand > ( ) ; if ( ! band ) { throw promotion :: PromotionLogicError ( " " ) ; } std :: unordered_set < mapping :: ThreadId , mapping :: ThreadId :: Hash > usedThreads ; for ( auto n : node -> ancestors ( root ) ) { if ( auto filterNode = n -> elemAs < ScheduleTreeElemMappingFilter > ( ) ) { for ( auto id : filterNode -> mappingIds ) { if ( id . isThreadId ( ) ) { throw promotion :: PromotionBelowThreadsException ( " " " " ) ; } } } } auto filter = node -> elemAs < ScheduleTreeElemFilter > ( ) -> filter_ ; auto filterSets = isl :: UnionAsVector < isl :: union_set > ( filter ) ; int t = 0 ; for ( int i = band -> nMember ( ) - 1 ; i >= 0 && t < mscop . numThreads . view . size ( ) ; -- i ) { auto skip = std :: all_of ( filterSets . begin ( ) , filterSets . end ( ) , [ & mscop , i ] ( isl :: set s ) { auto groupId = s . get_space ( ) . unwrap ( ) . get_tuple_id ( isl :: dim_type :: out ) ; if ( mscop . scop ( ) . promotedDecls ( ) . count ( groupId ) != 1 ) { std :: stringstream ss ; ss << " " << groupId << " " ; throw promotion :: PromotionLogicError ( ss . str ( ) ) ; } auto decl = mscop . scop ( ) . promotedDecls ( ) . at ( groupId ) ; return i >= decl . sizes . size ( ) || decl . sizes [ i ] == 1 ; } ) ; if ( skip ) { continue ; } mapToParameterWithExtent ( root , bandNode , i , mapping :: ThreadId :: makeId ( t ) , mscop . numThreads . view [ t ] ) ; ++ t ; } mscop . mapRemaining < mapping :: ThreadId > ( bandNode , t , mscop . numThreads . view . size ( ) ) ; if ( unroll ) { markUnroll ( root , bandNode , mscop . unroll ) ; } } }
Map global<->shared copy bands to threads, starting from the innermost
loop as it iterates over the last subscript and will result in coalescing.
Map global< - > shared copy bands to threads starting from the innermost loop as it iterates over the last subscript and will result in coalescing .
// Find all filters with reads from or writes to global memory. // We need to modify the nodes and have non-const mscop. // Check that we are not mapping to threads below other thread mappings. // Map band dimensions to threads, in inverse order since the last member // iterates over the last subscript and is likely to result in coalescing. // Step over band members that iterate over size-1 arrays subscripts as // they would have been executed by a single thread. // If not all available thread ids are used, fix remaining to 1 thread. // Unroll if requested.