[llvm-branch-commits] [clang] [CIR][CIRGen] Introduce ExtraFuncAttr to FuncOp (PR #186331)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Mar 13 00:50:07 PDT 2026


https://github.com/skc7 updated https://github.com/llvm/llvm-project/pull/186331

>From f137fbd75a779b2f903c4d9d5643f804169c132e Mon Sep 17 00:00:00 2001
From: skc7 <Krishna.Sankisa at amd.com>
Date: Fri, 13 Mar 2026 13:01:05 +0530
Subject: [PATCH] [CIR][CIRGen] Introduce ExtraFuncAttr to FuncOp

---
 .../include/clang/CIR/Dialect/IR/CIRAttrs.td  | 22 +++++++++++++++++++
 clang/include/clang/CIR/Dialect/IR/CIROps.td  |  6 +++++
 clang/include/clang/CIR/MissingFeatures.h     |  1 -
 clang/lib/CIR/CodeGen/CIRGenExpr.cpp          |  3 +++
 clang/lib/CIR/CodeGen/CIRGenFunction.cpp      |  3 +++
 clang/lib/CIR/CodeGen/CIRGenModule.cpp        | 10 ++++-----
 clang/lib/CIR/CodeGen/CIRGenVTables.cpp       |  3 +++
 clang/lib/CIR/Dialect/IR/CIRDialect.cpp       | 21 ++++++++++++++++++
 .../CIR/Dialect/Transforms/EHABILowering.cpp  |  4 ++++
 .../Dialect/Transforms/LoweringPrepare.cpp    |  5 +++--
 .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 14 ++++++++++--
 .../Lowering/DirectToLLVM/LowerToLLVMIR.cpp   | 13 ++++++++++-
 12 files changed, 93 insertions(+), 12 deletions(-)

diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 16d32802d7c2c..a3a1d8c329abc 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -943,6 +943,28 @@ def CIR_VisibilityAttr : CIR_EnumAttr<CIR_VisibilityKind, "visibility"> {
   }];
 }
 
+//===----------------------------------------------------------------------===//
+// ExtraFuncAttr
+//===----------------------------------------------------------------------===//
+
+def CIR_ExtraFuncAttr : CIR_Attr<"ExtraFuncAttributes", "extra"> {
+  let summary = "Represents aggregated attributes for a function";
+  let description = [{
+    This is a wrapper of attribute dictionary that contains extra attributes of
+    a function.
+  }];
+
+  let parameters = (ins "mlir::DictionaryAttr":$elements);
+
+  let builders = [
+    AttrBuilderWithInferredContext<(ins "mlir::DictionaryAttr":$elements), [{
+      return $_get(elements.getContext(), elements);
+    }]>
+  ];
+
+  let assemblyFormat = [{ `(` $elements `)` }];
+}
+
 //===----------------------------------------------------------------------===//
 // GloblCtorAttr
 //===----------------------------------------------------------------------===//
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index d10bed40e75d4..7306a0b8fa3cc 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -3418,6 +3418,11 @@ def CIR_FuncOp : CIR_Op<"func", [
     without a prototype and, consequently, may contain calls with invalid
     arguments and undefined behavior.
 
+    The `extra_attrs`, which is an aggregate of function-specific attributes is
+    required and mandatory to describle additional attributes that are not listed
+    above. Though mandatory, the prining of the attribute can be omitted if it is
+    empty.
+
     The `global_ctor` keyword indicates whether a function should execute before
     `main()` function, as specified by `__attribute__((constructor))`. An
     execution priority can also be specified `global_ctor(<priority>)`.
@@ -3473,6 +3478,7 @@ def CIR_FuncOp : CIR_Op<"func", [
       CIR_GlobalLinkageKind,
       "cir::GlobalLinkageKind::ExternalLinkage"
     >:$linkage,
+    CIR_ExtraFuncAttr:$extra_attrs,
     OptionalAttr<StrAttr>:$sym_visibility,
     UnitAttr:$comdat,
     OptionalAttr<DictArrayAttr>:$arg_attrs,
diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h
index b7b4d73afa0f8..4000446862c53 100644
--- a/clang/include/clang/CIR/MissingFeatures.h
+++ b/clang/include/clang/CIR/MissingFeatures.h
@@ -75,7 +75,6 @@ struct MissingFeatures {
   static bool opFuncColdHotAttr() { return false; }
   static bool opFuncCPUAndFeaturesAttributes() { return false; }
   static bool opFuncExceptions() { return false; }
-  static bool opFuncExtraAttrs() { return false; }
   static bool opFuncMaybeHandleStaticInExternC() { return false; }
   static bool opFuncMinSizeAttr() { return false; }
   static bool opFuncMultipleReturnVals() { return false; }
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 1f08ba773dfb5..186b1e861cf2b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -1975,6 +1975,9 @@ CIRGenCallee CIRGenFunction::emitDirectCallee(const GlobalDecl &gd) {
             &cgm.getMLIRContext(), cir::GlobalLinkageKind::InternalLinkage));
         clone.setSymVisibility("private");
         clone.setInlineKind(cir::InlineKind::AlwaysInline);
+        mlir::NamedAttrList attrs;
+        clone.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get(
+            attrs.getDictionary(&cgm.getMLIRContext())));
       }
       return CIRGenCallee::forDirect(clone, gd);
     }
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
index 71a647e37ea52..81ec4c5205baa 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp
@@ -720,6 +720,9 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn,
       clone.setLinkage(cir::GlobalLinkageKind::InternalLinkage);
       clone.setSymVisibility("private");
       clone.setInlineKind(cir::InlineKind::AlwaysInline);
