Author: Erich Keane
Date: 2026-02-02T15:04:52Z
New Revision: 8cf99c263ef9099e58c7143de3c611190cb556ed

URL: 
https://github.com/llvm/llvm-project/commit/8cf99c263ef9099e58c7143de3c611190cb556ed
DIFF: 
https://github.com/llvm/llvm-project/commit/8cf99c263ef9099e58c7143de3c611190cb556ed.diff

LOG: [CIR] Implement lowering for 'no-builtins' attributes (#178899)

This patch adds the 'no-builtins' and 'no-builtin-XXX' attributes from
LLVM-IR to both LLVMIR-MLIR and Clang lowering. However, I've done a
slightly different implementation of them.

LLVM-IR represents them as 'no-builtins' and 'no-builtin-NAME', where
the latter can be multiple names. This is problematic for the MLIR for a
variety of reasons, most particularly is our preference for explicit
attribute (of which the latter is an infinite list). Additionally of
course, our inability to have dashes in attribute names is troublesome.

Therefore, I've lowered them instead as `nobuiltins` for both, which is
an array attribute.

IF the array attribute is empty, it is intended to mean 'all functions'
(ie, the same as `no-builtins`), else it is a list of StringAttrs that
contain the variants of `NAME`.

I considered using nobuiltins=['*'] for the 'all functions', but that
seemed like a differentiation without purpose.

Added: 
    clang/test/CIR/CodeGen/no-builtin-attr.cpp

Modified: 
    clang/include/clang/CIR/Dialect/IR/CIRDialect.td
    clang/lib/CIR/CodeGen/CIRGenCall.cpp
    clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c
    clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c
    clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c
    clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c
    clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c
    mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
    mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
    mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
    mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
    mlir/lib/Target/LLVMIR/ModuleImport.cpp
    mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
    mlir/test/Dialect/LLVMIR/func.mlir
    mlir/test/Dialect/LLVMIR/roundtrip.mlir
    mlir/test/Target/LLVMIR/Import/function-attributes.ll
    mlir/test/Target/LLVMIR/Import/instructions.ll
    mlir/test/Target/LLVMIR/llvmir.mlir

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td 
b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
index 079b4cd87d019..bbd9831e73a50 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td
@@ -60,6 +60,7 @@ def CIR_Dialect : Dialect {
     // 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"; }
+    static llvm::StringRef getNoBuiltinsAttrName() { return "nobuiltins"; }
 
     void registerAttributes();
     void registerTypes();

diff  --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp 
b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 809d775e77d55..7a1efb2ace010 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -111,6 +111,40 @@ static void 
addAttributesFromFunctionProtoType(CIRGenBuilderTy &builder,
               mlir::UnitAttr::get(builder.getContext()));
 }
 
+static void addNoBuiltinAttributes(mlir::MLIRContext &ctx,
+                                   mlir::NamedAttrList &attrs,
+                                   const LangOptions &langOpts,
+                                   const NoBuiltinAttr *nba = nullptr) {
+  // First, handle the language options passed through -fno-builtin.
+  // or, if there is a wildcard in the builtin names specified through the
+  // attribute, disable them all.
+  if (langOpts.NoBuiltin ||
+      (nba && llvm::is_contained(nba->builtinNames(), "*"))) {
+    // -fno-builtin disables them all.
+    // Empty attribute means 'all'.
+    attrs.set(cir::CIRDialect::getNoBuiltinsAttrName(),
+              mlir::ArrayAttr::get(&ctx, {}));
+    return;
+  }
+
+  llvm::SetVector<mlir::Attribute> nbFuncs;
+  auto addNoBuiltinAttr = [&ctx, &nbFuncs](StringRef builtinName) {
+    nbFuncs.insert(mlir::StringAttr::get(&ctx, builtinName));
+  };
+
+  // Then, add attributes for builtins specified through -fno-builtin-<name>.
+  llvm::for_each(langOpts.NoBuiltinFuncs, addNoBuiltinAttr);
+
+  // Now, let's check the __attribute__((no_builtin("...")) attribute added to
+  // the source.
+  if (nba)
+    llvm::for_each(nba->builtinNames(), addNoBuiltinAttr);
+
+  if (!nbFuncs.empty())
+    attrs.set(cir::CIRDialect::getNoBuiltinsAttrName(),
+              mlir::ArrayAttr::get(&ctx, nbFuncs.getArrayRef()));
+}
+
 /// Construct the CIR attribute list of a function or call.
 void CIRGenModule::constructAttributeList(llvm::StringRef name,
                                           const CIRGenFunctionInfo &info,
@@ -137,6 +171,13 @@ void CIRGenModule::constructAttributeList(llvm::StringRef 
name,
 
   const Decl *targetDecl = calleeInfo.getCalleeDecl().getDecl();
 
+  // TODO(cir): OMP Assume Attributes should be here.
+
+  const NoBuiltinAttr *nba = nullptr;
+
+  // TODO(cir): Some work for arg memory effects can be done here, as it is in
+  // classic codegen.
+
   if (targetDecl) {
     if (targetDecl->hasAttr<NoThrowAttr>())
       addUnitAttr(cir::CIRDialect::getNoThrowAttrName());
@@ -173,7 +214,7 @@ void CIRGenModule::constructAttributeList(llvm::StringRef 
name,
       if (!(attrOnCallSite && isVirtualCall)) {
         if (func->isNoReturn())
           addUnitAttr(cir::CIRDialect::getNoReturnAttrName());
-        // TODO(cir): Set NoBuiltinAttr here.
+        nba = func->getAttr<NoBuiltinAttr>();
       }
     }
 
@@ -229,13 +270,15 @@ void CIRGenModule::constructAttributeList(llvm::StringRef 
name,
       attrs.set(cir::CIRDialect::getModularFormatAttrName(),
                 builder.getStringAttr(llvm::join(args, ",")));
     }
+  }
 
-    // TODO(cir): We should set nobuiltin and default function attrs here.
+  addNoBuiltinAttributes(getMLIRContext(), attrs, getLangOpts(), nba);
 
-    // 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.
-  }
+  // TODO(cir): We should set 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());
 }
 

diff  --git a/clang/test/CIR/CodeGen/no-builtin-attr.cpp 
b/clang/test/CIR/CodeGen/no-builtin-attr.cpp
new file mode 100644
index 0000000000000..6abdb8835d5dd
--- /dev/null
+++ b/clang/test/CIR/CodeGen/no-builtin-attr.cpp
@@ -0,0 +1,204 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o 
%t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefixes=CIR,CIR-DEF
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o 
%t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-DEF
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-DEF
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir 
-fno-builtin-memcmp %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefixes=CIR,CIR-SPC
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-fno-builtin-memcmp %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-SPC
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm 
-fno-builtin-memcmp %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-SPC
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir 
-fno-builtin-memcmp -fno-builtin-memset %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefixes=CIR,CIR-BTH
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-fno-builtin-memcmp -fno-builtin-memset %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-BTH
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm 
-fno-builtin-memcmp -fno-builtin-memset %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-BTH
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir 
-fno-builtin %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefixes=CIR,CIR-ALL
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm 
-fno-builtin %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-ALL
+//
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -fno-builtin %s 
-o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-ALL
+
+extern "C" {
+// CIR: cir.func{{.*}}@normal() attributes {
+// CIR-DEF-NOT: nobuiltins
+// CIR-SPC-SAME: nobuiltins = ["memcmp"]
+// CIR-BTH-SAME: nobuiltins = ["memcmp", "memset"]
+// CIR-ALL-SAME: nobuiltins = []
+// LLVM: define{{.*}}normal() #[[NORM_ATTR:.*]] {
+__attribute__((cold)) // to force attributes on the call to be around.
+void normal(){}
+
+// CIR: cir.func{{.*}}@no_builtins() attributes {
+// CIR-DEF-SAME: nobuiltins = []
+// CIR-SPC-SAME: nobuiltins = []
+// CIR-BTH-SAME: nobuiltins = []
+// CIR-ALL-SAME: nobuiltins = []
+// LLVM: define{{.*}}no_builtins() #[[NB_ATTR:.*]] {
+__attribute__((no_builtin))
+__attribute__((hot)) // force unique attributes
+void no_builtins() {}
+
+// CIR: cir.func{{.*}}@no_memcpy() attributes {
+// CIR-DEF-SAME: nobuiltins = ["memcpy"]
+// CIR-SPC-SAME: nobuiltins = ["memcmp", "memcpy"]
+// CIR-BTH-SAME: nobuiltins = ["memcmp", "memset", "memcpy"]
+// CIR-ALL-SAME: nobuiltins = []
+// LLVM: define{{.*}}no_memcpy() #[[NO_MCPY_ATTR:.*]] {
+__attribute__((no_builtin("memcpy")))
+__attribute__((leaf)) // force unique attributes
+void no_memcpy() {}
+
+// CIR: cir.func{{.*}}@no_memcmp() attributes {
+// CIR-DEF-SAME: nobuiltins = ["memcmp"]
+// CIR-SPC-SAME: nobuiltins = ["memcmp"]
+// CIR-BTH-SAME: nobuiltins = ["memcmp", "memset"]
+// CIR-ALL-SAME: nobuiltins = []
+// LLVM: define{{.*}}no_memcmp() #[[NO_MCMP_ATTR:.*]] {
+__attribute__((no_builtin("memcmp")))
+__attribute__((noduplicate)) // force unique attributes
+void no_memcmp() {}
+
+// CIR: cir.func{{.*}}@no_both() attributes {
+// CIR-DEF-SAME: nobuiltins = ["memcmp", "memcpy"]
+// CIR-SPC-SAME: nobuiltins = ["memcmp", "memcpy"]
+// CIR-BTH-SAME: nobuiltins = ["memcmp", "memset", "memcpy"]
+// CIR-ALL-SAME: nobuiltins = []
+// LLVM: define{{.*}}no_both() #[[NO_BOTH_ATTR:.*]] {
+__attribute__((no_builtin("memcpy")))
+__attribute__((no_builtin("memcmp")))
+__attribute__((convergent)) // force unique attributes
+void no_both(){}
+}
+
+void caller() {
+  // CIR: cir.call @normal() {
+  // CIR-DEF-NOT: nobuiltins
+  // CIR-SPC-SAME: nobuiltins = ["memcmp"]
+  // CIR-BTH-SAME: nobuiltins = ["memcmp", "memset"]
+  // CIR-ALL-SAME: nobuiltins = []
+  // LLVM: call void @normal() #[[NORM_CALL_ATTR:.*]]
+  normal();
+  // CIR: cir.call @no_builtins() {
+  // CIR-DEF-SAME: nobuiltins = []
+  // CIR-SPC-SAME: nobuiltins = []
+  // CIR-BTH-SAME: nobuiltins = []
+  // CIR-ALL-SAME: nobuiltins = []
+  // LLVM: call void @no_builtins() #[[NB_CALL_ATTR:.*]]
+  no_builtins();
+  // CIR: cir.call @no_memcpy() {
+  // CIR-DEF-SAME: nobuiltins = ["memcpy"]
+  // CIR-SPC-SAME: nobuiltins = ["memcmp", "memcpy"]
+  // CIR-BTH-SAME: nobuiltins = ["memcmp", "memset", "memcpy"]
+  // CIR-ALL-SAME: nobuiltins = []
+  // LLVM: call void @no_memcpy() #[[NO_MCPY_CALL_ATTR:.*]]
+  no_memcpy();
+  // CIR: cir.call @no_memcmp() {
+  // CIR-DEF-SAME: nobuiltins = ["memcmp"]
+  // CIR-SPC-SAME: nobuiltins = ["memcmp"]
+  // CIR-BTH-SAME: nobuiltins = ["memcmp", "memset"]
+  // CIR-ALL-SAME: nobuiltins = []
+  // LLVM: call void @no_memcmp() #[[NO_MCMP_CALL_ATTR:.*]]
+  no_memcmp();
+  // CIR: cir.call @no_both() {
+  // CIR-DEF-SAME: nobuiltins = ["memcmp", "memcpy"]
+  // CIR-SPC-SAME: nobuiltins = ["memcmp", "memcpy"]
+  // CIR-BTH-SAME: nobuiltins = ["memcmp", "memset", "memcpy"]
+  // CIR-ALL-SAME: nobuiltins = []
+  // LLVM: call void @no_both() #[[NO_BOTH_CALL_ATTR:.*]]
+  no_both();
+}
+
+// LLVM: attributes #[[NORM_ATTR]] = {
+// LLVM-DEF-NOT: no-builtin
+// LLVM-SPC-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memset"
+// LLVM-ALL-SAME:"no-builtins"
+//
+// LLVM: attributes #[[NB_ATTR]] = {
+// LLVM-DEF-SAME:"no-builtins"
+// LLVM-SPC-SAME:"no-builtins"
+// LLVM-BTH-SAME:"no-builtins"
+// LLVM-ALL-SAME:"no-builtins"
+// 
+// LLVM: attributes #[[NO_MCPY_ATTR]] = {
+// LLVM-DEF-SAME: "no-builtin-memcpy"
+// LLVM-SPC-SAME: "no-builtin-memcmp"
+// LLVM-SPC-SAME: "no-builtin-memcpy"
+// LLVM-BTH-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memcpy"
+// LLVM-BTH-SAME: "no-builtin-memset"
+// LLVM-ALL-SAME:"no-builtins"
+//
+// LLVM: attributes #[[NO_MCMP_ATTR]] = {
+// LLVM-DEF-SAME: "no-builtin-memcmp"
+// LLVM-SPC-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memset"
+// LLVM-ALL-SAME:"no-builtins"
+//
+// LLVM: attributes #[[NO_BOTH_ATTR]] = {
+// LLVM-DEF-SAME: "no-builtin-memcmp"
+// LLVM-DEF-SAME: "no-builtin-memcpy"
+// LLVM-SPC-SAME: "no-builtin-memcmp"
+// LLVM-SPC-SAME: "no-builtin-memcpy"
+// LLVM-BTH-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memcpy"
+// LLVM-BTH-SAME: "no-builtin-memset"
+// LLVM-ALL-SAME:"no-builtins"
+//
+//
+// LLVM: attributes #[[NORM_CALL_ATTR]] = {
+// LLVM-DEF-NOT: no-builtin
+// LLVM-SPC-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memset"
+// LLVM-ALL-SAME:"no-builtins"
+//
+// LLVM: attributes #[[NB_CALL_ATTR]] = {
+// LLVM-DEF-SAME:"no-builtins"
+// LLVM-SPC-SAME:"no-builtins"
+// LLVM-BTH-SAME:"no-builtins"
+// LLVM-ALL-SAME:"no-builtins"
+//
+// LLVM: attributes #[[NO_MCPY_CALL_ATTR]] = {
+// LLVM-DEF-SAME: "no-builtin-memcpy"
+// LLVM-SPC-SAME: "no-builtin-memcmp"
+// LLVM-SPC-SAME: "no-builtin-memcpy"
+// LLVM-BTH-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memcpy"
+// LLVM-BTH-SAME: "no-builtin-memset"
+// LLVM-ALL-SAME:"no-builtins"
+//
+// LLVM: attributes #[[NO_MCMP_CALL_ATTR]] = {
+// LLVM-DEF-SAME: "no-builtin-memcmp"
+// LLVM-SPC-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memset"
+// LLVM-ALL-SAME:"no-builtins"
+//
+// LLVM: attributes #[[NO_BOTH_CALL_ATTR]] = {
+// LLVM-DEF-SAME: "no-builtin-memcmp"
+// LLVM-DEF-SAME: "no-builtin-memcpy"
+// LLVM-SPC-SAME: "no-builtin-memcmp"
+// LLVM-SPC-SAME: "no-builtin-memcpy"
+// LLVM-BTH-SAME: "no-builtin-memcmp"
+// LLVM-BTH-SAME: "no-builtin-memcpy"
+// LLVM-BTH-SAME: "no-builtin-memset"
+// LLVM-ALL-SAME:"no-builtins"

diff  --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c 
b/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c
index bc4249ffd25fc..d2e15e3889a2d 100644
--- a/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c
+++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c
@@ -10,7 +10,7 @@ double test_mm512_reduce_add_pd(__m512d __W, double 
ExtraAddOp){
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : 
(!cir.double, !cir.vector<8 x !cir.double>) -> !cir.double
 
   // CIR-LABEL: test_mm512_reduce_add_pd
-  // CIR: cir.call @_mm512_reduce_add_pd(%[[VEC:.*]]) : (!cir.vector<8 x 
!cir.double>) -> !cir.double
+  // CIR: cir.call @_mm512_reduce_add_pd(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<8 x !cir.double>) -> !cir.double
 
   // LLVM-LABEL: test_mm512_reduce_add_pd
   // LLVM: call double @llvm.vector.reduce.fadd.v8f64(double -0.000000e+00, <8 
x double> %{{.*}})
@@ -27,7 +27,7 @@ double test_mm512_reduce_mul_pd(__m512d __W, double 
ExtraMulOp){
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : 
(!cir.double, !cir.vector<8 x !cir.double>) -> !cir.double
 
   // CIR-LABEL: test_mm512_reduce_mul_pd
-  // CIR: cir.call @_mm512_reduce_mul_pd(%[[VEC:.*]]) : (!cir.vector<8 x 
!cir.double>) -> !cir.double
+  // CIR: cir.call @_mm512_reduce_mul_pd(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<8 x !cir.double>) -> !cir.double
 
   // LLVM-LABEL: test_mm512_reduce_mul_pd
   // LLVM: call double @llvm.vector.reduce.fmul.v8f64(double 1.000000e+00, <8 
