[clang] [mlir] [CIR] 3 more 'quick' function attribute lowering through LLVMIRDialect (PR #178443)

via cfe-commits cfe-commits at lists.llvm.org
Wed Jan 28 07:17:16 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clangir

Author: Erich Keane (erichkeane)

<details>
<summary>Changes</summary>

This patch lowers 3 more attributes, two of which are trivial, and one which has a touch of a complication.

The two trivial ones are no_caller_saved_registers and nocallback, which are language-level attributes that are effectively just passed on.

The final one is a touch more complicated, as it is a 'string' attribute: modular-format.  Also, it has a dash in the LLVM-IR version, but that isn't possible to add as a name in the LLVM-IR MLIR Dialect (see the comment inline). It also has a string of some consequence (that is checked in LLVM), but that is just passed to LLVM directly.

---

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


13 Files Affected:

- (modified) clang/include/clang/CIR/Dialect/IR/CIRDialect.td (+9) 
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+52-8) 
- (modified) clang/test/CIR/CodeGen/misc-attrs.cpp (+40) 
- (modified) mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td (+5) 
- (modified) mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp (+4) 
- (modified) mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp (+9) 
- (modified) mlir/lib/Target/LLVMIR/ModuleImport.cpp (+17) 
- (modified) mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (+6) 
- (modified) mlir/test/Dialect/LLVMIR/func.mlir (+19) 
- (modified) mlir/test/Dialect/LLVMIR/roundtrip.mlir (+9) 
- (modified) mlir/test/Target/LLVMIR/Import/function-attributes.ll (+18) 
- (modified) mlir/test/Target/LLVMIR/Import/instructions.ll (+37) 
- (modified) mlir/test/Target/LLVMIR/llvmir.mlir (+33) 


``````````diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 31cebdde1aa64..079b4cd87d019 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -51,6 +51,15 @@ def CIR_Dialect : Dialect {
     static llvm::StringRef getGlobalCtorsAttrName() { return "cir.global_ctors"; }
     static llvm::StringRef getGlobalDtorsAttrName() { return "cir.global_dtors"; }
     static llvm::StringRef getOperandSegmentSizesAttrName() { return "operandSegmentSizes"; }
+    static llvm::StringRef getNoCallerSavedRegsAttrName() { return "no_caller_saved_registers"; }
+    static llvm::StringRef getNoCallbackAttrName() { return "nocallback"; }
+    // Note: we have to name this with the underscore instead of the dash like
+    // traditional LLVM-IR does, because the LLVM-IR-Dialect doesn't have a way
+    // of forming names with a dash instead of underscore in its auto-generated
+    // names. TGLexer.cpp(from tablegen) only allows tablegen-names
+    // of a [a-zA-Z0-9_] character regex(numbers only if not first), so there is
+    // no way to get an underscore into this, even with escaping.
+    static llvm::StringRef getModularFormatAttrName() { return "modular_format"; }
 
     void registerAttributes();
     void registerTypes();
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 83b1c4e78c4d6..34e0309e3e64e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -129,7 +129,8 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name,
   if (info.isNoReturn())
     addUnitAttr(cir::CIRDialect::getNoReturnAttrName());
 
-  // TODO(cir): Check/add cmse_nonsecure_call attribute here.
+  // TODO(cir): Implement/check the CSME Nonsecure call attribute here. This
+  // requires being in CSME mode.
 
   addAttributesFromFunctionProtoType(getBuilder(), attrs,
                                      calleeInfo.getCalleeFunctionProtoType());
@@ -159,6 +160,9 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name,
     if (const FunctionDecl *func = dyn_cast<FunctionDecl>(targetDecl)) {
       addAttributesFromFunctionProtoType(
           getBuilder(), attrs, func->getType()->getAs<FunctionProtoType>());
+
+      // TODO(cir): When doing 'return attrs' we need to cover the 'NoAlias' for
+      // global allocation functions here.
       assert(!cir::MissingFeatures::opCallAttrs());
 
       const CXXMethodDecl *md = dyn_cast<CXXMethodDecl>(func);
@@ -168,8 +172,7 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name,
       // virtual function. These attributes are not inherited by overloads.
       if (!(attrOnCallSite && isVirtualCall)) {
         if (func->isNoReturn())
-          attrs.set(cir::CIRDialect::getNoReturnAttrName(),
-                    mlir::UnitAttr::get(&getMLIRContext()));
+          addUnitAttr(cir::CIRDialect::getNoReturnAttrName());
         // TODO(cir): Set NoBuiltinAttr here.
       }
     }
@@ -186,13 +189,54 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name,
       sideEffect = cir::SideEffect::Pure;
     }
 
