-
Notifications
You must be signed in to change notification settings - Fork 449
/
Copy pathtableKeyNames.cpp
143 lines (113 loc) · 5.06 KB
/
tableKeyNames.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
Copyright 2017 VMware, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#include "tableKeyNames.h"
namespace P4 {
using namespace literals;
void KeyNameGenerator::error(const IR::Expression *expression) {
::P4::error(ErrorType::ERR_EXPECTED, "%1%: Complex key expression requires a @name annotation",
expression);
}
void KeyNameGenerator::postorder(const IR::Expression *expression) { error(expression); }
void KeyNameGenerator::postorder(const IR::PathExpression *expression) {
name.emplace(expression, expression->path->toString());
}
namespace {
// The constants are used below. We use `$valid$` to represent `isValid()` calls
// on headers and header unions; this is what P4Runtime expects.
static const cstring isValid = "isValid"_cs;
static const cstring isValidKey = "$valid$"_cs;
/// @return a canonicalized string representation of the given Member
/// expression's right-hand side, suitable for use as part of a key name.
cstring keyComponentNameForMember(const IR::Member *expression, const P4::TypeMap *typeMap) {
cstring fname = expression->member.name;
// Without type information, we can't do any deeper analysis.
if (!typeMap) return fname;
auto *type = typeMap->getType(expression->expr, true);
// Use `$valid$` to represent `isValid()` calls on headers and header
// unions; this is what P4Runtime expects.
// XXX(seth): Should we do this for header unions? It's not symmetric with
// SynthesizeValidField, which leaves `isValid()` as-is for header unions,
// but that's a BMV2-specific thing.
if (type->is<IR::Type_Header>() || type->is<IR::Type_HeaderUnion>())
if (expression->member == isValid) return isValidKey;
// If this Member represents a field which has an @name annotation, use it.
if (type->is<IR::Type_StructLike>()) {
auto *st = type->to<IR::Type_StructLike>();
auto *field = st->getField(expression->member);
if (field != nullptr) return field->externalName();
}
return fname;
}
} // namespace
void KeyNameGenerator::postorder(const IR::Member *expression) {
cstring fname = keyComponentNameForMember(expression, typeMap);
// If the member name begins with `.`, it's a global name, and we can
// discard the left-hand side of the Member expression. (We'll also strip
// off the `.` so it doesn't appear in the key name.)
if (fname.startsWith(".")) {
name.emplace(expression, fname.substr(1));
return;
}
// We can generate a name for the overall Member expression only if we were
// able to generate a name for its left-hand side.
if (cstring n = getName(expression->expr)) name.emplace(expression, n + "."_cs + fname);
}
void KeyNameGenerator::postorder(const IR::ArrayIndex *expression) {
cstring l = getName(expression->left);
cstring r = getName(expression->right);
if (!l || !r) return;
name.emplace(expression, l + "[" + r + "]");
}
void KeyNameGenerator::postorder(const IR::Constant *expression) {
name.emplace(expression, Util::toString(expression->value, 0, false, expression->base));
}
void KeyNameGenerator::postorder(const IR::Slice *expression) {
cstring e0 = getName(expression->e0);
cstring e1 = getName(expression->e1);
cstring e2 = getName(expression->e2);
if (!e0 || !e1 || !e2) return;
name.emplace(expression, e0 + "[" + e1 + ":" + e2 + "]");
}
void KeyNameGenerator::postorder(const IR::BAnd *expression) {
cstring left = getName(expression->left);
if (!left) return;
cstring right = getName(expression->right);
if (!right) return;
name.emplace(expression, left + " & " + right);
}
void KeyNameGenerator::postorder(const IR::MethodCallExpression *expression) {
cstring m = getName(expression->method);
if (!m) return;
// This is a heuristic.
if (m.endsWith("$valid$") && expression->arguments->size() == 0) {
name.emplace(expression, m);
return;
}
error(expression);
}
const IR::Node *DoTableKeyNames::postorder(IR::KeyElement *keyElement) {
LOG3("Visiting " << getOriginal());
if (keyElement->hasAnnotation(IR::Annotation::nameAnnotation))
// already present: no changes
return keyElement;
KeyNameGenerator kng(typeMap);
kng.setCalledBy(this);
(void)keyElement->expression->apply(kng);
cstring name = kng.getName(keyElement->expression);
LOG3("Generated name " << name);
if (!name) return keyElement;
keyElement->addAnnotation(IR::Annotation::nameAnnotation,
new IR::StringLiteral(keyElement->expression->srcInfo, name));
return keyElement;
}
} // namespace P4