Skip to content

[MLIR][Arith] Add ExpandOps to convertArithToLLVM #117305

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

Merged
merged 6 commits into from
Dec 4, 2024

Conversation

nujaa
Copy link
Contributor

@nujaa nujaa commented Nov 22, 2024

Arith Floor and Ceil ops would not get lowered when running --convert-arith-to-llvm.

@banach-space
Copy link
Contributor

Hey Hugo, thanks for sending this! This is marked as draft, so I presume not yet ready for reviewing?

@nujaa nujaa marked this pull request as ready for review November 27, 2024 07:51
@llvmbot llvmbot added the mlir label Nov 27, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 27, 2024

@llvm/pr-subscribers-mlir

Author: Hugo Trachino (nujaa)

Changes

Arith Floor and Ceil ops would not get lowered when running --convert-arith-to-llvm.


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

2 Files Affected:

  • (modified) mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp (+4-1)
  • (modified) mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir (+62)
diff --git a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
index aac24f113d891f..b1a971e3e9e8eb 100644
--- a/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
+++ b/mlir/lib/Conversion/ArithToLLVM/ArithToLLVM.cpp
@@ -13,6 +13,7 @@
 #include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
 #include "mlir/Conversion/LLVMCommon/VectorPattern.h"
 #include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Arith/Transforms/Passes.h"
 #include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
 #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
 #include "mlir/IR/TypeUtilities.h"
@@ -477,7 +478,8 @@ struct ArithToLLVMConversionPass
       options.overrideIndexBitwidth(indexBitwidth);
 
     LLVMTypeConverter converter(&getContext(), options);
-    mlir::arith::populateArithToLLVMConversionPatterns(converter, patterns);
+    arith::populateArithExpandOpsPatterns(patterns);
+    arith::populateArithToLLVMConversionPatterns(converter, patterns);
 
     if (failed(applyPartialConversion(getOperation(), target,
                                       std::move(patterns))))
@@ -503,6 +505,7 @@ struct ArithToLLVMDialectInterface : public ConvertToLLVMPatternInterface {
   void populateConvertToLLVMConversionPatterns(
       ConversionTarget &target, LLVMTypeConverter &typeConverter,
       RewritePatternSet &patterns) const final {
+    arith::populateArithExpandOpsPatterns(patterns);
     arith::populateArithToLLVMConversionPatterns(typeConverter, patterns);
   }
 };
