kumasento / polymer

Bridging polyhedral analysis tools to the MLIR framework
MIT License
99 stars 20 forks source link

Add the reg2mem pass to break dependences in imperfectly nested loops #56

Closed kumasento closed 3 years ago

kumasento commented 3 years ago
affine.for %i ... {
  %0 = affine.load %A[%i]
  affine.store %something, %A[%i]
  affine.for %j {
    %1 = mulf %0, %0
    affine.store %1, %B[%i, %j]
  }
}

This code is hard to handle because:

  1. The loops are imperfectly nested, and in our current implementation of PlutoTransform , we need to create a statement that contains a loop structure in it. Don't know if Pluto will be unhappy about this, or it may cause problems;
  2. There is a WAR dependence between the first load/store pair. So we cannot reorder them.

One solution is to adapt a reg2mem pass, which breaks the dependences between nested loops by storing the SSA values (%0 in the given example) that may still live when we enter a nested block. Such that we don't have to create statements that across multiple loops, and we can explicitly model the dependences.

For instance, if we transform the previously given example in the following way:

affine.for %i ... {
  // S1(i)
  %0 = affine.load %A[%i]
  affine.store %0, %scatchpad[%i]

  // S2(i)
  affine.store %something %A[%i]
  affine.for %j {
    // S3(i, j)
    %1 = affine.load %scatchpad[%i]
    %2 = mulf %0, %0
    affine.store %2, %B[%i, %j]
  }
}

We may create clearly separated statements just within each loop nest level. The %scratchpad is the memory we create to store those live-out SSA values.

We could implement this pass based on the basic liveness analysis algorithm. The size of the allocated memory depends on the iteration space of the loop nest level it resides in.

It would be helpful for the following issues: #5 #42 #48