-    assert(!cir::MissingFeatures::opCallAttrs());
-  }
+    attrs.set(cir::CIRDialect::getSideEffectAttrName(),
+              cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
+
+    // TODO(cir): When doing 'return attrs' we need to cover the Restrict and
+    // ReturnsNonNull attributes here.
+    if (targetDecl->hasAttr<AnyX86NoCallerSavedRegistersAttr>())
+      addUnitAttr(cir::CIRDialect::getNoCallerSavedRegsAttrName());
+    // TODO(cir): Implement 'NoCFCheck' attribute here.  This requires
+    // fcf-protection mode.
+    if (targetDecl->hasAttr<LeafAttr>())
+      addUnitAttr(cir::CIRDialect::getNoCallbackAttrName());
+    // TODO(cir): Implement 'BPFFastCall' attribute here.  This requires C, and
+    // the BPF target.
+
+    // TODO(cir): Detecting 'OptimizeNone' is done here in classic codegen, when
+    // we figure out when to do that, we should do it here.
+    // TODO(cir): AllocSize attr should be done here, but it has some additional
+    // work with forming the correct value for it.  Typically this calls into
+    // LLVM to set it correctly, which flattens the elem size and num-elems into
+    // a single value.  CIR should probably represent these as two values and
+    // handle the combination during lowering by calling into LLVM.
+
+    // TODO(cir): Quite a few CUDA and OpenCL attributes are added here, like
+    // uniform-work-group-size.
+
+    // TODO(cir): we should also do 'aarch64_pstate_sm_body' here.
+
+    if (auto *modularFormat = targetDecl->getAttr<ModularFormatAttr>()) {
+      FormatAttr *format = targetDecl->getAttr<FormatAttr>();
+      StringRef type = format->getType()->getName();
+      std::string formatIdx = std::to_string(format->getFormatIdx());
+      std::string firstArg = std::to_string(format->getFirstArg());
+      SmallVector<StringRef> args = {
+          type, formatIdx, firstArg,
+          modularFormat->getModularImplFn()->getName(),
+          modularFormat->getImplName()};
+      llvm::append_range(args, modularFormat->aspects());
+      attrs.set(cir::CIRDialect::getModularFormatAttrName(),
+          builder.getStringAttr(llvm::join(args, ",")));
+    }
 
+    // TODO(cir): We should set nobuiltin and default function attrs here.
+  
+    // TODO(cir): There is another region of `if (targetDecl)` that handles
+    // removing some attributes that are necessary modifications of the
+    // default-function attrs.  We should do that here.
+  }
   assert(!cir::MissingFeatures::opCallAttrs());
-
-  attrs.set(cir::CIRDialect::getSideEffectAttrName(),
-            cir::SideEffectAttr::get(&getMLIRContext(), sideEffect));
 }
 
 /// Returns the canonical formal type of the given C++ method.
