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