https://github.com/erichkeane created 
https://github.com/llvm/llvm-project/pull/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.

>From e1427c2ec1484b600cd231658d5bc7a71136a444 Mon Sep 17 00:00:00 2001
From: erichkeane <[email protected]>
Date: Wed, 28 Jan 2026 07:21:56 -0800
Subject: [PATCH] [CIR] Implement lowering for 'no-builtins' attributes

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.
---
 .../clang/CIR/Dialect/IR/CIRDialect.td        |   1 +
 clang/lib/CIR/CodeGen/CIRGenCall.cpp          |  52 ++++-
 clang/test/CIR/CodeGen/no-builtin-attr.cpp    | 204 ++++++++++++++++++
 .../CodeGenBuiltins/X86/avx512-reduceIntrin.c |   8 +-
 .../X86/avx512-reduceMinMaxIntrin.c           |   8 +-
 .../CodeGenBuiltins/X86/avx512fp16-builtins.c |   8 +-
 .../X86/avx512vlbf16-builtins.c               |  12 +-
 .../X86/avx512vlfp16-builtins.c               |  16 +-
 mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td   |   2 +
 mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp    |   8 +-
 .../LLVMIR/LLVMToLLVMIRTranslation.cpp        |  14 ++
 mlir/lib/Target/LLVMIR/ModuleImport.cpp       |  66 +++++-
 mlir/lib/Target/LLVMIR/ModuleTranslation.cpp  |  13 ++
 mlir/test/Dialect/LLVMIR/func.mlir            |  12 ++
 mlir/test/Dialect/LLVMIR/roundtrip.mlir       |   6 +
 .../LLVMIR/Import/function-attributes.ll      |  12 ++
 .../test/Target/LLVMIR/Import/instructions.ll |  24 +++
 mlir/test/Target/LLVMIR/llvmir.mlir           |  23 ++
 18 files changed, 450 insertions(+), 39 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/no-builtin-attr.cpp

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..46118300d5a9e 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -111,6 +111,45 @@ 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::SmallVector<mlir::Attribute> nbFuncs;
+  auto addNoBuiltinAttr = [&ctx, &nbFuncs](StringRef builtinName) {
+    auto attrMatches = [=](mlir::Attribute a) {
+      return mlir::cast<mlir::StringAttr>(a).getValue() == builtinName;
+    };
+    if (nbFuncs.end() == llvm::find_if(nbFuncs, attrMatches))
+      nbFuncs.push_back(mlir::StringAttr::get(&ctx, builtinName));
+  };
+
+  // Then, add attributes for builtins specified through -fno-builtin-<name>.
+  llvm::for_each(langOpts.NoBuiltinFuncs, addNoBuiltinAttr);
+
+  if (nba) {
+    // Now, let's check the __attribute__((no_builtin("...")) attribute added 
to
+    // the source.
+    llvm::for_each(nba->builtinNames(), addNoBuiltinAttr);
+  }
+
+  if (!nbFuncs.empty())
+    attrs.set(cir::CIRDialect::getNoBuiltinsAttrName(),
+              mlir::ArrayAttr::get(&ctx, nbFuncs));
+}
+
 /// Construct the CIR attribute list of a function or call.
 void CIRGenModule::constructAttributeList(llvm::StringRef name,
                                           const CIRGenFunctionInfo &info,
@@ -137,6 +176,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 +219,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>();
       }
     }
 
@@ -230,7 +276,9 @@ void CIRGenModule::constructAttributeList(llvm::StringRef 
name,
                 builder.getStringAttr(llvm::join(args, ",")));
     }
 
-    // TODO(cir): We should set nobuiltin and default function attrs here.
+    addNoBuiltinAttributes(getMLIRContext(), attrs, getLangOpts(), nba);
+
+    // 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
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..e10c7cbd104c4 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..334b41f6db526 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..92bb9cf0dc02a 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..c6356263b96c1 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..995521f686d9b 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/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..8cb4528a2ab44 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp
@@ -447,6 +447,20 @@ 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"));
+
+      for (Attribute a : noBuiltins) {
+        if (auto str = dyn_cast<StringAttr>(a)) {
+          std::string attrName = ("no-builtin-" + str.getValue()).str();
+          call->addFnAttr(llvm::Attribute::get(
+              moduleTranslation.getLLVMContext(), attrName));
+        }
+      }
+    }
+
     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..d666434f61f41 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,55 @@ 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(mlir::ArrayAttr::get(ctx, {}));
+    return;
+  }
+
+  llvm::SmallVector<mlir::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-")) {
+      StringRef str = val.drop_front(sizeof("no-builtin-") - 1);
+
+      if (nbAttrs.end() == llvm::find_if(nbAttrs, [str](Attribute a) {
+            return mlir::cast<StringAttr>(a).getValue() == str;
+          }))
+        nbAttrs.push_back(mlir::StringAttr::get(
+            ctx, val.drop_front(sizeof("no-builtin-") - 1)));
+    }
+  }
+
+  if (!nbAttrs.empty())
+    target.setNobuiltinsAttr(mlir::ArrayAttr::get(ctx, nbAttrs));
+}
+
 /// 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 +2799,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 +3041,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..4b6b1b70a7f9e 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -1700,6 +1700,19 @@ 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");
+
+    for (Attribute a : noBuiltins) {
+      if (auto str = dyn_cast<StringAttr>(a)) {
+        std::string attrName = ("no-builtin-" + str.getValue()).str();
+        llvmFunc->addFnAttr(attrName);
+      }
+    }
+  }
+
   convertFunctionMemoryAttributes(func, llvmFunc);
 }
 
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..da5328af12773 100644
--- a/mlir/test/Target/LLVMIR/llvmir.mlir
+++ b/mlir/test/Target/LLVMIR/llvmir.mlir
@@ -2719,6 +2719,29 @@ 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(%arg : i32) 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(%arg : i32) attributes { 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