Skip to content

Conversation

@xlauko
Copy link
Contributor

@xlauko xlauko commented Nov 30, 2025

Switches to more efficient explicit enum property instead of a wrapped storage, simplifying the string representation. The attribute is now placed before the symbol name for consistency with other FuncOp attributes. FileCheck patterns are also simplified to match only the attributes under test.

Switches to more efficient explicit enum property instead of a wrapped storage, simplifying the string representation. The attribute is now placed before the symbol name for consistency with other FuncOp attributes. FileCheck patterns are also simplified to match only the attributes under test.
@xlauko
Copy link
Contributor Author

xlauko commented Nov 30, 2025

This stack of pull requests is managed by Graphite. Learn more about stacking.

@xlauko xlauko marked this pull request as ready for review November 30, 2025 20:11
@llvmbot llvmbot added clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project labels Nov 30, 2025
@llvmbot
Copy link
Member

llvmbot commented Nov 30, 2025

@llvm/pr-subscribers-clang

Author: Henrich Lauko (xlauko)

Changes

Switches to more efficient explicit enum property instead of a wrapped storage, simplifying the string representation. The attribute is now placed before the symbol name for consistency with other FuncOp attributes. FileCheck patterns are also simplified to match only the attributes under test.


Patch is 100.72 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170050.diff

48 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+4-38)
  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+27-23)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+1-2)
  • (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+6-13)
  • (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+46-34)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c (+7-7)
  • (modified) clang/test/CIR/CodeGen/address-space-conversion.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/address-space.c (+3-3)
  • (modified) clang/test/CIR/CodeGen/array-ctor.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/asm-label-inline-builtins.c (+1-1)
  • (modified) clang/test/CIR/CodeGen/assign-operator.cpp (+2-2)
  • (modified) clang/test/CIR/CodeGen/bitfield-union.c (+1-1)
  • (modified) clang/test/CIR/CodeGen/bitfields.c (+3-3)
  • (modified) clang/test/CIR/CodeGen/bitfields.cpp (+3-3)
  • (modified) clang/test/CIR/CodeGen/bitfields_be.c (+2-2)
  • (modified) clang/test/CIR/CodeGen/constant-inits.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/copy-constructor.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/coro-task.cpp (+2-2)
  • (modified) clang/test/CIR/CodeGen/cxx-conversion-operators.cpp (+5-5)
  • (modified) clang/test/CIR/CodeGen/delete.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/destructors.cpp (+3-3)
  • (modified) clang/test/CIR/CodeGen/dtors.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/dynamic-cast.cpp (+6-6)
  • (modified) clang/test/CIR/CodeGen/global-ctor-dtor.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/goto.cpp (+8-8)
  • (modified) clang/test/CIR/CodeGen/inline-attributes.cpp (+6-6)
  • (modified) clang/test/CIR/CodeGen/label-values.c (+4-4)
  • (modified) clang/test/CIR/CodeGen/label.c (+7-7)
  • (modified) clang/test/CIR/CodeGen/lambda-static-invoker.cpp (+3-3)
  • (modified) clang/test/CIR/CodeGen/lambda.cpp (+14-14)
  • (modified) clang/test/CIR/CodeGen/linkage-spec.cpp (+14-14)
  • (modified) clang/test/CIR/CodeGen/no-prototype.c (+8-8)
  • (modified) clang/test/CIR/CodeGen/placement-new.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/ptrdiff.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/statement-exprs.c (+8-8)
  • (modified) clang/test/CIR/CodeGen/stmt-expr.cpp (+2-2)
  • (modified) clang/test/CIR/CodeGen/var_arg.c (+2-2)
  • (modified) clang/test/CIR/CodeGen/variable-decomposition.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/vbase.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/volatile.cpp (+10-10)
  • (modified) clang/test/CIR/CodeGen/vtable-emission.cpp (+2-2)
  • (modified) clang/test/CIR/CodeGenBuiltins/builtin-fcmp-sse.c (+8-8)
  • (modified) clang/test/CIR/CodeGenBuiltins/builtin_inline.c (+1-1)
  • (modified) clang/test/CIR/CodeGenBuiltins/builtin_prefetch.c (+1-1)
  • (modified) clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp (+30-30)
  • (modified) clang/test/CIR/IR/inline-attrs.cir (+22-15)
  • (modified) clang/test/CIR/func-linkage.cpp (+4-4)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 12bc9cf7b5b04..98d4636dafc29 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1085,44 +1085,10 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> {
 //===----------------------------------------------------------------------===//
 
 def CIR_InlineKind : CIR_I32EnumAttr<"InlineKind", "inlineKind", [
-  I32EnumAttrCase<"NoInline", 1, "never">,
-  I32EnumAttrCase<"AlwaysInline", 2, "always">,
-  I32EnumAttrCase<"InlineHint", 3, "hint">
-]> {
-  let genSpecializedAttr = 0;
-}
-
-def CIR_InlineAttr : CIR_EnumAttr<CIR_InlineKind, "inline"> {
-  let summary = "Inline attribute";
-  let description = [{
-    Inline attribute represents user directives for inlining behavior.
-    This attribute is only used by `cir.func` operations.
-
-    Values:
-    - `never`: Prevents the function from being inlined (__attribute__((noinline)))
-    - `always`: Forces the function to be inlined (__attribute__((always_inline)))
-    - `hint`: Suggests the function should be inlined (inline keyword)
-
-    Example:
-    ```
-    cir.func @noinline_func(%arg0: !s32i) -> !s32i inline(never) {
-      cir.return %arg0 : !s32i
-    }
-    cir.func @always_inline_func() -> !s32i inline(always) {
-      %0 = cir.const #cir.int<42> : !s32i
-      cir.return %0 : !s32i
-    }
-    ```
-  }];
-
-  let cppClassName = "InlineAttr";
-
-  let extraClassDeclaration = [{
-    bool isNoInline() const { return getValue() == InlineKind::NoInline; };
-    bool isAlwaysInline() const { return getValue() == InlineKind::AlwaysInline; };
-    bool isInlineHint() const { return getValue() == InlineKind::InlineHint; };
-  }];
-}
+  I32EnumAttrCase<"NoInline", 1, "no_inline">,
+  I32EnumAttrCase<"AlwaysInline", 2, "always_inline">,
+  I32EnumAttrCase<"InlineHint", 3, "inline_hint">
+]>;
 
 //===----------------------------------------------------------------------===//
 // CatchAllAttr & UnwindAttr
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 5f5fab6f12300..11422d31df0ad 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2564,9 +2564,9 @@ def CIR_FuncOp : CIR_Op<"func", [
     Similarly, for global destructors both `global_dtor` and
     `global_dtor(<priority>)` are available.
 
-    The `inline(never)` keyword marks a function that should not be inlined.
-    The `inline(always)` keyword marks a function that should always be inlined.
-    The `inline(hint)` keyword suggests that the function should be inlined.
+    The `no_inline` attribute marks a function that should not be inlined.
+    The `always_inline` attribute marks a function that should always be inlined.
+    The `inline_hint` attribute suggests that the function should be inlined.
 
     Example:
 
@@ -2580,7 +2580,10 @@ def CIR_FuncOp : CIR_Op<"func", [
 
     // Linkage information
     cir.func linkonce_odr @some_method(...)
-    ```
+
+    // Inline information
+    cir.func no_inline @some_method(...)
+    
     // Builtin function
     cir.func builtin @__builtin_coro_end(!cir.ptr<i8>, !cir.bool) -> !cir.bool
     // Coroutine
@@ -2592,25 +2595,26 @@ def CIR_FuncOp : CIR_Op<"func", [
     ```
   }];
 
