Skip to content

Commit cefe472

Browse files
committed
[clang] Fix __has_builtin
Fix __has_builtin to return 1 only if the requested target features of a builtin are enabled by refactoring the code for checking required target features of a builtin and use it in evaluation of __has_builtin. Reviewed by: Artem Belevich Differential Revision: https://reviews.llvm.org/D125829
1 parent 3ed9f60 commit cefe472

File tree

9 files changed

+142
-85
lines changed

9 files changed

+142
-85
lines changed

clang/include/clang/Basic/Builtins.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
#define LLVM_CLANG_BASIC_BUILTINS_H
1717

1818
#include "llvm/ADT/ArrayRef.h"
19+
#include "llvm/ADT/StringMap.h"
20+
#include "llvm/ADT/StringRef.h"
1921
#include <cstring>
2022

2123
// VC++ defines 'alloca' as an object-like macro, which interferes with our
@@ -263,7 +265,15 @@ class Context {
263265
const char *Fmt) const;
264266
};
265267

266-
}
268+
/// Returns true if the required target features of a builtin function are
269+
/// enabled.
270+
/// \p TargetFeatureMap maps a target feature to true if it is enabled and
271+
/// false if it is disabled.
272+
bool evaluateRequiredTargetFeatures(
273+
llvm::StringRef RequiredFatures,
274+
const llvm::StringMap<bool> &TargetFetureMap);
275+
276+
} // namespace Builtin
267277