x double> %{{.*}})
@@ -45,7 +45,7 @@ float test_mm512_reduce_add_ps(__m512 __W){
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : 
(!cir.float, !cir.vector<16 x !cir.float>) -> !cir.float
 
   // CIR-LABEL: test_mm512_reduce_add_ps
-  // CIR: cir.call @_mm512_reduce_add_ps(%[[VEC:.*]]) : (!cir.vector<16 x 
!cir.float>) -> !cir.float
+  // CIR: cir.call @_mm512_reduce_add_ps(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<16 x !cir.float>) -> !cir.float
 
   // LLVM-LABEL: test_mm512_reduce_add_ps
   // LLVM: call float @llvm.vector.reduce.fadd.v16f32(float -0.000000e+00, <16 
x float> %{{.*}})
@@ -60,7 +60,7 @@ float test_mm512_reduce_mul_ps(__m512 __W){
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : 
(!cir.float, !cir.vector<16 x !cir.float>) -> !cir.float
 
   // CIR-LABEL: test_mm512_reduce_mul_ps
-  // CIR: cir.call @_mm512_reduce_mul_ps(%[[VEC:.*]]) : (!cir.vector<16 x 
!cir.float>) -> !cir.float
+  // CIR: cir.call @_mm512_reduce_mul_ps(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<16 x !cir.float>) -> !cir.float
 
   // LLVM-LABEL: test_mm512_reduce_mul_ps
   // LLVM: call float @llvm.vector.reduce.fmul.v16f32(float 1.000000e+00, <16 
