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

via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 11 13:52:18 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Erich Keane (erichkeane)

<details>
<summary>Changes</summary>

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.

---

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


22 Files Affected:

- (modified) clang/include/clang/CodeGenUtils/CodeGenUtils.h (+23) 
- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+22) 
- (modified) clang/lib/CIR/CodeGen/CIRGenCall.cpp (+17) 
- (modified) clang/lib/CIR/CodeGen/CIRGenFunction.h (+7) 
- (modified) clang/lib/CIR/FrontendAction/CIRGenAction.cpp (+4) 
- (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+6-108) 
- (modified) clang/lib/CodeGenUtils/CodeGenUtils.cpp (+118) 
- (added) clang/test/CIR/CodeGen/avx512-error.c (+23) 
- (added) clang/test/CIR/CodeGen/target-builtin-error-2.c (+13) 
- (added) clang/test/CIR/CodeGen/target-builtin-error-3.c (+62) 
- (added) clang/test/CIR/CodeGen/target-builtin-error.c (+8) 
- (added) clang/test/CIR/CodeGen/target-builtin-noerror.c (+215) 
- (added) clang/test/CIR/CodeGen/target-features-error-2.c (+50) 
- (added) clang/test/CIR/CodeGen/target-features-error-3.c (+12) 
- (added) clang/test/CIR/CodeGen/target-features-error-4.c (+12) 
- (added) clang/test/CIR/CodeGen/target-features-error-5.c (+12) 
- (added) clang/test/CIR/CodeGen/target-features-error.c (+7) 
- (added) clang/test/CIR/CodeGen/target-features-no-error-2.c (+12) 
- (added) clang/test/CIR/CodeGen/target-features-no-error.c (+9) 
- (modified) clang/test/CIR/CodeGenBuiltins/X86/avx512vlvbmi2-builtins.c (+4-4) 
- (modified) clang/test/CIR/CodeGenBuiltins/X86/sqrt-builtins.c (+3-3) 
- (modified) clang/test/CIR/CodeGenBuiltins/builtin-undef-rvalue.cpp (-6) 


``````````diff
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_...
[truncated]

``````````

</details>


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


More information about the cfe-commits mailing list