P4C
The P4 Compiler
Loading...
Searching...
No Matches
sideEffects.h
1/*
2 * Copyright 2016 VMware, Inc.
3 * SPDX-FileCopyrightText: 2016 VMware, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef FRONTENDS_P4_SIDEEFFECTS_H_
9#define FRONTENDS_P4_SIDEEFFECTS_H_
10
11/* makes explicit side effect ordering */
12
13#include "frontends/common/resolveReferences/referenceMap.h"
14#include "frontends/common/resolveReferences/resolveReferences.h"
15#include "frontends/p4/methodInstance.h"
16#include "frontends/p4/typeChecking/typeChecker.h"
17#include "ir/ir.h"
18
19namespace P4 {
20
22class HasTableApply : public Inspector, public ResolutionContext {
23 TypeMap *typeMap;
24
25 public:
26 const IR::P4Table *table;
27 const IR::MethodCallExpression *call;
28 explicit HasTableApply(TypeMap *typeMap) : typeMap(typeMap), table(nullptr), call(nullptr) {
29 CHECK_NULL(typeMap);
30 setName("HasTableApply");
31 }
32
33 void postorder(const IR::MethodCallExpression *expression) override {
34 auto mi = MethodInstance::resolve(expression, this, typeMap);
35 if (!mi->isApply()) return;
36 auto am = mi->to<P4::ApplyMethod>();
37 if (!am->object->is<IR::P4Table>()) return;
38 BUG_CHECK(table == nullptr, "%1% and %2%: multiple table applications in one expression",
39 table, am->object);
40 table = am->object->to<IR::P4Table>();
41 call = expression;
42 LOG3("Invoked table is " << dbp(table));
43 }
44};
45
53class SideEffects : public Inspector, public ResolutionContext {
54 private:
55 TypeMap *typeMap;
56
57 public:
59 const IR::Node *nodeWithSideEffect = nullptr;
60
62 unsigned sideEffectCount = 0;
63
64 void postorder(const IR::MethodCallExpression *mce) override {
65 if (mayHaveSideEffect(mce, this, typeMap)) {
68 }
69 }
70
71 void postorder(const IR::ConstructorCallExpression *cce) override {
74 }
75
78 explicit SideEffects(TypeMap *typeMap) : typeMap(typeMap) { setName("SideEffects"); }
79
81 static bool check(const IR::Expression *expression, const Visitor *calledBy,
82 TypeMap *typeMap = nullptr, const Visitor::Context *ctxt = nullptr) {
83 SideEffects se(typeMap);
84 se.setCalledBy(calledBy);
85 if (calledBy && !ctxt) ctxt = calledBy->getChildContext();
86 expression->apply(se, ctxt);
87 return se.nodeWithSideEffect != nullptr;
88 }
89
90 static bool mayHaveSideEffect(const IR::MethodCallExpression *mce, DeclarationLookup *refMap,
91 TypeMap *typeMap) {
92 // mce does not produce a side effect in few cases:
93 // * isValid()
94 // * function, extern function, or extern method with noSideEffects annotation
95 auto mi = MethodInstance::resolve(mce, refMap, typeMap, !typeMap);
96 if (!mi) return true;
97 if (const auto *ec = mi->to<P4::ExternCall>())
98 return !ec->method->hasAnnotation(IR::Annotation::noSideEffectsAnnotation);
99 if (const auto *ef = mi->to<P4::FunctionCall>())
100 return !ef->function->hasAnnotation(IR::Annotation::noSideEffectsAnnotation);
101 if (const auto *bim = mi->to<BuiltInMethod>()) return bim->name != IR::Type_Header::isValid;
102 return true;
103 }
104};
105
138class DoSimplifyExpressions : public Transform, P4WriteContext, public ResolutionContext {
139 MinimalNameGenerator nameGen;
140 TypeMap *typeMap;
141 // Expressions holding temporaries that are already added.
142 std::set<const IR::Expression *> *added;
143
144 IR::IndexedVector<IR::Declaration> toInsert; // temporaries
148 std::set<const IR::Expression *> temporaries;
149
150 IR::ID createTemporary(Util::SourceInfo srcInfo, const IR::Type *type);
151 const IR::Expression *addAssignment(Util::SourceInfo srcInfo, IR::ID varName,
152 const IR::Expression *expression,
153 Util::SourceInfo resultSrcInfo = {});
154 bool mayAlias(const IR::Expression *left, const IR::Expression *right,
155 const Visitor::Context *ctxt) const;
156 bool containsHeaderType(const IR::Type *type);
157
158 public:
159 DoSimplifyExpressions(TypeMap *typeMap, std::set<const IR::Expression *> *added)
160 : typeMap(typeMap), added(added) {
161 CHECK_NULL(typeMap);
162 setName("DoSimplifyExpressions");
163 }
164
165 const IR::Node *postorder(IR::Expression *expression) override;
166 const IR::Node *preorder(IR::StructExpression *expression) override;
167 const IR::Node *preorder(IR::ListExpression *expression) override;
168 const IR::Node *preorder(IR::Literal *expression) override;
169 const IR::Node *preorder(IR::ArrayIndex *expression) override;
170 const IR::Node *preorder(IR::Member *expression) override;
171 const IR::Node *preorder(IR::SelectExpression *expression) override;
172 const IR::Node *preorder(IR::Operation_Unary *expression) override;
173 const IR::Node *preorder(IR::Operation_Binary *expression) override;
174 const IR::Node *shortCircuit(IR::Operation_Binary *expression);
175 const IR::Node *preorder(IR::Mux *expression) override;
176 const IR::Node *preorder(IR::LAnd *expression) override;
177 const IR::Node *preorder(IR::LOr *expression) override;
178 const IR::Node *preorder(IR::MethodCallExpression *mce) override;
179
180 const IR::Node *preorder(IR::ConstructorCallExpression *cce) override {
181 prune();
182 return cce;
183 }
184 const IR::Node *preorder(IR::Property *prop) override {
185 prune();
186 return prop;
187 }
188 const IR::Node *preorder(IR::Annotation *anno) override {
189 prune();
190 return anno;
191 }
192
193 const IR::Node *postorder(IR::P4Parser *parser) override;
194 const IR::Node *postorder(IR::Function *function) override;
195 const IR::Node *postorder(IR::P4Control *control) override;
196 const IR::Node *postorder(IR::P4Action *action) override;
197 const IR::Node *postorder(IR::ParserState *state) override;
198 const IR::Node *postorder(IR::BaseAssignmentStatement *statement) override;
199 const IR::Node *postorder(IR::MethodCallStatement *statement) override;
200 const IR::Node *postorder(IR::ReturnStatement *statement) override;
201 const IR::Node *preorder(IR::SwitchStatement *statement) override;
202 const IR::Node *preorder(IR::IfStatement *statement) override;
203 const IR::Node *preorder(IR::ForStatement *statement) override;
204 const IR::Node *preorder(IR::ForInStatement *statement) override;
205
206 profile_t init_apply(const IR::Node *node) override;
207 void end_apply(const IR::Node *) override;
208};
209
211 public:
212 std::vector<const IR::Declaration_Variable *> declarations;
213 std::vector<const IR::BaseAssignmentStatement *> statements;
214};
215
254class KeySideEffect : public Transform, public ResolutionContext {
255 protected:
256 MinimalNameGenerator nameGen;
257 TypeMap *typeMap;
258 std::map<const IR::P4Table *, TableInsertions *> toInsert;
259 std::set<const IR::P4Table *> *invokedInKey;
260
261 public:
262 KeySideEffect(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
263 : typeMap(typeMap), invokedInKey(invokedInKey) {
264 CHECK_NULL(typeMap);
265 CHECK_NULL(invokedInKey);
266 setName("KeySideEffect");
267 }
268
269 profile_t init_apply(const IR::Node *node) override;
270
271 virtual const IR::Node *doStatement(const IR::Statement *statement,
272 const IR::Expression *expression,
273 const Visitor::Context *ctxt);
274
275 const IR::Node *preorder(IR::Key *key) override;
276
277 // These should be all kinds of statements that may contain a table apply
278 // after the program has been simplified
279 const IR::Node *postorder(IR::MethodCallStatement *statement) override {
280 return doStatement(statement, statement->methodCall, getContext());
281 }
282 const IR::Node *postorder(IR::IfStatement *statement) override {
283 return doStatement(statement, statement->condition, getContext());
284 }
285 const IR::Node *postorder(IR::SwitchStatement *statement) override {
286 return doStatement(statement, statement->expression, getContext());
287 }
288 const IR::Node *postorder(IR::BaseAssignmentStatement *statement) override {
289 return doStatement(statement, statement->right, getContext());
290 }
291 const IR::Node *postorder(IR::KeyElement *element) override;
292 const IR::Node *postorder(IR::P4Table *table) override;
293 const IR::Node *preorder(IR::P4Table *table) override;
294};
295
301class TablesInKeys : public Inspector {
302 TypeMap *typeMap;
303 std::set<const IR::P4Table *> *invokedInKey;
304
305 public:
306 TablesInKeys(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
307 : typeMap(typeMap), invokedInKey(invokedInKey) {
308 CHECK_NULL(invokedInKey);
309 setName("TableInKeys");
310 }
311 Visitor::profile_t init_apply(const IR::Node *node) override {
312 invokedInKey->clear();
313 return Inspector::init_apply(node);
314 }
315 void postorder(const IR::MethodCallExpression *mce) override {
316 if (!isInContext<IR::Key>()) return;
317 HasTableApply hta(typeMap);
318 hta.setCalledBy(this);
319 (void)mce->apply(hta, getContext());
320 if (hta.table != nullptr) {
321 LOG2("Table " << hta.table << " invoked in key of another table");
322 invokedInKey->emplace(hta.table);
323 }
324 }
325};
326
332class TablesInActions : public Inspector {
333 TypeMap *typeMap;
334
335 public:
336 explicit TablesInActions(TypeMap *typeMap) : typeMap(typeMap) {}
337 void postorder(const IR::MethodCallExpression *expression) override {
338 if (isInContext<IR::ActionList>()) {
339 HasTableApply hta(typeMap);
340 hta.setCalledBy(this);
341 (void)expression->apply(hta, getContext());
342 if (hta.table != nullptr) {
343 ::P4::error(ErrorType::ERR_UNSUPPORTED, "%1%: table invocation in action argument",
344 expression);
345 }
346 }
347 }
348};
349
350class SideEffectOrdering : public PassRepeated {
351 // Contains all tables that are invoked within key
352 // computations for other tables. The keys for these
353 // inner tables cannot be expanded until the keys of
354 // the caller tables have been expanded.
355 std::set<const IR::P4Table *> invokedInKey;
356 // Temporaries that were added
357 std::set<const IR::Expression *> added;
358
359 public:
360 SideEffectOrdering(TypeMap *typeMap, bool skipSideEffectOrdering,
361 TypeChecking *typeChecking = nullptr) {
362 if (!typeChecking) typeChecking = new TypeChecking(nullptr, typeMap);
363 if (!skipSideEffectOrdering) {
364 passes.push_back(new TypeChecking(nullptr, typeMap));
365 passes.push_back(new DoSimplifyExpressions(typeMap, &added));
366 passes.push_back(new ClearTypeMap(typeMap));
367 passes.push_back(typeChecking);
368 passes.push_back(new TablesInActions(typeMap));
369 passes.push_back(new TablesInKeys(typeMap, &invokedInKey));
370 passes.push_back(new KeySideEffect(typeMap, &invokedInKey));
371 }
372 setName("SideEffectOrdering");
373 }
374};
375
376} // namespace P4
377
378#endif /* FRONTENDS_P4_SIDEEFFECTS_H_ */
Definition methodInstance.h:120
Definition methodInstance.h:251
Definition typeChecker.h:23
Definition referenceMap.h:48
Convert expressions so that each expression contains at most one side effect.
Definition sideEffects.h:138
Definition methodInstance.h:140
Definition methodInstance.h:223
Checks to see whether an IR node includes a table.apply() sub-expression.
Definition sideEffects.h:22
Definition indexed_vector.h:31
Definition node.h:44
Definition visitor.h:409
Definition sideEffects.h:254
static MethodInstance * resolve(const IR::MethodCallExpression *mce, const DeclarationLookup *refMap, TypeMap *typeMap, bool useExpressionType=false, const Visitor::Context *ctxt=nullptr, bool incomplete=false)
Definition methodInstance.cpp:16
Definition referenceMap.h:27
Definition visitor.h:802
static bool mayHaveSideEffect(const IR::MethodCallExpression *mce, DeclarationLookup *refMap, TypeMap *typeMap)
Definition sideEffects.h:90
unsigned sideEffectCount
Number of side effects in this expression.
Definition sideEffects.h:62
static bool check(const IR::Expression *expression, const Visitor *calledBy, TypeMap *typeMap=nullptr, const Visitor::Context *ctxt=nullptr)
Definition sideEffects.h:81
const IR::Node * nodeWithSideEffect
Last visited side-effecting node. Null if no node has side effects.
Definition sideEffects.h:59
SideEffects(TypeMap *typeMap)
Definition sideEffects.h:78
Definition sideEffects.h:332
Definition sideEffects.h:301
Definition visitor.h:433
Definition typeChecker.h:46
Definition typeMap.h:32
Definition source_file.h:123
Definition visitor.h:69
Definition visitor.h:66
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:48
Definition sideEffects.h:210
Definition id.h:19