P4C
The P4 Compiler
Loading...
Searching...
No Matches
arch.h
1
18
24#ifndef BF_P4C_ARCH_ARCH_H_
25#define BF_P4C_ARCH_ARCH_H_
26
27#include <optional>
28
29#include <boost/algorithm/string.hpp>
30
31#include "backends/tofino/bf-p4c/arch/program_structure.h"
32#include "backends/tofino/bf-p4c/bf-p4c-options.h"
33#include "backends/tofino/bf-p4c/ir/gress.h"
34#include "backends/tofino/bf-p4c/lib/assoc.h"
35#include "backends/tofino/bf-p4c/midend/type_checker.h"
36#include "frontends/common/options.h"
37#include "frontends/common/resolveReferences/referenceMap.h"
38#include "frontends/common/resolveReferences/resolveReferences.h"
39#include "frontends/p4/cloner.h"
40#include "frontends/p4/coreLibrary.h"
41#include "frontends/p4/evaluator/evaluator.h"
42#include "frontends/p4/methodInstance.h"
43#include "frontends/p4/sideEffects.h"
44#include "frontends/p4/typeChecking/typeChecker.h"
45#include "frontends/p4/typeMap.h"
46#include "frontends/p4/uniqueNames.h"
47#include "ir/ir.h"
48#include "ir/namemap.h"
49#include "ir/pass_manager.h"
50#include "ir/visitor.h"
51
52namespace BFN {
53
54// An Inspector pass to extract @pkginfo annotation from the P4 program
55class Architecture : public Inspector {
56 public:
57 enum Arch_t { TNA, T2NA, PSA, V1MODEL, UNKNOWN };
58
59 private:
60 inline static Arch_t architecture = Arch_t::UNKNOWN;
61 inline static cstring version = "UNKNOWN"_cs;
62 inline static bool disabled_for_gtest = false;
63 bool found = false;
64
65 public:
66 Architecture() {}
67 profile_t init_apply(const IR::Node *node) override {
68 found = false;
69 return Inspector::init_apply(node);
70 }
71 void end_apply() override {
72 if (disabled_for_gtest) return;
73 BUG_CHECK(found != false, "No @pkginfo annotation found in the program");
74 }
75 bool preorder(const IR::PackageBlock *pkg) override;
76 static Arch_t toArchEnum(cstring arch) {
77 if (arch == "TNA" || arch == "tna")
78 return Arch_t::TNA;
79 else if (arch == "T2NA" || arch == "t2na")
80 return Arch_t::T2NA;
81 else
82 return Arch_t::UNKNOWN;
83 }
84
85 static Arch_t currentArchitecture() { return architecture; }
86 static cstring currentArchitectureVersion() { return version; }
87
88 // for gtest
89 static void init(cstring arch) {
90 architecture = toArchEnum(arch);
91 disabled_for_gtest = true;
92 }
93};
94
95struct FindArchitecture : public PassManager {
96 P4::ReferenceMap refMap;
97 P4::TypeMap typeMap;
98
99 FindArchitecture() {
100 refMap.setIsV1(true);
101 auto typeChecking = new P4::TypeChecking(&refMap, &typeMap);
102 auto *evaluator = new P4::EvaluatorPass(&refMap, &typeMap);
103 passes.emplace_back(typeChecking);
104 passes.emplace_back(evaluator);
105 passes.emplace_back(new VisitFunctor([evaluator]() {
106 auto toplevel = evaluator->getToplevelBlock();
107 auto main = toplevel->getMain();
108 ERROR_CHECK(main != nullptr, ErrorType::ERR_INVALID,
109 "program: does not instantiate `main`");
110 main->apply(*new Architecture());
111 }));
112 }
113};
114
124 const IR::MethodCallStatement *preorder(IR::MethodCallStatement *call) override {
125 auto *action = findContext<IR::P4Action>();
126 if (!action) return call;
127
128 auto *callExpr = call->methodCall->to<IR::MethodCallExpression>();
129 BUG_CHECK(callExpr, "Malformed method call IR: %1%", call);
130
131 auto *dontTranslate = action->getAnnotation("dont_translate_extern_method"_cs);
132 if (!dontTranslate) return call;
133 for (auto *excluded : dontTranslate->getExpr()) {
134 auto *excludedMethod = excluded->to<IR::StringLiteral>();
135 if (!excludedMethod) {
136 error(
137 "Non-string argument to @dont_translate_extern_method: "
138 "%1%",
139 excluded);
140 return call;
141 }
142
143 if (excludedMethod->value == callExpr->method->toString()) {
144 ::warning(
145 "Excluding method call from translation due to "
146 "@dont_translate_extern_method: %1%",
147 call);
148 return nullptr;
149 }
150 }
151
152 return call;
153 }
154};
155
157class GenerateTofinoProgram : public Transform {
158 ProgramStructure *structure;
159
160 public:
161 explicit GenerateTofinoProgram(ProgramStructure *structure) : structure(structure) {
162 CHECK_NULL(structure);
163 setName("GenerateTofinoProgram");
164 }
165
166 const IR::Node *preorder(IR::P4Program *program) override {
167 auto *rv = structure->create(program);
168 return rv;
169 }
170};
171
173class TranslationFirst : public PassManager {
174 public:
175 TranslationFirst() { setName("TranslationFirst"); }
176};
177
179class TranslationLast : public PassManager {
180 public:
181 TranslationLast() { setName("TranslationLast"); }
182};
183
190class ArchTranslation : public PassManager {
191 public:
192 ArchTranslation(P4::ReferenceMap *refMap, P4::TypeMap *typeMap, BFN_Options &options);
193};
194
196enum ArchBlock_t { PARSER = 0, MAU, DEPARSER, BLOCK_TYPE };
197
198static const std::map<Architecture::Arch_t, std::map<std::pair<ArchBlock_t, gress_t>, int>>
199 archBlockIndex = {
200 {Architecture::TNA,
201 {{{PARSER, INGRESS}, 0},
202 {{MAU, INGRESS}, 1},
203 {{DEPARSER, INGRESS}, 2},
204 {{PARSER, EGRESS}, 3},
205 {{MAU, EGRESS}, 4},
206 {{DEPARSER, EGRESS}, 5}}},
207 {Architecture::T2NA,
208 {{{PARSER, INGRESS}, 0},
209 {{MAU, INGRESS}, 1},
210 {{DEPARSER, INGRESS}, 2},
211 {{PARSER, EGRESS}, 3},
212 {{MAU, EGRESS}, 4},
213 {{DEPARSER, EGRESS}, 5},
214 {{MAU, GHOST}, 6}}},
215};
216
218struct BlockInfo {
223 gress_t gress;
225 std::vector<int> portmap;
227 ArchBlock_t block_type;
232
233 BlockInfo(int pipe_index, cstring pipe_name, gress_t gress, ArchBlock_t block_type,
234 cstring parser_inst = ""_cs)
237 gress(gress),
239 parser_instance_name(parser_inst) {
240 auto p4_arch = Architecture::currentArchitecture();
241 BUG_CHECK(archBlockIndex.count(p4_arch) != 0, "Unknown architecture %1%", p4_arch);
242 BUG_CHECK(archBlockIndex.at(p4_arch).find({block_type, gress}) !=
243 archBlockIndex.at(p4_arch).end(),
244 "Unknown block type %1% for architecture %2%", block_type, p4_arch);
245 block_index = archBlockIndex.at(p4_arch).at({block_type, gress});
246 }
247 void dbprint(std::ostream &out) {
248 out << "pipe_index " << pipe_index << " ";
249 out << "pipe_name" << pipe_name << " ";
250 out << "gress " << gress << " ";
251 out << "block_index" << block_index << " ";
252 out << "type " << block_type << std::endl;
253 }
254 bool operator==(const BlockInfo &other) const {
255 return pipe_index == other.pipe_index && pipe_name == other.pipe_name &&
256 gress == other.gress && block_index == other.block_index &&
257 block_type == other.block_type;
258 }
259 bool operator<(const BlockInfo &other) const {
260 return std::tie(pipe_index, pipe_name, gress, block_index, block_type) <
261 std::tie(other.pipe_index, other.pipe_name, other.gress, other.block_index,
262 other.block_type);
263 }
264};
265
266struct Pipeline {
267 public:
268 // Name of the pipeline.
269 std::vector<cstring> names;
270
271 // One or more pipe ids. Contains multiple ids in case the top-level switch instance is
272 // instantiated with multiple equivalent pipeline instances.
273 std::vector<int> ids;
274
276
277 // Global pragmas applied either for all pragmas or for this pipeline specifically.
278 std::vector<const IR::Annotation *> pragmas;
279
280 // Constructs new pipeline.
281 Pipeline(cstring name, const IR::BFN::P4Thread *ingress, const IR::BFN::P4Thread *egress,
282 const IR::BFN::P4Thread *ghost);
283
284 // Checks if two pipelines are sematically equivalent.
285 bool equiv(const Pipeline &other) const;
286
287 private:
288 // Inserts global pragmas into this instance. Filters out all pragmas which are applied
289 // to a different pipeline.
290 void insertPragmas(const std::vector<const IR::Annotation *> &all_pragmas);
291};
292
294 public:
295 void addPipeline(int pipe_idx, Pipeline pipeline, cstring name) {
296 auto it = std::find_if(pipelines.begin(), pipelines.end(),
297 [&](const auto &p) { return p.equiv(pipeline); });
298 if (it == pipelines.end()) {
299 it = pipelines.insert(pipelines.end(), pipeline);
300 }
301 pipeIdxToPipeline[pipe_idx] = std::distance(pipelines.begin(), it);
302 it->ids.push_back(pipe_idx);
303 it->names.push_back(name);
304 }
305
306 const Pipeline &getPipeline(size_t pipe_idx) const {
307 return pipelines.at(pipeIdxToPipeline.at(pipe_idx));
308 }
309
310 // Returns list of all unique pipelines in the program.
311 const std::vector<Pipeline> &getPipelines() const { return pipelines; }
312
313 size_t size() const { return pipeIdxToPipeline.size(); }
314
315 private:
316 std::vector<Pipeline> pipelines;
317 ordered_map<int, int> pipeIdxToPipeline;
318};
319
321using BlockInfoMapping = std::multimap<const IR::Node *, BlockInfo>;
323using DefaultPortMap = std::map<int, std::vector<int>>;
324
326class ParseTna : public Inspector {
327 const IR::PackageBlock *mainBlock = nullptr;
328 P4::ReferenceMap *refMap;
329 P4::TypeMap *typeMap;
330
331 public:
332 ParseTna(P4::ReferenceMap *refMap, P4::TypeMap *typeMap) : refMap(refMap), typeMap(typeMap) {
333 setName("ParseTna");
334 }
335
336 // parse tna pipeline with single parser.
337 void parseSingleParserPipeline(const IR::PackageBlock *block, unsigned index);
338
339 // parse tna pipeline with multiple parser.
340 void parseMultipleParserInstances(const IR::PackageBlock *block, cstring pipe,
341 IR::BFN::P4Thread *thread, gress_t gress);
342
343 void parsePortMapAnnotation(const IR::PackageBlock *block, DefaultPortMap &map);
344
345 bool preorder(const IR::PackageBlock *block) override;
346
347 public:
348 ProgramPipelines pipelines;
349 BlockInfoMapping toBlockInfo;
350 bool hasMultiplePipes = false;
351 bool hasMultipleParsers = false;
352};
353
354struct DoRewriteControlAndParserBlocks : Transform {
355 P4::ReferenceMap *refMap;
356 P4::TypeMap *typeMap;
357 BlockInfoMapping *block_info;
358 // mapping from tuple(pipeline_name, block_index) to the block name.
360
361 explicit DoRewriteControlAndParserBlocks(P4::ReferenceMap *refMap, P4::TypeMap *typeMap,
362 BlockInfoMapping *block_info)
363 : refMap(refMap), typeMap(typeMap), block_info(block_info) {}
364 const IR::Node *postorder(IR::P4Parser *node) override;
365 const IR::Node *postorder(IR::P4Control *node) override;
366 const IR::Node *postorder(IR::Declaration_Instance *node) override;
367 Visitor::profile_t init_apply(const IR::Node *node) override {
368 block_name_map.clear();
369 return Transform::init_apply(node);
370 }
371};
372
382struct RewriteControlAndParserBlocks : public PassManager {
383 RewriteControlAndParserBlocks(P4::ReferenceMap *refMap, P4::TypeMap *typeMap) {
384 auto *evaluator = new P4::EvaluatorPass(refMap, typeMap);
385 auto *parseTna = new ParseTna(refMap, typeMap);
386
387 passes.push_back(evaluator);
388 passes.push_back(new VisitFunctor([evaluator, parseTna](const IR::Node *root) {
389 auto *evaluated_program = root->to<IR::P4Program>();
390 auto *toplevel = evaluator->getToplevelBlock();
391 // setup the context to know which pipes are available in the program: for logging and
392 // other output declarations.
393 BFNContext::get().discoverPipes(evaluated_program, toplevel);
394
395 auto *main = toplevel->getMain();
396 ERROR_CHECK(main != nullptr, ErrorType::ERR_INVALID,
397 "program: does not instantiate `main`");
398 main->apply(*parseTna);
399 return root;
400 }));
401 passes.emplace_back(new P4::TypeChecking(refMap, typeMap));
402 passes.emplace_back(
403 new DoRewriteControlAndParserBlocks(refMap, typeMap, &parseTna->toBlockInfo));
404 }
405};
406
412struct RestoreParams : public Transform {
413 explicit RestoreParams(BFN_Options &options, P4::ReferenceMap *refMap, P4::TypeMap *typeMap)
414 : options(options), refMap(refMap), typeMap(typeMap) {}
415 const IR::Node *postorder(IR::BFN::TnaControl *control) override;
416 const IR::Node *postorder(IR::BFN::TnaParser *parser) override;
417 const IR::Node *postorder(IR::BFN::TnaDeparser *deparser) override;
418 BFN_Options &options;
419 P4::ReferenceMap *refMap;
420 P4::TypeMap *typeMap;
421 cstring arch;
422 cstring version;
423};
424
429class LoweringType : public Transform {
430 std::map<cstring, unsigned> enum_encoding;
431
432 public:
433 LoweringType() {}
434
435 // lower MeterColor_t to bit<2> because it is used
436 const IR::Node *postorder(IR::Type_Enum *node) override {
437 if (node->name == "MeterColor_t") enum_encoding.emplace(node->name, 2);
438 return node;
439 }
440
441 const IR::Node *postorder(IR::Type_Name *node) override {
442 auto name = node->path->name;
443 if (enum_encoding.count(name)) {
444 auto size = enum_encoding.at(name);
445 return IR::Type_Bits::get(size);
446 }
447 return node;
448 }
449};
450
452class ApplyEvaluator : public PassManager {
453 public:
454 P4::ReferenceMap *refMap;
455 P4::TypeMap *typeMap;
456 const IR::ToplevelBlock *toplevel = nullptr;
457
458 ApplyEvaluator() {
459 refMap = new P4::ReferenceMap;
460 typeMap = new P4::TypeMap;
461 refMap->setIsV1(true);
462 auto evaluator = new BFN::EvaluatorPass(refMap, typeMap);
463 addPasses({
464 new BFN::TypeChecking(refMap, typeMap, true),
465 evaluator,
466 new VisitFunctor([this, evaluator]() { toplevel = evaluator->getToplevelBlock(); }),
467 });
468 }
469
470 ApplyEvaluator(P4::ReferenceMap *refMap, P4::TypeMap *typeMap)
471 : refMap(refMap), typeMap(typeMap) {
472 CHECK_NULL(refMap);
473 CHECK_NULL(typeMap);
474 refMap->setIsV1(true);
475 auto evaluator = new BFN::EvaluatorPass(refMap, typeMap);
476 addPasses({
477 new BFN::TypeChecking(refMap, typeMap, true),
478 evaluator,
479 new VisitFunctor([this, evaluator]() { toplevel = evaluator->getToplevelBlock(); }),
480 });
481 }
482
483 const IR::ToplevelBlock *getToplevelBlock() { return toplevel; }
484};
485
486} // namespace BFN
487
488#endif /* BF_P4C_ARCH_ARCH_H_ */
Definition arch.h:55
Definition arch.h:293
Definition bf-p4c-options.h:28
static BFNContext & get()
Definition bf-p4c-options.cpp:777
void discoverPipes(const IR::P4Program *, const IR::ToplevelBlock *)
identify the pipelines in the program and setup the _pipes map
Definition bf-p4c-options.cpp:829
Definition evaluator.h:115
Definition node.h:94
Definition visitor.h:413
Definition backends/common/programStructure.h:32
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition visitor.h:437
Definition typeChecker.h:55
Definition typeMap.h:41
Definition ir/pass_manager.h:184
Definition visitor.h:78
Definition cstring.h:85
Definition ordered_map.h:32
Definition assoc.h:300
int block_index
Index of the constructor.
Definition arch.h:231
cstring pipe_name
The pipe name to generate a fully qualified name in case of multipipe scenarios.
Definition arch.h:222
std::vector< int > portmap
which port to configure using this impl.
Definition arch.h:225
int pipe_index
Index in the Pipeline invocation.
Definition arch.h:220
cstring parser_instance_name
used by multi-parser support
Definition arch.h:229
ArchBlock_t block_type
A block could be a parser, deparser or a mau.
Definition arch.h:227
Definition arch.h:326
The namespace encapsulating Barefoot/Intel-specific stuff.
Definition add_t2na_meta.cpp:21
void warning(const char *format, Args &&...args)
Report a warning with the given message.
Definition lib/error.h:122
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition arch.h:266