[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