x float> %{{.*}})

diff  --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c 
b/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c
index 104e76fa6ad03..c724942a7a7f2 100644
--- a/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c
+++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c
@@ -9,7 +9,7 @@ double test_mm512_reduce_max_pd(__m512d __W, double ExtraAddOp){
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] : 
(!cir.vector<8 x !cir.double>) -> !cir.double
 
   // CIR-LABEL: test_mm512_reduce_max_pd
-  // CIR: cir.call @_mm512_reduce_max_pd(%[[VEC:.*]]) : (!cir.vector<8 x 
!cir.double>) -> !cir.double
+  // CIR: cir.call @_mm512_reduce_max_pd(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<8 x !cir.double>) -> !cir.double
 
   // LLVM-LABEL: test_mm512_reduce_max_pd
   // LLVM: call double @llvm.vector.reduce.fmax.v8f64(<8 x double> %{{.*}})
@@ -26,7 +26,7 @@ double test_mm512_reduce_min_pd(__m512d __W, double 
ExtraMulOp){
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] : 
(!cir.vector<8 x !cir.double>) -> !cir.double
 
   // CIR-LABEL: test_mm512_reduce_min_pd
-  // CIR: cir.call @_mm512_reduce_min_pd(%[[VEC:.*]]) : (!cir.vector<8 x 
!cir.double>) -> !cir.double
+  // CIR: cir.call @_mm512_reduce_min_pd(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<8 x !cir.double>) -> !cir.double
 
   // LLVM-LABEL: test_mm512_reduce_min_pd
   // LLVM: call double @llvm.vector.reduce.fmin.v8f64(<8 x double> %{{.*}})