+      mlir::NamedAttrList attrs;
+      clone.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get(
+          attrs.getDictionary(builder.getContext())));
     }
     fn.setLinkage(cir::GlobalLinkageKind::ExternalLinkage);
     fn.setSymVisibility("private");
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index fd08cdae37881..5514257c052e5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -2356,11 +2356,7 @@ void CIRGenModule::setCIRFunctionAttributes(GlobalDecl globalDecl,
   cir::CallingConv callingConv;
   cir::SideEffect sideEffect;
 
-  // TODO(cir): The current list should be initialized with the extra function
-  // attributes, but we don't have those yet.  For now, the PAL is initialized
-  // with nothing.
-  assert(!cir::MissingFeatures::opFuncExtraAttrs());
-  // Initialize PAL with existing attributes to merge attributes.
+  // TODO(cir): Move all function attributes into extra_attrs.
   mlir::NamedAttrList pal{};
   std::vector<mlir::NamedAttrList> argAttrs(info.arguments().size());
   mlir::NamedAttrList retAttrs{};
@@ -2694,7 +2690,9 @@ CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
     mlir::SymbolTable::setSymbolVisibility(
         func, mlir::SymbolTable::Visibility::Private);
 
-    assert(!cir::MissingFeatures::opFuncExtraAttrs());
+    // Initialize with empty dict of extra attributes.
+    func.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get(
+        &getMLIRContext(), mlir::DictionaryAttr::get(&getMLIRContext())));
 
     // Mark C++ special member functions (Constructor, Destructor etc.)
     setCXXSpecialMemberAttr(func, funcDecl);
diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
index cdc83a3ede3c7..4e94f13f01753 100644
--- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp
@@ -858,6 +858,9 @@ cir::FuncOp CIRGenVTables::maybeEmitThunk(GlobalDecl gd,
     thunkFn =
         cir::FuncOp::create(cgm.getBuilder(), thunk->getLoc(), name.str(),
                             thunkFnTy, cir::GlobalLinkageKind::ExternalLinkage);
+    mlir::NamedAttrList attrs;
+    thunkFn.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get(
+        attrs.getDictionary(cgm.getBuilder().getContext())));
     cgm.setCIRFunctionAttributes(md, fnInfo, thunkFn, /*isThunk=*/false);
 
     if (!oldThunkFn->use_empty())
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index 8d2990af5de8c..e3e67edbc7c3d 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -2153,6 +2153,21 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
     hasAlias = true;
   }
 
