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
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 {
63 private:
64 DeclarationLookup *refMap;
65 TypeMap *typeMap;
66
67 public:
69 const IR::Node *nodeWithSideEffect = nullptr;
70
72 unsigned sideEffectCount = 0;
73
74 void postorder(const IR::MethodCallExpression *mce) override {
75 if (refMap == nullptr || typeMap == nullptr) {
76 // conservative
79 return;
80 }
81 auto mi = MethodInstance::resolve(mce, refMap, typeMap);
82 if (!mi->is<BuiltInMethod>()) {
85 return;
86 }
87 auto bim = mi->to<BuiltInMethod>();
88 if (bim->name.name != IR::Type_Header::isValid) {
91 }
92 }
93
94 void postorder(const IR::ConstructorCallExpression *cce) override {
97 }
98
101 SideEffects(DeclarationLookup *refMap, TypeMap *typeMap) : refMap(refMap), typeMap(typeMap) {
102 setName("SideEffects");
103 }
104
106 static bool check(const IR::Expression *expression, const Visitor *calledBy,
107 DeclarationLookup *refMap, TypeMap *typeMap,
108 const Visitor::Context *ctxt = nullptr) {
109 SideEffects se(refMap, typeMap);
110 se.setCalledBy(calledBy);
111 expression->apply(se, ctxt);
112 return se.nodeWithSideEffect != nullptr;
113 }
115 static bool hasSideEffect(const IR::MethodCallExpression *mce, DeclarationLookup *refMap,
116 TypeMap *typeMap) {
117 // mce does not produce a side effect in few cases:
118 // * isValid()
119 // * function, extern function, or extern method with noSideEffects annotation
120 auto mi = MethodInstance::resolve(mce, refMap, typeMap);
121 if (auto em = mi->to<P4::ExternMethod>()) {
122 if (em->method->getAnnotation(IR::Annotation::noSideEffectsAnnotation)) {
123 return false;
124 }
125 return true;
126 }
127 if (auto ef = mi->to<P4::ExternFunction>()) {
128 if (ef->method->getAnnotation(IR::Annotation::noSideEffectsAnnotation)) {
129 return false;
130 }
131 return true;
132 }
133 if (auto ef = mi->to<P4::FunctionCall>()) {
134 if (ef->function->getAnnotation(IR::Annotation::noSideEffectsAnnotation)) {
135 return false;
136 }
137 return true;
138 }
139 if (auto bim = mi->to<BuiltInMethod>()) {
140 if (bim->name.name == IR::Type_Header::isValid) {
141 return false;
142 }
143 }
144 return true;
145 }
146};
147
181 MinimalNameGenerator nameGen;
182 TypeMap *typeMap;
183 // Expressions holding temporaries that are already added.
184 std::set<const IR::Expression *> *added;
185
186 IR::IndexedVector<IR::Declaration> toInsert; // temporaries
190 std::set<const IR::Expression *> temporaries;
191
192 cstring createTemporary(const IR::Type *type);
193 const IR::Expression *addAssignment(Util::SourceInfo srcInfo, cstring varName,
194 const IR::Expression *expression);
195 bool mayAlias(const IR::Expression *left, const IR::Expression *right,
196 const Visitor::Context *ctxt) const;
197 bool containsHeaderType(const IR::Type *type);
198
199 public:
200 DoSimplifyExpressions(TypeMap *typeMap, std::set<const IR::Expression *> *added)
201 : typeMap(typeMap), added(added) {
202 CHECK_NULL(typeMap);
203 setName("DoSimplifyExpressions");
204 }
205
206 const IR::Node *postorder(IR::Expression *expression) override;
207 const IR::Node *preorder(IR::StructExpression *expression) override;
208 const IR::Node *preorder(IR::ListExpression *expression) override;
209 const IR::Node *preorder(IR::Literal *expression) override;
210 const IR::Node *preorder(IR::ArrayIndex *expression) override;
211 const IR::Node *preorder(IR::Member *expression) override;
212 const IR::Node *preorder(IR::SelectExpression *expression) override;
213 const IR::Node *preorder(IR::Operation_Unary *expression) override;
214 const IR::Node *preorder(IR::Operation_Binary *expression) override;
215 const IR::Node *shortCircuit(IR::Operation_Binary *expression);
216 const IR::Node *preorder(IR::Mux *expression) override;
217 const IR::Node *preorder(IR::LAnd *expression) override;
218 const IR::Node *preorder(IR::LOr *expression) override;
219 const IR::Node *preorder(IR::MethodCallExpression *mce) override;
220
221 const IR::Node *preorder(IR::ConstructorCallExpression *cce) override {
222 prune();
223 return cce;
224 }
225 const IR::Node *preorder(IR::Property *prop) override {
226 prune();
227 return prop;
228 }
229 const IR::Node *preorder(IR::Annotation *anno) override {
230 prune();
231 return anno;
232 }
233
234 const IR::Node *postorder(IR::P4Parser *parser) override;
235 const IR::Node *postorder(IR::Function *function) override;
236 const IR::Node *postorder(IR::P4Control *control) override;
237 const IR::Node *postorder(IR::P4Action *action) override;
238 const IR::Node *postorder(IR::ParserState *state) override;
239 const IR::Node *postorder(IR::AssignmentStatement *statement) override;
240 const IR::Node *postorder(IR::MethodCallStatement *statement) override;
241 const IR::Node *postorder(IR::ReturnStatement *statement) override;
242 const IR::Node *preorder(IR::SwitchStatement *statement) override;
243 const IR::Node *preorder(IR::IfStatement *statement) override;
244 const IR::Node *preorder(IR::ForStatement *statement) override;
245 const IR::Node *preorder(IR::ForInStatement *statement) override;
246
247 profile_t init_apply(const IR::Node *node) override;
248 void end_apply(const IR::Node *) override;
249};
250
252 public:
253 std::vector<const IR::Declaration_Variable *> declarations;
254 std::vector<const IR::AssignmentStatement *> statements;
255};
256
296 protected:
297 MinimalNameGenerator nameGen;
298 TypeMap *typeMap;
299 std::map<const IR::P4Table *, TableInsertions *> toInsert;
300 std::set<const IR::P4Table *> *invokedInKey;
301
302 public:
303 KeySideEffect(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
304 : typeMap(typeMap), invokedInKey(invokedInKey) {
305 CHECK_NULL(typeMap);
306 CHECK_NULL(invokedInKey);
307 setName("KeySideEffect");
308 }
309
310 profile_t init_apply(const IR::Node *node) override;
311
312 virtual const IR::Node *doStatement(const IR::Statement *statement,
313 const IR::Expression *expression,
314 const Visitor::Context *ctxt);
315
316 const IR::Node *preorder(IR::Key *key) override;
317
318 // These should be all kinds of statements that may contain a table apply
319 // after the program has been simplified
320 const IR::Node *postorder(IR::MethodCallStatement *statement) override {
321 return doStatement(statement, statement->methodCall, getContext());
322 }
323 const IR::Node *postorder(IR::IfStatement *statement) override {
324 return doStatement(statement, statement->condition, getContext());
325 }
326 const IR::Node *postorder(IR::SwitchStatement *statement) override {
327 return doStatement(statement, statement->expression, getContext());
328 }
329 const IR::Node *postorder(IR::AssignmentStatement *statement) override {
330 return doStatement(statement, statement->right, getContext());
331 }
332 const IR::Node *postorder(IR::KeyElement *element) override;
333 const IR::Node *postorder(IR::P4Table *table) override;
334 const IR::Node *preorder(IR::P4Table *table) override;
335};
336
342class TablesInKeys : public Inspector {
343 TypeMap *typeMap;
344 std::set<const IR::P4Table *> *invokedInKey;
345
346 public:
347 TablesInKeys(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
348 : typeMap(typeMap), invokedInKey(invokedInKey) {
349 CHECK_NULL(invokedInKey);
350 setName("TableInKeys");
351 }
352 Visitor::profile_t init_apply(const IR::Node *node) override {
353 invokedInKey->clear();
354 return Inspector::init_apply(node);
355 }
356 void postorder(const IR::MethodCallExpression *mce) override {
357 if (!findContext<IR::Key>()) return;
358 HasTableApply hta(typeMap);
359 hta.setCalledBy(this);
360 (void)mce->apply(hta, getContext());
361 if (hta.table != nullptr) {
362 LOG2("Table " << hta.table << " invoked in key of another table");
363 invokedInKey->emplace(hta.table);
364 }
365 }
366};
367
374 TypeMap *typeMap;
375
376 public:
377 explicit TablesInActions(TypeMap *typeMap) : typeMap(typeMap) {}
378 void postorder(const IR::MethodCallExpression *expression) override {
379 if (findContext<IR::ActionList>()) {
380 HasTableApply hta(typeMap);
381 hta.setCalledBy(this);
382 (void)expression->apply(hta, getContext());
383 if (hta.table != nullptr) {
384 ::P4::error(ErrorType::ERR_UNSUPPORTED, "%1%: table invocation in action argument",
385 expression);
386 }
387 }
388 }
389};
390
392 // Contains all tables that are invoked within key
393 // computations for other tables. The keys for these
394 // inner tables cannot be expanded until the keys of
395 // the caller tables have been expanded.
396 std::set<const IR::P4Table *> invokedInKey;
397 // Temporaries that were added
398 std::set<const IR::Expression *> added;
399
400 public:
401 SideEffectOrdering(TypeMap *typeMap, bool skipSideEffectOrdering,
402 TypeChecking *typeChecking = nullptr) {
403 if (!typeChecking) typeChecking = new TypeChecking(nullptr, typeMap);
404 if (!skipSideEffectOrdering) {
405 passes.push_back(new TypeChecking(nullptr, typeMap));
406 passes.push_back(new DoSimplifyExpressions(typeMap, &added));
407 passes.push_back(typeChecking);
408 passes.push_back(new TablesInActions(typeMap));
409 passes.push_back(new TablesInKeys(typeMap, &invokedInKey));
410 passes.push_back(new KeySideEffect(typeMap, &invokedInKey));
411 }
412 setName("SideEffectOrdering");
413 }
414};
415
416} // namespace P4
417
418#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:180
Definition methodInstance.h:194
Definition methodInstance.h:168
Definition methodInstance.h:232
Checks to see whether an IR node includes a table.apply() sub-expression.
Definition sideEffects.h:31
Definition node.h:52
Definition node.h:95
Definition visitor.h:400
Definition sideEffects.h:295
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:788
Definition ir/pass_manager.h:145
Visitor mixin for looking up names in enclosing scopes from the Visitor::Context.
Definition resolveReferences.h:35
Definition sideEffects.h:391
Determines whether an expression may have method or constructor invocations.
Definition sideEffects.h:62
unsigned sideEffectCount
Number of side effects in this expression.
Definition sideEffects.h:72
SideEffects(DeclarationLookup *refMap, TypeMap *typeMap)
Definition sideEffects.h:101
const IR::Node * nodeWithSideEffect
Last visited side-effecting node. Null if no node has side effects.
Definition sideEffects.h:69
static bool hasSideEffect(const IR::MethodCallExpression *mce, DeclarationLookup *refMap, TypeMap *typeMap)
Definition sideEffects.h:115
static bool check(const IR::Expression *expression, const Visitor *calledBy, DeclarationLookup *refMap, TypeMap *typeMap, const Visitor::Context *ctxt=nullptr)
Definition sideEffects.h:106
Definition sideEffects.h:373
Definition sideEffects.h:342
Definition visitor.h:424
Definition typeChecker.h:55
Definition typeMap.h:41
Definition source_file.h:125
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:51
Definition sideEffects.h:251
Definition visitor.h:47