-  let arguments = (ins SymbolNameAttr:$sym_name,
-                       CIR_VisibilityAttr:$global_visibility,
-                       TypeAttrOf<CIR_FuncType>:$function_type,
-                       UnitAttr:$builtin,
-                       UnitAttr:$coroutine,
-                       UnitAttr:$lambda,
-                       UnitAttr:$no_proto,
-                       UnitAttr:$dso_local,
-                       DefaultValuedAttr<CIR_GlobalLinkageKind,
-                                         "cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
-                       OptionalAttr<CIR_InlineAttr>:$inline_kind,
-                       OptionalAttr<StrAttr>:$sym_visibility,
-                       UnitAttr:$comdat,
-                       OptionalAttr<DictArrayAttr>:$arg_attrs,
-                       OptionalAttr<DictArrayAttr>:$res_attrs,
-                       OptionalAttr<FlatSymbolRefAttr>:$aliasee,
-                       CIR_OptionalPriorityAttr:$global_ctor_priority,
-                       CIR_OptionalPriorityAttr:$global_dtor_priority,
-                       OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member
+  let arguments = (ins 
+    SymbolNameAttr:$sym_name,
+    CIR_VisibilityAttr:$global_visibility,
+    TypeAttrOf<CIR_FuncType>:$function_type,
+    UnitAttr:$builtin,
+    UnitAttr:$coroutine,
+    OptionalAttr<CIR_InlineKind>:$inline_kind,
+    UnitAttr:$lambda,
+    UnitAttr:$no_proto,
+    UnitAttr:$dso_local,
+    DefaultValuedAttr<CIR_GlobalLinkageKind,
+                      "cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
+    OptionalAttr<StrAttr>:$sym_visibility,
+    UnitAttr:$comdat,
+    OptionalAttr<DictArrayAttr>:$arg_attrs,
+    OptionalAttr<DictArrayAttr>:$res_attrs,
+    OptionalAttr<FlatSymbolRefAttr>:$aliasee,
+    CIR_OptionalPriorityAttr:$global_ctor_priority,
+    CIR_OptionalPriorityAttr:$global_dtor_priority,
+    OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member
    );
 
   let regions = (region AnyRegion:$body);
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 4065124f8f568..1c2b83e6094f3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -1870,8 +1870,7 @@ CIRGenCallee CIRGenFunction::emitDirectCallee(const GlobalDecl &gd) {
         clone.setLinkageAttr(cir::GlobalLinkageKindAttr::get(
             &cgm.getMLIRContext(), cir::GlobalLinkageKind::InternalLinkage));
         clone.setSymVisibility("private");
-        clone.setInlineKindAttr(cir::InlineAttr::get(
-            &cgm.getMLIRContext(), cir::InlineKind::AlwaysInline));
+        clone.setInlineKind(cir::InlineKind::AlwaysInline);
       }
       return CIRGenCallee::forDirect(clone, gd);
     }
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 809c24f8aa670..03bbfbffce717 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1975,7 +1975,6 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
       existingInlineKind && *existingInlineKind == cir::InlineKind::NoInline;
   bool isAlwaysInline = existingInlineKind &&
                         *existingInlineKind == cir::InlineKind::AlwaysInline;
