[clang] [CIR][CodeGen] Implement target-features checking(CodeGenUtils!) (PR #223056)

Erich Keane via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 11 13:51:44 PDT 2026


https://github.com/erichkeane created https://github.com/llvm/llvm-project/pull/223056

This DOES move checking functions out of CodeGen and into CodeGenUtils so both can use it.

This is a diagnostic for builtins/etc that is built in to classic codegen.  We have to implement it, because otherwise autoconfig thinks that we support AVX without a flag, and thus causes us to fail builds later on that now expect __AVX__/etc to be defined without enabling them.

>From 4ddc1ad3d3ebaa86cbbe35dbcab49dc7e5ce48e0 Mon Sep 17 00:00:00 2001
From: erichkeane <ekeane at nvidia.com>
Date: Thu, 10 Sep 2026 15:16:14 -0700
Subject: [PATCH] [CIR][CodeGen] Implement target-features
 checking(CodeGenUtils!)

This DOES move checking functions out of CodeGen and into
CodeGenUtils so both can use it.

This is a diagnostic for builtins/etc that is built in to classic
codegen.  We have to implement it, because otherwise autoconfig thinks
that we support AVX without a flag, and thus causes us to fail builds
later on that now expect __AVX__/etc to be defined without enabling
them.
---
 .../include/clang/CodeGenUtils/CodeGenUtils.h |  23 ++
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |  22 ++
 clang/lib/CIR/CodeGen/CIRGenCall.cpp          |  17 ++
 clang/lib/CIR/CodeGen/CIRGenFunction.h        |   7 +
 clang/lib/CIR/FrontendAction/CIRGenAction.cpp |   4 +
 clang/lib/CodeGen/CodeGenFunction.cpp         | 114 +---------
 clang/lib/CodeGenUtils/CodeGenUtils.cpp       | 118 ++++++++++
 clang/test/CIR/CodeGen/avx512-error.c         |  23 ++
 .../test/CIR/CodeGen/target-builtin-error-2.c |  13 ++
 .../test/CIR/CodeGen/target-builtin-error-3.c |  62 +++++
 clang/test/CIR/CodeGen/target-builtin-error.c |   8 +
 .../test/CIR/CodeGen/target-builtin-noerror.c | 215 ++++++++++++++++++
 .../CIR/CodeGen/target-features-error-2.c     |  50 ++++
 .../CIR/CodeGen/target-features-error-3.c     |  12 +
 .../CIR/CodeGen/target-features-error-4.c     |  12 +
 .../CIR/CodeGen/target-features-error-5.c     |  12 +
 .../test/CIR/CodeGen/target-features-error.c  |   7 +
 .../CIR/CodeGen/target-features-no-error-2.c  |  12 +
 .../CIR/CodeGen/target-features-no-error.c    |   9 +
 .../X86/avx512vlvbmi2-builtins.c              |   8 +-
 .../CIR/CodeGenBuiltins/X86/sqrt-builtins.c   |   6 +-
 .../CodeGenBuiltins/builtin-undef-rvalue.cpp  |   6 -
 22 files changed, 639 insertions(+), 121 deletions(-)
 create mode 100644 clang/test/CIR/CodeGen/avx512-error.c
 create mode 100644 clang/test/CIR/CodeGen/target-builtin-error-2.c
 create mode 100644 clang/test/CIR/CodeGen/target-builtin-error-3.c
 create mode 100644 clang/test/CIR/CodeGen/target-builtin-error.c
 create mode 100644 clang/test/CIR/CodeGen/target-builtin-noerror.c
 create mode 100644 clang/test/CIR/CodeGen/target-features-error-2.c
 create mode 100644 clang/test/CIR/CodeGen/target-features-error-3.c
 create mode 100644 clang/test/CIR/CodeGen/target-features-error-4.c
 create mode 100644 clang/test/CIR/CodeGen/target-features-error-5.c
 create mode 100644 clang/test/CIR/CodeGen/target-features-error.c
 create mode 100644 clang/test/CIR/CodeGen/target-features-no-error-2.c
 create mode 100644 clang/test/CIR/CodeGen/target-features-no-error.c

diff --git a/clang/include/clang/CodeGenUtils/CodeGenUtils.h b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
index 2ecae74d1f606..b24f457f9537c 100644
--- a/clang/include/clang/CodeGenUtils/CodeGenUtils.h
+++ b/clang/include/clang/CodeGenUtils/CodeGenUtils.h
@@ -10,6 +10,14 @@
 #define LLVM_CLANG_CODEGENUTILS_CODEGENUTILS_H
 
 #include "clang/AST/ASTContext.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+class CallExpr;
+class DiagnosticsEngine;
+class FunctionDecl;
+class LangOptions;
+} // namespace clang
 
 namespace clang::CodeGenUtils {
 /// Check whether we need to initialize any vtable pointers before calling this
@@ -37,6 +45,21 @@ bool hasUnwindExceptions(const LangOptions &LangOpts);
 bool isAAPCS(const TargetInfo &TargetInfo);
 
 bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit);
+
+/// Check that a call to a target-specific builtin has the required target
+/// features enabled in the caller, emitting an error diagnostic if not.
+/// \p caller is the FunctionDecl of the enclosing function (may be null).
+void checkTargetFeatures(ASTContext &Ctx, DiagnosticsEngine &Diags,
+                         const LangOptions &LangOpts, const CallExpr *E,
+                         const FunctionDecl *Caller,
+                         const FunctionDecl *TargetDecl);
+
+/// Overload taking a raw source location instead of a CallExpr.
+void checkTargetFeatures(ASTContext &Ctx, DiagnosticsEngine &Diags,
+                         const LangOptions &LangOpts, SourceLocation Loc,
+                         const FunctionDecl *Caller,
+                         const FunctionDecl *TargetDecl);
+
 } // namespace clang::CodeGenUtils
 
 #endif // LLVM_CLANG_CODEGENUTILS_CODEGENUTILS_H
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index c7ce147b68d61..e039f85851337 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -26,6 +26,7 @@
 #include "clang/Basic/OperatorKinds.h"
 #include "clang/CIR/Dialect/IR/CIRTypes.h"
 #include "clang/CIR/MissingFeatures.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -1236,6 +1237,20 @@ static cir::FuncType getIntrinsicType(CIRGenFunction &cgf,
   return cir::FuncType::get(context, argTypes, resultTy, isVarArg);
 }
 
