Skip to content

Commit a449021

Browse files
authored
merge code for llvm.emit_c_interface into convertFuncOpToLLVMFuncOp (#92986)
In today's repo, attribute `llvm.emit_c_interface` of func op is handled outside of `mlir::convertFuncOpToLLVMFuncOp` in `FuncOpConversion` pattern. In some cases, `FuncOpConversion` can't be directly re-used, but we still want to re-use the code to emit c interface for `llvm.emit_c_interface`. Changes in this PR * move the code to generate c with "llvm.emit_c_interface" interface into `mlir::convertFuncOpToLLVMFuncOp` to be able to re-use it. * added unit test to verify c interface for jit can be generated correctly if only call `convertFuncOpToLLVMFuncOp`. * removed `FuncOpConversionBase` --------- Co-authored-by: Fung Xie <[email protected]>
1 parent af31883 commit a449021

File tree

5 files changed

+133
-39
lines changed

5 files changed

+133
-39
lines changed

mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp

Lines changed: 25 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -449,61 +449,47 @@ mlir::convertFuncOpToLLVMFuncOp(FunctionOpInterface funcOp,
449449
"region types conversion failed");
450450
}
451451

452+
if (!shouldUseBarePtrCallConv(funcOp, &converter)) {
453+
if (funcOp->getAttrOfType<UnitAttr>(
454+
LLVM::LLVMDialect::getEmitCWrapperAttrName())) {
455+
if (newFuncOp.isVarArg())
456+
return funcOp.emitError("C interface for variadic functions is not "
457+
"supported yet.");
458+
459+
if (newFuncOp.isExternal())
460+
wrapExternalFunction(rewriter, funcOp->getLoc(), converter, funcOp,
461+
newFuncOp);
462+
else
463+
wrapForExternalCallers(rewriter, funcOp->getLoc(), converter, funcOp,
464+
newFuncOp);
465+
}
466+
} else {
467+
modifyFuncOpToUseBarePtrCallingConv(
468+
rewriter, funcOp->getLoc(), converter, newFuncOp,
469+
llvm::cast<FunctionType>(funcOp.getFunctionType()).getInputs());
470+
}
471+
452472
return newFuncOp;
453473
}
454474