+  // If extra func attributes are present, parse them.
+  NamedAttrList extraAttrs;
+  if (::mlir::succeeded(parser.parseOptionalKeyword("extra"))) {
+    if (parser.parseLParen().failed())
+      return failure();
+    if (parser.parseOptionalAttrDict(extraAttrs).failed())
+      return failure();
+    if (parser.parseRParen().failed())
+      return failure();
+  }
+  state.addAttribute(
+      getExtraAttrsAttrName(state.name),
+      cir::ExtraFuncAttributesAttr::get(
+          parser.getContext(), extraAttrs.getDictionary(parser.getContext())));
+
   mlir::StringAttr personalityNameAttr = getPersonalityAttrName(state.name);
   if (parser.parseOptionalKeyword("personality").succeeded()) {
     if (parser.parseLParen().failed())
@@ -2413,6 +2428,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
   function_interface_impl::printFunctionAttributes(
       p, *this, cir::FuncOp::getAttributeNames());
 
+  if (!getExtraAttrs().getElements().empty()) {
+    p << " extra(";
+    p.printOptionalAttrDict(getExtraAttrs().getElements().getValue());
+    p << ')';
+  }
+
   // Print the body if this is not an external function.
   Region &body = getOperation()->getRegion(0);
   if (!body.empty()) {
diff --git a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
index d5d10b1b251be..e0be09d0151f5 100644
--- a/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/EHABILowering.cpp
@@ -25,6 +25,7 @@
 
 #include "PassDetail.h"
 #include "mlir/IR/Builders.h"
+#include "clang/CIR/Dialect/IR/CIRAttrs.h"
 #include "clang/CIR/Dialect/IR/CIRDialect.h"
 #include "clang/CIR/Dialect/IR/CIROpsEnums.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
@@ -61,6 +62,9 @@ static cir::FuncOp getOrCreateRuntimeFuncDecl(mlir::ModuleOp mod,
   auto funcOp = cir::FuncOp::create(builder, loc, name, funcTy);
   funcOp.setLinkage(cir::GlobalLinkageKind::ExternalLinkage);
   funcOp.setPrivate();
+  mlir::NamedAttrList attrs;
+  funcOp.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get(
+      attrs.getDictionary(builder.getContext())));
   return funcOp;
 }
 
diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
index 232d320d71f37..8ad88c3336e89 100644
--- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
+++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp
@@ -334,8 +334,9 @@ cir::FuncOp LoweringPreparePass::buildRuntimeFunction(
         cir::GlobalLinkageKindAttr::get(builder.getContext(), linkage));
     mlir::SymbolTable::setSymbolVisibility(
         f, mlir::SymbolTable::Visibility::Private);
-
-    assert(!cir::MissingFeatures::opFuncExtraAttrs());
+    mlir::NamedAttrList attrs;
+    f.setExtraAttrsAttr(cir::ExtraFuncAttributesAttr::get(
+        attrs.getDictionary(builder.getContext())));
   }
   return f;
 }
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 9c68248d5dede..d6aca6e84bc4a 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1881,7 +1881,6 @@ static void lowerCallAttributes(cir::CIRCallOpInterface op,
         attr.getName() == CIRDialect::getNoReturnAttrName())
       continue;
 
-    assert(!cir::MissingFeatures::opFuncExtraAttrs());
     result.push_back(attr);
   }
 }
@@ -2386,7 +2385,18 @@ void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
           attr.getName() == func.getResAttrsAttrName())))
       continue;
 
-    assert(!cir::MissingFeatures::opFuncExtraAttrs());
+    // Propagate extra function attributes to LLVM via amendOperation. Rename
+    // with "cir." prefix so CIRDialectLLVMIRTranslationInterface picks them up.
+    // Skip empty extra_attrs to avoid leaking CIR dialect attributes into the
+    // LLVM dialect output when there's nothing to translate.
+    if (attr.getName() == func.getExtraAttrsAttrName()) {
+      if (auto extraAttr =
+              mlir::dyn_cast<cir::ExtraFuncAttributesAttr>(attr.getValue());
+          extraAttr && extraAttr.getElements().empty())
+        continue;
+      std::string cirName = "cir." + func.getExtraAttrsAttrName().str();
+      attr.setName(mlir::StringAttr::get(getContext(), cirName));
+    }
     result.push_back(attr);
   }
 }
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp
index 7daeb88ec0900..18125b6a5f213 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVMIR.cpp
@@ -68,7 +68,18 @@ class CIRDialectLLVMIRTranslationInterface
                      llvm::ArrayRef<llvm::Instruction *> instructions,
                      mlir::NamedAttribute attribute,
                      mlir::LLVM::ModuleTranslation &moduleTranslation) const {
-    // TODO(cir): Implement this
+    llvm::Function *llvmFunc = moduleTranslation.lookupFunction(func.getName());
+    llvm::LLVMContext &llvmCtx = moduleTranslation.getLLVMContext();
+    if (auto extraAttr = mlir::dyn_cast<cir::ExtraFuncAttributesAttr>(
+            attribute.getValue())) {
+      for (mlir::NamedAttribute attr : extraAttr.getElements()) {
+        if (auto strAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getValue())) {
+          llvmFunc->addFnAttr(attr.getName().str(), strAttr.getValue().str());
+        }
+      }
+    }
+    // Drop ammended CIR attribute from LLVM op.
+    func->removeAttr(attribute.getName());
   }
 
   // Translate CIR's module attributes to LLVM's module metadata



More information about the llvm-branch-commits mailing list