+void CIRGenFunction::checkTargetFeatures(const CallExpr *e,
+                                         const FunctionDecl *targetDecl) {
+  const FunctionDecl *fd = dyn_cast_or_null<FunctionDecl>(curCodeDecl);
+  CodeGenUtils::checkTargetFeatures(getContext(), cgm.getDiags(), getLangOpts(),
+                                    e, fd, targetDecl);
+}
+
+void CIRGenFunction::checkTargetFeatures(SourceLocation loc,
+                                         const FunctionDecl *targetDecl) {
+  const FunctionDecl *fd = dyn_cast_or_null<FunctionDecl>(curCodeDecl);
+  CodeGenUtils::checkTargetFeatures(getContext(), cgm.getDiags(), getLangOpts(),
+                                    loc, fd, targetDecl);
+}
+
 RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
                                        const CallExpr *e,
                                        ReturnValueSlot returnValue) {
@@ -2998,6 +3013,13 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
     return emitLibraryCall(*this, fd, e,
                            emitScalarExpr(e->getCallee()).getDefiningOp());
 
+  // Check that a call to a target specific builtin has the correct target
+  // features.
+  // This is down here to avoid non-target specific builtins, however, if
+  // generic builtins start to require generic target features then we
+  // can move this up to the beginning of the function.
+  checkTargetFeatures(e, fd);
+
   // See if we have a target specific intrinsic.
   std::string name = getContext().BuiltinInfo.getName(builtinID);
   Intrinsic::ID intrinsicID = Intrinsic::not_intrinsic;
diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
index 2caf22d3beb88..b9c3472190553 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp
@@ -1218,6 +1218,23 @@ RValue CIRGenFunction::emitCall(const CIRGenFunctionInfo &funcInfo,
   SmallVector<mlir::Value, 16> cirCallArgs(args.size());
 
   const Decl *targetDecl = callee.getAbstractInfo().getCalleeDecl().getDecl();
+
+  if (const FunctionDecl *fd = dyn_cast_or_null<FunctionDecl>(targetDecl)) {
+    // We can only guarantee that a function is called from the correct
+    // context/function based on the appropriate target attributes,
+    // so only check in the case where we have both always_inline and target
+    // since otherwise we could be making a conditional call after a check for
+    // the proper cpu features (and it won't cause code generation issues due to
+    // function based code generation).
+    if ((targetDecl->hasAttr<AlwaysInlineAttr>() &&
+         (targetDecl->hasAttr<TargetAttr>() ||
+          (curFuncDecl && curFuncDecl->hasAttr<TargetAttr>()))) ||
+        (curFuncDecl && curFuncDecl->hasAttr<FlattenAttr>() &&
+         (curFuncDecl->hasAttr<TargetAttr>() ||
+          targetDecl->hasAttr<TargetAttr>())))
+      checkTargetFeatures(clangLoc.getBegin(), fd);
+  }
+
   const FunctionDecl *callerDecl = dyn_cast_or_null<FunctionDecl>(curCodeDecl);
   const FunctionDecl *calleeDecl = dyn_cast_or_null<FunctionDecl>(targetDecl);
 
diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h
index 86a8736980773..dc57fd826337b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenFunction.h
+++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h
@@ -2346,6 +2346,13 @@ class CIRGenFunction : public CIRGenTypeCache {
   emitTargetBuiltinExpr(unsigned builtinID, const clang::CallExpr *e,
                         ReturnValueSlot &returnValue);
 
+  /// Emit a diagnostic if the target features required by \p targetDecl are
+  /// not available in the calling function. Mirrors CodeGenFunction behavior.
+  void checkTargetFeatures(const clang::CallExpr *e,
+                           const clang::FunctionDecl *targetDecl);
+  void checkTargetFeatures(clang::SourceLocation loc,
+                           const clang::FunctionDecl *targetDecl);
+
   /// Given a value and its clang type, returns the value casted to its memory
   /// representation.
   /// Note: CIR defers most of the special casting to the final lowering passes
diff --git a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
index 66c2f9b7a8937..57c40121fb39b 100644
--- a/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
+++ b/clang/lib/CIR/FrontendAction/CIRGenAction.cpp
@@ -195,6 +195,10 @@ class CIRGenConsumer : public clang::ASTConsumer {
           MlirModule->print(out);
       }
 
+      // If errors occurred during codegen, stop before running the backend.
+      if (CI.getDiagnostics().hasErrorOccurred())
+        return;
+
       std::unique_ptr<llvm::Module> LLVMModule = lowerFromCIRToLLVMIR(
           MlirModule, LLVMCtx, C.getLangOpts().OpenMP, mlirSaveTempsOutFile,
           &CI.getVirtualFileSystem());
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 7e7f9a072f765..fe39235fcd4f6 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -36,6 +36,7 @@
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
+#include "clang/CodeGenUtils/CodeGenUtils.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/ScopeExit.h"
 #include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
@@ -2884,121 +2885,18 @@ void CGBuilderInserter::InsertHelper(
 // called function.
 void CodeGenFunction::checkTargetFeatures(const CallExpr *E,
                                           const FunctionDecl *TargetDecl) {
-  // SemaChecking cannot handle below x86 builtins because they have different
-  // parameter ranges with different TargetAttribute of caller.
-  if (CGM.getContext().getTargetInfo().getTriple().isX86()) {
-    unsigned BuiltinID = TargetDecl->getBuiltinID();
-    if (BuiltinID == X86::BI__builtin_ia32_cmpps ||
-        BuiltinID == X86::BI__builtin_ia32_cmpss ||
-        BuiltinID == X86::BI__builtin_ia32_cmppd ||
-        BuiltinID == X86::BI__builtin_ia32_cmpsd) {
-      const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl);
-      llvm::StringMap<bool> TargetFetureMap;
-      CGM.getContext().getFunctionFeatureMap(TargetFetureMap, FD);
-      llvm::APSInt Result =
-          *(E->getArg(2)->getIntegerConstantExpr(CGM.getContext()));
-      if (Result.getSExtValue() > 7 && !TargetFetureMap.lookup("avx"))
-        CGM.getDiags().Report(E->getBeginLoc(), diag::err_builtin_needs_feature)
-            << TargetDecl->getDeclName() << "avx";
-    }
-  }
-  return checkTargetFeatures(E->getBeginLoc(), TargetDecl);
+  const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl);
+  CodeGenUtils::checkTargetFeatures(CGM.getContext(), CGM.getDiags(),
+                                    getLangOpts(), E, FD, TargetDecl);
 }
 
 // Emits an error if we don't have a valid set of target features for the
 // called function.
 void CodeGenFunction::checkTargetFeatures(SourceLocation Loc,
                                           const FunctionDecl *TargetDecl) {
-  // Early exit if this is an indirect call.
-  if (!TargetDecl)
-    return;
-
-  // Get the current enclosing function if it exists. If it doesn't
-  // we can't check the target features anyhow.
   const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurCodeDecl);
-  if (!FD)
-    return;
-
-  bool IsAlwaysInline = TargetDecl->hasAttr<AlwaysInlineAttr>();
-  bool IsFlatten = FD && FD->hasAttr<FlattenAttr>();
-
-  // Grab the required features for the call. For a builtin this is listed in
-  // the td file with the default cpu, for an always_inline function this is any
-  // listed cpu and any listed features.
-  unsigned BuiltinID = TargetDecl->getBuiltinID();
-  std::string MissingFeature;
-  llvm::StringMap<bool> CallerFeatureMap;
-  CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD);
-  // When compiling in HipStdPar mode we have to be conservative in rejecting
-  // target specific features in the FE, and defer the possible error to the
-  // AcceleratorCodeSelection pass, wherein iff an unsupported target builtin is
-  // referenced by an accelerator executable function, we emit an error.
-  bool IsHipStdPar = getLangOpts().HIPStdPar && getLangOpts().CUDAIsDevice;
-  if (BuiltinID) {
-    StringRef FeatureList(CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID));
-    if (!Builtin::evaluateRequiredTargetFeatures(
-        FeatureList, CallerFeatureMap) && !IsHipStdPar) {
-      CGM.getDiags().Report(Loc, diag::err_builtin_needs_feature)
-          << TargetDecl->getDeclName()
-          << FeatureList;
-    }
-  } else if (!TargetDecl->isMultiVersion() &&
-             TargetDecl->hasAttr<TargetAttr>()) {
-    // Get the required features for the callee.
-
-    const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>();
-    ParsedTargetAttr ParsedAttr =
-        CGM.getContext().filterFunctionTargetAttrs(TD);
-
-    SmallVector<StringRef, 1> ReqFeatures;
-    llvm::StringMap<bool> CalleeFeatureMap;
-    CGM.getContext().getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);
-
-    for (const auto &F : ParsedAttr.Features) {
-      if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1)))
-        ReqFeatures.push_back(StringRef(F).substr(1));
-    }
-
-    for (const auto &F : CalleeFeatureMap) {
-      // Only positive features are "required".
-      if (F.getValue())
-        ReqFeatures.push_back(F.getKey());
-    }
-    if (!llvm::all_of(ReqFeatures,
-                      [&](StringRef Feature) {
-                        if (!CallerFeatureMap.lookup(Feature)) {
-                          MissingFeature = Feature.str();
-                          return false;
-                        }
-                        return true;
-                      }) &&
-        !IsHipStdPar) {
-      if (IsAlwaysInline)
-        CGM.getDiags().Report(Loc, diag::err_function_needs_feature)
-            << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature;
-      else if (IsFlatten)
-        CGM.getDiags().Report(Loc, diag::err_flatten_function_needs_feature)
-            << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature;
-    }
-
-  } else if (!FD->isMultiVersion() && FD->hasAttr<TargetAttr>()) {
-    llvm::StringMap<bool> CalleeFeatureMap;
-    CGM.getContext().getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);
-
-    for (const auto &F : CalleeFeatureMap) {
-      if (F.getValue() &&
-          (!CallerFeatureMap.lookup(F.getKey()) ||
-           !CallerFeatureMap.find(F.getKey())->getValue()) &&
-          !IsHipStdPar) {
-        if (IsAlwaysInline)
-          CGM.getDiags().Report(Loc, diag::err_function_needs_feature)
-              << FD->getDeclName() << TargetDecl->getDeclName() << F.getKey();
-        else if (IsFlatten)
-          CGM.getDiags().Report(Loc, diag::err_flatten_function_needs_feature)
-              << FD->getDeclName() << TargetDecl->getDeclName() << F.getKey();
-      }
-    }
-  }
+  CodeGenUtils::checkTargetFeatures(CGM.getContext(), CGM.getDiags(),
+                                    getLangOpts(), Loc, FD, TargetDecl);
 }
 
 void CodeGenFunction::EmitSanitizerStatReport(llvm::SanitizerStatKind SSK) {
diff --git a/clang/lib/CodeGenUtils/CodeGenUtils.cpp b/clang/lib/CodeGenUtils/CodeGenUtils.cpp
index 42544c74af4aa..4fd78d6997e95 100644
--- a/clang/lib/CodeGenUtils/CodeGenUtils.cpp
+++ b/clang/lib/CodeGenUtils/CodeGenUtils.cpp
@@ -7,7 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/CodeGenUtils/CodeGenUtils.h"
+#include "clang/AST/Attr.h"
+#include "clang/AST/Expr.h"
+#include "clang/Basic/Builtins.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
+#include "llvm/ADT/StringMap.h"
 
 namespace clang::CodeGenUtils {
 static bool
@@ -112,4 +118,116 @@ bool isInitializerOfDynamicClass(const CXXCtorInitializer *BaseInit) {
   return BaseType->castAsCXXRecordDecl()->isDynamicClass();
 }
 
+// Emits an error if we don't have a valid set of target features for the
+// called function.
+void checkTargetFeatures(ASTContext &Ctx, DiagnosticsEngine &Diags,
+                         const LangOptions &LangOpts, const CallExpr *E,
+                         const FunctionDecl *Caller,
+                         const FunctionDecl *TargetDecl) {
+  // SemaChecking cannot handle these x86 builtins because they have different
+  // parameter ranges depending on the caller's TargetAttribute.
+  if (Ctx.getTargetInfo().getTriple().isX86()) {
+    unsigned BuiltinID = TargetDecl->getBuiltinID();
+    if (BuiltinID == X86::BI__builtin_ia32_cmpps ||
+        BuiltinID == X86::BI__builtin_ia32_cmpss ||
+        BuiltinID == X86::BI__builtin_ia32_cmppd ||
+        BuiltinID == X86::BI__builtin_ia32_cmpsd) {
+      llvm::StringMap<bool> TargetFeatureMap;
+      Ctx.getFunctionFeatureMap(TargetFeatureMap, Caller);
+      llvm::APSInt Result = *(E->getArg(2)->getIntegerConstantExpr(Ctx));
+      if (Result.getSExtValue() > 7 && !TargetFeatureMap.lookup("avx"))
+        Diags.Report(E->getBeginLoc(), diag::err_builtin_needs_feature)
+            << TargetDecl->getDeclName() << "avx";
+    }
+  }
+  checkTargetFeatures(Ctx, Diags, LangOpts, E->getBeginLoc(), Caller,
+                      TargetDecl);
+}
+
+// Emits an error if we don't have a valid set of target features for the
+// called function.
+void checkTargetFeatures(ASTContext &Ctx, DiagnosticsEngine &Diags,
+                         const LangOptions &LangOpts, SourceLocation Loc,
+                         const FunctionDecl *Caller,
+                         const FunctionDecl *TargetDecl) {
+  if (!TargetDecl || !Caller)
+    return;
+
+  bool IsAlwaysInline = TargetDecl->hasAttr<AlwaysInlineAttr>();
+  bool IsFlatten = Caller->hasAttr<FlattenAttr>();
+
+  unsigned BuiltinID = TargetDecl->getBuiltinID();
+  std::string MissingFeature;
+  llvm::StringMap<bool> CallerFeatureMap;
+  Ctx.getFunctionFeatureMap(CallerFeatureMap, Caller);
+  // When compiling in HipStdPar mode we have to be conservative in rejecting
+  // target specific features in the FE, and defer the possible error to the
+  // AcceleratorCodeSelection pass, wherein iff an unsupported target builtin is
+  // referenced by an accelerator executable function, we emit an error.
+  bool IsHipStdPar = LangOpts.HIPStdPar && LangOpts.CUDAIsDevice;
+  if (BuiltinID) {
+    StringRef FeatureList(Ctx.BuiltinInfo.getRequiredFeatures(BuiltinID));
+    if (!Builtin::evaluateRequiredTargetFeatures(FeatureList,
+                                                 CallerFeatureMap) &&
+        !IsHipStdPar)
+      Diags.Report(Loc, diag::err_builtin_needs_feature)
+          << TargetDecl->getDeclName() << FeatureList;
+  } else if (!TargetDecl->isMultiVersion() &&
+             TargetDecl->hasAttr<TargetAttr>()) {
+    // Get the required features for the callee.
+    const TargetAttr *TD = TargetDecl->getAttr<TargetAttr>();
+    ParsedTargetAttr ParsedAttr = Ctx.filterFunctionTargetAttrs(TD);
+
+    SmallVector<StringRef, 1> ReqFeatures;
+    llvm::StringMap<bool> CalleeFeatureMap;
+    Ctx.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);
+
+    for (const auto &F : ParsedAttr.Features) {
+      if (F[0] == '+' && CalleeFeatureMap.lookup(F.substr(1)))
+        ReqFeatures.push_back(StringRef(F).substr(1));
+    }
+    for (const auto &F : CalleeFeatureMap) {
+      if (F.getValue())
+        ReqFeatures.push_back(F.getKey());
+    }
+    if (!llvm::all_of(ReqFeatures,
+                      [&](StringRef Feature) {
+                        if (!CallerFeatureMap.lookup(Feature)) {
+                          MissingFeature = Feature.str();
+                          return false;
+                        }
+                        return true;
+                      }) &&
+        !IsHipStdPar) {
+      if (IsAlwaysInline)
+        Diags.Report(Loc, diag::err_function_needs_feature)
+            << Caller->getDeclName() << TargetDecl->getDeclName()
+            << MissingFeature;
+      else if (IsFlatten)
+        Diags.Report(Loc, diag::err_flatten_function_needs_feature)
+            << Caller->getDeclName() << TargetDecl->getDeclName()
+            << MissingFeature;
+    }
+  } else if (!Caller->isMultiVersion() && Caller->hasAttr<TargetAttr>()) {
+    llvm::StringMap<bool> CalleeFeatureMap;
+    Ctx.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl);
+
+    for (const auto &F : CalleeFeatureMap) {
+      if (F.getValue() &&
+          (!CallerFeatureMap.lookup(F.getKey()) ||
+           !CallerFeatureMap.find(F.getKey())->getValue()) &&
+          !IsHipStdPar) {
+        if (IsAlwaysInline)
+          Diags.Report(Loc, diag::err_function_needs_feature)
+              << Caller->getDeclName() << TargetDecl->getDeclName()
+              << F.getKey();
+        else if (IsFlatten)
+          Diags.Report(Loc, diag::err_flatten_function_needs_feature)
+              << Caller->getDeclName() << TargetDecl->getDeclName()
+              << F.getKey();
+      }
+    }
+  }
+}
+
 } // namespace clang::CodeGenUtils
