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/p4/methodInstance.h"
24#include "frontends/p4/typeChecking/typeChecker.h"
25#include "ir/ir.h"
26
27namespace P4 {
28
30class HasTableApply : public Inspector {
31 ReferenceMap *refMap;
32 TypeMap *typeMap;
33
34 public:
35 const IR::P4Table *table;
36 const IR::MethodCallExpression *call;
37 HasTableApply(ReferenceMap *refMap, TypeMap *typeMap)
38 : refMap(refMap), typeMap(typeMap), table(nullptr), call(nullptr) {
39 CHECK_NULL(refMap);
40 CHECK_NULL(typeMap);
41 setName("HasTableApply");
42 }
43
44 void postorder(const IR::MethodCallExpression *expression) override {
45 auto mi = MethodInstance::resolve(expression, refMap, typeMap);
46 if (!mi->isApply()) return;
47 auto am = mi->to<P4::ApplyMethod>();
48 if (!am->object->is<IR::P4Table>()) return;
49 BUG_CHECK(table == nullptr, "%1% and %2%: multiple table applications in one expression",
50 table, am->object);
51 table = am->object->to<IR::P4Table>();
52 call = expression;
53 LOG3("Invoked table is " << dbp(table));
54 }
55};
56
64class SideEffects : public Inspector {
65 private:
66 ReferenceMap *refMap;
67 TypeMap *typeMap;
68
69 public:
71 const IR::Node *nodeWithSideEffect = nullptr;
72
74 unsigned sideEffectCount = 0;
75
76 void postorder(const IR::MethodCallExpression *mce) override {
77 if (refMap == nullptr || typeMap == nullptr) {
78 // conservative
81 return;
82 }
83 auto mi = MethodInstance::resolve(mce, refMap, typeMap);
84 if (!mi->is<BuiltInMethod>()) {
87 return;
88 }
89 auto bim = mi->to<BuiltInMethod>();
90 if (bim->name.name != IR::Type_Header::isValid) {
93 }
94 }
95
96 void postorder(const IR::ConstructorCallExpression *cce) override {
99 }
100
103 SideEffects(ReferenceMap *refMap, TypeMap *typeMap) : refMap(refMap), typeMap(typeMap) {
104 setName("SideEffects");
105 }
106
108 static bool check(const IR::Expression *expression, const Visitor *calledBy,
109 ReferenceMap *refMap, TypeMap *typeMap) {
110 SideEffects se(refMap, typeMap);
111 se.setCalledBy(calledBy);
112 expression->apply(se);
113 return se.nodeWithSideEffect != nullptr;
114 }
116 static bool hasSideEffect(const IR::MethodCallExpression *mce, ReferenceMap *refMap,
117 TypeMap *typeMap) {
118 // mce does not produce a side effect in few cases:
119 // * isValid()
120 // * function, extern function, or extern method with noSideEffects annotation
121 auto mi = MethodInstance::resolve(mce, refMap, typeMap);
122 if (auto em = mi->to<P4::ExternMethod>()) {
123 if (em->method->getAnnotation(IR::Annotation::noSideEffectsAnnotation)) {
124 return false;
125 }
126 return true;
127 }
128 if (auto ef = mi->to<P4::ExternFunction>()) {
129 if (ef->method->getAnnotation(IR::Annotation::noSideEffectsAnnotation)) {
130 return false;
131 }
132 return true;
133 }
134 if (auto ef = mi->to<P4::FunctionCall>()) {
135 if (ef->function->getAnnotation(IR::Annotation::noSideEffectsAnnotation)) {
136 return false;
137 }
138 return true;
139 }
140 if (auto bim = mi->to<BuiltInMethod>()) {
141 if (bim->name.name == IR::Type_Header::isValid) {
142 return false;
143 }
144 }
145 return true;
146 }
147};
148
181class DoSimplifyExpressions : public Transform, P4WriteContext {
182 ReferenceMap *refMap;
183 TypeMap *typeMap;
184 // Expressions holding temporaries that are already added.
185 std::set<const IR::Expression *> *added;
186
187 IR::IndexedVector<IR::Declaration> toInsert; // temporaries
188 IR::IndexedVector<IR::StatOrDecl> statements;
191 std::set<const IR::Expression *> temporaries;
192
193 cstring createTemporary(const IR::Type *type);
194 const IR::Expression *addAssignment(Util::SourceInfo srcInfo, cstring varName,
195 const IR::Expression *expression);
196 bool mayAlias(const IR::Expression *left, const IR::Expression *right) const;
197 bool containsHeaderType(const IR::Type *type);
198
199 public:
201 std::set<const IR::Expression *> *added)
202 : refMap(refMap), typeMap(typeMap), added(added) {
203 CHECK_NULL(refMap);
204 CHECK_NULL(typeMap);
205 setName("DoSimplifyExpressions");
206 }
207
208 const IR::Node *postorder(IR::Expression *expression) override;
209 const IR::Node *preorder(IR::StructExpression *expression) override;
210 const IR::Node *preorder(IR::ListExpression *expression) override;
211 const IR::Node *preorder(IR::Literal *expression) override;
212 const IR::Node *preorder(IR::ArrayIndex *expression) override;
213 const IR::Node *preorder(IR::Member *expression) override;
214 const IR::Node *preorder(IR::SelectExpression *expression) override;
215 const IR::Node *preorder(IR::Operation_Unary *expression) override;
216 const IR::Node *preorder(IR::Operation_Binary *expression) override;
217 const IR::Node *shortCircuit(IR::Operation_Binary *expression);
218 const IR::Node *preorder(IR::Mux *expression) override;
219 const IR::Node *preorder(IR::LAnd *expression) override;
220 const IR::Node *preorder(IR::LOr *expression) override;
221 const IR::Node *preorder(IR::MethodCallExpression *mce) override;
222
223 const IR::Node *preorder(IR::ConstructorCallExpression *cce) override {
224 prune();
225 return cce;
226 }
227 const IR::Node *preorder(IR::Property *prop) override {
228 prune();
229 return prop;
230 }
231 const IR::Node *preorder(IR::Annotation *anno) override {
232 prune();
233 return anno;
234 }
235
236 const IR::Node *postorder(IR::P4Parser *parser) override;
237 const IR::Node *postorder(IR::Function *function) override;
238 const IR::Node *postorder(IR::P4Control *control) override;
239 const IR::Node *postorder(IR::P4Action *action) override;
240 const IR::Node *postorder(IR::ParserState *state) override;
241 const IR::Node *postorder(IR::AssignmentStatement *statement) override;
242 const IR::Node *postorder(IR::MethodCallStatement *statement) override;
243 const IR::Node *postorder(IR::ReturnStatement *statement) override;
244 const IR::Node *preorder(IR::SwitchStatement *statement) override;
245 const IR::Node *preorder(IR::IfStatement *statement) override;
246
247 void end_apply(const IR::Node *) override;
248};
249
251 public:
252 std::vector<const IR::Declaration_Variable *> declarations;
253 std::vector<const IR::AssignmentStatement *> statements;
254};
255
294class KeySideEffect : public Transform {
295 protected:
296 ReferenceMap *refMap;
297 TypeMap *typeMap;
298 std::map<const IR::P4Table *, TableInsertions *> toInsert;
299 std::set<const IR::P4Table *> *invokedInKey;
300
301 public:
302 KeySideEffect(ReferenceMap *refMap, TypeMap *typeMap,
303 std::set<const IR::P4Table *> *invokedInKey)
304 : refMap(refMap), typeMap(typeMap), invokedInKey(invokedInKey) {
305 CHECK_NULL(refMap);
306 CHECK_NULL(typeMap);
307 CHECK_NULL(invokedInKey);
308 setName("KeySideEffect");
309 }
310 virtual const IR::Node *doStatement(const IR::Statement *statement,
311 const IR::Expression *expression);
312
313 const IR::Node *preorder(IR::Key *key) override;
314
315 // These should be all kinds of statements that may contain a table apply
316 // after the program has been simplified
317 const IR::Node *postorder(IR::MethodCallStatement *statement) override {
318 return doStatement(statement, statement->methodCall);
319 }
320 const IR::Node *postorder(IR::IfStatement *statement) override {
321 return doStatement(statement, statement->condition);
322 }
323 const IR::Node *postorder(IR::SwitchStatement *statement) override {
324 return doStatement(statement, statement->expression);
325 }
326 const IR::Node *postorder(IR::AssignmentStatement *statement) override {
327 return doStatement(statement, statement->right);
328 }
329 const IR::Node *postorder(IR::KeyElement *element) override;
330 const IR::Node *postorder(IR::P4Table *table) override;
331 const IR::Node *preorder(IR::P4Table *table) override;
332};
333
339class TablesInKeys : public Inspector {
340 ReferenceMap *refMap;
341 TypeMap *typeMap;
342 std::set<const IR::P4Table *> *invokedInKey;
343
344 public:
345 TablesInKeys(ReferenceMap *refMap, TypeMap *typeMap,
346 std::set<const IR::P4Table *> *invokedInKey)
347 : refMap(refMap), typeMap(typeMap), invokedInKey(invokedInKey) {
348 CHECK_NULL(invokedInKey);
349 setName("TableInKeys");
350 }
351 Visitor::profile_t init_apply(const IR::Node *node) override {
352 invokedInKey->clear();
353 return Inspector::init_apply(node);
354 }
355 void postorder(const IR::MethodCallExpression *mce) override {
356 if (!findContext<IR::Key>()) return;
357 HasTableApply hta(refMap, typeMap);
358 hta.setCalledBy(this);
359 (void)mce->apply(hta);
360 if (hta.table != nullptr) {
361 LOG2("Table " << hta.table << " invoked in key of another table");
362 invokedInKey->emplace(hta.table);
363 }
364 }
365};
366
372class TablesInActions : public Inspector {
373 ReferenceMap *refMap;
374 TypeMap *typeMap;
375
376 public:
377 TablesInActions(ReferenceMap *refMap, TypeMap *typeMap) : refMap(refMap), typeMap(typeMap) {}
378 void postorder(const IR::MethodCallExpression *expression) override {
379 if (findContext<IR::ActionList>()) {
380 HasTableApply hta(refMap, typeMap);
381 hta.setCalledBy(this);
382 (void)expression->apply(hta);
383 if (hta.table != nullptr) {
384 ::error(ErrorType::ERR_UNSUPPORTED, "%1%: table invocation in action argument",
385 expression);
386 }
387 }
388 }
389};
390
391class SideEffectOrdering : public PassRepeated {
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(ReferenceMap *refMap, TypeMap *typeMap, bool skipSideEffectOrdering,
402 TypeChecking *typeChecking = nullptr) {
403 if (!typeChecking) typeChecking = new TypeChecking(refMap, typeMap);
404 if (!skipSideEffectOrdering) {
405 passes.push_back(new TypeChecking(refMap, typeMap));
406 passes.push_back(new DoSimplifyExpressions(refMap, typeMap, &added));
407 passes.push_back(typeChecking);
408 passes.push_back(new TablesInActions(refMap, typeMap));
409 passes.push_back(new TablesInKeys(refMap, typeMap, &invokedInKey));
410 passes.push_back(new KeySideEffect(refMap, typeMap, &invokedInKey));
411 }
412 setName("SideEffectOrdering");
413 }
414};
415
416} // namespace P4
417
418#endif /* FRONTENDS_P4_SIDEEFFECTS_H_ */
Definition methodInstance.h:124
Definition methodInstance.h:249
Convert expressions so that each expression contains at most one side effect.
Definition sideEffects.h:181
Definition methodInstance.h:176
Definition methodInstance.h:144
Definition methodInstance.h:221
Checks to see whether an IR node includes a table.apply() sub-expression.
Definition sideEffects.h:30
Definition sideEffects.h:294
static MethodInstance * resolve(const IR::MethodCallExpression *mce, DeclarationLookup *refMap, TypeMap *typeMap, bool useExpressionType=false, const Visitor::Context *ctxt=nullptr, bool incomplete=false)
Definition methodInstance.cpp:26
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition sideEffects.h:391
Determines whether an expression may have method or constructor invocations.
Definition sideEffects.h:64
unsigned sideEffectCount
Number of side effects in this expression.
Definition sideEffects.h:74
static bool check(const IR::Expression *expression, const Visitor *calledBy, ReferenceMap *refMap, TypeMap *typeMap)
Definition sideEffects.h:108
SideEffects(ReferenceMap *refMap, TypeMap *typeMap)
Definition sideEffects.h:103
static bool hasSideEffect(const IR::MethodCallExpression *mce, ReferenceMap *refMap, TypeMap *typeMap)
Definition sideEffects.h:116
const IR::Node * nodeWithSideEffect
Last visited side-effecting node. Null if no node has side effects.
Definition sideEffects.h:71
Definition sideEffects.h:372
Definition sideEffects.h:339
Definition typeChecker.h:60
Definition typeMap.h:42
Definition source_file.h:126
Definition cstring.h:72
Definition applyOptionsPragmas.cpp:24
Definition sideEffects.h:250