-
   if (!decl) {
     assert(!cir::MissingFeatures::hlsl());
 
@@ -1984,8 +1983,7 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
       // If inlining is disabled and we don't have a declaration to control
       // inlining, mark the function as 'noinline' unless it is explicitly
       // marked as 'alwaysinline'.
-      f.setInlineKindAttr(
-          cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
+      f.setInlineKind(cir::InlineKind::NoInline);
     }
 
     return;
@@ -2002,19 +2000,16 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
   // Handle inline attributes
   if (decl->hasAttr<NoInlineAttr>() && !isAlwaysInline) {
     // Add noinline if the function isn't always_inline.
-    f.setInlineKindAttr(
-        cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
+    f.setInlineKind(cir::InlineKind::NoInline);
   } else if (decl->hasAttr<AlwaysInlineAttr>() && !isNoInline) {
     // Don't override AlwaysInline with NoInline, or vice versa, since we can't
     // specify both in IR.
-    f.setInlineKindAttr(
-        cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline));
+    f.setInlineKind(cir::InlineKind::AlwaysInline);
   } else if (codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {
     // If inlining is disabled, force everything that isn't always_inline
     // to carry an explicit noinline attribute.
     if (!isAlwaysInline) {
-      f.setInlineKindAttr(
-          cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
+      f.setInlineKind(cir::InlineKind::NoInline);
     }
   } else {
     // Otherwise, propagate the inline hint attribute and potentially use its
@@ -2036,13 +2031,11 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
         return any_of(pattern->redecls(), checkRedeclForInline);
       };
       if (checkForInline(fd)) {
-        f.setInlineKindAttr(cir::InlineAttr::get(&getMLIRContext(),
-                                                 cir::InlineKind::InlineHint));
+        f.setInlineKind(cir::InlineKind::InlineHint);
       } else if (codeGenOpts.getInlining() ==
                      CodeGenOptions::OnlyHintInlining &&
                  !fd->isInlined() && !isAlwaysInline) {
-        f.setInlineKindAttr(
-            cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
+        f.setInlineKind(cir::InlineKind::NoInline);
       }
     }
   }
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index d505ca141d383..7479dc0ef1554 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -220,6 +220,41 @@ void parseVisibilityAttr(OpAsmParser &parser, cir::VisibilityAttr &visibility) {
   visibility = cir::VisibilityAttr::get(parser.getContext(), visibilityKind);
 }
 
+//===----------------------------------------------------------------------===//
+// InlineKindAttr (FIXME: remove once FuncOp uses assembly format)
+//===----------------------------------------------------------------------===//
+
+ParseResult parseInlineKindAttr(OpAsmParser &parser,
+                                cir::InlineKindAttr &inlineKindAttr) {
+  // Static list of possible inline kind keywords
+  static constexpr llvm::StringRef keywords[] = {"no_inline", "always_inline",
+                                                 "inline_hint"};
+
+  // Parse the inline kind keyword (optional)
+  llvm::StringRef keyword;
+  if (parser.parseOptionalKeyword(&keyword, keywords).failed()) {
+    // Not an inline kind keyword, leave inlineKindAttr empty
+    return success();
+  }
+
+  // Parse the enum value from the keyword
+  auto inlineKindResult = ::cir::symbolizeEnum<::cir::InlineKind>(keyword);
+  if (!inlineKindResult) {
+    return parser.emitError(parser.getCurrentLocation(), "expected one of [")
+           << llvm::join(llvm::ArrayRef(keywords), ", ")
+           << "] for inlineKind, got: " << keyword;
+  }
+
+  inlineKindAttr =
+      ::cir::InlineKindAttr::get(parser.getContext(), *inlineKindResult);
+  return success();
+}
+
+void printInlineKindAttr(OpAsmPrinter &p, cir::InlineKindAttr inlineKindAttr) {
+  if (inlineKindAttr) {
+    p << " " << stringifyInlineKind(inlineKindAttr.getValue());
+  }
+}
 //===----------------------------------------------------------------------===//
 // CIR Custom Parsers/Printers
 //===----------------------------------------------------------------------===//
@@ -1753,6 +1788,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
 
   mlir::StringAttr builtinNameAttr = getBuiltinAttrName(state.name);
   mlir::StringAttr coroutineNameAttr = getCoroutineAttrName(state.name);
+  mlir::StringAttr inlineKindNameAttr = getInlineKindAttrName(state.name);
   mlir::StringAttr lambdaNameAttr = getLambdaAttrName(state.name);
   mlir::StringAttr noProtoNameAttr = getNoProtoAttrName(state.name);
   mlir::StringAttr visNameAttr = getSymVisibilityAttrName(state.name);
@@ -1765,6 +1801,14 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
   if (::mlir::succeeded(
           parser.parseOptionalKeyword(coroutineNameAttr.strref())))
     state.addAttribute(coroutineNameAttr, parser.getBuilder().getUnitAttr());
+
+  // Parse optional inline kind attribute
+  cir::InlineKindAttr inlineKindAttr;
+  if (failed(parseInlineKindAttr(parser, inlineKindAttr)))
+    return failure();
+  if (inlineKindAttr)
+    state.addAttribute(inlineKindNameAttr, inlineKindAttr);
+
   if (::mlir::succeeded(parser.parseOptionalKeyword(lambdaNameAttr.strref())))
     state.addAttribute(lambdaNameAttr, parser.getBuilder().getUnitAttr());
   if (parser.parseOptionalKeyword(noProtoNameAttr).succeeded())
@@ -1890,36 +1934,6 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
       }).failed())
     return failure();
 
-  // Parse optional inline kind: inline(never|always|hint)
-  if (parser.parseOptionalKeyword("inline").succeeded()) {
-    if (parser.parseLParen().failed())
-      return failure();
-
-    llvm::StringRef inlineKindStr;
-    const std::array<llvm::StringRef, cir::getMaxEnumValForInlineKind()>
-        allowedInlineKindStrs{
-            cir::stringifyInlineKind(cir::InlineKind::NoInline),
-            cir::stringifyInlineKind(cir::InlineKind::AlwaysInline),
-            cir::stringifyInlineKind(cir::InlineKind::InlineHint),
-        };
-    if (parser.parseOptionalKeyword(&inlineKindStr, allowedInlineKindStrs)
-            .failed())
-      return parser.emitError(parser.getCurrentLocation(),
-                              "expected 'never', 'always', or 'hint'");
-
-    std::optional<InlineKind> inlineKind =
-        cir::symbolizeInlineKind(inlineKindStr);
-    if (!inlineKind)
-      return parser.emitError(parser.getCurrentLocation(),
-                              "invalid inline kind");
-
-    state.addAttribute(getInlineKindAttrName(state.name),
-                       cir::InlineAttr::get(builder.getContext(), *inlineKind));
-
-    if (parser.parseRParen().failed())
-      return failure();
-  }
-
   // Parse the optional function body.
   auto *body = state.addRegion();
   OptionalParseResult parseResult = parser.parseOptionalRegion(
@@ -2014,6 +2028,8 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
   if (getCoroutine())
     p << " coroutine";
 
+  printInlineKindAttr(p, getInlineKindAttr());
+
   if (getLambda())
     p << " lambda";
 
@@ -2069,10 +2085,6 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
       p << "(" << globalDtorPriority.value() << ")";
   }
 