diff --git a/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir b/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
index 64c40f1aba43bc..a9dcc0a16b3dbd 100644
--- a/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
+++ b/mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir
@@ -540,6 +540,68 @@ func.func @select(%arg0 : i1, %arg1 : i32, %arg2 : i32) -> i32 {
 
 // -----
 
+// CHECK-LABEL: @ceildivsi
+// CHECK-SAME: %[[ARG0:.*]]: i64) -> i64
+func.func @ceildivsi(%arg0 : i64) -> i64 {
+  // CHECK: %[[CST0:.*]] = llvm.mlir.constant(1 : i64) : i64
+  // CHECK: %[[CST1:.*]] = llvm.mlir.constant(0 : i64) : i64
+  // CHECK: %[[CST2:.*]] = llvm.mlir.constant(-1 : i64) : i64
+  // CHECK: %[[CMP0:.*]] = llvm.icmp "sgt" %[[ARG0]], %[[CST1]] : i64
+  // CHECK: %[[SEL0:.*]] = llvm.select %[[CMP0]], %[[CST2]], %[[CST0]] : i1, i64
+  // CHECK: %[[ADD0:.*]] = llvm.add %[[SEL0]], %[[ARG0]] : i64
+  // CHECK: %[[DIV0:.*]] = llvm.sdiv %[[ADD0]], %[[ARG0]] : i64
+  // CHECK: %[[ADD1:.*]] = llvm.add %[[DIV0]], %[[CST0]] : i64
+  // CHECK: %[[SUB0:.*]] = llvm.sub %[[CST1]], %[[ARG0]] : i64
+  // CHECK: %[[DIV1:.*]] = llvm.sdiv %[[SUB0]], %[[ARG0]] : i64
+  // CHECK: %[[SUB1:.*]] = llvm.sub %[[CST1]], %[[DIV1]] : i64
+  // CHECK: %[[CMP1:.*]] = llvm.icmp "slt" %[[ARG0]], %[[CST1]] : i64
+  // CHECK: %[[CMP2:.*]] = llvm.icmp "sgt" %[[ARG0]], %[[CST1]] : i64
+  // CHECK: %[[CMP3:.*]] = llvm.icmp "slt" %[[ARG0]], %[[CST1]] : i64
+  // CHECK: %[[CMP4:.*]] = llvm.icmp "sgt" %[[ARG0]], %[[CST1]] : i64
+  // CHECK: %[[AND0:.*]] = llvm.and %[[CMP1]], %[[CMP3]] : i1
+  // CHECK: %[[AND1:.*]] = llvm.and %[[CMP2]], %[[CMP4]] : i1
+  // CHECK: %[[OR:.*]] = llvm.or %[[AND0]], %[[AND1]] : i1
+  // CHECK: %[[SEL1:.*]] = llvm.select %[[OR]], %[[ADD1]], %[[SUB1]] : i1, i64
+  %0 = arith.ceildivsi %arg0, %arg0 : i64
+  return %0: i64
+}
+
+// CHECK-LABEL: @ceildivui
+// CHECK-SAME: %[[ARG0:.*]]: i32) -> i32
+func.func @ceildivui(%arg0 : i32) -> i32 {
+// CHECK: %[[CST0:.*]] = llvm.mlir.constant(0 : i32) : i32
+// CHECK: %[[CMP0:.*]] = llvm.icmp "eq" %[[ARG0]], %[[CST0]] : i32
+// CHECK: %[[CST1:.*]] = llvm.mlir.constant(1 : i32) : i32
+// CHECK: %[[SUB0:.*]] = llvm.sub %[[ARG0]], %[[CST1]] : i32
+// CHECK: %[[DIV0:.*]] = llvm.udiv %[[SUB0]], %[[ARG0]] : i32
+// CHECK: %[[ADD0:.*]] = llvm.add %[[DIV0]], %[[CST1]] : i32
+// CHECK: %[[SEL0:.*]] = llvm.select %[[CMP0]], %[[CST0]], %[[ADD0]] : i1, i32
+  %0 = arith.ceildivui %arg0, %arg0 : i32
+  return %0: i32
+}
+
+// -----
+
+// CHECK-LABEL: @floordivsi
+// CHECK-SAME: %[[ARG0:.*]]: i32, %[[ARG1:.*]]: i32) -> i32
+func.func @floordivsi(%arg0 : i32, %arg1 : i32) -> i32 {
+  // CHECK: %[[SDIV:.*]] = llvm.sdiv %[[ARG0]], %[[ARG1]] : i32
+  // CHECK: %[[MUL0:.*]] = llvm.mul %[[SDIV]], %[[ARG1]] : i32
+  // CHECK: %[[CMP0:.*]] = llvm.icmp "ne" %[[ARG0]], %[[MUL0]] : i32
+  // CHECK: %[[CST0:.*]] = llvm.mlir.constant(0 : i32) : i32
+  // CHECK: %[[CMP1:.*]] = llvm.icmp "slt" %[[ARG0]], %[[CST0]] : i32
+  // CHECK: %[[CMP2:.*]] = llvm.icmp "slt" %[[ARG1]], %[[CST0]] : i32
+  // CHECK: %[[CMP3:.*]] = llvm.icmp "ne" %[[CMP1]], %[[CMP2]] : i1
+  // CHECK: %[[AND:.*]] = llvm.and %[[CMP0]], %[[CMP3]] : i1
+  // CHECK: %[[CST1:.*]] = llvm.mlir.constant(-1 : i32) : i32
+  // CHECK: %[[ADD:.*]] = llvm.add %[[SDIV]], %[[CST1]] : i32
+  // CHECK: %[[SEL:.*]] = llvm.select %[[AND]], %[[ADD]], %[[SDIV]] : i1, i32
+  %0 = arith.floordivsi %arg0, %arg1 : i32
+  return %0 : i32
+}
+
+// -----
+
 // CHECK-LABEL: @minmaxi
 func.func @minmaxi(%arg0 : i32, %arg1 : i32) -> i32 {
   // CHECK: = llvm.intr.smin(%arg0, %arg1) : (i32, i32) -> i32

@nujaa
Copy link
Contributor Author

nujaa commented Nov 27, 2024

Hey Hugo, thanks for sending this! This is marked as draft, so I presume not yet ready for reviewing?

Sorry I forgot to submit it after running the draft tests. 🙄

Copy link
Contributor

@krzysz00 krzysz00 left a comment

Choose a reason for hiding this comment

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

Given the context, I'll argue for mlir::arith::populateCeilFloorDivExpandOpsPatterns specifically.

The other "expand" patterns include things like expanding minsi or maxui, which have LLVM lowerings, and we don't want to add those here.

@@ -503,6 +505,7 @@ struct ArithToLLVMDialectInterface : public ConvertToLLVMPatternInterface {
void populateConvertToLLVMConversionPatterns(
ConversionTarget &target, LLVMTypeConverter &typeConverter,
RewritePatternSet &patterns) const final {
arith::populateArithExpandOpsPatterns(patterns);
arith::populateArithToLLVMConversionPatterns(typeConverter, patterns);
}
};
Copy link
Collaborator

Choose a reason for hiding this comment

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

This pass is kind of deprecated: we're supposed to migrate to --convert-to-llvm.
I'm concerned by additions here that wouldn't carry over to --convert-to-llvm!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not completely sure of what you mean.
The tests mlir/test/Conversion/ArithToLLVM/arith-to-llvm.mlir calls both convert-arith-to-llvm and --convert-to-llvm. If either arith-to-llvm or convert-to-llvm is updated, the other must be updated as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

@nujaa , wouldn't adding this in "ConvertToLLVMPass.cpp" instead also work?

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm confused because you're only changing the ArithToLLVMConversionPass here, so was this behavior already implemented in the convert-to-llvm flow and you're just catching up?

(I guess that makes my point as well somehow: we should remove the convert-arith-to-llvm pass: it does not provide anything that convert-to-llvm can't do, hopefully).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nujaa , wouldn't adding this in "ConvertToLLVMPass.cpp" instead also work?

I think it is Arith specific and should not be part of generic ConvertToLLVMPass

Copy link
Contributor Author

@nujaa nujaa Dec 4, 2024

Choose a reason for hiding this comment

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

so was this behavior already implemented in the convert-to-llvm flow and you're just catching up?

Neither arith-to-llvm nor convert-to-llvm was not expanding ops. As the test runs both with the same CHECK-lines.

@nujaa
Copy link
Contributor Author

nujaa commented Nov 28, 2024

Given the context, I'll argue for mlir::arith::populateCeilFloorDivExpandOpsPatterns specifically.

The other "expand" patterns include things like expanding minsi or maxui, which have LLVM lowerings, and we don't want to add those here.

Good catch, thanks.

Copy link

github-actions bot commented Nov 28, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@krzysz00 krzysz00 self-requested a review December 2, 2024 18:06
Copy link
Contributor

@krzysz00 krzysz00 left a comment

Choose a reason for hiding this comment

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

Removing my hold

@nujaa nujaa merged commit 2c739df into llvm:main Dec 4, 2024
8 checks passed
@RoboTux
Copy link
Contributor

RoboTux commented Dec 4, 2024

A dependency on MLIRArithTransforms seems to be missing, CI is failing:

/usr/bin/ld: tools/mlir/lib/Conversion/ArithToLLVM/CMakeFiles/obj.MLIRArithToLLVM.dir/ArithToLLVM.cpp.o: in function (anonymous namespace)::ArithToLLVMDialectInterface::populateConvertToLLVMConversionPatterns(mlir::ConversionTarget&, mlir::LLVMTypeConverter&, mlir::RewritePatternSet&) const': ArithToLLVM.cpp:(.text._ZNK12_GLOBAL__N_127ArithToLLVMDialectInterface39populateConvertToLLVMConversionPatternsERN4mlir16ConversionTargetERNS1_17LLVMTypeConverterERNS1_17RewritePatternSetE+0x18): undefined reference to mlir::arith::populateCeilFloorDivExpandOpsPatterns(mlir::RewritePatternSet&)'
/usr/bin/ld: tools/mlir/lib/Conversion/ArithToLLVM/CMakeFiles/obj.MLIRArithToLLVM.dir/ArithToLLVM.cpp.o: in function (anonymous namespace)::ArithToLLVMConversionPass::runOnOperation()': ArithToLLVM.cpp:(.text._ZN12_GLOBAL__N_125ArithToLLVMConversionPass14runOnOperationEv+0x10c): undefined reference to mlir::arith::populateCeilFloorDivExpandOpsPatterns(mlir::RewritePatternSet&)'
clang++: error: linker command failed with exit code 1 (use -v to see invocation)

See:
https://lab.llvm.org/buildbot/#/builders/80/builds/7168
https://lab.llvm.org/buildbot/#/builders/130/builds/7036
https://lab.llvm.org/buildbot/#/builders/138/builds/7290

@RoboTux
Copy link
Contributor

RoboTux commented Dec 4, 2024

Another option is to move that code that into MLIRArithUtils if we do not want to depend on MLIRArithTransforms

sys-ceuplift pushed a commit to nstester/llvm-project that referenced this pull request Dec 4, 2024
@banach-space
Copy link
Contributor

banach-space commented Dec 4, 2024

Reverted.

@nujaa , this shouldn't land while there's an ongoing design discussion on the suitable placement of these patterns.

EDIT

Just to clarify. I know @krzysz00 has already approved this.That was effectively LGTM without any qualification (we're missing "explicit" LGTM, but that's beside the point). From How Patch is Accepted:

When providing an unqualified LGTM (approval to commit), it is the responsibility of the reviewer to have reviewed all of the prior discussion and feedback from all reviewers ensuring that all feedback has been addressed and that all other reviewers will almost surely be satisfied with the patch being approved.

I just don't believe that all feedback has been addressed - especially given that the discussion continued post-LGTM :) And then the failing bot.

@nujaa
Copy link
Contributor Author

nujaa commented Dec 4, 2024

@nujaa , this shouldn't land while there's an ongoing design discussion on the suitable placement of these patterns.

Yes, Sorry, I didn't see the upper comments until I merged following the approval and passing tests. My bad.

@banach-space
Copy link
Contributor

Yes, Sorry, I didn't see the upper comments until I merged following the approval and passing tests. My bad.

No worries, I also find GitHub quite tricky to navigate. Note that we have a very liberal "revert" policy in LLVM - please don't let this discourage you from contributing! :)

@nujaa
Copy link
Contributor Author

nujaa commented Dec 4, 2024

Alright. Thanks both for reverting, pointing it out and the motivation. I could not find guidelines on how to revert a commit without going through the MR review process. Do I simply push the revert commit without waiting for approval ?

Before I submit any fix, I would like to make sure of a few things :
To answer @joker-eph ,

I'm confused because you're only changing the ArithToLLVMConversionPass

If I am not mistaken, convert-to-llvm calls populateConvertToLLVMConversionPatterns implemented by a ConvertToLLVMPatternInterface extended for Arith behind the ArithToLLVMDialectInterface. This patch does adds a call to populateCeilFloorDivExpandOpsPatterns to both ArithToLLVMConversionPass (the deprecated pass) AND ArithToLLVMDialectInterface::populateConvertToLLVMConversionPatterns (the preferred one). I am not sure if I should do something else to mention it is part of convert-to-llvm.

wouldn't adding this in "ConvertToLLVMPass.cpp" instead also work?

I think ConvertToLLVMPass.cpp implements a shared interface among dialects to lower to LLVM and should not implement a requirement for some ops of a given dialect.
@banach-space , do you maybe mean adding CeilFloorDivExpandOpsPatterns to populateArithToLLVMConversionPatterns which is called in both ArithToLLVMConversionPass AND ArithToLLVMDialectInterface::populateConvertToLLVMConversionPatterns ? I agree it does factorize the code. Although, populateArithToLLVMConversionPatterns calls specifically lowerings of arith ops to LLVM of the type %OpName%Lowering. Whereas CeilFloorDivExpandOpsPatterns is not an op lowering to LLVM per se. I am convincible on this, you have the last word.

Thanks again all for your patience.

@banach-space
Copy link
Contributor

I could not find guidelines on how to revert a commit without going through the MR review process.

There's a few relevant parts to consider here. First, the revert policy:

And indeed, it does not discuss "how". However, note:

Reverts should be reasonably timely. A change submitted two hours ago can be reverted without prior discussion.

And then, under obtaining-commit-access

You are allowed to commit patches without approval which you think are obvious. This is clearly a subjective decision — we simply expect you to use good judgement.

From my experience, "reverts" are where you tend to 100% rely on your judgement - it's the easiest and quickest way to fix buildbot failures. In more complex situation (e.g. no buildbot breakage upstream, but some issues downstream), we tend use PRs. But even then, if a repro has been shared, folks tend to revert. This way patch authors are not under pressure to fix immediately (sometimes that's just physically not possible).

Thanks again all for your patience.

No worries Hugo, this is standard practice ;-)

@banach-space
Copy link
Contributor

If I am not mistaken, convert-to-llvm calls populateConvertToLLVMConversionPatterns implemented by a ConvertToLLVMPatternInterface extended for Arith behind the ArithToLLVMDialectInterface.

OK, this is what we were missing :) And apologies, I forgot how -convert-to-llvm was wired-up.

Like you said, ConvertToLLVM invokes these populateConvertToLLVMConversionPatterns methods for every Dialect that implements ConvertToLLVMPatternInterface:

// Populate the patterns with the dialect interface.
if (failed(visitInterfaces([&](ConvertToLLVMPatternInterface *iface) {
iface->populateConvertToLLVMConversionPatterns(
*target, *typeConverter, tempPatterns);
})))

And that's what's being updated here. But you are also updating the -convert-arith-to-llvm path, right? In summary:

Is this accurate?

Arith Floor and Ceil ops would not get lowered when running --convert-arith-to-llvm.

Considering Mehdi's comment re this path being deprecated in favour of -convert-to-llvm, shouldn't this comment focus on -convert-to-llvm instead? Also, some element of this discussion should be included in the summary. We shouldn't be required to scan PR discussions to understand the rationale behind a particular change - that's what summaries are for ;-)

@joker-eph
Copy link
Collaborator

The confusion to me came from comments like:

I think it is Arith specific and should not be part of generic ConvertToLLVMPass

I think an answer that would have resolved the discussion immediately could have been along the line of:

this patch is actually plumbing the new pattern through both passes, since this is adding the call in ArithToLLVMDialectInterface as well. The test demonstrates the behavior is consistent between the two passes.

We should be all good now I think.

