[Mlir-commits] [mlir] 5cc6df5 - [mlir][FuncToLLVM][NFC] Refactor convertFuncOpToLLVMFuncOp into helpers (#192218)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Apr 15 05:40:30 PDT 2026
Author: zackc6
Date: 2026-04-15T14:40:25+02:00
New Revision: 5cc6df520eef0ca9ab329a2eb6f14cf0c3717b22
URL: https://github.com/llvm/llvm-project/commit/5cc6df520eef0ca9ab329a2eb6f14cf0c3717b22
DIFF: https://github.com/llvm/llvm-project/commit/5cc6df520eef0ca9ab329a2eb6f14cf0c3717b22.diff
LOG: [mlir][FuncToLLVM][NFC] Refactor convertFuncOpToLLVMFuncOp into helpers (#192218)
Split convertFuncOpToLLVMFuncOp into focused helper functions for
signature conversion, llvm.func creation, attribute propagation, and
C-wrapper handling.
This reduces nesting and improves readability while preserving existing
lowering behavior.
Added:
Modified:
mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
Removed:
################################################################################
diff --git a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
index 88abc4400c9b7..05f4ceced3e86 100644
--- a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
+++ b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
@@ -352,54 +352,34 @@ static void restoreByValRefArgumentType(
}
}
-/// TODO: Refactor this function to be more modular and easier to understand.
-FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
- FunctionOpInterface funcOp, ConversionPatternRewriter &rewriter,
- const LLVMTypeConverter &converter, SymbolTableCollection *symbolTables) {
- // Check the funcOp has `FunctionType`.
- auto funcTy = dyn_cast<FunctionType>(funcOp.getFunctionType());
- if (!funcTy)
- return rewriter.notifyMatchFailure(
- funcOp, "Only support FunctionOpInterface with FunctionType");
-
- // Convert the original function arguments. They are converted using the
- // LLVMTypeConverter provided to this legalization pattern.
+static FailureOr<LLVM::LLVMFunctionType> convertFuncSignature(
+ FunctionOpInterface funcOp, const LLVMTypeConverter &converter,
+ bool useBarePtrCallConv, TypeConverter::SignatureConversion &result,
+ SmallVectorImpl<std::optional<NamedAttribute>> &byValRefNonPtrAttrs) {
auto varargsAttr = funcOp->getAttrOfType<BoolAttr>(varargsAttrName);
- // Gather `llvm.byval` and `llvm.byref` arguments whose type convertion was
- // overriden with an LLVM pointer type for later processing.
- SmallVector<std::optional<NamedAttribute>> byValRefNonPtrAttrs;
- TypeConverter::SignatureConversion result(funcOp.getNumArguments());
auto llvmType = dyn_cast_or_null<LLVM::LLVMFunctionType>(
converter.convertFunctionSignature(
- funcOp, varargsAttr && varargsAttr.getValue(),
- shouldUseBarePtrCallConv(funcOp, &converter), result,
- byValRefNonPtrAttrs));
+ funcOp, varargsAttr && varargsAttr.getValue(), useBarePtrCallConv,
+ result, byValRefNonPtrAttrs));
if (!llvmType)
- return rewriter.notifyMatchFailure(funcOp, "signature conversion failed");
-
- // Check for unsupported variadic functions.
- if (!shouldUseBarePtrCallConv(funcOp, &converter))
- if (funcOp->getAttrOfType<UnitAttr>(
- LLVM::LLVMDialect::getEmitCWrapperAttrName()))
- if (llvmType.isVarArg())
- return funcOp.emitError("C interface for variadic functions is not "
- "supported yet.");
-
- FailureOr<LoweredFuncAttrs> loweredAttrs = lowerFuncAttributes(funcOp);
- if (failed(loweredAttrs))
- return rewriter.notifyMatchFailure(funcOp,
- "failed to lower func attributes");
+ return failure();
+ return llvmType;
+}
+static LLVM::LLVMFuncOp createLLVMFuncOp(FunctionOpInterface funcOp,
+ ConversionPatternRewriter &rewriter,
+ LLVM::LLVMFunctionType llvmType,
+ LoweredFuncAttrs &loweredAttrs,
+ SymbolTableCollection *symbolTables) {
Operation *symbolTableOp = funcOp->getParentWithTrait<OpTrait::SymbolTable>();
-
if (symbolTables && symbolTableOp) {
SymbolTable &symbolTable = symbolTables->getSymbolTable(symbolTableOp);
symbolTable.remove(funcOp);
}
- buildLLVMFuncProperties(rewriter, funcOp, llvmType, loweredAttrs->properties);
+ buildLLVMFuncProperties(rewriter, funcOp, llvmType, loweredAttrs.properties);
auto newFuncOp = LLVM::LLVMFuncOp::create(rewriter, funcOp.getLoc(),
- loweredAttrs->properties,
- loweredAttrs->discardableAttrs);
+ loweredAttrs.properties,
+ loweredAttrs.discardableAttrs);
if (symbolTables && symbolTableOp) {
auto ip = rewriter.getInsertionPoint();
@@ -410,9 +390,8 @@ FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
cast<FunctionOpInterface>(newFuncOp.getOperation())
.setVisibility(funcOp.getVisibility());
- // Create a memory effect attribute corresponding to readnone.
- StringRef readnoneAttrName = LLVM::LLVMDialect::getReadnoneAttrName();
- if (funcOp->hasAttr(readnoneAttrName)) {
+ // Set readnone memory effects
+ if (funcOp->hasAttr(LLVM::LLVMDialect::getReadnoneAttrName())) {
auto memoryAttr = LLVM::MemoryEffectsAttr::get(
rewriter.getContext(), {/*other=*/LLVM::ModRefInfo::NoModRef,
/*argMem=*/LLVM::ModRefInfo::NoModRef,
@@ -423,6 +402,46 @@ FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
newFuncOp.setMemoryEffectsAttr(memoryAttr);
}
+ return newFuncOp;
+}
+
+static SmallVector<NamedAttribute>
+convertArgumentAttributes(DictionaryAttr attrsDict,
+ ConversionPatternRewriter &rewriter,
+ const LLVMTypeConverter &converter) {
+ SmallVector<NamedAttribute, 4> convertedAttrs;
+ convertedAttrs.reserve(attrsDict.size());
+ for (const NamedAttribute &attr : attrsDict) {
+ const auto convert = [&](const NamedAttribute &attr) {
+ return TypeAttr::get(
+ converter.convertType(cast<TypeAttr>(attr.getValue()).getValue()));
+ };
+ if (attr.getName().getValue() == LLVM::LLVMDialect::getByValAttrName()) {
+ convertedAttrs.push_back(rewriter.getNamedAttr(
+ LLVM::LLVMDialect::getByValAttrName(), convert(attr)));
+ } else if (attr.getName().getValue() ==
+ LLVM::LLVMDialect::getByRefAttrName()) {
+ convertedAttrs.push_back(rewriter.getNamedAttr(
+ LLVM::LLVMDialect::getByRefAttrName(), convert(attr)));
+ } else if (attr.getName().getValue() ==
+ LLVM::LLVMDialect::getStructRetAttrName()) {
+ convertedAttrs.push_back(rewriter.getNamedAttr(
+ LLVM::LLVMDialect::getStructRetAttrName(), convert(attr)));
+ } else if (attr.getName().getValue() ==
+ LLVM::LLVMDialect::getInAllocaAttrName()) {
+ convertedAttrs.push_back(rewriter.getNamedAttr(
+ LLVM::LLVMDialect::getInAllocaAttrName(), convert(attr)));
+ } else {
+ convertedAttrs.push_back(attr);
+ }
+ }
+ return convertedAttrs;
+}
+
+static void propagateFunctionArgResAttrs(
+ FunctionOpInterface funcOp, ConversionPatternRewriter &rewriter,
+ const LLVMTypeConverter &converter, TypeConverter::SignatureConversion &sig,
+ LLVM::LLVMFunctionType llvmType, LLVM::LLVMFuncOp newFuncOp) {
// Propagate argument/result attributes to all converted arguments/result
// obtained after converting a given original argument/result.
if (ArrayAttr resAttrDicts = funcOp.getAllResultAttrs()) {
@@ -431,41 +450,15 @@ FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
newFuncOp.setAllResultAttrs(resAttrDicts);
}
if (ArrayAttr argAttrDicts = funcOp.getAllArgAttrs()) {
- SmallVector<Attribute> newArgAttrs(
- cast<LLVM::LLVMFunctionType>(llvmType).getNumParams());
+ SmallVector<Attribute> newArgAttrs(llvmType.getNumParams());
for (unsigned i = 0, e = funcOp.getNumArguments(); i < e; ++i) {
// Some LLVM IR attribute have a type attached to them. During FuncOp ->
// LLVMFuncOp conversion these types may have changed. Account for that
// change by converting attributes' types as well.
- SmallVector<NamedAttribute, 4> convertedAttrs;
auto attrsDict = cast<DictionaryAttr>(argAttrDicts[i]);
- convertedAttrs.reserve(attrsDict.size());
- for (const NamedAttribute &attr : attrsDict) {
- const auto convert = [&](const NamedAttribute &attr) {
- return TypeAttr::get(converter.convertType(
- cast<TypeAttr>(attr.getValue()).getValue()));
- };
- if (attr.getName().getValue() ==
- LLVM::LLVMDialect::getByValAttrName()) {
- convertedAttrs.push_back(rewriter.getNamedAttr(
- LLVM::LLVMDialect::getByValAttrName(), convert(attr)));
- } else if (attr.getName().getValue() ==
- LLVM::LLVMDialect::getByRefAttrName()) {
- convertedAttrs.push_back(rewriter.getNamedAttr(
- LLVM::LLVMDialect::getByRefAttrName(), convert(attr)));
- } else if (attr.getName().getValue() ==
- LLVM::LLVMDialect::getStructRetAttrName()) {
- convertedAttrs.push_back(rewriter.getNamedAttr(
- LLVM::LLVMDialect::getStructRetAttrName(), convert(attr)));
- } else if (attr.getName().getValue() ==
- LLVM::LLVMDialect::getInAllocaAttrName()) {
- convertedAttrs.push_back(rewriter.getNamedAttr(
- LLVM::LLVMDialect::getInAllocaAttrName(), convert(attr)));
- } else {
- convertedAttrs.push_back(attr);
- }
- }
- auto mapping = result.getInputMapping(i);
+ SmallVector<NamedAttribute, 4> convertedAttrs =
+ convertArgumentAttributes(attrsDict, rewriter, converter);
+ auto mapping = sig.getInputMapping(i);
assert(mapping && "unexpected deletion of function argument");
// Only attach the new argument attributes if there is a one-to-one
// mapping from old to new types. Otherwise, attributes might be
@@ -484,7 +477,75 @@ FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
if (!newArgAttrs.empty())
newFuncOp.setAllArgAttrs(rewriter.getArrayAttr(newArgAttrs));
}
+}
+
+static void wrapWithCInterface(FunctionOpInterface funcOp,
+ ConversionPatternRewriter &rewriter,
+ const LLVMTypeConverter &converter,
+ LLVM::LLVMFuncOp newFuncOp) {
+ if (newFuncOp.isExternal())
+ wrapExternalFunction(rewriter, funcOp->getLoc(), converter, funcOp,
+ newFuncOp);
+ else
+ wrapForExternalCallers(rewriter, funcOp->getLoc(), converter, funcOp,
+ newFuncOp);
+}
+
+// Conversion steps
+// 1. Validate function type
+// 2. Convert signature
+// 3. Validate C wrapper varargs constraint
+// 4. Lower function attrs
+// 5. Create llvm.func
+// 6. Propagate arg/result attrs
+// 7. Inline body + signature conversion
+// 8. Restore byval/byref pointee types
+// 9. C-wrapper handling
+FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
+ FunctionOpInterface funcOp, ConversionPatternRewriter &rewriter,
+ const LLVMTypeConverter &converter, SymbolTableCollection *symbolTables) {
+ // 1. Validate function type
+ // Check the funcOp has `FunctionType`.
+ auto funcTy = dyn_cast<FunctionType>(funcOp.getFunctionType());
+ if (!funcTy)
+ return rewriter.notifyMatchFailure(
+ funcOp, "Only support FunctionOpInterface with FunctionType");
+
+ // 2. Convert signature
+ bool useBarePtrCallConv = shouldUseBarePtrCallConv(funcOp, &converter);
+ // Convert the original function arguments. They are converted using the
+ // LLVMTypeConverter provided to this legalization pattern.
+ // Gather `llvm.byval` and `llvm.byref` arguments whose type convertion was
+ // overriden with an LLVM pointer type for later processing.
+ SmallVector<std::optional<NamedAttribute>> byValRefNonPtrAttrs;
+ TypeConverter::SignatureConversion result(funcOp.getNumArguments());
+ FailureOr<LLVM::LLVMFunctionType> llvmType = convertFuncSignature(
+ funcOp, converter, useBarePtrCallConv, result, byValRefNonPtrAttrs);
+ if (failed(llvmType))
+ return rewriter.notifyMatchFailure(funcOp, "signature conversion failed");
+ // 3. Validate C wrapper varargs constraint
+ bool emitCWrapper = funcOp->hasAttrOfType<UnitAttr>(
+ LLVM::LLVMDialect::getEmitCWrapperAttrName());
+ if (!useBarePtrCallConv && emitCWrapper && llvmType->isVarArg())
+ return funcOp.emitError("C interface for variadic functions is not "
+ "supported yet.");
+
+ // 4. Lower function attrs
+ FailureOr<LoweredFuncAttrs> loweredAttrs = lowerFuncAttributes(funcOp);
+ if (failed(loweredAttrs))
+ return rewriter.notifyMatchFailure(funcOp,
+ "failed to lower func attributes");
+
+ // 5. Create llvm.func
+ auto newFuncOp = createLLVMFuncOp(funcOp, rewriter, *llvmType, *loweredAttrs,
+ symbolTables);
+
+ // 6. Propagate arg/result attrs
+ propagateFunctionArgResAttrs(funcOp, rewriter, converter, result, *llvmType,
+ newFuncOp);
+
+ // 7. Inline body + signature conversion
rewriter.inlineRegionBefore(funcOp.getFunctionBody(), newFuncOp.getBody(),
newFuncOp.end());
// Convert just the entry block. The remaining unstructured control flow is
@@ -493,23 +554,16 @@ FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
rewriter.applySignatureConversion(&newFuncOp.getBody().front(), result,
&converter);
+ // 8. Restore byval/byref pointee types
// Fix the type mismatch between the materialized `llvm.ptr` and the expected
// pointee type in the function body when converting `llvm.byval`/`llvm.byref`
// function arguments.
restoreByValRefArgumentType(rewriter, converter, byValRefNonPtrAttrs,
newFuncOp);
- if (!shouldUseBarePtrCallConv(funcOp, &converter)) {
- if (funcOp->getAttrOfType<UnitAttr>(
- LLVM::LLVMDialect::getEmitCWrapperAttrName())) {
- if (newFuncOp.isExternal())
- wrapExternalFunction(rewriter, funcOp->getLoc(), converter, funcOp,
- newFuncOp);
- else
- wrapForExternalCallers(rewriter, funcOp->getLoc(), converter, funcOp,
- newFuncOp);
- }
- }
+ // 9. C-wrapper handling
+ if (!useBarePtrCallConv && emitCWrapper)
+ wrapWithCInterface(funcOp, rewriter, converter, newFuncOp);
return newFuncOp;
}
More information about the Mlir-commits
mailing list