src/core/compile.cpp
/*
Nodes are values! Here's how memory is allocated:
1. Immediately deduce their scope - find LCA among dependents
2. Preserving the node's var order, find the minimum required memory to allocate
  for c:
    for a in 3r1: // shared scope
      for b in 2:
        for a in 5:
          create(T[a,b,c])
      for b in 2:
        for a in 5:
          for k: // note this is unrelated
            use(T[a,b,c])
  T[a, b, c], scope is {a:{5,0}, {b:{2,0}}, which means we need to allocate
       10 elements (scope for C and part of A is shared).  Even though
       A is a total of 16 elems, we can allocate 5 elems in the shared scope!
       We will partially use this allocation in the tail run (1/5th of it)
  We can also handle "weird" splits:
  for c:
    for a in 3r1: // shared scope
      for b in 2:
        for a in 2r1: // note the loops no longer match and theres a tail
          for a in 2:
            create(T[a,b,c])
      for b in 2:
        for a in 5:
          for k:
            use(T[a,b,c])
  Because we have strong invariants, we know that the LCA preserves sizing
  despite complex loop tiling.  we still have 5 a elems and 2 b elems for a
total of 10 The resultant expressions will share memory but will have different
  indexing semantics, which allows us to chain unique strategies without concern
  of accidental memory over-use

  gen_alloc maps a node to its LCA, size, idx into allocation map
  gen_idx_vec maps a user + alloc to an indexing vector
*/
Nodes are values. Here's how memory is allocated:
1. Immediately deduce their scope - find LCA among dependents
2.

gen_alloc maps a node to its LCA, size, idx into allocation map
gen_idx_vec maps a user + alloc to an indexing vector
Nodes are values . Here ' s how memory is allocated : 1 . Immediately deduce their scope - find LCA among dependents 2 . gen_alloc maps a node to its LCA size idx into allocation map gen_idx_vec maps a user + alloc to an indexing vector
void gen_alloc(const LoopTree &lt, Auxiliary &aux, LoopTree::TreeRef ref) {
  ASSERT(lt.node(ref).kind == LoopTree::NODE);
  LoopTree::TreeRef lca = get_scope(lt, ref);
  auto loop_ref = lt.parent(ref);
  auto var_vec = lt.ir.node(lt.node(ref).node).vars();
  std::unordered_set<IR::VarRef> vars = {var_vec.begin(), var_vec.end()};
  std::unordered_map<IR::VarRef, std::pair<int, int>> var_sizes;
  while (loop_ref != lca) {
    auto loop = lt.node(loop_ref).loop;
    auto size = loop.size;
    if (!vars.count(loop.var)) {
      loop_ref = lt.parent(loop_ref);
      continue;
    }
    if (var_sizes.count(loop.var)) {
      auto s = var_sizes[loop.var];
      size = size * (s.first + s.second);
    }
    var_sizes[loop.var] = std::make_pair(size, loop.tail);
    loop_ref = lt.parent(loop_ref);
  }
  size_t total = 1;
  for (auto &p : var_sizes) {
    total *= (p.second.first + p.second.second);
  }
  auto node_ref = lt.node(ref).node;
  bool reduction = (lt.ir.pointwise_vars(node_ref).size() !=
                    lt.ir.all_vars(node_ref).size());
  bool should_init = false;
  float init_val = -1337;
  if (lt.ir.node(node_ref).op() == "mul") {
    should_init = reduction;
    init_val = 1;
  } else if (lt.ir.node(node_ref).op() == "add") {
    should_init = reduction;
    init_val = 0;
  }
  Allocation alloc{total,       static_cast<int>(aux.allocs.size()),
                   should_init, init_val,
                   lca,         ref};
  aux.allocs[node_ref] = alloc;
  aux.resets[alloc.lca].emplace_back(alloc);
}
void gen_alloc ( const LoopTree & lt , Auxiliary & aux , LoopTree :: TreeRef ref ) { ASSERT ( lt . node ( ref ) . kind == LoopTree :: NODE ) ; LoopTree :: TreeRef lca = get_scope ( lt , ref ) ; auto loop_ref = lt . parent ( ref ) ; auto var_vec = lt . ir . node ( lt . node ( ref ) . node ) . vars ( ) ; std :: unordered_set < IR :: VarRef > vars = { var_vec . begin ( ) , var_vec . end ( ) } ; std :: unordered_map < IR :: VarRef , std :: pair < int , int > > var_sizes ; while ( loop_ref != lca ) { auto loop = lt . node ( loop_ref ) . loop ; auto size = loop . size ; if ( ! vars . count ( loop . var ) ) { loop_ref = lt . parent ( loop_ref ) ; continue ; } if ( var_sizes . count ( loop . var ) ) { auto s = var_sizes [ loop . var ] ; size = size * ( s . first + s . second ) ; } var_sizes [ loop . var ] = std :: make_pair ( size , loop . tail ) ; loop_ref = lt . parent ( loop_ref ) ; } size_t total = 1 ; for ( auto & p : var_sizes ) { total *= ( p . second . first + p . second . second ) ; } auto node_ref = lt . node ( ref ) . node ; bool reduction = ( lt . ir . pointwise_vars ( node_ref ) . size ( ) != lt . ir . all_vars ( node_ref ) . size ( ) ) ; bool should_init = false ; float init_val = -1337 ; if ( lt . ir . node ( node_ref ) . op ( ) == " " ) { should_init = reduction ; init_val = 1 ; } else if ( lt . ir . node ( node_ref ) . op ( ) == " " ) { should_init = reduction ; init_val = 0 ; } Allocation alloc { total , static_cast < int > ( aux . allocs . size ( ) ) , should_init , init_val , lca , ref } ; aux . allocs [ node_ref ] = alloc ; aux . resets [ alloc . lca ] . emplace_back ( alloc ) ; }
Nodes are values!
Nodes are values!
// var -> running size, last tail