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
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::map<cstring, std::vector<ParserStateInfo *> *> states;
115
116 public:
117 std::vector<ParserStateInfo *> *get(cstring origState) {
118 std::vector<ParserStateInfo *> *vec;
119 auto it = states.find(origState);
120 if (it == states.end()) {
121 vec = new std::vector<ParserStateInfo *>;
122 states.emplace(origState, vec);
123 } else {
124 vec = it->second;
125 }
126 return vec;
127 }
128 void add(ParserStateInfo *si) {
129 cstring origState = si->state->name.name;
130 auto vec = get(origState);
131 vec->push_back(si);
132 }
133 std::map<cstring, std::vector<ParserStateInfo *> *> &getStates() { return states; }
134};
135
137
140 friend class ParserStateRewriter;
141 friend class ParserSymbolicInterpreter;
142 friend class AnalyzeParser;
143 std::map<cstring, const IR::ParserState *> stateMap;
144
145 public:
146 const IR::P4Parser *parser;
147 const IR::ParserState *start;
148 const ParserInfo *result;
149 StateCallGraph *callGraph;
150 std::map<cstring, std::set<cstring>> statesWithHeaderStacks;
151 std::map<cstring, size_t> callsIndexes; // map for curent calls of state insite current one
152 void setParser(const IR::P4Parser *parser) {
153 CHECK_NULL(parser);
154 callGraph = new StateCallGraph(parser->name.name.string_view());
155 this->parser = parser;
156 start = nullptr;
157 }
158 void addState(const IR::ParserState *state) { stateMap.emplace(state->name, state); }
159 const IR::ParserState *get(cstring state) const { return ::P4::get(stateMap, state); }
160 void calls(const IR::ParserState *caller, const IR::ParserState *callee) {
161 callGraph->calls(caller, callee);
162 }
163
164 bool analyze(ReferenceMap *refMap, TypeMap *typeMap, bool unroll, bool &wasError);
166 bool reachableHSUsage(IR::ID id, const ParserStateInfo *state) const;
167
168 protected:
172 void addStateHSUsage(const IR::ParserState *state, const IR::Expression *expression);
173};
174
175class AnalyzeParser : public Inspector {
176 const ReferenceMap *refMap;
177 ParserStructure *current;
178 const IR::ParserState *currentState;
179
180 public:
181 AnalyzeParser(const ReferenceMap *refMap, ParserStructure *current)
182 : refMap(refMap), current(current), currentState(nullptr) {
183 CHECK_NULL(refMap);
184 CHECK_NULL(current);
185 setName("AnalyzeParser");
186 visitDagOnce = false;
187 }
188
189 bool preorder(const IR::P4Parser *parser) override {
190 LOG2("Scanning " << parser);
191 current->setParser(parser);
192 return true;
193 }
194 bool preorder(const IR::ParserState *state) override;
195 void postorder(const IR::ParserState *state) override;
196 void postorder(const IR::ArrayIndex *array) override;
197 void postorder(const IR::Member *member) override;
198 void postorder(const IR::PathExpression *expression) override;
199};
200
201// Applied to a P4Parser object.
203 ParserStructure current;
204 friend class RewriteAllParsers;
205
206 public:
207 bool hasOutOfboundState;
208 bool wasError;
209 ParserRewriter(ReferenceMap *refMap, TypeMap *typeMap, bool unroll) {
210 CHECK_NULL(refMap);
211 CHECK_NULL(typeMap);
212 wasError = false;
213 setName("ParserRewriter");
214 addPasses({
215 new AnalyzeParser(refMap, &current),
216 [this, refMap, typeMap, unroll](void) {
217 hasOutOfboundState = current.analyze(refMap, typeMap, unroll, wasError);
218 },
219 });
220 }
221};
222
224// The following are applied to the entire program
225
227 ReferenceMap *refMap;
228 TypeMap *typeMap;
229 bool unroll;
230
231 public:
232 RewriteAllParsers(ReferenceMap *refMap, TypeMap *typeMap, bool unroll)
233 : refMap(refMap), typeMap(typeMap), unroll(unroll) {
234 CHECK_NULL(refMap);
235 CHECK_NULL(typeMap);
236 setName("RewriteAllParsers");
237 }
238
239 // start generation of a code
240 const IR::Node *postorder(IR::P4Parser *parser) override {
241 // making rewriting
242 auto rewriter = new ParserRewriter(refMap, typeMap, unroll);
243 rewriter->setCalledBy(this);
244 parser->apply(*rewriter);
245 if (rewriter->wasError) {
246 return parser;
247 }
249 BUG_CHECK(rewriter->current.result,
250 "No result was found after unrolling of the parser loop");
251 IR::P4Parser *newParser = parser->clone();
252 IR::IndexedVector<IR::ParserState> states = newParser->states;
253 newParser->states.clear();
254 if (rewriter->hasOutOfboundState) {
255 // generating state with verify(false, error.StackOutOfBounds)
257 arguments->push_back(new IR::Argument(IR::BoolLiteral::get(false)));
258 arguments->push_back(new IR::Argument(
259 new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(IR::ID("error"))),
260 IR::ID("StackOutOfBounds"))));
263 parameters.push_back(
264 new IR::Parameter(IR::ID("check"), IR::Direction::In, IR::Type::Boolean::get()));
265 parameters.push_back(new IR::Parameter(IR::ID("toSignal"), IR::Direction::In,
266 new IR::Type_Name(IR::ID("error"))));
267 components.push_back(new IR::MethodCallStatement(new IR::MethodCallExpression(
268 IR::Type::Void::get(),
269 new IR::PathExpression(
270 new IR::Type_Method(IR::Type::Void::get(), new IR::ParameterList(parameters),
271 "*method"_cs),
272 new IR::Path(IR::ID("verify"))),
273 arguments)));
274 auto *outOfBoundsState = new IR::ParserState(
275 IR::ID(outOfBoundsStateName), components,
276 new IR::PathExpression(IR::Type_State::get(),
277 new IR::Path(IR::ParserState::reject, false)));
278 newParser->states.push_back(outOfBoundsState);
279 }
280 for (auto &i : rewriter->current.result->states) {
281 for (auto &j : *i.second)
282 if (j->newState) {
283 if (rewriter->hasOutOfboundState &&
284 j->newState->name.name == "stateOutOfBound") {
285 continue;
286 }
287 newParser->states.push_back(j->newState);
288 }
289 }
290 // adding accept/reject
291 newParser->states.push_back(new IR::ParserState(IR::ParserState::accept, nullptr));
292 newParser->states.push_back(new IR::ParserState(IR::ParserState::reject, nullptr));
293 return newParser;
294 }
295};
296
298 public:
299 ParsersUnroll(bool unroll, ReferenceMap *refMap, TypeMap *typeMap) {
300 // remove block statements
301 passes.push_back(new SimplifyControlFlow(typeMap));
302 passes.push_back(new TypeChecking(refMap, typeMap));
303 passes.push_back(new RewriteAllParsers(refMap, typeMap, unroll));
304 setName("ParsersUnroll");
305 }
306};
307
308} // namespace P4
309
310#endif /* MIDEND_PARSERUNROLL_H_ */
Definition parserUnroll.h:175
Definition callGraph.h:41
Definition node.h:52
Definition node.h:95
Definition vector.h:59
Definition visitor.h:400
Information produced for a parser by the symbolic evaluator.
Definition parserUnroll.h:111
Definition parserUnroll.h:202
Information about a parser in the input program.
Definition parserUnroll.h:139
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
Definition parserUnroll.h:297
Definition ir/pass_manager.h:40
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition parserUnroll.h:226
const IR::Node * postorder(IR::P4Parser *parser) override
Definition parserUnroll.h:240
Definition simplify.h:70
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:424
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 id.h:28
Information produced for a parser state by the symbolic evaluator.
Definition parserUnroll.h:74