Skip to content

Commit 611d418

Browse files
Elimination of non-concrete indexes for header stacks from controls (#2914)
1 parent 3c3f60a commit 611d418

File tree

67 files changed

+5099
-28
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+5099
-28
lines changed

backends/p4test/midend.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ limitations under the License.
3636
#include "midend/eliminateSwitch.h"
3737
#include "midend/flattenHeaders.h"
3838
#include "midend/flattenInterfaceStructs.h"
39+
#include "midend/hsIndexSimplify.h"
3940
#include "midend/replaceSelectRange.h"
4041
#include "midend/expandEmit.h"
4142
#include "midend/expandLookahead.h"
@@ -142,6 +143,7 @@ MidEnd::MidEnd(CompilerOptions& options, std::ostream* outStream) {
142143
v1controls->emplace(deparser->to<IR::ControlBlock>()->container->name);
143144
}
144145
return root; },
146+
new P4::HSIndexSimplifier(&refMap, &typeMap),
145147
new P4::SynthesizeActions(&refMap, &typeMap, new SkipControls(v1controls)),
146148
new P4::MoveActionsToTables(&refMap, &typeMap),
147149
options.loopsUnrolling ? new P4::ParsersUnroll(true, &refMap, &typeMap) : nullptr,

midend/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ set (MIDEND_SRCS
2727
fillEnumMap.cpp
2828
flattenHeaders.cpp
2929
flattenInterfaceStructs.cpp
30+
hsIndexSimplify.cpp
3031
interpreter.cpp
3132
global_copyprop.cpp
3233
local_copyprop.cpp

midend/hsIndexSimplify.cpp

+227
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
#include <iostream>
2+
#include <sstream>
3+
4+
#include "midend/hsIndexSimplify.h"
5+
#include "midend/simplifyKey.h"
6+
7+
namespace P4 {
8+
9+
void HSIndexFinder::postorder(const IR::ArrayIndex* curArrayIndex) {
10+
if (arrayIndex == nullptr && !curArrayIndex->right->is<IR::Constant>()) {
11+
arrayIndex = curArrayIndex;
12+
addNewVariable();
13+
}
14+
}
15+
16+
void HSIndexFinder::addNewVariable() {
17+
BUG_CHECK(arrayIndex != nullptr, "Can't generate new name for empty ArrayIndex");
18+
// If index is an expression then create new variable.
19+
if (locals != nullptr && (arrayIndex->right->is<IR::Operation_Ternary>() ||
20+
arrayIndex->right->is<IR::Operation_Binary>() ||
21+
arrayIndex->right->is<IR::Operation_Unary>() ||
22+
arrayIndex->right->is<IR::PathExpression>())) {
23+
// Generate new local variable if needed.
24+
std::ostringstream ostr;
25+
ostr << arrayIndex->right;
26+
cstring indexString = ostr.str();
27+
if (arrayIndex->right->is<IR::PathExpression>()) {
28+
newVariable = arrayIndex->right->to<IR::PathExpression>();
29+
} else if (generatedVariables->count(indexString) == 0) {
30+
// Generate new temporary variable.
31+
auto type = typeMap->getTypeType(arrayIndex->right->type, true);
32+
auto name = refMap->newName("hsiVar");
33+
auto decl = new IR::Declaration_Variable(name, type);
34+
locals->push_back(decl);
35+
typeMap->setType(decl, type);
36+
newVariable = new IR::PathExpression(arrayIndex->srcInfo, type, new IR::Path(name));
37+
generatedVariables->emplace(indexString, newVariable);
38+
} else {
39+
newVariable = generatedVariables->at(indexString);
40+
}
41+
}
42+
}
43+
44+
const IR::Node* HSIndexTransform::postorder(IR::ArrayIndex* curArrayIndex) {
45+
if (hsIndexFinder.arrayIndex != nullptr && curArrayIndex->equiv(*hsIndexFinder.arrayIndex)) {
46+
// Translating current array index.
47+
auto* newArrayIndex = hsIndexFinder.arrayIndex->clone();
48+
newArrayIndex->right = new IR::Constant(newArrayIndex->right->type, index);
49+
return newArrayIndex;
50+
}
51+
return curArrayIndex;
52+
}
53+
54+
IR::Node* HSIndexSimplifier::eliminateArrayIndexes(HSIndexFinder& aiFinder,
55+
IR::Statement* statement,
56+
const IR::Expression* expr) {
57+
if (aiFinder.arrayIndex == nullptr) {
58+
return statement;
59+
}
60+
const IR::Statement* elseBody = nullptr;
61+
auto* curIf = statement->to<IR::IfStatement>();
62+
if (curIf != nullptr) {
63+
elseBody = curIf->ifFalse;
64+
}
65+
IR::IndexedVector<IR::StatOrDecl> newComponents;
66+
if (aiFinder.newVariable != nullptr) {
67+
if (!aiFinder.newVariable->equiv(*aiFinder.arrayIndex->right)) {
68+
newComponents.push_back(new IR::AssignmentStatement(
69+
aiFinder.arrayIndex->srcInfo, aiFinder.newVariable, aiFinder.arrayIndex->right));
70+
}
71+
}
72+
IR::IfStatement* result = nullptr;
73+
IR::IfStatement* curResult = nullptr;
74+
IR::IfStatement* newIf = nullptr;
75+
const auto* typeStack = aiFinder.arrayIndex->left->type->checkedTo<IR::Type_Stack>();
76+
size_t sz = typeStack->getSize();
77+
for (size_t i = 0; i < sz; i++) {
78+
HSIndexTransform aiRewriter(aiFinder, i);
79+
auto* newStatement = statement->apply(aiRewriter)->to<IR::Statement>();
80+
auto* newIndex = new IR::Constant(aiFinder.arrayIndex->right->type, i);
81+
auto* newCondition = new IR::Equ(aiFinder.newVariable, newIndex);
82+
if (curIf != nullptr) {
83+
newIf = newStatement->checkedTo<IR::IfStatement>()->clone();
84+
newIf->condition = new IR::LAnd(newCondition, newIf->condition);
85+
} else {
86+
newIf = new IR::IfStatement(newCondition, newStatement, nullptr);
87+
}
88+
if (result == nullptr) {
89+
result = newIf;
90+
} else {
91+
curResult->ifFalse = newIf;
92+
}
93+
curResult = newIf;
94+
}
95+
if (expr != nullptr && locals != nullptr) {
96+
// Add case for write out of bound.
97+
cstring typeString = expr->type->node_type_name();
98+
const IR::PathExpression* pathExpr = nullptr;
99+
if (generatedVariables->count(typeString) == 0) {
100+
// Add assigment of undefined header.
101+
auto name = refMap->newName("hsVar");
102+
auto decl = new IR::Declaration_Variable(name, expr->type);
103+
locals->push_back(decl);
104+
typeMap->setType(decl, expr->type);
105+
pathExpr = new IR::PathExpression(aiFinder.arrayIndex->srcInfo, expr->type,
106+
new IR::Path(name));
107+
generatedVariables->emplace(typeString, pathExpr);
108+
} else {
109+
pathExpr = generatedVariables->at(typeString);
110+
}
111+
auto* newStatement =
112+
new IR::AssignmentStatement(aiFinder.arrayIndex->srcInfo, expr, pathExpr);
113+
auto* newCondition = new IR::Geq(
114+
aiFinder.newVariable, new IR::Constant(aiFinder.arrayIndex->right->type, sz - 1));
115+
newIf = new IR::IfStatement(newCondition, newStatement, nullptr);
116+
curResult->ifFalse = newIf;
117+
}
118+
newIf->ifFalse = elseBody;
119+
newComponents.push_back(result);
120+
return new IR::BlockStatement(newComponents);
121+
}
122+
123+
IR::Node* HSIndexSimplifier::preorder(IR::AssignmentStatement* assignmentStatement) {
124+
HSIndexFinder aiFinder(locals, refMap, typeMap, generatedVariables);
125+
assignmentStatement->left->apply(aiFinder);
126+
if (aiFinder.arrayIndex == nullptr) {
127+
assignmentStatement->right->apply(aiFinder);
128+
return eliminateArrayIndexes(aiFinder, assignmentStatement, assignmentStatement->left);
129+
} else {
130+
return eliminateArrayIndexes(aiFinder, assignmentStatement, nullptr);
131+
}
132+
}
133+
134+
/**
135+
* Policy that treats a key as ArrayIndex with non constant index.
136+
*/
137+
class IsNonConstantArrayIndex : public KeyIsSimple, public Inspector {
138+
protected:
139+
bool simple;
140+
141+
public:
142+
IsNonConstantArrayIndex() { setName("IsNonConstantArrayIndex"); }
143+
144+
void postorder(const IR::ArrayIndex* arrayIndex) override {
145+
if (simple) {
146+
simple = arrayIndex->right->is<IR::Constant>();
147+
}
148+
}
149+
profile_t init_apply(const IR::Node* root) override {
150+
simple = true;
151+
return Inspector::init_apply(root);
152+
}
153+
154+
bool isSimple(const IR::Expression* expression, const Visitor::Context*) override {
155+
(void)expression->apply(*this);
156+
return simple;
157+
}
158+
};
159+
160+
IR::Node* HSIndexSimplifier::preorder(IR::P4Control* control) {
161+
DoSimplifyKey keySimplifier(refMap, typeMap, new IsNonConstantArrayIndex());
162+
const auto* controlKeySimplified = control->apply(keySimplifier)->to<IR::P4Control>();
163+
auto* newControl = controlKeySimplified->clone();
164+
IR::IndexedVector<IR::Declaration> newControlLocals;
165+
HSIndexSimplifier hsSimplifier(refMap, typeMap, &newControlLocals, generatedVariables);
166+
newControl->body = newControl->body->apply(hsSimplifier)->to<IR::BlockStatement>();
167+
for (auto* declaration : controlKeySimplified->controlLocals) {
168+
if (declaration->is<IR::P4Action>()) {
169+
newControlLocals.push_back(declaration->apply(hsSimplifier)->to<IR::Declaration>());
170+
} else {
171+
newControlLocals.push_back(declaration);
172+
}
173+
}
174+
newControl->controlLocals = newControlLocals;
175+
return newControl;
176+
}
177+
178+
IR::Node* HSIndexSimplifier::preorder(IR::P4Parser* parser) {
179+
prune();
180+
return parser;
181+
}
182+
183+
IR::Node* HSIndexSimplifier::preorder(IR::BlockStatement* blockStatement) {
184+
generatedVariablesMap blockGeneratedVariables;
185+
HSIndexFinder aiFinder(locals, refMap, typeMap, &blockGeneratedVariables);
186+
blockStatement->apply(aiFinder);
187+
if (aiFinder.arrayIndex == nullptr) {
188+
return blockStatement;
189+
}
190+
HSIndexSimplifier hsSimplifier(refMap, typeMap, locals, &blockGeneratedVariables);
191+
auto* newBlock = blockStatement->clone();
192+
IR::IndexedVector<IR::StatOrDecl> newComponents;
193+
for (auto& component : blockStatement->components) {
194+
const auto* newComponent = component->apply(hsSimplifier)->to<IR::StatOrDecl>();
195+
if (const auto* newComponentBlock = newComponent->to<IR::BlockStatement>()) {
196+
for (auto& blockComponent : newComponentBlock->components) {
197+
newComponents.push_back(blockComponent);
198+
}
199+
} else {
200+
newComponents.push_back(newComponent);
201+
}
202+
}
203+
newBlock->components = newComponents;
204+
return newBlock;
205+
}
206+
207+
IR::Node* HSIndexSimplifier::preorder(IR::IfStatement* ifStatement) {
208+
HSIndexFinder aiFinder(locals, refMap, typeMap, generatedVariables);
209+
ifStatement->condition->apply(aiFinder);
210+
return eliminateArrayIndexes(aiFinder, ifStatement, nullptr);
211+
}
212+
213+
IR::Node* HSIndexSimplifier::preorder(IR::MethodCallStatement* methodCallStatement) {
214+
HSIndexFinder aiFinder(locals, refMap, typeMap, generatedVariables);
215+
methodCallStatement->apply(aiFinder);
216+
// Here we mean that in/out parameter will be replaced by correspondent assignments.
217+
// In this case no need to consider assignment to undefined value.
218+
return eliminateArrayIndexes(aiFinder, methodCallStatement, nullptr);
219+
}
220+
221+
IR::Node* HSIndexSimplifier::preorder(IR::SwitchStatement* switchStatement) {
222+
HSIndexFinder aiFinder(locals, refMap, typeMap, generatedVariables);
223+
switchStatement->expression->apply(aiFinder);
224+
return eliminateArrayIndexes(aiFinder, switchStatement, nullptr);
225+
}
226+
227+
} // namespace P4

midend/hsIndexSimplify.h

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
#ifndef _MIDEND_HSINDEXSIMPLIFY_H_
2+
#define _MIDEND_HSINDEXSIMPLIFY_H_
3+
4+
#include "frontends/common/resolveReferences/referenceMap.h"
5+
#include "frontends/p4/typeChecking/typeChecker.h"
6+
#include "frontends/p4/typeMap.h"
7+
#include "ir/ir.h"
8+
9+
namespace P4 {
10+
11+
typedef std::map<cstring, const IR::PathExpression*> generatedVariablesMap;
12+
13+
/// This class finds innermost header stack with non-concrete index.
14+
/// For each found innermost header stack it generates new local variable and
15+
/// adds it to the corresponded local definitions.
16+
class HSIndexFinder : public Inspector {
17+
friend class HSIndexTransform;
18+
friend class HSIndexSimplifier;
19+
IR::IndexedVector<IR::Declaration>* locals;
20+
ReferenceMap* refMap;
21+
TypeMap* typeMap;
22+
const IR::ArrayIndex* arrayIndex;
23+
const IR::PathExpression* newVariable;
24+
generatedVariablesMap* generatedVariables;
25+
std::set<cstring> storedMember;
26+
std::list<IR::Member*> dependedMembers;
27+
28+
public:
29+
HSIndexFinder(IR::IndexedVector<IR::Declaration>* locals, ReferenceMap* refMap,
30+
TypeMap* typeMap, generatedVariablesMap* generatedVariables)
31+
: locals(locals),
32+
refMap(refMap),
33+
typeMap(typeMap),
34+
arrayIndex(nullptr),
35+
newVariable(nullptr),
36+
generatedVariables(generatedVariables) {}
37+
void postorder(const IR::ArrayIndex* curArrayIndex) override;
38+
39+
protected:
40+
void addNewVariable();
41+
};
42+
43+
/// This class substitutes index of a header stack in all occurence of found header stack.
44+
class HSIndexTransform : public Transform {
45+
friend class HSIndexSimplifier;
46+
int index;
47+
HSIndexFinder& hsIndexFinder;
48+
49+
public:
50+
HSIndexTransform(HSIndexFinder& finder, int index) : index(index), hsIndexFinder(finder) {}
51+
const IR::Node* postorder(IR::ArrayIndex* curArrayIndex) override;
52+
};
53+
54+
/// This class eliminates all non-concrete indexes of the header stacks in the controls.
55+
/// It generates new variables for all expressions in the header stacks indexes and
56+
/// checks their values for substitution of concrete values.
57+
/// Restriction : in/out parameters should be replaced by correspondent assignments.
58+
/// Let
59+
/// header h_index { bit<32> index;}
60+
/// header h_stack { bit<32> a;}
61+
/// struct headers { h_stack[2] h; h_index i;}
62+
/// headers hdr;
63+
/// Then the assignment hdr.h[hdr.i] = 1 will be translated into
64+
/// bit<32> hdivr0;
65+
/// hdivr0 = hdr.i;
66+
/// if (hdivr0 == 0) { hdr.h[0] = 1;}
67+
/// else if (hdivr0 == 1){hdr.h[1] = 1;}
68+
class HSIndexSimplifier : public Transform {
69+
ReferenceMap* refMap;
70+
TypeMap* typeMap;
71+
IR::IndexedVector<IR::Declaration>* locals;
72+
generatedVariablesMap* generatedVariables;
73+
74+
public:
75+
HSIndexSimplifier(ReferenceMap* refMap, TypeMap* typeMap,
76+
IR::IndexedVector<IR::Declaration>* locals = nullptr,
77+
generatedVariablesMap* generatedVariables = nullptr)
78+
: refMap(refMap), typeMap(typeMap), locals(locals), generatedVariables(generatedVariables) {
79+
if (generatedVariables == nullptr) generatedVariables = new generatedVariablesMap();
80+
}
81+
IR::Node* preorder(IR::IfStatement* ifStatement) override;
82+
IR::Node* preorder(IR::AssignmentStatement* assignmentStatement) override;
83+
IR::Node* preorder(IR::BlockStatement* assignmentStatement) override;
84+
IR::Node* preorder(IR::MethodCallStatement* methodCallStatement) override;
85+
IR::Node* preorder(IR::P4Control* control) override;
86+
IR::Node* preorder(IR::P4Parser* parser) override;
87+
IR::Node* preorder(IR::SwitchStatement* switchStatement) override;
88+
89+
protected:
90+
IR::Node* eliminateArrayIndexes(HSIndexFinder& aiFinder, IR::Statement* statement,
91+
const IR::Expression* expr);
92+
};
93+
94+
} // namespace P4
95+
96+
#endif /* _MIDEND_HSINDEXSIMPLIFY_H_ */

0 commit comments

Comments
 (0)