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 (const auto *ec = mi->to<P4::ExternCall>())
122 return !ec->method->hasAnnotation(IR::Annotation::noSideEffectsAnnotation);
123 if (const auto *ef = mi->to<P4::FunctionCall>())
124 return !ef->function->hasAnnotation(IR::Annotation::noSideEffectsAnnotation);
125 if (const auto *bim = mi->to<BuiltInMethod>()) return bim->name != IR::Type_Header::isValid;
126 return true;
127 }
128};
129
163 MinimalNameGenerator nameGen;
164 TypeMap *typeMap;
165 // Expressions holding temporaries that are already added.
166 std::set<const IR::Expression *> *added;
167
168 IR::IndexedVector<IR::Declaration> toInsert; // temporaries
172 std::set<const IR::Expression *> temporaries;
173
174 cstring createTemporary(const IR::Type *type);
175 const IR::Expression *addAssignment(Util::SourceInfo srcInfo, cstring varName,
176 const IR::Expression *expression);
177 bool mayAlias(const IR::Expression *left, const IR::Expression *right,
178 const Visitor::Context *ctxt) const;
179 bool containsHeaderType(const IR::Type *type);
180
181 public:
182 DoSimplifyExpressions(TypeMap *typeMap, std::set<const IR::Expression *> *added)
183 : typeMap(typeMap), added(added) {
184 CHECK_NULL(typeMap);
185 setName("DoSimplifyExpressions");
186 }
187
188 const IR::Node *postorder(IR::Expression *expression) override;
189 const IR::Node *preorder(IR::StructExpression *expression) override;
190 const IR::Node *preorder(IR::ListExpression *expression) override;
191 const IR::Node *preorder(IR::Literal *expression) override;
192 const IR::Node *preorder(IR::ArrayIndex *expression) override;
193 const IR::Node *preorder(IR::Member *expression) override;
194 const IR::Node *preorder(IR::SelectExpression *expression) override;
195 const IR::Node *preorder(IR::Operation_Unary *expression) override;
196 const IR::Node *preorder(IR::Operation_Binary *expression) override;
197 const IR::Node *shortCircuit(IR::Operation_Binary *expression);
198 const IR::Node *preorder(IR::Mux *expression) override;
199 const IR::Node *preorder(IR::LAnd *expression) override;
200 const IR::Node *preorder(IR::LOr *expression) override;
201 const IR::Node *preorder(IR::MethodCallExpression *mce) override;
202
203 const IR::Node *preorder(IR::ConstructorCallExpression *cce) override {
204 prune();
205 return cce;
206 }
207 const IR::Node *preorder(IR::Property *prop) override {
208 prune();
209 return prop;
210 }
211 const IR::Node *preorder(IR::Annotation *anno) override {
212 prune();
213 return anno;
214 }
215
216 const IR::Node *postorder(IR::P4Parser *parser) override;
217 const IR::Node *postorder(IR::Function *function) override;
218 const IR::Node *postorder(IR::P4Control *control) override;
219 const IR::Node *postorder(IR::P4Action *action) override;
220 const IR::Node *postorder(IR::ParserState *state) override;
221 const IR::Node *postorder(IR::AssignmentStatement *statement) override;
222 const IR::Node *postorder(IR::MethodCallStatement *statement) override;
223 const IR::Node *postorder(IR::ReturnStatement *statement) override;
224 const IR::Node *preorder(IR::SwitchStatement *statement) override;
225 const IR::Node *preorder(IR::IfStatement *statement) override;
226 const IR::Node *preorder(IR::ForStatement *statement) override;
227 const IR::Node *preorder(IR::ForInStatement *statement) override;
228
229 profile_t init_apply(const IR::Node *node) override;
230 void end_apply(const IR::Node *) override;
231};
232
234 public:
235 std::vector<const IR::Declaration_Variable *> declarations;
236 std::vector<const IR::AssignmentStatement *> statements;
237};
238
278 protected:
279 MinimalNameGenerator nameGen;
280 TypeMap *typeMap;
281 std::map<const IR::P4Table *, TableInsertions *> toInsert;
282 std::set<const IR::P4Table *> *invokedInKey;
283
284 public:
285 KeySideEffect(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
286 : typeMap(typeMap), invokedInKey(invokedInKey) {
287 CHECK_NULL(typeMap);
288 CHECK_NULL(invokedInKey);
289 setName("KeySideEffect");
290 }
291
292 profile_t init_apply(const IR::Node *node) override;
293
294 virtual const IR::Node *doStatement(const IR::Statement *statement,
295 const IR::Expression *expression,
296 const Visitor::Context *ctxt);
297
298 const IR::Node *preorder(IR::Key *key) override;
299
300 // These should be all kinds of statements that may contain a table apply
301 // after the program has been simplified
302 const IR::Node *postorder(IR::MethodCallStatement *statement) override {
303 return doStatement(statement, statement->methodCall, getContext());
304 }
305 const IR::Node *postorder(IR::IfStatement *statement) override {
306 return doStatement(statement, statement->condition, getContext());
307 }
308 const IR::Node *postorder(IR::SwitchStatement *statement) override {
309 return doStatement(statement, statement->expression, getContext());
310 }
311 const IR::Node *postorder(IR::AssignmentStatement *statement) override {
312 return doStatement(statement, statement->right, getContext());
313 }
314 const IR::Node *postorder(IR::KeyElement *element) override;
315 const IR::Node *postorder(IR::P4Table *table) override;
316 const IR::Node *preorder(IR::P4Table *table) override;
317};
318
324class TablesInKeys : public Inspector {
325 TypeMap *typeMap;
326 std::set<const IR::P4Table *> *invokedInKey;
327
328 public:
329 TablesInKeys(TypeMap *typeMap, std::set<const IR::P4Table *> *invokedInKey)
330 : typeMap(typeMap), invokedInKey(invokedInKey) {
331 CHECK_NULL(invokedInKey);
332 setName("TableInKeys");
333 }
334 Visitor::profile_t init_apply(const IR::Node *node) override {
335 invokedInKey->clear();
336 return Inspector::init_apply(node);
337 }
338 void postorder(const IR::MethodCallExpression *mce) override {
339 if (!findContext<IR::Key>()) return;
340 HasTableApply hta(typeMap);
341 hta.setCalledBy(this);
342 (void)mce->apply(hta, getContext());
343 if (hta.table != nullptr) {
344 LOG2("Table " << hta.table << " invoked in key of another table");
345 invokedInKey->emplace(hta.table);
346 }
347 }
348};
349
356 TypeMap *typeMap;
357
358 public:
359 explicit TablesInActions(TypeMap *typeMap) : typeMap(typeMap) {}
360 void postorder(const IR::MethodCallExpression *expression) override {
361 if (findContext<IR::ActionList>()) {
362 HasTableApply hta(typeMap);
363 hta.setCalledBy(this);
364 (void)expression->apply(hta, getContext());
365 if (hta.table != nullptr) {
366 ::P4::error(ErrorType::ERR_UNSUPPORTED, "%1%: table invocation in action argument",
367 expression);
368 }
369 }
370 }
371};
372
374 // Contains all tables that are invoked within key
375 // computations for other tables. The keys for these
376 // inner tables cannot be expanded until the keys of
377 // the caller tables have been expanded.
378 std::set<const IR::P4Table *> invokedInKey;
379 // Temporaries that were added
380 std::set<const IR::Expression *> added;
381
382 public:
383 SideEffectOrdering(TypeMap *typeMap, bool skipSideEffectOrdering,
384 TypeChecking *typeChecking = nullptr) {
385 if (!typeChecking) typeChecking = new TypeChecking(nullptr, typeMap);
386 if (!skipSideEffectOrdering) {
387 passes.push_back(new TypeChecking(nullptr, typeMap));
388 passes.push_back(new DoSimplifyExpressions(typeMap, &added));
389 passes.push_back(typeChecking);
390 passes.push_back(new TablesInActions(typeMap));
391 passes.push_back(new TablesInKeys(typeMap, &invokedInKey));
392 passes.push_back(new KeySideEffect(typeMap, &invokedInKey));
393 }
394 setName("SideEffectOrdering");
395 }
396};
397
398} // namespace P4
399
400#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:162
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 node.h:52
Definition node.h:94
Definition visitor.h:400
Definition sideEffects.h:277
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:373
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:355
Definition sideEffects.h:324
Definition visitor.h:424
Definition typeChecker.h:55
Definition typeMap.h:41
Definition source_file.h:131
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:233
Definition visitor.h:47