8#ifndef MIDEND_PARSERUNROLL_H_
9#define MIDEND_PARSERUNROLL_H_
11#include <unordered_map>
13#include "frontends/common/resolveReferences/referenceMap.h"
14#include "frontends/p4/callGraph.h"
15#include "frontends/p4/simplify.h"
16#include "frontends/p4/typeChecking/typeChecker.h"
17#include "frontends/p4/typeMap.h"
18#include "interpreter.h"
37 friend class StackVariableHash;
41 static bool repOk(
const IR::Expression *expr);
47 const IR::Expression *variable;
60typedef std::unordered_map<StackVariable, size_t, StackVariableHash> StackVariableMap;
61typedef std::unordered_map<StackVariable, const IR::Expression *, StackVariableHash>
62 StackVariableIndexMap;
65struct ParserStateInfo {
66 friend class ParserStateRewriter;
68 const IR::P4Parser *parser;
69 const IR::ParserState *state;
70 const ParserStateInfo *predecessor;
73 IR::ParserState *newState;
75 StackVariableMap statesIndexes;
77 std::unordered_set<cstring> scenarioStates;
78 std::unordered_set<cstring> scenarioHS;
79 StackVariableIndexMap substitutedIndexes;
80 ParserStateInfo(
cstring name,
const IR::P4Parser *parser,
const IR::ParserState *state,
81 const ParserStateInfo *predecessor,
ValueMap *before,
size_t index)
85 predecessor(predecessor),
94 statesIndexes = predecessor->statesIndexes;
95 scenarioHS = predecessor->scenarioHS;
96 substitutedIndexes = predecessor->substitutedIndexes;
103 friend class RewriteAllParsers;
105 std::vector<ParserStateInfo *> *ordered_states =
new std::vector<ParserStateInfo *>();
106 std::map<cstring, std::vector<ParserStateInfo *> *> states;
110 cstring origState = si->state->name.name;
111 std::vector<ParserStateInfo *> *vec;
112 auto it = states.find(origState);
113 if (it == states.end()) {
114 vec =
new std::vector<ParserStateInfo *>;
115 states.emplace(origState, vec);
116 ordered_states->push_back(si);
126 std::map<cstring, std::vector<ParserStateInfo *> *> &getStates() {
return states; }
133 friend class ParserStateRewriter;
134 friend class ParserSymbolicInterpreter;
135 friend class AnalyzeParser;
136 std::map<cstring, const IR::ParserState *> stateMap;
139 const IR::P4Parser *parser;
140 const IR::ParserState *start;
142 StateCallGraph *callGraph;
143 std::map<cstring, std::set<cstring>> statesWithHeaderStacks;
144 std::map<cstring, size_t> callsIndexes;
145 void setParser(
const IR::P4Parser *parser) {
147 callGraph =
new StateCallGraph(parser->name.name);
148 this->parser = parser;
151 void addState(
const IR::ParserState *state) { stateMap.emplace(state->name, state); }
152 const IR::ParserState *get(
cstring state)
const { return ::P4::get(stateMap, state); }
153 void calls(
const IR::ParserState *caller,
const IR::ParserState *callee) {
154 callGraph->calls(caller, callee);
165 void addStateHSUsage(
const IR::ParserState *state,
const IR::Expression *expression);
171 const IR::ParserState *currentState;
175 : refMap(refMap), current(current), currentState(
nullptr) {
178 setName(
"AnalyzeParser");
179 visitDagOnce =
false;
182 bool preorder(
const IR::P4Parser *parser)
override {
183 LOG2(
"Scanning " << parser);
184 current->setParser(parser);
187 bool preorder(
const IR::ParserState *state)
override;
188 void postorder(
const IR::ParserState *state)
override;
189 void postorder(
const IR::ArrayIndex *array)
override;
190 void postorder(
const IR::Member *member)
override;
191 void postorder(
const IR::PathExpression *expression)
override;
195class ParserRewriter :
public PassManager {
197 friend class RewriteAllParsers;
200 bool hasOutOfboundState;
206 setName(
"ParserRewriter");
209 [
this, refMap, typeMap, unroll](void) {
210 hasOutOfboundState = current.analyze(refMap, typeMap, unroll, wasError);
221 bool order_states =
false;
231 : refMap(refMap), config(config), typeMap(typeMap) {
234 setName(
"RewriteAllParsers");
240 auto rewriter =
new ParserRewriter(refMap, typeMap, config.unroll);
241 rewriter->setCalledBy(
this);
242 parser->apply(*rewriter);
243 if (rewriter->wasError) {
247 BUG_CHECK(rewriter->current.result,
248 "No result was found after unrolling of the parser loop");
249 IR::P4Parser *newParser = parser->clone();
251 newParser->states.clear();
252 if (rewriter->hasOutOfboundState) {
255 arguments->push_back(
new IR::Argument(IR::BoolLiteral::get(
false)));
256 arguments->push_back(
new IR::Argument(
257 new IR::Member(
new IR::TypeNameExpression(
new IR::Type_Name(
IR::ID(
"error"))),
258 IR::ID(
"StackOutOfBounds"))));
261 parameters.push_back(
262 new IR::Parameter(
IR::ID(
"check"), IR::Direction::In, IR::Type::Boolean::get()));
263 parameters.push_back(
new IR::Parameter(
IR::ID(
"toSignal"), IR::Direction::In,
264 new IR::Type_Name(
IR::ID(
"error"))));
265 components.push_back(
new IR::MethodCallStatement(
new IR::MethodCallExpression(
266 IR::Type::Void::get(),
267 new IR::PathExpression(
268 new IR::Type_Method(IR::Type::Void::get(),
new IR::ParameterList(parameters),
270 new IR::Path(
IR::ID(
"verify"))),
272 auto *outOfBoundsState =
new IR::ParserState(
274 new IR::PathExpression(IR::Type_State::get(),
275 new IR::Path(IR::ParserState::reject,
false)));
276 newParser->states.push_back(outOfBoundsState);
279 if (config.order_states) {
280 if (rewriter->current.result->ordered_states) {
281 for (
auto &i : *rewriter->current.result->ordered_states) {
282 if (rewriter->hasOutOfboundState && i->name ==
"stateOutOfBound") {
285 newParser->states.push_back(i->state);
289 for (
auto &i : rewriter->current.result->states) {
290 for (
auto &j : *i.second)
292 if (rewriter->hasOutOfboundState &&
293 j->newState->name.name ==
"stateOutOfBound") {
296 newParser->states.push_back(j->newState);
301 newParser->states.push_back(
new IR::ParserState(IR::ParserState::accept,
nullptr));
302 newParser->states.push_back(
new IR::ParserState(IR::ParserState::reject,
nullptr));
308class ParsersUnroll :
public PassManager {
315 setName(
"ParsersUnroll");
Definition parserUnroll.h:168
Definition callGraph.h:41
Definition indexed_vector.h:31
Definition ir/vector.h:59
Information produced for a parser by the symbolic evaluator.
Definition parserUnroll.h:102
Definition parserUnroll.h:195
Information about a parser in the input program.
Definition parserUnroll.h:132
bool reachableHSUsage(IR::ID id, const ParserStateInfo *state) const
check reachability for usage of header stack
Definition parserUnroll.cpp:882
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:902
Class used to encode maps from paths to declarations.
Definition referenceMap.h:67
Definition parserUnroll.h:224
const IR::Node * postorder(IR::P4Parser *parser) override
Definition parserUnroll.h:238
Class with hash function for StackVariable.
Definition parserUnroll.h:55
Definition parserUnroll.h:36
static bool repOk(const IR::Expression *expr)
Determines whether @expr can represent a StateVariable.
Definition parserUnroll.cpp:20
StackVariable(const IR::Expression *expr)
Implicitly converts IR::Expression* to a StackVariable.
Definition parserUnroll.cpp:14
Definition typeChecker.h:55
Definition interpreter.h:63
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
const char outOfBoundsStateName[]
Name of out of bound state.
Definition parserUnroll.h:24
Definition parserUnroll.h:219
Information produced for a parser state by the symbolic evaluator.
Definition parserUnroll.h:65