@@ -43,7 +43,7 @@ float test_mm512_reduce_max_ps(__m512 __W){
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] : 
(!cir.vector<16 x !cir.float>) -> !cir.float
 
   // CIR-LABEL: test_mm512_reduce_max_ps
-  // CIR: cir.call @_mm512_reduce_max_ps(%[[VEC:.*]]) : (!cir.vector<16 x 
!cir.float>) -> !cir.float
+  // CIR: cir.call @_mm512_reduce_max_ps(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<16 x !cir.float>) -> !cir.float
 
   // LLVM-LABEL: test_mm512_reduce_max_ps
   // LLVM: call float @llvm.vector.reduce.fmax.v16f32(<16 x float> %{{.*}})
@@ -58,7 +58,7 @@ float test_mm512_reduce_min_ps(__m512 __W){
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] : 
(!cir.vector<16 x !cir.float>) -> !cir.float
 
   // CIR-LABEL: test_mm512_reduce_min_ps
-  // CIR: cir.call @_mm512_reduce_min_ps(%[[VEC:.*]]) : (!cir.vector<16 x 
!cir.float>) -> !cir.float
+  // CIR: cir.call @_mm512_reduce_min_ps(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<16 x !cir.float>) -> !cir.float
 
   // LLVM-LABEL: test_mm512_reduce_min_ps
   // LLVM: call float @llvm.vector.reduce.fmin.v16f32(<16 x float> %{{.*}})

diff  --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c 
b/clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c
index 74e40c0d5a76e..399dfee75d81c 100644
--- a/clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c
+++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c
@@ -70,7 +70,7 @@ _Float16 test_mm512_reduce_add_ph(__m512h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : 
(!cir.f16, !cir.vector<32 x !cir.f16>) -> !cir.f16
 
   // CIR-LABEL: test_mm512_reduce_add_ph
-  // CIR: cir.call @_mm512_reduce_add_ph(%[[VEC:.*]]) : (!cir.vector<32 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm512_reduce_add_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<32 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm512_reduce_add_ph
   // LLVM: call half @llvm.vector.reduce.fadd.v32f16(half 0xH8000, <32 x half> 
%{{.*}})
@@ -85,7 +85,7 @@ _Float16 test_mm512_reduce_mul_ph(__m512h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : 
(!cir.f16, !cir.vector<32 x !cir.f16>) -> !cir.f16
 
   // CIR-LABEL: test_mm512_reduce_mul_ph
-  // CIR: cir.call @_mm512_reduce_mul_ph(%[[VEC:.*]]) : (!cir.vector<32 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm512_reduce_mul_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<32 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm512_reduce_mul_ph
   // LLVM: call half @llvm.vector.reduce.fmul.v32f16(half 0xH3C00, <32 x half> 
%{{.*}})
@@ -100,7 +100,7 @@ _Float16 test_mm512_reduce_max_ph(__m512h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] 
(!cir.vector<32 x !cir.f16>) -> !cir.f16 
 
   // CIR-LABEL: test_mm512_reduce_max_ph
-  // CIR: cir.call @_mm512_reduce_max_ph(%[[VEC:.*]]) : (!cir.vector<32 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm512_reduce_max_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<32 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm512_reduce_max_ph
   // LLVM: call half @llvm.vector.reduce.fmax.v32f16(<32 x half> %{{.*}})
@@ -115,7 +115,7 @@ _Float16 test_mm512_reduce_min_ph(__m512h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] 
(!cir.vector<32 x !cir.f16>) -> !cir.f16 
 
   // CIR-LABEL: test_mm512_reduce_min_ph
-  // CIR: cir.call @_mm512_reduce_min_ph(%[[VEC:.*]]) : (!cir.vector<32 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm512_reduce_min_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<32 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm512_reduce_min_ph
   // LLVM: call half @llvm.vector.reduce.fmin.v32f16(<32 x half> %{{.*}})