diff --git a/clang/test/CIR/CodeGen/avx512-error.c b/clang/test/CIR/CodeGen/avx512-error.c
new file mode 100644
index 0000000000000..1402c01ce5e55
--- /dev/null
+++ b/clang/test/CIR/CodeGen/avx512-error.c
@@ -0,0 +1,23 @@
+// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-linux-gnu -fclangir -target-feature +avx512bw -emit-llvm -o /dev/null -verify
+// RUN: %clang_cc1 %s -ffreestanding -triple=x86_64-linux-gnu -fclangir -target-feature +avx10.1 -emit-llvm -o /dev/null -verify
+
+#include <immintrin.h>
+
+__attribute__((target("avx512bw")))
+__mmask64 k64_verify_1(__mmask64 a) {
+  return _knot_mask64(a); // expected-no-diagnostics
+}
+
+__mmask64 k64_verify_2(__mmask64 a) {
+  return _knot_mask64(a); // expected-no-diagnostic
+}
+
+__attribute__((target("avx512bw")))
+__m512d zmm_verify_ok(__m512d a) {
+  return __builtin_ia32_sqrtpd512(a, _MM_FROUND_CUR_DIRECTION); // expected-no-diagnostic
+}
+
+__m512d zmm_error(__m512d a) {
+  // CHECK-LABEL: @test_mm512_sqrt_pd
+  return __builtin_ia32_sqrtpd512(a, _MM_FROUND_CUR_DIRECTION); // noevex-error {{'__builtin_ia32_sqrtpd512' needs target feature avx512f}}
+}
diff --git a/clang/test/CIR/CodeGen/target-builtin-error-2.c b/clang/test/CIR/CodeGen/target-builtin-error-2.c
new file mode 100644
index 0000000000000..bc18a9fba0940
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-builtin-error-2.c
@@ -0,0 +1,13 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -S -verify -o -
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+// Since we do code generation on a function level this needs to error out since
+// the subtarget feature won't be available.
+__m128 wombat(__m128i a) {
+  if (__builtin_cpu_supports("avx"))
+    return __builtin_ia32_vpermilvarps((__v4sf) {0.0f, 1.0f, 2.0f, 3.0f}, (__v4si)a); // expected-error {{'__builtin_ia32_vpermilvarps' needs target feature avx}}
+  else
+    return (__m128){0, 0};
+}
diff --git a/clang/test/CIR/CodeGen/target-builtin-error-3.c b/clang/test/CIR/CodeGen/target-builtin-error-3.c
new file mode 100644
index 0000000000000..0f75fff278abb
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-builtin-error-3.c
@@ -0,0 +1,62 @@
+// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin -fclangir -S -verify -o - -target-feature +avx
+
+// RUN: not %clang_cc1 %s -triple=x86_64-apple-darwin -fclangir -emit-obj -target-feature +avx 2> %t.err
+// RUN: FileCheck < %t.err %s
+//
+// CHECK: 1 error generated
+
+typedef unsigned short uint16_t;
+typedef long long __m128i __attribute__((__vector_size__(16)));
+typedef float __v8sf __attribute__ ((__vector_size__ (32)));
+typedef float __m256 __attribute__ ((__vector_size__ (32)));
+typedef uint16_t half;
+typedef __attribute__ ((ext_vector_type( 8),__aligned__( 16))) half half8;
+typedef __attribute__ ((ext_vector_type(16),__aligned__( 32))) half half16;
+typedef __attribute__ ((ext_vector_type(16),__aligned__( 2))) half half16U;
+typedef __attribute__ ((ext_vector_type( 8),__aligned__( 32))) float float8;
+typedef __attribute__ ((ext_vector_type(16),__aligned__( 64))) float float16;
+static inline half8 __attribute__((__overloadable__)) convert_half( float8 a ) {
+  return __extension__ ({ __m256 __a = (a); (__m128i)__builtin_ia32_vcvtps2ph256((__v8sf)__a, (0x00)); }); // expected-error {{'__builtin_ia32_vcvtps2ph256' needs target feature f16c}}
+}
+// Internal definitions do not warn.
+static inline half16 __attribute__((__overloadable__)) convert_half( float16 a ) {
+  half16 r;
+  r.lo = convert_half(a.lo);
+  return r;
+}
+// FIXME(cir): The below warning should be emitted, which requires avx builtin checking..
+// <expected>-warning at +1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}}
+void avx_test( uint16_t *destData, float16 argbF)
+{
+  ((half16U *)destData)[0] = convert_half(argbF);
+}
+
+// FIXME(cir): The below warning should be emitted, which requires avx builtin checking..
+// <expected>-warning at +1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}}
+half16 test( float16 a ) {
+  half16 r;
+  r.lo = convert_half(a.lo);
+  return r;
+}
+// FIXME(cir): The below warning should be emitted, which requires avx builtin checking..
+// <expected>-warning at +1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}}
+void avx_test2( uint16_t *destData, float16 argbF)
+{
+  // FIXME(cir): The below warning should be emitted, which requires avx builtin checking..
+  // <expected>-warning at +1{{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}}
+  ((half16U *)destData)[0] = test(argbF);
+}
+
+// FIXME(cir): The below warning should be emitted, which requires avx builtin checking..
+// <expected>-warning at +1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}}
+__attribute__((always_inline)) half16 test2( float16 a ) {
+  half16 r;
+  r.lo = convert_half(a.lo);
+  return r;
+}
+// FIXME(cir): The below warning should be emitted, which requires avx builtin checking..
+// <expected>-warning at +1 {{AVX vector argument of type 'float16' (vector of 16 'float' values) without 'avx512f' enabled changes the ABI}}
+void avx_test3( uint16_t *destData, float16 argbF)
+{
+  ((half16U *)destData)[0] = test2(argbF);
+}
diff --git a/clang/test/CIR/CodeGen/target-builtin-error.c b/clang/test/CIR/CodeGen/target-builtin-error.c
new file mode 100644
index 0000000000000..d8bd68ac11ce6
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-builtin-error.c
@@ -0,0 +1,8 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -S -verify -o -
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+__m128 foo(__m128 a, __m128 b) {
+  return __builtin_ia32_addsubps(b, a); // expected-error {{'__builtin_ia32_addsubps' needs target feature sse3}}
+}
diff --git a/clang/test/CIR/CodeGen/target-builtin-noerror.c b/clang/test/CIR/CodeGen/target-builtin-noerror.c
new file mode 100644
index 0000000000000..30161947a99ee
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-builtin-noerror.c
@@ -0,0 +1,215 @@
+// REQUIRES: x86-registered-target
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -S -o - -Werror
+#define __MM_MALLOC_H
+
+#include <x86intrin.h>
+
+// No warnings.
+extern __m256i a;
+int __attribute__((target("avx"))) bar(void) {
+  return _mm256_extract_epi32(a, 3);
+}
+
+int baz(void) {
+  return bar();
+}
+
+int __attribute__((target("avx"))) qq_avx(void) {
+  return _mm256_extract_epi32(a, 3);
+}
+
+int qq_noavx(void) {
+  return 0;
+}
+
+extern __m256i a;
+int qq(void) {
+  if (__builtin_cpu_supports("avx"))
+    return qq_avx();
+  else
+    return qq_noavx();
+}
+
+// Test that fma and fma4 are both separately and combined valid for an fma intrinsic.
+__m128 __attribute__((target("fma"))) fma_1(__m128 a, __m128 b, __m128 c) {
+  return __builtin_ia32_vfmaddsubps(a, b, c);
+}
+
+__m128 __attribute__((target("fma4"))) fma_2(__m128 a, __m128 b, __m128 c) {
+  return __builtin_ia32_vfmaddsubps(a, b, c);
+}
+
+__m128 __attribute__((target("fma,fma4"))) fma_3(__m128 a, __m128 b, __m128 c) {
+  return __builtin_ia32_vfmaddsubps(a, b, c);
+}
+
+void verifyfeaturestrings(void) {
+  (void)__builtin_cpu_supports("cmov");
+  (void)__builtin_cpu_supports("mmx");
+  (void)__builtin_cpu_supports("popcnt");
+  (void)__builtin_cpu_supports("sse");
+  (void)__builtin_cpu_supports("sse2");
+  (void)__builtin_cpu_supports("sse3");
+  (void)__builtin_cpu_supports("ssse3");
+  (void)__builtin_cpu_supports("sse4.1");
+  (void)__builtin_cpu_supports("sse4.2");
+  (void)__builtin_cpu_supports("avx");
+  (void)__builtin_cpu_supports("avx2");
+  (void)__builtin_cpu_supports("sse4a");
+  (void)__builtin_cpu_supports("fma4");
+  (void)__builtin_cpu_supports("xop");
+  (void)__builtin_cpu_supports("fma");
+  (void)__builtin_cpu_supports("avx512f");
+  (void)__builtin_cpu_supports("bmi");
+  (void)__builtin_cpu_supports("bmi2");
+  (void)__builtin_cpu_supports("aes");
+  (void)__builtin_cpu_supports("pclmul");
+  (void)__builtin_cpu_supports("avx512vl");
+  (void)__builtin_cpu_supports("avx512bw");
+  (void)__builtin_cpu_supports("avx512dq");
+  (void)__builtin_cpu_supports("avx512cd");
+  (void)__builtin_cpu_supports("avx512vbmi");
+  (void)__builtin_cpu_supports("avx512ifma");
+  (void)__builtin_cpu_supports("avx512vpopcntdq");
+  (void)__builtin_cpu_supports("avx512vbmi2");
+  (void)__builtin_cpu_supports("gfni");
+  (void)__builtin_cpu_supports("vpclmulqdq");
+  (void)__builtin_cpu_supports("avx512vnni");
+  (void)__builtin_cpu_supports("avx512bitalg");
+  (void)__builtin_cpu_supports("avx512bmm");
+  (void)__builtin_cpu_supports("avx512bf16");
+  (void)__builtin_cpu_supports("avx512vp2intersect");
+  (void)__builtin_cpu_supports("f16c");
+  (void)__builtin_cpu_supports("avx512fp16");
+  (void)__builtin_cpu_supports("adx");
+  (void)__builtin_cpu_supports("cldemote");
+  (void)__builtin_cpu_supports("clflushopt");
+  (void)__builtin_cpu_supports("clwb");
+  (void)__builtin_cpu_supports("clzero");
+  (void)__builtin_cpu_supports("cx16");
+  (void)__builtin_cpu_supports("enqcmd");
+  (void)__builtin_cpu_supports("fsgsbase");
+  (void)__builtin_cpu_supports("lwp");
+  (void)__builtin_cpu_supports("lzcnt");
+  (void)__builtin_cpu_supports("movbe");
+  (void)__builtin_cpu_supports("movdir64b");
+  (void)__builtin_cpu_supports("movdiri");
+  (void)__builtin_cpu_supports("mwaitx");
+  (void)__builtin_cpu_supports("pconfig");
+  (void)__builtin_cpu_supports("pku");
+  (void)__builtin_cpu_supports("prfchw");
+  (void)__builtin_cpu_supports("ptwrite");
+  (void)__builtin_cpu_supports("rdpid");
+  (void)__builtin_cpu_supports("rdrnd");
+  (void)__builtin_cpu_supports("rdseed");
+  (void)__builtin_cpu_supports("rtm");
+  (void)__builtin_cpu_supports("serialize");
+  (void)__builtin_cpu_supports("sgx");
+  (void)__builtin_cpu_supports("sha");
+  (void)__builtin_cpu_supports("shstk");
+  (void)__builtin_cpu_supports("tbm");
+  (void)__builtin_cpu_supports("tsxldtrk");
+  (void)__builtin_cpu_supports("vaes");
+  (void)__builtin_cpu_supports("waitpkg");
+  (void)__builtin_cpu_supports("wbnoinvd");
+  (void)__builtin_cpu_supports("xsave");
+  (void)__builtin_cpu_supports("xsavec");
+  (void)__builtin_cpu_supports("xsaveopt");
+  (void)__builtin_cpu_supports("xsaves");
+  (void)__builtin_cpu_supports("amx-tile");
+  (void)__builtin_cpu_supports("amx-int8");
+  (void)__builtin_cpu_supports("amx-bf16");
+  (void)__builtin_cpu_supports("uintr");
+  (void)__builtin_cpu_supports("hreset");
+  (void)__builtin_cpu_supports("kl");
+  (void)__builtin_cpu_supports("widekl");
+  (void)__builtin_cpu_supports("avxvnni");
+  (void)__builtin_cpu_supports("avxifma");
+  (void)__builtin_cpu_supports("avxvnniint8");
+  (void)__builtin_cpu_supports("avxneconvert");
+  (void)__builtin_cpu_supports("cmpccxadd");
+  (void)__builtin_cpu_supports("amx-fp16");
+  (void)__builtin_cpu_supports("prefetchi");
+  (void)__builtin_cpu_supports("raoint");
+  (void)__builtin_cpu_supports("amx-complex");
+  (void)__builtin_cpu_supports("avxvnniint16");
+  (void)__builtin_cpu_supports("sm3");
+  (void)__builtin_cpu_supports("sha512");
+  (void)__builtin_cpu_supports("sm4");
+  (void)__builtin_cpu_supports("apxf");
+  (void)__builtin_cpu_supports("usermsr");
+  (void)__builtin_cpu_supports("avx10.1");
+  (void)__builtin_cpu_supports("avx10.2");
+  (void)__builtin_cpu_supports("movrs");
+}
+
+void verifycpustrings(void) {
+  (void)__builtin_cpu_is("alderlake");
+  (void)__builtin_cpu_is("amd");
+  (void)__builtin_cpu_is("amdfam10h");
+  (void)__builtin_cpu_is("amdfam15h");
+  (void)__builtin_cpu_is("amdfam17h");
+  (void)__builtin_cpu_is("atom");
+  (void)__builtin_cpu_is("barcelona");
+  (void)__builtin_cpu_is("bdver1");
+  (void)__builtin_cpu_is("bdver2");
+  (void)__builtin_cpu_is("bdver3");
+  (void)__builtin_cpu_is("bdver4");
+  (void)__builtin_cpu_is("bonnell");
+  (void)__builtin_cpu_is("broadwell");
+  (void)__builtin_cpu_is("btver1");
+  (void)__builtin_cpu_is("btver2");
+  (void)__builtin_cpu_is("cannonlake");
+  (void)__builtin_cpu_is("cascadelake");
+  (void)__builtin_cpu_is("cooperlake");
+  (void)__builtin_cpu_is("core2");
+  (void)__builtin_cpu_is("corei7");
+  (void)__builtin_cpu_is("goldmont");
+  (void)__builtin_cpu_is("goldmont-plus");
+  (void)__builtin_cpu_is("grandridge");
+  (void)__builtin_cpu_is("graniterapids");
+  (void)__builtin_cpu_is("emeraldrapids");
+  (void)__builtin_cpu_is("graniterapids-d");
+  (void)__builtin_cpu_is("arrowlake");
+  (void)__builtin_cpu_is("arrowlake-s");
+  (void)__builtin_cpu_is("lunarlake");
+  (void)__builtin_cpu_is("clearwaterforest");
+  (void)__builtin_cpu_is("pantherlake");
+  (void)__builtin_cpu_is("wildcatlake");
+  (void)__builtin_cpu_is("novalake");
+  (void)__builtin_cpu_is("haswell");
+  (void)__builtin_cpu_is("icelake-client");
+  (void)__builtin_cpu_is("icelake-server");
+  (void)__builtin_cpu_is("intel");
+  (void)__builtin_cpu_is("istanbul");
+  (void)__builtin_cpu_is("ivybridge");
+  (void)__builtin_cpu_is("knl");
+  (void)__builtin_cpu_is("knm");
+  (void)__builtin_cpu_is("meteorlake");
+  (void)__builtin_cpu_is("nehalem");
+  (void)__builtin_cpu_is("raptorlake");
+  (void)__builtin_cpu_is("rocketlake");
+  (void)__builtin_cpu_is("sandybridge");
+  (void)__builtin_cpu_is("shanghai");
+  (void)__builtin_cpu_is("sierraforest");
+  (void)__builtin_cpu_is("silvermont");
+  (void)__builtin_cpu_is("skylake");
+  (void)__builtin_cpu_is("skylake-avx512");
+  (void)__builtin_cpu_is("slm");
+  (void)__builtin_cpu_is("tigerlake");
+  (void)__builtin_cpu_is("sapphirerapids");
+  (void)__builtin_cpu_is("tremont");
+  (void)__builtin_cpu_is("gracemont");
+  (void)__builtin_cpu_is("westmere");
+  (void)__builtin_cpu_is("znver1");
+  (void)__builtin_cpu_is("znver2");
+  (void)__builtin_cpu_is("znver3");
+  (void)__builtin_cpu_is("znver4");
+  (void)__builtin_cpu_is("znver5");
+  (void)__builtin_cpu_is("znver6");
+  (void)__builtin_cpu_is("diamondrapids");
+  (void)__builtin_cpu_is("c86-4g-m4");
+  (void)__builtin_cpu_is("c86-4g-m6");
+  (void)__builtin_cpu_is("c86-4g-m7");
+  (void)__builtin_cpu_is("c86-4g-m8");
+}
diff --git a/clang/test/CIR/CodeGen/target-features-error-2.c b/clang/test/CIR/CodeGen/target-features-error-2.c
new file mode 100644
index 0000000000000..6891e6c73a4e2
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-features-error-2.c
@@ -0,0 +1,50 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -S -verify -o - -D NEED_AVX_1
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -S -verify -o - -D NEED_AVX_2
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -S -verify -o - -D NEED_AVX512f
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -target-feature +movdir64b -S -verify -o - -D NEED_MOVDIRI
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -target-feature +avx512vnni -target-feature +movdiri -S -verify -o - -D NEED_CLWB
+
+#define __MM_MALLOC_H
+#include <x86intrin.h>
+
+#if NEED_AVX_1
+// FIXME(cir): The below warning should be emitted, which requires avx builtin checking..
+// <expected>-warning at +1 {{AVX vector argument of type '__m256i' (vector of 4 'long long' values) without 'avx' enabled changes the ABI}}
+int baz(__m256i a) {
+  return _mm256_extract_epi32(a, 3); // expected-error {{'__builtin_ia32_vec_ext_v8si' needs target feature avx}}
+}
+#endif
+
+#if NEED_AVX_2
+__m128 need_avx(__m128 a, __m128 b) {
+  // expected-error at +2{{unimplemented X86 builtin call:}}
+  // expected-error at +1{{unimplemented builtin call:}}
+  return _mm_cmp_ps(a, b, 8); // expected-error {{'__builtin_ia32_cmpps' needs target feature avx}}
+}
+#endif
+
+#if NEED_AVX512f
+unsigned short need_avx512f(unsigned short a, unsigned short b) {
+  return __builtin_ia32_korhi(a, b); // expected-error {{'__builtin_ia32_korhi' needs target feature avx512f}}
+}
+#endif
+
+#if NEED_MOVDIRI
+void need_movdiri(unsigned int *a, unsigned int b) {
+  __builtin_ia32_directstore_u32(a, b); // expected-error {{'__builtin_ia32_directstore_u32' needs target feature movdiri}}
+}
+#endif
+
+#if NEED_CLWB
+static __inline__ void
+ __attribute__((__always_inline__, __nodebug__,  __target__("avx512vnni,clwb,movdiri,movdir64b")))
+ func(unsigned int *a, unsigned int b)
+{
+  __builtin_ia32_directstore_u32(a, b);
+}
+
+void need_clwb(unsigned int *a, unsigned int b) {
+  func(a, b); // expected-error {{always_inline function 'func' requires target feature 'clwb', but would be inlined into function 'need_clwb' that is compiled without support for 'clwb'}}
+
+}
+#endif
diff --git a/clang/test/CIR/CodeGen/target-features-error-3.c b/clang/test/CIR/CodeGen/target-features-error-3.c
new file mode 100644
index 0000000000000..4690b5a258c77
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-features-error-3.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -emit-llvm -verify -o /dev/null
+
+typedef double __v2df __attribute__((__vector_size__(16)));
+
+__v2df __attribute__((target("sse4.1"))) foo() {
+    __v2df v = {0.0, 0.0};
+    return v;
+}
+
+__v2df __attribute__((flatten)) bar() {
+    return foo(); // expected-error {{flatten function 'bar' calls 'foo' which requires target feature 'sse4.1', but the caller is compiled without support for 'sse4.1'}}
+}
diff --git a/clang/test/CIR/CodeGen/target-features-error-4.c b/clang/test/CIR/CodeGen/target-features-error-4.c
new file mode 100644
index 0000000000000..107f79cb669f1
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-features-error-4.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -emit-llvm -verify -o /dev/null
+
+typedef double __v2df __attribute__((__vector_size__(16)));
+
+__v2df __attribute__((target("sse4.1"))) foo() {
+    __v2df v = {0.0, 0.0};
+    return v;
+}
+
+__v2df __attribute__((target("no-sse4.1"), flatten)) bar() {
+    return foo(); // expected-error {{flatten function 'bar' calls 'foo' which requires target feature 'sse4.1', but the caller is compiled without support for 'sse4.1'}}
+}
diff --git a/clang/test/CIR/CodeGen/target-features-error-5.c b/clang/test/CIR/CodeGen/target-features-error-5.c
new file mode 100644
index 0000000000000..2d01f381a427f
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-features-error-5.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -target-feature +sse4.1 -emit-llvm -verify -o /dev/null
+
+typedef double __v2df __attribute__((__vector_size__(16)));
+
+__v2df foo() {
+    __v2df v = {0.0, 0.0};
+    return v;
+}
+
+__v2df __attribute__((target("no-sse4.1"), flatten)) bar() {
+    return foo(); // expected-error {{flatten function 'bar' calls 'foo' which requires target feature 'sse4.1', but the caller is compiled without support for 'sse4.1'}}
+}
diff --git a/clang/test/CIR/CodeGen/target-features-error.c b/clang/test/CIR/CodeGen/target-features-error.c
new file mode 100644
index 0000000000000..8ac0ecad4dd30
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-features-error.c
@@ -0,0 +1,7 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -fclangir -S -verify -o -
+int __attribute__((target("avx"), always_inline)) foo(int a) {
+  return a + 4;
+}
+int bar(void) {
+  return foo(4); // expected-error {{always_inline function 'foo' requires target feature 'avx', but would be inlined into function 'bar' that is compiled without support for 'avx'}}
+}
diff --git a/clang/test/CIR/CodeGen/target-features-no-error-2.c b/clang/test/CIR/CodeGen/target-features-no-error-2.c
new file mode 100644
index 0000000000000..5d2cc59835d79
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-features-no-error-2.c
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fclangir -verify -o /dev/null
+
+typedef double __v2df __attribute__((__vector_size__(16)));
+
+__v2df __attribute__((target("sse4.1"))) foo() {
+    __v2df v = {0.0, 0.0};
+    return v;
+}
+
+__v2df __attribute__((target("sse4.1"), flatten)) bar() {
+    return foo(); // expected-no-diagnostics
+}
diff --git a/clang/test/CIR/CodeGen/target-features-no-error.c b/clang/test/CIR/CodeGen/target-features-no-error.c
new file mode 100644
index 0000000000000..4f535495a78ed
--- /dev/null
+++ b/clang/test/CIR/CodeGen/target-features-no-error.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -emit-llvm -fclangir -o - -target-feature -sse2
+
+// Verify that negative features don't cause additional requirements on the inline function.
+int __attribute__((target("sse"), always_inline)) foo(int a) {
+  return a + 4;
+}
+int bar(void) {
+  return foo(4); // expected-no-diagnostics
+}
diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlvbmi2-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlvbmi2-builtins.c
index 9e0cdaa9eea75..c1e60b2f0a5a5 100644
--- a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlvbmi2-builtins.c
+++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlvbmi2-builtins.c
@@ -1,12 +1,12 @@
 
-// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512vlvbmi2 -fclangir -emit-cir -o %t.cir -Wall -Werror -Wsign-conversion
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512vl -target-feature +avx512vbmi2 -fclangir -emit-cir -o %t.cir -Wall -Werror -Wsign-conversion
 // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512vlvbmi2 -fclangir -emit-llvm -o %t.ll -Wall -Werror -Wsign-conversion
+// RUN: %clang_cc1 -x c -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512vl -target-feature +avx512vbmi2 -fclangir -emit-llvm -o %t.ll -Wall -Werror -Wsign-conversion
 // RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s
 
-// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512vlvbmi2 -fclangir -emit-cir -o %t.cir -Wall -Werror -Wsign-conversion
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512vl -target-feature +avx512vbmi2 -fclangir -emit-cir -o %t.cir -Wall -Werror -Wsign-conversion
 // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512vlvbmi2 -fclangir -emit-llvm -o %t.ll -Wall -Werror -Wsign-conversion
+// RUN: %clang_cc1 -x c++ -flax-vector-conversions=none -ffreestanding %s -triple=x86_64-unknown-linux -target-feature +avx512vl -target-feature +avx512vbmi2 -fclangir -emit-llvm -o %t.ll -Wall -Werror -Wsign-conversion
 // RUN: FileCheck --check-prefixes=LLVM --input-file=%t.ll %s
 
 #include <immintrin.h>
