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 */
96