-  if (cir::InlineAttr inlineAttr = getInlineKindAttr()) {
-    p << " inline(" << cir::stringifyInlineKind(inlineAttr.getValue()) << ")";
-  }
-
   // Print the body if this is not an external function.
   Region &body = getOperation()->getRegion(0);
   if (!body.empty()) {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 0c34d87734c3e..c572eb820b385 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1978,10 +1978,10 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
 
   assert(!cir::MissingFeatures::opFuncMultipleReturnVals());
 
-  if (auto inlineKind = op.getInlineKind()) {
-    fn.setNoInline(inlineKind == cir::InlineKind::NoInline);
-    fn.setInlineHint(inlineKind == cir::InlineKind::InlineHint);
-    fn.setAlwaysInline(inlineKind == cir::InlineKind::AlwaysInline);
+  if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) {
+    fn.setNoInline(*inlineKind == cir::InlineKind::NoInline);
+    fn.setInlineHint(*inlineKind == cir::InlineKind::InlineHint);
+    fn.setAlwaysInline(*inlineKind == cir::InlineKind::AlwaysInline);
   }
 
   fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(
diff --git a/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c b/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
index 19362cf79b107..66891f9e1ad78 100644
--- a/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
+++ b/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
@@ -82,7 +82,7 @@ int check_load(st1 *s1) {
   return s1->b;
 }
 
-// CIR:  cir.func dso_local @check_load
+// CIR:  cir.func {{.*}} @check_load
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st1>>, !cir.ptr<!rec_st1>
 // CIR:    [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "b"} : !cir.ptr<!rec_st1> -> !cir.ptr<!u16i>
 // CIR:    [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_b, [[MEMBER]] {is_volatile} : !cir.ptr<!u16i>) -> !u32i
@@ -114,7 +114,7 @@ int check_load_exception(st3 *s3) {
   return s3->b;
 }
 
-// CIR:  cir.func dso_local @check_load_exception
+// CIR:  cir.func {{.*}} @check_load_exception
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st3>>, !cir.ptr<!rec_st3>
 // CIR:    [[MEMBER:%.*]] = cir.get_member [[LOAD]][2] {name = "b"} : !cir.ptr<!rec_st3> -> !cir.ptr<!u8i>
 // CIR:    [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_b1, [[MEMBER]] {is_volatile} : !cir.ptr<!u8i>) -> !u32i
@@ -151,7 +151,7 @@ int clip_load_exception2(clip *c) {
   return c->a;
 }
 
-// CIR:  cir.func dso_local @clip_load_exception2
+// CIR:  cir.func {{.*}} @clip_load_exception2
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_clip>>, !cir.ptr<!rec_clip>
 // CIR:    [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "a"} : !cir.ptr<!rec_clip> -> !cir.ptr<!cir.array<!u8i x 3>>
 // CIR:    [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_a1, [[MEMBER]] {is_volatile} : !cir.ptr<!cir.array<!u8i x 3>>) -> !s32i
@@ -178,7 +178,7 @@ void check_store(st2 *s2) {
   s2->a = 1;
 }
 
-// CIR:  cir.func dso_local @check_store
+// CIR:  cir.func {{.*}} @check_store
 // CIR:    [[CONST:%.*]] = cir.const #cir.int<1> : !s32i
 // CIR:    [[CAST:%.*]] = cir.cast integral [[CONST]] : !s32i -> !s16i
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st2>>, !cir.ptr<!rec_st2>
@@ -209,7 +209,7 @@ void check_store_exception(st3 *s3) {
   s3->b = 2;
 }
 
-// CIR:  cir.func dso_local @check_store_exception
+// CIR:  cir.func {{.*}} @check_store_exception
 // CIR:    [[CONST:%.*]] = cir.const #cir.int<2> : !s32i
 // CIR:    [[CAST:%.*]] = cir.cast integral [[CONST]] : !s32i -> !u32i
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st3>>, !cir.ptr<!rec_st3>
@@ -239,7 +239,7 @@ void clip_store_exception2(clip *c) {
   c->a = 3;
 }
 
-// CIR:  cir.func dso_local @clip_store_exception2
+// CIR:  cir.func {{.*}} @clip_store_exception2
 // CIR:    [[CONST:%.*]] = cir.const #cir.int<3> : !s32i
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_clip>>, !cir.ptr<!rec_clip>
 // CIR:    [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "a"} : !cir.ptr<!rec_clip> -> !cir.ptr<!cir.array<!u8i x 3>>
@@ -261,7 +261,7 @@ void check_store_second_member (st4 *s4) {
   s4->b = 1;
 }
 
-// CIR:  cir.func dso_local @check_store_second_member
+// CIR:  cir.func {{.*}} @check_store_second_member
 // CIR:    [[ONE:%.*]] = cir.const #cir.int<1> : !s32i
 // CIR:    [[CAST:%.*]] = cir.cast integral [[ONE]] : !s32i -> !u64i
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st4>>, !cir.ptr<!rec_st4>
diff --git a/clang/test/CIR/CodeGen/address-space-conversion.cpp b/clang/test/CIR/CodeGen/address-space-conversion.cpp
index ca026be60ee71..9ce1f5e4b8e24 100644
--- a/clang/test/CIR/CodeGen/address-space-conversion.cpp
+++ b/clang/test/CIR/CodeGen/address-space-conversion.cpp
@@ -11,7 +11,7 @@ using pi2_t = int __attribute__((address_space(2))) *;
 using ri1_t = int __attribute__((address_space(1))) &;
 using ri2_t = int __attribute__((address_space(2))) &;
 
-// CIR: cir.func dso_local @{{.*test_ptr.*}}
+// CIR: cir.func {{.*}} @{{.*test_ptr.*}}
 // LLVM: define dso_local void @{{.*test_ptr.*}}
 // OGCG: define dso_local void @{{.*test_ptr.*}}
 void test_ptr() {
@@ -30,7 +30,7 @@ void test_ptr() {
   // OGCG-NEXT: store ptr addrspace(2)  %{{.*}}, ptr %{{.*}}
 }
 
-// CIR: cir.func dso_local @{{.*test_ref.*}}
+// CIR: cir.func {{.*}} @{{.*test_ref.*}}
 // LLVM: define dso_local void @{{.*test_ref.*}}
 // OGCG: define dso_local void @{{.*test_ref.*}}
 void test_ref() {
@@ -56,7 +56,7 @@ void test_ref() {
   // OGCG-NEXT: store ptr addrspace(2) %{{.*}}, ptr %{{.*}}
 }
 
-// CIR: cir.func dso_local @{{.*test_nullptr.*}}
+// CIR: cir.func {{.*}} @{{.*test_nullptr.*}}
 // LLVM: define dso_local void @{{.*test_nullptr.*}}
 // OGCG: define dso_local void @{{.*test_nullptr.*}}
 void test_nullptr() {
@@ -74,7 +74,7 @@ void test_nullptr() {
   // OGCG-NEXT: store ptr addrspace(2) nu...
[truncated]

@llvmbot
Copy link
Member

llvmbot commented Nov 30, 2025

@llvm/pr-subscribers-clangir

Author: Henrich Lauko (xlauko)

Changes

Switches to more efficient explicit enum property instead of a wrapped storage, simplifying the string representation. The attribute is now placed before the symbol name for consistency with other FuncOp attributes. FileCheck patterns are also simplified to match only the attributes under test.


Patch is 100.72 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/170050.diff

48 Files Affected:

  • (modified) clang/include/clang/CIR/Dialect/IR/CIRAttrs.td (+4-38)
  • (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+27-23)
  • (modified) clang/lib/CIR/CodeGen/CIRGenExpr.cpp (+1-2)
  • (modified) clang/lib/CIR/CodeGen/CIRGenModule.cpp (+6-13)
  • (modified) clang/lib/CIR/Dialect/IR/CIRDialect.cpp (+46-34)
  • (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c (+7-7)
  • (modified) clang/test/CIR/CodeGen/address-space-conversion.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/address-space.c (+3-3)
  • (modified) clang/test/CIR/CodeGen/array-ctor.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/asm-label-inline-builtins.c (+1-1)
  • (modified) clang/test/CIR/CodeGen/assign-operator.cpp (+2-2)
  • (modified) clang/test/CIR/CodeGen/bitfield-union.c (+1-1)
  • (modified) clang/test/CIR/CodeGen/bitfields.c (+3-3)
  • (modified) clang/test/CIR/CodeGen/bitfields.cpp (+3-3)
  • (modified) clang/test/CIR/CodeGen/bitfields_be.c (+2-2)
  • (modified) clang/test/CIR/CodeGen/constant-inits.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/copy-constructor.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/coro-task.cpp (+2-2)
  • (modified) clang/test/CIR/CodeGen/cxx-conversion-operators.cpp (+5-5)
  • (modified) clang/test/CIR/CodeGen/delete.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/destructors.cpp (+3-3)
  • (modified) clang/test/CIR/CodeGen/dtors.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/dynamic-cast.cpp (+6-6)
  • (modified) clang/test/CIR/CodeGen/global-ctor-dtor.cpp (+4-4)
  • (modified) clang/test/CIR/CodeGen/goto.cpp (+8-8)
  • (modified) clang/test/CIR/CodeGen/inline-attributes.cpp (+6-6)
  • (modified) clang/test/CIR/CodeGen/label-values.c (+4-4)
  • (modified) clang/test/CIR/CodeGen/label.c (+7-7)
  • (modified) clang/test/CIR/CodeGen/lambda-static-invoker.cpp (+3-3)
  • (modified) clang/test/CIR/CodeGen/lambda.cpp (+14-14)
  • (modified) clang/test/CIR/CodeGen/linkage-spec.cpp (+14-14)
  • (modified) clang/test/CIR/CodeGen/no-prototype.c (+8-8)
  • (modified) clang/test/CIR/CodeGen/placement-new.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/ptrdiff.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/statement-exprs.c (+8-8)
  • (modified) clang/test/CIR/CodeGen/stmt-expr.cpp (+2-2)
  • (modified) clang/test/CIR/CodeGen/var_arg.c (+2-2)
  • (modified) clang/test/CIR/CodeGen/variable-decomposition.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/vbase.cpp (+1-1)
  • (modified) clang/test/CIR/CodeGen/volatile.cpp (+10-10)
  • (modified) clang/test/CIR/CodeGen/vtable-emission.cpp (+2-2)
  • (modified) clang/test/CIR/CodeGenBuiltins/builtin-fcmp-sse.c (+8-8)
  • (modified) clang/test/CIR/CodeGenBuiltins/builtin_inline.c (+1-1)
  • (modified) clang/test/CIR/CodeGenBuiltins/builtin_prefetch.c (+1-1)
  • (modified) clang/test/CIR/CodeGenBuiltins/builtins-overflow.cpp (+30-30)
  • (modified) clang/test/CIR/IR/inline-attrs.cir (+22-15)
  • (modified) clang/test/CIR/func-linkage.cpp (+4-4)
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
index 12bc9cf7b5b04..98d4636dafc29 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td
@@ -1085,44 +1085,10 @@ def CIR_TypeInfoAttr : CIR_Attr<"TypeInfo", "typeinfo", [TypedAttrInterface]> {
 //===----------------------------------------------------------------------===//
 
 def CIR_InlineKind : CIR_I32EnumAttr<"InlineKind", "inlineKind", [
-  I32EnumAttrCase<"NoInline", 1, "never">,
-  I32EnumAttrCase<"AlwaysInline", 2, "always">,
-  I32EnumAttrCase<"InlineHint", 3, "hint">
-]> {
-  let genSpecializedAttr = 0;
-}
-
-def CIR_InlineAttr : CIR_EnumAttr<CIR_InlineKind, "inline"> {
-  let summary = "Inline attribute";
-  let description = [{
-    Inline attribute represents user directives for inlining behavior.
-    This attribute is only used by `cir.func` operations.
-
-    Values:
-    - `never`: Prevents the function from being inlined (__attribute__((noinline)))
-    - `always`: Forces the function to be inlined (__attribute__((always_inline)))
-    - `hint`: Suggests the function should be inlined (inline keyword)
-
-    Example:
-    ```
-    cir.func @noinline_func(%arg0: !s32i) -> !s32i inline(never) {
-      cir.return %arg0 : !s32i
-    }
-    cir.func @always_inline_func() -> !s32i inline(always) {
-      %0 = cir.const #cir.int<42> : !s32i
-      cir.return %0 : !s32i
-    }
-    ```
-  }];
-
-  let cppClassName = "InlineAttr";
-
-  let extraClassDeclaration = [{
-    bool isNoInline() const { return getValue() == InlineKind::NoInline; };
-    bool isAlwaysInline() const { return getValue() == InlineKind::AlwaysInline; };
-    bool isInlineHint() const { return getValue() == InlineKind::InlineHint; };
-  }];
-}
+  I32EnumAttrCase<"NoInline", 1, "no_inline">,
+  I32EnumAttrCase<"AlwaysInline", 2, "always_inline">,
+  I32EnumAttrCase<"InlineHint", 3, "inline_hint">
+]>;
 
 //===----------------------------------------------------------------------===//
 // CatchAllAttr & UnwindAttr
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 5f5fab6f12300..11422d31df0ad 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2564,9 +2564,9 @@ def CIR_FuncOp : CIR_Op<"func", [
     Similarly, for global destructors both `global_dtor` and
     `global_dtor(<priority>)` are available.
 
-    The `inline(never)` keyword marks a function that should not be inlined.
-    The `inline(always)` keyword marks a function that should always be inlined.
-    The `inline(hint)` keyword suggests that the function should be inlined.
+    The `no_inline` attribute marks a function that should not be inlined.
+    The `always_inline` attribute marks a function that should always be inlined.
+    The `inline_hint` attribute suggests that the function should be inlined.
 
     Example:
 
@@ -2580,7 +2580,10 @@ def CIR_FuncOp : CIR_Op<"func", [
 
     // Linkage information
     cir.func linkonce_odr @some_method(...)
-    ```
+
+    // Inline information
+    cir.func no_inline @some_method(...)
+    
     // Builtin function
     cir.func builtin @__builtin_coro_end(!cir.ptr<i8>, !cir.bool) -> !cir.bool
     // Coroutine
@@ -2592,25 +2595,26 @@ def CIR_FuncOp : CIR_Op<"func", [
     ```
   }];
 
-  let arguments = (ins SymbolNameAttr:$sym_name,
-                       CIR_VisibilityAttr:$global_visibility,
-                       TypeAttrOf<CIR_FuncType>:$function_type,
-                       UnitAttr:$builtin,
-                       UnitAttr:$coroutine,
-                       UnitAttr:$lambda,
-                       UnitAttr:$no_proto,
-                       UnitAttr:$dso_local,
-                       DefaultValuedAttr<CIR_GlobalLinkageKind,
-                                         "cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
-                       OptionalAttr<CIR_InlineAttr>:$inline_kind,
-                       OptionalAttr<StrAttr>:$sym_visibility,
-                       UnitAttr:$comdat,
-                       OptionalAttr<DictArrayAttr>:$arg_attrs,
-                       OptionalAttr<DictArrayAttr>:$res_attrs,
-                       OptionalAttr<FlatSymbolRefAttr>:$aliasee,
-                       CIR_OptionalPriorityAttr:$global_ctor_priority,
-                       CIR_OptionalPriorityAttr:$global_dtor_priority,
-                       OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member
+  let arguments = (ins 
+    SymbolNameAttr:$sym_name,
+    CIR_VisibilityAttr:$global_visibility,
+    TypeAttrOf<CIR_FuncType>:$function_type,
+    UnitAttr:$builtin,
+    UnitAttr:$coroutine,
+    OptionalAttr<CIR_InlineKind>:$inline_kind,
+    UnitAttr:$lambda,
+    UnitAttr:$no_proto,
+    UnitAttr:$dso_local,
+    DefaultValuedAttr<CIR_GlobalLinkageKind,
+                      "cir::GlobalLinkageKind::ExternalLinkage">:$linkage,
+    OptionalAttr<StrAttr>:$sym_visibility,
+    UnitAttr:$comdat,
+    OptionalAttr<DictArrayAttr>:$arg_attrs,
+    OptionalAttr<DictArrayAttr>:$res_attrs,
+    OptionalAttr<FlatSymbolRefAttr>:$aliasee,
+    CIR_OptionalPriorityAttr:$global_ctor_priority,
+    CIR_OptionalPriorityAttr:$global_dtor_priority,
+    OptionalAttr<CIR_CXXSpecialMemberAttr>:$cxx_special_member
    );
 
   let regions = (region AnyRegion:$body);
diff --git a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
index 4065124f8f568..1c2b83e6094f3 100644
--- a/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenExpr.cpp
@@ -1870,8 +1870,7 @@ CIRGenCallee CIRGenFunction::emitDirectCallee(const GlobalDecl &gd) {
         clone.setLinkageAttr(cir::GlobalLinkageKindAttr::get(
             &cgm.getMLIRContext(), cir::GlobalLinkageKind::InternalLinkage));
         clone.setSymVisibility("private");
-        clone.setInlineKindAttr(cir::InlineAttr::get(
-            &cgm.getMLIRContext(), cir::InlineKind::AlwaysInline));
+        clone.setInlineKind(cir::InlineKind::AlwaysInline);
       }
       return CIRGenCallee::forDirect(clone, gd);
     }
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index 809c24f8aa670..03bbfbffce717 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -1975,7 +1975,6 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
       existingInlineKind && *existingInlineKind == cir::InlineKind::NoInline;
   bool isAlwaysInline = existingInlineKind &&
                         *existingInlineKind == cir::InlineKind::AlwaysInline;
-
   if (!decl) {
     assert(!cir::MissingFeatures::hlsl());
 
@@ -1984,8 +1983,7 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
       // If inlining is disabled and we don't have a declaration to control
       // inlining, mark the function as 'noinline' unless it is explicitly
       // marked as 'alwaysinline'.
-      f.setInlineKindAttr(
-          cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
+      f.setInlineKind(cir::InlineKind::NoInline);
     }
 
     return;
@@ -2002,19 +2000,16 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
   // Handle inline attributes
   if (decl->hasAttr<NoInlineAttr>() && !isAlwaysInline) {
     // Add noinline if the function isn't always_inline.
-    f.setInlineKindAttr(
-        cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
+    f.setInlineKind(cir::InlineKind::NoInline);
   } else if (decl->hasAttr<AlwaysInlineAttr>() && !isNoInline) {
     // Don't override AlwaysInline with NoInline, or vice versa, since we can't
     // specify both in IR.
-    f.setInlineKindAttr(
-        cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::AlwaysInline));
+    f.setInlineKind(cir::InlineKind::AlwaysInline);
   } else if (codeGenOpts.getInlining() == CodeGenOptions::OnlyAlwaysInlining) {
     // If inlining is disabled, force everything that isn't always_inline
     // to carry an explicit noinline attribute.
     if (!isAlwaysInline) {
-      f.setInlineKindAttr(
-          cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
+      f.setInlineKind(cir::InlineKind::NoInline);
     }
   } else {
     // Otherwise, propagate the inline hint attribute and potentially use its
@@ -2036,13 +2031,11 @@ void CIRGenModule::setCIRFunctionAttributesForDefinition(
         return any_of(pattern->redecls(), checkRedeclForInline);
       };
       if (checkForInline(fd)) {
-        f.setInlineKindAttr(cir::InlineAttr::get(&getMLIRContext(),
-                                                 cir::InlineKind::InlineHint));
+        f.setInlineKind(cir::InlineKind::InlineHint);
       } else if (codeGenOpts.getInlining() ==
                      CodeGenOptions::OnlyHintInlining &&
                  !fd->isInlined() && !isAlwaysInline) {
-        f.setInlineKindAttr(
-            cir::InlineAttr::get(&getMLIRContext(), cir::InlineKind::NoInline));
+        f.setInlineKind(cir::InlineKind::NoInline);
       }
     }
   }
diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
index d505ca141d383..7479dc0ef1554 100644
--- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
+++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp
@@ -220,6 +220,41 @@ void parseVisibilityAttr(OpAsmParser &parser, cir::VisibilityAttr &visibility) {
   visibility = cir::VisibilityAttr::get(parser.getContext(), visibilityKind);
 }
 
+//===----------------------------------------------------------------------===//
+// InlineKindAttr (FIXME: remove once FuncOp uses assembly format)
+//===----------------------------------------------------------------------===//
+
+ParseResult parseInlineKindAttr(OpAsmParser &parser,
+                                cir::InlineKindAttr &inlineKindAttr) {
+  // Static list of possible inline kind keywords
+  static constexpr llvm::StringRef keywords[] = {"no_inline", "always_inline",
+                                                 "inline_hint"};
+
+  // Parse the inline kind keyword (optional)
+  llvm::StringRef keyword;
+  if (parser.parseOptionalKeyword(&keyword, keywords).failed()) {
+    // Not an inline kind keyword, leave inlineKindAttr empty
+    return success();
+  }
+
+  // Parse the enum value from the keyword
+  auto inlineKindResult = ::cir::symbolizeEnum<::cir::InlineKind>(keyword);
+  if (!inlineKindResult) {
+    return parser.emitError(parser.getCurrentLocation(), "expected one of [")
+           << llvm::join(llvm::ArrayRef(keywords), ", ")
+           << "] for inlineKind, got: " << keyword;
+  }
+
+  inlineKindAttr =
+      ::cir::InlineKindAttr::get(parser.getContext(), *inlineKindResult);
+  return success();
+}
+
+void printInlineKindAttr(OpAsmPrinter &p, cir::InlineKindAttr inlineKindAttr) {
+  if (inlineKindAttr) {
+    p << " " << stringifyInlineKind(inlineKindAttr.getValue());
+  }
+}
 //===----------------------------------------------------------------------===//
 // CIR Custom Parsers/Printers
 //===----------------------------------------------------------------------===//
@@ -1753,6 +1788,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
 
   mlir::StringAttr builtinNameAttr = getBuiltinAttrName(state.name);
   mlir::StringAttr coroutineNameAttr = getCoroutineAttrName(state.name);
+  mlir::StringAttr inlineKindNameAttr = getInlineKindAttrName(state.name);
   mlir::StringAttr lambdaNameAttr = getLambdaAttrName(state.name);
   mlir::StringAttr noProtoNameAttr = getNoProtoAttrName(state.name);
   mlir::StringAttr visNameAttr = getSymVisibilityAttrName(state.name);
@@ -1765,6 +1801,14 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
   if (::mlir::succeeded(
           parser.parseOptionalKeyword(coroutineNameAttr.strref())))
     state.addAttribute(coroutineNameAttr, parser.getBuilder().getUnitAttr());
+
+  // Parse optional inline kind attribute
+  cir::InlineKindAttr inlineKindAttr;
+  if (failed(parseInlineKindAttr(parser, inlineKindAttr)))
+    return failure();
+  if (inlineKindAttr)
+    state.addAttribute(inlineKindNameAttr, inlineKindAttr);
+
   if (::mlir::succeeded(parser.parseOptionalKeyword(lambdaNameAttr.strref())))
     state.addAttribute(lambdaNameAttr, parser.getBuilder().getUnitAttr());
   if (parser.parseOptionalKeyword(noProtoNameAttr).succeeded())
@@ -1890,36 +1934,6 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {
       }).failed())
     return failure();
 
-  // Parse optional inline kind: inline(never|always|hint)
-  if (parser.parseOptionalKeyword("inline").succeeded()) {
-    if (parser.parseLParen().failed())
-      return failure();
-
-    llvm::StringRef inlineKindStr;
-    const std::array<llvm::StringRef, cir::getMaxEnumValForInlineKind()>
-        allowedInlineKindStrs{
-            cir::stringifyInlineKind(cir::InlineKind::NoInline),
-            cir::stringifyInlineKind(cir::InlineKind::AlwaysInline),
-            cir::stringifyInlineKind(cir::InlineKind::InlineHint),
-        };
-    if (parser.parseOptionalKeyword(&inlineKindStr, allowedInlineKindStrs)
-            .failed())
-      return parser.emitError(parser.getCurrentLocation(),
-                              "expected 'never', 'always', or 'hint'");
-
-    std::optional<InlineKind> inlineKind =
-        cir::symbolizeInlineKind(inlineKindStr);
-    if (!inlineKind)
-      return parser.emitError(parser.getCurrentLocation(),
-                              "invalid inline kind");
-
-    state.addAttribute(getInlineKindAttrName(state.name),
-                       cir::InlineAttr::get(builder.getContext(), *inlineKind));
-
-    if (parser.parseRParen().failed())
-      return failure();
-  }
-
   // Parse the optional function body.
   auto *body = state.addRegion();
   OptionalParseResult parseResult = parser.parseOptionalRegion(
@@ -2014,6 +2028,8 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
   if (getCoroutine())
     p << " coroutine";
 
+  printInlineKindAttr(p, getInlineKindAttr());
+
   if (getLambda())
     p << " lambda";
 
@@ -2069,10 +2085,6 @@ void cir::FuncOp::print(OpAsmPrinter &p) {
       p << "(" << globalDtorPriority.value() << ")";
   }
 
-  if (cir::InlineAttr inlineAttr = getInlineKindAttr()) {
-    p << " inline(" << cir::stringifyInlineKind(inlineAttr.getValue()) << ")";
-  }
-
   // Print the body if this is not an external function.
   Region &body = getOperation()->getRegion(0);
   if (!body.empty()) {
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 0c34d87734c3e..c572eb820b385 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -1978,10 +1978,10 @@ mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
 
   assert(!cir::MissingFeatures::opFuncMultipleReturnVals());
 
-  if (auto inlineKind = op.getInlineKind()) {
-    fn.setNoInline(inlineKind == cir::InlineKind::NoInline);
-    fn.setInlineHint(inlineKind == cir::InlineKind::InlineHint);
-    fn.setAlwaysInline(inlineKind == cir::InlineKind::AlwaysInline);
+  if (std::optional<cir::InlineKind> inlineKind = op.getInlineKind()) {
+    fn.setNoInline(*inlineKind == cir::InlineKind::NoInline);
+    fn.setInlineHint(*inlineKind == cir::InlineKind::InlineHint);
+    fn.setAlwaysInline(*inlineKind == cir::InlineKind::AlwaysInline);
   }
 
   fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(
diff --git a/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c b/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
index 19362cf79b107..66891f9e1ad78 100644
--- a/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
+++ b/clang/test/CIR/CodeGen/aapcs-volatile-bitfields.c
@@ -82,7 +82,7 @@ int check_load(st1 *s1) {
   return s1->b;
 }
 
-// CIR:  cir.func dso_local @check_load
+// CIR:  cir.func {{.*}} @check_load
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st1>>, !cir.ptr<!rec_st1>
 // CIR:    [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "b"} : !cir.ptr<!rec_st1> -> !cir.ptr<!u16i>
 // CIR:    [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_b, [[MEMBER]] {is_volatile} : !cir.ptr<!u16i>) -> !u32i
@@ -114,7 +114,7 @@ int check_load_exception(st3 *s3) {
   return s3->b;
 }
 
-// CIR:  cir.func dso_local @check_load_exception
+// CIR:  cir.func {{.*}} @check_load_exception
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st3>>, !cir.ptr<!rec_st3>
 // CIR:    [[MEMBER:%.*]] = cir.get_member [[LOAD]][2] {name = "b"} : !cir.ptr<!rec_st3> -> !cir.ptr<!u8i>
 // CIR:    [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_b1, [[MEMBER]] {is_volatile} : !cir.ptr<!u8i>) -> !u32i
@@ -151,7 +151,7 @@ int clip_load_exception2(clip *c) {
   return c->a;
 }
 
-// CIR:  cir.func dso_local @clip_load_exception2
+// CIR:  cir.func {{.*}} @clip_load_exception2
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_clip>>, !cir.ptr<!rec_clip>
 // CIR:    [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "a"} : !cir.ptr<!rec_clip> -> !cir.ptr<!cir.array<!u8i x 3>>
 // CIR:    [[BITFI:%.*]] = cir.get_bitfield align(4) (#bfi_a1, [[MEMBER]] {is_volatile} : !cir.ptr<!cir.array<!u8i x 3>>) -> !s32i
@@ -178,7 +178,7 @@ void check_store(st2 *s2) {
   s2->a = 1;
 }
 
-// CIR:  cir.func dso_local @check_store
+// CIR:  cir.func {{.*}} @check_store
 // CIR:    [[CONST:%.*]] = cir.const #cir.int<1> : !s32i
 // CIR:    [[CAST:%.*]] = cir.cast integral [[CONST]] : !s32i -> !s16i
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st2>>, !cir.ptr<!rec_st2>
@@ -209,7 +209,7 @@ void check_store_exception(st3 *s3) {
   s3->b = 2;
 }
 
-// CIR:  cir.func dso_local @check_store_exception
+// CIR:  cir.func {{.*}} @check_store_exception
 // CIR:    [[CONST:%.*]] = cir.const #cir.int<2> : !s32i
 // CIR:    [[CAST:%.*]] = cir.cast integral [[CONST]] : !s32i -> !u32i
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st3>>, !cir.ptr<!rec_st3>
@@ -239,7 +239,7 @@ void clip_store_exception2(clip *c) {
   c->a = 3;
 }
 
-// CIR:  cir.func dso_local @clip_store_exception2
+// CIR:  cir.func {{.*}} @clip_store_exception2
 // CIR:    [[CONST:%.*]] = cir.const #cir.int<3> : !s32i
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_clip>>, !cir.ptr<!rec_clip>
 // CIR:    [[MEMBER:%.*]] = cir.get_member [[LOAD]][0] {name = "a"} : !cir.ptr<!rec_clip> -> !cir.ptr<!cir.array<!u8i x 3>>
@@ -261,7 +261,7 @@ void check_store_second_member (st4 *s4) {
   s4->b = 1;
 }
 
-// CIR:  cir.func dso_local @check_store_second_member
+// CIR:  cir.func {{.*}} @check_store_second_member
 // CIR:    [[ONE:%.*]] = cir.const #cir.int<1> : !s32i
 // CIR:    [[CAST:%.*]] = cir.cast integral [[ONE]] : !s32i -> !u64i
 // CIR:    [[LOAD:%.*]] = cir.load align(8) {{.*}} : !cir.ptr<!cir.ptr<!rec_st4>>, !cir.ptr<!rec_st4>
diff --git a/clang/test/CIR/CodeGen/address-space-conversion.cpp b/clang/test/CIR/CodeGen/address-space-conversion.cpp
index ca026be60ee71..9ce1f5e4b8e24 100644
--- a/clang/test/CIR/CodeGen/address-space-conversion.cpp
+++ b/clang/test/CIR/CodeGen/address-space-conversion.cpp
@@ -11,7 +11,7 @@ using pi2_t = int __attribute__((address_space(2))) *;
 using ri1_t = int __attribute__((address_space(1))) &;
 using ri2_t = int __attribute__((address_space(2))) &;
 
-// CIR: cir.func dso_local @{{.*test_ptr.*}}
+// CIR: cir.func {{.*}} @{{.*test_ptr.*}}
 // LLVM: define dso_local void @{{.*test_ptr.*}}
 // OGCG: define dso_local void @{{.*test_ptr.*}}
 void test_ptr() {
@@ -30,7 +30,7 @@ void test_ptr() {
   // OGCG-NEXT: store ptr addrspace(2)  %{{.*}}, ptr %{{.*}}
 }
 
-// CIR: cir.func dso_local @{{.*test_ref.*}}
+// CIR: cir.func {{.*}} @{{.*test_ref.*}}
 // LLVM: define dso_local void @{{.*test_ref.*}}
 // OGCG: define dso_local void @{{.*test_ref.*}}
 void test_ref() {
@@ -56,7 +56,7 @@ void test_ref() {
   // OGCG-NEXT: store ptr addrspace(2) %{{.*}}, ptr %{{.*}}
 }
 
-// CIR: cir.func dso_local @{{.*test_nullptr.*}}
+// CIR: cir.func {{.*}} @{{.*test_nullptr.*}}
 // LLVM: define dso_local void @{{.*test_nullptr.*}}
 // OGCG: define dso_local void @{{.*test_nullptr.*}}
 void test_nullptr() {
@@ -74,7 +74,7 @@ void test_nullptr() {
   // OGCG-NEXT: store ptr addrspace(2) nu...
[truncated]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang Clang issues not falling into any other category ClangIR Anything related to the ClangIR project

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants