P4C
The P4 Compiler
Loading...
Searching...
No Matches
mau/stateful_alu.h
1
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/device.h"
100#include "frontends/common/resolveReferences/referenceMap.h"
101#include "ir/ir.h"
102#include "mau_visitor.h"
103
104using namespace P4;
105
107 bool CmpMask; // are cmp oprerands maskable?
108 std::vector<cstring> CmpUnits;
109 int MaxSize;
110 int MaxDualSize;
111 int MaxPhvInputWidth;
112 int MaxInstructions;
113 int MaxInstructionConstWidth;
114 int MinInstructionConstValue;
115 int MaxInstructionConstValue;
116 int OutputWords;
117 bool DivModUnit;
118 bool FastClear;
119 int MaxRegfileRows;
120
121 cstring cmpUnit(unsigned idx) const;
122};
123
162 IR::MAU::StatefulAlu *salu;
163 const IR::Type *regtype;
164 const IR::Declaration_Instance *reg_action = nullptr;
165 cstring action_type_name;
166 enum class param_t { VALUE, OUTPUT, HASH, LEARN, MATCH };
167 const std::vector<param_t> *param_types = nullptr;
168 IR::MAU::SaluAction *action = nullptr;
169 const IR::ParameterList *params = nullptr;
170
171 struct LocalVar {
172 cstring name;
173 bool pair;
174 const IR::MAU::SaluRegfileRow *regfile = nullptr;
175 enum use_t { NONE, ALUHI, MEMLO, MEMHI, MEMALL, REGFILE } use = NONE;
176 LocalVar(cstring name, bool pair, use_t use = NONE,
177 const IR::MAU::SaluRegfileRow *regfile = nullptr)
178 : name(name), pair(pair), regfile(regfile), use(use) {}
179 } *dest = nullptr; // destination of current assignment
180 std::map<cstring, LocalVar> locals;
181 enum etype_t {
182 // tracks the use (context) of the expression we're currently visiting
183 // lvalue contexts
184 NONE, // unknown
185 MINMAX_IDX, // output index of min/max
186 // rvalue contexts
187 IF, // condition -- operand of an if
188 MINMAX_SRC, // 128-bit input to min/max instruction
189 VALUE, // value to be written to memory -- alu output
190 OUTPUT_ALUHI, // value to be written to adb via alu_hi alu (non-dual)
191 OUTPUT, // value to be written to action data bus output
192 MATCH, // value to be written to match output
193 } etype = NONE;
194 static bool islvalue(etype_t t) { return t < IF; }
195 bool negate = false;
196 bool negate_regfile = false;
197 bool alu_write[2] = {false, false};
198 cstring opcode;
199 IR::Vector<IR::Expression> operands, pred_operands;
200 int output_index = -1;
201 std::vector<const IR::MAU::SaluInstruction *> cmp_instr;
202 const IR::MAU::SaluInstruction *divmod_instr = nullptr, *minmax_instr = nullptr;
203 int minmax_width = -1; // 0 = min/max8, 1 = min/max16
204 const IR::Expression *predicate = nullptr;
205 const IR::MAU::SaluInstruction *onebit = nullptr; // the single 1-bit alu op
206 bool onebit_cmpl = false; // 1-bit op needs cmpl
207 int address_subword = 0;
208 std::vector<IR::MAU::SaluInstruction *> outputs; // add to end of action body
209 std::map<int, const IR::Expression *> output_address_subword_predicate;
210 IR::MAU::StatefulAlu::MathUnit math;
211 IR::MAU::SaluFunction *math_function = nullptr;
212 bool assignDone = false;
213 int comb_pred_width = 0;
214 IR::MAU::SaluAction::ReturnEnumEncoding *return_encoding = nullptr;
215 int return_enum_word = -1;
216 bool split_ifs = false;
217 std::map<int, const IR::Expression *> output_param_operands;
218 std::map<int, const IR::Expression *> output_predicates;
219 std::set<const IR::Expression *> or_targets;
220
221 // Map for detection of WAW data hazards
222 // * Key is the lvalue
223 // * Value is the set of predicates for a given expression and source code position
224 // of given assignment
225 struct AssignmentProperties {
226 const IR::Expression *predicate;
227 const Util::SourceInfo &srcInfo;
228 explicit AssignmentProperties(const IR::Expression *pred, const Util::SourceInfo &src)
229 : predicate(pred), srcInfo(src) {}
230 };
231 std::map<cstring, std::vector<AssignmentProperties>> written_dest;
232 const IR::AssignmentStatement *assig_st = nullptr;
233 const IR::Expression *assig_pred = nullptr;
234 void captureAssigstateProps();
235 void checkWriteAfterWrite();
236
237 bool isComplexInstruction(const IR::Operation_Binary *op) const;
238 void checkAndReportComplexInstruction(const IR::Operation_Binary *op) const;
239
247 void insert_instruction(const IR::MAU::SaluInstruction *si);
248
249 void clearFuncState();
250 const IR::MAU::SaluInstruction *createInstruction();
251 bool applyArg(const IR::PathExpression *, cstring);
252 const IR::Expression *reuseCmp(const IR::MAU::SaluInstruction *cmp, int idx);
253 void setupCmp(cstring op);
254 void splitWideInstructions();
255 void assignOutputAlus();
256 const IR::MAU::SaluInstruction *setup_output();
257 bool outputEnumAsPredicate(const IR::Member *);
258 bool canBeIXBarExpr(const IR::Expression *);
259 bool outputAluHi();
260 void checkActions(const Util::SourceInfo &srcInfo);
261
262 bool preorder(const IR::Declaration_Instance *di) override;
263 bool preorder(const IR::Declaration_Variable *v) override;
264 bool preorder(const IR::Property *) override { BUG("unconverted p4_14"); }
265 void postorder(const IR::Property *) override { BUG("unconverted p4_14"); }
266 bool preorder(const IR::Function *) override;
267 void postorder(const IR::Function *) override;
268 bool preorder(const IR::Annotations *) override { return false; }
269 void doAssignment(const Util::SourceInfo &srcInfo);
270 bool preorder(const IR::AssignmentStatement *) override;
271 bool preorder(const IR::IfStatement *) override;
272 bool preorder(const IR::BlockStatement *) override { return true; }
273 bool preorder(const IR::EmptyStatement *) override { return true; }
274 bool preorder(const IR::Statement *s) override {
275 error("%s: statement too complex for register action %s", s->srcInfo, s);
276 return false;
277 }
278
279 void doPrimary(const IR::Expression *, const IR::PathExpression *, cstring);
280 bool preorder(const IR::PathExpression *pe) override;
281 bool preorder(const IR::Member *m) override;
282 bool preorder(const IR::StructExpression *m) override;
283
284 bool preorder(const IR::Constant *) override;
285 bool preorder(const IR::BoolLiteral *) override;
286 bool preorder(const IR::AttribLocal *) override { BUG("unconverted p4_14"); }
287 bool preorder(const IR::Slice *) override;
288 bool preorder(const IR::MAU::Primitive *) override;
289 bool preorder(const IR::MAU::SaluRegfileRow *) override;
290 bool preorder(const IR::Operation::Relation *, cstring op, bool eq);
291 bool preorder(const IR::Equ *r) override { return preorder(r, "equ"_cs, true); }
292 bool preorder(const IR::Neq *r) override { return preorder(r, "neq"_cs, true); }
293 bool preorder(const IR::Grt *r) override { return preorder(r, "grt"_cs, false); }
294 bool preorder(const IR::Lss *r) override { return preorder(r, "lss"_cs, false); }
295 bool preorder(const IR::Geq *r) override { return preorder(r, "geq"_cs, false); }
296 bool preorder(const IR::Leq *r) override { return preorder(r, "leq"_cs, false); }
297 bool preorder(const IR::Cast *) override;
298 void postorder(const IR::Cast *) override;
299 bool preorder(const IR::BFN::SignExtend *) override;
300 bool preorder(const IR::BFN::ReinterpretCast *) override { return true; }
301 void postorder(const IR::BFN::ReinterpretCast *) override;
302 bool preorder(const IR::LNot *) override { return true; }
303 void postorder(const IR::LNot *) override;
304 bool preorder(const IR::LAnd *) override { return true; }
305 void postorder(const IR::LAnd *) override;
306 bool preorder(const IR::LOr *) override { return true; }
307 void postorder(const IR::LOr *) override;
308 bool preorder(const IR::Mux *) override;
309 bool preorder(const IR::Add *) override;
310 bool preorder(const IR::AddSat *) override;
311 bool preorder(const IR::Sub *) override;
312 bool preorder(const IR::SubSat *) override;
313 bool preorder(const IR::Neg *) override;
314 void postorder(const IR::Neg *) override;
315 bool preorder(const IR::Cmpl *) override { return true; }
316 void postorder(const IR::Cmpl *) override;
317 bool preorder(const IR::BAnd *) override;
318 void postorder(const IR::BAnd *) override;
319 bool preorder(const IR::BOr *) override;
320 void postorder(const IR::BOr *) override;
321 bool preorder(const IR::BXor *) override;
322 void postorder(const IR::BXor *) override;
323 bool preorder(const IR::Concat *) override;
324 void postorder(const IR::Concat *) override;
325 bool divmod(const IR::Operation::Binary *, cstring op);
326 bool preorder(const IR::Div *e) override { return divmod(e, "div"_cs); }
327 bool preorder(const IR::Mod *e) override { return divmod(e, "mod"_cs); }
328 bool preorder(const IR::Expression *e) override {
329 error("%s: expression too complex for register action", e->srcInfo);
330 return false;
331 }
332
333 friend std::ostream &operator<<(std::ostream &, CreateSaluInstruction::LocalVar::use_t);
334 friend std::ostream &operator<<(std::ostream &, CreateSaluInstruction::etype_t);
335 static std::map<std::pair<cstring, cstring>, std::vector<param_t>> function_param_types;
336
337 public:
338 explicit CreateSaluInstruction(IR::MAU::StatefulAlu *salu) : salu(salu) {
339 if (auto spec = salu->reg->type->to<IR::Type_Specialized>())
340 regtype = spec->arguments->at(0); // RegisterAction
341 else
342 regtype = IR::Type::Bits::get(1); // SelectorAction
343 visitDagOnce = false;
344 }
345};
346
350 // There's a nasty problem outputting the address on jbay -- we have a way of
351 // specifying an extra bit via lmatch on the output, but it is shared across
352 // all the instructions in the salu. So we have to ensure all instructions that
353 // use lmatch have identical lmatch usage, possibly modifying them.
354 struct AddressLmatchUsage : public Inspector {
355 static unsigned regmasks[];
356 void clear();
357 unsigned eval_cmp(const IR::Expression *);
358 bool preorder(const IR::MAU::SaluAction *) override;
359 bool preorder(const IR::MAU::SaluFunction *) override;
360 bool preorder(const IR::MAU::SaluCmpReg *) override;
361 bool safe_merge(const IR::Expression *a, const IR::Expression *b, unsigned inuse);
362 const IR::MAU::StatefulAlu *salu;
363 unsigned inuse_mask; // cmp registers used in this action
364 const IR::Expression *lmatch_operand;
365 unsigned lmatch_inuse_mask;
366 } lmatch_usage;
367
368 bool preorder(IR::MAU::StatefulAlu *) override;
369 bool preorder(IR::MAU::SaluFunction *) override;
370 bool preorder(IR::MAU::Primitive *) override;
371
377 void postorder(IR::MAU::StatefulAlu *) override;
378 void postorder(IR::MAU::SaluInstruction *) override;
379
380 // FIXME -- Type_Typedef should have been resolved and removed by Typechecking in the
381 // midend? But we're running into it here, so a helper to skip over typedefs.
382 static const IR::Type *getType(const IR::Type *t) {
383 while (auto td = t->to<IR::Type_Typedef>()) t = td->type;
384 return t;
385 }
386
387 std::set<big_int> large_constants;
388};
389
410 struct return_enum_info_t {
411 cstring enum_name;
413 const IR::MAU::SaluAction::ReturnEnumEncoding *encoding;
414 };
416 int pred_type_size;
417 const IR::Type::Bits *pred_type;
418
419 struct FindEncodings : public MauInspector {
420 FixupStatefulAlu &self;
421 bool preorder(const IR::MAU::SaluAction *) override;
422 bool preorder(const IR::MAU::Action *) override { return false; }
423 explicit FindEncodings(FixupStatefulAlu &self) : self(self) {}
424 };
425 struct UpdateEncodings : public Transform {
426 FixupStatefulAlu &self;
427 const IR::BFN::Pipe *preorder(IR::BFN::Pipe *p) override {
428 if (self.encodings.empty()) prune();
429 return p;
430 }
431 const IR::MAU::SaluAction *preorder(IR::MAU::SaluAction *) override;
432 const IR::Operation::Relation *preorder(IR::Operation::Relation *) override;
433 const IR::Expression *preorder(IR::Member *) override;
434 const IR::Expression *preorder(IR::Expression *) override;
435 const IR::BFN::ParserRVal *postorder(IR::BFN::SavedRVal *) override;
436
437 explicit UpdateEncodings(FixupStatefulAlu &self) : self(self) {}
438 };
439 struct ReplaceUpdatedEnumTypes : public Transform {
440 FixupStatefulAlu &self;
441 const IR::Expression *postorder(IR::Expression *exp) {
442 visit(exp->type, "type");
443 return exp;
444 }
445 const IR::Type *preorder(IR::Type_Enum *enum_t) {
446 if (self.encodings.count(getOriginal<IR::Type_Enum>())) return self.pred_type;
447 return enum_t;
448 }
449 explicit ReplaceUpdatedEnumTypes(FixupStatefulAlu &self) : self(self) {}
450 };
451
452 public:
454 : PassManager({
456 new FindEncodings(*this),
457 new UpdateEncodings(*this),
458 new ReplaceUpdatedEnumTypes(*this),
459 }) {
460 pred_type_size = 1 << Device::statefulAluSpec().CmpUnits.size();
461 pred_type = IR::Type::Bits::get(pred_type_size);
462 }
463};
464
465#endif /* BACKENDS_TOFINO_BF_P4C_MAU_STATEFUL_ALU_H_ */
Definition mau/stateful_alu.h:349
Definition mau/stateful_alu.h:390
Definition mau_visitor.h:29
Definition mau_visitor.h:45
Definition vector.h:59
Definition visitor.h:400
Definition ir/pass_manager.h:40
Definition visitor.h:424
Definition source_file.h:131
Definition cstring.h:85
Definition ordered_map.h:32
Definition ordered_set.h:32
The pass creates SALU VLIW instructions.
Definition mau/stateful_alu.h:161
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:51
Definition mau/stateful_alu.h:106