Index: lib/CodeGen/CodeGenFunction.cpp =================================================================== --- lib/CodeGen/CodeGenFunction.cpp +++ lib/CodeGen/CodeGenFunction.cpp @@ -2267,8 +2267,24 @@ CGF->InsertHelper(I, Name, BB, InsertPt); } +static bool hasRequiredFeature(StringRef Feature, + llvm::StringMap& CallerFeatureMap, + std::string &Missing) { + SmallVector OrFeatures; + Feature.split(OrFeatures, '|'); + return std::any_of(OrFeatures.begin(), OrFeatures.end(), + [&](StringRef Feature) { + if (!CallerFeatureMap.lookup(Feature)) { + Missing = Feature.str(); + return false; + } + return true; + }); +} + static bool hasRequiredFeatures(const SmallVectorImpl &ReqFeatures, CodeGenModule &CGM, const FunctionDecl *FD, + const FunctionDecl *TargetDecl, std::string &FirstMissing) { // If there aren't any required features listed then go ahead and return. if (ReqFeatures.empty()) @@ -2279,20 +2295,23 @@ llvm::StringMap CallerFeatureMap; CGM.getFunctionFeatureMap(CallerFeatureMap, FD); + TargetAttr::ParsedTargetAttr ParsedAttr = CGM.getFunctionTargetAttrs(TargetDecl); + for (auto& Feature : ReqFeatures) { + if (std::any_of(ParsedAttr.Features.begin(), ParsedAttr.Features.end(), + [&](StringRef ExplicitFeature) { + if (ExplicitFeature[0] != '+') + return false; + return Feature == ExplicitFeature.substr(1); + })) + if (!hasRequiredFeature(Feature, CallerFeatureMap, FirstMissing)) + return false; + } + // If we have at least one of the features in the feature list return // true, otherwise return false. return std::all_of( ReqFeatures.begin(), ReqFeatures.end(), [&](StringRef Feature) { - SmallVector OrFeatures; - Feature.split(OrFeatures, '|'); - return std::any_of(OrFeatures.begin(), OrFeatures.end(), - [&](StringRef Feature) { - if (!CallerFeatureMap.lookup(Feature)) { - FirstMissing = Feature.str(); - return false; - } - return true; - }); + return hasRequiredFeature(Feature, CallerFeatureMap, FirstMissing); }); } @@ -2323,7 +2342,7 @@ if (!FeatureList || StringRef(FeatureList) == "") return; StringRef(FeatureList).split(ReqFeatures, ','); - if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature)) + if (!hasRequiredFeatures(ReqFeatures, CGM, FD, TargetDecl, MissingFeature)) CGM.getDiags().Report(E->getLocStart(), diag::err_builtin_needs_feature) << TargetDecl->getDeclName() << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); @@ -2338,7 +2357,7 @@ if (F.getValue()) ReqFeatures.push_back(F.getKey()); } - if (!hasRequiredFeatures(ReqFeatures, CGM, FD, MissingFeature)) + if (!hasRequiredFeatures(ReqFeatures, CGM, FD, TargetDecl, MissingFeature)) CGM.getDiags().Report(E->getLocStart(), diag::err_function_needs_feature) << FD->getDeclName() << TargetDecl->getDeclName() << MissingFeature; } Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -1082,6 +1082,8 @@ /// It's up to you to ensure that this is safe. void AddDefaultFnAttrs(llvm::Function &F); + TargetAttr::ParsedTargetAttr getFunctionTargetAttrs(const FunctionDecl *FD); + // Fills in the supplied string map with the set of target features for the // passed in function. void getFunctionFeatureMap(llvm::StringMap &FeatureMap, Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -4995,11 +4995,8 @@ } } -// Fills in the supplied string map with the set of target features for the -// passed in function. -void CodeGenModule::getFunctionFeatureMap(llvm::StringMap &FeatureMap, - const FunctionDecl *FD) { - StringRef TargetCPU = Target.getTargetOpts().CPU; +TargetAttr::ParsedTargetAttr CodeGenModule::getFunctionTargetAttrs(const FunctionDecl *FD) +{ if (const auto *TD = FD->getAttr()) { // If we have a TargetAttr build up the feature map based on that. TargetAttr::ParsedTargetAttr ParsedAttr = TD->parse(); @@ -5011,7 +5008,20 @@ StringRef{Feat}.substr(1)); }), ParsedAttr.Features.end()); + return ParsedAttr; + } else { + return TargetAttr::ParsedTargetAttr(); + } +} + +// Fills in the supplied string map with the set of target features for the +// passed in function. +void CodeGenModule::getFunctionFeatureMap(llvm::StringMap &FeatureMap, + const FunctionDecl *FD) { + StringRef TargetCPU = Target.getTargetOpts().CPU; + TargetAttr::ParsedTargetAttr ParsedAttr = getFunctionTargetAttrs(FD); + if (ParsedAttr.Features.size() != 0) { // Make a copy of the features as passed on the command line into the // beginning of the additional features from the function to override. ParsedAttr.Features.insert(ParsedAttr.Features.begin(), Index: test/CodeGen/target-features-error-2.c =================================================================== --- test/CodeGen/target-features-error-2.c +++ test/CodeGen/target-features-error-2.c @@ -3,13 +3,14 @@ // RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX_2 // RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX_3 // RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX_4 +// RUN: %clang_cc1 %s -triple=x86_64-linux-gnu -S -verify -o - -D NEED_AVX512f #define __MM_MALLOC_H #include #if NEED_SSE42 int baz(__m256i a) { - return _mm256_extract_epi32(a, 3); // expected-error {{always_inline function '_mm256_extract_epi32' requires target feature 'sse4.2', but would be inlined into function 'baz' that is compiled without support for 'sse4.2'}} + return _mm256_extract_epi32(a, 3); // expected-error {{always_inline function '_mm256_extract_epi32' requires target feature 'avx', but would be inlined into function 'baz' that is compiled without support for 'avx'}} } #endif @@ -36,3 +37,9 @@ return _mm_cmp_sd(a, b, 0); // expected-error {{'__builtin_ia32_cmpsd' 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 Index: test/CodeGen/target-features-error.c =================================================================== --- test/CodeGen/target-features-error.c +++ test/CodeGen/target-features-error.c @@ -3,6 +3,5 @@ return a + 4; } int bar() { - return foo(4); // expected-error {{always_inline function 'foo' requires target feature 'sse4.2', but would be inlined into function 'bar' that is compiled without support for 'sse4.2'}} + 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'}} } -