268278
/// Kinds of BuiltinTemplateDecl.
269279
enum BuiltinTemplateKind : int {
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
//===-- CodeGenFunction.h - Target features for builtin ---------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// This is the internal required target features for builtin.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
#ifndef LLVM_CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H
14+
#define LLVM_CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H
15+
#include "llvm/ADT/StringMap.h"
16+
#include "llvm/ADT/StringRef.h"
17+
18+
using llvm::StringRef;
19+
20+
namespace clang {
21+
namespace Builtin {
22+
/// TargetFeatures - This class is used to check whether the builtin function
23+
/// has the required tagert specific features. It is able to support the
24+
/// combination of ','(and), '|'(or), and '()'. By default, the priority of
25+
/// ',' is higher than that of '|' .
26+
/// E.g:
27+
/// A,B|C means the builtin function requires both A and B, or C.
28+
/// If we want the builtin function requires both A and B, or both A and C,
29+
/// there are two ways: A,B|A,C or A,(B|C).
30+
/// The FeaturesList should not contain spaces, and brackets must appear in
31+
/// pairs.
32+
class TargetFeatures {
33+
struct FeatureListStatus {
34+
bool HasFeatures;
35+
StringRef CurFeaturesList;
36+
};
37+
38+
const llvm::StringMap<bool> &CallerFeatureMap;
39+
40+
FeatureListStatus getAndFeatures(StringRef FeatureList) {
41+
int InParentheses = 0;
42+
bool HasFeatures = true;
43+
size_t SubexpressionStart = 0;
44+
for (size_t i = 0, e = FeatureList.size(); i < e; ++i) {
45+
char CurrentToken = FeatureList[i];
46+
switch (CurrentToken) {
47+
default:
48+
break;
49+
case '(':
50+
if (InParentheses == 0)
51+
SubexpressionStart = i + 1;
52+
++InParentheses;
53+
break;
54+
case ')':
55+
--InParentheses;
56+
assert(InParentheses >= 0 && "Parentheses are not in pair");
57+
LLVM_FALLTHROUGH;
58+
case '|':
59+
case ',':
60+
if (InParentheses == 0) {
61+
if (HasFeatures && i != SubexpressionStart) {
62+
StringRef F = FeatureList.slice(SubexpressionStart, i);
63+
HasFeatures = CurrentToken == ')' ? hasRequiredFeatures(F)
64+
: CallerFeatureMap.lookup(F);
65+
}
66+
SubexpressionStart = i + 1;
67+
if (CurrentToken == '|') {
68+
return {HasFeatures, FeatureList.substr(SubexpressionStart)};
69+
}
70+
}
71+
break;
72+
}
73+
}
74+
assert(InParentheses == 0 && "Parentheses are not in pair");
75+
if (HasFeatures && SubexpressionStart != FeatureList.size())
76+
HasFeatures =
77+
CallerFeatureMap.lookup(FeatureList.substr(SubexpressionStart));
78+
return {HasFeatures, StringRef()};
79+
}
80+
81+
public:
82+
bool hasRequiredFeatures(StringRef FeatureList) {
83+
FeatureListStatus FS = {false, FeatureList};
84+
while (!FS.HasFeatures && !FS.CurFeaturesList.empty())
85+
FS = getAndFeatures(FS.CurFeaturesList);
86+
return FS.HasFeatures;
87+
}
88+
89+
TargetFeatures(const llvm::StringMap<bool> &CallerFeatureMap)
90+
: CallerFeatureMap(CallerFeatureMap) {}
91+
};
92+
93+
} // namespace Builtin
94+
} // namespace clang
95+
#endif /* CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H */

clang/lib/Basic/Builtins.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "clang/Basic/Builtins.h"
14+
#include "BuiltinTargetFeatures.h"
1415
#include "clang/Basic/IdentifierTable.h"
1516
#include "clang/Basic/LangOptions.h"
1617
#include "clang/Basic/TargetInfo.h"
@@ -211,3 +212,14 @@ bool Builtin::Context::canBeRedeclared(unsigned ID) const {
211212
(!hasReferenceArgsOrResult(ID) && !hasCustomTypechecking(ID)) ||
212213
isInStdNamespace(ID);
213214
}
215+
216+
bool Builtin::evaluateRequiredTargetFeatures(
217+
StringRef RequiredFeatures, const llvm::StringMap<bool> &TargetFetureMap) {
218+
// Return true if the builtin doesn't have any required features.
219+
if (RequiredFeatures.empty())
220+
return true;
221+
assert(!RequiredFeatures.contains(' ') && "Space in feature list");
222+
223+
TargetFeatures TF(TargetFetureMap);
224+
return TF.hasRequiredFeatures(RequiredFeatures);
225+
}

clang/lib/CodeGen/CodeGenFunction.cpp

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,16 +2550,13 @@ void CodeGenFunction::checkTargetFeatures(SourceLocation Loc,
25502550
llvm::StringMap<bool> CallerFeatureMap;
25512551
CGM.getContext().getFunctionFeatureMap(CallerFeatureMap, FD);
25522552
if (BuiltinID) {
2553-
StringRef FeatureList(
2554-
CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID));
2555-
// Return if the builtin doesn't have any required features.
2556-
if (FeatureList.empty())
2557-
return;
2558-
assert(!FeatureList.contains(' ') && "Space in feature list");
2559-
TargetFeatures TF(CallerFeatureMap);
2560-
if (!TF.hasRequiredFeatures(FeatureList))
2553+
StringRef FeatureList(CGM.getContext().BuiltinInfo.getRequiredFeatures(BuiltinID));
2554+
if (!Builtin::evaluateRequiredTargetFeatures(
2555+
FeatureList, CallerFeatureMap)) {
25612556
CGM.getDiags().Report(Loc, diag::err_builtin_needs_feature)
2562-
<< TargetDecl->getDeclName() << FeatureList;
2557+
<< TargetDecl->getDeclName()
2558+
<< FeatureList;
2559+
}
25632560
} else if (!TargetDecl->isMultiVersion() &&
25642561
TargetDecl->hasAttr<TargetAttr>()) {
25652562
// Get the required features for the callee.

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -4814,76 +4814,6 @@ class CodeGenFunction : public CodeGenTypeCache {
48144814
llvm::Value *FormResolverCondition(const MultiVersionResolverOption &RO);
48154815
};
48164816

4817-
/// TargetFeatures - This class is used to check whether the builtin function
4818-
/// has the required tagert specific features. It is able to support the
4819-
/// combination of ','(and), '|'(or), and '()'. By default, the priority of
4820-
/// ',' is higher than that of '|' .
4821-
/// E.g:
4822-
/// A,B|C means the builtin function requires both A and B, or C.
4823-
/// If we want the builtin function requires both A and B, or both A and C,
4824-
/// there are two ways: A,B|A,C or A,(B|C).
4825-
/// The FeaturesList should not contain spaces, and brackets must appear in
4826-
/// pairs.
4827-
class TargetFeatures {
4828-
struct FeatureListStatus {
4829-
bool HasFeatures;
4830-
StringRef CurFeaturesList;
4831-
};
4832-
4833-
const llvm::StringMap<bool> &CallerFeatureMap;
4834-
4835-
FeatureListStatus getAndFeatures(StringRef FeatureList) {
4836-
int InParentheses = 0;
4837-
bool HasFeatures = true;
4838-
size_t SubexpressionStart = 0;
4839-
for (size_t i = 0, e = FeatureList.size(); i < e; ++i) {
4840-
char CurrentToken = FeatureList[i];
4841-
switch (CurrentToken) {
4842-
default:
4843-
break;
4844-
case '(':
4845-
if (InParentheses == 0)
4846-
SubexpressionStart = i + 1;
4847-
++InParentheses;
4848-
break;
4849-
case ')':
4850-
--InParentheses;
4851-
assert(InParentheses >= 0 && "Parentheses are not in pair");
4852-
LLVM_FALLTHROUGH;
4853-
case '|':
4854-
case ',':
4855-
if (InParentheses == 0) {
4856-
if (HasFeatures && i != SubexpressionStart) {
4857-
StringRef F = FeatureList.slice(SubexpressionStart, i);
4858-
HasFeatures = CurrentToken == ')' ? hasRequiredFeatures(F)
4859-
: CallerFeatureMap.lookup(F);
4860-
}
4861-
SubexpressionStart = i + 1;
4862-
if (CurrentToken == '|') {
4863-
return {HasFeatures, FeatureList.substr(SubexpressionStart)};
4864-
}
4865-
}
4866-
break;
4867-
}
4868-
}
4869-
assert(InParentheses == 0 && "Parentheses are not in pair");
4870-
if (HasFeatures && SubexpressionStart != FeatureList.size())
4871-
HasFeatures =
4872-
CallerFeatureMap.lookup(FeatureList.substr(SubexpressionStart));
4873-
return {HasFeatures, StringRef()};
4874-
}
4875-
4876-
public:
4877-
bool hasRequiredFeatures(StringRef FeatureList) {
4878-
FeatureListStatus FS = {false, FeatureList};
4879-
while (!FS.HasFeatures && !FS.CurFeaturesList.empty())
4880-
FS = getAndFeatures(FS.CurFeaturesList);
4881-
return FS.HasFeatures;
4882-
}
4883-
4884-
TargetFeatures(const llvm::StringMap<bool> &CallerFeatureMap)
4885-
: CallerFeatureMap(CallerFeatureMap) {}
4886-
};
48874817

48884818
inline DominatingLLVMValue::saved_type
48894819
DominatingLLVMValue::save(CodeGenFunction &CGF, llvm::Value *value) {

clang/lib/Lex/PPMacroExpansion.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1640,7 +1640,9 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) {
16401640
// usual allocation and deallocation functions. Required by libc++
16411641
return 201802;
16421642
default:
1643-
return true;
1643+
return Builtin::evaluateRequiredTargetFeatures(
1644+
getBuiltinInfo().getRequiredFeatures(II->getBuiltinID()),
1645+
getTargetInfo().getTargetOpts().FeatureMap);
16441646
}
16451647
return true;
16461648
} else if (II->getTokenID() != tok::identifier ||

clang/test/Preprocessor/feature_tests.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
// RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -verify -DVERIFY
2-
// RUN: %clang_cc1 %s -E -triple=i686-apple-darwin9
1+
// RUN: %clang_cc1 %s -triple=i686-apple-darwin9 -target-cpu pentium4 -verify -DVERIFY
2+
// RUN: %clang_cc1 %s -E -triple=i686-apple-darwin9 -target-cpu pentium4
33
#ifndef __has_feature
44
#error Should have __has_feature
55
#endif
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %clang_cc1 -triple amdgcn -target-cpu gfx906 -E %s -o - | FileCheck %s
2+
3+
// CHECK: has_s_memtime_inst
4+
#if __has_builtin(__builtin_amdgcn_s_memtime)
5+
int has_s_memtime_inst;
6+
#endif
7+
8+
// CHECK-NOT: has_gfx10_inst
9+
#if __has_builtin(__builtin_amdgcn_mov_dpp8)
10+
int has_gfx10_inst;
11+
#endif

clang/unittests/CodeGen/CheckTargetFeaturesTest.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include "../lib/CodeGen/CodeGenFunction.h"
1+
#include "../lib/Basic/BuiltinTargetFeatures.h"
22
#include "gtest/gtest.h"
33

44
using namespace llvm;
@@ -11,7 +11,7 @@ TEST(CheckTargetFeaturesTest, checkBuiltinFeatures) {
1111
StringMap<bool> SM;
1212
for (StringRef F : Features)
1313
SM.insert(std::make_pair(F, true));
14-
clang::CodeGen::TargetFeatures TF(SM);
14+
clang::Builtin::TargetFeatures TF(SM);
1515
return TF.hasRequiredFeatures(BuiltinFeatures);
1616
};
1717
// Make sure the basic function ',' and '|' works correctly

0 commit comments

Comments
 (0)