P4C
The P4 Compiler
Loading...
Searching...
No Matches
decaf.h
1
19#ifndef BF_P4C_PARDE_DECAF_H_
20#define BF_P4C_PARDE_DECAF_H_
21
22#include "backends/tofino/bf-p4c/common/field_defuse.h"
23#include "backends/tofino/bf-p4c/lib/assoc.h"
24#include "backends/tofino/bf-p4c/logging/pass_manager.h"
25#include "backends/tofino/bf-p4c/mau/mau_visitor.h"
26#include "backends/tofino/bf-p4c/mau/table_dependency_graph.h"
27#include "backends/tofino/bf-p4c/parde/create_pov_encoder.h"
28#include "backends/tofino/bf-p4c/parde/parde_visitor.h"
29
117struct Value {
118 const PHV::Field *field = nullptr;
119 const IR::Constant *constant = nullptr;
120
121 Value() {}
122 explicit Value(const PHV::Field *f) : field(f) {}
123 explicit Value(const IR::Constant *c) : constant(c) {}
124
125 explicit Value(const Value &other) : field(other.field), constant(other.constant) {
126 if (field && constant) BUG("Value cannot be both field and constant");
127 }
128
129 Value &operator=(const Value &other) {
130 field = other.field;
131 constant = other.constant;
132 if (field && constant) BUG("Value cannot be both field and constant");
133 return *this;
134 }
135
136 std::string print() const {
137 std::stringstream ss;
138 if (field)
139 ss << field->name;
140 else if (constant)
141 ss << "0x" << std::hex << constant << std::dec;
142 return ss.str();
143 }
144
145 bool operator<(const Value &other) const {
146 if (field && other.field)
147 return field->id < other.field->id;
148 else if (constant && other.constant)
149 return constant->value < other.constant->value;
150 else if (field && other.constant)
151 return false;
152 else if (constant && other.field)
153 return true;
154
155 BUG("Value is neither constant nor field?");
156 }
157
158 bool operator==(const Value &other) const {
159 if (field != other.field) {
160 return false;
161 } else if (constant && other.constant) {
162 if (!constant->equiv(*(other.constant))) return false;
163 } else if (constant != other.constant) {
164 return false;
165 }
166
167 return true;
168 }
169};
170
174struct Assign {
175 Assign(const IR::MAU::Instruction *instr, const PHV::Field *dst, const IR::Constant *src)
176 : dst(dst), src(new Value(src)), instr(instr) {}
177
178 Assign(const IR::MAU::Instruction *instr, const PHV::Field *dst, const PHV::Field *src)
179 : dst(dst), src(new Value(src)), instr(instr) {}
180
181 std::string print() const {
182 std::stringstream ss;
183 ss << dst->name << " <= " << src->print();
184 return ss.str();
185 }
186
187 const PHV::Field *dst;
188 const Value *src;
189
190 const IR::MAU::Instruction *instr = nullptr;
191};
192
196class AssignChain : public std::vector<const Assign *> {
197 public:
198 void push_front(const Assign *assign) { insert(begin(), assign); }
199
200 bool contains(const IR::MAU::Instruction *instr) const {
201 for (auto &assign : *this) {
202 if (assign->instr == instr) return true;
203 }
204
205 return false;
206 }
207};
208
212struct FieldGroup : public ordered_set<const PHV::Field *> {
213 FieldGroup() {}
214 explicit FieldGroup(int i) : id(i) {}
215 int id = -1;
216};
217
222 const PhvInfo &phv;
223
225
227
231
232 explicit CollectHeaderValidity(const PhvInfo &phv) : phv(phv) {}
233
234 const IR::Expression *get_valid_bit_expr(const PHV::Field *f) const {
235 auto vld = field_to_valid_bit.at(f);
236 return field_to_expr.at(vld);
237 }
238
239 // bool preorder(const IR::BFN::Extract* extract) override {
240 // // TODO
241 // return false;
242 // }
243
244 bool preorder(const IR::MAU::Instruction *instr) override {
245 auto action = findContext<IR::MAU::Action>();
246
247 if (instr->operands.size() != 2) return false;
248
249 auto dst = instr->operands[0];
250 auto f_dst = phv.field(dst);
251
252 if (f_dst && f_dst->pov) {
253 auto src = instr->operands[1];
254 auto c = src->to<IR::Constant>();
255 if (c) {
256 if (c->equiv(IR::Constant(IR::Type::Bits::get(1), 1)))
257 validate_to_action[f_dst].insert(action);
258 else if (c->equiv(IR::Constant(IR::Type::Bits::get(1), 0)))
259 invalidate_to_action[f_dst].insert(action);
260 }
261 }
262
263 return false;
264 }
265
266 bool preorder(const IR::BFN::Emit *emit) override {
267 auto pov_bit = emit->povBit->field;
268 auto f_pov_bit = phv.field(pov_bit);
269 field_to_expr[f_pov_bit] = pov_bit;
270
271 if (auto ef = emit->to<IR::BFN::EmitField>()) {
272 auto f = phv.field(ef->source->field);
273 field_to_valid_bit[f] = f_pov_bit;
274 } else if (auto ec = emit->to<IR::BFN::EmitChecksum>()) {
275 auto f = phv.field(ec->dest->field);
276 field_to_valid_bit[f] = f_pov_bit;
277 } else {
278 BUG("Unknown deparser emit type %1%", emit);
279 }
280
281 return false;
282 }
283
284 void end_apply() override {
285 LOG4(*this);
286 LOG1("=== DONE collecting header validity bits ===");
287 }
288
289 void dbprint(std::ostream &out) const override {
290 for (auto &kv : field_to_valid_bit)
291 out << kv.first->name << " : " << kv.second->name << std::endl;
292 }
293};
294
305 const PhvInfo &phv;
306 const PhvUse &uses;
307 const FieldDefUse &defuse;
308 const DependencyGraph &dg;
309
310 FieldGroup strong_fields;
311
314
315 public:
317 FieldGroup read_only_weak_fields;
318 std::map<gress_t, ordered_set<const IR::Constant *>> all_constants;
319
320 CollectWeakFields(const PhvInfo &phv, const PhvUse &uses, const FieldDefUse &defuse,
321 const DependencyGraph &dg)
322 : phv(phv), uses(uses), defuse(defuse), dg(dg) {
323 joinFlows = true;
324 visitDagOnce = false;
325 BackwardsCompatibleBroken = true;
326 }
327
328 const IR::MAU::Action *get_action(const Assign *assign) const {
329 auto action = instr_to_action.at(assign->instr);
330 return action;
331 }
332
333 const IR::MAU::Table *get_table(const Assign *assign) const {
334 auto action = instr_to_action.at(assign->instr);
335 auto table = action_to_table.at(action);
336 return table;
337 }
338
339 std::string print_assign_context(const Assign *assign) const {
340 auto action = instr_to_action.at(assign->instr);
341 auto table = action_to_table.at(action);
342
343 std::stringstream ss;
344 ss << "(" << table->name << " : " << action->name << ")";
345 return ss.str();
346 }
347
348 std::string print_assign(const Assign *assign) const {
349 std::stringstream ss;
350
351 ss << assign->print();
352 ss << " : ";
353 ss << print_assign_context(assign);
354 return ss.str();
355 }
356
357 void remove_weak_field(const PHV::Field *field) {
358 field_to_weak_assigns.erase(field);
359 read_only_weak_fields.erase(field);
360 // TODO remove constants for field
361 }
362
363 void dbprint(std::ostream &out) const override;
364
365 private:
366 bool filter_join_point(const IR::Node *) override { return true; }
367
368 void flow_merge(Visitor &other_) override {
369 CollectWeakFields &other = dynamic_cast<CollectWeakFields &>(other_);
370
371 for (auto &kv : other.field_to_weak_assigns) {
372 for (auto a : kv.second) field_to_weak_assigns[kv.first].insert(a);
373 }
374
375 strong_fields.insert(other.strong_fields.begin(), other.strong_fields.end());
376
377 for (auto a : strong_fields) add_strong_field(a);
378
379 for (auto &kv : other.instr_to_action) instr_to_action[kv.first] = kv.second;
380
381 for (auto &kv : other.action_to_table) action_to_table[kv.first] = kv.second;
382 }
383
384 void flow_copy(::ControlFlowVisitor &other_) override {
385 CollectWeakFields &other = dynamic_cast<CollectWeakFields &>(other_);
386 field_to_weak_assigns = other.field_to_weak_assigns;
387 strong_fields = other.strong_fields;
388 instr_to_action = other.instr_to_action;
389 action_to_table = other.action_to_table;
390 // FIXME what about read_only_weak_fields and all_constants? They're not merged
391 // in flow_merge, so perhaps don't need to be copied?
392 }
393
394 CollectWeakFields *clone() const override { return new CollectWeakFields(*this); }
395
396 Visitor::profile_t init_apply(const IR::Node *root) override {
397 auto rv = Inspector::init_apply(root);
398
399 field_to_weak_assigns.clear();
400 strong_fields.clear();
401
402 instr_to_action.clear();
403 action_to_table.clear();
404
405 return rv;
406 }
407
408 void end_apply() override {
409 add_read_only_weak_fields();
410
411 elim_by_strong_transitivity();
412
413 elim_non_byte_aligned_fields();
414
415 // elim_if_too_few_weak_fields();
416
417 get_all_constants();
418
419 LOG3(*this);
420 LOG1("=== DONE collecting weak fields ===");
421 }
422
423 void add_weak_assign(const PHV::Field *dst, const PHV::Field *field_src,
424 const IR::Constant *const_src, const IR::MAU::Instruction *instr);
425
426 void add_strong_field(const PHV::Field *f, std::string reason = "");
427
428 static bool other_elim_reason(const PHV::Field *f) {
429 return !f->deparsed() || // we need the weak field's value to reach deparser
430 f->pov || f->metadata || f->bridged || f->is_digest() || f->is_intrinsic();
431 }
432
433 bool preorder(const IR::MAU::TableKey *ixbar) override;
434 bool preorder(const IR::MAU::StatefulAlu *) override { return false; }
435 bool preorder(const IR::MAU::Instruction *instr) override;
436
437 // returns true if all defs of src happen before dst
438 bool all_defs_happen_before(const PHV::Field *src, const PHV::Field *dst);
439 bool is_strong_by_transitivity(const PHV::Field *dst, const PHV::Field *src,
441 bool is_strong_by_transitivity(const PHV::Field *dst);
442
443 void add_read_only_weak_fields();
444 void get_all_constants();
445
446 void elim_by_strong_transitivity();
447 void elim_non_byte_aligned_fields();
448};
449
458 public:
459 std::vector<FieldGroup> weak_field_groups;
460
462
463 CollectWeakFields &weak_fields;
464
465 public:
466 explicit ComputeValuesAtDeparser(CollectWeakFields &weak_fields) : weak_fields(weak_fields) {}
467
468 bool is_weak_assign(const IR::MAU::Instruction *instr) const;
469
470 std::string print_assign_chain(const AssignChain &chain) const;
471 std::string print_assign_chains(const ordered_set<AssignChain> &chains) const;
472 std::string print_value_map(const FieldGroup &weak_field_group,
473 const ordered_set<AssignChain> &all_chains_in_group) const;
474
475 private:
476 Visitor::profile_t init_apply(const IR::Node *root) override;
477
478 ordered_set<const Value *> get_all_weak_srcs(const PHV::Field *field,
480
481 ordered_set<const Value *> get_all_weak_srcs(const PHV::Field *field);
482
483 // Group fields that have transitive assignment to one another. Basically members
484 // in a group can only take on the value of other members in the group, or constant.
485 void group_weak_fields();
486
487 std::vector<const IR::MAU::Table *> get_next_tables(
488 const IR::MAU::Table *curr_table,
489 const ordered_map<const IR::MAU::Table *, ordered_set<const Assign *>> &table_to_assigns);
490
491 ordered_set<AssignChain> enumerate_all_assign_chains(
492 const IR::MAU::Table *curr_table,
493 const ordered_map<const IR::MAU::Table *, ordered_set<const Assign *>> &table_to_assigns);
494
495 ordered_map<const PHV::Field *, Value> propagate_value_on_assign_chain(
496 const AssignChain &chain);
497
498 bool compute_all_reachable_values_at_deparser(const FieldGroup &weak_field_group);
499};
500
506
508
509 ordered_set<const IR::TempVar *> get_all_version_bits() const {
511
512 for (auto v : default_version) rv.insert(v.second);
513
514 for (auto &fvv : value_to_version) {
515 for (auto &vv : fvv.second) rv.insert(vv.second);
516 }
517
518 return rv;
519 }
520};
521
530 const CollectHeaderValidity &pov_bits;
531 const CollectWeakFields &weak_fields;
532 const ComputeValuesAtDeparser &values_at_deparser;
533
534 std::map<gress_t, std::vector<IR::MAU::Table *>> tables_to_insert;
535
537
539
541
542 public:
545
547
549
550 explicit SynthesizePovEncoder(const CollectHeaderValidity &pov_bits,
551 const ComputeValuesAtDeparser &values_at_deparser)
552 : pov_bits(pov_bits),
553 weak_fields(values_at_deparser.weak_fields),
554 values_at_deparser(values_at_deparser) {}
555
556 void dbprint(std::ostream &out) const override;
557
558 private:
559 gress_t get_gress(const FieldGroup &group) {
560 auto it = group.begin();
561 return (*it)->gress;
562 }
563
564 std::vector<const IR::Expression *> get_valid_bits(const FieldGroup &group);
565
566 ordered_set<const IR::MAU::Action *> get_all_actions(const FieldGroup &group);
567
568 std::vector<const IR::TempVar *> create_action_ctl_bits(
570
571 bool have_same_vld_ctl_bits(const FieldGroup *a, const FieldGroup *b);
572
573 bool have_same_action_chain(const AssignChain &a, const AssignChain &b);
574
575 bool have_same_assign_chains(const PHV::Field *p, const Value &pv, const PHV::Field *q,
576 const Value &qv);
577
578 bool have_same_hdr_vld_bit(const PHV::Field *p, const PHV::Field *q);
579
580 const IR::TempVar *find_equiv_version_bit_for_value(const PHV::Field *f, unsigned version,
581 const Value &value,
582 const VersionMap &version_map);
583
584 const IR::TempVar *find_equiv_version_bit_for_value(const PHV::Field *f,
585 const FieldGroup &group, unsigned version,
586 const Value &value);
587
588 const IR::TempVar *create_version_bit_for_value(const PHV::Field *f, const FieldGroup &group,
589 unsigned version, const Value &value);
590
591 const VersionMap &create_version_map(const FieldGroup &group);
592
593 unsigned encode_assign_chain(const AssignChain &chain,
594 const ordered_set<const IR::MAU::Action *> &all_actions);
595 bool is_valid(const PHV::Field *f, const std::vector<const IR::Expression *> &vld_bits_onset);
596
597 MatchAction *create_match_action(const FieldGroup &group);
598
599 IR::MAU::TableSeq *preorder(IR::MAU::TableSeq *seq) override;
600
601 unsigned num_coalesced_match_bits(const FieldGroup &a, const FieldGroup &b);
602
603 bool is_trivial_group(const FieldGroup &group);
604
605 void resolve_trivial_group(const FieldGroup &group);
606
607 std::pair<std::map<gress_t, std::vector<FieldGroup>>,
608 std::map<gress_t, std::vector<FieldGroup>>>
609 coalesce_weak_field_groups();
610
611 Visitor::profile_t init_apply(const IR::Node *root) override;
612
613 void end_apply() override {
614 LOG3(*this);
615 LOG1("=== DONE synthesizing decaf POV encoder ===");
616 }
617};
618
627 const ComputeValuesAtDeparser &values_at_deparser;
628 unsigned cid = 0;
629
630 public:
631 std::map<gress_t, ordered_map<const IR::Constant *, std::vector<uint8_t>>> const_to_bytes;
632
633 // these need to be written from the parser
634 std::map<gress_t, ordered_map<uint8_t, const IR::TempVar *>> byte_to_temp_var;
635
636 // these can be directly be sourced from the deparser
637 std::map<gress_t, ordered_set<uint8_t>> deparser_bytes;
638
639 explicit CreateConstants(const ComputeValuesAtDeparser &values_at_deparser)
640 : values_at_deparser(values_at_deparser) {}
641
642 void dbprint(std::ostream &out) const override;
643
644 bool is_inserted(const IR::TempVar *constant) const {
645 for (auto &kv : byte_to_temp_var) {
646 for (auto &bt : kv.second) {
647 if (bt.second == constant) return true;
648 }
649 }
650 return false;
651 }
652
653 private:
654 void create_temp_var_for_parser_constant_bytes(
655 gress_t gress, const ordered_set<const IR::Constant *> &constants);
656
657 Visitor::profile_t init_apply(const IR::Node *root) override;
658
659 void end_apply() override {
660 LOG3(*this);
661 LOG1("=== DONE inserting parser constants ===");
662 }
663
664 void insert_init_consts_state(IR::BFN::Parser *parser);
665
666 IR::BFN::Parser *preorder(IR::BFN::Parser *parser) override;
667};
668
677 const ComputeValuesAtDeparser &values_at_deparser;
678 const SynthesizePovEncoder &synth_pov_encoder;
679
681
683
684 public:
685 RewriteWeakFieldWrites(const ComputeValuesAtDeparser &values_at_deparser,
686 const SynthesizePovEncoder &synth_pov_encoder)
687 : values_at_deparser(values_at_deparser), synth_pov_encoder(synth_pov_encoder) {}
688
689 private:
690 void end_apply() override { LOG1("=== DONE rewriting weak fields ==="); }
691
692 const IR::Node *preorder(IR::MAU::Action *action) override;
693
694 bool cache_instr(const IR::MAU::Action *orig_action, const IR::MAU::Instruction *new_instr);
695
696 const IR::Node *postorder(IR::MAU::Instruction *instr) override;
697};
698
707 const PhvInfo &phv;
708 const SynthesizePovEncoder &synth_pov_encoder;
709 const CreateConstants &create_consts;
710
711 public:
712 ordered_set<cstring> must_split_fields;
713
714 RewriteDeparser(const PhvInfo &phv, const SynthesizePovEncoder &synth_pov_encoder,
715 const CreateConstants &create_consts)
716 : phv(phv), synth_pov_encoder(synth_pov_encoder), create_consts(create_consts) {}
717
718 private:
719 void end_apply() override { LOG1("=== DONE rewriting deparser ==="); }
720
721 void add_emit(IR::Vector<IR::BFN::Emit> &emits, const IR::Expression *source,
722 const IR::TempVar *pov_bit);
723
724 void add_emit(IR::Vector<IR::BFN::Emit> &emits, uint8_t value, const IR::TempVar *pov_bit);
725
726 const IR::Expression *find_emit_source(const PHV::Field *field,
727 const IR::Vector<IR::BFN::Emit> &emits);
728
729 ordered_set<ordered_set<const IR::Expression *>> get_all_disjoint_pov_bit_sets();
730
731 std::vector<const IR::BFN::Emit *> coalesce_disjoint_emits(
732 const std::vector<const IR::BFN::Emit *> &disjoint_emits);
733
734 void coalesce_emits_for_packing(
735 IR::BFN::Deparser *deparser,
736 const ordered_set<ordered_set<const IR::Expression *>> &disjoint_pov_sets);
737
738 void infer_deparser_no_repeat_constraint(
739 IR::BFN::Deparser *deparser,
740 const ordered_set<ordered_set<const IR::Expression *>> &disjoint_pov_sets);
741
742 bool preorder(IR::BFN::Deparser *deparser) override;
743};
744
750 CollectHeaderValidity collect_hdr_valid_bits;
751 CollectWeakFields collect_weak_fields;
752 ComputeValuesAtDeparser values_at_deparser;
753 SynthesizePovEncoder synth_pov_encoder;
754 CreateConstants create_consts;
755 RewriteWeakFieldWrites rewrite_weak_fields;
756
757 public:
758 RewriteDeparser rewrite_deparser;
759
760 DeparserCopyOpt(const PhvInfo &phv, PhvUse &uses, const FieldDefUse &defuse,
761 const DependencyGraph &dg)
763 collect_hdr_valid_bits(phv),
764 collect_weak_fields(phv, uses, defuse, dg),
765 values_at_deparser(collect_weak_fields),
766 synth_pov_encoder(collect_hdr_valid_bits, values_at_deparser),
767 create_consts(values_at_deparser),
768 rewrite_weak_fields(values_at_deparser, synth_pov_encoder),
769 rewrite_deparser(phv, synth_pov_encoder, create_consts) {
770 addPasses({
771 &uses, &collect_hdr_valid_bits, &collect_weak_fields, &values_at_deparser,
772 &synth_pov_encoder, // mau-transform
773 &create_consts, // parde-transform
774 &rewrite_weak_fields, // mau-transform
775 &rewrite_deparser // dep-modifier
776 });
777 }
778};
779
780#endif /* BF_P4C_PARDE_DECAF_H_ */
Definition backends/tofino/bf-p4c/logging/pass_manager.h:36
Definition mau_visitor.h:29
Definition mau_visitor.h:55
Definition visitor.h:463
Definition stringify.h:33
Definition node.h:94
Definition vector.h:59
Definition visitor.h:400
Definition visitor.h:78
Definition visitor.h:75
Definition ordered_map.h:32
Definition ordered_set.h:32
Definition phv_fields.h:154
int id
Unique field ID.
Definition phv_fields.h:164
bool deparsed() const
Definition phv_fields.h:444
cstring name
Definition phv_fields.h:161
bool pov
True if this Field is a validity bit.
Definition phv_fields.h:253
bool bridged
True if this Field is metadata bridged from ingress to egress.
Definition phv_fields.h:219
bool metadata
True if this Field is metadata.
Definition phv_fields.h:209
Definition phv_fields.h:1095
Definition phv_parde_mau_use.h:154
Definition assoc.h:300
Definition assoc.h:355
Definition decaf.h:196
Definition decaf.h:304
Definition decaf.h:457
Definition decaf.h:626
Top level PassManager.
Definition decaf.h:749
Definition decaf.h:706
Definition decaf.h:676
Definition decaf.h:529
Definition decaf.h:174
Definition decaf.h:221
Definition decaf.h:212
Definition decaf.h:117
Definition decaf.h:504
Definition parde_visitor.h:129
Definition field_defuse.h:77
Definition parde_visitor.h:47
@ AUTO
Creates if this is the first time writing to the log; otherwise, appends.
Definition filelog.h:43
Definition table_dependency_graph.h:52
Definition create_pov_encoder.h:24