P4C
The P4 Compiler
Loading...
Searching...
No Matches
init_in_mau.h
1
18
19#ifndef BF_P4C_PHV_INIT_IN_MAU_H_
20#define BF_P4C_PHV_INIT_IN_MAU_H_
21
22#include "backends/tofino/bf-p4c/phv/add_initialization.h"
23#include "backends/tofino/bf-p4c/phv/phv_fields.h"
24#include "ir/visitor.h"
25
26// *****************************************************************************************
27// AddInitTable class adds a new table called __mau_inits_table__ in the beginning of the
28// first Table Sequence in the IR with one action that contains
29// zero-initializations to selected field-slices. The table is added
30// to handle initializations that cannot be done in the parser.
31//
32// Currently it handles initializations for non-extracted field which
33// are packed with extracted fields in the same slice list, thus need
34// to be allocated in the same container. An example of this happens
35// in Arista's profile 'obfucscated-map.p4' where 2 header fields are
36// aliased with 2 metadata fields. One of the metadata fields is
37// defined in the parser whereas the other is not. The profile is
38// quite complex and removing the alias results in non-fitting on
39// Tofino-1 device.
40//
41// The field-slices that get initialized are contained in
42// "mauInitFields" set. This container is populated during phv
43// allocation by "ParserPackingValidator" which checks for packing
44// constraints due to parsing. During Trivial allocation where packing
45// is minimal due to infinite phv resources we mark pairs of field-slices that
46// belong in the same slice list and one of the slices is extracted
47// whereas the other is not.
48// During regular PHV-Allocation, field-slices will not be added to "mauInitFields".
49// The packing will be rejected unless Trivial PHV-Allocation marked
50// the pair of fields for initialization which most likely means that
51// Trivial Allocation was not able to pack fields in a way that
52// initializations were not required.
53//
54// The "AddInitsInMAU" pass is run twice in the backend list of passes:
55// Once before PHV-Allocation and once after PHV-Allocation (before Table-Placement)
56// The reason for running this pass twice is due to the fact that the
57// added table is removed when progressing from Table-Placement to
58// real PHV-Allocation in the alt-phv-alloc flow and thus we lose its
59// physical stage info as well.
60//
61// *TODO* Eliminate the first instance of "AddInitsInMAU" before
62// PHV-Allocation by handling the physical-stage info issues that
63// arise.
64//
65// *TODO* Use "mauInitFields" to also handle initialization for fields
66// that are upcasted in the parser.
67// *****************************************************************************************
68class AddInitTable : public Transform {
69 private:
70 PhvInfo &phv;
71 const MapFieldToExpr &fieldToExpr;
72 std::set<PHV::FieldRange> &mauInitFields;
73 std::vector<IR::Slice *> mauInitSlices;
74 bool ingress_inits = false, egress_inits = false;
75 bool check_container;
76
77 bool same_container(PHV::FieldSlice sl1, PHV::FieldSlice sl2) {
78 if (!check_container) return true;
79
80 for (const auto &alloc_sl1 : sl1.field()->get_alloc()) {
81 // Look for corresponding allocated slice of FieldSlice sl1
82 if (sl1.range().overlaps(alloc_sl1.field_slice()) &&
83 alloc_sl1.container() != PHV::Container()) {
84 for (const auto &alloc_sl2 : sl2.field()->get_alloc()) {
85 // Look for corresponding allocated slice of FieldSlice sl2
86 if (sl2.range().overlaps(alloc_sl2.field_slice())) {
87 if (alloc_sl1.container() == alloc_sl2.container()) {
88 return true;
89 }
90 }
91 }
92 }
93 }
94 return false;
95 }
96
97 profile_t init_apply(const IR::Node *root) override {
98 auto rv = Transform::init_apply(root);
99
100 LOG3("AddInitTable: init_apply");
101 mauInitSlices.clear();
102 // Collect set of FieldRange's which do not need initialization to remove
103 std::set<PHV::FieldRange> removeInitFields;
104 for (const auto &mau_init : mauInitFields) {
105 // Get the field requiring mau init
106 if (const auto *fld1 = phv.field(mau_init.field_name)) {
107 // Get the extracted field that is possibly allocated
108 // to the same container as fld1
109 for (auto &f_range : mau_init.conflicts) {
110 const auto *fld2 = phv.field(f_range.field_name);
111 if (fld2 && same_container(PHV::FieldSlice(fld1, mau_init.range),
112 PHV::FieldSlice(fld2, f_range.range))) {
113 ingress_inits = (fld1->gress == INGRESS);
114 egress_inits = (fld1->gress == EGRESS);
115 auto slice = new IR::Slice(fieldToExpr.getExpr(fld1), mau_init.range.hi,
116 mau_init.range.lo);
117 mauInitSlices.push_back(slice);
118 LOG4("\t Added slice: " << slice << " for " << mau_init.field_name << " "
119 << mau_init.range);
120 } else {
121 removeInitFields.insert(mau_init);
122 }
123 }
124 }
125 }
126
127 for (auto remInit : removeInitFields) {
128 mauInitFields.erase(remInit);
129 LOG5("\t Removing mau init " << remInit.field_name << " " << remInit.range);
130 }
131
132 return rv;
133 }
134
135 IR::MAU::TableSeq *preorder(IR::MAU::TableSeq *tSeq) override {
136 LOG3("AddInitTable: preorder TableSeq " << tSeq);
137 gress_t seq_gress;
138 cstring tableName;
139 cstring actionName;
140 const IR::MAU::Table *init_table = nullptr;
141
142 if (tSeq->tables.empty()) {
143 LOG3("AddInitTable: empty TableSeq - skipping");
144 return tSeq;
145 } else {
146 LOG3("\t Table: " << tSeq->tables.front()->name);
147 seq_gress = tSeq->tables.front()->gress;
148 tableName = "__mau_inits_table__" + toString(seq_gress);
149 actionName = "__mau_inits_action__" + toString(seq_gress);
150 for (auto *tbl : tSeq->tables) {
151 if (tbl->name == tableName) {
152 init_table = tbl;
153 BUG_CHECK(tbl->actions.count(actionName), "Table %1% does not have action %2%?",
154 tableName, actionName);
155 }
156 }
157 }
158
159 // Check that this Table Sequence is the first one
160 const IR::MAU::Table *parent_table = nullptr;
161 parent_table = findContext<IR::MAU::Table>();
162 BUG_CHECK(!parent_table, "This Table Sequence has parent table %1% ?", parent_table->name);
163
164 prune();
165
166 if (((seq_gress == INGRESS) && !ingress_inits) ||
167 ((seq_gress == EGRESS) && !egress_inits)) {
168 LOG3("AddInitTable: Table Sequence of gress "
169 << seq_gress << " without fields of that gress requiring init - nothing to do");
170 return tSeq;
171 }
172
173 // No need to do anything if initialization table exist
174 // *TODO* This is meant to handle re-creation of the initialization
175 // table during real PHV Allocation already exists
176 // from trivial PHV-Allocation. Though this would not happen
177 // in the current implementation. But in the future if we
178 // want to update the set of fields initialized we should
179 // need to check if initialization table exists and also if
180 // if field-slices are already initialized. Thus leaving this as is for now
181 if (init_table) return tSeq;
182
183 // Create the table and action that will contain the slice inits
184 auto createDummyTableAndAction = [&]() -> std::pair<IR::MAU::Table *, IR::MAU::Action *> {
185 LOG3("AddInitTable: " << "new table name " << tableName);
186 auto table = new IR::MAU::Table(tableName, seq_gress);
187 table->gress = seq_gress;
188 auto action = new IR::MAU::Action(actionName);
189 table->match_table = new IR::P4Table(tableName.c_str(), new IR::TableProperties());
190 table->is_compiler_generated = true;
191 action->init_default = true;
192 action->default_allowed = true;
193
194 for (auto &slice : mauInitSlices) {
195 auto type = IR::Type_Bits::get(slice->getH() - slice->getL() + 1);
196 auto instr = new IR::MAU::Instruction("set"_cs, {slice, new IR::Constant(type, 0)});
197 LOG3("AddInitTable: " << "adding " << instr);
198 action->action.push_back(instr);
199 }
200
201 table->actions[action->name] = action;
202
203 return {table, action};
204 };
205
206 // Create init table if it has not been created before
207 auto [table, action] = createDummyTableAndAction();
208
209 tSeq->tables.insert(tSeq->tables.begin(), table);
210 LOG3("AddInitTable: the first tableSeq now looks like this " << tSeq);
211 return tSeq;
212 }
213
214 public:
215 explicit AddInitTable(PhvInfo &p, MapFieldToExpr &f2exp,
216 std::set<PHV::FieldRange> &to_be_inited, bool container_info)
217 : phv(p),
218 fieldToExpr(f2exp),
219 mauInitFields(to_be_inited),
220 check_container(container_info) {}
221};
222
223class AddInitsInMAU : public PassManager {
224 public:
225 explicit AddInitsInMAU(PhvInfo &phv, std::set<PHV::FieldRange> &to_be_inited,
226 bool container_info) {
227 auto mapFieldToExpr = new MapFieldToExpr(phv);
228 addPasses({
229 mapFieldToExpr,
230 new AddInitTable(phv, *mapFieldToExpr, to_be_inited, container_info),
231 });
232 }
233};
234
235#endif /* BF_P4C_PHV_INIT_IN_MAU_H_ */
Definition init_in_mau.h:68
Definition node.h:94
Definition visitor.h:437
Definition visitor.h:78
Definition cstring.h:85
Definition phv.h:176
const safe_vector< PHV::AllocSlice > & get_alloc() const
Definition phv_fields.h:717
Definition phv_fields.h:898
const PHV::Field * field() const override
Definition phv_fields.h:977
const le_bitrange & range() const override
Definition phv_fields.h:980
Definition phv_fields.h:1095
bool overlaps(ClosedRange a) const
Definition lib/bitrange.h:603