19#ifndef BACKENDS_TOFINO_BF_P4C_MAU_ACTION_ANALYSIS_H_
20#define BACKENDS_TOFINO_BF_P4C_MAU_ACTION_ANALYSIS_H_
22#include "bf-p4c/ir/bitrange.h"
23#include "bf-p4c/ir/tofino_write_context.h"
24#include "bf-p4c/mau/mau_visitor.h"
25#include "bf-p4c/mau/reduction_or.h"
26#include "lib/safe_vector.h"
56 enum op_type_t { NONE = 0, DST, SRC1, SRC2, SRC3 };
57 static constexpr int LOADCONST_MAX = 21;
58 static constexpr int CONST_SRC_MAX = 3;
59 static constexpr int JBAY_CONST_SRC_MIN = 2;
60 static constexpr int MAX_PHV_SOURCES = 2;
66 enum type_t {
PHV, ACTIONDATA, CONSTANT, TOTAL_TYPES } type;
67 const IR::Expression *expr;
75 } speciality = NO_SPECIAL;
76 bool is_conditional =
false;
79 ActionParam(type_t t,
const IR::Expression *e) : type(t), expr(e) {}
81 ActionParam(type_t t,
const IR::Expression *e, speciality_t s)
82 : type(t), expr(e), speciality(s) {}
85 BUG_CHECK(expr->type,
"Untyped expression in backend action");
86 return expr->type->width_bits();
90 if (
auto sl = expr->to<IR::Slice>())
91 return {
static_cast<int>(sl->getL()),
static_cast<int>(sl->getH())};
92 return {0, size() - 1};
95 friend std::ostream &operator<<(std::ostream &out,
const ActionParam &);
99 const IR::Expression *unsliced_expr()
const;
101 cstring get_type_string()
const {
104 else if (type == ACTIONDATA)
105 return "ACTIONDATA"_cs;
106 else if (type == CONSTANT)
107 return "CONSTANT"_cs;
108 return "INVALID_TYPE"_cs;
111 cstring get_speciality_string()
const {
112 if (speciality == NO_SPECIAL)
113 return "NO_SPECIAL"_cs;
114 else if (speciality == HASH_DIST)
115 return "HASH_DIST"_cs;
116 else if (speciality == METER_COLOR)
117 return "METER_COLOR"_cs;
118 else if (speciality == RANDOM)
120 else if (speciality == METER_ALU)
121 return "METER_ALU"_cs;
122 else if (speciality == STFUL_COUNTER)
123 return "STFUL_COUNTER"_cs;
124 return "INVALID_SPECIALITY"_cs;
133 bool write_found =
false;
135 const IR::MAU::Instruction *instruction;
148 bool requires_split =
false;
149 bool constant_to_ad =
false;
154 bool is_bitwise_overwritable()
const {
155 return name ==
"and" || name ==
"or" || name ==
"xor" || name ==
"xnor";
158 bool is_single_shift()
const {
return name ==
"shru" || name ==
"shrs" || name ==
"shl"; }
160 bool is_funnel_shift()
const {
return name ==
"funnel-shift"; }
162 bool is_shift()
const {
return is_single_shift() || is_funnel_shift(); }
164 enum container_overwrite_t {
173 enum source_type_t { CONSTANT, ACTION_DATA_CONSTANT, OTHER };
175 std::pair<container_overwrite_t, source_type_t> container_write_type()
const;
179 READ_AFTER_WRITES = 1 << 0,
180 REPEATED_WRITES = 1 << 1,
181 MULTIPLE_ACTION_DATA = 1 << 2,
182 DIFFERENT_OP_SIZE = 1 << 3,
183 BAD_CONDITIONAL_SET = 1 << 4
185 unsigned error_code = 0;
187 friend std::ostream &operator<<(std::ostream &out,
const FieldAction &);
188 std::string to_string()
const;
189 static std::set<unsigned> codesForErrorCases;
202 : write_bits(wb), read_bits(rb), read_src(rs) {}
205 friend std::ostream &operator<<(std::ostream &out,
const Alignment &);
215 bool verbose =
false;
219 bitvec unused_container_bits;
222 bitvec implicit_write_bits;
223 bitvec implicit_read_bits;
225 bitvec write_bits()
const {
return direct_write_bits | implicit_write_bits; }
226 bitvec read_bits()
const {
return direct_read_bits | implicit_read_bits; }
232 bool is_src1 =
false;
235 indiv_alignments.emplace_back(wb, rb);
236 direct_write_bits.setrange(wb.
lo, wb.
size());
237 direct_read_bits.setrange(rb.
lo, rb.
size());
240 bool equiv_bit_totals()
const {
241 return direct_write_bits.popcount() == direct_read_bits.popcount();
250 bool contiguous()
const;
266 return write_bits().max().index() - write_bits().min().index() + 1;
269 bool bitrange_contiguous()
const {
return write_bits().is_contiguous(); }
279 rv.indiv_alignments.insert(rv.indiv_alignments.end(), indiv_alignments.begin(),
280 indiv_alignments.end());
281 rv.indiv_alignments.insert(rv.indiv_alignments.begin(), ta.indiv_alignments.begin(),
282 ta.indiv_alignments.end());
284 rv.direct_write_bits = direct_write_bits | ta.direct_write_bits;
285 rv.direct_read_bits = direct_read_bits | ta.direct_read_bits;
286 rv.unused_container_bits = unused_container_bits | ta.unused_container_bits;
287 rv.verbose = verbose | ta.verbose;
290 friend std::ostream &operator<<(std::ostream &out,
const TotalAlignment &);
298 bool initialized =
false;
302 bool immediate =
false;
304 int total_field_affects = 0;
305 int field_affects = 0;
309 void initialize(
cstring adn,
bool imm,
int s,
int tfa) {
311 action_data_name = adn;
314 total_field_affects = tfa;
330 bool initialized =
false;
333 int container_size = -1;
334 unsigned build_constant();
337 unsigned constant_value;
338 bool signExtend =
false;
347 bool verbose =
false;
348 bool convert_instr_to_deposit_field =
false;
351 bool total_overwrite_possible =
false;
353 bool is_deposit_field_variant =
false;
356 bool implicit_src1 =
false;
361 bool unhandled_action =
false;
362 bool constant_to_ad =
false;
369 MULTIPLE_CONTAINER_ACTIONS = (1 << 0),
370 READ_PHV_MISMATCH = (1 << 1),
371 ACTION_DATA_MISMATCH = (1 << 2),
372 CONSTANT_MISMATCH = (1 << 3),
373 TOO_MANY_PHV_SOURCES = (1 << 4),
374 IMPOSSIBLE_ALIGNMENT = (1 << 5),
375 CONSTANT_TO_ACTION_DATA = (1 << 6),
376 MULTIPLE_ACTION_DATA = (1 << 7),
377 ILLEGAL_OVERWRITE = (1 << 8),
378 BIT_COLLISION = (1 << 9),
379 OPERAND_MISMATCH = (1 << 10),
380 UNHANDLED_ACTION_DATA = (1 << 11),
381 DIFFERENT_READ_SIZE = (1 << 12),
382 MAU_GROUP_MISMATCH = (1 << 13),
383 PHV_AND_ACTION_DATA = (1 << 14),
384 PARTIAL_OVERWRITE = (1 << 15),
385 MULTIPLE_SHIFTS = (1 << 16),
386 ILLEGAL_ACTION_DATA = (1 << 17),
387 REFORMAT_CONSTANT = (1 << 18),
388 UNRESOLVED_REPEATED_ACTION_DATA = (1 << 19),
389 ATTACHED_OUTPUT_ILLEGAL_ALIGNMENT = (1 << 20),
390 CONSTANT_TO_HASH = (1 << 21),
391 ILLEGAL_MOCHA_OR_DARK_WRITE = (1 << 22),
392 BIT_COLLISION_SET = (1 << 23),
393 MULTIPLE_SPECIALITIES = (1 << 24)
395 unsigned error_code = NO_PROBLEM;
396 static const std::vector<cstring> error_code_string_t;
399 const IR::MAU::Table *table_context =
nullptr;
402 bitvec invalidate_write_bits;
409 std::multimap<PHV::Container, TotalAlignment> phv_alignment;
410 bool is_background_source =
false;
413 static std::set<unsigned> codesForErrorCases;
415 int counts[ActionParam::TOTAL_TYPES] = {0, 0, 0};
419 ContainerAction(
cstring n,
const IR::MAU::Table *tbl) : name(n), table_context(tbl) {}
422 return counts[ActionParam::PHV] + counts[ActionParam::ACTIONDATA] +
423 counts[ActionParam::CONSTANT];
426 bool is_single_shift()
const {
return name ==
"shru" || name ==
"shrs" || name ==
"shl"; }
428 bool is_funnel_shift()
const {
return name ==
"funnel-shift"; }
430 bool is_shift()
const {
return is_single_shift() || is_funnel_shift(); }
437 int rv = adi.alignment.indiv_alignments.size() + ci.alignment.indiv_alignments.size();
438 for (
auto pa : phv_alignment) rv += pa.second.indiv_alignments.size();
442 int operands()
const {
443 if (name ==
"to-bitmasked-set" || is_single_shift())
445 else if (is_funnel_shift())
448 if (field_actions.size() == 0)
449 BUG(
"Cannot call operands function on empty container process");
450 return field_actions[0].reads.size();
453 int ad_sources()
const {
454 return std::min(1, counts[ActionParam::ACTIONDATA] + counts[ActionParam::CONSTANT]);
457 int read_sources()
const {
return ad_sources() + counts[ActionParam::PHV]; }
459 bool is_from_set()
const {
return name ==
"set" || name ==
"to-bitmasked-set"; }
461 bool has_ad_or_constant()
const {
return ad_sources() > 0; }
463 bool partial_overwrite()
const {
464 return ((error_code & PARTIAL_OVERWRITE) != 0 && !convert_instr_to_deposit_field) ||
468 bool unresolved_ad()
const {
return (error_code & UNRESOLVED_REPEATED_ACTION_DATA) != 0; }
470 bool ad_renamed()
const {
return adi.field_affects > 1 || unresolved_ad(); }
472 bool no_sources()
const {
return name ==
"invalidate"; }
474 void set_mismatch(ActionParam::type_t type);
476 bool action_data_isolated()
const {
return !is_from_set(); }
478 bool set_invalidate_write_bits(
le_bitrange write) {
479 if (name !=
"invalidate")
return false;
480 invalidate_write_bits.setrange(write.
lo, write.
size());
484 bool is_total_overwrite_possible() {
return total_overwrite_possible && !is_shift(); }
495 bool verify_one_alignment(TotalAlignment &tot_alignment,
int size,
int &unaligned_count,
496 int &non_contiguous_count);
508 void determine_src1();
511 bitvec specialities()
const;
513 bitvec total_write()
const;
514 bool convert_constant_to_actiondata()
const {
515 return (error_code & CONSTANT_TO_ACTION_DATA) != 0;
518 bool convert_constant_to_hash()
const {
return (error_code & CONSTANT_TO_HASH) != 0; }
520 bool is_commutative()
const {
521 return (name ==
"add") || (name ==
"addc") || (name ==
"saddu") || (name ==
"sadds") ||
522 (name ==
"minu") || (name ==
"mins") || (name ==
"maxu") || (name ==
"maxs") ||
523 (name ==
"setz") || (name ==
"nor") || (name ==
"xor") || (name ==
"nand") ||
524 (name ==
"and") || (name ==
"xnor") || (name ==
"or") || (name ==
"sethi");
527 bool verify_multiple_action_data()
const;
529 friend std::ostream &operator<<(std::ostream &out,
const ContainerAction &);
530 std::string to_string()
const;
534 typedef std::map<PHV::Container, ContainerAction> ContainerActionsMap;
538 bool phv_alloc =
false;
539 bool ad_alloc =
false;
540 bool has_warning =
false;
541 bool has_error =
false;
542 bool allow_unalloc =
false;
543 bool sequential =
true;
545 bool action_data_misaligned =
false;
546 bool verbose =
false;
547 bool error_verbose =
false;
549 FieldActionsMap *field_actions_map =
nullptr;
550 ContainerActionsMap *container_actions_map =
nullptr;
551 const IR::MAU::Table *tbl;
553 FieldAction field_action;
557 void initialize_phv_field(
const IR::Expression *expr);
558 void initialize_action_data(
const IR::Expression *expr);
559 ActionParam::speciality_t classify_attached_output(
const IR::MAU::AttachedOutput *);
560 bool preorder(
const IR::MAU::Action *)
override {
564 bool preorder(
const IR::MAU::Table *)
override {
568 bool preorder(
const IR::MAU::TableSeq *)
override {
572 bool preorder(
const IR::Annotation *)
override {
return false; }
574 bool preorder(
const IR::Slice *)
override;
575 bool preorder(
const IR::MAU::ActionArg *)
override;
576 bool preorder(
const IR::MAU::ConditionalArg *)
override;
577 bool preorder(
const IR::Cast *)
override;
578 bool preorder(
const IR::Expression *)
override;
579 bool preorder(
const IR::Mux *)
override;
580 bool preorder(
const IR::Member *)
override;
581 bool preorder(
const IR::MAU::ActionDataConstant *)
override;
582 bool preorder(
const IR::Constant *)
override;
583 bool preorder(
const IR::MAU::AttachedOutput *)
override;
584 bool preorder(
const IR::MAU::HashDist *)
override;
585 bool preorder(
const IR::MAU::IXBarExpression *)
override;
586 bool preorder(
const IR::MAU::RandomNumber *)
override;
587 bool preorder(
const IR::MAU::StatefulAlu *)
override;
588 bool preorder(
const IR::MAU::Instruction *)
override;
589 bool preorder(
const IR::MAU::StatefulCall *)
override;
590 bool preorder(
const IR::MAU::StatefulCounter *sc)
override;
591 bool preorder(
const IR::MAU::Primitive *)
override;
592 void postorder(
const IR::MAU::Instruction *)
override;
593 void postorder(
const IR::MAU::Action *)
override;
594 bool preorder(
const IR::BFN::ReinterpretCast *cast)
override;
596 bool initialize_invalidate_alignment(
const ActionParam &write, ContainerAction &cont_action);
597 bool initialize_alignment(
const ActionParam &write,
const ActionParam &read,
598 const op_type_t read_src, ContainerAction &cont_action,
601 bool init_phv_alignment(
const ActionParam &read,
const op_type_t read_src,
602 ContainerAction &cont_action,
le_bitrange write_bits,
604 bool init_special_alignment(
const ActionParam &read, ContainerAction &cont_action,
607 bool init_ad_alloc_alignment(
const ActionParam &read, ContainerAction &cont_action,
610 bool init_hash_constant_alignment(
const ActionParam &read, ContainerAction &cont_action,
613 bool init_constant_alignment(
const ActionParam &read, ContainerAction &cont_action,
616 bool init_simple_alignment(
const ActionParam &read, ContainerAction &cont_action,
618 void initialize_constant(
const ActionParam &read, ContainerAction &cont_action,
620 void build_phv_alignment(
PHV::Container container, ContainerAction &cont_action);
621 void determine_unused_bits(
PHV::Container container, ContainerAction &cont_action);
623 void check_constant_to_actiondata(ContainerAction &cont_action,
PHV::Container container);
624 void add_to_single_ad_params(ContainerAction &cont_action);
625 void check_single_ad_params(ContainerAction &cont_action);
627 void verify_conditional_set_without_phv(
cstring action_name, FieldAction &fa);
629 void verify_P4_action_for_tofino(
cstring action_name);
630 void verify_P4_action_without_phv(
cstring action_name);
631 void verify_P4_action_with_phv(
cstring action_name);
633 bool is_allowed_unalloc(
const IR::Expression *e) {
634 if (!allow_unalloc)
return false;
635 while (
auto *sl = e->to<IR::Slice>()) e = sl->e0;
636 return e->is<IR::TempVar>();
641 ActionParam::type_t *type =
nullptr);
643 const IR::MAU::ActionArg *isActionArg(
const IR::Expression *expr,
645 bool isReductionOr(ContainerAction &cont_action)
const;
647 bool misaligned_actiondata() {
return action_data_misaligned; }
649 void set_field_actions_map(FieldActionsMap *fam) {
650 if (ad_alloc ==
true)
return;
651 field_actions_map = fam;
654 void set_container_actions_map(ContainerActionsMap *cam) {
655 if (phv_alloc ==
false)
return;
656 container_actions_map = cam;
659 void set_verbose() { verbose =
true; }
660 void set_error_verbose() { error_verbose =
true; }
661 bool warning_found()
const {
return has_warning; }
662 bool error_found()
const {
return has_error; }
663 bool get_phv_alloc()
const {
return phv_alloc; }
664 bool get_ad_alloc()
const {
return ad_alloc; }
665 bool get_allow_unalloc()
const {
return allow_unalloc; }
666 bool get_sequential()
const {
return sequential; }
667 bool get_action_data_misaligned()
const {
return action_data_misaligned; }
668 bool get_verbose()
const {
return verbose; }
669 bool get_error_verbose()
const {
return error_verbose; }
670 const IR::MAU::Table *get_table()
const {
return tbl; }
671 const ContainerActionsMap *get_container_actions_map()
const {
return container_actions_map; }
682 visitDagOnce =
false;
686std::ostream &operator<<(std::ostream &out,
const ActionAnalysis &);
Definition action_analysis.h:54
const IR::Expression * isStrengthReducible(const IR::Expression *expr)
Definition mau/action_analysis.cpp:339
const IR::Expression * isActionParam(const IR::Expression *expr, le_bitrange *bits_out=nullptr, ActionParam::type_t *type=nullptr)
Definition mau/action_analysis.cpp:304
Definition mau_visitor.h:29
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition safe_vector.h:27
Definition phv_fields.h:1095
Definition tofino_write_context.h:24
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
The namespace encapsulating PHV-related stuff.
Definition gateway.h:32
Definition action_analysis.h:297
Definition action_analysis.h:65
std::string to_string() const
Definition mau/action_analysis.cpp:126
Definition action_analysis.h:197
Definition action_analysis.h:329
unsigned build_shiftable_constant()
Definition mau/action_analysis.cpp:213
unsigned valid_instruction_constant(int container_size) const
Definition mau/action_analysis.cpp:232
Definition action_analysis.h:321
Definition action_analysis.h:346
bool verify_overwritten(PHV::Container container, const PhvInfo &phv)
Definition mau/action_analysis.cpp:2144
void determine_implicit_bits(PHV::Container container, TotalAlignment &ad_alignment)
Definition mau/action_analysis.cpp:1960
bool implicit_src2
Definition action_analysis.h:359
bool verify_deposit_field_variant(PHV::Container container, TotalAlignment &ad_alignment)
Definition mau/action_analysis.cpp:1659
bool verify_possible(cstring &error_message, PHV::Container container, cstring action_name, const PhvInfo &phv)
Definition mau/action_analysis.cpp:2717
bool verify_source_to_bit(int operands, PHV::Container container)
Definition mau/action_analysis.cpp:2499
int alignment_counts() const
Definition action_analysis.h:436
bool verify_set_alignment(PHV::Container, TotalAlignment &ad_alignment)
Definition mau/action_analysis.cpp:1784
bool convert_instr_to_byte_rotate_merge
Definition action_analysis.h:350
bool verify_only_read(const PhvInfo &phv, int num_source)
Definition mau/action_analysis.cpp:2287
error_code_t
Definition action_analysis.h:367
bool is_byte_rotate_merge(PHV::Container container, TotalAlignment &ad_alignment)
Definition mau/action_analysis.cpp:1627
bool verify_speciality(cstring &error_message, PHV::Container container, cstring action_name)
Definition mau/action_analysis.cpp:2568
bool verify_shift(cstring &error_message, PHV::Container container, const PhvInfo &phv)
Definition mau/action_analysis.cpp:2643
bool convert_instr_to_bitmasked_set
Definition action_analysis.h:349
bool impossible
Definition action_analysis.h:360
bool verify_phv_mau_group(PHV::Container container)
Definition mau/action_analysis.cpp:2535
Definition action_analysis.h:132
Definition action_analysis.h:214
int right_shift
Definition action_analysis.h:231
bool deposit_field_src1() const
Definition mau/action_analysis.cpp:1571
bitvec df_src2_mask(PHV::Container container) const
Definition mau/action_analysis.cpp:1433
bool verify_individual_alignments(PHV::Container &container)
Definition mau/action_analysis.cpp:1540
bitvec brm_src_mask(PHV::Container container) const
Definition mau/action_analysis.cpp:1597
bitvec df_src1_mask() const
Definition mau/action_analysis.cpp:1414
int bitrange_cover_size() const
Definition action_analysis.h:265
bool deposit_field_src2(PHV::Container container) const
Definition mau/action_analysis.cpp:1577
int bitrange_contiguous_size() const
Definition action_analysis.h:273
bitvec byte_rotate_merge_byte_mask(PHV::Container container) const
Definition mau/action_analysis.cpp:1609
bool is_wrapped_shift(PHV::Container container, int *lo=nullptr, int *hi=nullptr) const
Definition mau/action_analysis.cpp:1500
int lo
Definition lib/bitrange.h:694
ssize_t size() const
Definition lib/bitrange.h:539
Definition reduction_or.h:47