Index: clang/include/clang/Basic/Builtins.h =================================================================== --- clang/include/clang/Basic/Builtins.h +++ clang/include/clang/Basic/Builtins.h @@ -16,6 +16,7 @@ #define LLVM_CLANG_BASIC_BUILTINS_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringMap.h" #include // VC++ defines 'alloca' as an object-like macro, which interferes with our @@ -255,6 +256,13 @@ /// for non-builtins. bool canBeRedeclared(unsigned ID) const; + /// Returns true if the required target features of a builtin function are + /// enabled. + /// \p TargetFeatureMap maps a target feature to true if it is enabled and + /// false if it is disabled. + bool isRequiredTargetFeaturesEnabled( + unsigned BuiltinID, const llvm::StringMap &TargetFetureMap) const; + private: const Info &getRecord(unsigned ID) const; Index: clang/lib/Basic/BuiltinTargetFeatures.h =================================================================== --- /dev/null +++ clang/lib/Basic/BuiltinTargetFeatures.h @@ -0,0 +1,95 @@ +//===-- CodeGenFunction.h - Target features for builtin ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This is the internal required target features for builtin. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H +#define LLVM_CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H +#include "llvm/ADT/StringMap.h" +#include "llvm/ADT/StringRef.h" + +using llvm::StringRef; + +namespace clang { +namespace Builtin { +/// TargetFeatures - This class is used to check whether the builtin function +/// has the required tagert specific features. It is able to support the +/// combination of ','(and), '|'(or), and '()'. By default, the priority of +/// ',' is higher than that of '|' . +/// E.g: +/// A,B|C means the builtin function requires both A and B, or C. +/// If we want the builtin function requires both A and B, or both A and C, +/// there are two ways: A,B|A,C or A,(B|C). +/// The FeaturesList should not contain spaces, and brackets must appear in +/// pairs. +class TargetFeatures { + struct FeatureListStatus { + bool HasFeatures; + StringRef CurFeaturesList; + }; + + const llvm::StringMap &CallerFeatureMap; + + FeatureListStatus getAndFeatures(StringRef FeatureList) { + int InParentheses = 0; + bool HasFeatures = true; + size_t SubexpressionStart = 0; + for (size_t i = 0, e = FeatureList.size(); i < e; ++i) { + char CurrentToken = FeatureList[i]; + switch (CurrentToken) { + default: + break; + case '(': + if (InParentheses == 0) + SubexpressionStart = i + 1; + ++InParentheses; + break; + case ')': + --InParentheses; + assert(InParentheses >= 0 && "Parentheses are not in pair"); + LLVM_FALLTHROUGH; + case '|': + case ',': + if (InParentheses == 0) { + if (HasFeatures && i != SubexpressionStart) { + StringRef F = FeatureList.slice(SubexpressionStart, i); + HasFeatures = CurrentToken == ')' ? hasRequiredFeatures(F) + : CallerFeatureMap.lookup(F); + } + SubexpressionStart = i + 1; + if (CurrentToken == '|') { + return {HasFeatures, FeatureList.substr(SubexpressionStart)}; + } + } + break; + } + } + assert(InParentheses == 0 && "Parentheses are not in pair"); + if (HasFeatures && SubexpressionStart != FeatureList.size()) + HasFeatures = + CallerFeatureMap.lookup(FeatureList.substr(SubexpressionStart)); + return {HasFeatures, StringRef()}; + } + +public: + bool hasRequiredFeatures(StringRef FeatureList) { + FeatureListStatus FS = {false, FeatureList}; + while (!FS.HasFeatures && !FS.CurFeaturesList.empty()) + FS = getAndFeatures(FS.CurFeaturesList); + return FS.HasFeatures; + } + + TargetFeatures(const llvm::StringMap &CallerFeatureMap) + : CallerFeatureMap(CallerFeatureMap) {} +}; + +} // namespace Builtin +} // namespace clang +#endif /* CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H */ Index: clang/lib/Basic/Builtins.cpp =================================================================== --- clang/lib/Basic/Builtins.cpp +++ clang/lib/Basic/Builtins.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "clang/Basic/Builtins.h" +#include "BuiltinTargetFeatures.h" #include "clang/Basic/IdentifierTable.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" @@ -211,3 +212,15 @@ (!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) || isInStdNamespace(ID); } + +bool Builtin::Context::isRequiredTargetFeaturesEnabled( + unsigned BuiltinID, const llvm::StringMap &TargetFetureMap) const { + StringRef FeatureList(getRequiredFeatures(BuiltinID)); + // Return true if the builtin doesn't have any required features. + if (FeatureList.empty()) + return true; + assert(!FeatureList.contains(' ') && "Space in feature list"); + + TargetFeatures TF(TargetFetureMap); + return TF.hasRequiredFeatures(FeatureList); +} Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -4840,76 +4840,6 @@ llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO); }; -/// TargetFeatures - This class is used to check whether the builtin function -/// has the required tagert specific features. It is able to support the -/// combination of ','(and), '|'(or), and '()'. By default, the priority of -/// ',' is higher than that of '|' . -/// E.g: -/// A,B|C means the builtin function requires both A and B, or C. -/// If we want the builtin function requires both A and B, or both A and C, -/// there are two ways: A,B|A,C or A,(B|C). -/// The FeaturesList should not contain spaces, and brackets must appear in -/// pairs. -class TargetFeatures { - struct FeatureListStatus { - bool HasFeatures; - StringRef CurFeaturesList; - }; - - const llvm::StringMap &CallerFeatureMap; - - FeatureListStatus getAndFeatures(StringRef FeatureList) { - int InParentheses = 0; - bool HasFeatures = true; - size_t SubexpressionStart = 0; - for (size_t i = 0, e = FeatureList.size(); i < e; ++i) { - char CurrentToken = FeatureList[i]; - switch (CurrentToken) { - default: - break; - case '(': - if (InParentheses == 0) - SubexpressionStart = i + 1; - ++InParentheses; - break; - case ')': - --InParentheses; - assert(InParentheses >= 0 && "Parentheses are not in pair"); - LLVM_FALLTHROUGH; - case '|': - case ',': - if (InParentheses == 0) { - if (HasFeatures && i != SubexpressionStart) { - StringRef F = FeatureList.slice(SubexpressionStart, i); - HasFeatures = CurrentToken == ')' ? hasRequiredFeatures(F) - : CallerFeatureMap.lookup(F); - } - SubexpressionStart = i + 1; - if (CurrentToken == '|') { - return {HasFeatures, FeatureList.substr(SubexpressionStart)}; - } - } - break; - } - } - assert(InParentheses == 0 && "Parentheses are not in pair"); - if (HasFeatures && SubexpressionStart != FeatureList.size()) - HasFeatures = - CallerFeatureMap.lookup(FeatureList.substr(SubexpressionStart)); - return {HasFeatures, StringRef()}; - } - -public: - bool hasRequiredFeatures(StringRef FeatureList) { - FeatureListStatus FS = {false, FeatureList}; - while (!FS.HasFeatures && !FS.CurFeaturesList.empty()) - FS = getAndFeatures(FS.CurFeaturesList); - return FS.HasFeatures; - } - - TargetFeatures(const llvm::StringMap &CallerFeatureMap) - : CallerFeatureMap(CallerFeatureMap) {} -}; inline DominatingLLVMValue::saved_type DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) { Index: clang/lib/CodeGen/CodeGenFunction.cpp =================================================================== --- clang/lib/CodeGen/CodeGenFunction.cpp +++ clang/lib/CodeGen/CodeGenFunction.cpp @@ -2550,16 +2550,12 @@ llvm::StringMap CallerFeatureMap; CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD); if (BuiltinID) { - StringRef FeatureList( - CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID)); - // Return if the builtin doesn't have any required features. - if (FeatureList.empty()) - return; - assert(!FeatureList.contains(' ') && "Space in feature list"); - TargetFeatures TF(CallerFeatureMap); - if (!TF.hasRequiredFeatures(FeatureList)) + if (!CGM.getContext().BuiltinInfo.isRequiredTargetFeaturesEnabled( + BuiltinID, CallerFeatureMap)) { CGM.getDiags().Report(Loc, diag::err_builtin_needs_feature) - << TargetDecl->getDeclName() << FeatureList; + << TargetDecl->getDeclName() + << CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID); + } } else if (!TargetDecl->isMultiVersion() && TargetDecl->hasAttr()) { // Get the required features for the callee. Index: clang/lib/Lex/PPMacroExpansion.cpp =================================================================== --- clang/lib/Lex/PPMacroExpansion.cpp +++ clang/lib/Lex/PPMacroExpansion.cpp @@ -1640,7 +1640,8 @@ // usual allocation and deallocation functions. Required by libc++ return 201802; default: - return true; + return getBuiltinInfo().isRequiredTargetFeaturesEnabled( + II->getBuiltinID(), getTargetInfo().getTargetOpts().FeatureMap); } return true; } else if (II->getTokenID() != tok::identifier || Index: clang/test/Preprocessor/hash_builtin.cpp =================================================================== --- /dev/null +++ clang/test/Preprocessor/hash_builtin.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple amdgcn -target-cpu gfx906 -E %s -o - | FileCheck %s + +// CHECK: has_s_memtime_inst +#if __has_builtin(__builtin_amdgcn_s_memtime) + int has_s_memtime_inst; +#endif + +// CHECK-NOT: has_gfx10_inst +#if __has_builtin(__builtin_amdgcn_mov_dpp8) + int has_gfx10_inst; +#endif Index: clang/unittests/CodeGen/CheckTargetFeaturesTest.cpp =================================================================== --- clang/unittests/CodeGen/CheckTargetFeaturesTest.cpp +++ clang/unittests/CodeGen/CheckTargetFeaturesTest.cpp @@ -1,4 +1,4 @@ -#include "../lib/CodeGen/CodeGenFunction.h" +#include "../lib/Basic/BuiltinTargetFeatures.h" #include "gtest/gtest.h" using namespace llvm; @@ -11,7 +11,7 @@ StringMap SM; for (StringRef F : Features) SM.insert(std::make_pair(F, true)); - clang::CodeGen::TargetFeatures TF(SM); + clang::Builtin::TargetFeatures TF(SM); return TF.hasRequiredFeatures(BuiltinFeatures); }; // Make sure the basic function ',' and '|' works correctly