diff --git a/clang/test/CIR/CodeGenBuiltins/X86/sqrt-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/sqrt-builtins.c
index d540e9c227e67..2ba0e2ca63ff1 100644
--- a/clang/test/CIR/CodeGenBuiltins/X86/sqrt-builtins.c
+++ b/clang/test/CIR/CodeGenBuiltins/X86/sqrt-builtins.c
@@ -1,8 +1,8 @@
 // Test X86-specific sqrt builtins
 
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +avx512f -target-feature +avx512fp16 -fclangir -emit-cir %s -o %t.cir
 // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +avx512f -target-feature +avx512fp16 -fclangir -emit-llvm %s -o %t-cir.ll
 // RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -target-feature +avx512f -target-feature +avx512fp16 -emit-llvm %s -o %t.ll
 // RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s
@@ -42,4 +42,4 @@ __m512d test_sqrtpd512(__m512d a) {
 // LLVM-LABEL: define {{.*}} @test_sqrtpd512
 // LLVM: call <8 x double> @llvm.sqrt.v8f64
 // OGCG-LABEL: define {{.*}} @test_sqrtpd512
-// OGCG: call <8 x double> @llvm.sqrt.v8f64
\ No newline at end of file
+// OGCG: call <8 x double> @llvm.sqrt.v8f64
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp b/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
index dac0ddf366334..c15375621f08a 100644
--- a/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp
@@ -1,7 +1,5 @@
 // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir -verify %s -o - > %t.cir
 // RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
-// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm -verify %s -o - > %t.ll
-// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s
 
 typedef int v4si __attribute__((vector_size(16)));
 
@@ -13,7 +11,3 @@ int test_builtin_reduce_add_undef_rvalue(v4si x) {
 // CIR-LABEL: @_Z36test_builtin_reduce_add_undef_rvalueDv4_i
 // CIR:         cir.const #cir.undef : !s32i
 // CIR:         cir.return
-
-// LLVM-LABEL: @_Z36test_builtin_reduce_add_undef_rvalueDv4_i
-// LLVM:         store i32 undef, ptr %{{.+}}, align 4
-// LLVM:         ret i32 %{{.+}}



More information about the cfe-commits mailing list