diff --git a/clang/test/CIR/CodeGen/misc-attrs.cpp b/clang/test/CIR/CodeGen/misc-attrs.cpp
index 837f99275c70d..929316f0f208f 100644
--- a/clang/test/CIR/CodeGen/misc-attrs.cpp
+++ b/clang/test/CIR/CodeGen/misc-attrs.cpp
@@ -32,6 +32,28 @@ extern "C" {
   __attribute__((convergent))
   void convergent() {}
 
+  // CIR: cir.func{{.*}}@no_caller_saved_registers() attributes {no_caller_saved_registers} {
+  // LLVM: Function Attrs:
+  // LLVM-NOT: no_caller_saved_registers
+  // LLVM-NEXT: define{{.*}}@no_caller_saved_registers() #[[NCSR_ATTR:.*]] {
+  __attribute__((no_caller_saved_registers))
+  void no_caller_saved_registers() {}
+
+  // CIR: cir.func{{.*}}@leaf() attributes {nocallback} {
+  // LLVM: Function Attrs:
+  // LLVM-NOT: leaf
+  // LLVM-NEXT: define{{.*}}@leaf() #[[LEAF_ATTR:.*]] {
+  __attribute__((leaf))
+  void leaf() {}
+
+  // CIR: cir.func{{.*}}@modular_format({{.*}}) attributes {"modular-format" = "kprintf,1,2,someIdent,someStr,aspect,aspect2"} {
+  // LLVM: Function Attrs:
+  // LLVM-NOT:modular_format
+  // LLVM-NEXT: define{{.*}}@modular_format({{.*}}) #[[MOD_FORMAT_ATTR:.*]] {
+  __attribute__((format(kprintf, 1, 2)))
+  __attribute__((modular_format(someIdent, "someStr", "aspect", "aspect2")))
+  void modular_format(const char *c, ...) {}
+
   void caller() {
   // CIR: cir.call @returns_twice() {returns_twice} : () -> ()
   // LLVM: call void @returns_twice() #[[RT_CALL_ATTR:.*]]
@@ -48,6 +70,18 @@ extern "C" {
   // CIR: cir.call @convergent() {convergent} : () -> ()
   // LLVM: call void @convergent() #[[CONV_CALL_ATTR:.*]]
     convergent();
+
+  // CIR: cir.call @no_caller_saved_registers() {no_caller_saved_registers} : () -> ()
+  // LLVM: call void @no_caller_saved_registers() #[[NCSR_CALL_ATTR:.*]]
+    no_caller_saved_registers();
+
+  // CIR: cir.call @leaf() {nocallback} : () -> ()
+  // LLVM: call void @leaf() #[[LEAF_CALL_ATTR:.*]]
+    leaf();
+
+  // CIR: cir.call @modular_format({{.*}}) {"modular-format" = "kprintf,1,2,someIdent,someStr,aspect,aspect2"} : 
+  // LLVM: call void {{.*}}@modular_format({{.*}}) #[[MOD_FORMAT_CALL_ATTR:.*]]
+    modular_format("");
   }
 }
 
@@ -56,8 +90,14 @@ extern "C" {
 // LLVM: attributes #[[HOT_ATTR]] = {{.*}}hot
 // LLVM: attributes #[[ND_ATTR]] = {{.*}}noduplicate
 // LLVM: attributes #[[CONV_ATTR]] = {{.*}}convergent
+// LLVM: attributes #[[NCSR_ATTR]] = {{.*}}no_caller_saved_registers
+// LLVM: attributes #[[LEAF_ATTR]] = {{.*}}nocallback
+// LLVM: attributes #[[MOD_FORMAT_ATTR]] = {{.*}}"modular-format"="kprintf,1,2,someIdent,someStr,aspect,aspect2"
 // LLVM: attributes #[[RT_CALL_ATTR]] = {{.*}}returns_twice
 // LLVM: attributes #[[COLD_CALL_ATTR]] = {{.*}}cold
 // LLVM: attributes #[[HOT_CALL_ATTR]] = {{.*}}hot
 // LLVM: attributes #[[ND_CALL_ATTR]] = {{.*}}noduplicate
 // LLVM: attributes #[[CONV_CALL_ATTR]] = {{.*}}convergent
+// LLVM: attributes #[[NCSR_CALL_ATTR]] = {{.*}}no_caller_saved_registers
+// LLVM: attributes #[[LEAF_CALL_ATTR]] = {{.*}}nocallback
+// LLVM: attributes #[[MOD_FORMAT_CALL_ATTR]] = {{.*}}"modular-format"="kprintf,1,2,someIdent,someStr,aspect,aspect2"
diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index f6f1c90b481c5..3bf4875678a9d 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -797,6 +797,8 @@ def LLVM_CallOp
       UnitAttr:$convergent, UnitAttr:$no_unwind, UnitAttr:$will_return,
       UnitAttr:$noreturn, UnitAttr:$returns_twice, UnitAttr:$hot,
       UnitAttr:$cold, UnitAttr:$noduplicate,
+      UnitAttr:$no_caller_saved_registers, UnitAttr:$nocallback,
+      OptionalAttr<StrAttr>:$modular_format,
       VariadicOfVariadic<LLVM_Type, "op_bundle_sizes">:$op_bundle_operands,
       DenseI32ArrayAttr:$op_bundle_sizes,
       OptionalAttr<ArrayAttr>:$op_bundle_tags,
@@ -2000,6 +2002,9 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
     OptionalAttr<UnitAttr>:$hot,
     OptionalAttr<UnitAttr>:$cold,
     OptionalAttr<UnitAttr>:$noduplicate,
+    OptionalAttr<UnitAttr>:$no_caller_saved_registers,
+    OptionalAttr<UnitAttr>:$nocallback,
+    OptionalAttr<StrAttr>:$modular_format,
     OptionalAttr<LLVM_VecTypeHintAttr>:$vec_type_hint,
     OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint,
     OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size,
diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index 27d6355c9e221..2ef2a72db81d7 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -997,6 +997,7 @@ void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results,
         /*convergent=*/nullptr, /*no_unwind=*/nullptr, /*will_return=*/nullptr,
         /*noreturn=*/nullptr, /*returns_twice=*/nullptr, /*hot=*/nullptr,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
+        /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr, /*modular_format=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
@@ -1030,6 +1031,7 @@ void CallOp::build(OpBuilder &builder, OperationState &state,
         /*noreturn=*/nullptr,
         /*returns_twice=*/nullptr, /*hot=*/nullptr,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
+        /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr, /*modular_format=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr,
@@ -1049,6 +1051,7 @@ void CallOp::build(OpBuilder &builder, OperationState &state,
         /*noreturn=*/nullptr,
         /*returns_twice=*/nullptr, /*hot=*/nullptr,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
+        /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr, /*modular_format=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
@@ -1068,6 +1071,7 @@ void CallOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func,
         /*noreturn=*/nullptr,
         /*returns_twice=*/nullptr, /*hot=*/nullptr,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
+        /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr, /*modular_format=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
index 31636abfff27f..e818fdaccc2d8 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -437,6 +437,15 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder,
       call->addFnAttr(llvm::Attribute::AlwaysInline);
     if (callOp.getInlineHintAttr())
       call->addFnAttr(llvm::Attribute::InlineHint);
+    if (callOp.getNoCallerSavedRegistersAttr())
+      call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(),
+                                           "no_caller_saved_registers"));
+    if (callOp.getNocallbackAttr())
+      call->addFnAttr(llvm::Attribute::NoCallback);
+    if (StringAttr modFormat = callOp.getModularFormatAttr())
+      call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(),
+                                           "modular-format",
+                                           modFormat.getValue()));
 
     if (failed(moduleTranslation.convertArgAndResultAttrs(callOp, call)))
       return failure();
diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
index 928e7a57ae24f..deaeb98d9abdc 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -2663,10 +2663,13 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{
     StringLiteral("inlinehint"),
     StringLiteral("instrument-function-entry"),
     StringLiteral("instrument-function-exit"),
+    StringLiteral("modular-format"),
     StringLiteral("memory"),
+    StringLiteral("no_caller_saved_registers"),
     StringLiteral("no-infs-fp-math"),
     StringLiteral("no-nans-fp-math"),
     StringLiteral("no-signed-zeros-fp-math"),
+    StringLiteral("nocallback"),
     StringLiteral("noduplicate"),
     StringLiteral("noinline"),
     StringLiteral("noreturn"),
@@ -2722,6 +2725,13 @@ void ModuleImport::processFunctionAttributes(llvm::Function *func,
     funcOp.setHot(true);
   if (func->hasFnAttribute(llvm::Attribute::NoDuplicate))
     funcOp.setNoduplicate(true);
+  if (func->hasFnAttribute("no_caller_saved_registers"))
+    funcOp.setNoCallerSavedRegisters(true);
+  if (func->hasFnAttribute(llvm::Attribute::NoCallback))
+    funcOp.setNocallback(true);
+  if (llvm::Attribute attr = func->getFnAttribute("modular-format");
+      attr.isStringAttribute())
+    funcOp.setModularFormat(StringAttr::get(context, attr.getValueAsString()));
 
   if (func->hasFnAttribute("aarch64_pstate_sm_enabled"))
     funcOp.setArmStreaming(true);
@@ -2949,6 +2959,13 @@ LogicalResult ModuleImport::convertCallAttributes(llvm::CallInst *inst,
   op.setCold(callAttrs.getFnAttr(llvm::Attribute::Cold).isValid());
   op.setNoduplicate(
       callAttrs.getFnAttr(llvm::Attribute::NoDuplicate).isValid());
+  op.setNoCallerSavedRegisters(
+      callAttrs.getFnAttr("no_caller_saved_registers").isValid());
+  op.setNocallback(callAttrs.getFnAttr(llvm::Attribute::NoCallback).isValid());
+
+  if (llvm::Attribute attr = callAttrs.getFnAttr("modular-format");
+      attr.isStringAttribute())
+    op.setModularFormat(StringAttr::get(context, attr.getValueAsString()));
   op.setNoInline(callAttrs.getFnAttr(llvm::Attribute::NoInline).isValid());
   op.setAlwaysInline(
       callAttrs.getFnAttr(llvm::Attribute::AlwaysInline).isValid());
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 79d65ffe4e551..7d14efc0b6695 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1686,6 +1686,12 @@ static void convertFunctionAttributes(LLVMFuncOp func,
     llvmFunc->addFnAttr(llvm::Attribute::WillReturn);
   if (func.getNoreturnAttr())
     llvmFunc->addFnAttr(llvm::Attribute::NoReturn);
+  if(func.getNoCallerSavedRegistersAttr())
+    llvmFunc->addFnAttr("no_caller_saved_registers");
+  if (func.getNocallbackAttr())
+    llvmFunc->addFnAttr(llvm::Attribute::NoCallback);
+  if (StringAttr modFormat = func.getModularFormatAttr())
+    llvmFunc->addFnAttr("modular-format", modFormat.getValue());
   if (TargetFeaturesAttr targetFeatAttr = func.getTargetFeaturesAttr())
     llvmFunc->addFnAttr("target-features", targetFeatAttr.getFeaturesString());
   if (FramePointerKindAttr fpAttr = func.getFramePointerAttr())
diff --git a/mlir/test/Dialect/LLVMIR/func.mlir b/mlir/test/Dialect/LLVMIR/func.mlir
index a66087e431eee..7d9cafe05bff0 100644
--- a/mlir/test/Dialect/LLVMIR/func.mlir
+++ b/mlir/test/Dialect/LLVMIR/func.mlir
@@ -354,6 +354,25 @@ module {
     llvm.return
   }
 
+  llvm.func @no_caller_saved_registers_function() attributes {no_caller_saved_registers} {
+    // CHECK: @no_caller_saved_registers_function
+    // CHECK-SAME: attributes {no_caller_saved_registers}
+    llvm.return
+  }
+
+  llvm.func @nocallback_function() attributes {nocallback} {
+    // CHECK: @nocallback_function
+    // CHECK-SAME: attributes {nocallback}
+    llvm.return
+  }
+
+  llvm.func @modular_format_function(%arg: i32) attributes {modular_format = "ident,1,1,foo,bar"} {
+    // CHECK: @modular_format_function
+    // CHECK-SAME: attributes {modular_format = "ident,1,1,foo,bar"}
+    llvm.return
+  }
+
+
 }
 
 // -----
diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index 9ce45afd96c25..c97574f41e8a4 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -137,6 +137,15 @@ func.func @ops(%arg0: i32, %arg1: f32,
 // CHECK: llvm.call @baz() {noduplicate} : () -> ()
   llvm.call @baz() {noduplicate} : () -> ()
 
+// CHECK: llvm.call @baz() {no_caller_saved_registers} : () -> ()
+  llvm.call @baz() {no_caller_saved_registers} : () -> ()
+
+// CHECK: llvm.call @baz() {nocallback} : () -> ()
+  llvm.call @baz() {nocallback} : () -> ()
+
+// CHECK: llvm.call @baz() {modular_format = "format str"} : () -> ()
+  llvm.call @baz() {modular_format = "format str"} : () -> ()
+
 // CHECK: llvm.call @baz() {memory = #llvm.memory_effects<other = none, argMem = read, inaccessibleMem = write, errnoMem = none, targetMem0 = none, targetMem1 = none>} : () -> ()
   llvm.call @baz() {memory = #llvm.memory_effects<other = none, argMem = read, inaccessibleMem = write, errnoMem = none, targetMem0 = none, targetMem1 = none>} : () -> ()
 
diff --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll b/mlir/test/Target/LLVMIR/Import/function-attributes.ll
index 1002ad03c227c..153912fbae34a 100644
--- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll
+++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll
@@ -441,5 +441,23 @@ declare void @noduplicate_attribute() noduplicate
 
 // -----
 
+; CHECK-LABEL: @no_caller_saved_registers_attribute
+; CHECK-SAME: attributes {no_caller_saved_registers}
+declare void @no_caller_saved_registers_attribute () "no_caller_saved_registers"
+
+// -----
+
+; CHECK-LABEL: @nocallback_attribute
+; CHECK-SAME: attributes {nocallback}
+declare void @nocallback_attribute() nocallback
+
+// -----
+
+; CHECK-LABEL: @modular_format_attribute
+; CHECK-SAME: attributes {modular_format = "Ident,1,1,Foo,Bar"}
+declare void @modular_format_attribute(i32) "modular-format" = "Ident,1,1,Foo,Bar"
+
+// -----
+
 ; expected-warning @unknown {{'preallocated' attribute is invalid on current operation, skipping it}}
 declare void @test() preallocated(i32)
diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll
index 11ebd70def8ce..9b3ad17c31a28 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -761,6 +761,43 @@ define void @call_nodupli...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/178443


More information about the cfe-commits mailing list