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