-
Notifications
You must be signed in to change notification settings - Fork 14.3k
merge code for llvm.emit_c_interface into convertFuncOpToLLVMFuncOp #92986
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
merge code for llvm.emit_c_interface into convertFuncOpToLLVMFuncOp #92986
Conversation
@llvm/pr-subscribers-mlir @llvm/pr-subscribers-mlir-core Author: drazi (fengxie) ChangesIn today's repo, attribute This PR
Full diff: https://github.com/llvm/llvm-project/pull/92986.diff 5 Files Affected:
diff --git a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
index 53b44aa3241bb..202bbd6fd17ab 100644
--- a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
+++ b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
@@ -449,6 +449,26 @@ mlir::convertFuncOpToLLVMFuncOp(FunctionOpInterface funcOp,
"region types conversion failed");
}
+ if (!shouldUseBarePtrCallConv(funcOp, &converter)) {
+ if (funcOp->getAttrOfType<UnitAttr>(
+ LLVM::LLVMDialect::getEmitCWrapperAttrName())) {
+ if (newFuncOp.isVarArg())
+ return funcOp.emitError("C interface for variadic functions is not "
+ "supported yet.");
+
+ if (newFuncOp.isExternal())
+ wrapExternalFunction(rewriter, funcOp->getLoc(), converter, funcOp,
+ newFuncOp);
+ else
+ wrapForExternalCallers(rewriter, funcOp->getLoc(), converter, funcOp,
+ newFuncOp);
+ }
+ } else {
+ modifyFuncOpToUseBarePtrCallingConv(
+ rewriter, funcOp->getLoc(), converter, newFuncOp,
+ llvm::cast<FunctionType>(funcOp.getFunctionType()).getInputs());
+ }
+
return newFuncOp;
}
@@ -484,26 +504,6 @@ struct FuncOpConversion : public FuncOpConversionBase {
if (failed(newFuncOp))
return rewriter.notifyMatchFailure(funcOp, "Could not convert funcop");
- if (!shouldUseBarePtrCallConv(funcOp, this->getTypeConverter())) {
- if (funcOp->getAttrOfType<UnitAttr>(
- LLVM::LLVMDialect::getEmitCWrapperAttrName())) {
- if (newFuncOp->isVarArg())
- return funcOp->emitError("C interface for variadic functions is not "
- "supported yet.");
-
- if (newFuncOp->isExternal())
- wrapExternalFunction(rewriter, funcOp->getLoc(), *getTypeConverter(),
- funcOp, *newFuncOp);
- else
- wrapForExternalCallers(rewriter, funcOp->getLoc(),
- *getTypeConverter(), funcOp, *newFuncOp);
- }
- } else {
- modifyFuncOpToUseBarePtrCallingConv(rewriter, funcOp->getLoc(),
- *getTypeConverter(), *newFuncOp,
- funcOp.getFunctionType().getInputs());
- }
-
rewriter.eraseOp(funcOp);
return success();
}
diff --git a/mlir/test/Transforms/test-convert-func-op.mlir b/mlir/test/Transforms/test-convert-func-op.mlir
new file mode 100644
index 0000000000000..6e96703cda578
--- /dev/null
+++ b/mlir/test/Transforms/test-convert-func-op.mlir
@@ -0,0 +1,12 @@
+// RUN: mlir-opt %s -test-convert-func-op | FileCheck %s
+
+// CHECK-LABEL: llvm.func @add
+func.func @add(%arg0: i32, %arg1: i32) -> i32 attributes { llvm.emit_c_interface } {
+ %res = arith.addi %arg0, %arg1 : i32
+ return %res : i32
+}
+// CHECK-LABEL: llvm.func @_mlir_ciface_add
+// CHECK-SAME: [[ARG0:%[a-zA-Z0-9_]+]]: i32
+// CHECK-SAME: [[ARG1:%[a-zA-Z0-9_]+]]: i32
+// CHECK-NEXT: [[RES:%.*]] = llvm.call @add([[ARG0]], [[ARG1]])
+// CHECK-NEXT: llvm.return [[RES]]
diff --git a/mlir/test/lib/Conversion/FuncToLLVM/CMakeLists.txt b/mlir/test/lib/Conversion/FuncToLLVM/CMakeLists.txt
index 45ba62d839d36..d3dbc94a99bc7 100644
--- a/mlir/test/lib/Conversion/FuncToLLVM/CMakeLists.txt
+++ b/mlir/test/lib/Conversion/FuncToLLVM/CMakeLists.txt
@@ -1,6 +1,7 @@
# Exclude tests from libMLIR.so
add_mlir_library(MLIRTestFuncToLLVM
TestConvertCallOp.cpp
+ TestConvertFuncOp.cpp
EXCLUDE_FROM_LIBMLIR
diff --git a/mlir/test/lib/Conversion/FuncToLLVM/TestConvertFuncOp.cpp b/mlir/test/lib/Conversion/FuncToLLVM/TestConvertFuncOp.cpp
new file mode 100644
index 0000000000000..87fbf2dd15917
--- /dev/null
+++ b/mlir/test/lib/Conversion/FuncToLLVM/TestConvertFuncOp.cpp
@@ -0,0 +1,62 @@
+//===- TestConvertFuncOp.cpp - Test LLVM Conversion of Func FuncOp --------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "TestDialect.h"
+
+#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
+#include "mlir/Conversion/LLVMCommon/Pattern.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/Pass/Pass.h"
+
+using namespace mlir;
+
+namespace {
+
+struct TestConvertFuncOp
+ : public PassWrapper<TestConvertFuncOp, OperationPass<ModuleOp>> {
+ MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestConvertFuncOp)
+
+ void getDependentDialects(DialectRegistry ®istry) const final {
+ registry.insert<LLVM::LLVMDialect>();
+ }
+ [[nodiscard]] StringRef getArgument() const final {
+ return "test-convert-func-op";
+ }
+ [[nodiscard]] StringRef getDescription() const final {
+ return "Tests conversion of `func.func` to `llvm.func` for different "
+ "attributes";
+ }
+
+ void runOnOperation() override {
+ ModuleOp m = getOperation();
+
+ LowerToLLVMOptions options(m.getContext());
+
+ // Populate type conversions.
+ LLVMTypeConverter typeConverter(m.getContext(), options);
+
+ // Populate patterns.
+ RewritePatternSet patterns(m.getContext());
+ populateFuncToLLVMConversionPatterns(typeConverter, patterns);
+
+ // Set target.
+ ConversionTarget target(getContext());
+ target.addLegalDialect<LLVM::LLVMDialect>();
+ target.addIllegalDialect<func::FuncDialect>();
+
+ if (failed(applyPartialConversion(m, target, std::move(patterns))))
+ signalPassFailure();
+ }
+};
+
+} // namespace
+
+namespace mlir::test {
+void registerConvertFuncOpPass() { PassRegistration<TestConvertFuncOp>(); }
+} // namespace mlir::test
diff --git a/mlir/tools/mlir-opt/mlir-opt.cpp b/mlir/tools/mlir-opt/mlir-opt.cpp
index 1dfc5d178b614..0e8b161d51345 100644
--- a/mlir/tools/mlir-opt/mlir-opt.cpp
+++ b/mlir/tools/mlir-opt/mlir-opt.cpp
@@ -71,6 +71,7 @@ namespace test {
void registerTestCompositePass();
void registerCommutativityUtils();
void registerConvertCallOpPass();
+void registerConvertFuncOpPass();
void registerInliner();
void registerMemRefBoundCheck();
void registerPatternsTestPass();
@@ -199,6 +200,7 @@ void registerTestPasses() {
mlir::test::registerTestCompositePass();
mlir::test::registerCommutativityUtils();
mlir::test::registerConvertCallOpPass();
+ mlir::test::registerConvertFuncOpPass();
mlir::test::registerInliner();
mlir::test::registerMemRefBoundCheck();
mlir::test::registerPatternsTestPass();
|
The change LGTM but I'd want to ask @ftynse : do you see a reason why the pattern included this code and not the "utility API" before? |
Updated test to only test utility function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the patch! I suppose this is the case of "nobody needed this yet".
Can we do one step further and actually generalize this function to be usable without conversion patterns? It can take a RewriterBase &
instead of ConversionPatternRewriter
as far as I can see. Then it becomes usable standalone and the test can be simplified to actually test the function and not the function + conversion infra.
RewritePatternSet patterns(ctx); | ||
patterns.add<FuncOpConversion>(ctx); | ||
|
||
populateFuncToLLVMConversionPatterns(typeConverter, patterns, nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this add the regular func conversion pattern in addition to the one added above? So we don't actually know what we are testing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot for suggestion. I actually started with RewriterBase &. But RewriterBase doesn't have inlineRegionBefore and convertRegionTypes. I prefer RewriterBase & if it works. Do you have suggestion on it?
rewriter.inlineRegionBefore(funcOp.getFunctionBody(), newFuncOp.getBody(),
newFuncOp.end());
if (failed(rewriter.convertRegionTypes(&newFuncOp.getBody(), converter,
&result))) {
return rewriter.notifyMatchFailure(funcOp,
"region types conversion failed");
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this add the regular func conversion pattern in addition to the one added above? So we don't actually know what we are testing?
Yes, this adds regular func conversion patterns. I created a test only have "llvm.emit_c_interface" to only test it is handled by this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why we need the regular func conversion pattern here. It should be enough to exercise the new pattern, and we want tests to be as minimal as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, thanks for explanation. I think I misunderstood your feedback. What I need to do is to delete this line right?
populateFuncToLLVMConversionPatterns(typeConverter, patterns, nullptr);
I just deleted this line and replaced it with pattern conversion for return op to llvm ( I need this to convert full func op ). Please let me know if this addressed the comment. Thanks in advance!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically we don't even need to use a pattern, just a walk() should do right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For this one, I have to use pattern as convertFuncOpToLLVMFuncOp
requires pattern rewriter which I can't create outside of pattern. I started with walk
+ RewriteBase &
in the beginning but switch back to pattern.
patterns.add<FuncOpConversion>(ctx);
For ReturnOpConversion
, I choose to use pattern as I already have pattern rewriter setup in place for funcOp.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ftynse if got a chance, can you review latest changes are good to address feedbacks?
- deleting general pattern and replace it with return op -> llvm.return pattern.
populateFuncToLLVMConversionPatterns(typeConverter, patterns, nullptr);
Thanks for checking. In this case, it looks easier to just keep the |
@ftynse please let me know if all comments are addressed
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG, but let's wait for @ftynse !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks!
In today's repo, attribute
llvm.emit_c_interface
of func op is handled outside ofmlir::convertFuncOpToLLVMFuncOp
inFuncOpConversion
pattern. In some cases,FuncOpConversion
can't be directly re-used, but we still want to re-use the code to emit c interface forllvm.emit_c_interface
.Changes in this PR
mlir::convertFuncOpToLLVMFuncOp
to be able to re-use it.convertFuncOpToLLVMFuncOp
.FuncOpConversionBase