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