llvm.org GIT mirror llvm / 53ea3b0
[FileCheck] Share variable instance among uses Summary: This patch changes expression support to use one instance of FileCheckNumericVariable per numeric variable rather than one per variable and per definition. The current system was only necessary for the last patch of the numeric expression support patch series in order to handle a line using a variable defined earlier on the same line from the input text. However this can be dealt more efficiently. Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk Subscribers: JonChesterfield, rogfer01, hfinkel, kristina, rnk, tra, arichardson, grimar, dblaikie, probinson, llvm-commits, hiraditya Tags: #llvm Differential Revision: https://reviews.llvm.org/D64229 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@365220 91177308-0d34-0410-b5e6-96231b3b80d8 Thomas Preud'homme 3 months ago
3 changed file(s) with 61 addition(s) and 45 deletion(s). Raw diff Collapse all Expand all
3939 // Numeric substitution handling code.
4040 //===----------------------------------------------------------------------===//
4141
42 /// Class representing a numeric variable with a given value in a numeric
43 /// expression. Each definition of a variable gets its own instance of this
44 /// class. Variable uses share the same instance as their respective
45 /// definition.
42 /// Class representing a numeric variable and its associated current value.
4643 class FileCheckNumericVariable {
4744 private:
4845 /// Name of the numeric variable.
270267 StringMap DefinedVariableTable;
271268
272269 /// When matching a given pattern, this holds the pointers to the classes
273 /// representing the last definitions of numeric variables defined in
274 /// previous patterns. Earlier definitions of the variables, if any, have
275 /// their own class instance not referenced by this table. When matching a
276 /// pattern all definitions for that pattern are recorded in the
270 /// representing the numeric variables defined in previous patterns. When
271 /// matching a pattern all definitions for that pattern are recorded in the
277272 /// NumericVariableDefs table in the FileCheckPattern instance of that
278273 /// pattern.
279274 StringMap GlobalNumericVariableTable;
275
276 /// Pointer to the class instance representing the @LINE pseudo variable for
277 /// easily updating its value.
278 FileCheckNumericVariable *LineVariable = nullptr;
280279
281280 /// Vector holding pointers to all parsed expressions. Used to automatically
282281 /// free the expressions once they are guaranteed to no longer be used.
301300 /// \p SM for all definition parsing failures, if any, or Success otherwise.
302301 Error defineCmdlineVariables(std::vector &CmdlineDefines,
303302 SourceMgr &SM);
303
304 /// Create @LINE pseudo variable. Value is set when pattern are being
305 /// matched.
306 void createLineVariable();
304307
305308 /// Undefines local variables (variables whose name does not start with a '$'
306309 /// sign), i.e. removes them from GlobalVariableTable and from
461464 /// name.
462465 static Expected parseVariable(StringRef &Str, bool &IsPseudo,
463466 const SourceMgr &SM);
464 /// Parses \p Expr for the name of a numeric variable to be defined. \returns
465 /// an error holding a diagnostic against \p SM should defining such a
466 /// variable be invalid, or Success otherwise. In the latter case, sets
467 /// \p Name to the name of the parsed numeric variable name.
468 static Error parseNumericVariableDefinition(StringRef &Expr, StringRef &Name,
469 FileCheckPatternContext *Context,
470 const SourceMgr &SM);
467 /// Parses \p Expr for the name of a numeric variable to be defined at line
468 /// \p LineNumber. \returns a pointer to the class instance representing that
469 /// variable, creating it if needed, or an error holding a diagnostic against
470 /// \p SM should defining such a variable be invalid.
471 static Expected
472 parseNumericVariableDefinition(StringRef &Expr,
473 FileCheckPatternContext *Context,
474 size_t LineNumber, const SourceMgr &SM);
471475 /// Parses \p Expr for a numeric substitution block. \returns the class
472476 /// representing the AST of the expression whose value must be substituted,
473477 /// or an error holding a diagnostic against \p SM if parsing fails. If
109109 char FileCheckErrorDiagnostic::ID = 0;
110110 char FileCheckNotFoundError::ID = 0;
111111
112 Error FileCheckPattern::parseNumericVariableDefinition(
113 StringRef &Expr, StringRef &Name, FileCheckPatternContext *Context,
112 Expected
113 FileCheckPattern::parseNumericVariableDefinition(
114 StringRef &Expr, FileCheckPatternContext *Context, size_t LineNumber,
114115 const SourceMgr &SM) {
115116 bool IsPseudo;
116117 Expected ParseVarResult = parseVariable(Expr, IsPseudo, SM);
117118 if (!ParseVarResult)
118119 return ParseVarResult.takeError();
119 Name = *ParseVarResult;
120 StringRef Name = *ParseVarResult;
120121
121122 if (IsPseudo)
122123 return FileCheckErrorDiagnostic::get(
134135 return FileCheckErrorDiagnostic::get(
135136 SM, Expr, "unexpected characters after numeric variable name");
136137
137 return Error::success();
138 FileCheckNumericVariable *DefinedNumericVariable;
139 auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
140 if (VarTableIter != Context->GlobalNumericVariableTable.end())
141 DefinedNumericVariable = VarTableIter->second;
142 else
143 DefinedNumericVariable = Context->makeNumericVariable(LineNumber, Name);
144
145 return DefinedNumericVariable;
138146 }
139147
140148 Expected
153161 // Numeric variable definitions and uses are parsed in the order in which
154162 // they appear in the CHECK patterns. For each definition, the pointer to the
155163 // class instance of the corresponding numeric variable definition is stored
156 // in GlobalNumericVariableTable in parsePattern. Therefore, the pointer we
157 // get below is for the class instance corresponding to the last definition
158 // of this variable use. If we don't find a variable definition we create a
159 // dummy one so that parsing can continue. All uses of undefined variables,
160 // whether string or numeric, are then diagnosed in printSubstitutions()
161 // after failing to match.
164 // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer
165 // we get below is null, it means no such variable was defined before. When
166 // that happens, we create a dummy variable so that parsing can continue. All
167 // uses of undefined variables, whether string or numeric, are then diagnosed
168 // in printSubstitutions() after failing to match.
162169 auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
163170 FileCheckNumericVariable *NumericVariable;
164171 if (VarTableIter != Context->GlobalNumericVariableTable.end())
248255 "unexpected string after variable definition: '" + UseExpr + "'");
249256
250257 DefExpr = DefExpr.ltrim(SpaceChars);
251 StringRef Name;
252 Error Err = parseNumericVariableDefinition(DefExpr, Name, Context, SM);
253 if (Err)
254 return std::move(Err);
255 DefinedNumericVariable = Context->makeNumericVariable(LineNumber, Name);
258 Expected ParseResult =
259 parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);
260 if (!ParseResult)
261 return ParseResult.takeError();
262 DefinedNumericVariable = *ParseResult;
256263
257264 return Context->makeExpression(add, nullptr, 0);
258265 }
268275 bool MatchFullLinesHere = Req.MatchFullLines && CheckTy != Check::CheckNot;
269276
270277 PatternLoc = SMLoc::getFromPointer(PatternStr.data());
271
272 // Create fake @LINE pseudo variable definition.
273 StringRef LinePseudo = "@LINE";
274 uint64_t LineNumber64 = LineNumber;
275 FileCheckNumericVariable *LinePseudoVar =
276 Context->makeNumericVariable(LinePseudo, LineNumber64);
277 Context->GlobalNumericVariableTable[LinePseudo] = LinePseudoVar;
278278
279279 if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
280280 // Ignore trailing whitespace.
570570 std::string TmpStr;
571571 if (!Substitutions.empty()) {
572572 TmpStr = RegExStr;
573 Context->LineVariable->setValue(LineNumber);
573574
574575 size_t InsertOffset = 0;
575576 // Substitute all string variables and expressions whose values are only
589590
590591 // Match the newly constructed regex.
591592 RegExToMatch = TmpStr;
593 Context->LineVariable->clearValue();
592594 }
593595
594596 SmallVector MatchInfo;
10571059 return {StringRef(), StringRef()};
10581060 }
10591061
1062 void FileCheckPatternContext::createLineVariable() {
1063 assert(!LineVariable && "@LINE pseudo numeric variable already created");
1064 StringRef LineName = "@LINE";
1065 LineVariable = makeNumericVariable(0, LineName);
1066 GlobalNumericVariableTable[LineName] = LineVariable;
1067 }
1068
10601069 bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
10611070 std::vector &CheckStrings) {
10621071 Error DefineError =
10651074 logAllUnhandledErrors(std::move(DefineError), errs());
10661075 return true;
10671076 }
1077
1078 PatternContext.createLineVariable();
10681079
10691080 std::vector ImplicitNegativeChecks;
10701081 for (const auto &PatternString : Req.ImplicitCheckNot) {
17381749 // Numeric variable definition.
17391750 if (CmdlineDef[0] == '#') {
17401751 StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);
1741 StringRef VarName;
1742 Error ErrorDiagnostic = FileCheckPattern::parseNumericVariableDefinition(
1743 CmdlineName, VarName, this, SM);
1744 if (ErrorDiagnostic) {
1745 Errs = joinErrors(std::move(Errs), std::move(ErrorDiagnostic));
1752 Expected ParseResult =
1753 FileCheckPattern::parseNumericVariableDefinition(CmdlineName, this, 0,
1754 SM);
1755 if (!ParseResult) {
1756 Errs = joinErrors(std::move(Errs), ParseResult.takeError());
17461757 continue;
17471758 }
17481759
17561767 CmdlineVal + "'"));
17571768 continue;
17581769 }
1759 auto DefinedNumericVariable = makeNumericVariable(0, VarName);
1770 FileCheckNumericVariable *DefinedNumericVariable = *ParseResult;
17601771 DefinedNumericVariable->setValue(Val);
17611772
17621773 // Record this variable definition.
177177 GlobalDefines.emplace_back(std::string("BAR=BAZ"));
178178 EXPECT_FALSE(
179179 errorToBool(Context.defineCmdlineVariables(GlobalDefines, SM)));
180 Context.createLineVariable();
180181 // Call parsePattern to have @LINE defined.
181182 P.parsePattern("N/A", "CHECK", SM, Req);
182183 // parsePattern does not expect to be called twice for the same line and
191192
192193 bool parseNumVarDefExpect(StringRef Expr) {
193194 StringRef ExprBufferRef = bufferize(SM, Expr);
194 StringRef Name;
195195 return errorToBool(FileCheckPattern::parseNumericVariableDefinition(
196 ExprBufferRef, Name, &Context, SM));
196 ExprBufferRef, &Context, LineNumber, SM)
197 .takeError());
197198 }
198199
199200 bool parseSubstExpect(StringRef Expr) {