[clang] bb49346 - Revert "Implement target_clones multiversioning"

Adrian Kuegel via cfe-commits cfe-commits at lists.llvm.org
Fri Nov 12 02:14:57 PST 2021


Author: Adrian Kuegel
Date: 2021-11-12T11:05:58+01:00
New Revision: bb4934601d731465e01e2e22c80ce2dbe687d73f

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

LOG: Revert "Implement target_clones multiversioning"

This reverts commit 9deab60ae710f8c4cc810cd680edfb64c803f42d.
There is a possibly unintended semantic change.

Added: 
    

Modified: 
    clang/include/clang/AST/Decl.h
    clang/include/clang/Basic/Attr.td
    clang/include/clang/Basic/AttrDocs.td
    clang/include/clang/Basic/DiagnosticGroups.td
    clang/include/clang/Basic/DiagnosticSemaKinds.td
    clang/include/clang/Sema/Sema.h
    clang/lib/AST/ASTContext.cpp
    clang/lib/AST/Decl.cpp
    clang/lib/CodeGen/CodeGenModule.cpp
    clang/lib/CodeGen/CodeGenModule.h
    clang/lib/Sema/SemaDecl.cpp
    clang/lib/Sema/SemaDeclAttr.cpp
    clang/test/Misc/pragma-attribute-supported-attributes-list.test
    clang/test/Sema/attr-cpuspecific.c

Removed: 
    clang/test/CodeGen/attr-target-clones.c
    clang/test/CodeGenCXX/attr-target-clones.cpp
    clang/test/Sema/attr-target-clones.c
    clang/test/SemaCXX/attr-target-clones.cpp


################################################################################
diff  --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 2eacf1105c18c..85a3a8ab69708 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -1840,8 +1840,7 @@ enum class MultiVersionKind {
   None,
   Target,
   CPUSpecific,
-  CPUDispatch,
-  TargetClones
+  CPUDispatch
 };
 
 /// Represents a function declaration or definition.
@@ -2460,10 +2459,6 @@ class FunctionDecl : public DeclaratorDecl,
   /// the target functionality.
   bool isTargetMultiVersion() const;
 
-  /// True if this function is a multiversioned dispatch function as a part of
-  /// the target-clones functionality.
-  bool isTargetClonesMultiVersion() const;
-
   /// \brief Get the associated-constraints of this function declaration.
   /// Currently, this will either be a vector of size 1 containing the
   /// trailing-requires-clause or an empty vector.

diff  --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index 1efde2a0f25f4..d8f0fcd56550c 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -2676,40 +2676,6 @@ def Target : InheritableAttr {
   }];
 }
 
-def TargetClones : InheritableAttr {
-  let Spellings = [GCC<"target_clones">];
-  let Args = [VariadicStringArgument<"featuresStrs">];
-  let Documentation = [TargetClonesDocs];
-  let Subjects = SubjectList<[Function], ErrorDiag>;
-  let AdditionalMembers = [{
-    StringRef getFeatureStr(unsigned Index) const {
-      return *(featuresStrs_begin() + Index);
-    }
-    // 'default' is always moved to the end, so it isn't considered
-    // when mangling the index.
-    unsigned getMangledIndex(unsigned Index) const {
-      if (getFeatureStr(Index) == "default")
-        return std::count_if(featuresStrs_begin(), featuresStrs_end(),
-                              [](StringRef S) { return S != "default"; });
-
-      return std::count_if(featuresStrs_begin(), featuresStrs_begin() + Index,
-                           [](StringRef S) { return S != "default"; });
-    }
-
-    // True if this is the first of this version to appear in the config string.
-    // This is used to make sure we don't try to emit this function multiple
-    // times.
-    bool isFirstOfVersion(unsigned Index) const {
-      StringRef FeatureStr(getFeatureStr(Index));
-      return 0 == std::count_if(
-                      featuresStrs_begin(), featuresStrs_begin() + Index,
-                      [FeatureStr](StringRef S) { return S == FeatureStr; });
-    }
-  }];
-}
-
-def : MutualExclusions<[TargetClones, Target, CPUDispatch, CPUSpecific]>;
-
 def MinVectorWidth : InheritableAttr {
   let Spellings = [Clang<"min_vector_width">];
   let Args = [UnsignedArgument<"VectorWidth">];

diff  --git a/clang/include/clang/Basic/AttrDocs.td b/clang/include/clang/Basic/AttrDocs.td
index 10cce4c2d6898..e7afb3699eb17 100644
--- a/clang/include/clang/Basic/AttrDocs.td
+++ b/clang/include/clang/Basic/AttrDocs.td
@@ -2233,40 +2233,6 @@ Additionally, a function may not become multiversioned after its first use.
 }];
 }
 
-def TargetClonesDocs : Documentation {
-  let Category = DocCatFunction;
-  let Content = [{
-Clang supports the ``target_clones("OPTIONS")`` attribute. This attribute may be
-attached to a function declaration and causes function multiversioning, where
-multiple versions of the function will be emitted with 
diff erent code
-generation options.  Additionally, these versions will be resolved at runtime
-based on the priority of their attribute options. All ``target_clone`` functions
-are considered multiversioned functions.
-
-All multiversioned functions must contain a ``default`` (fallback)
-implementation, otherwise usages of the function are considered invalid.
-Additionally, a function may not become multiversioned after its first use.
-
-The options to ``target_clones`` can either be a target-specific architecture
-(specified as ``arch=CPU``), or one of a list of subtarget features.
-
-Example "subtarget features" from the x86 backend include: "mmx", "sse", "sse4.2",
-"avx", "xop" and largely correspond to the machine specific options handled by
-the front end.
-
-The versions can either be listed as a comma-separated sequence of string
-literals or as a single string literal containing a comma-separated list of
-versions.  For compatibility with GCC, the two formats can be mixed.  For
-example, the following will emit 4 versions of the function:
-
-  .. code-block:: c++
-
-    __attribute__((target_clones("arch=atom,avx2","arch=ivybridge","default")))
-    void foo() {}
-
-}];
-}
-
 def MinVectorWidthDocs : Documentation {
   let Category = DocCatFunction;
   let Content = [{

diff  --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 4bd3464f0a8cc..60d417fd5770e 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1271,14 +1271,9 @@ def : DiagGroup<"spirv-compat", [SpirCompat]>; // Alias.
 // Warning for the GlobalISel options.
 def GlobalISel : DiagGroup<"global-isel">;
 
-// A warning group for the GNU extension to allow mixed specifier types for
-// target-clones multiversioning.
-def TargetClonesMixedSpecifiers : DiagGroup<"target-clones-mixed-specifiers">;
-
 // A warning group specifically for warnings related to function
 // multiversioning.
-def FunctionMultiVersioning
-    : DiagGroup<"function-multiversion", [TargetClonesMixedSpecifiers]>;
+def FunctionMultiVersioning : DiagGroup<"function-multiversion">;
 
 def NoDeref : DiagGroup<"noderef">;
 

diff  --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 60c0ac103e5f4..76d4f9286d371 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -2981,8 +2981,7 @@ def err_invalid_branch_protection_spec : Error<
   "invalid or misplaced branch protection specification '%0'">;
 def warn_unsupported_target_attribute
     : Warning<"%select{unsupported|duplicate|unknown}0%select{| architecture|"
-              " tune CPU}1 '%2' in the '%select{target|target_clones}3' "
-              "attribute string; '%select{target|target_clones}3' "
+              " tune CPU}1 '%2' in the 'target' attribute string; 'target' "
               "attribute ignored">,
       InGroup<IgnoredAttributes>;
 def err_attribute_unsupported
@@ -9865,8 +9864,6 @@ def warn_duplicate_attribute_exact : Warning<
 def warn_duplicate_attribute : Warning<
   "attribute %0 is already applied with 
diff erent arguments">,
   InGroup<IgnoredAttributes>;
-def err_disallowed_duplicate_attribute : Error<
-  "attribute %0 cannot appear more than once on a declaration">;
 
 def warn_sync_fetch_and_nand_semantics_change : Warning<
   "the semantics of this intrinsic changed with GCC "
@@ -11251,11 +11248,9 @@ def err_multiversion_duplicate : Error<
   "multiversioned function redeclarations require identical target attributes">;
 def err_multiversion_noproto : Error<
   "multiversioned function must have a prototype">;
-def err_multiversion_disallowed_other_attr
-    : Error<"attribute "
-            "'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' "
-            "multiversioning cannot be combined"
-            " with attribute %1">;
+def err_multiversion_disallowed_other_attr : Error<
+  "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioning cannot be combined"
+  " with attribute %1">;
 def err_multiversion_mismatched_attrs
     : Error<"attributes on multiversioned functions must all match, attribute "
             "%0 %select{is missing|has 
diff erent arguments}1">;
@@ -11263,14 +11258,11 @@ def err_multiversion_
diff  : Error<
   "multiversioned function declaration has a 
diff erent %select{calling convention"
   "|return type|constexpr specification|inline specification|linkage|"
   "language linkage}0">;
-def err_multiversion_doesnt_support
-    : Error<"attribute "
-            "'%select{|target|cpu_specific|cpu_dispatch|target_clones}0' "
-            "multiversioned functions do not "
-            "yet support %select{function templates|virtual functions|"
-            "deduced return types|constructors|destructors|deleted functions|"
-            "defaulted functions|constexpr functions|consteval "
-            "function|lambdas}1">;
+def err_multiversion_doesnt_support : Error<
+  "attribute '%select{target|cpu_specific|cpu_dispatch}0' multiversioned functions do not "
+  "yet support %select{function templates|virtual functions|"
+  "deduced return types|constructors|destructors|deleted functions|"
+  "defaulted functions|constexpr functions|consteval function}1">;
 def err_multiversion_not_allowed_on_main : Error<
   "'main' cannot be a multiversioned function">;
 def err_multiversion_not_supported : Error<
@@ -11287,19 +11279,6 @@ def warn_multiversion_duplicate_entries : Warning<
 def warn_dispatch_body_ignored : Warning<
   "body of cpu_dispatch function will be ignored">,
   InGroup<FunctionMultiVersioning>;
-def err_target_clone_must_have_default
-    : Error<"'target_clones' multiversioning requires a default target">;
-def err_target_clone_doesnt_match
-    : Error<"'target_clones' attribute does not match previous declaration">;
-def warn_target_clone_mixed_values
-    : ExtWarn<
-          "mixing 'target_clones' specifier mechanisms is permitted for GCC "
-          "compatibility; use a comma separated sequence of string literals, "
-          "or a string literal containing a comma-separated list of versions">,
-      InGroup<TargetClonesMixedSpecifiers>;
-def warn_target_clone_duplicate_options
-    : Warning<"version list contains duplicate entries">,
-      InGroup<FunctionMultiVersioning>;
 
 // three-way comparison operator diagnostics
 def err_implied_comparison_category_type_not_found : Error<

diff  --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 330827bad88a1..5f5755ef13435 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4352,10 +4352,6 @@ class Sema final {
   llvm::Error isValidSectionSpecifier(StringRef Str);
   bool checkSectionName(SourceLocation LiteralLoc, StringRef Str);
   bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str);
-  bool checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
-                                   const StringLiteral *Literal,
-                                   bool &HasDefault, bool &HasCommas,
-                                   SmallVectorImpl<StringRef> &Strings);
   bool checkMSInheritanceAttrOnDefinition(
       CXXRecordDecl *RD, SourceRange Range, bool BestCase,
       MSInheritanceModel SemanticSpelling);

diff  --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index 3d180844fdafd..f0b931bdc9050 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -11797,15 +11797,6 @@ void ASTContext::getFunctionFeatureMap(llvm::StringMap<bool> &FeatureMap,
                     Target->getTargetOpts().FeaturesAsWritten.begin(),
                     Target->getTargetOpts().FeaturesAsWritten.end());
     Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
-  } else if (const auto *TC = FD->getAttr<TargetClonesAttr>()) {
-    std::vector<std::string> Features;
-    StringRef VersionStr = TC->getFeatureStr(GD.getMultiVersionIndex());
-    if (VersionStr.startswith("arch="))
-      TargetCPU = VersionStr.drop_front(sizeof("arch=") - 1);
-    else if (VersionStr != "default")
-      Features.push_back((StringRef{"+"} + VersionStr).str());
-
-    Target->initFeatureMap(FeatureMap, getDiagnostics(), TargetCPU, Features);
   } else {
     FeatureMap = Target->getTargetOpts().FeatureMap;
   }

diff  --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 68dfef248f65a..5ea091edcf4c9 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -3271,8 +3271,6 @@ MultiVersionKind FunctionDecl::getMultiVersionKind() const {
     return MultiVersionKind::CPUDispatch;
   if (hasAttr<CPUSpecificAttr>())
     return MultiVersionKind::CPUSpecific;
-  if (hasAttr<TargetClonesAttr>())
-    return MultiVersionKind::TargetClones;
   return MultiVersionKind::None;
 }
 
@@ -3288,10 +3286,6 @@ bool FunctionDecl::isTargetMultiVersion() const {
   return isMultiVersion() && hasAttr<TargetAttr>();
 }
 
-bool FunctionDecl::isTargetClonesMultiVersion() const {
-  return isMultiVersion() && hasAttr<TargetClonesAttr>();
-}
-
 void
 FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) {
   redeclarable_base::setPreviousDecl(PrevDecl);

diff  --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 2e497ae45994e..c28c2e2e85d89 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1264,20 +1264,6 @@ static bool isUniqueInternalLinkageDecl(GlobalDecl GD,
          (CGM.getFunctionLinkage(GD) == llvm::GlobalValue::InternalLinkage);
 }
 
-static void AppendTargetClonesMangling(const CodeGenModule &CGM,
-                                       const TargetClonesAttr *Attr,
-                                       unsigned VersionIndex,
-                                       raw_ostream &Out) {
-  Out << '.';
-  StringRef FeatureStr = Attr->getFeatureStr(VersionIndex);
-  if (FeatureStr.startswith("arch="))
-    Out << "arch_" << FeatureStr.substr(sizeof("arch=") - 1);
-  else
-    Out << FeatureStr;
-
-  Out << '.' << Attr->getMangledIndex(VersionIndex);
-}
-
 static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD,
                                       const NamedDecl *ND,
                                       bool OmitMultiVersionMangling = false) {
@@ -1331,10 +1317,6 @@ static std::string getMangledNameImpl(CodeGenModule &CGM, GlobalDecl GD,
       case MultiVersionKind::Target:
         AppendTargetMangling(CGM, FD->getAttr<TargetAttr>(), Out);
         break;
-      case MultiVersionKind::TargetClones:
-        AppendTargetClonesMangling(CGM, FD->getAttr<TargetClonesAttr>(),
-                                   GD.getMultiVersionIndex(), Out);
-        break;
       case MultiVersionKind::None:
         llvm_unreachable("None multiversion type isn't valid here");
       }
@@ -1999,9 +1981,8 @@ bool CodeGenModule::GetCPUAndFeaturesAttributes(GlobalDecl GD,
   FD = FD ? FD->getMostRecentDecl() : FD;
   const auto *TD = FD ? FD->getAttr<TargetAttr>() : nullptr;
   const auto *SD = FD ? FD->getAttr<CPUSpecificAttr>() : nullptr;
-  const auto *TC = FD ? FD->getAttr<TargetClonesAttr>() : nullptr;
   bool AddedAttr = false;
-  if (TD || SD || TC) {
+  if (TD || SD) {
     llvm::StringMap<bool> FeatureMap;
     getContext().getFunctionFeatureMap(FeatureMap, GD);
 
@@ -3243,12 +3224,6 @@ void CodeGenModule::EmitMultiVersionFunctionDefinition(GlobalDecl GD,
     for (unsigned I = 0; I < Spec->cpus_size(); ++I)
       EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
     // Requires multiple emits.
-  } else if (FD->isTargetClonesMultiVersion()) {
-    auto *Clone = FD->getAttr<TargetClonesAttr>();
-    for (unsigned I = 0; I < Clone->featuresStrs_size(); ++I)
-      if (Clone->isFirstOfVersion(I))
-        EmitGlobalFunctionDefinition(GD.getWithMultiVersionIndex(I), nullptr);
-    EmitTargetClonesResolver(GD);
   } else
     EmitGlobalFunctionDefinition(GD, GV);
 }
@@ -3330,63 +3305,6 @@ llvm::GlobalValue::LinkageTypes getMultiversionLinkage(CodeGenModule &CGM,
   return llvm::GlobalValue::WeakODRLinkage;
 }
 
-void CodeGenModule::EmitTargetClonesResolver(GlobalDecl GD) {
-  const auto *FD = cast<FunctionDecl>(GD.getDecl());
-  assert(FD && "Not a FunctionDecl?");
-  const auto *TC = FD->getAttr<TargetClonesAttr>();
-  assert(TC && "Not a target_clones Function?");
-
-  QualType CanonTy = Context.getCanonicalType(FD->getType());
-  llvm::Type *DeclTy = getTypes().ConvertType(CanonTy);
-
-  if (const auto *CXXFD = dyn_cast<CXXMethodDecl>(FD)) {
-    const CGFunctionInfo &FInfo = getTypes().arrangeCXXMethodDeclaration(CXXFD);
-    DeclTy = getTypes().GetFunctionType(FInfo);
-  }
-
-  llvm::Function *ResolverFunc;
-  if (getTarget().supportsIFunc()) {
-    auto *IFunc = cast<llvm::GlobalIFunc>(
-        GetOrCreateMultiVersionResolver(GD, DeclTy, FD));
-    ResolverFunc = cast<llvm::Function>(IFunc->getResolver());
-  } else
-    ResolverFunc =
-        cast<llvm::Function>(GetOrCreateMultiVersionResolver(GD, DeclTy, FD));
-
-  SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> Options;
-  for (unsigned VersionIndex = 0; VersionIndex < TC->featuresStrs_size();
-       ++VersionIndex) {
-    if (!TC->isFirstOfVersion(VersionIndex))
-      continue;
-    StringRef Version = TC->getFeatureStr(VersionIndex);
-    StringRef MangledName =
-        getMangledName(GD.getWithMultiVersionIndex(VersionIndex));
-    llvm::Constant *Func = GetGlobalValue(MangledName);
-    assert(Func &&
-           "Should have already been created before calling resolver emit");
-
-    StringRef Architecture;
-    llvm::SmallVector<StringRef, 1> Feature;
-
-    if (Version.startswith("arch="))
-      Architecture = Version.drop_front(sizeof("arch=") - 1);
-    else if (Version != "default")
-      Feature.push_back(Version);
-
-    Options.emplace_back(cast<llvm::Function>(Func), Architecture, Feature);
-  }
-
-  const TargetInfo &TI = getTarget();
-  std::stable_sort(
-      Options.begin(), Options.end(),
-      [&TI](const CodeGenFunction::MultiVersionResolverOption &LHS,
-            const CodeGenFunction::MultiVersionResolverOption &RHS) {
-        return TargetMVPriority(TI, LHS) > TargetMVPriority(TI, RHS);
-      });
-  CodeGenFunction CGF(*this);
-  CGF.EmitMultiVersionResolver(ResolverFunc, Options);
-}
-
 void CodeGenModule::emitMultiVersionFunctions() {
   std::vector<GlobalDecl> MVFuncsToEmit;
   MultiVersionFuncs.swap(MVFuncsToEmit);
@@ -3591,25 +3509,8 @@ llvm::Constant *CodeGenModule::GetOrCreateMultiVersionResolver(
   // Since this is the first time we've created this IFunc, make sure
   // that we put this multiversioned function into the list to be
   // replaced later if necessary (target multiversioning only).
-  if (FD->isTargetMultiVersion())
+  if (!FD->isCPUDispatchMultiVersion() && !FD->isCPUSpecificMultiVersion())
     MultiVersionFuncs.push_back(GD);
-  else if (FD->isTargetClonesMultiVersion()) {
-    // In target_clones multiversioning, make sure we emit this if used.
-    auto DDI =
-        DeferredDecls.find(getMangledName(GD.getWithMultiVersionIndex(0)));
-    if (DDI != DeferredDecls.end()) {
-      addDeferredDeclToEmit(GD);
-      DeferredDecls.erase(DDI);
-    } else {
-      // Emit the symbol of the 1st variant, so that the deferred decls know we
-      // need it, otherwise the only global value will be the resolver/ifunc,
-      // which end up getting broken if we search for them with GetGlobalValue'.
-      GetOrCreateLLVMFunction(
-          getMangledName(GD.getWithMultiVersionIndex(0)), DeclTy, FD,
-          /*ForVTable=*/false, /*DontDefer=*/true,
-          /*IsThunk=*/false, llvm::AttributeList(), ForDefinition);
-    }
-  }
 
   if (getTarget().supportsIFunc()) {
     llvm::Type *ResolverType = llvm::FunctionType::get(

diff  --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index e1c7f486d334e..fbed22376c827 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -1500,7 +1500,6 @@ class CodeGenModule : public CodeGenTypeCache {
   void EmitAliasDefinition(GlobalDecl GD);
   void emitIFuncDefinition(GlobalDecl GD);
   void emitCPUDispatchDefinition(GlobalDecl GD);
-  void EmitTargetClonesResolver(GlobalDecl GD);
   void EmitObjCPropertyImplementations(const ObjCImplementationDecl *D);
   void EmitObjCIvarInitializations(ObjCImplementationDecl *D);
 

diff  --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6d6f7088fd55a..5d15fd2aec586 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -10268,9 +10268,13 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S,
                                                  const FunctionDecl *FD,
                                                  const FunctionDecl *CausedFD,
                                                  MultiVersionKind MVType) {
-  const auto Diagnose = [FD, CausedFD, MVType](Sema &S, const Attr *A) {
+  bool IsCPUSpecificCPUDispatchMVType =
+      MVType == MultiVersionKind::CPUDispatch ||
+      MVType == MultiVersionKind::CPUSpecific;
+  const auto Diagnose = [FD, CausedFD, IsCPUSpecificCPUDispatchMVType](
+                            Sema &S, const Attr *A) {
     S.Diag(FD->getLocation(), diag::err_multiversion_disallowed_other_attr)
-        << static_cast<unsigned>(MVType) << A;
+        << IsCPUSpecificCPUDispatchMVType << A;
     if (CausedFD)
       S.Diag(CausedFD->getLocation(), diag::note_multiversioning_caused_here);
     return true;
@@ -10288,10 +10292,6 @@ static bool checkNonMultiVersionCompatAttributes(Sema &S,
       if (MVType != MultiVersionKind::Target)
         return Diagnose(S, A);
       break;
-    case attr::TargetClones:
-      if (MVType != MultiVersionKind::TargetClones)
-        return Diagnose(S, A);
-      break;
     default:
       if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType))
         return Diagnose(S, A);
@@ -10318,7 +10318,6 @@ bool Sema::areMultiversionVariantFunctionsCompatible(
     DefaultedFuncs = 6,
     ConstexprFuncs = 7,
     ConstevalFuncs = 8,
-    Lambda = 9,
   };
   enum Different {
     CallingConv = 0,
@@ -10446,7 +10445,7 @@ static bool CheckMultiVersionAdditionalRules(Sema &S, const FunctionDecl *OldFD,
                           S.PDiag(diag::note_multiversioning_caused_here)),
       PartialDiagnosticAt(NewFD->getLocation(),
                           S.PDiag(diag::err_multiversion_doesnt_support)
-                              << static_cast<unsigned>(MVType)),
+                              << IsCPUSpecificCPUDispatchMVType),
       PartialDiagnosticAt(NewFD->getLocation(),
                           S.PDiag(diag::err_multiversion_
diff )),
       /*TemplatesSupported=*/false,
@@ -10575,30 +10574,21 @@ static bool CheckTargetCausesMultiVersioning(
   return false;
 }
 
-static bool MultiVersionTypesCompatible(MultiVersionKind Old,
-                                        MultiVersionKind New) {
-  if (Old == New || Old == MultiVersionKind::None ||
-      New == MultiVersionKind::None)
-    return true;
-
-  return (Old == MultiVersionKind::CPUDispatch &&
-          New == MultiVersionKind::CPUSpecific) ||
-         (Old == MultiVersionKind::CPUSpecific &&
-          New == MultiVersionKind::CPUDispatch);
-}
-
 /// Check the validity of a new function declaration being added to an existing
 /// multiversioned declaration collection.
 static bool CheckMultiVersionAdditionalDecl(
     Sema &S, FunctionDecl *OldFD, FunctionDecl *NewFD,
     MultiVersionKind NewMVType, const TargetAttr *NewTA,
     const CPUDispatchAttr *NewCPUDisp, const CPUSpecificAttr *NewCPUSpec,
-    const TargetClonesAttr *NewClones, bool &Redeclaration, NamedDecl *&OldDecl,
-    bool &MergeTypeWithPrevious, LookupResult &Previous) {
+    bool &Redeclaration, NamedDecl *&OldDecl, bool &MergeTypeWithPrevious,
+    LookupResult &Previous) {
 
   MultiVersionKind OldMVType = OldFD->getMultiVersionKind();
   // Disallow mixing of multiversioning types.
-  if (!MultiVersionTypesCompatible(OldMVType, NewMVType)) {
+  if ((OldMVType == MultiVersionKind::Target &&
+       NewMVType != MultiVersionKind::Target) ||
+      (NewMVType == MultiVersionKind::Target &&
+       OldMVType != MultiVersionKind::Target)) {
     S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed);
     S.Diag(OldFD->getLocation(), diag::note_previous_declaration);
     NewFD->setInvalidDecl();
@@ -10623,12 +10613,7 @@ static bool CheckMultiVersionAdditionalDecl(
     if (S.IsOverload(NewFD, CurFD, UseMemberUsingDeclRules))
       continue;
 
-    switch (NewMVType) {
-    case MultiVersionKind::None:
-      assert(OldMVType == MultiVersionKind::TargetClones &&
-             "Only target_clones can be omitted in subsequent declarations");
-      break;
-    case MultiVersionKind::Target: {
+    if (NewMVType == MultiVersionKind::Target) {
       const auto *CurTA = CurFD->getAttr<TargetAttr>();
       if (CurTA->getFeaturesStr() == NewTA->getFeaturesStr()) {
         NewFD->setIsMultiVersion();
@@ -10644,30 +10629,7 @@ static bool CheckMultiVersionAdditionalDecl(
         NewFD->setInvalidDecl();
         return true;
       }
-      break;
-    }
-    case MultiVersionKind::TargetClones: {
-      const auto *CurClones = CurFD->getAttr<TargetClonesAttr>();
-      Redeclaration = true;
-      OldDecl = CurFD;
-      MergeTypeWithPrevious = true;
-      NewFD->setIsMultiVersion();
-
-      if (CurClones && NewClones &&
-          (CurClones->featuresStrs_size() != NewClones->featuresStrs_size() ||
-           !std::equal(CurClones->featuresStrs_begin(),
-                       CurClones->featuresStrs_end(),
-                       NewClones->featuresStrs_begin()))) {
-        S.Diag(NewFD->getLocation(), diag::err_target_clone_doesnt_match);
-        S.Diag(CurFD->getLocation(), diag::note_previous_declaration);
-        NewFD->setInvalidDecl();
-        return true;
-      }
-
-      return false;
-    }
-    case MultiVersionKind::CPUSpecific:
-    case MultiVersionKind::CPUDispatch: {
+    } else {
       const auto *CurCPUSpec = CurFD->getAttr<CPUSpecificAttr>();
       const auto *CurCPUDisp = CurFD->getAttr<CPUDispatchAttr>();
       // Handle CPUDispatch/CPUSpecific versions.
@@ -10722,8 +10684,8 @@ static bool CheckMultiVersionAdditionalDecl(
           }
         }
       }
-      break;
-    }
+      // If the two decls aren't the same MVType, there is no possible error
+      // condition.
     }
   }
 
@@ -10759,6 +10721,7 @@ static bool CheckMultiVersionAdditionalDecl(
   return false;
 }
 
+
 /// Check the validity of a mulitversion function declaration.
 /// Also sets the multiversion'ness' of the function itself.
 ///
@@ -10772,14 +10735,23 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
   const auto *NewTA = NewFD->getAttr<TargetAttr>();
   const auto *NewCPUDisp = NewFD->getAttr<CPUDispatchAttr>();
   const auto *NewCPUSpec = NewFD->getAttr<CPUSpecificAttr>();
-  const auto *NewClones = NewFD->getAttr<TargetClonesAttr>();
-  MultiVersionKind MVType = NewFD->getMultiVersionKind();
+
+  // Mixing Multiversioning types is prohibited.
+  if ((NewTA && NewCPUDisp) || (NewTA && NewCPUSpec) ||
+      (NewCPUDisp && NewCPUSpec)) {
+    S.Diag(NewFD->getLocation(), diag::err_multiversion_types_mixed);
+    NewFD->setInvalidDecl();
+    return true;
+  }
+
+  MultiVersionKind  MVType = NewFD->getMultiVersionKind();
 
   // Main isn't allowed to become a multiversion function, however it IS
   // permitted to have 'main' be marked with the 'target' optimization hint.
   if (NewFD->isMain()) {
-    if (MVType != MultiVersionKind::None &&
-        !(MVType == MultiVersionKind::Target && !NewTA->isDefaultVersion())) {
+    if ((MVType == MultiVersionKind::Target && NewTA->isDefaultVersion()) ||
+        MVType == MultiVersionKind::CPUDispatch ||
+        MVType == MultiVersionKind::CPUSpecific) {
       S.Diag(NewFD->getLocation(), diag::err_multiversion_not_allowed_on_main);
       NewFD->setInvalidDecl();
       return true;
@@ -10802,35 +10774,13 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
   if (!OldFD->isMultiVersion() && MVType == MultiVersionKind::None)
     return false;
 
-  // Multiversioned redeclarations aren't allowed to omit the attribute, except
-  // for target_clones.
-  if (OldFD->isMultiVersion() && MVType == MultiVersionKind::None &&
-      OldFD->getMultiVersionKind() != MultiVersionKind::TargetClones) {
+  if (OldFD->isMultiVersion() && MVType == MultiVersionKind::None) {
     S.Diag(NewFD->getLocation(), diag::err_multiversion_required_in_redecl)
         << (OldFD->getMultiVersionKind() != MultiVersionKind::Target);
     NewFD->setInvalidDecl();
     return true;
   }
 
-  if (!OldFD->isMultiVersion()) {
-    switch (MVType) {
-    case MultiVersionKind::Target:
-      return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA,
-                                              Redeclaration, OldDecl,
-                                              MergeTypeWithPrevious, Previous);
-    case MultiVersionKind::TargetClones:
-      if (OldFD->isUsed(false)) {
-        NewFD->setInvalidDecl();
-        return S.Diag(NewFD->getLocation(), diag::err_multiversion_after_used);
-      }
-      OldFD->setIsMultiVersion();
-      break;
-    case MultiVersionKind::CPUDispatch:
-    case MultiVersionKind::CPUSpecific:
-    case MultiVersionKind::None:
-      break;
-    }
-  }
   // Handle the target potentially causes multiversioning case.
   if (!OldFD->isMultiVersion() && MVType == MultiVersionKind::Target)
     return CheckTargetCausesMultiVersioning(S, OldFD, NewFD, NewTA,
@@ -10841,8 +10791,8 @@ static bool CheckMultiVersionFunction(Sema &S, FunctionDecl *NewFD,
   // appropriate attribute in the current function decl.  Resolve that these are
   // still compatible with previous declarations.
   return CheckMultiVersionAdditionalDecl(
-      S, OldFD, NewFD, MVType, NewTA, NewCPUDisp, NewCPUSpec, NewClones,
-      Redeclaration, OldDecl, MergeTypeWithPrevious, Previous);
+      S, OldFD, NewFD, MVType, NewTA, NewCPUDisp, NewCPUSpec, Redeclaration,
+      OldDecl, MergeTypeWithPrevious, Previous);
 }
 
 /// Perform semantic checking of a new function declaration.

diff  --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index f54196879e0c2..743b292d29759 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -1965,28 +1965,6 @@ static void handleRestrictAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
 }
 
 static void handleCPUSpecificAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
-  // Ensure we don't combine these with themselves, since that causes some
-  // confusing behavior.
-  if (AL.getParsedKind() == ParsedAttr::AT_CPUDispatch) {
-    if (checkAttrMutualExclusion<CPUSpecificAttr>(S, D, AL))
-      return;
-
-    if (const auto *Other = D->getAttr<CPUDispatchAttr>()) {
-      S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL;
-      S.Diag(Other->getLocation(), diag::note_conflicting_attribute);
-      return;
-    }
-  } else if (AL.getParsedKind() == ParsedAttr::AT_CPUSpecific) {
-    if (checkAttrMutualExclusion<CPUDispatchAttr>(S, D, AL))
-      return;
-
-    if (const auto *Other = D->getAttr<CPUSpecificAttr>()) {
-      S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL;
-      S.Diag(Other->getLocation(), diag::note_conflicting_attribute);
-      return;
-    }
-  }
-
   FunctionDecl *FD = cast<FunctionDecl>(D);
 
   if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
@@ -3233,41 +3211,40 @@ static void handleCodeSegAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
 bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
   enum FirstParam { Unsupported, Duplicate, Unknown };
   enum SecondParam { None, Architecture, Tune };
-  enum ThirdParam { Target, TargetClones };
   if (AttrStr.contains("fpmath="))
     return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-           << Unsupported << None << "fpmath=" << Target;
+           << Unsupported << None << "fpmath=";
 
   // Diagnose use of tune if target doesn't support it.
   if (!Context.getTargetInfo().supportsTargetAttributeTune() &&
       AttrStr.contains("tune="))
     return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-           << Unsupported << None << "tune=" << Target;
+           << Unsupported << None << "tune=";
 
   ParsedTargetAttr ParsedAttrs = TargetAttr::parse(AttrStr);
 
   if (!ParsedAttrs.Architecture.empty() &&
       !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Architecture))
     return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-           << Unknown << Architecture << ParsedAttrs.Architecture << Target;
+           << Unknown << Architecture << ParsedAttrs.Architecture;
 
   if (!ParsedAttrs.Tune.empty() &&
       !Context.getTargetInfo().isValidCPUName(ParsedAttrs.Tune))
     return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-           << Unknown << Tune << ParsedAttrs.Tune << Target;
+           << Unknown << Tune << ParsedAttrs.Tune;
 
   if (ParsedAttrs.DuplicateArchitecture)
     return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-           << Duplicate << None << "arch=" << Target;
+           << Duplicate << None << "arch=";
   if (ParsedAttrs.DuplicateTune)
     return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-           << Duplicate << None << "tune=" << Target;
+           << Duplicate << None << "tune=";
 
   for (const auto &Feature : ParsedAttrs.Features) {
     auto CurFeature = StringRef(Feature).drop_front(); // remove + or -.
     if (!Context.getTargetInfo().isValidFeatureName(CurFeature))
       return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-             << Unsupported << None << CurFeature << Target;
+             << Unsupported << None << CurFeature;
   }
 
   TargetInfo::BranchProtectionInfo BPI;
@@ -3277,7 +3254,7 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
           ParsedAttrs.BranchProtection, BPI, Error)) {
     if (Error.empty())
       return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-             << Unsupported << None << "branch-protection" << Target;
+             << Unsupported << None << "branch-protection";
     else
       return Diag(LiteralLoc, diag::err_invalid_branch_protection_spec)
              << Error;
@@ -3287,14 +3264,6 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) {
 }
 
 static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
-  // Ensure we don't combine these with themselves, since that causes some
-  // confusing behavior.
-  if (const auto *Other = D->getAttr<TargetAttr>()) {
-    S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL;
-    S.Diag(Other->getLocation(), diag::note_conflicting_attribute);
-    return;
-  }
-
   StringRef Str;
   SourceLocation LiteralLoc;
   if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) ||
@@ -3305,107 +3274,6 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   D->addAttr(NewAttr);
 }
 
-bool Sema::checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str,
-                                       const StringLiteral *Literal,
-                                       bool &HasDefault, bool &HasCommas,
-                                       SmallVectorImpl<StringRef> &Strings) {
-  enum FirstParam { Unsupported, Duplicate, Unknown };
-  enum SecondParam { None, Architecture, Tune };
-  enum ThirdParam { Target, TargetClones };
-  HasCommas = HasCommas || Str.contains(',');
-  // Warn on empty at the beginning of a string.
-  if (Str.size() == 0)
-    return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-           << Unsupported << None << "" << TargetClones;
-
-  std::pair<StringRef, StringRef> Parts = {{}, Str};
-  while (!Parts.second.empty()) {
-    Parts = Parts.second.split(',');
-    StringRef Cur = Parts.first.trim();
-    SourceLocation CurLoc = Literal->getLocationOfByte(
-        Cur.data() - Literal->getString().data(), getSourceManager(),
-        getLangOpts(), Context.getTargetInfo());
-
-    bool DefaultIsDupe = false;
-    if (Cur.empty())
-      return Diag(CurLoc, diag::warn_unsupported_target_attribute)
-             << Unsupported << None << "" << TargetClones;
-
-    if (Cur.startswith("arch=")) {
-      if (!Context.getTargetInfo().isValidCPUName(
-              Cur.drop_front(sizeof("arch=") - 1)))
-        return Diag(CurLoc, diag::warn_unsupported_target_attribute)
-               << Unsupported << Architecture
-               << Cur.drop_front(sizeof("arch=") - 1) << TargetClones;
-    } else if (Cur == "default") {
-      DefaultIsDupe = HasDefault;
-      HasDefault = true;
-    } else if (!Context.getTargetInfo().isValidFeatureName(Cur))
-      return Diag(CurLoc, diag::warn_unsupported_target_attribute)
-             << Unsupported << None << Cur << TargetClones;
-
-    if (llvm::find(Strings, Cur) != Strings.end() || DefaultIsDupe)
-      Diag(CurLoc, diag::warn_target_clone_duplicate_options);
-    // Note: Add even if there are duplicates, since it changes name mangling.
-    Strings.push_back(Cur);
-  }
-
-  if (Str.rtrim().endswith(","))
-    return Diag(LiteralLoc, diag::warn_unsupported_target_attribute)
-           << Unsupported << None << "" << TargetClones;
-  return false;
-}
-
-static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
-  // Ensure we don't combine these with themselves, since that causes some
-  // confusing behavior.
-  if (const auto *Other = D->getAttr<TargetClonesAttr>()) {
-    S.Diag(AL.getLoc(), diag::err_disallowed_duplicate_attribute) << AL;
-    S.Diag(Other->getLocation(), diag::note_conflicting_attribute);
-    return;
-  }
-  if (checkAttrMutualExclusion<TargetClonesAttr>(S, D, AL))
-    return;
-
-  SmallVector<StringRef, 2> Strings;
-  bool HasCommas = false, HasDefault = false;
-
-  for (unsigned I = 0, E = AL.getNumArgs(); I != E; ++I) {
-    StringRef CurStr;
-    SourceLocation LiteralLoc;
-    if (!S.checkStringLiteralArgumentAttr(AL, I, CurStr, &LiteralLoc) ||
-        S.checkTargetClonesAttrString(
-            LiteralLoc, CurStr,
-            cast<StringLiteral>(AL.getArgAsExpr(I)->IgnoreParenCasts()),
-            HasDefault, HasCommas, Strings))
-      return;
-  }
-
-  if (HasCommas && AL.getNumArgs() > 1)
-    S.Diag(AL.getLoc(), diag::warn_target_clone_mixed_values);
-
-  if (!HasDefault) {
-    S.Diag(AL.getLoc(), diag::err_target_clone_must_have_default);
-    return;
-  }
-
-  // FIXME: We could probably figure out how to get this to work for lambdas
-  // someday.
-  if (const auto *MD = dyn_cast<CXXMethodDecl>(D)) {
-    if (MD->getParent()->isLambda()) {
-      S.Diag(D->getLocation(), diag::err_multiversion_doesnt_support)
-          << static_cast<unsigned>(MultiVersionKind::TargetClones)
-          << /*Lambda*/ 9;
-      return;
-    }
-  }
-
-  cast<FunctionDecl>(D)->setIsMultiVersion();
-  TargetClonesAttr *NewAttr = ::new (S.Context)
-      TargetClonesAttr(S.Context, AL, Strings.data(), Strings.size());
-  D->addAttr(NewAttr);
-}
-
 static void handleMinVectorWidthAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
   Expr *E = AL.getArgAsExpr(0);
   uint32_t VecWidth;
@@ -8348,9 +8216,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
   case ParsedAttr::AT_Target:
     handleTargetAttr(S, D, AL);
     break;
-  case ParsedAttr::AT_TargetClones:
-    handleTargetClonesAttr(S, D, AL);
-    break;
   case ParsedAttr::AT_MinVectorWidth:
     handleMinVectorWidthAttr(S, D, AL);
     break;

diff  --git a/clang/test/CodeGen/attr-target-clones.c b/clang/test/CodeGen/attr-target-clones.c
deleted file mode 100644
index e17cca125b5ba..0000000000000
--- a/clang/test/CodeGen/attr-target-clones.c
+++ /dev/null
@@ -1,126 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefixes=LINUX,CHECK
-// RUN: %clang_cc1 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefixes=WINDOWS,CHECK
-
-// LINUX: @foo.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo.resolver
-// LINUX: @foo_dupes.ifunc = weak_odr ifunc void (), void ()* ()* @foo_dupes.resolver
-// LINUX: @unused.ifunc = weak_odr ifunc void (), void ()* ()* @unused.resolver
-// LINUX: @foo_inline.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo_inline.resolver
-// LINUX: @foo_inline2.ifunc = weak_odr ifunc i32 (), i32 ()* ()* @foo_inline2.resolver
-
-int __attribute__((target_clones("sse4.2, default"))) foo(void) { return 0; }
-// LINUX: define {{.*}}i32 @foo.sse4.2.0()
-// LINUX: define {{.*}}i32 @foo.default.1()
-// LINUX: define i32 ()* @foo.resolver()
-// LINUX: ret i32 ()* @foo.sse4.2.0
-// LINUX: ret i32 ()* @foo.default.1
-
-// WINDOWS: define dso_local i32 @foo.sse4.2.0()
-// WINDOWS: define dso_local i32 @foo.default.1()
-// WINDOWS: define dso_local i32 @foo()
-// WINDOWS: musttail call i32 @foo.sse4.2.0
-// WINDOWS: musttail call i32 @foo.default.1
-
-__attribute__((target_clones("default,default ,sse4.2"))) void foo_dupes(void) {}
-// LINUX: define {{.*}}void @foo_dupes.default.1()
-// LINUX: define {{.*}}void @foo_dupes.sse4.2.0()
-// LINUX: define void ()* @foo_dupes.resolver()
-// LINUX: ret void ()* @foo_dupes.sse4.2.0
-// LINUX: ret void ()* @foo_dupes.default.1
-
-// WINDOWS: define dso_local void @foo_dupes.default.1()
-// WINDOWS: define dso_local void @foo_dupes.sse4.2.0()
-// WINDOWS: define dso_local void @foo_dupes()
-// WINDOWS: musttail call void @foo_dupes.sse4.2.0
-// WINDOWS: musttail call void @foo_dupes.default.1
-
-void bar2() {
-  // LINUX: define {{.*}}void @bar2()
-  // WINDOWS: define dso_local void @bar2()
-  foo_dupes();
-  // LINUX: call void @foo_dupes.ifunc()
-  // WINDOWS: call void @foo_dupes()
-}
-
-int bar() {
-  // LINUX: define {{.*}}i32 @bar() #[[DEF:[0-9]+]]
-  // WINDOWS: define dso_local i32 @bar() #[[DEF:[0-9]+]]
-  return foo();
-  // LINUX: call i32 @foo.ifunc()
-  // WINDOWS: call i32 @foo()
-}
-
-void __attribute__((target_clones("default, arch=ivybridge"))) unused(void) {}
-// LINUX: define {{.*}}void @unused.default.1()
-// LINUX: define {{.*}}void @unused.arch_ivybridge.0()
-// LINUX: define void ()* @unused.resolver()
-// LINUX: ret void ()* @unused.arch_ivybridge.0
-// LINUX: ret void ()* @unused.default.1
-
-// WINDOWS: define dso_local void @unused.default.1()
-// WINDOWS: define dso_local void @unused.arch_ivybridge.0()
-// WINDOWS: define dso_local void @unused()
-// WINDOWS: musttail call void @unused.arch_ivybridge.0
-// WINDOWS: musttail call void @unused.default.1
-
-
-inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2")))
-foo_inline(void) { return 0; }
-inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2")))
-foo_inline2(void);
-
-int bar3() {
-  // LINUX: define {{.*}}i32 @bar3()
-  // WINDOWS: define dso_local i32 @bar3()
-  return foo_inline() + foo_inline2();
-  // LINUX: call i32 @foo_inline.ifunc()
-  // LINUX: call i32 @foo_inline2.ifunc()
-  // WINDOWS: call i32 @foo_inline()
-  // WINDOWS: call i32 @foo_inline2()
-}
-
-// Deferred emission of foo_inline, which got delayed because it is inline.
-// LINUX: define i32 ()* @foo_inline.resolver()
-// LINUX: ret i32 ()* @foo_inline.arch_sandybridge.0
-// LINUX: ret i32 ()* @foo_inline.sse4.2.1
-// LINUX: ret i32 ()* @foo_inline.default.2
-
-// WINDOWS: define dso_local i32 @foo_inline()
-// WINDOWS: musttail call i32 @foo_inline.arch_sandybridge.0
-// WINDOWS: musttail call i32 @foo_inline.sse4.2.1
-// WINDOWS: musttail call i32 @foo_inline.default.2
-
-inline int __attribute__((target_clones("arch=sandybridge,default,sse4.2")))
-foo_inline2(void){ return 0; }
-// LINUX: define linkonce i32 @foo_inline2.arch_sandybridge.0() #[[SB:[0-9]+]]
-// LINUX: define i32 ()* @foo_inline2.resolver()
-// LINUX: ret i32 ()* @foo_inline2.arch_sandybridge.0
-// LINUX: ret i32 ()* @foo_inline2.sse4.2.1
-// LINUX: ret i32 ()* @foo_inline2.default.2
-
-// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.arch_sandybridge.0() #[[SB:[0-9]+]]
-// WINDOWS: define dso_local i32 @foo_inline2()
-// WINDOWS: musttail call i32 @foo_inline2.arch_sandybridge.0
-// WINDOWS: musttail call i32 @foo_inline2.sse4.2.1
-// WINDOWS: musttail call i32 @foo_inline2.default.2
-
-// LINUX: define linkonce i32 @foo_inline.arch_sandybridge.0() #[[SB]]
-// LINUX: define linkonce i32 @foo_inline.default.2() #[[DEF]]
-// LINUX: define linkonce i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
-
-// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.arch_sandybridge.0() #[[SB]]
-// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.default.2() #[[DEF]]
-// WINDOWS: define linkonce_odr dso_local i32 @foo_inline.sse4.2.1() #[[SSE42:[0-9]+]]
-
-
-// LINUX: define linkonce i32 @foo_inline2.default.2() #[[DEF]]
-// LINUX: define linkonce i32 @foo_inline2.sse4.2.1() #[[SSE42]]
-
-// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.default.2() #[[DEF]]
-// WINDOWS: define linkonce_odr dso_local i32 @foo_inline2.sse4.2.1() #[[SSE42]]
-
-// CHECK: attributes #[[SSE42]] =
-// CHECK-SAME: "target-features"="+crc32,+cx8,+mmx,+popcnt,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87"
-// CHECK: attributes #[[DEF]] =
-// Don't bother checking features, we verified it is the same as a normal function.
-// CHECK: attributes #[[SB]] =
-// CHECK-SAME: "target-features"="+avx,+crc32,+cx16,+cx8,+fxsr,+mmx,+pclmul,+popcnt,+sahf,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+ssse3,+x87,+xsave,+xsaveopt"

diff  --git a/clang/test/CodeGenCXX/attr-target-clones.cpp b/clang/test/CodeGenCXX/attr-target-clones.cpp
deleted file mode 100644
index 9830ba54c4f1f..0000000000000
--- a/clang/test/CodeGenCXX/attr-target-clones.cpp
+++ /dev/null
@@ -1,116 +0,0 @@
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s --check-prefix=LINUX
-// RUN: %clang_cc1 -std=c++11 -triple x86_64-windows-pc -emit-llvm %s -o - | FileCheck %s --check-prefix=WINDOWS
-
-// Overloaded ifuncs
-// LINUX: @_Z10overloadedi.ifunc = weak_odr ifunc i32 (i32), i32 (i32)* ()* @_Z10overloadedi.resolver
-// LINUX: @_Z10overloadedPKc.ifunc = weak_odr ifunc i32 (i8*), i32 (i8*)* ()* @_Z10overloadedPKc.resolver
-// struct 'C' ifuncs, note the 'float, U' one doesn't get one.
-// LINUX: @_ZN1CIssE3fooEv.ifunc = weak_odr ifunc i32 (%struct.C*), i32 (%struct.C*)* ()* @_ZN1CIssE3fooEv.resolver
-// LINUX: @_ZN1CIisE3fooEv.ifunc = weak_odr ifunc i32 (%struct.C.0*), i32 (%struct.C.0*)* ()* @_ZN1CIisE3fooEv.resolver
-// LINUX: @_ZN1CIdfE3fooEv.ifunc = weak_odr ifunc i32 (%struct.C.2*), i32 (%struct.C.2*)* ()* @_ZN1CIdfE3fooEv.resolver
-
-int __attribute__((target_clones("sse4.2", "default"))) overloaded(int) { return 1; }
-// LINUX: define {{.*}}i32 @_Z10overloadedi.sse4.2.0(i32{{.+}})
-// LINUX: define {{.*}}i32 @_Z10overloadedi.default.1(i32{{.+}})
-// LINUX: define i32 (i32)* @_Z10overloadedi.resolver
-// LINUX: ret i32 (i32)* @_Z10overloadedi.sse4.2.0
-// LINUX: ret i32 (i32)* @_Z10overloadedi.default.1
-
-// WINDOWS: define dso_local i32 @"?overloaded@@YAHH at Z.sse4.2.0"(i32{{.+}})
-// WINDOWS: define dso_local i32 @"?overloaded@@YAHH at Z.default.1"(i32{{.+}})
-// WINDOWS: define dso_local i32 @"?overloaded@@YAHH at Z"(i32{{.+}})
-// WINDOWS: call i32 @"?overloaded@@YAHH at Z.sse4.2.0"
-// WINDOWS: call i32 @"?overloaded@@YAHH at Z.default.1"
-
-int __attribute__((target_clones("arch=ivybridge", "default"))) overloaded(const char *) { return 2; }
-// LINUX: define {{.*}}i32 @_Z10overloadedPKc.arch_ivybridge.0(i8*{{.+}})
-// LINUX: define {{.*}}i32 @_Z10overloadedPKc.default.1(i8*{{.+}})
-// LINUX: define i32 (i8*)* @_Z10overloadedPKc.resolver
-// LINUX: ret i32 (i8*)* @_Z10overloadedPKc.arch_ivybridge.0
-// LINUX: ret i32 (i8*)* @_Z10overloadedPKc.default.1
-
-// WINDOWS: define dso_local i32 @"?overloaded@@YAHPEBD at Z.arch_ivybridge.0"(i8*{{.+}})
-// WINDOWS: define dso_local i32 @"?overloaded@@YAHPEBD at Z.default.1"(i8*{{.+}})
-// WINDOWS: define dso_local i32 @"?overloaded@@YAHPEBD at Z"(i8*{{.+}})
-// WINDOWS: call i32 @"?overloaded@@YAHPEBD at Z.arch_ivybridge.0"
-// WINDOWS: call i32 @"?overloaded@@YAHPEBD at Z.default.1"
-//
-void use_overloaded() {
-  overloaded(1);
-  // LINUX: call i32 @_Z10overloadedi.ifunc
-  // WINDOWS: call i32 @"?overloaded@@YAHH at Z"
-  overloaded(nullptr);
-  // LINUX: call i32 @_Z10overloadedPKc.ifunc 
-  // WINDOWS: call i32 @"?overloaded@@YAHPEBD at Z"
-}
-
-template<typename T, typename U>
-struct C {
-int __attribute__((target_clones("sse4.2", "default"))) foo(){ return 1;}
-};
-template<typename U>
-struct C<int, U> {
-int __attribute__((target_clones("sse4.2", "default"))) foo(){ return 2;}
-};
-template<typename U>
-struct C<float, U> {
-int foo(){ return 2;}
-};
-template<>
-struct C<double, float> {
-int __attribute__((target_clones("sse4.2", "default"))) foo(){ return 3;}
-};
-
-void uses_specialized() {
-  C<short, short> c;
-  c.foo();
-  // LINUX: call i32 @_ZN1CIssE3fooEv.ifunc(%struct.C
-  // WINDOWS: call i32 @"?foo@?$C at FF@@QEAAHXZ"(%struct.C
-  C<int, short> c2;
-  c2.foo();
-  // LINUX: call i32 @_ZN1CIisE3fooEv.ifunc(%struct.C
-  // WINDOWS: call i32 @"?foo@?$C at HF@@QEAAHXZ"(%struct.C
-  C<float, short> c3;
-  c3.foo();
-  // Note this is not an ifunc/mv
-  // LINUX: call i32 @_ZN1CIfsE3fooEv(%struct.C
-  // WINDOWS: call i32 @"?foo@?$C at MF@@QEAAHXZ"(%struct.C
-  C<double, float> c4;
-  c4.foo();
-  // LINUX: call i32 @_ZN1CIdfE3fooEv.ifunc(%struct.C
-  // WINDOWS: call i32 @"?foo@?$C at NM@@QEAAHXZ"(%struct.C
-}
-
-// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.sse4.2.0(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at FF@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
-// LINUX: define i32 (%struct.C*)* @_ZN1CIssE3fooEv.resolver
-// LINUX: ret i32 (%struct.C*)* @_ZN1CIssE3fooEv.sse4.2.0
-// LINUX: ret i32 (%struct.C*)* @_ZN1CIssE3fooEv.default.1
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at FF@@QEAAHXZ"(%struct.C{{.+}})
-// WINDOWS: call i32 @"?foo@?$C at FF@@QEAAHXZ.sse4.2.0"
-// WINDOWS: call i32 @"?foo@?$C at FF@@QEAAHXZ.default.1"
-
-// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.sse4.2.0(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at HF@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
-// LINUX: define i32 (%struct.C{{.+}})* @_ZN1CIisE3fooEv.resolver
-// LINUX: ret i32 (%struct.C{{.+}})* @_ZN1CIisE3fooEv.sse4.2.0
-// LINUX: ret i32 (%struct.C{{.+}})* @_ZN1CIisE3fooEv.default.1
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at HF@@QEAAHXZ"(%struct.C{{.+}})
-// WINDOWS: call i32 @"?foo@?$C at HF@@QEAAHXZ.sse4.2.0"
-// WINDOWS: call i32 @"?foo@?$C at HF@@QEAAHXZ.default.1"
-
-// LINUX: define i32 (%struct.C{{.+}})* @_ZN1CIdfE3fooEv.resolver
-// LINUX: ret i32 (%struct.C{{.+}})* @_ZN1CIdfE3fooEv.sse4.2.0
-// LINUX: ret i32 (%struct.C{{.+}})* @_ZN1CIdfE3fooEv.default.1
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at NM@@QEAAHXZ"(%struct.C{{.+}})
-// WINDOWS: call i32 @"?foo@?$C at NM@@QEAAHXZ.sse4.2.0"
-// WINDOWS: call i32 @"?foo@?$C at NM@@QEAAHXZ.default.1"
-
-// LINUX: define {{.*}}i32 @_ZN1CIdfE3fooEv.sse4.2.0(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at NM@@QEAAHXZ.sse4.2.0"(%struct.C{{.+}})
-// LINUX: define {{.*}}i32 @_ZN1CIdfE3fooEv.default.1(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at NM@@QEAAHXZ.default.1"(%struct.C{{.+}})
-// LINUX: define {{.*}}i32 @_ZN1CIssE3fooEv.default.1(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at FF@@QEAAHXZ.default.1"(%struct.C{{.+}})
-// LINUX: define {{.*}}i32 @_ZN1CIisE3fooEv.default.1(%struct.C{{.+}})
-// WINDOWS: define {{.*}}i32 @"?foo@?$C at HF@@QEAAHXZ.default.1"(%struct.C{{.+}})

diff  --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
index e2b41812d66f5..199934b2791da 100644
--- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test
+++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test
@@ -172,7 +172,6 @@
 // CHECK-NEXT: SwiftObjCMembers (SubjectMatchRule_objc_interface)
 // CHECK-NEXT: TLSModel (SubjectMatchRule_variable_is_thread_local)
 // CHECK-NEXT: Target (SubjectMatchRule_function)
-// CHECK-NEXT: TargetClones (SubjectMatchRule_function)
 // CHECK-NEXT: TestTypestate (SubjectMatchRule_function_is_member)
 // CHECK-NEXT: TrivialABI (SubjectMatchRule_record)
 // CHECK-NEXT: Uninitialized (SubjectMatchRule_variable_is_local)

diff  --git a/clang/test/Sema/attr-cpuspecific.c b/clang/test/Sema/attr-cpuspecific.c
index 07ca516c8ae04..9cfeef8a23562 100644
--- a/clang/test/Sema/attr-cpuspecific.c
+++ b/clang/test/Sema/attr-cpuspecific.c
@@ -88,8 +88,7 @@ void __attribute__((target("default"))) addtl_attrs2(void);
 // expected-note at -2 {{previous declaration is here}}
 void __attribute__((cpu_specific(sandybridge))) addtl_attrs2(void);
 
-// expected-error at +2 {{'cpu_dispatch' and 'cpu_specific' attributes are not compatible}}
-// expected-note at +1 {{conflicting attribute is here}}
+// expected-error at +2 {{multiversioning attributes cannot be combined}}
 void __attribute((cpu_specific(sandybridge), cpu_dispatch(atom, sandybridge)))
 combine_attrs(void);
 

diff  --git a/clang/test/Sema/attr-target-clones.c b/clang/test/Sema/attr-target-clones.c
deleted file mode 100644
index ea7cf91c3ab86..0000000000000
--- a/clang/test/Sema/attr-target-clones.c
+++ /dev/null
@@ -1,88 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu  -fsyntax-only -verify %s
-
-// expected-error at +1 {{'target_clones' multiversioning requires a default target}}
-void __attribute__((target_clones("sse4.2", "arch=sandybridge")))
-no_default(void);
-
-// expected-error at +2 {{'target_clones' and 'target' attributes are not compatible}}
-// expected-note at +1 {{conflicting attribute is here}}
-void __attribute__((target("sse4.2"), target_clones("arch=sandybridge")))
-ignored_attr(void);
-// expected-error at +2 {{'target' and 'target_clones' attributes are not compatible}}
-// expected-note at +1 {{conflicting attribute is here}}
-void __attribute__((target_clones("arch=sandybridge,default"), target("sse4.2")))
-ignored_attr2(void);
-
-int redecl(void);
-int __attribute__((target_clones("sse4.2", "default"))) redecl(void) { return 1; }
-
-int __attribute__((target_clones("sse4.2", "default"))) redecl2(void);
-int __attribute__((target_clones("sse4.2", "default"))) redecl2(void) { return 1; }
-
-int __attribute__((target_clones("sse4.2", "default"))) redecl3(void);
-int redecl3(void);
-
-int __attribute__((target_clones("sse4.2", "arch=atom", "default"))) redecl4(void);
-// expected-error at +3 {{'target_clones' attribute does not match previous declaration}}
-// expected-note at -2 {{previous declaration is here}}
-int __attribute__((target_clones("sse4.2", "arch=sandybridge", "default")))
-redecl4(void) { return 1; }
-
-int __attribute__((target("sse4.2"))) redef2(void) { return 1; }
-// expected-error at +2 {{multiversioning attributes cannot be combined}}
-// expected-note at -2 {{previous declaration is here}}
-int __attribute__((target_clones("sse4.2", "default"))) redef2(void) { return 1; }
-
-int __attribute__((target_clones("sse4.2,default"))) redef3(void) { return 1; }
-// expected-error at +2 {{redefinition of 'redef3'}}
-// expected-note at -2 {{previous definition is here}}
-int __attribute__((target_clones("sse4.2,default"))) redef3(void) { return 1; }
-
-int __attribute__((target_clones("sse4.2,default"))) redef4(void) { return 1; }
-// expected-error at +2 {{redefinition of 'redef4'}}
-// expected-note at -2 {{previous definition is here}}
-int __attribute__((target_clones("sse4.2,default"))) redef4(void) { return 1; }
-
-// Duplicates are allowed, however they alter name mangling.
-// expected-warning at +2 {{mixing 'target_clones' specifier mechanisms is permitted for GCC compatibility}}
-// expected-warning at +1 2 {{version list contains duplicate entries}}
-int __attribute__((target_clones("arch=atom,arch=atom", "arch=atom,default")))
-dupes(void) { return 1; }
-
-// expected-warning at +1 {{unsupported '' in the 'target_clones' attribute string;}}
-void __attribute__((target_clones("")))
-empty_target_1(void);
-// expected-warning at +1 {{unsupported '' in the 'target_clones' attribute string;}}
-void __attribute__((target_clones(",default")))
-empty_target_2(void);
-// expected-warning at +1 {{unsupported '' in the 'target_clones' attribute string;}}
-void __attribute__((target_clones("default,")))
-empty_target_3(void);
-// expected-warning at +1 {{unsupported '' in the 'target_clones' attribute string;}}
-void __attribute__((target_clones("default, ,avx2")))
-empty_target_4(void);
-
-// expected-warning at +1 {{unsupported '' in the 'target_clones' attribute string;}}
-void __attribute__((target_clones("default,avx2", "")))
-empty_target_5(void);
-
-// expected-warning at +1 {{version list contains duplicate entries}}
-void __attribute__((target_clones("default", "default")))
-dupe_default(void);
-
-// expected-warning at +1 {{version list contains duplicate entries}}
-void __attribute__((target_clones("avx2,avx2,default")))
-dupe_normal(void);
-
-// expected-error at +2 {{attribute 'target_clones' cannot appear more than once on a declaration}}
-// expected-note at +1 {{conflicting attribute is here}}
-void __attribute__((target_clones("avx2,default"), target_clones("arch=atom,default")))
-dupe_normal2(void);
-
-int mv_after_use(void);
-int useage() {
-  return mv_after_use();
-}
-// expected-error at +1 {{function declaration cannot become a multiversioned function after first usage}}
-int __attribute__((target_clones("sse4.2", "default"))) mv_after_use(void) { return 1; }
-

diff  --git a/clang/test/SemaCXX/attr-target-clones.cpp b/clang/test/SemaCXX/attr-target-clones.cpp
deleted file mode 100644
index 68c9a4ff48ed9..0000000000000
--- a/clang/test/SemaCXX/attr-target-clones.cpp
+++ /dev/null
@@ -1,11 +0,0 @@
-// RUN: %clang_cc1 -triple x86_64-linux-gnu  -fsyntax-only -verify -fexceptions -fcxx-exceptions %s -std=c++14
-
-// expected-error at +2 {{attribute 'target_clones' multiversioned functions do not yet support function templates}}
-template<typename T, typename U>
-int __attribute__((target_clones("sse4.2", "default"))) foo(){ return 1;}
-
-void uses_lambda() {
-  // expected-error at +1 {{attribute 'target_clones' multiversioned functions do not yet support lambdas}}
-  auto x = []()__attribute__((target_clones("sse4.2", "arch=ivybridge", "default"))) {};
-  x();
-}


        


More information about the cfe-commits mailing list