P4C
The P4 Compiler
Loading...
Searching...
No Matches
ixbar_expr.h
1
18
19#ifndef BF_P4C_MAU_IXBAR_EXPR_H_
20#define BF_P4C_MAU_IXBAR_EXPR_H_
21
22#include "backends/tofino/bf-p4c/bf-p4c-options.h"
23#include "backends/tofino/bf-p4c/common/utils.h"
24#include "backends/tofino/bf-p4c/mau/mau_visitor.h"
25#include "backends/tofino/bf-p4c/phv/phv_fields.h"
26#include "boost/range/adaptor/reversed.hpp"
27#include "ir/ir.h"
28#include "lib/bitvec.h"
29
30using namespace P4;
31
33class CanBeIXBarExpr : public Inspector {
34 static constexpr int MAX_HASH_BITS = 52;
35
36 static int get_max_hash_bits() {
37 // If hash parity is enabled reserve a bit for parity
38 if (!BackendOptions().disable_gfm_parity) return MAX_HASH_BITS - 1;
39 return MAX_HASH_BITS;
40 }
41
42 bool rv = true;
43 // FIXME -- if we want to run this *before* SimplifyReferences has converted all
44 // PathExpressions into the referred to object, we need some way of resolving what the
45 // path expressions refer to, or at least whether they refer to something that can be
46 // accessed in the ixbar. So we use this function on a per-use basis. The default
47 // implementation throws a BUG if ever called (as normally we're after SimplifyReferences
48 // and all PathExpressions are gone), but in the case where we're before that (calling
49 // from CreateSaluInstruction called from AttachTables called from extract_maupipe),
50 // we use a functor that can tell a local of the RegisterAction (which can't be in the
51 // ixbar) from anything else (which is assumed to be a header or metadata instance.)
52 // If we ever clean up the frontend reference handling so we no longer need to resolve
53 // names via the refmap, this can go away. Or if we could do SimplifyRefernces before
54 // trying to build StatefulAlu instructions.
55 std::function<bool(const IR::PathExpression *)> checkPath;
56
57 static const IR::Type_Extern *externType(const IR::Type *type) {
58 if (auto *spec = type->to<IR::Type_SpecializedCanonical>()) type = spec->baseType;
59 return type->to<IR::Type_Extern>();
60 }
61
62 profile_t init_apply(const IR::Node *n) {
63 auto *expr = n->to<IR::Expression>();
64 BUG_CHECK(expr, "CanBeIXBarExpr called on non-expression");
65 rv = expr->type->width_bits() <= get_max_hash_bits();
66 return Inspector::init_apply(n);
67 }
68 bool preorder(const IR::Node *) { return false; } // ignore non-expressions
69 bool preorder(const IR::PathExpression *pe) {
70 if (!checkPath(pe)) rv = false;
71 return false;
72 }
73 bool preorder(const IR::Constant *) { return false; }
74 bool preorder(const IR::Member *m) {
75 auto *base = m->expr;
76 while ((m = base->to<IR::Member>())) base = m->expr;
77 if (auto *pe = base->to<IR::PathExpression>()) {
78 if (!checkPath(pe)) rv = false;
79 } else if (base->is<IR::HeaderRef>() || base->is<IR::TempVar>()) {
80 // ok
81 } else {
82 rv = false;
83 }
84 return false;
85 }
86 bool preorder(const IR::TempVar *) { return false; }
87 bool preorder(const IR::Slice *) { return rv; }
88 bool preorder(const IR::Concat *) { return rv; }
89 bool preorder(const IR::Cast *) { return rv; }
90 bool preorder(const IR::BFN::SignExtend *) { return rv; }
91 bool preorder(const IR::BFN::ReinterpretCast *) { return rv; }
92 bool preorder(const IR::BXor *) { return rv; }
93 bool preorder(const IR::BAnd *e) {
94 if (!e->left->is<IR::Constant>() && !e->right->is<IR::Constant>()) rv = false;
95 return rv;
96 }
97 bool preorder(const IR::BOr *e) {
98 if (!e->left->is<IR::Constant>() && !e->right->is<IR::Constant>()) rv = false;
99 return rv;
100 }
101 bool preorder(const IR::MethodCallExpression *mce) {
102 if (auto *method = mce->method->to<IR::Member>()) {
103 if (auto *ext = externType(method->type)) {
104 if (ext->name == "Hash" && method->member == "get") {
105 return false;
106 }
107 }
108 }
109 return rv = false;
110 }
111 // any other expression cannot be an ixbar expression
112 bool preorder(const IR::Expression *) { return rv = false; }
113
114 public:
115 explicit CanBeIXBarExpr(
116 const IR::Expression *e,
117 std::function<bool(const IR::PathExpression *)> checkPath =
118 [](const IR::PathExpression *) -> bool { BUG("Unexpected path expression"); })
119 : checkPath(checkPath) {
120 e->apply(*this);
121 }
122 operator bool() const { return rv; }
123};
124
125/* FIXME -- this should be a constructor of bitvec in the open source code */
126inline bitvec to_bitvec(big_int v) {
127 bitvec rv(static_cast<uintptr_t>(v));
128 v >>= sizeof(uintptr_t) * CHAR_BIT;
129 if (v > 0) rv |= to_bitvec(v) << (sizeof(uintptr_t) * CHAR_BIT);
130 return rv;
131}
132
134class IXBarExprSeed : public Inspector {
135 le_bitrange slice;
136 int shift = 0;
137 bitvec rv;
138
139 bool preorder(const IR::Annotation *) { return false; }
140 bool preorder(const IR::Type *) { return false; }
141 bool preorder(const IR::Member *) { return false; }
142 bool preorder(const IR::Constant *k) {
143 if (getParent<IR::BAnd>()) return false;
144 rv ^= to_bitvec((k->value >> slice.lo) & ((big_int(1) << slice.size()) - 1)) << shift;
145 return false;
146 }
147 bool preorder(const IR::Concat *e) {
148 auto tmp = slice;
149 int rwidth = e->right->type->width_bits();
150 if (slice.lo < rwidth) {
151 slice = slice.intersectWith(0, rwidth - 1);
152 visit(e->right, "right");
153 }
154 if (tmp.hi >= rwidth) {
155 slice = tmp;
156 slice.lo = rwidth;
157 shift += rwidth;
158 slice = slice.shiftedByBits(-rwidth);
159 visit(e->left, "left");
160 shift -= rwidth;
161 }
162 slice = tmp;
163 return false;
164 }
165 bool preorder(const IR::StructExpression *fl) {
166 // delegate to the ListExpression case
167 IR::ListExpression listExpr(*getListExprComponents(*fl));
168 return preorder(&listExpr);
169 }
170 bool preorder(const IR::ListExpression *fl) {
171 auto tmp = slice;
172 auto old_shift = shift;
173 for (auto *e : boost::adaptors::reverse(fl->components)) {
174 int width = e->type->width_bits();
175 if (slice.lo < width) {
176 auto t2 = slice;
177 slice = slice.intersectWith(0, width - 1);
178 visit(e);
179 slice = t2;
180 }
181 if (slice.hi < width) break;
182 slice = slice.shiftedByBits(-width);
183 shift += width;
184 }
185 slice = tmp;
186 shift = old_shift;
187 return false;
188 }
189 bool preorder(const IR::Slice *sl) {
190 auto tmp = slice;
191 slice = slice.shiftedByBits(-sl->getL());
192 int width = sl->getH() - sl->getL() + 1;
193 if (slice.size() > width) slice.hi = slice.lo + width - 1;
194 visit(sl->e0, "e0");
195 slice = tmp;
196 return false;
197 }
198 bool preorder(const IR::MethodCallExpression *mce) {
199 BUG("MethodCallExpression not supported in IXBarExprSeed: %s", mce);
200 return false;
201 }
202
203 public:
204 IXBarExprSeed(const IR::Expression *e, le_bitrange sl) : slice(sl) { e->apply(*this); }
205 operator bitvec() const { return rv >> slice.lo; }
206};
207
210 le_bitrange hash_bits;
211 IR::MAU::HashFunction algorithm;
212 cstring dyn_hash_name;
213 LTBitMatrix symmetrically_hashed_inputs;
214 const IR::Expression *hash_gen_expr = nullptr;
215 // FIXME -- we record the expression the hash is derived from so it can be copied to
216 // the IXBar::Use::HashDistHash and then output it in the .bfa file. Perhaps we should
217 // compute the (raw) GFM bits here instead?
218
219 bool is_dynamic() const {
220 bool rv = !dyn_hash_name.isNull();
221 // Symmetric is currently not supported with the dynamic hash library in bf-utils
222 if (rv)
223 BUG_CHECK(symmetrically_hashed_inputs.empty(),
224 "Dynamically hashed values cannot "
225 "have symmetric fields");
226 return rv;
227 }
228 bool equiv_dyn(const P4HashFunction *func) const;
229 bool equiv_inputs_alg(const P4HashFunction *func) const;
230
231 void slice(le_bitrange hash_slice);
232 cstring name() const { return is_dynamic() ? dyn_hash_name : "static_hash"_cs; }
233 int size() const { return hash_bits.size(); }
234 bool equiv(const P4HashFunction *) const;
235 bool is_next_bit_of_hash(const P4HashFunction *) const;
236
237 bool overlap(const P4HashFunction *, le_bitrange *my_overlap, le_bitrange *hash_overlap) const;
238 void dbprint(std::ostream &out) const;
239};
240
249bool verifySymmetricHashPairs(const PhvInfo &phv, safe_vector<const IR::Expression *> &field_list,
250 const IR::Vector<IR::Annotation> &annotations, gress_t gress,
251 const IR::MAU::HashFunction &hf, LTBitMatrix *sym_pairs);
252
265class BuildP4HashFunction : public PassManager {
266 P4HashFunction *_func = nullptr;
267 const PhvInfo &phv;
268
269 Visitor::profile_t init_apply(const IR::Node *node) override {
270 auto rv = PassManager::init_apply(node);
271 _func = nullptr;
272 return rv;
273 }
274
275 class InsideHashGenExpr : public MauInspector {
276 BuildP4HashFunction &self;
278 LTBitMatrix sym_fields;
279
280 enum class State {
281 OUTSIDE,
282 INSIDE,
283 FIELD_LIST,
284 IXBAR_EXPR,
285 } state = State::OUTSIDE;
286
287 Visitor::profile_t init_apply(const IR::Node *node) override {
288 auto rv = MauInspector::init_apply(node);
289 fields.clear();
290 sym_fields.clear();
291 state = State::OUTSIDE;
292 return rv;
293 }
294
295 bool preorder(const IR::MAU::HashGenExpression *) override;
296 bool preorder(const IR::MAU::FieldListExpression *) override;
297 bool preorder(const IR::Constant *) override;
298 bool preorder(const IR::Expression *) override;
299 bool preorder(const IR::MAU::ActionArg *) override;
300 bool preorder(const IR::Mask *) override;
301 bool preorder(const IR::Cast *) override;
302 bool preorder(const IR::Concat *) override;
303 bool preorder(const IR::StructExpression *) override;
304 bool preorder(const IR::ListExpression *) override;
305 void postorder(const IR::BFN::SignExtend *) override;
306 void postorder(const IR::MAU::HashGenExpression *) override;
307
308 public:
309 explicit InsideHashGenExpr(BuildP4HashFunction &s) : self(s) {}
310 };
311
312 class OutsideHashGenExpr : public MauInspector {
313 BuildP4HashFunction &self;
314 bool preorder(const IR::MAU::HashGenExpression *) override;
315 void postorder(const IR::Slice *) override;
316
317 public:
318 explicit OutsideHashGenExpr(BuildP4HashFunction &s) : self(s) {}
319 };
320
321 void end_apply() override;
322
323 public:
324 explicit BuildP4HashFunction(const PhvInfo &p) : phv(p) {
325 addPasses({new InsideHashGenExpr(*this), new OutsideHashGenExpr(*this)});
326 }
327
328 P4HashFunction *func() { return _func; }
329};
330
332 bool preorder(IR::MAU::IXBarExpression *e) override;
333};
334
335#endif /* BF_P4C_MAU_IXBAR_EXPR_H_ */
Definition ixbar_expr.h:331
Definition mau_visitor.h:29
Definition mau_visitor.h:45
Definition stringify.h:33
Definition node.h:94
Definition vector.h:59
Definition visitor.h:413
Definition ltbitmatrix.h:25
Definition visitor.h:78
Definition bitvec.h:120
Definition cstring.h:85
Definition safe_vector.h:27
Definition phv_fields.h:1095
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
Definition hash_function.h:28
T * to() noexcept
Definition rtti.h:226
Definition ixbar_expr.h:208
bool overlap(const P4HashFunction *, le_bitrange *my_overlap, le_bitrange *hash_overlap) const
Definition ixbar_expr.cpp:71
bool equiv_inputs_alg(const P4HashFunction *func) const
Definition ixbar_expr.cpp:42
void slice(le_bitrange hash_slice)
Definition ixbar_expr.cpp:25