HOME

2020-07-22

Where we stand

So, what's the status?

For now, we're only concerned with kernels. We know that all allocations and array initializations that we have to look at take place inside those kernels. Allocations can still be hoisted to the top of the kernel, and we preferably still want to be able to run the pass multiple times, but not after the ExpandAllocations pass has run. In addition, we should be a bit more conservative when creating our interference graph for loops and nested kernels.

This means that we are mostly concerned with kernels that look like this:

1: SegMap_n {
2:   let xs_mem = alloc x
3:   let xs@xs_mem = ...
4:   ...
5:   let ys_mem = alloc y
6:   let ys@ys_mem = ...
7: }

Although it can also be a nested map with an outer SegMapGroup. So let's imagine we have a pass that runs through the program, and then when it hits a kernel it runs the analyseBody and optimiseBody functions from yesterday.

Let's paste it here as well, so we know what we're talking about:

analyseStm :: LastUseMap -> InUse -> MemGraph -> Stm -> (InUse, LastUsed, MemGraph, Stm)
analyseStm lu_map inuse graph (let p = exp) =
  let (inuse_new, lus_new, graph_new, stm_new) =
    if exp is a loop with body b then
      let (inuse', lus, graph', b') = analyseBody lu_map b
      let graph'' = graphgraph' ∪ (inuse ↔ (inuse'lus))
      let inuse'' = inuselusinuse'
      in (inuse'', lus, graph'', let p = exp with b')
    else if exp is a if with bodies b1, b2 then
      let (inuse1, lus1, g1, b1') = analyseBody lu_map b1
      let (inuse2, lus2, g2, b2') = analyseBody lu_map b2
      let lus = lus1lus2
      let inuse' = (inuseinuse1inuse2) ∖ lus
      let g = graphg1g2
                ∪ ((inuse1lus1) ↔ (inuse ∖ (lus2lus1)))
                ∪ ((inuse2lus2) ↔ (inuse ∖ (lus1lus2)))
      in (inuse', lus, g, let p = exp with b1' and b2')
    else if exp is a kernel call with a body b then
      same as loop†
    else
      let lus = lookup p in lu_map
      let lus_mems = memory blocks referenced in lus
      let inuse' = inuselus_mems
      in (inuse'', lus_mems, graph, stm)

  let mems = memory blocks referenced in p
  let inuse_end = inuse_newmems
  let graph_end = graph_new ∪ (inuse_endinuse_end)
  in (inuse_end, lus_new, graph_end, stm_new)

The first thing we need to do, is make sure any memory blocks referenced in p interferes with the memory blocks inside exp.

analyseStm :: LastUseMap -> InUse -> MemGraph -> Stm -> (InUse, LastUsed, MemGraph, Stm)
analyseStm lu_map inuse0 graph0 (let p = exp) =
  let mems = memory blocks referenced in p
  let inuse = inuse0mems
  let graph = graph0 ∪ (inuseinuse)

  if exp is a loop with body b then
    let (inuse', lus, graph', b') = analyseBody lu_map b
    let graph'' = graphgraph' ∪ (inuse ↔ (inuse'lus))
    let inuse'' = inuselusinuse'
    in (inuse'', lus, graph'', let p = exp with b')
  else if exp is a if with bodies b1, b2 then
    let (inuse1, lus1, g1, b1') = analyseBody lu_map b1
    let (inuse2, lus2, g2, b2') = analyseBody lu_map b2
    let lus = lus1lus2
    let inuse' = (inuseinuse1inuse2) ∖ lus
    let g = graphg1g2
              ∪ ((inuse1lus1) ↔ (inuse ∖ (lus2lus1)))
              ∪ ((inuse2lus2) ↔ (inuse ∖ (lus1lus2)))
    in (inuse', lus, g, let p = exp with b1' and b2')
  else if exp is a kernel call with a body b then
    same as loop†
  else
    let lus = lookup p in lu_map
    let lus_mems = memory blocks referenced in lus
    let inuse' = inuselus_mems
    in (inuse'', lus_mems, graph, stm)

That should do it.

I kinda want to just go ahead and implement this now…

Well, it didn't happen today. I think I'll jump into it tomorrow.