181ad6265SDimitry Andric //===-- CodeGenFunction.h - Target features for builtin ---------*- C++ -*-===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric // This is the internal required target features for builtin.
1081ad6265SDimitry Andric //
1181ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1281ad6265SDimitry Andric 
1381ad6265SDimitry Andric #ifndef LLVM_CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H
1481ad6265SDimitry Andric #define LLVM_CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H
1581ad6265SDimitry Andric #include "llvm/ADT/StringMap.h"
1681ad6265SDimitry Andric #include "llvm/ADT/StringRef.h"
1781ad6265SDimitry Andric 
1881ad6265SDimitry Andric using llvm::StringRef;
1981ad6265SDimitry Andric 
2081ad6265SDimitry Andric namespace clang {
2181ad6265SDimitry Andric namespace Builtin {
2281ad6265SDimitry Andric /// TargetFeatures - This class is used to check whether the builtin function
2381ad6265SDimitry Andric /// has the required tagert specific features. It is able to support the
2481ad6265SDimitry Andric /// combination of ','(and), '|'(or), and '()'. By default, the priority of
2581ad6265SDimitry Andric /// ',' is higher than that of '|' .
2681ad6265SDimitry Andric /// E.g:
2781ad6265SDimitry Andric /// A,B|C means the builtin function requires both A and B, or C.
2881ad6265SDimitry Andric /// If we want the builtin function requires both A and B, or both A and C,
2981ad6265SDimitry Andric /// there are two ways: A,B|A,C or A,(B|C).
3081ad6265SDimitry Andric /// The FeaturesList should not contain spaces, and brackets must appear in
3181ad6265SDimitry Andric /// pairs.
3281ad6265SDimitry Andric class TargetFeatures {
3381ad6265SDimitry Andric   struct FeatureListStatus {
3481ad6265SDimitry Andric     bool HasFeatures;
3581ad6265SDimitry Andric     StringRef CurFeaturesList;
3681ad6265SDimitry Andric   };
3781ad6265SDimitry Andric 
3881ad6265SDimitry Andric   const llvm::StringMap<bool> &CallerFeatureMap;
3981ad6265SDimitry Andric 
getAndFeatures(StringRef FeatureList)4081ad6265SDimitry Andric   FeatureListStatus getAndFeatures(StringRef FeatureList) {
4181ad6265SDimitry Andric     int InParentheses = 0;
4281ad6265SDimitry Andric     bool HasFeatures = true;
4381ad6265SDimitry Andric     size_t SubexpressionStart = 0;
4481ad6265SDimitry Andric     for (size_t i = 0, e = FeatureList.size(); i < e; ++i) {
4581ad6265SDimitry Andric       char CurrentToken = FeatureList[i];
4681ad6265SDimitry Andric       switch (CurrentToken) {
4781ad6265SDimitry Andric       default:
4881ad6265SDimitry Andric         break;
4981ad6265SDimitry Andric       case '(':
5081ad6265SDimitry Andric         if (InParentheses == 0)
5181ad6265SDimitry Andric           SubexpressionStart = i + 1;
5281ad6265SDimitry Andric         ++InParentheses;
5381ad6265SDimitry Andric         break;
5481ad6265SDimitry Andric       case ')':
5581ad6265SDimitry Andric         --InParentheses;
5681ad6265SDimitry Andric         assert(InParentheses >= 0 && "Parentheses are not in pair");
57*bdd1243dSDimitry Andric         [[fallthrough]];
5881ad6265SDimitry Andric       case '|':
5981ad6265SDimitry Andric       case ',':
6081ad6265SDimitry Andric         if (InParentheses == 0) {
6181ad6265SDimitry Andric           if (HasFeatures && i != SubexpressionStart) {
6281ad6265SDimitry Andric             StringRef F = FeatureList.slice(SubexpressionStart, i);
6381ad6265SDimitry Andric             HasFeatures = CurrentToken == ')' ? hasRequiredFeatures(F)
6481ad6265SDimitry Andric                                               : CallerFeatureMap.lookup(F);
6581ad6265SDimitry Andric           }
6681ad6265SDimitry Andric           SubexpressionStart = i + 1;
6781ad6265SDimitry Andric           if (CurrentToken == '|') {
6881ad6265SDimitry Andric             return {HasFeatures, FeatureList.substr(SubexpressionStart)};
6981ad6265SDimitry Andric           }
7081ad6265SDimitry Andric         }
7181ad6265SDimitry Andric         break;
7281ad6265SDimitry Andric       }
7381ad6265SDimitry Andric     }
7481ad6265SDimitry Andric     assert(InParentheses == 0 && "Parentheses are not in pair");
7581ad6265SDimitry Andric     if (HasFeatures && SubexpressionStart != FeatureList.size())
7681ad6265SDimitry Andric       HasFeatures =
7781ad6265SDimitry Andric           CallerFeatureMap.lookup(FeatureList.substr(SubexpressionStart));
7881ad6265SDimitry Andric     return {HasFeatures, StringRef()};
7981ad6265SDimitry Andric   }
8081ad6265SDimitry Andric 
8181ad6265SDimitry Andric public:
hasRequiredFeatures(StringRef FeatureList)8281ad6265SDimitry Andric   bool hasRequiredFeatures(StringRef FeatureList) {
8381ad6265SDimitry Andric     FeatureListStatus FS = {false, FeatureList};
8481ad6265SDimitry Andric     while (!FS.HasFeatures && !FS.CurFeaturesList.empty())
8581ad6265SDimitry Andric       FS = getAndFeatures(FS.CurFeaturesList);
8681ad6265SDimitry Andric     return FS.HasFeatures;
8781ad6265SDimitry Andric   }
8881ad6265SDimitry Andric 
TargetFeatures(const llvm::StringMap<bool> & CallerFeatureMap)8981ad6265SDimitry Andric   TargetFeatures(const llvm::StringMap<bool> &CallerFeatureMap)
9081ad6265SDimitry Andric       : CallerFeatureMap(CallerFeatureMap) {}
9181ad6265SDimitry Andric };
9281ad6265SDimitry Andric 
9381ad6265SDimitry Andric } // namespace Builtin
9481ad6265SDimitry Andric } // namespace clang
9581ad6265SDimitry Andric #endif /* CLANG_LIB_BASIC_BUILTINTARGETFEATURES_H */
96