P4C
The P4 Compiler
Loading...
Searching...
No Matches
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 if (mayHaveSideEffect(mce, this, typeMap)) {
77 }
78 }
79
80 void postorder(const IR::ConstructorCallExpression *cce) override {
83 }
84
87 explicit SideEffects(TypeMap *typeMap) : typeMap(typeMap) { setName("SideEffects"); }
88
90 static bool check(const IR::Expression *expression, const Visitor *calledBy,
91 TypeMap *typeMap = nullptr, const Visitor::Context *ctxt = nullptr) {
92 SideEffects se(typeMap);
93 se.setCalledBy(calledBy);
94 if (calledBy && !ctxt) ctxt = calledBy->getChildContext();
95 expression->apply(se, ctxt);
96 return se.nodeWithSideEffect != nullptr;
97 }
98
99 static bool mayHaveSideEffect(const IR::MethodCallExpression *mce, DeclarationLookup *refMap,
100 TypeMap *typeMap) {
101 // mce does not produce a side effect in few cases:
102 // * isValid()
103 // * function, extern function, or extern method with noSideEffects annotation
104 auto mi = MethodInstance::resolve(mce, refMap, typeMap, !typeMap);
105 if (!mi) return true;
106 if (const auto *ec = mi->to<P4::ExternCall>())
107 return !ec->method->hasAnnotation(IR::Annotation::noSideEffectsAnnotation);
108 if (const auto *ef = mi->to<P4::FunctionCall>())
109 return !ef->function->hasAnnotation(IR::Annotation::noSideEffectsAnnotation);
110 if (const auto *bim = mi->to<BuiltInMethod>()) return bim->name != IR::Type_Header::isValid;
111 return true;
112 }
113};
114
147class DoSimplifyExpressions : public Transform, P4WriteContext, public ResolutionContext {
148 MinimalNameGenerator nameGen;
149 TypeMap *typeMap;
150 // Expressions holding temporaries that are already added.
151 std::set<const IR::Expression *> *added;
152
153 IR::IndexedVector<IR::Declaration> toInsert; // temporaries
157 std::set<const IR::Expression *> temporaries;
158
159 cstring createTemporary(const IR::Type *type);
160 const IR::Expression *addAssignment(Util::SourceInfo srcInfo, cstring varName,
161 const IR::Expression *expression);
162 bool mayAlias(const IR::Expression *left, const IR::Expression *right,
163 const Visitor::Context *ctxt) const;
164 bool containsHeaderType(const IR::Type *type);
165
166 public:
167 DoSimplifyExpressions(TypeMap *typeMap, std::set<const IR::Expression *> *added)
168 : typeMap(typeMap), added(added) {
169 CHECK_NULL(typeMap);
170 setName("DoSimplifyExpressions");
171 }
172
173 const IR::Node *postorder(IR::Expression *expression) override;
174 const IR::Node *preorder(IR::StructExpression *expression) override;
175 const IR::Node *preorder(IR::ListExpression *expression) override;
176 const IR::Node *preorder(IR::Literal *expression) override;
177 const IR::Node *preorder(IR::ArrayIndex *expression) override;
178 const IR::Node *preorder(IR::Member *expression) override;
179 const IR::Node *preorder(IR::SelectExpression *expression) override;
180 const IR::Node *preorder(IR::Operation_Unary *expression) override;
181 const IR::Node *preorder(IR::Operation_Binary *expression) override;
182 const IR::Node *shortCircuit(IR::Operation_Binary *expression);
183 const IR::Node *preorder(IR::Mux *expression) override;
184 const IR::Node *preorder(IR::LAnd *expression) override;
185 const IR::Node *preorder(IR::LOr *expression) override;
186 const IR::Node *preorder(IR::MethodCallExpression *mce) override;
187
188 const IR::Node *preorder(IR::ConstructorCallExpression *cce) override {
189 prune();
190 return cce;
191 }
192 const IR::Node *preorder(IR::Property *prop) override {
193 prune();
194 return prop;
195 }
196 const IR::Node *preorder(IR::Annotation *anno) override {
197 prune();
198 return anno;
199 }
200
201 const IR::Node *postorder(IR::P4Parser *parser) override;
202 const IR::Node *postorder(IR::Function *function) override;
203 const IR::Node *postorder(IR::P4Control *control) override;
204 const IR::Node *postorder(IR::P4Action *action) override;
205 const IR::Node *postorder(IR::ParserState *state) override;
206 const IR::Node *postorder(IR::BaseAssignmentStatement *statement) override;
207 const IR::Node *postorder(IR::MethodCallStatement *statement) override;
208 const IR::Node *postorder(IR::ReturnStatement *statement) override;
209 const IR::Node *preorder(IR::SwitchStatement *statement) override;
210 const IR::Node *preorder(IR::IfStatement *statement) override;
211 const IR::Node *preorder(IR::ForStatement *statement) override;
212 const IR::Node *preorder(IR::ForInStatement *statement) override;
213
214 profile_t init_apply(const IR::Node *node) override;
215 void end_apply(const IR::Node *) override;
216};
217
219 public:
220 std::vector<const IR::Declaration_Variable *> declarations;
221 std::vector<const IR::BaseAssignmentStatement *> statements;
222};
223
262class KeySideEffect : public Transform, public ResolutionContext {
263 protected:
264 MinimalNameGenerator nameGen;
265 TypeMap *typeMap;
266 std::map<const IR::P4Table *, TableInsertions *> toInsert;
267 std::set<const IR::P4Table *> *invokedInKey;
268
269 public:
270 KeySideEffect(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
271 : typeMap(typeMap), invokedInKey(invokedInKey) {
272 CHECK_NULL(typeMap);
273 CHECK_NULL(invokedInKey);
274 setName("KeySideEffect");
275 }
276
277 profile_t init_apply(const IR::Node *node) override;
278
279 virtual const IR::Node *doStatement(const IR::Statement *statement,
280 const IR::Expression *expression,
281 const Visitor::Context *ctxt);
282
283 const IR::Node *preorder(IR::Key *key) override;
284
285 // These should be all kinds of statements that may contain a table apply
286 // after the program has been simplified
287 const IR::Node *postorder(IR::MethodCallStatement *statement) override {
288 return doStatement(statement, statement->methodCall, getContext());
289 }
290 const IR::Node *postorder(IR::IfStatement *statement) override {
291 return doStatement(statement, statement->condition, getContext());
292 }
293 const IR::Node *postorder(IR::SwitchStatement *statement) override {
294 return doStatement(statement, statement->expression, getContext());
295 }
296 const IR::Node *postorder(IR::BaseAssignmentStatement *statement) override {
297 return doStatement(statement, statement->right, getContext());
298 }
299 const IR::Node *postorder(IR::KeyElement *element) override;
300 const IR::Node *postorder(IR::P4Table *table) override;
301 const IR::Node *preorder(IR::P4Table *table) override;
302};
303
309class TablesInKeys : public Inspector {
310 TypeMap *typeMap;
311 std::set<const IR::P4Table *> *invokedInKey;
312
313 public:
314 TablesInKeys(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
315 : typeMap(typeMap), invokedInKey(invokedInKey) {
316 CHECK_NULL(invokedInKey);
317 setName("TableInKeys");
318 }
319 Visitor::profile_t init_apply(const IR::Node *node) override {
320 invokedInKey->clear();
321 return Inspector::init_apply(node);
322 }
323 void postorder(const IR::MethodCallExpression *mce) override {
324 if (!isInContext<IR::Key>()) return;
325 HasTableApply hta(typeMap);
326 hta.setCalledBy(this);
327 (void)mce->apply(hta, getContext());
328 if (hta.table != nullptr) {
329 LOG2("Table " << hta.table << " invoked in key of another table");
330 invokedInKey->emplace(hta.table);
331 }
332 }
333};
334
340class TablesInActions : public Inspector {
341 TypeMap *typeMap;
342
343 public:
344 explicit TablesInActions(TypeMap *typeMap) : typeMap(typeMap) {}
345 void postorder(const IR::MethodCallExpression *expression) override {
346 if (isInContext<IR::ActionList>()) {
347 HasTableApply hta(typeMap);
348 hta.setCalledBy(this);
349 (void)expression->apply(hta, getContext());
350 if (hta.table != nullptr) {
351 ::P4::error(ErrorType::ERR_UNSUPPORTED, "%1%: table invocation in action argument",
352 expression);
353 }
354 }
355 }
356};
357
358class SideEffectOrdering : public PassRepeated {
359 // Contains all tables that are invoked within key
360 // computations for other tables. The keys for these
361 // inner tables cannot be expanded until the keys of
362 // the caller tables have been expanded.
363 std::set<const IR::P4Table *> invokedInKey;
364 // Temporaries that were added
365 std::set<const IR::Expression *> added;
366
367 public:
368 SideEffectOrdering(TypeMap *typeMap, bool skipSideEffectOrdering,
369 TypeChecking *typeChecking = nullptr) {
370 if (!typeChecking) typeChecking = new TypeChecking(nullptr, typeMap);
371 if (!skipSideEffectOrdering) {
372 passes.push_back(new TypeChecking(nullptr, typeMap));
373 passes.push_back(new DoSimplifyExpressions(typeMap, &added));
374 passes.push_back(typeChecking);
375 passes.push_back(new TablesInActions(typeMap));
376 passes.push_back(new TablesInKeys(typeMap, &invokedInKey));
377 passes.push_back(new KeySideEffect(typeMap, &invokedInKey));
378 }
379 setName("SideEffectOrdering");
380 }
381};
382
383} // namespace P4
384
385#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:147
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:262
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
static bool mayHaveSideEffect(const IR::MethodCallExpression *mce, DeclarationLookup *refMap, TypeMap *typeMap)
Definition sideEffects.h:99
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:90
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:87
Definition sideEffects.h:340
Definition sideEffects.h:309
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:218