Strange behavior of liveness in MLIR

Hello All,

I am using the liveness analysis in MLIR but I am getting some strange results. My example code is very simple:

%1 = ... (value is defined)
affine.for() {
  ... = %1 (value is used)
  ... = ... (other irrelevant computation)
}
... = %1 (value is used, last time)

When I query liveness.isDeadAfter(%1, … = … (other irrelevant computation)) I strangely get a true result, even though there is a use of %1 after the affine for loop.

Am I using the liveness object incorrectly?

Thanks for any hints,
Pedro

Hello All,

After debugging the liveness code it is clear why I am getting such result to the query. The liveOuts of the two blocks in my example program are never updated. The reason for that is as follows (liveness code follows):

  SetVector toProcess;

  operation->walk([&](Block *block) {
    BlockInfoBuilder &builder =
        builders.try_emplace(block, block).first->second;
    if (builder.updateLiveIn())
      toProcess.insert(block->pred_begin(), block->pred_end());
  });

  // Propagate the in and out-value sets (fixpoint iteration).
  while (!toProcess.empty()) {
   ...
  }

My example program has two Blocks, the main block and a block inside the region defined by the affine loop. Both blocks have no entries in the predecessor list. (block->hasNoPredecessors() returns true); hence the fix point computation never adds any blocks to “toProcess” and thinks the initial liveness is the final result, with all outSets empty.

All of this happens because Liveness seems to expect a traditional control flow graph but my MLIR program contains a region with one block which contains an affine loop; who itself contains a region with one block.

In my opinion the statement that liveness makes:

/// Represents an analysis for computing liveness information from a
/// given top-level operation. The analysis iterates over all associated
/// regions that are attached to the given top-level operation. It
/// computes liveness information for every value and block that are
/// included in the mentioned regions. It relies on a fixpoint iteration
/// to compute all live-in and live-out values of all included blocks.

Is at least misleading because it does not understand nested regions as far as I can tell.