17#ifndef MIDEND_PARSERUNROLL_H_
18#define MIDEND_PARSERUNROLL_H_
20#include <unordered_map>
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"
46 friend class StackVariableHash;
50 static bool repOk(
const IR::Expression *expr);
56 const IR::Expression *variable;
69typedef std::unordered_map<StackVariable, size_t, StackVariableHash> StackVariableMap;
70typedef std::unordered_map<StackVariable, const IR::Expression *, StackVariableHash>
71 StackVariableIndexMap;
74struct ParserStateInfo {
75 friend class ParserStateRewriter;
77 const IR::P4Parser *parser;
78 const IR::ParserState *state;
79 const ParserStateInfo *predecessor;
82 IR::ParserState *newState;
84 StackVariableMap statesIndexes;
86 std::unordered_set<cstring> scenarioStates;
87 std::unordered_set<cstring> scenarioHS;
88 StackVariableIndexMap substitutedIndexes;
89 ParserStateInfo(
cstring name,
const IR::P4Parser *parser,
const IR::ParserState *state,
90 const ParserStateInfo *predecessor,
ValueMap *before,
size_t index)
94 predecessor(predecessor),
103 statesIndexes = predecessor->statesIndexes;
104 scenarioHS = predecessor->scenarioHS;
105 substitutedIndexes = predecessor->substitutedIndexes;
112 friend class RewriteAllParsers;
114 std::vector<ParserStateInfo *> *ordered_states =
new std::vector<ParserStateInfo *>();
115 std::map<cstring, std::vector<ParserStateInfo *> *> states;
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);
135 std::map<cstring, std::vector<ParserStateInfo *> *> &getStates() {
return states; }
142 friend class ParserStateRewriter;
143 friend class ParserSymbolicInterpreter;
144 friend class AnalyzeParser;
145 std::map<cstring, const IR::ParserState *> stateMap;
148 const IR::P4Parser *parser;
149 const IR::ParserState *start;
151 StateCallGraph *callGraph;
152 std::map<cstring, std::set<cstring>> statesWithHeaderStacks;
153 std::map<cstring, size_t> callsIndexes;
154 void setParser(
const IR::P4Parser *parser) {
156 callGraph =
new StateCallGraph(parser->name.name);
157 this->parser = parser;
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);
174 void addStateHSUsage(
const IR::ParserState *state,
const IR::Expression *expression);
180 const IR::ParserState *currentState;
184 : refMap(refMap), current(current), currentState(
nullptr) {
187 setName(
"AnalyzeParser");
188 visitDagOnce =
false;
191 bool preorder(
const IR::P4Parser *parser)
override {
192 LOG2(
"Scanning " << parser);
193 current->setParser(parser);
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;
204class ParserRewriter :
public PassManager {
206 friend class RewriteAllParsers;
209 bool hasOutOfboundState;
215 setName(
"ParserRewriter");
218 [
this, refMap, typeMap, unroll](void) {
219 hasOutOfboundState = current.analyze(refMap, typeMap, unroll, wasError);
230 bool order_states =
false;
240 : refMap(refMap), config(config), typeMap(typeMap) {
243 setName(
"RewriteAllParsers");
249 auto rewriter =
new ParserRewriter(refMap, typeMap, config.unroll);
250 rewriter->setCalledBy(
this);
251 parser->apply(*rewriter);
252 if (rewriter->wasError) {
256 BUG_CHECK(rewriter->current.result,
257 "No result was found after unrolling of the parser loop");
258 IR::P4Parser *newParser = parser->clone();
260 newParser->states.clear();
261 if (rewriter->hasOutOfboundState) {
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),
279 new IR::Path(
IR::ID(
"verify"))),
281 auto *outOfBoundsState =
new IR::ParserState(
283 new IR::PathExpression(IR::Type_State::get(),
284 new IR::Path(IR::ParserState::reject,
false)));
285 newParser->states.push_back(outOfBoundsState);
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") {
294 newParser->states.push_back(i->state);
298 for (
auto &i : rewriter->current.result->states) {
299 for (
auto &j : *i.second)
301 if (rewriter->hasOutOfboundState &&
302 j->newState->name.name ==
"stateOutOfBound") {
305 newParser->states.push_back(j->newState);
310 newParser->states.push_back(
new IR::ParserState(IR::ParserState::accept,
nullptr));
311 newParser->states.push_back(
new IR::ParserState(IR::ParserState::reject,
nullptr));
317class ParsersUnroll :
public PassManager {
324 setName(
"ParsersUnroll");
Definition parserUnroll.h:177
Definition callGraph.h:41
Definition indexed_vector.h:40
Definition ir/vector.h:59
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
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 typeChecker.h:55
Definition interpreter.h:71
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
Information produced for a parser state by the symbolic evaluator.
Definition parserUnroll.h:74