diff  --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c 
b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c
index d1e9a030e637c..1c8d68c1ab69e 100644
--- a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c
+++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c
@@ -9,7 +9,7 @@
 
 __m256bh test_mm512_mask_cvtneps_pbh(__m256bh src, __mmask16 k, __m512 a) {
   // CIR-LABEL: test_mm512_mask_cvtneps_pbh
-  // CIR: cir.call @_mm512_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) : 
(!cir.vector<16 x !cir.bf16>, !u16i, !cir.vector<16 x !cir.float>) -> 
!cir.vector<16 x !cir.bf16>
+  // CIR: cir.call @_mm512_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) 
{nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.bf16>, !u16i, !cir.vector<16 x 
!cir.float>) -> !cir.vector<16 x !cir.bf16>
 
   // LLVM-LABEL: @test_mm512_mask_cvtneps_pbh
   // LLVM: call <16 x bfloat> @llvm.x86.avx512bf16.cvtneps2bf16.512
@@ -21,7 +21,7 @@ __m256bh test_mm512_mask_cvtneps_pbh(__m256bh src, __mmask16 
k, __m512 a) {
 
 __m256bh test_mm512_maskz_cvtneps_pbh(__mmask16 k, __m512 a) {
   // CIR-LABEL: test_mm512_maskz_cvtneps_pbh
-  // CIR: cir.call @_mm512_maskz_cvtneps_pbh({{.+}}, {{.+}}) : (!u16i, 
!cir.vector<16 x !cir.float>) -> !cir.vector<16 x !cir.bf16>
+  // CIR: cir.call @_mm512_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltins = 
[{{.*}}]} : (!u16i, !cir.vector<16 x !cir.float>) -> !cir.vector<16 x !cir.bf16>
 
   // LLVM-LABEL: @test_mm512_maskz_cvtneps_pbh
   // LLVM: call <16 x bfloat> @llvm.x86.avx512bf16.cvtneps2bf16.512(<16 x 
float> {{.+}})
@@ -34,7 +34,7 @@ __m256bh test_mm512_maskz_cvtneps_pbh(__mmask16 k, __m512 a) {
 
 __m128bh test_mm256_mask_cvtneps_pbh(__m128bh src, __mmask8 k, __m256 a) {
   // CIR-LABEL: test_mm256_mask_cvtneps_pbh
-  // CIR: cir.call @_mm256_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) : 
(!cir.vector<8 x !cir.bf16>, !u8i, !cir.vector<8 x !cir.float>) -> 
!cir.vector<8 x !cir.bf16>
+  // CIR: cir.call @_mm256_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) 
{nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.bf16>, !u8i, !cir.vector<8 x 
!cir.float>) -> !cir.vector<8 x !cir.bf16>
   
   // LLVM-LABEL: @test_mm256_mask_cvtneps_pbh
   // LLVM: call <8 x bfloat> @llvm.x86.avx512bf16.cvtneps2bf16.256(<8 x float> 
{{.+}})
@@ -46,7 +46,7 @@ __m128bh test_mm256_mask_cvtneps_pbh(__m128bh src, __mmask8 
k, __m256 a) {
 
 __m128bh test_mm256_maskz_cvtneps_pbh(__mmask8 k, __m256 a) {
   // CIR-LABEL: test_mm256_maskz_cvtneps_pbh
-  // CIR: cir.call @_mm256_maskz_cvtneps_pbh({{.+}}, {{.+}}) : (!u8i, 
!cir.vector<8 x !cir.float>) -> !cir.vector<8 x !cir.bf16>
+  // CIR: cir.call @_mm256_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltins = 
[{{.*}}]} : (!u8i, !cir.vector<8 x !cir.float>) -> !cir.vector<8 x !cir.bf16>
 
   // LLVM-LABEL: @test_mm256_maskz_cvtneps_pbh
   // LLVM: call <8 x bfloat> @llvm.x86.avx512bf16.cvtneps2bf16.256(<8 x float> 
{{.+}})
@@ -58,7 +58,7 @@ __m128bh test_mm256_maskz_cvtneps_pbh(__mmask8 k, __m256 a) {
 
 __m128bh test_mm_mask_cvtneps_pbh(__m128bh src, __mmask8 k, __m128 a) {
   // CIR-LABEL: test_mm_mask_cvtneps_pbh
-  // CIR: cir.call @_mm_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) : 
(!cir.vector<8 x !cir.bf16>, !u8i, !cir.vector<4 x !cir.float>) -> 
!cir.vector<8 x !cir.bf16>{{.+}}
+  // CIR: cir.call @_mm_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) {nobuiltins = 
[{{.*}}]} : (!cir.vector<8 x !cir.bf16>, !u8i, !cir.vector<4 x !cir.float>) -> 
!cir.vector<8 x !cir.bf16>{{.+}}
 
   // LLVM-LABEL: @test_mm_mask_cvtneps_pbh
   // LLVM: call <8 x bfloat> @llvm.x86.avx512bf16.mask.cvtneps2bf16.128(<4 x 
float> {{.+}}, <8 x bfloat> {{.+}}, <4 x i1> {{.+}})
@@ -70,7 +70,7 @@ __m128bh test_mm_mask_cvtneps_pbh(__m128bh src, __mmask8 k, 
__m128 a) {
 
 __m128bh test_mm_maskz_cvtneps_pbh(__mmask8 k, __m128 a) {
   // CIR-LABEL: test_mm_maskz_cvtneps_pbh
-  // CIR: cir.call @_mm_maskz_cvtneps_pbh({{.+}}, {{.+}}) : (!u8i, 
!cir.vector<4 x !cir.float>) -> !cir.vector<8 x !cir.bf16>
+  // CIR: cir.call @_mm_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltins = 
[{{.*}}]} : (!u8i, !cir.vector<4 x !cir.float>) -> !cir.vector<8 x !cir.bf16>
   
   // LLVM-LABEL: @test_mm_maskz_cvtneps_pbh
   // LLVM: call <8 x bfloat> @llvm.x86.avx512bf16.mask.cvtneps2bf16.128(<4 x 
float> {{.+}}, <8 x bfloat> {{.+}}, <4 x i1> {{.+}})

diff  --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c 
b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c
index 994fdfec23c2c..d3eaa8c66d273 100644
--- a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c
+++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c
@@ -12,7 +12,7 @@ _Float16 test_mm256_reduce_add_ph(__m256h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : 
(!cir.f16, !cir.vector<16 x !cir.f16>) -> !cir.f16
 
   // CIR-LABEL: test_mm256_reduce_add_ph
-  // CIR: cir.call @_mm256_reduce_add_ph(%[[VEC:.*]]) : (!cir.vector<16 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm256_reduce_add_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<16 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm256_reduce_add_ph
   // LLVM: call half @llvm.vector.reduce.fadd.v16f16(half 0xH8000, <16 x half> 
%{{.*}})
@@ -27,7 +27,7 @@ _Float16 test_mm256_reduce_mul_ph(__m256h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : 
(!cir.f16, !cir.vector<16 x !cir.f16>) -> !cir.f16
 
   // CIR-LABEL: test_mm256_reduce_mul_ph
-  // CIR: cir.call @_mm256_reduce_mul_ph(%[[VEC:.*]]) : (!cir.vector<16 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm256_reduce_mul_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<16 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm256_reduce_mul_ph
   // LLVM: call half @llvm.vector.reduce.fmul.v16f16(half 0xH3C00, <16 x half> 
%{{.*}})
@@ -42,7 +42,7 @@ _Float16 test_mm256_reduce_max_ph(__m256h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] 
(!cir.vector<16 x !cir.f16>) -> !cir.f16 
 
   // CIR-LABEL: test_mm256_reduce_max_ph
-  // CIR: cir.call @_mm256_reduce_max_ph(%[[VEC:.*]]) : (!cir.vector<16 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm256_reduce_max_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<16 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm256_reduce_max_ph
   // LLVM: call half @llvm.vector.reduce.fmax.v16f16(<16 x half> %{{.*}})
@@ -57,7 +57,7 @@ _Float16 test_mm256_reduce_min_ph(__m256h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] : 
(!cir.vector<16 x !cir.f16>) -> !cir.f16
 
   // CIR-LABEL: test_mm256_reduce_min_ph