455475
namespace {
456476

457-
struct FuncOpConversionBase : public ConvertOpToLLVMPattern<func::FuncOp> {
458-
protected:
459-
using ConvertOpToLLVMPattern<func::FuncOp>::ConvertOpToLLVMPattern;
460-
461-
// Convert input FuncOp to LLVMFuncOp by using the LLVMTypeConverter provided
462-
// to this legalization pattern.
463-
FailureOr<LLVM::LLVMFuncOp>
464-
convertFuncOpToLLVMFuncOp(func::FuncOp funcOp,
465-
ConversionPatternRewriter &rewriter) const {
466-
return mlir::convertFuncOpToLLVMFuncOp(
467-
cast<FunctionOpInterface>(funcOp.getOperation()), rewriter,
468-
*getTypeConverter());
469-
}
470-
};
471-
472477
/// FuncOp legalization pattern that converts MemRef arguments to pointers to
473478
/// MemRef descriptors (LLVM struct data types) containing all the MemRef type
474479
/// information.
475-
struct FuncOpConversion : public FuncOpConversionBase {
480+
struct FuncOpConversion : public ConvertOpToLLVMPattern<func::FuncOp> {
476481
FuncOpConversion(const LLVMTypeConverter &converter)
477-
: FuncOpConversionBase(converter) {}
482+
: ConvertOpToLLVMPattern(converter) {}
478483

479484
LogicalResult
480485
matchAndRewrite(func::FuncOp funcOp, OpAdaptor adaptor,
481486
ConversionPatternRewriter &rewriter) const override {
482-
FailureOr<LLVM::LLVMFuncOp> newFuncOp =
483-
convertFuncOpToLLVMFuncOp(funcOp, rewriter);
487+
FailureOr<LLVM::LLVMFuncOp> newFuncOp = mlir::convertFuncOpToLLVMFuncOp(
488+
cast<FunctionOpInterface>(funcOp.getOperation()), rewriter,
489+
*getTypeConverter());
484490
if (failed(newFuncOp))
485491
return rewriter.notifyMatchFailure(funcOp, "Could not convert funcop");
486492

487-
if (!shouldUseBarePtrCallConv(funcOp, this->getTypeConverter())) {
488-
if (funcOp->getAttrOfType<UnitAttr>(
489-
LLVM::LLVMDialect::getEmitCWrapperAttrName())) {
490-
if (newFuncOp->isVarArg())
491-
return funcOp->emitError("C interface for variadic functions is not "
492-
"supported yet.");
493-
494-
if (newFuncOp->isExternal())
495-
wrapExternalFunction(rewriter, funcOp->getLoc(), *getTypeConverter(),
496-
funcOp, *newFuncOp);
497-
else
498-
wrapForExternalCallers(rewriter, funcOp->getLoc(),
499-
*getTypeConverter(), funcOp, *newFuncOp);
500-
}
501-
} else {
502-
modifyFuncOpToUseBarePtrCallingConv(rewriter, funcOp->getLoc(),
503-
*getTypeConverter(), *newFuncOp,
504-
funcOp.getFunctionType().getInputs());
505-
}
506-
507493
rewriter.eraseOp(funcOp);
508494
return success();
509495
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: mlir-opt %s -test-convert-func-op | FileCheck %s
2+
3+
// CHECK-LABEL: llvm.func @add
4+
func.func @add(%arg0: i32, %arg1: i32) -> i32 attributes { llvm.emit_c_interface } {
5+
%res = arith.addi %arg0, %arg1 : i32
6+
return %res : i32
7+
}
8+
// CHECK-LABEL: llvm.func @_mlir_ciface_add
9+
// CHECK-SAME: [[ARG0:%[a-zA-Z0-9_]+]]: i32
10+
// CHECK-SAME: [[ARG1:%[a-zA-Z0-9_]+]]: i32
11+
// CHECK-NEXT: [[RES:%.*]] = llvm.call @add([[ARG0]], [[ARG1]])
12+
// CHECK-NEXT: llvm.return [[RES]]

mlir/test/lib/Conversion/FuncToLLVM/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Exclude tests from libMLIR.so
22
add_mlir_library(MLIRTestFuncToLLVM
33
TestConvertCallOp.cpp
4+
TestConvertFuncOp.cpp
45

56
EXCLUDE_FROM_LIBMLIR
67

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//===- TestConvertFuncOp.cpp - Test LLVM Conversion of Func FuncOp --------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "TestDialect.h"
10+
11+
#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
12+
#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
13+
#include "mlir/Conversion/LLVMCommon/Pattern.h"
14+
#include "mlir/Dialect/Func/IR/FuncOps.h"
15+
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
16+
#include "mlir/IR/PatternMatch.h"
17+
#include "mlir/Pass/Pass.h"
18+
19+
using namespace mlir;
20+
21+
namespace {
22+
23+
/// Test helper Conversion Pattern to directly call `convertFuncOpToLLVMFuncOp`
24+
/// to verify this utility function includes all functionalities of conversion
25+
struct FuncOpConversion : public ConvertOpToLLVMPattern<func::FuncOp> {
26+
FuncOpConversion(const LLVMTypeConverter &converter)
27+
: ConvertOpToLLVMPattern(converter) {}
28+
29+
LogicalResult
30+
matchAndRewrite(func::FuncOp funcOp, OpAdaptor adaptor,
31+
ConversionPatternRewriter &rewriter) const override {
32+
FailureOr<LLVM::LLVMFuncOp> newFuncOp = mlir::convertFuncOpToLLVMFuncOp(
33+
cast<FunctionOpInterface>(funcOp.getOperation()), rewriter,
34+
*getTypeConverter());
35+
if (failed(newFuncOp))
36+
return rewriter.notifyMatchFailure(funcOp, "Could not convert funcop");
37+
38+
rewriter.eraseOp(funcOp);
39+
return success();
40+
}
41+
};
42+
43+
struct ReturnOpConversion : public ConvertOpToLLVMPattern<func::ReturnOp> {
44+
ReturnOpConversion(const LLVMTypeConverter &converter)
45+
: ConvertOpToLLVMPattern(converter) {}
46+
47+
LogicalResult
48+
matchAndRewrite(func::ReturnOp returnOp, OpAdaptor adaptor,
49+
ConversionPatternRewriter &rewriter) const override {
50+
rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(returnOp,
51+
returnOp->getOperands());
52+
return success();
53+
}
54+
};
55+
56+
struct TestConvertFuncOp
57+
: public PassWrapper<TestConvertFuncOp, OperationPass<ModuleOp>> {
58+
MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(TestConvertFuncOp)
59+
60+
void getDependentDialects(DialectRegistry &registry) const final {
61+
registry.insert<LLVM::LLVMDialect>();
62+
}
63+
64+
StringRef getArgument() const final { return "test-convert-func-op"; }
65+
66+
StringRef getDescription() const final {
67+
return "Tests conversion of `func.func` to `llvm.func` for different "
68+
"attributes";
69+
}
70+
71+
void runOnOperation() override {
72+
MLIRContext *ctx = &getContext();
73+
74+
LowerToLLVMOptions options(ctx);
75+
// Populate type conversions.
76+
LLVMTypeConverter typeConverter(ctx, options);
77+
78+
RewritePatternSet patterns(ctx);
79+
patterns.add<FuncOpConversion>(typeConverter);
80+
patterns.add<ReturnOpConversion>(typeConverter);
81+
82+
LLVMConversionTarget target(getContext());
83+
if (failed(applyPartialConversion(getOperation(), target,
84+
std::move(patterns))))
85+
signalPassFailure();
86+
}
87+
};
88+
89+
} // namespace
90+
91+
namespace mlir::test {
92+
void registerConvertFuncOpPass() { PassRegistration<TestConvertFuncOp>(); }
93+
} // namespace mlir::test

mlir/tools/mlir-opt/mlir-opt.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ namespace test {
7171
void registerTestCompositePass();
7272
void registerCommutativityUtils();
7373
void registerConvertCallOpPass();
74+
void registerConvertFuncOpPass();
7475
void registerInliner();
7576
void registerMemRefBoundCheck();
7677
void registerPatternsTestPass();
@@ -199,6 +200,7 @@ void registerTestPasses() {
199200
mlir::test::registerTestCompositePass();
200201
mlir::test::registerCommutativityUtils();
201202
mlir::test::registerConvertCallOpPass();
203+
mlir::test::registerConvertFuncOpPass();
202204
mlir::test::registerInliner();
203205
mlir::test::registerMemRefBoundCheck();
204206
mlir::test::registerPatternsTestPass();

0 commit comments

Comments
 (0)