P4C
The P4 Compiler
Loading...
Searching...
No Matches
mau/stateful_alu.h
1
18
92
93#ifndef BACKENDS_TOFINO_BF_P4C_MAU_STATEFUL_ALU_H_
94#define BACKENDS_TOFINO_BF_P4C_MAU_STATEFUL_ALU_H_
95
96#include <map>
97#include <vector>
98
99#include "backends/tofino/bf-p4c/specs/device.h"
100#include "frontends/common/resolveReferences/referenceMap.h"
101#include "ir/ir.h"
102#include "mau_visitor.h"
103
104using namespace P4;
105
143class CreateSaluInstruction : public Inspector {
144 IR::MAU::StatefulAlu *salu;
145 const IR::Type *regtype;
146 const IR::Declaration_Instance *reg_action = nullptr;
147 cstring action_type_name;
148 enum class param_t { VALUE, OUTPUT, HASH, LEARN, MATCH };
149 const std::vector<param_t> *param_types = nullptr;
150 IR::MAU::SaluAction *action = nullptr;
151 const IR::ParameterList *params = nullptr;
152
153 struct LocalVar {
154 cstring name;
155 bool pair;
156 const IR::MAU::SaluRegfileRow *regfile = nullptr;
157 enum use_t { NONE, ALUHI, MEMLO, MEMHI, MEMALL, REGFILE } use = NONE;
158 LocalVar(cstring name, bool pair, use_t use = NONE,
159 const IR::MAU::SaluRegfileRow *regfile = nullptr)
160 : name(name), pair(pair), regfile(regfile), use(use) {}
161 } *dest = nullptr; // destination of current assignment
162 std::map<cstring, LocalVar> locals;
163 enum etype_t {
164 // tracks the use (context) of the expression we're currently visiting
165 // lvalue contexts
166 NONE, // unknown
167 MINMAX_IDX, // output index of min/max
168 // rvalue contexts
169 IF, // condition -- operand of an if
170 MINMAX_SRC, // 128-bit input to min/max instruction
171 VALUE, // value to be written to memory -- alu output
172 OUTPUT_ALUHI, // value to be written to adb via alu_hi alu (non-dual)
173 OUTPUT, // value to be written to action data bus output
174 MATCH, // value to be written to match output
175 } etype = NONE;
176 static bool islvalue(etype_t t) { return t < IF; }
177 bool negate = false;
178 bool negate_regfile = false;
179 bool alu_write[2] = {false, false};
180 cstring opcode;
181 IR::Vector<IR::Expression> operands, pred_operands;
182 int output_index = -1;
183 std::vector<const IR::MAU::SaluInstruction *> cmp_instr;
184 const IR::MAU::SaluInstruction *divmod_instr = nullptr, *minmax_instr = nullptr;
185 int minmax_width = -1; // 0 = min/max8, 1 = min/max16
186 const IR::Expression *predicate = nullptr;
187 const IR::MAU::SaluInstruction *onebit = nullptr; // the single 1-bit alu op
188 bool onebit_cmpl = false; // 1-bit op needs cmpl
189 int address_subword = 0;
190 std::vector<IR::MAU::SaluInstruction *> outputs; // add to end of action body
191 std::map<int, const IR::Expression *> output_address_subword_predicate;
192 IR::MAU::StatefulAlu::MathUnit math;
193 IR::MAU::SaluFunction *math_function = nullptr;
194 bool assignDone = false;
195 int comb_pred_width = 0;
196 IR::MAU::SaluAction::ReturnEnumEncoding *return_encoding = nullptr;
197 int return_enum_word = -1;
198 bool split_ifs = false;
199 std::map<int, const IR::Expression *> output_param_operands;
200 std::map<int, const IR::Expression *> output_predicates;
201 std::set<const IR::Expression *> or_targets;
202
203 // Map for detection of WAW data hazards
204 // * Key is the lvalue
205 // * Value is the set of predicates for a given expression and source code position
206 // of given assignment
207 struct AssignmentProperties {
208 const IR::Expression *predicate;
209 const Util::SourceInfo &srcInfo;
210 explicit AssignmentProperties(const IR::Expression *pred, const Util::SourceInfo &src)
211 : predicate(pred), srcInfo(src) {}
212 };
213 std::map<cstring, std::vector<AssignmentProperties>> written_dest;
214 const IR::AssignmentStatement *assig_st = nullptr;
215 const IR::Expression *assig_pred = nullptr;
216 void captureAssigstateProps();
217 void checkWriteAfterWrite();
218
219 bool isComplexInstruction(const IR::Operation_Binary *op) const;
220 void checkAndReportComplexInstruction(const IR::Operation_Binary *op) const;
221
229 void insert_instruction(const IR::MAU::SaluInstruction *si);
230
231 void clearFuncState();
232 const IR::MAU::SaluInstruction *createInstruction();
233 bool applyArg(const IR::PathExpression *, cstring);
234 const IR::Expression *reuseCmp(const IR::MAU::SaluInstruction *cmp, int idx);
235 void setupCmp(cstring op);
236 void splitWideInstructions();
237 void assignOutputAlus();
238 const IR::MAU::SaluInstruction *setup_output();
239 bool outputEnumAsPredicate(const IR::Member *);
240 bool canBeIXBarExpr(const IR::Expression *);
241 bool outputAluHi();
242 void checkActions(const Util::SourceInfo &srcInfo);
243
244 bool preorder(const IR::Declaration_Instance *di) override;
245 bool preorder(const IR::Declaration_Variable *v) override;
246 bool preorder(const IR::Property *) override { BUG("unconverted p4_14"); }
247 void postorder(const IR::Property *) override { BUG("unconverted p4_14"); }
248 bool preorder(const IR::Function *) override;
249 void postorder(const IR::Function *) override;
250 bool preorder(const IR::Annotation *) override { return false; }
251 void doAssignment(const Util::SourceInfo &srcInfo);
252 bool preorder(const IR::AssignmentStatement *) override;
253 bool preorder(const IR::IfStatement *) override;
254 bool preorder(const IR::BlockStatement *) override { return true; }
255 bool preorder(const IR::EmptyStatement *) override { return true; }
256 bool preorder(const IR::Statement *s) override {
257 error("%s: statement too complex for register action %s", s->srcInfo, s);
258 return false;
259 }
260
261 void doPrimary(const IR::Expression *, const IR::PathExpression *, cstring);
262 bool preorder(const IR::PathExpression *pe) override;
263 bool preorder(const IR::Member *m) override;
264 bool preorder(const IR::StructExpression *m) override;
265
266 bool preorder(const IR::Constant *) override;
267 bool preorder(const IR::BoolLiteral *) override;
268 bool preorder(const IR::AttribLocal *) override { BUG("unconverted p4_14"); }
269 bool preorder(const IR::Slice *) override;
270 bool preorder(const IR::MAU::Primitive *) override;
271 bool preorder(const IR::MAU::SaluRegfileRow *) override;
272 bool preorder(const IR::Operation::Relation *, cstring op, bool eq);
273 bool preorder(const IR::Equ *r) override { return preorder(r, "equ"_cs, true); }
274 bool preorder(const IR::Neq *r) override { return preorder(r, "neq"_cs, true); }
275 bool preorder(const IR::Grt *r) override { return preorder(r, "grt"_cs, false); }
276 bool preorder(const IR::Lss *r) override { return preorder(r, "lss"_cs, false); }
277 bool preorder(const IR::Geq *r) override { return preorder(r, "geq"_cs, false); }
278 bool preorder(const IR::Leq *r) override { return preorder(r, "leq"_cs, false); }
279 bool preorder(const IR::Cast *) override;
280 void postorder(const IR::Cast *) override;
281 bool preorder(const IR::BFN::SignExtend *) override;
282 bool preorder(const IR::BFN::ReinterpretCast *) override { return true; }
283 void postorder(const IR::BFN::ReinterpretCast *) override;
284 bool preorder(const IR::LNot *) override { return true; }
285 void postorder(const IR::LNot *) override;
286 bool preorder(const IR::LAnd *) override { return true; }
287 void postorder(const IR::LAnd *) override;
288 bool preorder(const IR::LOr *) override { return true; }
289 void postorder(const IR::LOr *) override;
290 bool preorder(const IR::Mux *) override;
291 bool preorder(const IR::Add *) override;
292 bool preorder(const IR::AddSat *) override;
293 bool preorder(const IR::Sub *) override;
294 bool preorder(const IR::SubSat *) override;
295 bool preorder(const IR::Neg *) override;
296 void postorder(const IR::Neg *) override;
297 bool preorder(const IR::Cmpl *) override { return true; }
298 void postorder(const IR::Cmpl *) override;
299 bool preorder(const IR::BAnd *) override;
300 void postorder(const IR::BAnd *) override;
301 bool preorder(const IR::BOr *) override;
302 void postorder(const IR::BOr *) override;
303 bool preorder(const IR::BXor *) override;
304 void postorder(const IR::BXor *) override;
305 bool preorder(const IR::Concat *) override;
306 void postorder(const IR::Concat *) override;
307 bool divmod(const IR::Operation::Binary *, cstring op);
308 bool preorder(const IR::Div *e) override { return divmod(e, "div"_cs); }
309 bool preorder(const IR::Mod *e) override { return divmod(e, "mod"_cs); }
310 bool preorder(const IR::Expression *e) override {
311 error("%s: expression too complex for register action", e->srcInfo);
312 return false;
313 }
314
315 friend std::ostream &operator<<(std::ostream &, CreateSaluInstruction::LocalVar::use_t);
316 friend std::ostream &operator<<(std::ostream &, CreateSaluInstruction::etype_t);
317 static std::map<std::pair<cstring, cstring>, std::vector<param_t>> function_param_types;
318
319 public:
320 explicit CreateSaluInstruction(IR::MAU::StatefulAlu *salu) : salu(salu) {
321 if (auto spec = salu->reg->type->to<IR::Type_Specialized>())
322 regtype = spec->arguments->at(0); // RegisterAction
323 else
324 regtype = IR::Type::Bits::get(1); // SelectorAction
325 visitDagOnce = false;
326 }
327};
328
332 // There's a nasty problem outputting the address on jbay -- we have a way of
333 // specifying an extra bit via lmatch on the output, but it is shared across
334 // all the instructions in the salu. So we have to ensure all instructions that
335 // use lmatch have identical lmatch usage, possibly modifying them.
336 struct AddressLmatchUsage : public Inspector {
337 static unsigned regmasks[];
338 void clear();
339 unsigned eval_cmp(const IR::Expression *);
340 bool preorder(const IR::MAU::SaluAction *) override;
341 bool preorder(const IR::MAU::SaluFunction *) override;
342 bool preorder(const IR::MAU::SaluCmpReg *) override;
343 bool safe_merge(const IR::Expression *a, const IR::Expression *b, unsigned inuse);
344 const IR::MAU::StatefulAlu *salu;
345 unsigned inuse_mask; // cmp registers used in this action
346 const IR::Expression *lmatch_operand;
347 unsigned lmatch_inuse_mask;
348 } lmatch_usage;
349
350 bool preorder(IR::MAU::StatefulAlu *) override;
351 bool preorder(IR::MAU::SaluFunction *) override;
352 bool preorder(IR::MAU::Primitive *) override;
353
359 void postorder(IR::MAU::StatefulAlu *) override;
360 void postorder(IR::MAU::SaluInstruction *) override;
361
362 // FIXME -- Type_Typedef should have been resolved and removed by Typechecking in the
363 // midend? But we're running into it here, so a helper to skip over typedefs.
364 static const IR::Type *getType(const IR::Type *t) {
365 while (auto td = t->to<IR::Type_Typedef>()) t = td->type;
366 return t;
367 }
368
369 std::set<big_int> large_constants;
370};
371
372class FixupStatefulAlu : public PassManager {
391
392 struct return_enum_info_t {
393 cstring enum_name;
395 const IR::MAU::SaluAction::ReturnEnumEncoding *encoding;
396 };
398 int pred_type_size;
399 const IR::Type::Bits *pred_type;
400
401 struct FindEncodings : public MauInspector {
402 FixupStatefulAlu &self;
403 bool preorder(const IR::MAU::SaluAction *) override;
404 bool preorder(const IR::MAU::Action *) override { return false; }
405 explicit FindEncodings(FixupStatefulAlu &self) : self(self) {}
406 };
407 struct UpdateEncodings : public Transform {
408 FixupStatefulAlu &self;
409 const IR::BFN::Pipe *preorder(IR::BFN::Pipe *p) override {
410 if (self.encodings.empty()) prune();
411 return p;
412 }
413 const IR::MAU::SaluAction *preorder(IR::MAU::SaluAction *) override;
414 const IR::Operation::Relation *preorder(IR::Operation::Relation *) override;
415 const IR::Expression *preorder(IR::Member *) override;
416 const IR::Expression *preorder(IR::Expression *) override;
417 const IR::BFN::ParserRVal *postorder(IR::BFN::SavedRVal *) override;
418
419 explicit UpdateEncodings(FixupStatefulAlu &self) : self(self) {}
420 };
421 struct ReplaceUpdatedEnumTypes : public Transform {
422 FixupStatefulAlu &self;
423 const IR::Expression *postorder(IR::Expression *exp) {
424 visit(exp->type, "type");
425 return exp;
426 }
427 const IR::Type *preorder(IR::Type_Enum *enum_t) {
428 if (self.encodings.count(getOriginal<IR::Type_Enum>())) return self.pred_type;
429 return enum_t;
430 }
431 explicit ReplaceUpdatedEnumTypes(FixupStatefulAlu &self) : self(self) {}
432 };
433
434 public:
435 FixupStatefulAlu()
436 : PassManager({
438 new FindEncodings(*this),
439 new UpdateEncodings(*this),
440 new ReplaceUpdatedEnumTypes(*this),
441 }) {
442 pred_type_size = 1 << Device::statefulAluSpec().CmpUnits.size();
443 pred_type = IR::Type::Bits::get(pred_type_size);
444 }
445};
446
447#endif /* BACKENDS_TOFINO_BF_P4C_MAU_STATEFUL_ALU_H_ */
Definition mau/stateful_alu.h:331
Definition mau_visitor.h:29
Definition mau_visitor.h:45
Definition ir/vector.h:59
Definition visitor.h:413
Definition visitor.h:437
Definition source_file.h:132
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58