P4C
The P4 Compiler
All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages
sideEffects.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 FRONTENDS_P4_SIDEEFFECTS_H_
18#define FRONTENDS_P4_SIDEEFFECTS_H_
19
20/* makes explicit side effect ordering */
21
22#include "frontends/common/resolveReferences/referenceMap.h"
23#include "frontends/common/resolveReferences/resolveReferences.h"
24#include "frontends/p4/methodInstance.h"
25#include "frontends/p4/typeChecking/typeChecker.h"
26#include "ir/ir.h"
27
28namespace P4 {
29
31class HasTableApply : public Inspector, public ResolutionContext {
32 TypeMap *typeMap;
33
34 public:
35 const IR::P4Table *table;
36 const IR::MethodCallExpression *call;
37 explicit HasTableApply(TypeMap *typeMap) : typeMap(typeMap), table(nullptr), call(nullptr) {
38 CHECK_NULL(typeMap);
39 setName("HasTableApply");
40 }
41
42 void postorder(const IR::MethodCallExpression *expression) override {
43 auto mi = MethodInstance::resolve(expression, this, typeMap);
44 if (!mi->isApply()) return;
45 auto am = mi->to<P4::ApplyMethod>();
46 if (!am->object->is<IR::P4Table>()) return;
47 BUG_CHECK(table == nullptr, "%1% and %2%: multiple table applications in one expression",
48 table, am->object);
49 table = am->object->to<IR::P4Table>();
50 call = expression;
51 LOG3("Invoked table is " << dbp(table));
52 }
53};
54
62class SideEffects : public Inspector, public ResolutionContext {
63 private:
64 TypeMap *typeMap;
65
66 public:
68 const IR::Node *nodeWithSideEffect = nullptr;
69
71 unsigned sideEffectCount = 0;
72
73 void postorder(const IR::MethodCallExpression *mce) override {
74 auto mi = MethodInstance::resolve(mce, this, typeMap, !typeMap);
75 if (!mi) {
76 // conservative
79 return;
80 }
81 if (!mi->is<BuiltInMethod>()) {
84 return;
85 }
86 auto bim = mi->to<BuiltInMethod>();
87 if (bim->name.name != IR::Type_Header::isValid) {
90 }
91 }
92
93 void postorder(const IR::ConstructorCallExpression *cce) override {
96 }
97
100 explicit SideEffects(TypeMap *typeMap) : typeMap(typeMap) { setName("SideEffects"); }
101
103 static bool check(const IR::Expression *expression, const Visitor *calledBy,
104 TypeMap *typeMap = nullptr, const Visitor::Context *ctxt = nullptr) {
105 SideEffects se(typeMap);
106 se.setCalledBy(calledBy);
107 if (calledBy && !ctxt) ctxt = calledBy->getChildContext();
108 expression->apply(se, ctxt);
109 return se.nodeWithSideEffect != nullptr;
110 }
111
112 static bool hasSideEffect(const IR::MethodCallExpression *mce, DeclarationLookup *refMap,
113 TypeMap *typeMap) {
114 // mce does not produce a side effect in few cases:
115 // * isValid()
116 // * function, extern function, or extern method with noSideEffects annotation
117 auto mi = MethodInstance::resolve(mce, refMap, typeMap);
118 if (const auto *ec = mi->to<P4::ExternCall>())
119 return !ec->method->hasAnnotation(IR::Annotation::noSideEffectsAnnotation);
120 if (const auto *ef = mi->to<P4::FunctionCall>())
121 return !ef->function->hasAnnotation(IR::Annotation::noSideEffectsAnnotation);
122 if (const auto *bim = mi->to<BuiltInMethod>()) return bim->name != IR::Type_Header::isValid;
123 return true;
124 }
125};
126
159class DoSimplifyExpressions : public Transform, P4WriteContext, public ResolutionContext {
160 MinimalNameGenerator nameGen;
161 TypeMap *typeMap;
162 // Expressions holding temporaries that are already added.
163 std::set<const IR::Expression *> *added;
164
165 IR::IndexedVector<IR::Declaration> toInsert; // temporaries
169 std::set<const IR::Expression *> temporaries;
170
171 cstring createTemporary(const IR::Type *type);
172 const IR::Expression *addAssignment(Util::SourceInfo srcInfo, cstring varName,
173 const IR::Expression *expression);
174 bool mayAlias(const IR::Expression *left, const IR::Expression *right,
175 const Visitor::Context *ctxt) const;
176 bool containsHeaderType(const IR::Type *type);
177
178 public:
179 DoSimplifyExpressions(TypeMap *typeMap, std::set<const IR::Expression *> *added)
180 : typeMap(typeMap), added(added) {
181 CHECK_NULL(typeMap);
182 setName("DoSimplifyExpressions");
183 }
184
185 const IR::Node *postorder(IR::Expression *expression) override;
186 const IR::Node *preorder(IR::StructExpression *expression) override;
187 const IR::Node *preorder(IR::ListExpression *expression) override;
188 const IR::Node *preorder(IR::Literal *expression) override;
189 const IR::Node *preorder(IR::ArrayIndex *expression) override;
190 const IR::Node *preorder(IR::Member *expression) override;
191 const IR::Node *preorder(IR::SelectExpression *expression) override;
192 const IR::Node *preorder(IR::Operation_Unary *expression) override;
193 const IR::Node *preorder(IR::Operation_Binary *expression) override;
194 const IR::Node *shortCircuit(IR::Operation_Binary *expression);
195 const IR::Node *preorder(IR::Mux *expression) override;
196 const IR::Node *preorder(IR::LAnd *expression) override;
197 const IR::Node *preorder(IR::LOr *expression) override;
198 const IR::Node *preorder(IR::MethodCallExpression *mce) override;
199
200 const IR::Node *preorder(IR::ConstructorCallExpression *cce) override {
201 prune();
202 return cce;
203 }
204 const IR::Node *preorder(IR::Property *prop) override {
205 prune();
206 return prop;
207 }
208 const IR::Node *preorder(IR::Annotation *anno) override {
209 prune();
210 return anno;
211 }
212
213 const IR::Node *postorder(IR::P4Parser *parser) override;
214 const IR::Node *postorder(IR::Function *function) override;
215 const IR::Node *postorder(IR::P4Control *control) override;
216 const IR::Node *postorder(IR::P4Action *action) override;
217 const IR::Node *postorder(IR::ParserState *state) override;
218 const IR::Node *postorder(IR::BaseAssignmentStatement *statement) override;
219 const IR::Node *postorder(IR::MethodCallStatement *statement) override;
220 const IR::Node *postorder(IR::ReturnStatement *statement) override;
221 const IR::Node *preorder(IR::SwitchStatement *statement) override;
222 const IR::Node *preorder(IR::IfStatement *statement) override;
223 const IR::Node *preorder(IR::ForStatement *statement) override;
224 const IR::Node *preorder(IR::ForInStatement *statement) override;
225
226 profile_t init_apply(const IR::Node *node) override;
227 void end_apply(const IR::Node *) override;
228};
229
231 public:
232 std::vector<const IR::Declaration_Variable *> declarations;
233 std::vector<const IR::BaseAssignmentStatement *> statements;
234};
235
274class KeySideEffect : public Transform, public ResolutionContext {
275 protected:
276 MinimalNameGenerator nameGen;
277 TypeMap *typeMap;
278 std::map<const IR::P4Table *, TableInsertions *> toInsert;
279 std::set<const IR::P4Table *> *invokedInKey;
280
281 public:
282 KeySideEffect(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
283 : typeMap(typeMap), invokedInKey(invokedInKey) {
284 CHECK_NULL(typeMap);
285 CHECK_NULL(invokedInKey);
286 setName("KeySideEffect");
287 }
288
289 profile_t init_apply(const IR::Node *node) override;
290
291 virtual const IR::Node *doStatement(const IR::Statement *statement,
292 const IR::Expression *expression,
293 const Visitor::Context *ctxt);
294
295 const IR::Node *preorder(IR::Key *key) override;
296
297 // These should be all kinds of statements that may contain a table apply
298 // after the program has been simplified
299 const IR::Node *postorder(IR::MethodCallStatement *statement) override {
300 return doStatement(statement, statement->methodCall, getContext());
301 }
302 const IR::Node *postorder(IR::IfStatement *statement) override {
303 return doStatement(statement, statement->condition, getContext());
304 }
305 const IR::Node *postorder(IR::SwitchStatement *statement) override {
306 return doStatement(statement, statement->expression, getContext());
307 }
308 const IR::Node *postorder(IR::BaseAssignmentStatement *statement) override {
309 return doStatement(statement, statement->right, getContext());
310 }
311 const IR::Node *postorder(IR::KeyElement *element) override;
312 const IR::Node *postorder(IR::P4Table *table) override;
313 const IR::Node *preorder(IR::P4Table *table) override;
314};
315
321class TablesInKeys : public Inspector {
322 TypeMap *typeMap;
323 std::set<const IR::P4Table *> *invokedInKey;
324
325 public:
326 TablesInKeys(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
327 : typeMap(typeMap), invokedInKey(invokedInKey) {
328 CHECK_NULL(invokedInKey);
329 setName("TableInKeys");
330 }
331 Visitor::profile_t init_apply(const IR::Node *node) override {
332 invokedInKey->clear();
333 return Inspector::init_apply(node);
334 }
335 void postorder(const IR::MethodCallExpression *mce) override {
336 if (!isInContext<IR::Key>()) return;
337 HasTableApply hta(typeMap);
338 hta.setCalledBy(this);
339 (void)mce->apply(hta, getContext());
340 if (hta.table != nullptr) {
341 LOG2("Table " << hta.table << " invoked in key of another table");
342 invokedInKey->emplace(hta.table);
343 }
344 }
345};
346
352class TablesInActions : public Inspector {
353 TypeMap *typeMap;
354
355 public:
356 explicit TablesInActions(TypeMap *typeMap) : typeMap(typeMap) {}
357 void postorder(const IR::MethodCallExpression *expression) override {
358 if (isInContext<IR::ActionList>()) {
359 HasTableApply hta(typeMap);
360 hta.setCalledBy(this);
361 (void)expression->apply(hta, getContext());
362 if (hta.table != nullptr) {
363 ::P4::error(ErrorType::ERR_UNSUPPORTED, "%1%: table invocation in action argument",
364 expression);
365 }
366 }
367 }
368};
369
370class SideEffectOrdering : public PassRepeated {
371 // Contains all tables that are invoked within key
372 // computations for other tables. The keys for these
373 // inner tables cannot be expanded until the keys of
374 // the caller tables have been expanded.
375 std::set<const IR::P4Table *> invokedInKey;
376 // Temporaries that were added
377 std::set<const IR::Expression *> added;
378
379 public:
380 SideEffectOrdering(TypeMap *typeMap, bool skipSideEffectOrdering,
381 TypeChecking *typeChecking = nullptr) {
382 if (!typeChecking) typeChecking = new TypeChecking(nullptr, typeMap);
383 if (!skipSideEffectOrdering) {
384 passes.push_back(new TypeChecking(nullptr, typeMap));
385 passes.push_back(new DoSimplifyExpressions(typeMap, &added));
386 passes.push_back(typeChecking);
387 passes.push_back(new TablesInActions(typeMap));
388 passes.push_back(new TablesInKeys(typeMap, &invokedInKey));
389 passes.push_back(new KeySideEffect(typeMap, &invokedInKey));
390 }
391 setName("SideEffectOrdering");
392 }
393};
394
395} // namespace P4
396
397#endif /* FRONTENDS_P4_SIDEEFFECTS_H_ */
Definition methodInstance.h:129
Definition methodInstance.h:260
Definition referenceMap.h:57
Convert expressions so that each expression contains at most one side effect.
Definition sideEffects.h:159
Definition methodInstance.h:149
Definition methodInstance.h:232
Checks to see whether an IR node includes a table.apply() sub-expression.
Definition sideEffects.h:31
Definition indexed_vector.h:40
Definition node.h:94
Definition visitor.h:413
Definition sideEffects.h:274
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:27
Definition referenceMap.h:36
Definition visitor.h:801
unsigned sideEffectCount
Number of side effects in this expression.
Definition sideEffects.h:71
static bool check(const IR::Expression *expression, const Visitor *calledBy, TypeMap *typeMap=nullptr, const Visitor::Context *ctxt=nullptr)
Definition sideEffects.h:103
const IR::Node * nodeWithSideEffect
Last visited side-effecting node. Null if no node has side effects.
Definition sideEffects.h:68
SideEffects(TypeMap *typeMap)
Definition sideEffects.h:100
static bool hasSideEffect(const IR::MethodCallExpression *mce, DeclarationLookup *refMap, TypeMap *typeMap)
Definition sideEffects.h:112
Definition sideEffects.h:352
Definition sideEffects.h:321
Definition visitor.h:437
Definition typeChecker.h:55
Definition typeMap.h:41
Definition source_file.h:132
Definition visitor.h:78
Definition visitor.h:75
Definition cstring.h:85
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition sideEffects.h:230