19#ifndef BF_P4C_MAU_ASM_FORMAT_HASH_H_
20#define BF_P4C_MAU_ASM_FORMAT_HASH_H_
29#include "backends/tofino/bf-p4c/common/ir_utils.h"
30#include "backends/tofino/bf-p4c/common/slice.h"
31#include "backends/tofino/bf-p4c/ir/tofino_write_context.h"
32#include "backends/tofino/bf-p4c/lib/error_type.h"
33#include "backends/tofino/bf-p4c/mau/asm_output.h"
34#include "backends/tofino/bf-p4c/phv/asm_output.h"
35#include "boost/range/adaptor/reversed.hpp"
36#include "lib/algorithm.h"
37#include "lib/bitops.h"
38#include "lib/bitrange.h"
40#include "lib/indent.h"
41#include "lib/stringref.h"
46 using RangeOfConstant = std::map<le_bitrange, const IR::Constant *>;
48 const std::multimap<int, Slice> *match_data_map;
49 const RangeOfConstant *constant_map;
56 const std::map<le_bitrange, const IR::Constant *> *cm,
const Slice *g,
65 BUG_CHECK(match_data ==
nullptr || match_data_map ==
nullptr,
67 "configured correctly");
79inline std::ostream &operator<<(std::ostream &out,
const FormatHash &hash) {
80 if (hash.field_range !=
nullptr) {
81 FormatHash hash2(hash.match_data, hash.match_data_map, hash.constant_map, hash.ghost,
82 hash.func, hash.total_bits);
83 out <<
"slice(" << hash2 <<
", " << hash.field_range->lo <<
"..";
84 out << hash.field_range->hi <<
")";
88 if (hash.func.type == IR::MAU::HashFunction::IDENTITY) {
89 BUG_CHECK(hash.match_data,
"For an identity, must be a standard vector");
90 out <<
"stripe(" << emit_vector(*hash.match_data) <<
")";
91 }
else if (hash.func.type == IR::MAU::HashFunction::RANDOM) {
92 BUG_CHECK(hash.match_data,
"For a random, must be a standard vector");
93 if (!hash.match_data->empty()) {
94 out <<
"random(" << emit_vector(*hash.match_data,
", ") <<
")";
95 if (hash.ghost) out <<
" ^ ";
100 }
else if (hash.func.type == IR::MAU::HashFunction::CRC) {
101 BUG_CHECK(hash.match_data_map,
"For a crc, must be a map");
103 if (hash.func.reverse) out <<
"_rev";
104 out <<
"(0x" <<
hex(hash.func.poly) <<
", ";
105 out <<
"0x" <<
hex(hash.func.init) <<
", ";
106 out <<
"0x" <<
hex(hash.func.final_xor) <<
", ";
107 out << hash.total_bits <<
", ";
108 out << *hash.match_data_map;
111 if (hash.constant_map) {
113 const char *sep =
" ";
114 for (
const auto &kv : *hash.constant_map) {
115 out << sep << kv.first.lo <<
".." << kv.first.hi <<
": " << kv.second;
123 }
else if (hash.func.type == IR::MAU::HashFunction::XOR) {
126 BUG_CHECK(hash.match_data_map,
"For a xor, must be a map");
127 out <<
"stripe(xor(" <<
"0x" <<
hex(hash.func.size) <<
", " << *hash.match_data_map <<
"))";
128 }
else if (hash.func.type == IR::MAU::HashFunction::CSUM) {
129 BUG(
"csum hashing algorithm not supported");
131 BUG(
"unknown hashing algorithm %d", hash.func.type);
144 bool preorder(
const IR::Annotation *) {
return false; }
145 bool preorder(
const IR::Type *) {
return false; }
146 bool preorder(
const IR::BXor *) {
return true; }
147 bool preorder(
const IR::BAnd *) {
return true; }
148 bool preorder(
const IR::BOr *) {
return true; }
149 bool preorder(
const IR::Constant *c) {
150 if (getParent<IR::BOr>()) {
152 big_int v = c->value >> bit;
156 while (((v >> w) & 1) == b) ++w;
157 if (width > w) width = w;
162 bool preorder(
const IR::Concat *e) {
163 if (bit < e->right->type->width_bits()) {
164 if (width > e->right->type->width_bits() - bit)
165 width = e->right->type->width_bits() - bit;
166 visit(e->right,
"right");
169 bit -= e->right->type->width_bits();
170 BUG_CHECK(bit < e->left->type->width_bits(),
"bit out of range in SliceWidth");
171 if (width > e->left->type->width_bits() - bit)
172 width = e->left->type->width_bits() - bit;
173 visit(e->left,
"left");
178 bool preorder(
const IR::ListExpression *fl) {
180 for (
auto *e : boost::adaptors::reverse(fl->components)) {
181 if (bit < e->type->width_bits()) {
182 if (width > e->type->width_bits() - bit) width = e->type->width_bits() - bit;
186 bit -= e->type->width_bits();
191 bool preorder(
const IR::StructExpression *sl) {
193 for (
auto *e : boost::adaptors::reverse(sl->components)) {
194 if (bit < e->expression->type->width_bits()) {
195 if (width > e->expression->type->width_bits() - bit)
196 width = e->expression->type->width_bits() - bit;
197 visit(e->expression);
200 bit -= e->expression->type->width_bits();
205 bool preorder(
const IR::BFN::SignExtend *e) {
206 int w = e->type->width_bits() - bit;
207 if (width > w) width = w;
210 if (width < w && width >= e->expr->type->width_bits()) width = w;
213 bool preorder(
const IR::Expression *e) {
214 int w = e->type->width_bits() - bit;
215 if (width > w) width = w;
216 Slice sl(phv, e, bit, bit + width - 1);
217 BUG_CHECK(sl,
"Invalid expression %s in FormatHash::SliceWidth", e);
218 for (
auto &md : match_data) {
219 if (
auto tmp = sl & md) {
220 if (tmp.get_lo() > sl.get_lo()) {
221 w = tmp.get_lo() - sl.get_lo();
222 if (width > w) width = w;
225 if (width > tmp.width()) width = tmp.width();
234 : phv(p), match_data(md), bit(b), width(e->type->width_bits() - b) {
237 operator int()
const {
return width; }
247 bool preorder(
const IR::Annotation *) {
return false; }
248 bool preorder(
const IR::Type *) {
return false; }
249 bool preorder(
const IR::BXor *e) {
251 visit(e->left,
"left");
254 visit(e->right,
"right");
259 bool preorder(
const IR::BAnd *) {
return true; }
260 bool preorder(
const IR::BOr *) {
return true; }
261 bool preorder(
const IR::BFN::SignExtend *) {
return true; }
262 bool preorder(
const IR::Constant *k) {
263 if (getParent<IR::BAnd>() || getParent<IR::BOr>()) {
264 big_int v = k->value, mask = 1;
266 mask <<= slice.
size();
269 if (getParent<IR::BAnd>()) {
270 if (v == 0) rv =
true;
271 }
else if (v == mask) {
274 BUG_CHECK(v == 0,
"Incorrect slicing of BOr in hash expression");
281 bool preorder(
const IR::Concat *e) {
282 int rwidth = e->right->type->width_bits();
283 if (slice.
lo < rwidth) {
284 BUG_CHECK(slice.
hi < rwidth,
"Slice too wide in FormatHash::ZeroHash");
285 visit(e->right,
"right");
289 visit(e->left,
"left");
294 bool preorder(
const IR::ListExpression *fl) {
296 for (
auto *e : boost::adaptors::reverse(fl->components)) {
297 int width = e->type->width_bits();
298 if (slice.
lo < width) {
299 BUG_CHECK(slice.
hi < width,
"Slice too wide in FormatHash::ZeroHash");
308 bool preorder(
const IR::StructExpression *sl) {
310 for (
auto *e : boost::adaptors::reverse(sl->components)) {
311 int width = e->expression->type->width_bits();
312 if (slice.
lo < width) {
313 BUG_CHECK(slice.
hi < width,
"Slice too wide in FormatHash::ZeroHash");
322 bool preorder(
const IR::Expression *e) {
323 Slice sl(phv, e, slice);
324 BUG_CHECK(sl,
"Invalid expression %s in FormatHash::ZeroHash", e);
325 for (
auto &md : match_data) {
326 if (
auto tmp = sl & md) {
336 : phv(p), slice(s), match_data(md) {
339 explicit operator bool()
const {
return rv; }
348 bool preorder(
const IR::Annotation *) {
return false; }
349 bool preorder(
const IR::Type *) {
return false; }
350 bool preorder(
const IR::BXor *e) {
351 bool need_left = !
ZeroHash(phv, e->left, slice, match_data);
352 bool need_right = !
ZeroHash(phv, e->right, slice, match_data);
353 if (need_left) visit(e->left,
"left");
354 if (need_left && need_right) out <<
" ^ ";
355 if (need_right) visit(e->right,
"right");
358 bool preorder(
const IR::BAnd *e) {
359 visit(e->left,
"left");
361 visit(e->right,
"right");
364 bool preorder(
const IR::BOr *e) {
365 auto k = e->left->to<IR::Constant>();
366 auto &op = k ? e->right : e->left;
367 if (!k) k = e->right->to<IR::Constant>();
368 big_int v = k->value >> slice.
lo;
376 bool preorder(
const IR::Constant *k) {
377 big_int v = k->value, mask = 1;
379 mask <<= slice.
size();
382 out <<
"0x" << std::hex << v << std::dec;
385 bool preorder(
const IR::Concat *e) {
386 if (slice.
lo < e->right->type->width_bits()) {
387 visit(e->right,
"right");
391 visit(e->left,
"left");
396 bool preorder(
const IR::ListExpression *fl) {
398 for (
auto *e : boost::adaptors::reverse(fl->components)) {
399 if (slice.
lo < e->type->width_bits()) {
408 bool preorder(
const IR::StructExpression *sl) {
410 for (
auto *e : boost::adaptors::reverse(sl->components)) {
411 if (slice.
lo < e->expression->type->width_bits()) {
412 visit(e->expression);
415 slice = slice.
shiftedByBits(-e->expression->type->width_bits());
420 bool preorder(
const IR::BFN::SignExtend *e) {
421 if (slice.
hi < e->expr->type->width_bits()) {
427 slice.
hi = e->expr->type->width_bits() - 1;
428 out <<
"sign_extend(";
429 visit(e->expr,
"expr");
434 bool preorder(
const IR::Expression *e) {
435 Slice sl(phv, e, slice);
436 BUG_CHECK(sl,
"Invalid expression %s in FormatHash::Output", e);
437 for (
auto &md : match_data) {
438 if (
auto tmp = sl & md) {
449 : phv(p), out(o), slice(s), match_data(md) {
Definition safe_vector.h:27
Definition phv_fields.h:1095
Definition common/asm_output.h:47
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
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