Skip to content

[MLIR][NFC] Adding a missing option in OneShotBufferizePass #130691

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

lialan
Copy link
Member

@lialan lialan commented Mar 11, 2025

#129850 removed let constructor for OneShotBufferizePass, however the list of tablegen options missed one inherited from BufferizationOptions.

it missed one option which is inherited from BufferizationOptions.
@lialan lialan requested review from chelini and removed request for matthias-springer March 11, 2025 00:22
@llvmbot llvmbot added mlir mlir:bufferization Bufferization infrastructure labels Mar 11, 2025
@lialan lialan requested a review from joker-eph March 11, 2025 00:23
@llvmbot
Copy link
Member

llvmbot commented Mar 11, 2025

@llvm/pr-subscribers-mlir

Author: Alan Li (lialan)

Changes

#129850 removed let constructor for OneShotBufferizePass, however the list of tablegen options missed one inherited from BufferizationOptions.


Full diff: https://github.com/llvm/llvm-project/pull/130691.diff

2 Files Affected:

  • (modified) mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td (+4)
  • (modified) mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp (+1)
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
index 3bbb8b02c644e..b979f9df620d2 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
@@ -450,6 +450,10 @@ def OneShotBufferizePass : Pass<"one-shot-bufferize", "ModuleOp"> {
        Option<"bufferAlignment", "buffer-alignment", "uint64_t",
               /*default=*/"64",
               "Sets the alignment of newly allocated buffers.">,
+       Option<"enforceAliasingInvariants", "enforce-aliasing-invariants", "bool",
+              /*default=*/"true",
+              "Enforce aliasing Op/Operand/OpResult invariants with buffer"
+              " copies.">,
   ];
 
   let statistics = [
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
index c0e3fca428376..f4891a317476d 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
@@ -81,6 +81,7 @@ struct OneShotBufferizePass
       opt.allowUnknownOps = allowUnknownOps;
       opt.analysisFuzzerSeed = analysisFuzzerSeed;
       opt.analysisHeuristic = parseHeuristicOption(analysisHeuristic);
+      opt.enforceAliasingInvariants = enforceAliasingInvariants;
       opt.copyBeforeWrite = copyBeforeWrite;
       opt.dumpAliasSets = dumpAliasSets;
       opt.setFunctionBoundaryTypeConversion(

@llvmbot
Copy link
Member

llvmbot commented Mar 11, 2025

@llvm/pr-subscribers-mlir-bufferization

Author: Alan Li (lialan)

Changes

#129850 removed let constructor for OneShotBufferizePass, however the list of tablegen options missed one inherited from BufferizationOptions.


Full diff: https://github.com/llvm/llvm-project/pull/130691.diff

2 Files Affected:

  • (modified) mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td (+4)
  • (modified) mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp (+1)
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
index 3bbb8b02c644e..b979f9df620d2 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
@@ -450,6 +450,10 @@ def OneShotBufferizePass : Pass<"one-shot-bufferize", "ModuleOp"> {
        Option<"bufferAlignment", "buffer-alignment", "uint64_t",
               /*default=*/"64",
               "Sets the alignment of newly allocated buffers.">,
+       Option<"enforceAliasingInvariants", "enforce-aliasing-invariants", "bool",
+              /*default=*/"true",
+              "Enforce aliasing Op/Operand/OpResult invariants with buffer"
+              " copies.">,
   ];
 
   let statistics = [
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
index c0e3fca428376..f4891a317476d 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
@@ -81,6 +81,7 @@ struct OneShotBufferizePass
       opt.allowUnknownOps = allowUnknownOps;
       opt.analysisFuzzerSeed = analysisFuzzerSeed;
       opt.analysisHeuristic = parseHeuristicOption(analysisHeuristic);
+      opt.enforceAliasingInvariants = enforceAliasingInvariants;
       opt.copyBeforeWrite = copyBeforeWrite;
       opt.dumpAliasSets = dumpAliasSets;
       opt.setFunctionBoundaryTypeConversion(

Copy link
Collaborator

@joker-eph joker-eph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we have test coverage for this option?

@lialan
Copy link
Member Author

lialan commented Mar 11, 2025

Don't we have test coverage for this option?

I looked and I don't think we have one.

@joker-eph
Copy link
Collaborator

Can we get some?

@lialan
Copy link
Member Author

lialan commented Mar 11, 2025

Can we get some?

To be fair most (if not all) of those options in the bufferization passes do not have corresponding tests, so #129850 skipped a lot of checks and got merged. If we want tests we would need to also cover all those. But historically no tests were in place, and adding tests is beyond the scope of this quick patch, and requires some coordination.

Our downstream does require to set this specific option, so this is just a quick patch to unblock downstream.

@chelini
Copy link
Contributor

chelini commented Mar 11, 2025

Can we get some?

To be fair most (if not all) of those options in the bufferization passes do not have corresponding tests, so #129850 skipped a lot of checks and got merged. If we want tests we would need to also cover all those. But historically no tests were in place, and adding tests is beyond the scope of this quick patch, and requires some coordination.

Our downstream does require to set this specific option, so this is just a quick patch to unblock downstream.

I don’t think #129850 “skipped a lot of checks.” The issue isn’t with #129850 itself but rather the lack of testing for options. I did not check this pass option yet, so I don't know how hard it is to add a test, but I will do it tomorrow.

@lialan
Copy link
Member Author

lialan commented Mar 11, 2025

I did not check this pass option yet, so I don't know how hard it is to add a test, but I will do it tomorrow.

@chelini Meanwhile can you approve this PR so we can get unblocked.

@joker-eph
Copy link
Collaborator

joker-eph commented Mar 11, 2025

I don't think it is OK to approve this PR because of downstream issue: if you have downstream issues you can always patch MLIR when you're consuming it downstream. Rushing PRs upstream because of quirks of your private downstream repo does not seem right to me.

We shouldn't expose options that are not tested.

Copy link
Collaborator

@joker-eph joker-eph left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Marking as needed changes)

@matthias-springer
Copy link
Member

matthias-springer commented Mar 12, 2025

Are you using this flag together with copyBeforeWrite = true? If not, this will probably make your program bufferize incorrectly.

  /// Certain ops have aliasing OpOperand/OpResult invariants (e.g., scf.for).
  /// If this flag is set to `false`, those invariants are no longer enforced
  /// with buffer copies.
  ///
  /// Note: Deactivating this flag can lead to incorrect bufferization results
  /// when used incorrectly. This flag is useful with
  /// `AlwaysCopyAnalysisState` which bufferizes all writing tensor
  /// OpOperands out-of-place.
  bool enforceAliasingInvariants = true;

If you set copyBeforeWrite = true, it is not necessary to set enforceAliasingInvariants = false. This is the only place where we read the flag:

    if (!state.getOptions().enforceAliasingInvariants ||
        state.getOptions().copyBeforeWrite)
      return success();

It's been a while since I looked at this, but maybe we can remove enforceAliasingInvariants entirely.

@chelini
Copy link
Contributor

chelini commented Mar 12, 2025

Are you using this flag together with copyBeforeWrite = true? If not, this will probably make your program bufferize incorrectly.

  /// Certain ops have aliasing OpOperand/OpResult invariants (e.g., scf.for).
  /// If this flag is set to `false`, those invariants are no longer enforced
  /// with buffer copies.
  ///
  /// Note: Deactivating this flag can lead to incorrect bufferization results
  /// when used incorrectly. This flag is useful with
  /// `AlwaysCopyAnalysisState` which bufferizes all writing tensor
  /// OpOperands out-of-place.
  bool enforceAliasingInvariants = true;

If you set copyBeforeWrite = true, it is not necessary to change enforceAliasingInvariants. This is the only place where we read the flag:

    if (!state.getOptions().enforceAliasingInvariants ||
        state.getOptions().copyBeforeWrite)
      return success();

It's been a while since I looked at this, but maybe we can remove enforceAliasingInvariants entirely.

I am trying to add a simple test case but I don't see any difference in the IR and the bufferization analysis state, here the simple test case:

func.func @loop_with_aliasing(%t: tensor<?xf32>, %idx: index, %n: index) -> tensor<?xf32> {
  %c1 = arith.constant 1 : index
  %v = arith.constant 1.0 : f32
  %0 = scf.for %i = %idx to %n step %c1 iter_args(%arg0 = %t) -> tensor<?xf32> {
    // This insert operation modifies the tensor in-place
    %1 = tensor.insert %v into %arg0[%i] : tensor<?xf32>
    scf.yield %1 : tensor<?xf32>
  }
  return %0 : tensor<?xf32>
}

It triggers the option but there is no IR difference. I would have expected a copy if I set it to false here.

@matthias-springer
Copy link
Member

What flag did you set? copyBeforeWrite or enforceAliasingInvariants? Only copyBeforeWrite will force a copy. When we have copies everywhere, some of the aliasing invariants can be relaxed. That's what the enforceAliasingInvariants is for. enforceAliasingInvariants by itself does not force a copy everywhere.

@chelini
Copy link
Contributor

chelini commented Mar 12, 2025

What flag did you set? copyBeforeWrite or enforceAliasingInvariants? Only copyBeforeWrite will force a copy. When we have copies everywhere, some of the aliasing invariants can be relaxed. That's what the enforceAliasingInvariants is for. enforceAliasingInvariants by itself does not force a copy everywhere.

I am testing with:

-one-shot-bufferize="bufferize-function-boundaries enforce-aliasing-invariants=false"
-one-shot-bufferize="bufferize-function-boundaries enforce-aliasing-invariants=true"

@matthias-springer
Copy link
Member

On a high level, enforceAliasingInvariants = true is adding additional copies for certain cases where you yield a value that is defined outside of the loop. (Whereas copyBeforeWrite will add copies every time you write to a buffer.)

@chelini
Copy link
Contributor

chelini commented Mar 12, 2025

@lialan FYI: I commented out the option in IREE and run ctest --test-dir ../iree-build/ and I don't see any test failures.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:bufferization Bufferization infrastructure mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants