P4C
The P4 Compiler
Loading...
Searching...
No Matches
parserUnroll.h
1/*
2Copyright 2016 VMware, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef MIDEND_PARSERUNROLL_H_
18#define MIDEND_PARSERUNROLL_H_
19
20#include <unordered_map>
21
22#include "frontends/common/resolveReferences/referenceMap.h"
23#include "frontends/p4/callGraph.h"
24#include "frontends/p4/simplify.h"
25#include "frontends/p4/typeChecking/typeChecker.h"
26#include "frontends/p4/typeMap.h"
27#include "interpreter.h"
28#include "ir/ir.h"
29
30namespace P4 {
31
33const char outOfBoundsStateName[] = "stateOutOfBound";
34
36// The following are for a single parser
37
38// Represents a variable for storing indexes values for a header stack.
39//
40// This is a thin wrapper around a 'const IR::Member*' to (1) enforce invariants on which forms of
41// Members can represent state variables and (2) enable the use of StackVariable as map keys.
42//
43// A Member can represent a StackVariable exactly when its qualifying variable
44// (IR::Member::expr) either is a PathExpression or can represent a StackVariable.
46 friend class StackVariableHash;
47
48 public:
50 static bool repOk(const IR::Expression *expr);
51
52 // Implements comparisons so that StateVariables can be used as map keys.
53 bool operator==(const StackVariable &other) const;
54
55 private:
56 const IR::Expression *variable;
57
58 public:
60 StackVariable(const IR::Expression *expr); // NOLINT(runtime/explicit)
61};
62
65 public:
66 size_t operator()(const StackVariable &var) const;
67};
68
69typedef std::unordered_map<StackVariable, size_t, StackVariableHash> StackVariableMap;
70typedef std::unordered_map<StackVariable, const IR::Expression *, StackVariableHash>
71 StackVariableIndexMap;
72
74struct ParserStateInfo {
75 friend class ParserStateRewriter;
76 cstring name; // new state name
77 const IR::P4Parser *parser;
78 const IR::ParserState *state; // original state this is produced from
79 const ParserStateInfo *predecessor; // how we got here in the symbolic evaluation
80 ValueMap *before;
81 ValueMap *after;
82 IR::ParserState *newState; // pointer to a new state
83 size_t currentIndex;
84 StackVariableMap statesIndexes; // global map in state indexes
85 // set of parsers' states names with are in current path.
86 std::unordered_set<cstring> scenarioStates;
87 std::unordered_set<cstring> scenarioHS; // scenario header stack's operations
88 StackVariableIndexMap substitutedIndexes; // values of the evaluated indexes
89 ParserStateInfo(cstring name, const IR::P4Parser *parser, const IR::ParserState *state,
90 const ParserStateInfo *predecessor, ValueMap *before, size_t index)
91 : name(name),
92 parser(parser),
93 state(state),
94 predecessor(predecessor),
95 before(before),
96 after(nullptr),
97 newState(nullptr),
98 currentIndex(index) {
99 CHECK_NULL(parser);
100 CHECK_NULL(state);
101 CHECK_NULL(before);
102 if (predecessor) {
103 statesIndexes = predecessor->statesIndexes;
104 scenarioHS = predecessor->scenarioHS;
105 substitutedIndexes = predecessor->substitutedIndexes;
106 }
107 }
108};
109
112 friend class RewriteAllParsers;
113 // for each original state a vector of states produced by unrolling
114 std::vector<ParserStateInfo *> *ordered_states = new std::vector<ParserStateInfo *>();
115 std::map<cstring, std::vector<ParserStateInfo *> *> states;
116
117 public:
118 std::vector<ParserStateInfo *> *get(ParserStateInfo *si) {
119 cstring origState = si->state->name.name;
120 std::vector<ParserStateInfo *> *vec;
121 auto it = states.find(origState);
122 if (it == states.end()) {
123 vec = new std::vector<ParserStateInfo *>;
124 states.emplace(origState, vec);
125 ordered_states->push_back(si);
126 } else {
127 vec = it->second;
128 }
129 return vec;
130 }
131 void add(ParserStateInfo *si) {
132 auto vec = get(si);
133 vec->push_back(si);
134 }
135 std::map<cstring, std::vector<ParserStateInfo *> *> &getStates() { return states; }
136};
137
138typedef CallGraph<const IR::ParserState *> StateCallGraph;
139
142 friend class ParserStateRewriter;
143 friend class ParserSymbolicInterpreter;
144 friend class AnalyzeParser;
145 std::map<cstring, const IR::ParserState *> stateMap;
146
147 public:
148 const IR::P4Parser *parser;
149 const IR::ParserState *start;
150 const ParserInfo *result;
151 StateCallGraph *callGraph;
152 std::map<cstring, std::set<cstring>> statesWithHeaderStacks;
153 std::map<cstring, size_t> callsIndexes; // map for curent calls of state insite current one
154 void setParser(const IR::P4Parser *parser) {
155 CHECK_NULL(parser);
156 callGraph = new StateCallGraph(parser->name.name);
157 this->parser = parser;
158 start = nullptr;
159 }
160 void addState(const IR::ParserState *state) { stateMap.emplace(state->name, state); }
161 const IR::ParserState *get(cstring state) const { return ::P4::get(stateMap, state); }
162 void calls(const IR::ParserState *caller, const IR::ParserState *callee) {
163 callGraph->calls(caller, callee);
164 }
165
166 bool analyze(ReferenceMap *refMap, TypeMap *typeMap, bool unroll, bool &wasError);
168 bool reachableHSUsage(IR::ID id, const ParserStateInfo *state) const;
169
170 protected:
174 void addStateHSUsage(const IR::ParserState *state, const IR::Expression *expression);
175};
176
177class AnalyzeParser : public Inspector {
178 const ReferenceMap *refMap;
179 ParserStructure *current;
180 const IR::ParserState *currentState;
181
182 public:
183 AnalyzeParser(const ReferenceMap *refMap, ParserStructure *current)
184 : refMap(refMap), current(current), currentState(nullptr) {
185 CHECK_NULL(refMap);
186 CHECK_NULL(current);
187 setName("AnalyzeParser");
188 visitDagOnce = false;
189 }
190
191 bool preorder(const IR::P4Parser *parser) override {
192 LOG2("Scanning " << parser);
193 current->setParser(parser);
194 return true;
195 }
196 bool preorder(const IR::ParserState *state) override;
197 void postorder(const IR::ParserState *state) override;
198 void postorder(const IR::ArrayIndex *array) override;
199 void postorder(const IR::Member *member) override;
200 void postorder(const IR::PathExpression *expression) override;
201};
202
203// Applied to a P4Parser object.
204class ParserRewriter : public PassManager {
205 ParserStructure current;
206 friend class RewriteAllParsers;
207
208 public:
209 bool hasOutOfboundState;
210 bool wasError;
211 ParserRewriter(ReferenceMap *refMap, TypeMap *typeMap, bool unroll) {
212 CHECK_NULL(refMap);
213 CHECK_NULL(typeMap);
214 wasError = false;
215 setName("ParserRewriter");
216 addPasses({
217 new AnalyzeParser(refMap, &current),
218 [this, refMap, typeMap, unroll](void) {
219 hasOutOfboundState = current.analyze(refMap, typeMap, unroll, wasError);
220 },
221 });
222 }
223};
224
226// The following are applied to the entire program
227
229 bool unroll = true;
230 bool order_states = false;
231};
232
233class RewriteAllParsers : public Transform {
234 ReferenceMap *refMap;
235 ParserConfig config;
236 TypeMap *typeMap;
237
238 public:
239 RewriteAllParsers(ReferenceMap *refMap, TypeMap *typeMap, ParserConfig config)
240 : refMap(refMap), config(config), typeMap(typeMap) {
241 CHECK_NULL(refMap);
242 CHECK_NULL(typeMap);
243 setName("RewriteAllParsers");
244 }
245
246 // start generation of a code
247 const IR::Node *postorder(IR::P4Parser *parser) override {
248 // making rewriting
249 auto rewriter = new ParserRewriter(refMap, typeMap, config.unroll);
250 rewriter->setCalledBy(this);
251 parser->apply(*rewriter);
252 if (rewriter->wasError) {
253 return parser;
254 }
256 BUG_CHECK(rewriter->current.result,
257 "No result was found after unrolling of the parser loop");
258 IR::P4Parser *newParser = parser->clone();
259 IR::IndexedVector<IR::ParserState> states = newParser->states;
260 newParser->states.clear();
261 if (rewriter->hasOutOfboundState) {
262 // generating state with verify(false, error.StackOutOfBounds)
264 arguments->push_back(new IR::Argument(IR::BoolLiteral::get(false)));
265 arguments->push_back(new IR::Argument(
266 new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(IR::ID("error"))),
267 IR::ID("StackOutOfBounds"))));
270 parameters.push_back(
271 new IR::Parameter(IR::ID("check"), IR::Direction::In, IR::Type::Boolean::get()));
272 parameters.push_back(new IR::Parameter(IR::ID("toSignal"), IR::Direction::In,
273 new IR::Type_Name(IR::ID("error"))));
274 components.push_back(new IR::MethodCallStatement(new IR::MethodCallExpression(
275 IR::Type::Void::get(),
276 new IR::PathExpression(
277 new IR::Type_Method(IR::Type::Void::get(), new IR::ParameterList(parameters),
278 "*method"_cs),
279 new IR::Path(IR::ID("verify"))),
280 arguments)));
281 auto *outOfBoundsState = new IR::ParserState(
282 IR::ID(outOfBoundsStateName), components,
283 new IR::PathExpression(IR::Type_State::get(),
284 new IR::Path(IR::ParserState::reject, false)));
285 newParser->states.push_back(outOfBoundsState);
286 }
287
288 if (config.order_states) {
289 if (rewriter->current.result->ordered_states) {
290 for (auto &i : *rewriter->current.result->ordered_states) {
291 if (rewriter->hasOutOfboundState && i->name == "stateOutOfBound") {
292 continue;
293 }
294 newParser->states.push_back(i->state);
295 }
296 }
297 } else {
298 for (auto &i : rewriter->current.result->states) {
299 for (auto &j : *i.second)
300 if (j->newState) {
301 if (rewriter->hasOutOfboundState &&
302 j->newState->name.name == "stateOutOfBound") {
303 continue;
304 }
305 newParser->states.push_back(j->newState);
306 }
307 }
308 }
309 // adding accept/reject
310 newParser->states.push_back(new IR::ParserState(IR::ParserState::accept, nullptr));
311 newParser->states.push_back(new IR::ParserState(IR::ParserState::reject, nullptr));
312
313 return newParser;
314 }
315};
316
317class ParsersUnroll : public PassManager {
318 public:
319 ParsersUnroll(ParserConfig config, ReferenceMap *refMap, TypeMap *typeMap) {
320 // remove block statements
321 passes.push_back(new SimplifyControlFlow(typeMap, false));
322 passes.push_back(new TypeChecking(refMap, typeMap));
323 passes.push_back(new RewriteAllParsers(refMap, typeMap, config));
324 setName("ParsersUnroll");
325 }
326};
327
328} // namespace P4
329
330#endif /* MIDEND_PARSERUNROLL_H_ */
Definition parserUnroll.h:177
Definition callGraph.h:41
Definition indexed_vector.h:40
Definition node.h:94
Definition ir/vector.h:59
Definition visitor.h:413
Information produced for a parser by the symbolic evaluator.
Definition parserUnroll.h:111
Definition parserUnroll.h:204
Information about a parser in the input program.
Definition parserUnroll.h:141
bool reachableHSUsage(IR::ID id, const ParserStateInfo *state) const
check reachability for usage of header stack
Definition parserUnroll.cpp:878
void evaluateReachability()
evaluates rechable states with HS operations for each path.
void addStateHSUsage(const IR::ParserState *state, const IR::Expression *expression)
add HS name which is used in a current state.
Definition parserUnroll.cpp:898
Class used to encode maps from paths to declarations.
Definition referenceMap.h:67
Definition parserUnroll.h:233
const IR::Node * postorder(IR::P4Parser *parser) override
Definition parserUnroll.h:247
Definition simplify.h:72
Class with hash function for StackVariable.
Definition parserUnroll.h:64
Definition parserUnroll.h:45
static bool repOk(const IR::Expression *expr)
Determines whether @expr can represent a StateVariable.
Definition parserUnroll.cpp:16
StackVariable(const IR::Expression *expr)
Implicitly converts IR::Expression* to a StackVariable.
Definition parserUnroll.cpp:10
Definition visitor.h:437
Definition typeChecker.h:55
Definition typeMap.h:41
Definition interpreter.h:71
Definition cstring.h:85
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
const char outOfBoundsStateName[]
Name of out of bound state.
Definition parserUnroll.h:33
Definition parserUnroll.h:228
Definition id.h:28
Information produced for a parser state by the symbolic evaluator.
Definition parserUnroll.h:74