xref: /aosp_15_r20/external/swiftshader/third_party/subzero/src/IceRangeSpec.cpp (revision 03ce13f70fcc45d86ee91b7ee4cab1936a95046e)
1*03ce13f7SAndroid Build Coastguard Worker //===- subzero/src/IceRangeSpec.cpp - Include/exclude specification -------===//
2*03ce13f7SAndroid Build Coastguard Worker //
3*03ce13f7SAndroid Build Coastguard Worker //                        The Subzero Code Generator
4*03ce13f7SAndroid Build Coastguard Worker //
5*03ce13f7SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*03ce13f7SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*03ce13f7SAndroid Build Coastguard Worker //
8*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*03ce13f7SAndroid Build Coastguard Worker ///
10*03ce13f7SAndroid Build Coastguard Worker /// \file
11*03ce13f7SAndroid Build Coastguard Worker /// \brief Implements a class for specifying sets of names and number ranges to
12*03ce13f7SAndroid Build Coastguard Worker /// match against.  This is specified as a comma-separated list of clauses.
13*03ce13f7SAndroid Build Coastguard Worker /// Each clause optionally starts with '-' to indicate exclusion instead of
14*03ce13f7SAndroid Build Coastguard Worker /// inclusion.  A clause can be a name, or a numeric range X:Y, or a single
15*03ce13f7SAndroid Build Coastguard Worker /// number X.  The X:Y form indicates a range of numbers greater than or equal
16*03ce13f7SAndroid Build Coastguard Worker /// to X and strictly less than Y.  A missing "X" is taken to be 0, and a
17*03ce13f7SAndroid Build Coastguard Worker /// missing "Y" is taken to be infinite.  E.g., "0:" and ":" specify the entire
18*03ce13f7SAndroid Build Coastguard Worker /// set.
19*03ce13f7SAndroid Build Coastguard Worker ///
20*03ce13f7SAndroid Build Coastguard Worker /// This is essentially the same implementation as in szbuild.py, except that
21*03ce13f7SAndroid Build Coastguard Worker /// regular expressions are not used for the names.
22*03ce13f7SAndroid Build Coastguard Worker ///
23*03ce13f7SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
24*03ce13f7SAndroid Build Coastguard Worker 
25*03ce13f7SAndroid Build Coastguard Worker #include "IceRangeSpec.h"
26*03ce13f7SAndroid Build Coastguard Worker #include "IceStringPool.h"
27*03ce13f7SAndroid Build Coastguard Worker 
28*03ce13f7SAndroid Build Coastguard Worker #include <cctype>
29*03ce13f7SAndroid Build Coastguard Worker #include <string>
30*03ce13f7SAndroid Build Coastguard Worker #include <unordered_set>
31*03ce13f7SAndroid Build Coastguard Worker #include <vector>
32*03ce13f7SAndroid Build Coastguard Worker 
33*03ce13f7SAndroid Build Coastguard Worker namespace Ice {
34*03ce13f7SAndroid Build Coastguard Worker 
35*03ce13f7SAndroid Build Coastguard Worker bool RangeSpec::HasNames = false;
36*03ce13f7SAndroid Build Coastguard Worker 
37*03ce13f7SAndroid Build Coastguard Worker namespace {
38*03ce13f7SAndroid Build Coastguard Worker 
39*03ce13f7SAndroid Build Coastguard Worker /// Helper function to parse "X" or "X:Y" into First and Last.
40*03ce13f7SAndroid Build Coastguard Worker /// - "X" is treated as "X:X+1".
41*03ce13f7SAndroid Build Coastguard Worker /// - ":Y" is treated as "0:Y".
42*03ce13f7SAndroid Build Coastguard Worker /// - "X:" is treated as "X:inf"
43*03ce13f7SAndroid Build Coastguard Worker ///
44*03ce13f7SAndroid Build Coastguard Worker /// Behavior is undefined if "X" or "Y" is not a proper number (since std::stoul
45*03ce13f7SAndroid Build Coastguard Worker /// throws an exception).
46*03ce13f7SAndroid Build Coastguard Worker ///
47*03ce13f7SAndroid Build Coastguard Worker /// If the string doesn't contain 1 or 2 ':' delimiters, or X>=Y,
48*03ce13f7SAndroid Build Coastguard Worker /// report_fatal_error is called.
getRange(const std::string & Token,uint32_t * First,uint32_t * Last)49*03ce13f7SAndroid Build Coastguard Worker void getRange(const std::string &Token, uint32_t *First, uint32_t *Last) {
50*03ce13f7SAndroid Build Coastguard Worker   bool Error = false;
51*03ce13f7SAndroid Build Coastguard Worker   auto Tokens = RangeSpec::tokenize(Token, RangeSpec::DELIM_RANGE);
52*03ce13f7SAndroid Build Coastguard Worker   if (Tokens.size() == 1) {
53*03ce13f7SAndroid Build Coastguard Worker     *First = std::stoul(Tokens[0]);
54*03ce13f7SAndroid Build Coastguard Worker     *Last = *First + 1;
55*03ce13f7SAndroid Build Coastguard Worker   } else if (Tokens.size() == 2) {
56*03ce13f7SAndroid Build Coastguard Worker     *First = Tokens[0].empty() ? 0 : std::stoul(Tokens[0]);
57*03ce13f7SAndroid Build Coastguard Worker     *Last = Tokens[1].empty() ? RangeSpec::RangeMax : std::stoul(Tokens[1]);
58*03ce13f7SAndroid Build Coastguard Worker   } else {
59*03ce13f7SAndroid Build Coastguard Worker     Error = true;
60*03ce13f7SAndroid Build Coastguard Worker   }
61*03ce13f7SAndroid Build Coastguard Worker   if (*First >= *Last) {
62*03ce13f7SAndroid Build Coastguard Worker     Error = true;
63*03ce13f7SAndroid Build Coastguard Worker   }
64*03ce13f7SAndroid Build Coastguard Worker   if (Error) {
65*03ce13f7SAndroid Build Coastguard Worker     llvm::report_fatal_error("Invalid range " + Token);
66*03ce13f7SAndroid Build Coastguard Worker   }
67*03ce13f7SAndroid Build Coastguard Worker }
68*03ce13f7SAndroid Build Coastguard Worker 
69*03ce13f7SAndroid Build Coastguard Worker /// Helper function to add one token to the include or exclude set.  The token
70*03ce13f7SAndroid Build Coastguard Worker /// is examined and then treated as either a numeric range or a single name.
record(const std::string & Token,RangeSpec::Desc * D)71*03ce13f7SAndroid Build Coastguard Worker void record(const std::string &Token, RangeSpec::Desc *D) {
72*03ce13f7SAndroid Build Coastguard Worker   if (Token.empty())
73*03ce13f7SAndroid Build Coastguard Worker     return;
74*03ce13f7SAndroid Build Coastguard Worker   // Mark that an include or exclude was explicitly given.  This affects the
75*03ce13f7SAndroid Build Coastguard Worker   // default decision when matching a value that wasn't explicitly provided in
76*03ce13f7SAndroid Build Coastguard Worker   // the include or exclude list.
77*03ce13f7SAndroid Build Coastguard Worker   D->IsExplicit = true;
78*03ce13f7SAndroid Build Coastguard Worker   // A range is identified by starting with a digit or a ':'.
79*03ce13f7SAndroid Build Coastguard Worker   if (Token[0] == RangeSpec::DELIM_RANGE || std::isdigit(Token[0])) {
80*03ce13f7SAndroid Build Coastguard Worker     uint32_t First = 0, Last = 0;
81*03ce13f7SAndroid Build Coastguard Worker     getRange(Token, &First, &Last);
82*03ce13f7SAndroid Build Coastguard Worker     if (Last == RangeSpec::RangeMax) {
83*03ce13f7SAndroid Build Coastguard Worker       D->AllFrom = std::min(D->AllFrom, First);
84*03ce13f7SAndroid Build Coastguard Worker     } else {
85*03ce13f7SAndroid Build Coastguard Worker       if (Last >= D->Numbers.size())
86*03ce13f7SAndroid Build Coastguard Worker         D->Numbers.resize(Last + 1);
87*03ce13f7SAndroid Build Coastguard Worker       D->Numbers.set(First, Last);
88*03ce13f7SAndroid Build Coastguard Worker     }
89*03ce13f7SAndroid Build Coastguard Worker   } else {
90*03ce13f7SAndroid Build Coastguard Worker     // Otherwise treat it as a single name.
91*03ce13f7SAndroid Build Coastguard Worker     D->Names.insert(Token);
92*03ce13f7SAndroid Build Coastguard Worker   }
93*03ce13f7SAndroid Build Coastguard Worker }
94*03ce13f7SAndroid Build Coastguard Worker 
95*03ce13f7SAndroid Build Coastguard Worker } // end of anonymous namespace
96*03ce13f7SAndroid Build Coastguard Worker 
tokenize(const std::string & Spec,char Delimiter)97*03ce13f7SAndroid Build Coastguard Worker std::vector<std::string> RangeSpec::tokenize(const std::string &Spec,
98*03ce13f7SAndroid Build Coastguard Worker                                              char Delimiter) {
99*03ce13f7SAndroid Build Coastguard Worker   std::vector<std::string> Tokens;
100*03ce13f7SAndroid Build Coastguard Worker   if (!Spec.empty()) {
101*03ce13f7SAndroid Build Coastguard Worker     std::string::size_type StartPos = 0;
102*03ce13f7SAndroid Build Coastguard Worker     std::string::size_type DelimPos = 0;
103*03ce13f7SAndroid Build Coastguard Worker     while (DelimPos != std::string::npos) {
104*03ce13f7SAndroid Build Coastguard Worker       DelimPos = Spec.find(Delimiter, StartPos);
105*03ce13f7SAndroid Build Coastguard Worker       Tokens.emplace_back(Spec.substr(StartPos, DelimPos - StartPos));
106*03ce13f7SAndroid Build Coastguard Worker       StartPos = DelimPos + 1;
107*03ce13f7SAndroid Build Coastguard Worker     }
108*03ce13f7SAndroid Build Coastguard Worker   }
109*03ce13f7SAndroid Build Coastguard Worker   return Tokens;
110*03ce13f7SAndroid Build Coastguard Worker }
111*03ce13f7SAndroid Build Coastguard Worker 
112*03ce13f7SAndroid Build Coastguard Worker /// Initialize the RangeSpec with the given string.  Calling init multiple times
113*03ce13f7SAndroid Build Coastguard Worker /// (e.g. init("A");init("B");) is equivalent to init("A,B"); .
init(const std::string & Spec)114*03ce13f7SAndroid Build Coastguard Worker void RangeSpec::init(const std::string &Spec) {
115*03ce13f7SAndroid Build Coastguard Worker   auto Tokens = tokenize(Spec, DELIM_LIST);
116*03ce13f7SAndroid Build Coastguard Worker   for (const auto &Token : Tokens) {
117*03ce13f7SAndroid Build Coastguard Worker     if (Token[0] == '-') {
118*03ce13f7SAndroid Build Coastguard Worker       exclude(Token.substr(1));
119*03ce13f7SAndroid Build Coastguard Worker     } else {
120*03ce13f7SAndroid Build Coastguard Worker       include(Token);
121*03ce13f7SAndroid Build Coastguard Worker     }
122*03ce13f7SAndroid Build Coastguard Worker   }
123*03ce13f7SAndroid Build Coastguard Worker   if (!Includes.Names.empty() || !Excludes.Names.empty())
124*03ce13f7SAndroid Build Coastguard Worker     HasNames = true;
125*03ce13f7SAndroid Build Coastguard Worker }
126*03ce13f7SAndroid Build Coastguard Worker 
127*03ce13f7SAndroid Build Coastguard Worker /// Determine whether the given Name/Number combo match the specification given
128*03ce13f7SAndroid Build Coastguard Worker /// to the init() method.  Explicit excludes take precedence over explicit
129*03ce13f7SAndroid Build Coastguard Worker /// includes.  If the combo doesn't match any explicit include or exclude:
130*03ce13f7SAndroid Build Coastguard Worker /// - false if the init() string is empty (no explicit includes or excludes)
131*03ce13f7SAndroid Build Coastguard Worker /// - true if there is at least one explicit exclude and no explicit includes
132*03ce13f7SAndroid Build Coastguard Worker /// - false otherwise (at least one explicit include)
match(const std::string & Name,uint32_t Number) const133*03ce13f7SAndroid Build Coastguard Worker bool RangeSpec::match(const std::string &Name, uint32_t Number) const {
134*03ce13f7SAndroid Build Coastguard Worker   // No match if it is explicitly excluded by name or number.
135*03ce13f7SAndroid Build Coastguard Worker   if (Excludes.Names.find(Name) != Excludes.Names.end())
136*03ce13f7SAndroid Build Coastguard Worker     return false;
137*03ce13f7SAndroid Build Coastguard Worker   if (Number >= Excludes.AllFrom)
138*03ce13f7SAndroid Build Coastguard Worker     return false;
139*03ce13f7SAndroid Build Coastguard Worker   if (Number < Excludes.Numbers.size() && Excludes.Numbers[Number])
140*03ce13f7SAndroid Build Coastguard Worker     return false;
141*03ce13f7SAndroid Build Coastguard Worker 
142*03ce13f7SAndroid Build Coastguard Worker   // Positive match if it is explicitly included by name or number.
143*03ce13f7SAndroid Build Coastguard Worker   if (Includes.Names.find(Name) != Includes.Names.end())
144*03ce13f7SAndroid Build Coastguard Worker     return true;
145*03ce13f7SAndroid Build Coastguard Worker   if (Number >= Includes.AllFrom)
146*03ce13f7SAndroid Build Coastguard Worker     return true;
147*03ce13f7SAndroid Build Coastguard Worker   if (Number < Includes.Numbers.size() && Includes.Numbers[Number])
148*03ce13f7SAndroid Build Coastguard Worker     return true;
149*03ce13f7SAndroid Build Coastguard Worker 
150*03ce13f7SAndroid Build Coastguard Worker   // Otherwise use the default decision.
151*03ce13f7SAndroid Build Coastguard Worker   return Excludes.IsExplicit && !Includes.IsExplicit;
152*03ce13f7SAndroid Build Coastguard Worker }
153*03ce13f7SAndroid Build Coastguard Worker 
include(const std::string & Token)154*03ce13f7SAndroid Build Coastguard Worker void RangeSpec::include(const std::string &Token) { record(Token, &Includes); }
155*03ce13f7SAndroid Build Coastguard Worker 
exclude(const std::string & Token)156*03ce13f7SAndroid Build Coastguard Worker void RangeSpec::exclude(const std::string &Token) { record(Token, &Excludes); }
157*03ce13f7SAndroid Build Coastguard Worker 
158*03ce13f7SAndroid Build Coastguard Worker } // end of namespace Ice
159