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