nujaa added a commit to nujaa/llvm-project that referenced this pull request Dec 5, 2024
Arith Floor and Ceil ops would not get lowered when running
--convert-arith-to-llvm.
nujaa added a commit that referenced this pull request Dec 16, 2024
… (Reland) (#118839)

When running `convert-to-llvm`, `ceildiv` and `floordiv` ops, which do not
have direct llvm conversion pattern, would not get lowered to llvm
dialect. This patch adds CeilFloorDivExpandOpsPatterns to both
`convert-to-llvm` and `arith-to-llvm` (deprecated) lowering those ops to
lower level arith ops which can be lowered to llvm using LLVM
conversion.

Reland of #117305 after
buildbot failures.
See:
https://lab.llvm.org/buildbot/#/builders/80/builds/7168
https://lab.llvm.org/buildbot/#/builders/130/builds/7036
https://lab.llvm.org/buildbot/#/builders/138/builds/7290

Added dependence to ArithTransforms in ArithToLLVM. In previous
discussion, it has been suggested to move the
CeilFloorDivExpandOpsPatterns to ArithUtils but I think linking
ArithTransforms makes more sense as otherwise :
* ArithToLLVM needs a new dependency to ArithUtils
* ArithUtils needs new dependency to ArithTransforms or move the
patterns as well which will create more dependencies
* It creates lots of code motion which makes it hard to review.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants