From 2b2d56f059e75553eac0c1d172ef5b6e4278607f Mon Sep 17 00:00:00 2001 From: Eric Christopher Date: Thu, 12 Nov 2015 00:44:12 +0000 Subject: Provide a frontend based error for always_inline functions that require target features that the caller function doesn't provide. This matches the existing backend failure to inline functions that don't have matching target features - and diagnoses earlier in the case of always_inline. Fix up a few test cases that were, in fact, invalid if you tried to generate code from the backend with the specified target features and add a couple of tests to illustrate what's going on. This should fix PR25246. llvm-svn: 252834 --- clang/lib/CodeGen/CodeGenFunction.cpp | 90 +++++++++++++++++++++++++---------- 1 file changed, 65 insertions(+), 25 deletions(-) (limited to 'clang/lib/CodeGen/CodeGenFunction.cpp') diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 879c1577dbc..8596f97a3b1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -1843,7 +1843,8 @@ template void CGBuilderInserter::InsertHelper( llvm::BasicBlock::iterator InsertPt) const; #undef PreserveNames -// Returns true if we have a valid set of target features. +// Emits an error if we don't have a valid set of target features for the +// called function. void CodeGenFunction::checkTargetFeatures(const CallExpr *E, const FunctionDecl *TargetDecl) { // Early exit if this is an indirect call. @@ -1856,31 +1857,70 @@ void CodeGenFunction::checkTargetFeatures(const CallExpr *E, if (!FD) return; + // 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(); - const char *FeatureList = - CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); + if (BuiltinID) { + SmallVector ReqFeatures; + const char *FeatureList = + CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); + // Return if the builtin doesn't have any required features. + if (!FeatureList || StringRef(FeatureList) == "") + return; + StringRef(FeatureList).split(ReqFeatures, ","); - if (!FeatureList || StringRef(FeatureList) == "") - return; + // If there aren't any required features listed then go ahead and return. + if (ReqFeatures.empty()) + return; - llvm::StringMap FeatureMap; - CGM.getFunctionFeatureMap(FeatureMap, FD); - - // If we have at least one of the features in the feature list return - // true, otherwise return false. - SmallVector AttrFeatures; - StringRef(FeatureList).split(AttrFeatures, ","); - if (!std::all_of(AttrFeatures.begin(), AttrFeatures.end(), - [&](StringRef &Feature) { - SmallVector OrFeatures; - Feature.split(OrFeatures, "|"); - return std::any_of(OrFeatures.begin(), OrFeatures.end(), - [&](StringRef &Feature) { - return FeatureMap[Feature]; - }); - })) - CGM.getDiags().Report(E->getLocStart(), diag::err_builtin_needs_feature) - << TargetDecl->getDeclName() - << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); -} + // Now build up the set of caller features and verify that all the required + // features are there. + llvm::StringMap CallerFeatureMap; + CGM.getFunctionFeatureMap(CallerFeatureMap, FD); + + // If we have at least one of the features in the feature list return + // true, otherwise return false. + if (!std::all_of( + ReqFeatures.begin(), ReqFeatures.end(), [&](StringRef &Feature) { + SmallVector OrFeatures; + Feature.split(OrFeatures, "|"); + return std::any_of(OrFeatures.begin(), OrFeatures.end(), + [&](StringRef &Feature) { + return CallerFeatureMap.lookup(Feature); + }); + })) + CGM.getDiags().Report(E->getLocStart(), diag::err_builtin_needs_feature) + << TargetDecl->getDeclName() + << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); + + } else if (TargetDecl->hasAttr()) { + // Get the required features for the callee. + SmallVector ReqFeatures; + llvm::StringMap CalleeFeatureMap; + CGM.getFunctionFeatureMap(CalleeFeatureMap, TargetDecl); + for (const auto &F : CalleeFeatureMap) + ReqFeatures.push_back(F.getKey()); + // If there aren't any required features listed then go ahead and return. + if (ReqFeatures.empty()) + return; + // Now get the features that the caller provides. + llvm::StringMap CallerFeatureMap; + CGM.getFunctionFeatureMap(CallerFeatureMap, FD); + + // If we have at least one of the features in the feature list return + // true, otherwise return false. + if (!std::all_of( + ReqFeatures.begin(), ReqFeatures.end(), [&](StringRef &Feature) { + SmallVector OrFeatures; + Feature.split(OrFeatures, "|"); + return std::any_of(OrFeatures.begin(), OrFeatures.end(), + [&](StringRef &Feature) { + return CallerFeatureMap.lookup(Feature); + }); + })) + CGM.getDiags().Report(E->getLocStart(), diag::err_function_needs_feature) + << FD->getDeclName() << TargetDecl->getDeclName(); + } +} -- cgit v1.2.3