-  // CIR: cir.call @_mm256_reduce_min_ph(%[[VEC:.*]]) : (!cir.vector<16 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm256_reduce_min_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} 
: (!cir.vector<16 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm256_reduce_min_ph
   // LLVM: call half @llvm.vector.reduce.fmin.v16f16(<16 x half> %{{.*}})
@@ -72,7 +72,7 @@ _Float16 test_mm_reduce_add_ph(__m128h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : 
(!cir.f16, !cir.vector<8 x !cir.f16>) -> !cir.f16
 
   // CIR-LABEL: test_mm_reduce_add_ph
-  // CIR: cir.call @_mm_reduce_add_ph(%[[VEC:.*]]) : (!cir.vector<8 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm_reduce_add_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : 
(!cir.vector<8 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm_reduce_add_ph
   // LLVM: call half @llvm.vector.reduce.fadd.v8f16(half 0xH8000, <8 x half> 
%{{.*}})
@@ -87,7 +87,7 @@ _Float16 test_mm_reduce_mul_ph(__m128h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : 
(!cir.f16, !cir.vector<8 x !cir.f16>) -> !cir.f16
 
   // CIR-LABEL: test_mm_reduce_mul_ph
-  // CIR: cir.call @_mm_reduce_mul_ph(%[[VEC:.*]]) : (!cir.vector<8 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm_reduce_mul_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : 
(!cir.vector<8 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm_reduce_mul_ph
   // LLVM: call half @llvm.vector.reduce.fmul.v8f16(half 0xH3C00, <8 x half> 
%{{.*}})
@@ -102,7 +102,7 @@ _Float16 test_mm_reduce_max_ph(__m128h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] 
(!cir.vector<8 x !cir.f16>) -> !cir.f16 
 
   // CIR-LABEL: test_mm_reduce_max_ph
-  // CIR: cir.call @_mm_reduce_max_ph(%[[VEC:.*]]) : (!cir.vector<8 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm_reduce_max_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : 
(!cir.vector<8 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm_reduce_max_ph
   // LLVM: call half @llvm.vector.reduce.fmax.v8f16(<8 x half> %{{.*}})
@@ -117,7 +117,7 @@ _Float16 test_mm_reduce_min_ph(__m128h __W) {
   // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] : 
(!cir.vector<8 x !cir.f16>) -> !cir.f16
 
   // CIR-LABEL: test_mm_reduce_min_ph
-  // CIR: cir.call @_mm_reduce_min_ph(%[[VEC:.*]]) : (!cir.vector<8 x 
!cir.f16>) -> !cir.f16
+  // CIR: cir.call @_mm_reduce_min_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : 
(!cir.vector<8 x !cir.f16>) -> !cir.f16
 
   // LLVM-LABEL: test_mm_reduce_min_ph
   // LLVM: call half @llvm.vector.reduce.fmin.v8f16(<8 x half> %{{.*}})

diff  --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td 
b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
index 3bf4875678a9d..e2358dcf1ed4c 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td
@@ -799,6 +799,7 @@ def LLVM_CallOp
       UnitAttr:$cold, UnitAttr:$noduplicate,
       UnitAttr:$no_caller_saved_registers, UnitAttr:$nocallback,
       OptionalAttr<StrAttr>:$modular_format,
+      OptionalAttr<ArrayAttr>:$nobuiltins,
       VariadicOfVariadic<LLVM_Type, "op_bundle_sizes">:$op_bundle_operands,
       DenseI32ArrayAttr:$op_bundle_sizes,
       OptionalAttr<ArrayAttr>:$op_bundle_tags,
@@ -2005,6 +2006,7 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [
     OptionalAttr<UnitAttr>:$no_caller_saved_registers,
     OptionalAttr<UnitAttr>:$nocallback,
     OptionalAttr<StrAttr>:$modular_format,
+    OptionalAttr<ArrayAttr>:$nobuiltins,
     OptionalAttr<LLVM_VecTypeHintAttr>:$vec_type_hint,
     OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint,
     OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size,

diff  --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h 
b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index 039ac8e2e1911..a9b6a58b30e10 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -349,6 +349,27 @@ class ModuleTranslation {
 
   SymbolTableCollection &symbolTable() { return symbolTableCollection; }
 
+  // A helper callback that takes an attribute, and if it is a StringAttr,
+  // properly converts it to the 'no-builtin-VALUE' form.
+  static std::optional<std::string> convertNoBuiltin(mlir::Attribute a) {
+    if (auto str = dyn_cast<StringAttr>(a))
+      return ("no-builtin-" + str.getValue()).str();
+    return std::nullopt;
+  }
+
+  /// A template that takes an ArrayAttr, converts it via a user provided
+  /// callback, then adds each element to as function attributes to the 
provided
+  /// operation.
+  template <typename Operation, typename Converter>
+  void convertFunctionArrayAttr(ArrayAttr array, Operation *op,
+                                const Converter &conv) {
+    for (Attribute a : array) {
+      auto result = conv(a);
+      if (result)
+        op->addFnAttr(llvm::Attribute::get(getLLVMContext(), *result));
+    }
+  }
+
 private:
   ModuleTranslation(Operation *module,
                     std::unique_ptr<llvm::Module> llvmModule);

diff  --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp 
b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
index fa7e9e53cfec7..34d0de078e553 100644
--- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
+++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp
@@ -998,7 +998,7 @@ void CallOp::build(OpBuilder &builder, OperationState 
&state, TypeRange results,
         /*noreturn=*/nullptr, /*returns_twice=*/nullptr, /*hot=*/nullptr,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
         /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr,
-        /*modular_format=*/nullptr,
+        /*modular_format=*/nullptr, /*nobuiltins=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
@@ -1033,7 +1033,7 @@ void CallOp::build(OpBuilder &builder, OperationState 
&state,
         /*returns_twice=*/nullptr, /*hot=*/nullptr,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
         /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr,
-        /*modular_format=*/nullptr,
+        /*modular_format=*/nullptr, /*nobuiltins=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr,
@@ -1054,7 +1054,7 @@ void CallOp::build(OpBuilder &builder, OperationState 
&state,
         /*returns_twice=*/nullptr, /*hot=*/nullptr,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
         /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr,
-        /*modular_format=*/nullptr,
+        /*modular_format=*/nullptr, /*nobuiltins=*/nullptr,
         /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{},
         /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr,
         /*access_groups=*/nullptr, /*alias_scopes=*/nullptr,
@@ -1075,7 +1075,7 @@ void CallOp::build(OpBuilder &builder, OperationState 
&state, LLVMFuncOp func,
         /*returns_twice=*/nullptr, /*hot=*/nullptr,
         /*cold=*/nullptr, /*noduplicate=*/nullptr,
         /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr,
-        /*modular_format=*/nullptr,
+        /*modular_format=*/nullptr, /*nobuiltins=*/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 e32719f10d7c1..68c634538d92b 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -447,6 +447,15 @@ convertOperationImpl(Operation &opInst, 
llvm::IRBuilderBase &builder,
                                            "modular-format",
                                            modFormat.getValue()));
 
+    if (ArrayAttr noBuiltins = callOp.getNobuiltinsAttr()) {
+      if (noBuiltins.empty())
+        
call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(),
+                                             "no-builtins"));
+
+      moduleTranslation.convertFunctionArrayAttr(
+          noBuiltins, call, ModuleTranslation::convertNoBuiltin);
+    }
+
     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 deaeb98d9abdc..feb5011a5cc91 100644
--- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp
@@ -1419,10 +1419,10 @@ LogicalResult 
ModuleImport::convertIFunc(llvm::GlobalIFunc *ifunc) {
 /// Converts LLVM string, integer, and enum attributes into MLIR attributes,
 /// skipping those in `attributesToSkip` and emitting a warning at `loc` for
 /// any other unsupported attributes.
-static ArrayAttr
-convertLLVMAttributesToMLIR(Location loc, MLIRContext *context,
-                            llvm::AttributeSet attributes,
-                            ArrayRef<StringLiteral> attributesToSkip = {}) {
+static ArrayAttr convertLLVMAttributesToMLIR(
+    Location loc, MLIRContext *context, llvm::AttributeSet attributes,
+    ArrayRef<StringLiteral> attributesToSkip = {},
+    ArrayRef<StringLiteral> attributePrefixesToSkip = {}) {
   SmallVector<Attribute> mlirAttributes;
   for (llvm::Attribute attr : attributes) {
     StringRef attrName;
@@ -1433,6 +1433,13 @@ convertLLVMAttributesToMLIR(Location loc, MLIRContext 
*context,
     if (llvm::is_contained(attributesToSkip, attrName))
       continue;
 
+    auto attrNameStartsWith = [attrName](StringLiteral sl) {
+      return attrName.starts_with(sl);
+    };
+    if (attributePrefixesToSkip.end() !=
+        llvm::find_if(attributePrefixesToSkip, attrNameStartsWith))
+      continue;
+
     auto keyAttr = StringAttr::get(context, attrName);
     if (attr.isStringAttribute()) {
       StringRef val = attr.getValueAsString();
@@ -2669,6 +2676,7 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{
     StringLiteral("no-infs-fp-math"),
     StringLiteral("no-nans-fp-math"),
     StringLiteral("no-signed-zeros-fp-math"),
+    StringLiteral("no-builtins"),
     StringLiteral("nocallback"),
     StringLiteral("noduplicate"),
     StringLiteral("noinline"),
@@ -2683,15 +2691,49 @@ static constexpr std::array 
kExplicitLLVMFuncOpAttributes{
     StringLiteral("willreturn"),
 };
 
+// List of LLVM IR attributes that are handled by prefix to map onto an MLIR
+// LLVMFuncOp.
+static constexpr std::array kExplicitLLVMFuncOpAttributePrefixes{
+    StringLiteral("no-builtin-"),
+};
+
+template <typename OpTy>
+static void convertNoBuiltinAttrs(MLIRContext *ctx,
+                                  const llvm::AttributeSet &attrs,
+                                  OpTy target) {
+  // 'no-builtins' is the complete collection, and overrides all the rest.
+  if (attrs.hasAttribute("no-builtins")) {
+    target.setNobuiltinsAttr(ArrayAttr::get(ctx, {}));
+    return;
+  }
+
+  llvm::SetVector<Attribute> nbAttrs;
+  for (llvm::Attribute attr : attrs) {
+    // Attributes that are part of llvm directly (that is, have an 
AttributeKind
+    // in the enum) shouldn't be checked.
+    if (attr.hasKindAsEnum())
+      continue;
+
+    StringRef val = attr.getKindAsString();
+
+    if (val.starts_with("no-builtin-"))
+      nbAttrs.insert(
+          StringAttr::get(ctx, val.drop_front(sizeof("no-builtin-") - 1)));
+  }
+
+  if (!nbAttrs.empty())
+    target.setNobuiltinsAttr(ArrayAttr::get(ctx, nbAttrs.getArrayRef()));
+}
+
 /// Converts LLVM attributes from `func` into MLIR attributes and adds them
 /// to `funcOp` as passthrough attributes, skipping those listed in
 /// `kExplicitLLVMFuncAttributes`.
 static void processPassthroughAttrs(llvm::Function *func, LLVMFuncOp funcOp) {
   llvm::AttributeSet funcAttrs = func->getAttributes().getAttributes(
       llvm::AttributeList::AttrIndex::FunctionIndex);
-  ArrayAttr passthroughAttr =
-      convertLLVMAttributesToMLIR(funcOp.getLoc(), funcOp.getContext(),
-                                  funcAttrs, kExplicitLLVMFuncOpAttributes);
+  ArrayAttr passthroughAttr = convertLLVMAttributesToMLIR(
+      funcOp.getLoc(), funcOp.getContext(), funcAttrs,
+      kExplicitLLVMFuncOpAttributes, kExplicitLLVMFuncOpAttributePrefixes);
   if (!passthroughAttr.empty())
     funcOp.setPassthroughAttr(passthroughAttr);
 }
@@ -2751,6 +2793,8 @@ void 
ModuleImport::processFunctionAttributes(llvm::Function *func,
   else if (func->hasFnAttribute("aarch64_preserves_za"))
     funcOp.setArmPreservesZa(true);
 
+  convertNoBuiltinAttrs(context, func->getAttributes().getFnAttrs(), funcOp);
+
   llvm::Attribute attr = func->getFnAttribute(llvm::Attribute::VScaleRange);
   if (attr.isValid()) {
     MLIRContext *context = funcOp.getContext();
@@ -2991,6 +3035,8 @@ LogicalResult 
ModuleImport::convertCallAttributes(llvm::CallInst *inst,
   if (!memAttr.isReadWrite())
     op.setMemoryEffectsAttr(memAttr);
 
+  convertNoBuiltinAttrs(op.getContext(), callAttrs.getFnAttrs(), op);
+
   return convertCallBaseAttributes(inst, op);
 }
 

diff  --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp 
b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 437701a48e460..e87b4a6502359 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1660,7 +1660,7 @@ static void convertFunctionMemoryAttributes(LLVMFuncOp 
func,
 }
 
 /// Converts function attributes from `func` and attaches them to `llvmFunc`.
-static void convertFunctionAttributes(LLVMFuncOp func,
+static void convertFunctionAttributes(ModuleTranslation &mod, LLVMFuncOp func,
                                       llvm::Function *llvmFunc) {
   if (func.getNoInlineAttr())
     llvmFunc->addFnAttr(llvm::Attribute::NoInline);
@@ -1700,6 +1700,15 @@ static void convertFunctionAttributes(LLVMFuncOp func,
   if (UWTableKindAttr uwTableKindAttr = func.getUwtableKindAttr())
     llvmFunc->setUWTableKind(
         convertUWTableKindToLLVM(uwTableKindAttr.getUwtableKind()));
+
+  if (ArrayAttr noBuiltins = func.getNobuiltinsAttr()) {
+    if (noBuiltins.empty())
+      llvmFunc->addFnAttr("no-builtins");
+
+    mod.convertFunctionArrayAttr(noBuiltins, llvmFunc,
+                                 ModuleTranslation::convertNoBuiltin);
+  }
+
   convertFunctionMemoryAttributes(func, llvmFunc);
 }
 
@@ -1869,7 +1878,7 @@ LogicalResult 
ModuleTranslation::convertFunctionSignatures() {
     addRuntimePreemptionSpecifier(function.getDsoLocal(), llvmFunc);
 
     // Convert function attributes.
-    convertFunctionAttributes(function, llvmFunc);
+    convertFunctionAttributes(*this, function, llvmFunc);
 
     // Convert function kernel attributes to metadata.
     convertFunctionKernelAttributes(function, llvmFunc, *this);

diff  --git a/mlir/test/Dialect/LLVMIR/func.mlir 
b/mlir/test/Dialect/LLVMIR/func.mlir
index e57a54cb43267..2f1bd0eb96910 100644
--- a/mlir/test/Dialect/LLVMIR/func.mlir
+++ b/mlir/test/Dialect/LLVMIR/func.mlir
@@ -372,6 +372,18 @@ module {
     llvm.return
   }
 
+  llvm.func @no_builtins_all() attributes { nobuiltins = [] } {
+    // CHECK: @no_builtins_all
+    // CHECK-SAME: attributes {nobuiltins = []}
+    llvm.return
+  }
+
+  llvm.func @no_builtins_2() attributes { nobuiltins = ["foo", "bar"] } {
+    // CHECK: @no_builtins_2
+    // CHECK-SAME: attributes {nobuiltins = ["foo", "bar"]}
+    llvm.return
+  }
+
 }
 
 // -----

diff  --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir 
b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
index c97574f41e8a4..2d1a383274e97 100644
--- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir
+++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir
@@ -149,6 +149,12 @@ func.func @ops(%arg0: i32, %arg1: f32,
 // 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>} : () -> ()
 
+// CHECK: llvm.call @baz() {nobuiltins = []} : () -> ()
+  llvm.call @baz() {nobuiltins = []} : () -> ()
+
+// CHECK: llvm.call @baz() {nobuiltins = ["asdf", "defg"]} : () -> ()
+  llvm.call @baz() {nobuiltins = ["asdf", "defg"]} : () -> ()
+
 // Terminator operations and their successors.
 //
 // CHECK: llvm.br ^[[BB1:.*]]

diff  --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll 
b/mlir/test/Target/LLVMIR/Import/function-attributes.ll
index 153912fbae34a..f4a060280a95c 100644
--- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll
+++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll
@@ -459,5 +459,17 @@ declare void @modular_format_attribute(i32) 
"modular-format" = "Ident,1,1,Foo,Ba
 
 // -----
 
+; CHECK-LABEL: @no_builtins_all
+; CHECK-SAME: attributes {nobuiltins = []}
+declare void @no_builtins_all() "no-builtins"
+
+// -----
+
+; CHECK-LABEL: @no_builtins_2
+; CHECK-SAME: attributes {nobuiltins = ["asdf", "defg"]}
+declare void @no_builtins_2() "no-builtin-asdf" "no-builtin-defg"
+
+// -----
+
 ; 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 9b3ad17c31a28..cf3962a92c46c 100644
--- a/mlir/test/Target/LLVMIR/Import/instructions.ll
+++ b/mlir/test/Target/LLVMIR/Import/instructions.ll
@@ -798,6 +798,30 @@ define void @call_modular_format() {
 ; CHECK: llvm.func @f()
 declare void @f()
 
+; CHECK-LABEL: @call_nobuiltins_all
+define void @call_nobuiltins_all() {
+; CHECK: llvm.call @f() {nobuiltins = []}
+  call void @f() "no-builtins"
+  ret void
+}
+
+; // -----
+
+; CHECK: llvm.func @f()
+declare void @f()
+
+; CHECK-LABEL: @call_nobuiltins_2
+define void @call_nobuiltins_2() {
+; CHECK: llvm.call @f() {nobuiltins = ["asdf", "ghij"]}
+  call void @f() "no-builtin-asdf" "no-builtin-ghij"
+  ret void
+}
+
+; // -----
+
+; CHECK: llvm.func @f()
+declare void @f()
+
 ; CHECK-LABEL: @call_memory_effects
 define void @call_memory_effects() {
 ; CHECK: llvm.call @f() {memory_effects = #llvm.memory_effects<other = none, 
argMem = none, inaccessibleMem = none, errnoMem = none, targetMem0 = none, 
targetMem1 = none>}

diff  --git a/mlir/test/Target/LLVMIR/llvmir.mlir 
b/mlir/test/Target/LLVMIR/llvmir.mlir
index 978199fbfb1a1..ba566e7931359 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2719,6 +2719,58 @@ llvm.func @modular_format(%arg : i32) attributes { 
modular_format = "ident,1,1,f
 
 // -----
 
+// CHECK-LABEL: @no_builtins_all
+// CHECK-SAME: #[[ATTRS:[0-9]+]]
+llvm.func @no_builtins_all() attributes { nobuiltins = [] } {
+  llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: no-builtins
+
+// -----
+
+// CHECK-LABEL: @no_builtins_2
+// CHECK-SAME: #[[ATTRS:[0-9]+]]
+llvm.func @no_builtins_2() attributes { nobuiltins = ["asdf", "defg"] } {
+  llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: no-builtin-asdf
+// CHECK-SAME: no-builtin-defg
+
+// -----
+
+llvm.func @f()
+
+// CHECK-LABEL: @no_builtins_call_all
+// CHECK: call void @f() #[[ATTRS:[0-9]+]]
+llvm.func @no_builtins_call_all() {
+  llvm.call @f() {nobuiltins = [] } : () -> ()
+  llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: no-builtins
+
+// -----
+
+llvm.func @f()
+
+// CHECK-LABEL: @no_builtins_call_2
+// CHECK: call void @f() #[[ATTRS:[0-9]+]]
+llvm.func @no_builtins_call_2() {
+  llvm.call @f() {nobuiltins = ["asdf", "defg"] } : () -> ()
+  llvm.return
+}
+
+// CHECK: #[[ATTRS]]
+// CHECK-SAME: no-builtin-asdf
+// CHECK-SAME: no-builtin-defg
+
+// -----
+
 llvm.func @f()
 
 // CHECK-LABEL: @convergent_call


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to