P4C
The P4 Compiler
Loading...
Searching...
No Matches
tofino/bf-p4c/control-plane/bfruntime_arch_handler.h
1
19#ifndef BACKENDS_TOFINO_BF_P4C_CONTROL_PLANE_BFRUNTIME_ARCH_HANDLER_H_
20#define BACKENDS_TOFINO_BF_P4C_CONTROL_PLANE_BFRUNTIME_ARCH_HANDLER_H_
21
22#include <iostream>
23#include <optional>
24#include <set>
25#include <string>
26#include <unordered_map>
27#include <vector>
28
29#include "backends/tofino/bf-p4c/arch/fromv1.0/phase0.h"
30#include "backends/tofino/bf-p4c/arch/helpers.h"
31#include "backends/tofino/bf-p4c/arch/tna.h"
32#include "backends/tofino/bf-p4c/common/utils.h"
33#include "backends/tofino/bf-p4c/control-plane/bfruntime.h"
34#include "backends/tofino/bf-p4c/control-plane/p4runtime_force_std.h"
35#include "backends/tofino/bf-p4c/control-plane/runtime.h"
36#include "backends/tofino/bf-p4c/device.h"
37#include "barefoot/p4info.pb.h"
38#include "control-plane/flattenHeader.h"
39#include "control-plane/p4RuntimeArchHandler.h"
40#include "control-plane/p4RuntimeSerializer.h"
41#include "control-plane/typeSpecConverter.h"
42#include "frontends/common/resolveReferences/referenceMap.h"
43#include "frontends/p4/externInstance.h"
44#include "frontends/p4/methodInstance.h"
45#include "frontends/p4/typeMap.h"
46#include "ir/ir-generated.h"
47#include "lib/log.h"
48#include "midend/eliminateTypedefs.h"
49
51using P4::TypeMap;
52using P4::ControlPlaneAPI::p4rt_id_t;
54
55namespace p4configv1 = ::p4::config::v1;
56
57namespace BFN {
58
65enum class Arch { TNA, PSA };
66
67template <Arch arch>
68struct CounterExtern {};
69template <Arch arch>
70struct MeterExtern {};
71
72} // namespace BFN
73
74namespace P4 {
75
76namespace ControlPlaneAPI {
77
78namespace Helpers {
79
81template <>
82struct CounterlikeTraits<::BFN::CounterExtern<BFN::Arch::TNA>> {
83 static const cstring name() { return "counter"_cs; }
84 static const cstring directPropertyName() { return "counters"_cs; }
85 static const cstring typeName() { return "Counter"_cs; }
86 static const cstring directTypeName() { return "DirectCounter"_cs; }
87 static const cstring sizeParamName() { return "size"_cs; }
88 static ::barefoot::CounterSpec::Unit mapUnitName(const cstring name) {
89 using ::barefoot::CounterSpec;
90 if (name == "PACKETS")
91 return CounterSpec::PACKETS;
92 else if (name == "BYTES")
93 return CounterSpec::BYTES;
94 else if (name == "PACKETS_AND_BYTES")
95 return CounterSpec::PACKETS_AND_BYTES;
96 return CounterSpec::UNSPECIFIED;
97 }
98 static std::optional<size_t> indexTypeParamIdx() { return 1; }
99};
100
102template <>
103struct CounterlikeTraits<::BFN::CounterExtern<BFN::Arch::PSA>> {
104 static const cstring name() { return "counter"_cs; }
105 static const cstring directPropertyName() { return "psa_direct_counter"_cs; }
106 static const cstring typeName() { return "Counter"_cs; }
107 static const cstring directTypeName() { return "DirectCounter"_cs; }
108 static const cstring sizeParamName() { return "n_counters"_cs; }
109 static ::barefoot::CounterSpec::Unit mapUnitName(const cstring name) {
110 using ::barefoot::CounterSpec;
111 if (name == "PACKETS")
112 return CounterSpec::PACKETS;
113 else if (name == "BYTES")
114 return CounterSpec::BYTES;
115 else if (name == "PACKETS_AND_BYTES")
116 return CounterSpec::PACKETS_AND_BYTES;
117 return CounterSpec::UNSPECIFIED;
118 }
119 // the index of the type parameter for the counter index, in the type
120 // parameter list of the extern type declaration.
121 static std::optional<size_t> indexTypeParamIdx() { return 1; }
122};
123
125template <>
126struct CounterlikeTraits<::BFN::MeterExtern<BFN::Arch::TNA>> {
127 static const cstring name() { return "meter"_cs; }
128 static const cstring directPropertyName() { return "meters"_cs; }
129 static const cstring typeName() { return "Meter"_cs; }
130 static const cstring directTypeName() { return "DirectMeter"_cs; }
131 static const cstring sizeParamName() { return "size"_cs; }
132 static ::barefoot::MeterSpec::Unit mapUnitName(const cstring name) {
133 using ::barefoot::MeterSpec;
134 if (name == "PACKETS")
135 return MeterSpec::PACKETS;
136 else if (name == "BYTES")
137 return MeterSpec::BYTES;
138 return MeterSpec::UNSPECIFIED;
139 }
140 static std::optional<size_t> indexTypeParamIdx() { return 0; }
141};
142
144template <>
145struct CounterlikeTraits<::BFN::MeterExtern<BFN::Arch::PSA>> {
146 static const cstring name() { return "meter"_cs; }
147 static const cstring directPropertyName() { return "psa_direct_meter"_cs; }
148 static const cstring typeName() { return "Meter"_cs; }
149 static const cstring directTypeName() { return "DirectMeter"_cs; }
150 static const cstring sizeParamName() { return "n_meters"_cs; }
151 static ::barefoot::MeterSpec::Unit mapUnitName(const cstring name) {
152 using ::barefoot::MeterSpec;
153 if (name == "PACKETS")
154 return MeterSpec::PACKETS;
155 else if (name == "BYTES")
156 return MeterSpec::BYTES;
157 return MeterSpec::UNSPECIFIED;
158 }
159 // the index of the type parameter for the meter index, in the type
160 // parameter list of the extern type declaration.
161 static std::optional<size_t> indexTypeParamIdx() { return 0; }
162};
163} // namespace Helpers
164
165} // namespace ControlPlaneAPI
166
167} // namespace P4
168
170
171namespace BFN {
172
173using namespace P4;
174
177 public:
178 SymbolType() = delete;
179
180 static P4RuntimeSymbolType P4RT_ACTION_PROFILE() {
181 return P4RuntimeSymbolType::make(barefoot::P4Ids::ACTION_PROFILE);
182 }
183 static P4RuntimeSymbolType P4RT_ACTION_SELECTOR() {
184 return P4RuntimeSymbolType::make(barefoot::P4Ids::ACTION_SELECTOR);
185 }
186 static P4RuntimeSymbolType P4RT_COUNTER() {
187 return P4RuntimeSymbolType::make(barefoot::P4Ids::COUNTER);
188 }
189 static P4RuntimeSymbolType P4RT_DIRECT_COUNTER() {
190 return P4RuntimeSymbolType::make(barefoot::P4Ids::DIRECT_COUNTER);
191 }
192 static P4RuntimeSymbolType P4RT_METER() {
193 return P4RuntimeSymbolType::make(barefoot::P4Ids::METER);
194 }
195 static P4RuntimeSymbolType P4RT_DIRECT_METER() {
196 return P4RuntimeSymbolType::make(barefoot::P4Ids::DIRECT_METER);
197 }
198 static P4RuntimeSymbolType P4RT_DIGEST() {
199 return P4RuntimeSymbolType::make(barefoot::P4Ids::DIGEST);
200 }
201 static P4RuntimeSymbolType P4RT_DIRECT_REGISTER() {
202 return P4RuntimeSymbolType::make(barefoot::P4Ids::DIRECT_REGISTER);
203 }
204 static P4RuntimeSymbolType P4RT_REGISTER() {
205 return P4RuntimeSymbolType::make(barefoot::P4Ids::REGISTER);
206 }
207 static P4RuntimeSymbolType P4RT_REGISTER_PARAM() {
208 return P4RuntimeSymbolType::make(barefoot::P4Ids::REGISTER_PARAM);
209 }
210 static P4RuntimeSymbolType P4RT_PORT_METADATA() {
211 return P4RuntimeSymbolType::make(barefoot::P4Ids::PORT_METADATA);
212 }
213 static P4RuntimeSymbolType P4RT_HASH() {
214 return P4RuntimeSymbolType::make(barefoot::P4Ids::HASH);
215 }
216 static P4RuntimeSymbolType P4RT_LPF() {
217 return P4RuntimeSymbolType::make(barefoot::P4Ids::LPF);
218 }
219 static P4RuntimeSymbolType P4RT_DIRECT_LPF() {
220 return P4RuntimeSymbolType::make(barefoot::P4Ids::DIRECT_LPF);
221 }
222 static P4RuntimeSymbolType P4RT_WRED() {
223 return P4RuntimeSymbolType::make(barefoot::P4Ids::WRED);
224 }
225 static P4RuntimeSymbolType P4RT_DIRECT_WRED() {
226 return P4RuntimeSymbolType::make(barefoot::P4Ids::DIRECT_WRED);
227 }
228 static P4RuntimeSymbolType P4RT_SNAPSHOT() {
229 return P4RuntimeSymbolType::make(barefoot::P4Ids::SNAPSHOT);
230 }
231 static P4RuntimeSymbolType P4RT_PARSER_CHOICES() {
232 return P4RuntimeSymbolType::make(barefoot::P4Ids::PARSER_CHOICES);
233 }
234 static P4RuntimeSymbolType P4RT_VALUE_SET() {
235 return P4RuntimeSymbolType::make(barefoot::P4Ids::VALUE_SET);
236 }
237};
238
239static cstring prefix(cstring p, cstring str) { return p.isNullOrEmpty() ? str : p + "." + str; }
240
244 const cstring name; // The fully qualified external name of this action profile.
245 const int64_t size;
246 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this action
247 // profile declaration.
248
249 p4rt_id_t getId(const P4RuntimeSymbolTableIface &symbols,
250 const cstring blockPrefix = cstring::empty) const {
251 auto symName = prefix(blockPrefix, name);
252 return symbols.getId(SymbolType::P4RT_ACTION_PROFILE(), symName);
253 }
254};
255
259 const cstring name; // The fully qualified external name of this action selector.
260 const std::optional<cstring> actionProfileName; // If not known, we will generate
261 // an action profile instance.
262 const int64_t size; // TODO: size does not make sense with new ActionSelector P4 extern
263 const int64_t maxGroupSize;
264 const int64_t numGroups;
265 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this action
266 // profile declaration.
267 bool selSuffix;
268
269 p4rt_id_t getId(const P4RuntimeSymbolTableIface &symbols,
270 const cstring blockPrefix = cstring::empty) const {
271 auto symName = prefix(blockPrefix, name);
272 auto symSelectorName = (selSuffix) ? symName + "_sel" : symName;
273 if (actionProfileName) {
274 return symbols.getId(SymbolType::P4RT_ACTION_SELECTOR(), symName);
275 }
276 return symbols.getId(SymbolType::P4RT_ACTION_SELECTOR(), symSelectorName);
277 }
278};
279
281struct Digest {
282 const cstring name; // The fully qualified external name of the digest
283 const p4configv1::P4DataTypeSpec *typeSpec; // The format of the packed data.
284 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this digest
285 // declaration.
286};
287
289struct DynHash {
290 const cstring name; // The fully qualified external name of the dynhash
291 // The format of the fields used for hash calculation.
292 const p4configv1::P4DataTypeSpec *typeSpec;
293 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this dynhash
294 // declaration.
295 struct hashField {
296 cstring hashFieldName; // Field Name
297 bool isConstant; // true if field is a constant
298 };
299 std::vector<hashField> hashFieldInfo;
300 const int hashWidth;
301};
302
304struct ValueSet {
305 const cstring name;
306 const p4configv1::P4DataTypeSpec *typeSpec; // The format of the stored data
307 const int64_t size; // Number of entries in the value set
308 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this value set
309 // declaration.
310
311 static std::optional<ValueSet> from(const cstring name, const IR::P4ValueSet *instance,
312 const ReferenceMap *refMap, TypeMap *typeMap,
313 p4configv1::P4TypeInfo *p4RtTypeInfo) {
314 CHECK_NULL(instance);
315 int64_t size = 0;
316 auto sizeConstant = instance->size->to<IR::Constant>();
317 if (sizeConstant == nullptr || !sizeConstant->fitsInt()) {
318 error("@size should be an integer for declaration %1%", instance);
319 return std::nullopt;
320 }
321 if (sizeConstant->value < 0) {
322 error("@size should be a positive integer for declaration %1%", instance);
323 return std::nullopt;
324 }
325 size = static_cast<int64_t>(sizeConstant->value);
327 refMap, typeMap, instance->elementType, p4RtTypeInfo);
328 CHECK_NULL(typeSpec);
329 return ValueSet{name, typeSpec, size, instance->to<IR::IAnnotated>()};
330 }
331};
332
334struct Register {
335 const cstring name; // The fully qualified external name of the register table
336 const p4configv1::P4DataTypeSpec *typeSpec; // The format of the packed data.
337 int64_t size;
338 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this register
339 // declaration.
340
343 static std::optional<Register> from(const IR::ExternBlock *instance, const ReferenceMap *refMap,
344 TypeMap *typeMap, p4configv1::P4TypeInfo *p4RtTypeInfo) {
345 CHECK_NULL(instance);
346 auto declaration = instance->node->to<IR::Declaration_Instance>();
347
348 auto size = instance->getParameterValue("size"_cs);
349
350 // retrieve type parameter for the register instance and convert it to P4DataTypeSpec
351 BUG_CHECK(declaration->type->is<IR::Type_Specialized>(), "%1%: expected Type_Specialized",
352 declaration->type);
353 auto type = declaration->type->to<IR::Type_Specialized>();
354 BUG_CHECK(type->arguments->size() == 2, "%1%: expected two type arguments", instance);
355 auto typeArg = type->arguments->at(0);
356 auto typeSpec =
357 P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
358 CHECK_NULL(typeSpec);
359
360 return Register{declaration->controlPlaneName(), typeSpec,
361 int64_t(size->to<IR::Constant>()->value),
362 declaration->to<IR::IAnnotated>()};
363 }
364
367 static std::optional<Register> fromDirect(const P4::ExternInstance &instance,
368 const IR::P4Table *table, const ReferenceMap *refMap,
369 TypeMap *typeMap,
370 p4configv1::P4TypeInfo *p4RtTypeInfo) {
371 CHECK_NULL(table);
372 BUG_CHECK(instance.name != std::nullopt, "Caller should've ensured we have a name");
373
374 // retrieve type parameter for the register instance and convert it to P4DataTypeSpec
375 if (!instance.expression->is<IR::PathExpression>()) {
376 return std::nullopt;
377 }
378 auto path = instance.expression->to<IR::PathExpression>()->path;
379 auto decl = refMap->getDeclaration(path, true);
380 BUG_CHECK(decl->is<IR::Declaration_Instance>(), "%1%: expected Declaration_Instance", decl);
381 auto declaration = decl->to<IR::Declaration_Instance>();
382 BUG_CHECK(declaration->type->is<IR::Type_Specialized>(), "%1%: expected Type_Specialized",
383 declaration->type);
384 auto type = declaration->type->to<IR::Type_Specialized>();
385 BUG_CHECK(type->arguments->size() == 1, "%1%: expected one type argument", declaration);
386 auto typeArg = type->arguments->at(0);
387 auto typeSpec =
388 P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
389 CHECK_NULL(typeSpec);
390
391 return Register{*instance.name, typeSpec, 0, instance.annotations};
392 }
393};
394
397 const cstring name; // The fully qualified external name of the register parameter
398 const p4configv1::P4DataTypeSpec *typeSpec; // The format of the packed data.
399 int64_t initial_value;
400 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this register
401 // declaration.
402
405 static std::optional<RegisterParam> from(const IR::ExternBlock *instance,
406 const ReferenceMap *refMap, TypeMap *typeMap,
407 p4configv1::P4TypeInfo *p4RtTypeInfo) {
408 CHECK_NULL(instance);
409 auto declaration = instance->node->to<IR::Declaration_Instance>();
410
411 auto initial_value = instance->getParameterValue("initial_value"_cs);
412
413 // retrieve type parameter for the register parameter instance
414 // and convert it to P4DataTypeSpec
415 BUG_CHECK(declaration->type->is<IR::Type_Specialized>(), "%1%: expected Type_Specialized",
416 declaration->type);
417 auto type = declaration->type->to<IR::Type_Specialized>();
418 BUG_CHECK(type->arguments->size() == 1, "%1%: expected one type argument", instance);
419 // initial value
420 auto typeArg = type->arguments->at(0);
421 auto typeSpec =
422 P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
423 CHECK_NULL(typeSpec);
424
425 return RegisterParam{declaration->controlPlaneName(), typeSpec,
426 initial_value->to<IR::Constant>()->asInt64(),
427 declaration->to<IR::IAnnotated>()};
428 }
429};
430
432struct Lpf {
433 const cstring name; // The fully qualified external name of the filter
434 int64_t size;
436 const std::optional<cstring> table;
437 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this Lpf
438 // declaration.
439
442 static std::optional<Lpf> from(const IR::ExternBlock *instance) {
443 CHECK_NULL(instance);
444 auto declaration = instance->node->to<IR::Declaration_Instance>();
445 auto size = instance->getParameterValue("size"_cs);
446 return Lpf{declaration->controlPlaneName(), size->to<IR::Constant>()->asInt(), std::nullopt,
447 declaration->to<IR::IAnnotated>()};
448 }
449
452 static std::optional<Lpf> fromDirect(const P4::ExternInstance &instance,
453 const IR::P4Table *table) {
454 CHECK_NULL(table);
455 BUG_CHECK(instance.name != std::nullopt, "Caller should've ensured we have a name");
456 return Lpf{*instance.name, 0, table->controlPlaneName(), instance.annotations};
457 }
458};
459
461struct Wred {
462 const cstring name; // The fully qualified external name of the filter
463 uint8_t dropValue;
464 uint8_t noDropValue;
465 int64_t size;
467 const std::optional<cstring> table;
468 const IR::IAnnotated *annotations; // If non-null, any annotations applied to this wred
469 // declaration.
470
473 static std::optional<Wred> from(const IR::ExternBlock *instance) {
474 CHECK_NULL(instance);
475 auto declaration = instance->node->to<IR::Declaration_Instance>();
476
477 auto size = instance->getParameterValue("size"_cs);
478 auto dropValue = instance->getParameterValue("drop_value"_cs);
479 auto noDropValue = instance->getParameterValue("no_drop_value"_cs);
480
481 return Wred{declaration->controlPlaneName(),
482 static_cast<uint8_t>(dropValue->to<IR::Constant>()->asUnsigned()),
483 static_cast<uint8_t>(noDropValue->to<IR::Constant>()->asUnsigned()),
484 size->to<IR::Constant>()->asInt(),
485 std::nullopt,
486 declaration->to<IR::IAnnotated>()};
487 }
488
491 static std::optional<Wred> fromDirect(const P4::ExternInstance &instance,
492 const IR::P4Table *table) {
493 CHECK_NULL(table);
494 BUG_CHECK(instance.name != std::nullopt, "Caller should've ensured we have a name");
495
496 auto dropValue = instance.substitution.lookupByName("drop_value"_cs)->expression;
497 BUG_CHECK(dropValue->to<IR::Constant>(), "Non-constant drop_value");
498 auto noDropValue = instance.substitution.lookupByName("no_drop_value"_cs)->expression;
499 BUG_CHECK(noDropValue->to<IR::Constant>(), "Non-constant no_drop_value");
500
501 return Wred{*instance.name,
502 static_cast<uint8_t>(dropValue->to<IR::Constant>()->asUnsigned()),
503 static_cast<uint8_t>(noDropValue->to<IR::Constant>()->asUnsigned()),
504 0,
505 table->controlPlaneName(),
506 instance.annotations};
507 }
508};
509
511 const p4configv1::P4DataTypeSpec *typeSpec; // format of port metadata
512 static const cstring name() { return "$PORT_METADATA"_cs; }
513};
514
519 std::string name;
520 uint32_t id;
521 int32_t bitwidth;
522 bool operator==(const SnapshotFieldInfo &s) const {
523 if (s.name == name && s.id == id && s.bitwidth == bitwidth) return true;
524 return false;
525 }
526 bool operator<(const SnapshotFieldInfo &s) const { return (id < s.id); }
527};
528
536 public:
537 using Id = uint32_t;
538 Id assignId(const std::string &name) {
539 auto idIt = idMap.find(name);
540 if (idIt != idMap.end()) return idIt->second;
541 // we never use an id of 0 in P4Info / P4Runtime / BFRT
542 idMap[name] = ++firstUnusedId;
543 return firstUnusedId;
544 }
545
546 private:
547 Id firstUnusedId{0};
548 std::unordered_map<std::string, Id> idMap{};
549};
550
556 private:
557 TypeMap *typeMap;
560 bool includeValid;
562 std::set<SnapshotFieldInfo> *fields;
566 SnapshotFieldIdTable *fieldIds;
570 std::vector<cstring> prefixList;
571
572 SnapshotFieldFinder(TypeMap *typeMap, cstring prefix, bool includeValid,
573 std::set<SnapshotFieldInfo> *fields, SnapshotFieldIdTable *fieldIds)
574 : typeMap(typeMap), includeValid(includeValid), fields(fields), fieldIds(fieldIds) {
575 prefixList.push_back(prefix);
576 // Setting visitDagOnce to false so IR nodes can be visited more than once. This is required
577 // while dealing with header stacks where we have to loop for all elements in a stack.
578 // Type_Stack is not a vector so we have a single node which needs to output 'n' values for
579 // a size 'n' stack.
580 visitDagOnce = false;
581 }
582
583 std::string assembleName() const {
584 std::string name;
585 for (const auto &e : prefixList) name += e + ".";
586 name.pop_back();
587 return name;
588 }
589
590 void addField(int32_t bitwidth) {
591 auto name = assembleName();
592 auto id = fieldIds->assignId(name);
593 SnapshotFieldInfo field = {name, id, bitwidth};
594 LOG5("Adding snapshot to bfrt info for field: { " << name << ", " << id << ", " << bitwidth
595 << " }");
596 fields->insert(field);
597 }
598
599 bool preorder(const IR::Type_Header *type) override {
600 Log::TempIndent indent;
601 LOG4("SnapshotFinder preorder Type_Header: " << type << indent);
602 auto flattenedType = P4::ControlPlaneAPI::FlattenHeader::flatten(typeMap, type);
603 if (includeValid) {
604 prefixList.push_back("$valid"_cs);
605 addField(1); // valid field (POV) has bitwidth of 1
606 prefixList.pop_back();
607 }
608 for (const auto &sf : flattenedType->fields) visit(sf);
609 return false;
610 }
611
612 bool preorder(const IR::StructField *f) override {
613 Log::TempIndent indent;
614 LOG4("SnapshotFinder preorder StructField : " << f << indent);
615 auto typeType = typeMap->getTypeType(f->type, true);
616 prefixList.push_back(f->controlPlaneName());
617 visit(typeType);
618 prefixList.pop_back();
619 return false;
620 }
621
622 bool preorder(const IR::Type_Stack *st) override {
623 Log::TempIndent indent;
624 LOG4("SnapshotFinder preorder Stack : " << st << indent);
625 // Remove stack name and re-insert based on index
626 // E.g. hdr.stack --> hdr.stack$0 / hdr.stack$1 ...
627 auto p = prefixList.back();
628 prefixList.pop_back();
629 for (size_t i = 0; i < st->getSize(); i++) {
630 prefixList.push_back(p + "$" + std::to_string(i));
631 visit(st->elementType);
632 prefixList.pop_back();
633 }
634 prefixList.push_back(p);
635 return false;
636 }
637
638 bool preorder(const IR::Type_Bits *type) override {
639 Log::TempIndent indent;
640 LOG4("SnapshotFinder preorder Type_Bits: " << type << indent);
641 addField(type->width_bits());
642 return false;
643 }
644
645 bool preorder(const IR::Type_Varbits *type) override {
646 Log::TempIndent indent;
647 LOG4("SnapshotFinder preorder Type_Varbits: " << type << indent);
648 // TODO: unsure whether anything needs to be done / can be done
649 // for VL fields.
650 (void)type;
651 return false;
652 }
653
654 public:
657 static void find(TypeMap *typeMap, const IR::Type *type, cstring paramName, bool includeValid,
658 std::set<SnapshotFieldInfo> *fields, SnapshotFieldIdTable *fieldIds) {
659 SnapshotFieldFinder finder(typeMap, paramName, includeValid, fields, fieldIds);
660 auto typeType = typeMap->getTypeType(type, true);
661 typeType->apply(finder);
662 }
663};
664
668template <Arch arch>
670 protected:
675
677 const IR::ToplevelBlock *evaluatedProgram)
678 : refMap(refMap), typeMap(typeMap), evaluatedProgram(evaluatedProgram) {}
679
680 // Overridden function call from base ArchIFace class. Table blocks are
681 // added entirely in the frontend and this call ensures we have our own
682 // implementation of control plane name generation (with the pipe prefix).
683 // This is relevant in multi pipe scenarios where a table (its control) is
684 // shared across pipes and needs fully qualified unique names.
685 cstring getControlPlaneName(const IR::Block *block) override {
686 return getControlPlaneName(block, nullptr);
687 }
688
689 cstring getControlPlaneName(const IR::Block *block, const IR::IDeclaration *decl) {
690 auto declName = decl ? decl->controlPlaneName() : cstring::empty;
691 return getFullyQualifiedName(block, declName);
692 }
693
694 // Given a block get its block prefix (usually pipe name) generate in the
695 // blockNamePrefixMap and prefix it to the control plane name. This name is
696 // unique to the resource. For multi pipe scenarios this becomes relevant
697 // since a resource can be shared across pipes but need to be addressed by
698 // the control plane as separate resources.
699 // Note, in some cases like multiparser blocks, the parser names are always
700 // arch names since the instantiations are always anonymous. In such cases
701 // we skip the control plane name
702 // E.g.
703 // P4:
704 // IngressParsers(IgCPUParser(), IgNetworkParser()) ig_pipe0;
705 // MultiParserPipeline(ig_pipe0, SwitchIngress(), SwitchIngressDeparser(),
706 // eg_pipe0, SwitchEgress(), SwitchEgressDeparser()) pipe0;
707 // BF-RT JSON : pipe0.ig_pipe0.prsr0
708 // CTXT JSON : ig_pipe0.prsr0
709 cstring getFullyQualifiedName(const IR::Block *block, const cstring name,
710 bool skip_control_plane_name = false) {
711 cstring block_name = cstring::empty;
712 cstring control_plane_name = cstring::empty;
713 cstring full_name = getBlockNamePrefix(block);
714 if (!skip_control_plane_name) {
715 if (auto cont = block->getContainer()) {
716 block_name = cont->getName();
717 control_plane_name = cont->controlPlaneName();
718 full_name = prefix(full_name, control_plane_name);
719 }
720 }
721
722 if (!name.isNullOrEmpty()) full_name = prefix(full_name, name);
723 LOG5("Block : " << block << ", block_name: " << block_name
724 << ", block_name_prefix: " << getBlockNamePrefix(block)
725 << ", control_plane_name: " << control_plane_name << ", name: " << name
726 << ", fqname: " << full_name);
727 return full_name;
728 }
729
730 virtual cstring getBlockNamePrefix(const IR::Block *) { return defaultPipeName; }
731
733 const IR::TableBlock *tableBlock) override {
734 CHECK_NULL(tableBlock);
735 bool isConstructedInPlace = false;
736
738
739 {
740 // Only collect the symbol if the action profile / selector is
741 // constructed in place. Otherwise it will be collected by
742 // collectExternInstance, which will avoid duplicates.
743 auto table = tableBlock->container;
744 LOG2("Collecting Table Properties on block " << table->name);
745 auto action_profile = getExternInstanceFromPropertyByTypeName(
746 table, implementationString, "ActionProfile"_cs, refMap, typeMap,
747 &isConstructedInPlace);
748 if (action_profile) {
749 cstring tableName = *action_profile->name;
750 tableName = prefix(getBlockNamePrefix(tableBlock), tableName);
751 if (isConstructedInPlace)
752 symbols->add(SymbolType::P4RT_ACTION_PROFILE(), tableName);
753 }
754 auto action_selector = getExternInstanceFromPropertyByTypeName(
755 table, implementationString, "ActionSelector"_cs, refMap, typeMap,
756 &isConstructedInPlace);
757 if (action_selector) {
758 cstring tableName = *action_selector->name;
759 tableName = prefix(getBlockNamePrefix(tableBlock), tableName);
760 if (action_selector->substitution.lookupByName("size"_cs)) {
761 std::string selectorName(tableName + "_sel");
762 symbols->add(SymbolType::P4RT_ACTION_SELECTOR(), selectorName);
763 symbols->add(SymbolType::P4RT_ACTION_PROFILE(), tableName);
764 } else {
765 symbols->add(SymbolType::P4RT_ACTION_SELECTOR(), tableName);
766 }
767 }
768 }
769 // In TNA direct counters / meters cannot be constructed in place in the
770 // table declaration because the count / execute method has to be
771 // called.
772 }
773
774 void collectExternInstanceCommon(P4RuntimeSymbolTableIface *symbols,
775 const IR::ExternBlock *externBlock) {
776 CHECK_NULL(externBlock);
777
778 auto decl = externBlock->node->to<IR::IDeclaration>();
779 // Skip externs instantiated inside table declarations (as properties);
780 // that should only apply to action profiles / selectors since direct
781 // resources cannot be constructed in place for TNA.
782 if (decl == nullptr) return;
783
784 auto symName = getControlPlaneName(externBlock, decl);
785 if (externBlock->type->name == "Counter") {
786 symbols->add(SymbolType::P4RT_COUNTER(), symName);
787 } else if (externBlock->type->name == "DirectCounter") {
788 symbols->add(SymbolType::P4RT_DIRECT_COUNTER(), symName);
789 } else if (externBlock->type->name == "Meter") {
790 symbols->add(SymbolType::P4RT_METER(), symName);
791 } else if (externBlock->type->name == "DirectMeter") {
792 symbols->add(SymbolType::P4RT_DIRECT_METER(), symName);
793 } else if (externBlock->type->name == "ActionProfile") {
794 symbols->add(SymbolType::P4RT_ACTION_PROFILE(), symName);
795 } else if (externBlock->type->name == "ActionSelector") {
796 if (externBlock->findParameterValue("size"_cs)) {
797 std::string selectorName(symName + "_sel");
798 symbols->add(SymbolType::P4RT_ACTION_SELECTOR(), selectorName);
799 symbols->add(SymbolType::P4RT_ACTION_PROFILE(), symName);
800 } else {
801 symbols->add(SymbolType::P4RT_ACTION_SELECTOR(), symName);
802 }
803 } else if (externBlock->type->name == "Digest") {
804 symbols->add(SymbolType::P4RT_DIGEST(), symName);
805 } else if (externBlock->type->name == "Register") {
806 symbols->add(SymbolType::P4RT_REGISTER(), symName);
807 } else if (externBlock->type->name == "DirectRegister") {
808 symbols->add(SymbolType::P4RT_DIRECT_REGISTER(), symName);
809 } else if (externBlock->type->name == "Hash") {
810 symbols->add(SymbolType::P4RT_HASH(), symName);
811 }
812 }
813
815 const IR::AssignmentStatement *) override {}
816
818
820
821 void collectParserSymbols(P4RuntimeSymbolTableIface *symbols,
822 const IR::ParserBlock *parserBlock) {
823 CHECK_NULL(parserBlock);
824 auto parser = parserBlock->container;
825 CHECK_NULL(parser);
826
827 // Collect any extern functions it may invoke.
828
829 for (auto s : parser->parserLocals) {
830 if (auto inst = s->to<IR::P4ValueSet>()) {
831 symbols->add(SymbolType::P4RT_VALUE_SET(), inst->controlPlaneName());
832 }
833 }
834 }
835
836 void collectExtra(P4RuntimeSymbolTableIface *symbols) override {
837 // Collect value sets. This step is required because value set support
838 // in "standard" P4Info is currently insufficient.
839 // Also retrieve user-provided name for ig_intr_md parameter in ingress
840 // parser to use as key name for phase0 table.
841 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
842 if (!block->is<IR::ParserBlock>()) return;
843 collectParserSymbols(symbols, block->to<IR::ParserBlock>());
844 });
845 }
846
847 void addTablePropertiesCommon(const P4RuntimeSymbolTableIface &symbols,
848 p4configv1::P4Info *p4info, p4configv1::Table *table,
849 const IR::TableBlock *tableBlock,
850 cstring blockPrefix = cstring::empty) {
851 CHECK_NULL(tableBlock);
852 auto tableDeclaration = tableBlock->container;
853
855
856 auto p4RtTypeInfo = p4info->mutable_type_info();
857
858 auto actionProfile = getActionProfile(tableDeclaration, refMap, typeMap);
859 auto actionSelector = getActionSelector(tableDeclaration, refMap, typeMap);
860 auto directCounter =
861 Helpers::getDirectCounterlike<ArchCounterExtern>(tableDeclaration, refMap, typeMap);
862 auto directMeter =
863 Helpers::getDirectCounterlike<ArchMeterExtern>(tableDeclaration, refMap, typeMap);
864 auto directRegister = getDirectRegister(tableDeclaration, refMap, typeMap, p4RtTypeInfo);
865 auto supportsTimeout = getSupportsTimeout(tableDeclaration);
866
867 if (actionProfile) {
868 auto id = actionProfile->getId(symbols, blockPrefix);
869 table->set_implementation_id(id);
870 if (isExternPropertyConstructedInPlace(tableDeclaration, implementationString)) {
871 addActionProfile(symbols, p4info, *actionProfile, blockPrefix);
872 }
873 }
874
875 if (actionSelector) {
876 auto id = actionSelector->getId(symbols, blockPrefix);
877 table->set_implementation_id(id);
878 if (isExternPropertyConstructedInPlace(tableDeclaration, implementationString)) {
879 addActionSelector(symbols, p4info, *actionSelector, blockPrefix);
880 }
881 }
882
883 // Direct resources are handled here. There is no risk to create
884 // duplicates as direct resources cannot be shared across tables. We
885 // could also handle those in addExternInstance but it would not be very
886 // convenient to get a handle on the parent table (the parent table's id
887 // is included in the P4Info message).
888 if (directCounter) {
889 auto id = symbols.getId(SymbolType::P4RT_DIRECT_COUNTER(),
890 prefix(blockPrefix, directCounter->name));
891 table->add_direct_resource_ids(id);
892 addCounter(symbols, p4info, *directCounter, blockPrefix);
893 }
894
895 if (directMeter) {
896 auto id = symbols.getId(SymbolType::P4RT_DIRECT_METER(),
897 prefix(blockPrefix, directMeter->name));
898 table->add_direct_resource_ids(id);
899 addMeter(symbols, p4info, *directMeter, blockPrefix);
900 }
901
902 if (directRegister) {
903 auto id = symbols.getId(SymbolType::P4RT_DIRECT_REGISTER(),
904 prefix(blockPrefix, directRegister->name));
905 table->add_direct_resource_ids(id);
906 addRegister(symbols, p4info, *directRegister, blockPrefix);
907 }
908
909 // TODO: idle timeout may change for TNA in the future and we
910 // may need to rely on P4Info table specific extensions.
911 if (supportsTimeout) {
912 table->set_idle_timeout_behavior(p4configv1::Table::NOTIFY_CONTROL);
913 } else {
914 table->set_idle_timeout_behavior(p4configv1::Table::NO_TIMEOUT);
915 }
916 }
917
920 static bool getSupportsTimeout(const IR::P4Table *table) {
921 auto timeout = table->properties->getProperty("idle_timeout"_cs);
922 if (timeout == nullptr) return false;
923 if (!timeout->value->is<IR::ExpressionValue>()) {
924 error("Unexpected value %1% for idle_timeout on table %2%", timeout, table);
925 return false;
926 }
927
928 auto expr = timeout->value->to<IR::ExpressionValue>()->expression;
929 if (!expr->is<IR::BoolLiteral>()) {
930 error(
931 "Unexpected non-boolean value %1% for idle_timeout "
932 "property on table %2%",
933 timeout, table);
934 return false;
935 }
936
937 return expr->to<IR::BoolLiteral>()->value;
938 }
939
942 static std::optional<Register> getDirectRegister(const IR::P4Table *table, ReferenceMap *refMap,
943 TypeMap *typeMap,
944 p4configv1::P4TypeInfo *p4RtTypeInfo) {
945 auto directRegisterInstance =
946 Helpers::getExternInstanceFromProperty(table, "registers"_cs, refMap, typeMap);
947 if (!directRegisterInstance) return std::nullopt;
948 return Register::fromDirect(*directRegisterInstance, table, refMap, typeMap, p4RtTypeInfo);
949 }
950
951 void addExternInstance(const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
952 const IR::ExternBlock *) override {}
953
954 void addExternInstanceCommon(const P4RuntimeSymbolTableIface &symbols,
955 p4configv1::P4Info *p4info, const IR::ExternBlock *externBlock,
956 cstring pipeName = cstring::empty) {
957 Log::TempIndent indent;
958 LOG1("Adding Extern Instances for pipe " << pipeName << indent);
959 auto decl = externBlock->node->to<IR::Declaration_Instance>();
960 // Skip externs instantiated inside table declarations (constructed in
961 // place as properties).
962 if (decl == nullptr) return;
963
965
966 auto p4RtTypeInfo = p4info->mutable_type_info();
967 // Direct resources are handled by addTableProperties.
968 if (externBlock->type->name == "ActionProfile") {
969 auto actionProfile = getActionProfile(externBlock);
970 if (actionProfile) addActionProfile(symbols, p4info, *actionProfile, pipeName);
971 } else if (externBlock->type->name == "ActionSelector") {
972 auto actionSelector = getActionSelector(externBlock);
973 if (actionSelector) addActionSelector(symbols, p4info, *actionSelector, pipeName);
974 } else if (externBlock->type->name == "Counter") {
975 auto counter =
976 Counterlike<ArchCounterExtern>::from(externBlock, refMap, typeMap, p4RtTypeInfo);
977 if (counter) addCounter(symbols, p4info, *counter, pipeName);
978 } else if (externBlock->type->name == "Meter") {
979 auto meter =
980 Counterlike<ArchMeterExtern>::from(externBlock, refMap, typeMap, p4RtTypeInfo);
981 if (meter) addMeter(symbols, p4info, *meter, pipeName);
982 } else if (externBlock->type->name == "Digest") {
983 auto digest = getDigest(decl, p4RtTypeInfo);
984 if (digest) addDigest(symbols, p4info, *digest, pipeName);
985 } else if (externBlock->type->name == "Register") {
986 auto register_ = Register::from(externBlock, refMap, typeMap, p4RtTypeInfo);
987 if (register_) addRegister(symbols, p4info, *register_, pipeName);
988 } else if (externBlock->type->name == "Hash") {
989 auto dynHash = getDynHash(decl, p4RtTypeInfo);
990 if (dynHash) addDynHash(symbols, p4info, *dynHash, pipeName);
991 }
992 }
993
994 void addExternFunction(const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
995 const P4::ExternFunction *) override {}
996
997 void addValueSet(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
998 const ValueSet &valueSetInstance) {
999 ::barefoot::ValueSet valueSet;
1000 valueSet.set_size(valueSetInstance.size);
1001 valueSet.mutable_type_spec()->CopyFrom(*valueSetInstance.typeSpec);
1002 addP4InfoExternInstance(symbols, SymbolType::P4RT_VALUE_SET(), "ValueSet"_cs,
1003 valueSetInstance.name, valueSetInstance.annotations, valueSet,
1004 p4info);
1005 LOG2("Added Instance - Value Set " << valueSetInstance.name);
1006 }
1007
1008 void analyzeParser(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
1009 const IR::ParserBlock *parserBlock) {
1010 CHECK_NULL(parserBlock);
1011 auto parser = parserBlock->container;
1012 CHECK_NULL(parser);
1013
1014 for (auto s : parser->parserLocals) {
1015 if (auto inst = s->to<IR::P4ValueSet>()) {
1016 auto valueSet = ValueSet::from(inst->controlPlaneName(), inst, refMap, typeMap,
1017 p4info->mutable_type_info());
1018 if (valueSet) addValueSet(symbols, p4info, *valueSet);
1019 }
1020 }
1021 }
1022
1024 ::p4::config::v1::P4Info *p4info) override {
1025 // Generates Tofino-specific ValueSet P4Info messages. This step is
1026 // required because value set support in "standard" P4Info is currently
1027 // insufficient: the standard ValueSet message restricts the element
1028 // type to a simple binary string (P4Runtime v1.0 limitation).
1029 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1030 if (!block->is<IR::ParserBlock>()) return;
1031 analyzeParser(symbols, p4info, block->to<IR::ParserBlock>());
1032 });
1033 }
1034
1035 void addExternEntries(const p4::v1::WriteRequest *, const P4RuntimeSymbolTableIface &,
1036 const IR::ExternBlock *) override {}
1037
1038 bool filterAnnotations(cstring) override { return false; }
1039
1040 std::optional<Digest> getDigest(const IR::Declaration_Instance *decl,
1041 p4configv1::P4TypeInfo *p4RtTypeInfo) {
1042 std::vector<const P4::ExternMethod *> packCalls;
1043 // Check that the pack method is called exactly once on the digest
1044 // instance. The type of the data being packed used to be a type
1045 // parameter of the pack method itself, and not a type parameter of the
1046 // extern, so the we used to require a reference to the P4::ExternMethod
1047 // for the pack call in order to produce the P4Info type spec. This is
1048 // no longer the case but we keep this code as a sanity check.
1050 decl, [&](const P4::ExternMethod *method) { packCalls.push_back(method); });
1051 if (packCalls.size() == 0) return std::nullopt;
1052 if (packCalls.size() > 1) {
1053 error("Expected single call to pack for digest instance '%1%'", decl);
1054 return std::nullopt;
1055 }
1056 LOG4("Found 'pack' method call for digest instance " << decl->controlPlaneName());
1057
1058 BUG_CHECK(decl->type->is<IR::Type_Specialized>(), "%1%: expected Type_Specialized",
1059 decl->type);
1060 auto type = decl->type->to<IR::Type_Specialized>();
1061 BUG_CHECK(type->arguments->size() == 1, "%1%: expected one type argument", decl);
1062 auto typeArg = type->arguments->at(0);
1063 auto typeSpec =
1064 P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
1065 BUG_CHECK(typeSpec != nullptr,
1066 "P4 type %1% could not be converted to P4Info P4DataTypeSpec");
1067 return Digest{decl->controlPlaneName(), typeSpec, decl->to<IR::IAnnotated>()};
1068 }
1069
1070 std::optional<DynHash> getDynHash(const IR::Declaration_Instance *decl,
1071 p4configv1::P4TypeInfo *p4RtTypeInfo) {
1072 std::vector<const P4::ExternMethod *> hashCalls;
1073 // Get Hash Calls in the program for the declaration.
1075 decl, [&](const P4::ExternMethod *method) { hashCalls.push_back(method); });
1076 if (hashCalls.size() == 0) return std::nullopt;
1077 if (hashCalls.size() > 1) {
1078 warning(
1079 "Expected single call to get for hash instance '%1%'."
1080 "Control plane API is not generated for this hash call",
1081 decl);
1082 return std::nullopt;
1083 }
1084 LOG4("Found 'get' method call for hash instance " << decl->controlPlaneName());
1085
1086 // Extract typeArgs and field Names to be passed on through dynHash
1087 // instance
1088 if (auto *call = hashCalls[0]->expr->to<IR::MethodCallExpression>()) {
1089 int hashWidth = 0;
1090 if (auto t = call->type->to<IR::Type_Bits>()) {
1091 hashWidth = t->width_bits();
1092 }
1093
1094 auto fieldListArg = call->arguments->at(0);
1095 LOG4("FieldList for Hash: " << fieldListArg);
1096 auto *typeArgs = new IR::Vector<IR::Type>();
1097 std::vector<DynHash::hashField> hashFieldInfo;
1098 if (fieldListArg->expression->is<IR::ListExpression>() ||
1099 fieldListArg->expression->is<IR::StructExpression>()) {
1100 for (auto f : *getListExprComponents(*fieldListArg->expression)) {
1101 if (auto c = f->to<IR::Concat>()) {
1102 for (auto e : convertConcatToList(c)) {
1103 hashFieldInfo.push_back({e->toString(), e->is<IR::Constant>()});
1104 typeArgs->push_back(e->type);
1105 }
1106 continue;
1107 }
1108 hashFieldInfo.push_back({f->toString(), f->is<IR::Constant>()});
1109 auto t = f->type->is<IR::Type_SerEnum>() ? f->type->to<IR::Type_SerEnum>()->type
1110 : f->type;
1111 typeArgs->push_back(t);
1112 }
1113 }
1114 auto *typeList = new IR::Type_List(*typeArgs);
1115 auto typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap,
1116 typeList, p4RtTypeInfo);
1117 BUG_CHECK(typeSpec != nullptr,
1118 "P4 type %1% could not be converted to P4Info P4DataTypeSpec");
1119 return DynHash{decl->controlPlaneName(), typeSpec, decl->to<IR::IAnnotated>(),
1120 hashFieldInfo, hashWidth};
1121 }
1122 return std::nullopt;
1123 }
1124
1127 std::optional<ActionProfile> getActionProfile(const IR::P4Table *table, ReferenceMap *refMap,
1128 TypeMap *typeMap) {
1130 auto instance = getExternInstanceFromProperty(table, implementationString, refMap, typeMap);
1131 if (!instance) return std::nullopt;
1132 if (instance->type->name != "ActionProfile") return std::nullopt;
1133 auto size = instance->substitution.lookupByName("size"_cs)->expression;
1134 // size is a bit<32> compile-time value
1135 BUG_CHECK(size->template is<IR::Constant>(), "Non-constant size");
1136 return ActionProfile{*instance->name, size->template to<IR::Constant>()->asInt(),
1137 getTableImplementationAnnotations(table, refMap)};
1138 }
1139
1141 static std::optional<ActionProfile> getActionProfile(const IR::ExternBlock *instance) {
1142 auto decl = instance->node->to<IR::IDeclaration>();
1143 auto size = instance->getParameterValue("size"_cs);
1144 BUG_CHECK(size->is<IR::Constant>(), "Non-constant size");
1145 return ActionProfile{decl->controlPlaneName(), size->to<IR::Constant>()->asInt(),
1146 decl->to<IR::IAnnotated>()};
1147 }
1148
1151 std::optional<ActionSelector> getActionSelector(const IR::P4Table *table, ReferenceMap *refMap,
1152 TypeMap *typeMap) {
1154 auto action_selector = getExternInstanceFromPropertyByTypeName(
1155 table, implementationString, "ActionSelector"_cs, refMap, typeMap);
1156 if (!action_selector) return std::nullopt;
1157 // TODO: remove legacy code
1158 // used to support deprecated ActionSelector constructor.
1159 if (action_selector->substitution.lookupByName("size"_cs)) {
1160 auto size = action_selector->substitution.lookupByName("size"_cs)->expression;
1161 BUG_CHECK(size->template is<IR::Constant>(), "Non-constant size");
1162 return ActionSelector{*action_selector->name,
1163 std::nullopt,
1164 size->template to<IR::Constant>()->asInt(),
1165 defaultMaxGroupSize,
1166 size->template to<IR::Constant>()->asInt(),
1167 getTableImplementationAnnotations(table, refMap),
1168 true /* _sel suffix */};
1169 }
1170 auto maxGroupSize =
1171 action_selector->substitution.lookupByName("max_group_size"_cs)->expression;
1172 auto numGroups = action_selector->substitution.lookupByName("num_groups"_cs)->expression;
1173 // size is a bit<32> compile-time value
1174 BUG_CHECK(maxGroupSize->template is<IR::Constant>(), "Non-constant max group size");
1175 BUG_CHECK(numGroups->template is<IR::Constant>(), "Non-constant num groups");
1176 return ActionSelector{*action_selector->name,
1177 *action_selector->name,
1178 -1 /* size */,
1179 maxGroupSize->template to<IR::Constant>()->asInt(),
1180 numGroups->template to<IR::Constant>()->asInt(),
1181 getTableImplementationAnnotations(table, refMap),
1182 false /* _sel suffix */};
1183 }
1184
1185 std::optional<ActionSelector> getActionSelector(const IR::ExternBlock *instance) {
1186 auto actionSelDecl = instance->node->to<IR::IDeclaration>();
1187 // to be deleted, used to support deprecated ActionSelector constructor.
1188 if (instance->findParameterValue("size"_cs)) {
1189 auto size = instance->getParameterValue("size"_cs);
1190 BUG_CHECK(size->is<IR::Constant>(), "Non-constant size");
1191 return ActionSelector{actionSelDecl->controlPlaneName(),
1192 std::nullopt,
1193 size->to<IR::Constant>()->asInt(),
1194 defaultMaxGroupSize,
1195 size->to<IR::Constant>()->asInt(),
1196 actionSelDecl->to<IR::IAnnotated>(),
1197 false /* sel suffix */};
1198 }
1199 auto maxGroupSize = instance->getParameterValue("max_group_size"_cs);
1200 auto numGroups = instance->getParameterValue("num_groups"_cs);
1201 BUG_CHECK(maxGroupSize->is<IR::Constant>(), "Non-constant max group size");
1202 BUG_CHECK(numGroups->is<IR::Constant>(), "Non-constant num groups");
1203 auto action_profile = instance->getParameterValue("action_profile"_cs);
1204 auto action_profile_decl =
1205 action_profile->to<IR::ExternBlock>()->node->to<IR::IDeclaration>();
1206 return ActionSelector{actionSelDecl->controlPlaneName(),
1207 cstring::to_cstring(action_profile_decl->controlPlaneName()),
1208 -1 /* size */,
1209 maxGroupSize->to<IR::Constant>()->asInt(),
1210 numGroups->to<IR::Constant>()->asInt(),
1211 actionSelDecl->to<IR::IAnnotated>(),
1212 false /* sel suffix */};
1213 }
1214
1215 static p4configv1::Extern *getP4InfoExtern(P4::ControlPlaneAPI::P4RuntimeSymbolType typeId,
1216 cstring typeName, p4configv1::P4Info *p4info) {
1217 for (auto &externType : *p4info->mutable_externs()) {
1218 if (externType.extern_type_id() == static_cast<p4rt_id_t>(typeId)) return &externType;
1219 }
1220 auto *externType = p4info->add_externs();
1221 externType->set_extern_type_id(static_cast<p4rt_id_t>(typeId));
1222 externType->set_extern_type_name(typeName);
1223 return externType;
1224 }
1225
1226 static void addP4InfoExternInstance(const P4RuntimeSymbolTableIface &symbols,
1228 cstring typeName, cstring name,
1229 const IR::IAnnotated *annotations,
1230 const ::google::protobuf::Message &message,
1231 p4configv1::P4Info *p4info) {
1232 auto *externType = getP4InfoExtern(typeId, typeName, p4info);
1233 auto *externInstance = externType->add_instances();
1234 auto *pre = externInstance->mutable_preamble();
1235 pre->set_id(symbols.getId(typeId, name));
1236 pre->set_name(name);
1237 pre->set_alias(symbols.getAlias(name));
1238 Helpers::addAnnotations(pre, annotations);
1239 Helpers::addDocumentation(pre, annotations);
1240 externInstance->mutable_info()->PackFrom(message);
1241 }
1242
1243 void addDigest(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1244 const Digest &digestInstance, cstring pipeName = cstring::empty) {
1245 ::barefoot::Digest digest;
1246 digest.mutable_type_spec()->CopyFrom(*digestInstance.typeSpec);
1247 auto digestName = prefix(pipeName, digestInstance.name);
1248 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIGEST(), "Digest"_cs, digestName,
1249 digestInstance.annotations, digest, p4Info);
1250 LOG2("Added Instance - Digest " << digestName);
1251 }
1252
1253 void addDynHash(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1254 const DynHash &dynHashInstance, cstring pipeName = cstring::empty) {
1255 ::barefoot::DynHash dynHash;
1256 dynHash.set_hash_width(dynHashInstance.hashWidth);
1257 dynHash.mutable_type_spec()->CopyFrom(*dynHashInstance.typeSpec);
1258 auto dynHashName = prefix(pipeName, dynHashInstance.name);
1259 for (const auto &f : dynHashInstance.hashFieldInfo) {
1260 auto newF = dynHash.add_field_infos();
1261 newF->set_field_name(f.hashFieldName);
1262 newF->set_is_constant(f.isConstant);
1263 }
1264 addP4InfoExternInstance(symbols, SymbolType::P4RT_HASH(), "DynHash"_cs, dynHashName,
1265 dynHashInstance.annotations, dynHash, p4Info);
1266 LOG2("Added Instance - DynHash " << dynHashName);
1267 }
1268
1269 // For Registers, the table name should have the associated pipe prefix but
1270 // the data field names should not since they have local scope.
1271 void addRegister(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1272 const Register &registerInstance, cstring pipeName = cstring::empty) {
1273 auto registerName = prefix(pipeName, registerInstance.name);
1274 if (registerInstance.size == 0) {
1275 ::barefoot::DirectRegister register_;
1276 register_.mutable_type_spec()->CopyFrom(*registerInstance.typeSpec);
1277 register_.set_data_field_name(registerInstance.name);
1278 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_REGISTER(),
1279 "DirectRegister"_cs, registerName, registerInstance.annotations,
1280 register_, p4Info);
1281 LOG2("Added Instance - DirectRegister " << registerName);
1282 } else {
1283 ::barefoot::Register register_;
1284 register_.set_size(registerInstance.size);
1285 register_.mutable_type_spec()->CopyFrom(*registerInstance.typeSpec);
1286 register_.set_data_field_name(registerInstance.name);
1287 addP4InfoExternInstance(symbols, SymbolType::P4RT_REGISTER(), "Register"_cs,
1288 registerName, registerInstance.annotations, register_, p4Info);
1289 LOG2("Added Instance - Register " << registerName);
1290 }
1291 }
1292
1294 template <typename Kind>
1295 void setCounterCommon(Kind *counter,
1296 const Helpers::Counterlike<ArchCounterExtern> &counterInstance) {
1297 auto counter_spec = counter->mutable_spec();
1298 counter_spec->set_unit(CounterTraits::mapUnitName(counterInstance.unit));
1299 }
1300
1301 void addCounter(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1302 const Helpers::Counterlike<ArchCounterExtern> &counterInstance,
1303 const cstring blockPrefix = cstring::empty) {
1304 if (counterInstance.table) {
1305 ::barefoot::DirectCounter counter;
1306 setCounterCommon(&counter, counterInstance);
1307 auto tableName = prefix(blockPrefix, *counterInstance.table);
1308 auto counterName = prefix(blockPrefix, counterInstance.name);
1309 auto tableId =
1310 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
1311 counter.set_direct_table_id(tableId);
1312 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_COUNTER(),
1314 counterName, counterInstance.annotations, counter, p4Info);
1315 LOG2("Added Instance - DirectCounter " << counterName);
1316 } else {
1317 ::barefoot::Counter counter;
1318 setCounterCommon(&counter, counterInstance);
1319 counter.set_size(counterInstance.size);
1320 auto counterName = prefix(blockPrefix, counterInstance.name);
1321 addP4InfoExternInstance(symbols, SymbolType::P4RT_COUNTER(),
1323 counterName, counterInstance.annotations, counter, p4Info);
1324 LOG2("Added Instance - Counter " << counterName);
1325 }
1326 }
1327
1329 template <typename Kind>
1330 void setMeterCommon(Kind *meter, const Helpers::Counterlike<ArchMeterExtern> &meterInstance) {
1331 using ::barefoot::MeterSpec;
1333 auto meter_spec = meter->mutable_spec();
1334 if (colorAwareMeters.find(meterInstance.name) != colorAwareMeters.end()) {
1335 meter_spec->set_type(MeterSpec::COLOR_AWARE);
1336 } else {
1337 meter_spec->set_type(MeterSpec::COLOR_UNAWARE);
1338 }
1339 meter_spec->set_unit(CounterlikeTraits<ArchMeterExtern>::mapUnitName(meterInstance.unit));
1340 }
1341
1342 void addMeter(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1343 const Helpers::Counterlike<ArchMeterExtern> &meterInstance,
1344 const cstring blockPrefix = cstring::empty) {
1345 auto meterName = prefix(blockPrefix, meterInstance.name);
1346 if (meterInstance.table) {
1347 ::barefoot::DirectMeter meter;
1348 setMeterCommon(&meter, meterInstance);
1349 auto tableName = prefix(blockPrefix, *meterInstance.table);
1350 auto tableId =
1351 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
1352 meter.set_direct_table_id(tableId);
1353 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_METER(),
1355 meterName, meterInstance.annotations, meter, p4Info);
1356 LOG2("Added Instance - DirectMeter " << meterName);
1357 } else {
1358 ::barefoot::Meter meter;
1359 setMeterCommon(&meter, meterInstance);
1360 meter.set_size(meterInstance.size);
1361 addP4InfoExternInstance(symbols, SymbolType::P4RT_METER(),
1363 meterName, meterInstance.annotations, meter, p4Info);
1364 LOG2("Added Instance - Meter " << meterName);
1365 }
1366 }
1367
1368 void addActionProfile(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1369 const ActionProfile &actionProfile, cstring pipeName = cstring::empty) {
1370 ::barefoot::ActionProfile profile;
1371 profile.set_size(actionProfile.size);
1372 auto actionProfileName = prefix(pipeName, actionProfile.name);
1373 auto tablesIt = actionProfilesRefs.find(actionProfileName);
1374 if (tablesIt != actionProfilesRefs.end()) {
1375 for (const auto &table : tablesIt->second) {
1376 cstring tableName = table;
1377 if (!pipeName.isNullOrEmpty()) tableName = prefix(pipeName, tableName);
1378 profile.add_table_ids(symbols.getId(
1379 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1380 }
1381 }
1382 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_PROFILE(), "ActionProfile"_cs,
1383 actionProfileName, actionProfile.annotations, profile, p4Info);
1384 LOG2("Added Extern Instance - Action Profile " << actionProfileName);
1385 }
1386
1387 virtual void addActionSelector(const P4RuntimeSymbolTableIface &symbols,
1388 p4configv1::P4Info *p4Info, const ActionSelector &actionSelector,
1389 cstring blockPrefix = cstring::empty) {
1390 ::barefoot::ActionSelector selector;
1391 selector.set_max_group_size(actionSelector.maxGroupSize);
1392 selector.set_num_groups(actionSelector.numGroups);
1393 cstring actionSelectorName = prefix(blockPrefix, actionSelector.name);
1394 if (actionSelector.actionProfileName) {
1395 selector.set_action_profile_id(
1396 symbols.getId(SymbolType::P4RT_ACTION_PROFILE(),
1397 prefix(blockPrefix, *actionSelector.actionProfileName)));
1398 auto tablesIt = actionProfilesRefs.find(actionSelectorName);
1399 if (tablesIt != actionProfilesRefs.end()) {
1400 for (const auto &table : tablesIt->second) {
1401 cstring tableName = prefix(blockPrefix, table);
1402 selector.add_table_ids(symbols.getId(
1403 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1404 }
1405 }
1406 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_SELECTOR(),
1407 "ActionSelector"_cs, actionSelectorName,
1408 actionSelector.annotations, selector, p4Info);
1409 LOG2("Added Extern Instance - Action Selector " << actionSelectorName);
1410 } else {
1411 ::barefoot::ActionProfile profile;
1412 profile.set_size(actionSelector.size);
1413 auto tablesIt = actionProfilesRefs.find(actionSelectorName);
1414 if (tablesIt != actionProfilesRefs.end()) {
1415 for (const auto &table : tablesIt->second) {
1416 cstring tableName = prefix(blockPrefix, table);
1417 profile.add_table_ids(symbols.getId(
1418 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1419 selector.add_table_ids(symbols.getId(
1420 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1421 }
1422 }
1423
1424 // We use the ActionSelector name for the action profile, and add a "_sel" suffix for
1425 // the action selector.
1426 cstring profileName = actionSelectorName;
1427 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_PROFILE(), "ActionProfile"_cs,
1428 profileName, actionSelector.annotations, profile, p4Info);
1429 selector.set_action_profile_id(
1430 symbols.getId(SymbolType::P4RT_ACTION_PROFILE(), profileName));
1431 cstring selectorName = profileName + "_sel";
1432 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_SELECTOR(),
1433 "ActionSelector"_cs, selectorName, actionSelector.annotations,
1434 selector, p4Info);
1435 LOG2("Added Extern Instance - Action Selector " << selectorName);
1436 }
1437 }
1438
1440 // TODO: for some reason we sometimes get multiple calls on the
1441 // same extern method (but different IR node), and I haven't found out why
1442 // or when this happens.
1443 template <typename Func>
1444 void forAllExternMethodCalls(const IR::IDeclaration *object, Func function) {
1446 evaluatedProgram->getProgram(), [&](const IR::MethodCallExpression *call) {
1447 auto instance = P4::MethodInstance::resolve(call, refMap, typeMap);
1448 if (instance->template is<P4::ExternMethod>() && instance->object == object) {
1449 function(instance->template to<P4::ExternMethod>());
1450 }
1451 });
1452 }
1453
1456 const IR::Property *getTableImplementationProperty(const IR::P4Table *table) {
1457 return table->properties->getProperty(implementationString);
1458 }
1459
1460 const IR::IAnnotated *getTableImplementationAnnotations(const IR::P4Table *table,
1461 ReferenceMap *refMap) {
1462 auto impl = getTableImplementationProperty(table);
1463 if (impl == nullptr) return nullptr;
1464 if (!impl->value->template is<IR::ExpressionValue>()) return nullptr;
1465 auto expr = impl->value->template to<IR::ExpressionValue>()->expression;
1466 if (expr->template is<IR::ConstructorCallExpression>())
1467 return impl->template to<IR::IAnnotated>();
1468 if (expr->template is<IR::PathExpression>()) {
1469 auto decl = refMap->getDeclaration(expr->template to<IR::PathExpression>()->path, true);
1470 return decl->template to<IR::IAnnotated>();
1471 }
1472 return nullptr;
1473 }
1474
1475 std::optional<cstring> getTableImplementationName(const IR::P4Table *table,
1476 ReferenceMap *refMap) {
1477 auto impl = getTableImplementationProperty(table);
1478 if (impl == nullptr) return std::nullopt;
1479 if (!impl->value->template is<IR::ExpressionValue>()) {
1480 error("Expected %1% property value for table %2% to be an expression: %2%",
1481 implementationString, table->controlPlaneName(), impl);
1482 return std::nullopt;
1483 }
1484 auto expr = impl->value->template to<IR::ExpressionValue>()->expression;
1485 if (expr->template is<IR::ConstructorCallExpression>()) return impl->controlPlaneName();
1486 if (expr->template is<IR::PathExpression>()) {
1487 auto decl = refMap->getDeclaration(expr->template to<IR::PathExpression>()->path, true);
1488 return decl->controlPlaneName();
1489 }
1490 return std::nullopt;
1491 }
1492
1493 ReferenceMap *refMap;
1494 TypeMap *typeMap;
1495 const IR::ToplevelBlock *evaluatedProgram;
1496
1498 std::unordered_map<cstring, std::set<cstring>> actionProfilesRefs;
1500 std::unordered_set<cstring> colorAwareMeters;
1501
1502 cstring implementationString;
1503 cstring defaultPipeName = "pipe"_cs;
1504
1505 static constexpr int64_t defaultMaxGroupSize = 120;
1506
1507 // JSON printing options for serialization
1508 google::protobuf::util::JsonPrintOptions jsonPrintOptions;
1509
1510 public:
1511 google::protobuf::util::JsonPrintOptions getJsonPrintOptions() override {
1512 return jsonPrintOptions;
1513 }
1514};
1515
1520 public:
1521 template <typename Func>
1522 void forAllPipeBlocks(const IR::ToplevelBlock *evaluatedProgram, Func function) {
1523 auto main = evaluatedProgram->getMain();
1524 if (!main) ::fatal_error("Program does not contain a `main` module");
1525 auto cparams = main->getConstructorParameters();
1526 int index = -1;
1527 for (auto param : main->constantValue) {
1528 index++;
1529 if (!param.second) continue;
1530 auto pipe = param.second;
1531 if (!pipe->is<IR::PackageBlock>()) {
1532 error(ErrorType::ERR_INVALID,
1533 "%1% package block. You are compiling for the %2% "
1534 "P4 architecture.\n"
1535 "Please verify that you included the correct architecture file.",
1536 pipe, BackendOptions().arch);
1537 return;
1538 }
1539 auto idxParam = cparams->getParameter(index);
1540 auto pipeName = idxParam->name;
1541 function(pipeName, pipe->to<IR::PackageBlock>());
1542 }
1543 }
1544
1545 template <typename Func>
1546 void forAllPortMetadataBlocks(const IR::ToplevelBlock *evaluatedProgram, Func function) {
1547 auto main = evaluatedProgram->getMain();
1548 if (!main) ::fatal_error("Program does not contain a `main` module");
1549 if (main->type->name == "MultiParserSwitch") {
1550 int numParsersPerPipe = Device::numParsersPerPipe();
1551 auto parsersName = "ig_prsr"_cs;
1552 forAllPipeBlocks(evaluatedProgram, [&](cstring, const IR::PackageBlock *pkg) {
1553 auto parsers = pkg->findParameterValue(parsersName);
1554 BUG_CHECK(parsers, "Expected Block");
1555 if (!parsers->is<IR::PackageBlock>()) {
1556 error(ErrorType::ERR_INVALID,
1557 "%1% package block. "
1558 "You are compiling for the %2% P4 architecture.\n"
1559 "Please verify that you included the correct architecture file.",
1560 parsers, BackendOptions().arch);
1561 return;
1562 }
1563 auto parsersBlock = parsers->to<IR::PackageBlock>();
1564 for (int idx = 0; idx < numParsersPerPipe; idx++) {
1565 auto mpParserName = "prsr" + std::to_string(idx);
1566 auto parser = parsersBlock->findParameterValue(mpParserName);
1567 if (!parser) break; // all parsers optional except for first one
1568 auto parserBlock = parser->to<IR::ParserBlock>();
1569 if (hasUserPortMetadata.count(parserBlock) == 0) { // no extern, add default
1570 auto portMetadataFullName =
1571 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
1572 function(portMetadataFullName, parserBlock);
1573 }
1574 }
1575 });
1576 } else {
1577 auto parserName = "ingress_parser"_cs;
1578 forAllPipeBlocks(evaluatedProgram, [&](cstring, const IR::PackageBlock *pkg) {
1579 auto *block = pkg->findParameterValue(parserName);
1580 if (!block) return;
1581 if (!block->is<IR::ParserBlock>()) return;
1582 auto parserBlock = block->to<IR::ParserBlock>();
1583 if (hasUserPortMetadata.count(parserBlock) == 0) { // no extern, add default
1584 auto portMetadataFullName =
1585 getFullyQualifiedName(parserBlock, PortMetadata::name());
1586 function(portMetadataFullName, parserBlock);
1587 }
1588 });
1589 }
1590 }
1591
1593 const IR::ToplevelBlock *evaluatedProgram)
1594 : BFRuntimeArchHandlerCommon<Arch::TNA>(refMap, typeMap, evaluatedProgram) {
1595 Log::TempIndent indent;
1596 LOG1("BFRuntimeArchHandlerTofino" << indent);
1597 implementationString = "implementation"_cs;
1598
1599 std::set<cstring> pipes;
1600 LOG2("Populating blockNamePrefixMap" << Log::indent);
1601 // Create a map of all blocks to their pipe names. This map will
1602 // be used during collect and post processing to prefix
1603 // table/extern instances wherever applicable with a fully qualified
1604 // name. This distinction is necessary when the driver looks up
1605 // context.json across multiple pipes for the table name
1606 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
1607 Helpers::forAllEvaluatedBlocks(pkg, [&](const IR::Block *block) {
1608 auto decl = pkg->node->to<IR::Declaration_Instance>();
1609 cstring blockNamePrefix = pipeName;
1610 if (decl) blockNamePrefix = decl->controlPlaneName();
1611 blockNamePrefixMap[block] = blockNamePrefix;
1612 LOG4("Updating blockNamePrefixMap with " << &*block << block->toString() << " : "
1613 << blockNamePrefixMap[block]);
1614 pipes.insert(pipeName);
1615 });
1616 });
1617 LOG2_UNINDENT;
1618
1619 // Update multi parser names
1620 static std::vector<cstring> gressNames = {"ig"_cs, "eg"_cs};
1621 int numParsersPerPipe = Device::numParsersPerPipe();
1622
1623 auto main = evaluatedProgram->getMain();
1624 if (!main) ::fatal_error("Program does not contain a `main` module");
1625
1626 isMultiParser = false;
1627 if (main->type->name == "MultiParserSwitch") {
1628 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
1629 BUG_CHECK(
1630 pkg->type->name == "MultiParserPipeline",
1631 "Only MultiParserPipeline pipes can be used with a MultiParserSwitch switch");
1632 for (auto gressName : gressNames) {
1633 auto parsersName = gressName + "_prsr";
1634 auto parsers = pkg->findParameterValue(parsersName);
1635 BUG_CHECK(parsers && parsers->is<IR::PackageBlock>(), "Expected PackageBlock");
1636 auto parsersBlock = parsers->to<IR::PackageBlock>();
1637 auto decl = parsersBlock->node->to<IR::Declaration_Instance>();
1638 if (decl) parsersName = decl->controlPlaneName();
1639 for (int idx = 0; idx < numParsersPerPipe; idx++) {
1640 auto parserName = "prsr" + std::to_string(idx);
1641 auto parser = parsersBlock->findParameterValue(parserName);
1642 if (!parser) break; // all parsers optional except for first one
1643 BUG_CHECK(parser->is<IR::ParserBlock>(), "Expected ParserBlock");
1644 auto parserBlock = parser->to<IR::ParserBlock>();
1645
1646 // Update Parser Block Names
1647 auto parserFullName = pipeName + "." + parsersName + "." + parserName;
1648 blockNamePrefixMap[parserBlock] = parserFullName;
1649 }
1650 isMultiParser = true;
1651 }
1652 });
1653 }
1654 }
1655
1656 cstring getBlockNamePrefix(const IR::Block *blk) override {
1657 if (blockNamePrefixMap.count(blk) > 0) return blockNamePrefixMap[blk];
1658 return cstring::empty;
1659 }
1660
1662 const IR::ExternBlock *externBlock) override {
1663 collectExternInstanceCommon(symbols, externBlock);
1664
1665 CHECK_NULL(externBlock);
1666
1667 auto decl = externBlock->node->to<IR::IDeclaration>();
1668 // Skip externs instantiated inside table declarations (as properties);
1669 // that should only apply to action profiles / selectors since direct
1670 // resources cannot be constructed in place for TNA.
1671 if (decl == nullptr) return;
1672
1673 auto symName = getControlPlaneName(externBlock, decl);
1674 if (externBlock->type->name == "Lpf") {
1675 symbols->add(SymbolType::P4RT_LPF(), symName);
1676 } else if (externBlock->type->name == "DirectLpf") {
1677 symbols->add(SymbolType::P4RT_DIRECT_LPF(), symName);
1678 } else if (externBlock->type->name == "Wred") {
1679 symbols->add(SymbolType::P4RT_WRED(), symName);
1680 } else if (externBlock->type->name == "DirectWred") {
1681 symbols->add(SymbolType::P4RT_DIRECT_WRED(), symName);
1682 } else if (externBlock->type->name == "RegisterParam") {
1683 symbols->add(SymbolType::P4RT_REGISTER_PARAM(), symName);
1684 }
1685 }
1686
1688
1689 void collectPortMetadataExternFunction(P4RuntimeSymbolTableIface *symbols,
1690 const P4::ExternFunction *externFunction,
1691 const IR::ParserBlock *parserBlock) {
1692 auto portMetadata = getPortMetadataExtract(externFunction, refMap, typeMap, nullptr);
1693 if (portMetadata) {
1694 if (hasUserPortMetadata.count(parserBlock)) {
1695 error("Cannot have multiple extern calls for %1%",
1696 BFN::ExternPortMetadataUnpackString);
1697 return;
1698 }
1699 hasUserPortMetadata.insert(parserBlock);
1700 auto portMetadataFullName =
1701 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
1702 symbols->add(SymbolType::P4RT_PORT_METADATA(), portMetadataFullName);
1703 }
1704 }
1705
1706 void collectParserSymbols(P4RuntimeSymbolTableIface *symbols,
1707 const IR::ParserBlock *parserBlock) {
1708 CHECK_NULL(parserBlock);
1709 auto parser = parserBlock->container;
1710 CHECK_NULL(parser);
1711
1712 // Collect any extern functions it may invoke.
1713 for (auto state : parser->states) {
1715 state, [&](const IR::MethodCallExpression *call) {
1716 auto instance = P4::MethodInstance::resolve(call, refMap, typeMap);
1717 if (instance->is<P4::ExternFunction>())
1718 collectPortMetadataExternFunction(
1719 symbols, instance->to<P4::ExternFunction>(), parserBlock);
1720 });
1721 }
1722
1723 for (auto s : parser->parserLocals) {
1724 if (auto inst = s->to<IR::P4ValueSet>()) {
1725 auto name = getFullyQualifiedName(parserBlock, inst->controlPlaneName(), true);
1726 symbols->add(SymbolType::P4RT_VALUE_SET(), name);
1727 }
1728 }
1729
1730 // Extract phase0 ingress intrinsic metadata name provided by user
1731 // (usually ig_intr_md). This value is prefixed to the key name in
1732 // phase0 table in bf-rt.json (e.g. ig_intr_md.ingress_port). TNA
1733 // translation will extract this value during midend and set the key
1734 // name in phase0 table in context.json to be consistent.
1735 auto *params = parser->getApplyParameters();
1736 for (auto p : *params) {
1737 if (p->type->toString() == "ingress_intrinsic_metadata_t") {
1738 BUG_CHECK(ingressIntrinsicMdParamName.count(parserBlock) == 0 ||
1739 ingressIntrinsicMdParamName[parserBlock] == p->name.toString(),
1740 "%1%: Multiple names of intrinsic metadata found in this parser block",
1741 parser->getName());
1742 ingressIntrinsicMdParamName[parserBlock] = p->name;
1743 break;
1744 }
1745 }
1746 }
1747
1752 cstring pipe;
1760 std::set<SnapshotFieldInfo> fields;
1761 };
1762
1766 static std::vector<cstring> gressNames = {"ingress"_cs, "egress"_cs};
1767 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
1768 for (auto gressName : gressNames) {
1769 auto gress = pkg->findParameterValue(gressName);
1770 BUG_CHECK(gress->is<IR::ControlBlock>(), "Expected control");
1771 auto control = gress->to<IR::ControlBlock>();
1772 if (blockNamePrefixMap.count(control) > 0) pipeName = blockNamePrefixMap[control];
1773 snapshotInfo.emplace(control,
1774 SnapshotInfo{pipeName, gressName, 0u, cstring::empty, {}});
1775 LOG3("Adding SnapshotInfo for " << control->getName() << " " << gressName
1776 << " on pipe " << pipeName);
1777 }
1778 });
1779 }
1780
1787 void collectSnapshot(P4RuntimeSymbolTableIface *symbols, const IR::ControlBlock *controlBlock,
1788 SnapshotFieldIdTable *fieldIds) {
1789 CHECK_NULL(controlBlock);
1790 auto control = controlBlock->container;
1791 CHECK_NULL(control);
1792 Log::TempIndent indent;
1793 auto sinfoIt = snapshotInfo.find(controlBlock);
1794 // if the block is not in snapshotInfo, it means it is not an ingress or
1795 // egress control.
1796 if (sinfoIt == snapshotInfo.end()) return;
1797 auto snapshot_name = getFullyQualifiedName(controlBlock, control->externalName());
1798 LOG1("Collecting Snapshot for control " << snapshot_name << indent);
1799 // Collect unique snapshot names across pipes, this will ensure there is
1800 // only one snapshot field generated even if the field is replicated
1801 // across pipes. While setting a snapshot the user always provides a
1802 // pipe id so we do not need multiple snapshot entries.
1803 if (snapshots.count(snapshot_name)) {
1804 snapshotInfo.erase(sinfoIt);
1805 return;
1806 }
1807 snapshots.insert(snapshot_name);
1808 sinfoIt->second.name = snapshot_name;
1809 auto snapshotFields = &sinfoIt->second.fields;
1810 auto params = control->getApplyParameters();
1811 for (size_t idx = 0; idx < params->size(); idx++) {
1812 auto p = params->getParameter(idx);
1813 // include validity fields (POV bits) only for user-defined header
1814 // fields (the "hdr" parameter)
1815 auto includeValid = (idx == sinfoIt->second.userHdrParamIdx);
1816 SnapshotFieldFinder::find(typeMap, p->type, p->name, includeValid, snapshotFields,
1817 fieldIds);
1818 }
1819 LOG3("Adding snaphot to bfrt info for control: " << snapshot_name);
1820 symbols->add(SymbolType::P4RT_SNAPSHOT(), snapshot_name);
1821 }
1822
1829 static std::vector<cstring> gressNames = {"ig"_cs, "eg"_cs};
1830 int numParsersPerPipe = Device::numParsersPerPipe();
1831
1832 auto main = evaluatedProgram->getMain();
1833 if (!main) ::fatal_error("Program does not contain a `main` module");
1834 if (main->type->name != "MultiParserSwitch") return;
1835
1836 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
1837 BUG_CHECK(pkg->type->name == "MultiParserPipeline",
1838 "Only MultiParserPipeline pipes can be used with a MultiParserSwitch switch");
1839 for (auto gressName : gressNames) {
1840 ::barefoot::ParserChoices parserChoices;
1841
1842 if (auto decl = pkg->node->to<IR::Declaration_Instance>()) pipeName = decl->Name();
1843
1844 parserChoices.set_pipe(pipeName);
1845 if (gressName == "ig")
1846 parserChoices.set_direction(::barefoot::DIRECTION_INGRESS);
1847 else
1848 parserChoices.set_direction(::barefoot::DIRECTION_EGRESS);
1849
1850 auto parsersName = gressName + "_prsr";
1851 auto parsers = pkg->findParameterValue(parsersName);
1852 BUG_CHECK(parsers && parsers->is<IR::PackageBlock>(), "Expected PackageBlock");
1853 auto parsersBlock = parsers->to<IR::PackageBlock>();
1854 auto decl = parsersBlock->node->to<IR::Declaration_Instance>();
1855 if (decl) parsersName = decl->controlPlaneName();
1856 for (int idx = 0; idx < numParsersPerPipe; idx++) {
1857 auto parserName = "prsr" + std::to_string(idx);
1858 auto parser = parsersBlock->findParameterValue(parserName);
1859 if (!parser) break; // all parsers optional except for first one
1860 BUG_CHECK(parser->is<IR::ParserBlock>(), "Expected ParserBlock");
1861 auto parserBlock = parser->to<IR::ParserBlock>();
1862 auto decl = parserBlock->node->to<IR::Declaration_Instance>();
1863 auto userName = (decl == nullptr) ? cstring::empty : decl->controlPlaneName();
1864
1865 auto choice = parserChoices.add_choices();
1866 auto parserFullName = prefix(parsersName, parserName);
1867 parserFullName = prefix(pipeName, parserFullName);
1868 choice->set_arch_name(parserFullName);
1869 choice->set_type_name(parserBlock->getName().name);
1870 choice->set_user_name(userName);
1871 }
1872 auto parsersFullName = prefix(pipeName, parsersName);
1873 symbols->add(SymbolType::P4RT_PARSER_CHOICES(), parsersFullName);
1874 parserConfiguration.emplace(parsersFullName, parserChoices);
1875 }
1876 });
1877 }
1878
1879 void collectExtra(P4RuntimeSymbolTableIface *symbols) override {
1880 Log::TempIndent indent;
1881 LOG1("BFRuntimeArchHandlerTofino::collectExtra" << indent);
1882 LOG2("Collecting Parser Symbols" << Log::indent);
1883 // Collect value sets. This step is required because value set support
1884 // in "standard" P4Info is currently insufficient.
1885 // Also retrieve user-provided name for ig_intr_md parameter in ingress
1886 // parser to use as key name for phase0 table.
1887 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1888 if (!block->is<IR::ParserBlock>()) return;
1889 collectParserSymbols(symbols, block->to<IR::ParserBlock>());
1890 });
1891 LOG2_UNINDENT;
1892
1893 LOG2("Collecting Snapshot Fields" << Log::indent);
1894 // Collect snapshot fields for each control by populating the
1895 // snapshotInfo map.
1896 getSnapshotControls();
1897 SnapshotFieldIdTable snapshotFieldIds;
1898 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1899 if (!block->is<IR::ControlBlock>()) return;
1900 collectSnapshot(symbols, block->to<IR::ControlBlock>(), &snapshotFieldIds);
1901 });
1902 LOG2_UNINDENT;
1903
1904 LOG2("Collecting Parser Choices" << Log::indent);
1905 collectParserChoices(symbols);
1906 LOG2_UNINDENT;
1907
1908 LOG2("Collecting PortMetadata" << Log::indent);
1909 // Check if each parser block in program has a port metadata extern
1910 // defined, if not we add a default instances to symbol table
1911 forAllPortMetadataBlocks(
1912 evaluatedProgram, [&](cstring portMetadataFullName, const IR::ParserBlock *) {
1913 symbols->add(SymbolType::P4RT_PORT_METADATA(), portMetadataFullName);
1914 LOG3("Adding PortMetadata symbol: " << portMetadataFullName);
1915 });
1916 LOG2_UNINDENT;
1917 }
1918
1919 void postCollect(const P4RuntimeSymbolTableIface &symbols) override {
1920 Log::TempIndent indent;
1921 LOG1("BFRuntimeArchHandlerTofino::postCollect" << indent);
1922 (void)symbols;
1923 // analyze action profiles / selectors and build a mapping from action
1924 // profile / selector name to the set of tables referencing them
1925 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1926 if (!block->is<IR::TableBlock>()) return;
1927 auto table = block->to<IR::TableBlock>()->container;
1928 auto implementation = getTableImplementationName(table, refMap);
1929 if (implementation) {
1930 auto pipeName = blockNamePrefixMap[block];
1931 auto implName = prefix(pipeName, *implementation);
1932 actionProfilesRefs[implName].insert(table->controlPlaneName());
1933 LOG5("Adding action profile : " << implName << " for table "
1934 << table->controlPlaneName());
1935 }
1936 });
1937
1938 // analyze action profile used by action selector and adds the set of
1939 // table referenced by action selector to the action profile.
1940 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1941 if (!block->is<IR::ExternBlock>()) return;
1942 auto selectorExternBlock = block->to<IR::ExternBlock>();
1943 if (selectorExternBlock->type->name != "ActionSelector") return;
1944 auto selectorDecl = selectorExternBlock->node->to<IR::Declaration_Instance>();
1945 CHECK_NULL(selectorDecl);
1946 auto profile = selectorExternBlock->getParameterValue("action_profile"_cs);
1947 if (profile) {
1948 auto profileExternBlock = profile->to<IR::ExternBlock>();
1949 auto profileDecl = profileExternBlock->node->to<IR::Declaration_Instance>();
1950 CHECK_NULL(profileDecl);
1951 auto pipeName = blockNamePrefixMap[selectorExternBlock];
1952 auto profileDeclName = prefix(pipeName, profileDecl->controlPlaneName());
1953 auto selectorDeclName = prefix(pipeName, selectorDecl->controlPlaneName());
1954 actionProfilesRefs[profileDeclName].insert(
1955 actionProfilesRefs[selectorDeclName].begin(),
1956 actionProfilesRefs[selectorDeclName].end());
1957 LOG5("Adding action profile : " << profileDeclName << " for tables "
1958 << actionProfilesRefs[profileDeclName]);
1959 }
1960 });
1961
1962 // Creates a set of color-aware meters by inspecting every call to the
1963 // execute method on each meter instance: if at least one method call
1964 // includes a second argument (pre-color), then the meter is
1965 // color-aware.
1966 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1967 if (!block->is<IR::ExternBlock>()) return;
1968 auto externBlock = block->to<IR::ExternBlock>();
1969 if (externBlock->type->name != "Meter" && externBlock->type->name != "DirectMeter")
1970 return;
1971 auto decl = externBlock->node->to<IR::Declaration_Instance>();
1972 // Should not happen for TNA: direct meters cannot be constructed
1973 // in-place.
1974 CHECK_NULL(decl);
1975 forAllExternMethodCalls(decl, [&](const P4::ExternMethod *method) {
1976 auto call = method->expr;
1977 if (call->arguments->size() == 2) {
1978 LOG3("Meter " << decl->controlPlaneName() << " is color-aware "
1979 << "because of 2-argument call to execute()");
1980 colorAwareMeters.insert(decl->controlPlaneName());
1981 }
1982 });
1983 });
1984
1985 class RegisterParamFinder : public Inspector {
1987
1988 bool checkExtern(const IR::Declaration_Instance *decl, cstring name) {
1989 if (auto *specialized = decl->type->to<IR::Type_Specialized>())
1990 if (auto *name_type = specialized->baseType->to<IR::Type_Name>())
1991 return name_type->path->name == name;
1992 return false;
1993 }
1994
1995 public:
1996 RegisterParamFinder(BFRuntimeArchHandlerTofino &self) : self(self) {}
1997 bool preorder(const IR::MethodCallExpression *mce) override {
1998 auto method = P4::MethodInstance::resolve(mce, self.refMap, self.typeMap);
1999 CHECK_NULL(method);
2000 if (method->object == nullptr) // extern functions
2001 return true;
2002 auto *reg_param = method->object->to<IR::Declaration_Instance>();
2003 if (reg_param == nullptr) // packet_in packet
2004 return true;
2005 if (!checkExtern(reg_param, "RegisterParam"_cs)) return true;
2006 // Find the declaration of RegisterAction
2007 auto *reg_action = findContext<IR::Declaration_Instance>();
2008 if (reg_action == nullptr) return true;
2009 if (!checkExtern(reg_action, "DirectRegisterAction"_cs) &&
2010 !checkExtern(reg_action, "RegisterAction"_cs))
2011 return true;
2012 BUG_CHECK(reg_action->arguments->size() > 0, "%1%: Missing argument", reg_action);
2013 auto *rap = reg_action->arguments->at(0)->expression->to<IR::PathExpression>();
2014 if (rap == nullptr) return true;
2015 // Find the declaration of Register or DirectRegister
2016 auto *rap_decl = getDeclInst(self.refMap, rap);
2017 if (rap_decl == nullptr) return true;
2018 if (checkExtern(rap_decl, "Register"_cs))
2019 self.registerParam2register[reg_param->controlPlaneName()] =
2020 rap_decl->controlPlaneName();
2021 if (checkExtern(rap_decl, "DirectRegister"_cs))
2022 self.registerParam2table[reg_param->controlPlaneName()] =
2023 rap_decl->controlPlaneName();
2024 return true;
2025 }
2026 void postorder(const IR::P4Table *table) override {
2027 // Find the M/A table with attached direct register that uses a register parameter
2028 auto *registers = table->properties->getProperty("registers"_cs);
2029 if (registers == nullptr) return;
2030 auto *registers_value = registers->value->to<IR::ExpressionValue>();
2031 CHECK_NULL(registers_value);
2032 auto *registers_path = registers_value->expression->to<IR::PathExpression>();
2033 CHECK_NULL(registers_path);
2034 auto *registers_decl = getDeclInst(self.refMap, registers_path);
2035 CHECK_NULL(registers_decl);
2036 // Replace a direct register with a M/A table it is attached to
2037 for (auto r : self.registerParam2table)
2038 if (r.second == registers_decl->controlPlaneName())
2039 self.registerParam2table[r.first] = table->controlPlaneName();
2040 }
2041 };
2042
2043 evaluatedProgram->getProgram()->apply(RegisterParamFinder(*this));
2044 }
2045
2046 void addTableProperties(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
2047 p4configv1::Table *table, const IR::TableBlock *tableBlock) override {
2048 CHECK_NULL(tableBlock);
2049 auto tableDeclaration = tableBlock->container;
2050 auto blockPrefix = blockNamePrefixMap[tableBlock];
2051
2052 addTablePropertiesCommon(symbols, p4info, table, tableBlock, blockPrefix);
2053
2054 auto directLpf = getDirectLpf(tableDeclaration, refMap, typeMap);
2055 if (directLpf) {
2056 auto id =
2057 symbols.getId(SymbolType::P4RT_DIRECT_LPF(), prefix(blockPrefix, directLpf->name));
2058 table->add_direct_resource_ids(id);
2059 addLpf(symbols, p4info, *directLpf, blockPrefix);
2060 }
2061
2062 auto directWred = getDirectWred(tableDeclaration, refMap, typeMap);
2063 if (directWred) {
2064 auto id = symbols.getId(SymbolType::P4RT_DIRECT_WRED(),
2065 prefix(blockPrefix, directWred->name));
2066 table->add_direct_resource_ids(id);
2067 addWred(symbols, p4info, *directWred, blockPrefix);
2068 }
2069 }
2070
2074 template <typename T>
2075 static std::optional<T> getDirectFilter(const IR::P4Table *table, ReferenceMap *refMap,
2076 TypeMap *typeMap, cstring filterType) {
2077 auto directFilterInstance =
2078 Helpers::getExternInstanceFromProperty(table, "filters"_cs, refMap, typeMap);
2079 if (!directFilterInstance) return std::nullopt;
2080 CHECK_NULL(directFilterInstance->type);
2081 if (directFilterInstance->type->name != filterType) return std::nullopt;
2082 return T::fromDirect(*directFilterInstance, table);
2083 }
2084
2087 static std::optional<Lpf> getDirectLpf(const IR::P4Table *table, ReferenceMap *refMap,
2088 TypeMap *typeMap) {
2089 return getDirectFilter<Lpf>(table, refMap, typeMap, "DirectLpf"_cs);
2090 }
2091
2094 static std::optional<Wred> getDirectWred(const IR::P4Table *table, ReferenceMap *refMap,
2095 TypeMap *typeMap) {
2096 return getDirectFilter<Wred>(table, refMap, typeMap, "DirectWred"_cs);
2097 }
2098
2099 void addExternInstance(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
2100 const IR::ExternBlock *externBlock) override {
2101 auto decl = externBlock->node->to<IR::Declaration_Instance>();
2102 // Skip externs instantiated inside table declarations (constructed in
2103 // place as properties).
2104 if (decl == nullptr) return;
2105
2108
2109 auto pipeName = blockNamePrefixMap[externBlock];
2110
2111 addExternInstanceCommon(symbols, p4info, externBlock, pipeName);
2112
2113 auto p4RtTypeInfo = p4info->mutable_type_info();
2114 // Direct resources are handled by addTableProperties.
2115 if (externBlock->type->name == "Lpf") {
2116 auto lpf = Lpf::from(externBlock);
2117 if (lpf) addLpf(symbols, p4info, *lpf, pipeName);
2118 } else if (externBlock->type->name == "Wred") {
2119 auto wred = Wred::from(externBlock);
2120 if (wred) addWred(symbols, p4info, *wred, pipeName);
2121 } else if (externBlock->type->name == "RegisterParam") {
2122 auto register_param_ = RegisterParam::from(externBlock, refMap, typeMap, p4RtTypeInfo);
2123 if (register_param_) addRegisterParam(symbols, p4info, *register_param_, pipeName);
2124 }
2125 }
2126
2127 void addExternFunction(const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
2128 const P4::ExternFunction *) override {}
2129
2130 void addPortMetadataExternFunction(const P4RuntimeSymbolTableIface &symbols,
2131 p4configv1::P4Info *p4info,
2132 const P4::ExternFunction *externFunction,
2133 const IR::ParserBlock *parserBlock) {
2134 auto p4RtTypeInfo = p4info->mutable_type_info();
2135 auto portMetadata = getPortMetadataExtract(externFunction, refMap, typeMap, p4RtTypeInfo);
2136 if (portMetadata) {
2137 if (blockNamePrefixMap.count(parserBlock)) {
2138 auto portMetadataFullName =
2139 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
2140 addPortMetadata(symbols, p4info, *portMetadata, portMetadataFullName, parserBlock);
2141 }
2142 }
2143 }
2144
2145 void analyzeParser(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
2146 const IR::ParserBlock *parserBlock) {
2147 CHECK_NULL(parserBlock);
2148 auto parser = parserBlock->container;
2149 CHECK_NULL(parser);
2150
2151 for (auto s : parser->parserLocals) {
2152 if (auto inst = s->to<IR::P4ValueSet>()) {
2153 auto namePrefix =
2154 getFullyQualifiedName(parserBlock, inst->controlPlaneName(), true);
2155 auto valueSet =
2156 ValueSet::from(namePrefix, inst, refMap, typeMap, p4info->mutable_type_info());
2157 if (valueSet) addValueSet(symbols, p4info, *valueSet);
2158 }
2159 }
2160
2161 // Add any extern functions within parser states.
2162 for (auto state : parser->states) {
2164 state, [&](const IR::MethodCallExpression *call) {
2165 auto instance = P4::MethodInstance::resolve(call, refMap, typeMap);
2166 if (instance->is<P4::ExternFunction>())
2167 addPortMetadataExternFunction(
2168 symbols, p4info, instance->to<P4::ExternFunction>(), parserBlock);
2169 });
2170 }
2171 }
2172
2174 ::p4::config::v1::P4Info *p4info) override {
2175 // Generates Tofino-specific ValueSet P4Info messages. This step is
2176 // required because value set support in "standard" P4Info is currently
2177 // insufficient: the standard ValueSet message restricts the element
2178 // type to a simple binary string (P4Runtime v1.0 limitation).
2179 //
2180 // ValueSets created by open-source p4RuntimeSerializer.cpp need
2181 // to be deleted because it creates duplicates when dealing with multipipe programs.
2182 p4info->clear_value_sets();
2183
2184 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
2185 if (!block->is<IR::ParserBlock>()) return;
2186 analyzeParser(symbols, p4info, block->to<IR::ParserBlock>());
2187 });
2188
2189 // Check if each parser block in program has a port metadata extern
2190 // defined, if not we add a default instances
2191 forAllPortMetadataBlocks(evaluatedProgram, [&](cstring portMetadataFullName,
2192 const IR::ParserBlock *parserBlock) {
2193 addPortMetadataDefault(symbols, p4info, portMetadataFullName, parserBlock);
2194 });
2195
2196 for (const auto &snapshot : snapshotInfo) addSnapshot(symbols, p4info, snapshot.second);
2197
2198 for (const auto &parser : parserConfiguration)
2199 addParserChoices(symbols, p4info, parser.first, parser.second);
2200 }
2201
2204 static std::optional<PortMetadata> getPortMetadataExtract(
2205 const P4::ExternFunction *function, ReferenceMap *refMap, TypeMap *typeMap,
2206 p4configv1::P4TypeInfo *p4RtTypeInfo) {
2207 if (function->method->name != BFN::ExternPortMetadataUnpackString) return std::nullopt;
2208
2209 if (auto *call = function->expr->to<IR::MethodCallExpression>()) {
2210 auto *typeArg = call->typeArguments->at(0);
2211 auto typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap,
2212 typeArg, p4RtTypeInfo);
2213 return PortMetadata{typeSpec};
2214 }
2215 return std::nullopt;
2216 }
2217
2218 void addPortMetadata(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2219 const PortMetadata &portMetadataExtract, const cstring &name,
2220 const IR::ParserBlock *parserBlock) {
2221 ::barefoot::PortMetadata portMetadata;
2222 portMetadata.mutable_type_spec()->CopyFrom(*portMetadataExtract.typeSpec);
2223 CHECK_NULL(parserBlock);
2224 auto parser = parserBlock->container;
2225 CHECK_NULL(parser);
2226 BUG_CHECK(ingressIntrinsicMdParamName.count(parserBlock),
2227 "%1%: Name of the intrinsic metadata not found for this parser block",
2228 parser->getName());
2229 portMetadata.set_key_name(ingressIntrinsicMdParamName[parserBlock]);
2230 addP4InfoExternInstance(symbols, SymbolType::P4RT_PORT_METADATA(), "PortMetadata"_cs, name,
2231 nullptr, portMetadata, p4Info);
2232 }
2233
2234 void addPortMetadataDefault(const P4RuntimeSymbolTableIface &symbols,
2235 p4configv1::P4Info *p4Info, const cstring &name,
2236 const IR::ParserBlock *parserBlock) {
2237 ::barefoot::PortMetadata portMetadata;
2238 CHECK_NULL(parserBlock);
2239 auto parser = parserBlock->container;
2240 CHECK_NULL(parser);
2241
2242 if (ingressIntrinsicMdParamName.count(parserBlock)) {
2243 portMetadata.set_key_name(ingressIntrinsicMdParamName[parserBlock]);
2244 } else {
2245 // Using the same default name used elsewhere in our toolchain for the "context.json".
2246 auto const DP0TKN = BFN::getDefaultPhase0TableKeyName();
2247 portMetadata.set_key_name(DP0TKN);
2248 }
2249
2250 addP4InfoExternInstance(symbols, SymbolType::P4RT_PORT_METADATA(), "PortMetadata"_cs, name,
2251 nullptr, portMetadata, p4Info);
2252 }
2253
2254 void addSnapshot(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2255 const SnapshotInfo &snapshotInstance) {
2256 ::barefoot::Snapshot snapshot;
2257 snapshot.set_pipe(snapshotInstance.pipe);
2258 if (snapshotInstance.gress == "ingress")
2259 snapshot.set_direction(::barefoot::DIRECTION_INGRESS);
2260 else if (snapshotInstance.gress == "egress")
2261 snapshot.set_direction(::barefoot::DIRECTION_EGRESS);
2262 else
2263 BUG("Invalid gress '%1%'", snapshotInstance.gress);
2264 for (const auto &f : snapshotInstance.fields) {
2265 auto newF = snapshot.add_fields();
2266 newF->set_id(f.id);
2267 newF->set_name(f.name);
2268 newF->set_bitwidth(f.bitwidth);
2269 }
2270 addP4InfoExternInstance(symbols, SymbolType::P4RT_SNAPSHOT(), "Snapshot"_cs,
2271 snapshotInstance.name, nullptr, snapshot, p4Info);
2272 }
2273
2274 void addParserChoices(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2275 cstring name, const ::barefoot::ParserChoices &parserChoices) {
2276 addP4InfoExternInstance(symbols, SymbolType::P4RT_PARSER_CHOICES(), "ParserChoices"_cs,
2277 name, nullptr, parserChoices, p4Info);
2278 }
2279
2280 void addLpf(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2281 const Lpf &lpfInstance, const cstring pipeName) {
2282 auto lpfName = prefix(pipeName, lpfInstance.name);
2283 if (lpfInstance.table) {
2284 ::barefoot::DirectLpf lpf;
2285 auto tableName = prefix(pipeName, *lpfInstance.table);
2286 auto tableId =
2287 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
2288 lpf.set_direct_table_id(tableId);
2289 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_LPF(), "DirectLpf"_cs, lpfName,
2290 lpfInstance.annotations, lpf, p4Info);
2291 LOG2("Added Instance - Direct LPF " << lpfName);
2292 } else {
2293 ::barefoot::Lpf lpf;
2294 lpf.set_size(lpfInstance.size);
2295 addP4InfoExternInstance(symbols, SymbolType::P4RT_LPF(), "Lpf"_cs, lpfName,
2296 lpfInstance.annotations, lpf, p4Info);
2297 LOG2("Added Instance - LPF " << lpfName);
2298 }
2299 }
2300
2302 template <typename Kind>
2303 void setWredCommon(Kind *wred, const Wred &wredInstance) {
2304 using ::barefoot::WredSpec;
2305 auto wred_spec = wred->mutable_spec();
2306 wred_spec->set_drop_value(wredInstance.dropValue);
2307 wred_spec->set_no_drop_value(wredInstance.noDropValue);
2308 }
2309
2310 void addWred(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2311 const Wred &wredInstance, const cstring pipeName) {
2312 auto wredName = prefix(pipeName, wredInstance.name);
2313 if (wredInstance.table) {
2314 ::barefoot::DirectWred wred;
2315 setWredCommon(&wred, wredInstance);
2316 auto tableName = prefix(pipeName, *wredInstance.table);
2317 auto tableId =
2318 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
2319 wred.set_direct_table_id(tableId);
2320 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_WRED(), "DirectWred"_cs,
2321 wredName, wredInstance.annotations, wred, p4Info);
2322 LOG2("Added Instance - Direct WRED " << wredName);
2323 } else {
2324 ::barefoot::Wred wred;
2325 setWredCommon(&wred, wredInstance);
2326 wred.set_size(wredInstance.size);
2327 addP4InfoExternInstance(symbols, SymbolType::P4RT_WRED(), "Wred"_cs, wredName,
2328 wredInstance.annotations, wred, p4Info);
2329 LOG2("Added Instance - WRED " << wredName);
2330 }
2331 }
2332
2333 // For RegisterParams, the table name should have the associated pipe prefix but
2334 // the data field names should not since they have local scope.
2335 void addRegisterParam(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2336 const RegisterParam &registerParamInstance,
2337 cstring pipeName = cstring::empty) {
2338 p4rt_id_t tableId = 0;
2339 if (registerParam2register.count(registerParamInstance.name) > 0)
2340 tableId =
2341 symbols.getId(SymbolType::P4RT_REGISTER(),
2342 prefix(pipeName, registerParam2register[registerParamInstance.name]));
2343 else if (registerParam2table.count(registerParamInstance.name) > 0)
2344 tableId =
2345 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(),
2346 prefix(pipeName, registerParam2table[registerParamInstance.name]));
2347 // If a register parameter is not used, it will show up in neither of the maps.
2348 ::barefoot::RegisterParam register_param_;
2349 register_param_.mutable_type_spec()->CopyFrom(*registerParamInstance.typeSpec);
2350 register_param_.set_table_id(tableId);
2351 register_param_.set_initial_value(registerParamInstance.initial_value);
2352 register_param_.set_data_field_name(registerParamInstance.name);
2353 auto registerParamName = prefix(pipeName, registerParamInstance.name);
2354 addP4InfoExternInstance(symbols, SymbolType::P4RT_REGISTER_PARAM(), "RegisterParam"_cs,
2355 registerParamName, registerParamInstance.annotations,
2356 register_param_, p4Info);
2357 LOG2("Added Instance - RegisterParam " << registerParamName);
2358 }
2359
2360 private:
2362 std::unordered_set<cstring> snapshots;
2364 std::unordered_set<const IR::Block *> hasUserPortMetadata;
2365
2368 std::unordered_map<const IR::ParserBlock *, cstring> ingressIntrinsicMdParamName;
2369
2370 using SnapshotInfoMap = std::map<const IR::ControlBlock *, SnapshotInfo>;
2371 SnapshotInfoMap snapshotInfo;
2372
2373 std::unordered_map<const IR::Block *, cstring> blockNamePrefixMap;
2374
2375 std::map<cstring, ::barefoot::ParserChoices> parserConfiguration;
2376
2377 bool isMultiParser;
2378
2380 std::unordered_map<cstring, cstring> registerParam2register;
2382 std::unordered_map<cstring, cstring> registerParam2table;
2383};
2384
2389 public:
2391 const IR::ToplevelBlock *evaluatedProgram)
2392 : BFRuntimeArchHandlerCommon<Arch::PSA>(refMap, typeMap, evaluatedProgram) {
2393 implementationString = "psa_implementation"_cs;
2394 }
2395
2397 (void)symbols;
2398 // analyze action profiles / selectors and build a mapping from action
2399 // profile / selector name to the set of tables referencing them
2400 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
2401 if (!block->is<IR::TableBlock>()) return;
2402 auto table = block->to<IR::TableBlock>()->container;
2403 auto implementation = getTableImplementationName(table, refMap);
2404 if (implementation)
2405 actionProfilesRefs[*implementation].insert(table->controlPlaneName());
2406 });
2407
2408 // Creates a set of color-aware meters by inspecting every call to the
2409 // execute method on each meter instance: if at least one method call
2410 // includes a second argument (pre-color), then the meter is
2411 // color-aware.
2412 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
2413 if (!block->is<IR::ExternBlock>()) return;
2414 auto externBlock = block->to<IR::ExternBlock>();
2415 if (externBlock->type->name != "Meter" && externBlock->type->name != "DirectMeter")
2416 return;
2417 auto decl = externBlock->node->to<IR::Declaration_Instance>();
2418 // Should not happen for TNA: direct meters cannot be constructed
2419 // in-place.
2420 CHECK_NULL(decl);
2421 forAllExternMethodCalls(decl, [&](const P4::ExternMethod *method) {
2422 auto call = method->expr;
2423 if (call->arguments->size() == 2) {
2424 LOG3("Meter " << decl->controlPlaneName() << " is color-aware "
2425 << "because of 2-argument call to execute()");
2426 colorAwareMeters.insert(decl->controlPlaneName());
2427 }
2428 });
2429 });
2430 }
2431
2432 void addTableProperties(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
2433 p4configv1::Table *table, const IR::TableBlock *tableBlock) override {
2434 CHECK_NULL(tableBlock);
2435 addTablePropertiesCommon(symbols, p4info, table, tableBlock, defaultPipeName);
2436 }
2437
2439 const IR::ExternBlock *externBlock) override {
2440 collectExternInstanceCommon(symbols, externBlock);
2441 }
2442
2444
2445 void addExternInstance(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
2446 const IR::ExternBlock *externBlock) {
2447 addExternInstanceCommon(symbols, p4info, externBlock, defaultPipeName);
2448 }
2449
2450 void addExternFunction(const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
2451 const P4::ExternFunction *) {}
2452};
2453
2457 ReferenceMap *refMap, TypeMap *typeMap,
2458 const IR::ToplevelBlock *evaluatedProgram) const override {
2459 return new BFRuntimeArchHandlerTofino(refMap, typeMap, evaluatedProgram);
2460 }
2461};
2462
2466 ReferenceMap *refMap, TypeMap *typeMap,
2467 const IR::ToplevelBlock *evaluatedProgram) const override {
2468 return new BFRuntimeArchHandlerPSA(refMap, typeMap, evaluatedProgram);
2469 }
2470};
2471
2472} // namespace BFN
2473#endif /* BACKENDS_TOFINO_BF_P4C_CONTROL_PLANE_BFRUNTIME_ARCH_HANDLER_H_ */
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:669
static std::optional< ActionProfile > getActionProfile(const IR::ExternBlock *instance)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1141
void forAllExternMethodCalls(const IR::IDeclaration *object, Func function)
calls function on every extern method applied to the extern object
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1444
static bool getSupportsTimeout(const IR::P4Table *table)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:920
std::unordered_map< cstring, std::set< cstring > > actionProfilesRefs
Maps each action profile / selector to the set of tables referencing it.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1498
void collectExternFunction(P4RuntimeSymbolTableIface *, const P4::ExternFunction *) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:819
google::protobuf::util::JsonPrintOptions getJsonPrintOptions() override
Control how JSON is output.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1511
void collectExtra(P4RuntimeSymbolTableIface *symbols) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:836
std::optional< ActionProfile > getActionProfile(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1127
const IR::Property * getTableImplementationProperty(const IR::P4Table *table)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1456
void addExternEntries(const p4::v1::WriteRequest *, const P4RuntimeSymbolTableIface &, const IR::ExternBlock *) override
This method is called to add target specific extern entries.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1035
void collectExternMethod(P4RuntimeSymbolTableIface *, const P4::ExternMethod *) override
Collects architecture-specific @externMethod instance in @symbols table.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:817
std::unordered_set< cstring > colorAwareMeters
The set of color-aware meters in the program.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1500
bool filterAnnotations(cstring) override
called when processing annotations via setPreamble
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1038
cstring getControlPlaneName(const IR::Block *block) override
Get control plane name for @block.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:685
void collectTableProperties(P4RuntimeSymbolTableIface *symbols, const IR::TableBlock *tableBlock) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:732
void collectAssignmentStatement(P4RuntimeSymbolTableIface *, const IR::AssignmentStatement *) override
Collects architecture-specific used in assignment statements.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:814
std::optional< ActionSelector > getActionSelector(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1151
static std::optional< Register > getDirectRegister(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap, p4configv1::P4TypeInfo *p4RtTypeInfo)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:942
void postAdd(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1023
void setMeterCommon(Kind *meter, const Helpers::Counterlike< ArchMeterExtern > &meterInstance)
Set common fields between barefoot::Meter and barefoot::DirectMeter.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1330
void setCounterCommon(Kind *counter, const Helpers::Counterlike< ArchCounterExtern > &counterInstance)
Set common fields between barefoot::Counter and barefoot::DirectCounter.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1295
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2388
void collectExternFunction(P4RuntimeSymbolTableIface *, const P4::ExternFunction *)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2443
void postCollect(const P4RuntimeSymbolTableIface &symbols)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2396
void collectExternInstance(P4RuntimeSymbolTableIface *symbols, const IR::ExternBlock *externBlock) override
Collects architecture-specific @externBlock instance in @symbols table.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2438
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1519
static std::optional< PortMetadata > getPortMetadataExtract(const P4::ExternFunction *function, ReferenceMap *refMap, TypeMap *typeMap, p4configv1::P4TypeInfo *p4RtTypeInfo)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2204
std::set< SnapshotFieldInfo > fields
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1760
size_t userHdrParamIdx
one of "ingress", "egress"
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1754
void postAdd(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2173
void collectExternInstance(P4RuntimeSymbolTableIface *symbols, const IR::ExternBlock *externBlock) override
Collects architecture-specific @externBlock instance in @symbols table.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1661
static std::optional< T > getDirectFilter(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap, cstring filterType)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2075
void setWredCommon(Kind *wred, const Wred &wredInstance)
Set common fields between barefoot::Wred and barefoot::DirectWred.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2303
void collectExternFunction(P4RuntimeSymbolTableIface *, const P4::ExternFunction *) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1687
cstring gress
one of "pipe0", "pipe1", "pipe2", "pipe3"
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1753
void collectParserChoices(P4RuntimeSymbolTableIface *symbols)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1828
void collectSnapshot(P4RuntimeSymbolTableIface *symbols, const IR::ControlBlock *controlBlock, SnapshotFieldIdTable *fieldIds)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1787
void postCollect(const P4RuntimeSymbolTableIface &symbols) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1919
cstring name
the index of the "hdr" parameter in the control parameter list
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1755
void collectExtra(P4RuntimeSymbolTableIface *symbols) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1879
static std::optional< Wred > getDirectWred(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2094
static std::optional< Lpf > getDirectLpf(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2087
void getSnapshotControls()
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1765
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1751
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:555
static void find(TypeMap *typeMap, const IR::Type *type, cstring paramName, bool includeValid, std::set< SnapshotFieldInfo > *fields, SnapshotFieldIdTable *fieldIds)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:657
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:535
Extends P4RuntimeSymbolType for the Tofino extern types.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:176
static const IR::Type_Header * flatten(P4::TypeMap *typeMap, const IR::Type_Header *headerType)
Definition flattenHeader.cpp:78
Definition p4RuntimeArchHandler.h:139
Definition p4RuntimeArchHandler.h:109
virtual p4rt_id_t getId(P4RuntimeSymbolType type, const IR::IDeclaration *declaration) const =0
virtual cstring getAlias(cstring name) const =0
virtual void add(P4RuntimeSymbolType type, const IR::IDeclaration *declaration)=0
Add a @type symbol, extracting the name and id from @declaration.
Definition p4RuntimeArchHandler.h:63
static const ::p4::config::v1::P4DataTypeSpec * convert(const P4::ReferenceMap *refMap, P4::TypeMap *typeMap, const IR::Type *type, ::p4::config::v1::P4TypeInfo *typeInfo)
Definition typeSpecConverter.cpp:390
Definition methodInstance.h:194
Definition methodInstance.h:168
The Declaration interface, representing objects with names.
Definition declaration.h:26
Definition vector.h:59
Definition visitor.h:400
static MethodInstance * resolve(const IR::MethodCallExpression *mce, const DeclarationLookup *refMap, TypeMap *typeMap, bool useExpressionType=false, const Visitor::Context *ctxt=nullptr, bool incomplete=false)
Definition methodInstance.cpp:27
const IR::IDeclaration * object
Definition methodInstance.h:79
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
const IR::IDeclaration * getDeclaration(const IR::Path *path, bool notNull=false) const override
Definition referenceMap.cpp:78
Definition typeMap.h:41
Definition cstring.h:85
The namespace encapsulating Barefoot/Intel-specific stuff.
Definition add_t2na_meta.cpp:21
std::optional< P4::ExternInstance > getExternInstanceFromPropertyByTypeName(const IR::P4Table *table, cstring propertyName, cstring externTypeName, P4::ReferenceMap *refMap, P4::TypeMap *typeMap, bool *isConstructedInPlace)
Definition tofino/bf-p4c/arch/helpers.cpp:60
const IR::Declaration_Instance * getDeclInst(const P4::ReferenceMap *refMap, const IR::PathExpression *path)
Definition tofino/bf-p4c/arch/helpers.cpp:29
std::optional< P4::ExternInstance > getExternInstanceFromProperty(const IR::P4Table *table, cstring propertyName, P4::ReferenceMap *refMap, P4::TypeMap *typeMap)
Definition tofino/bf-p4c/arch/helpers.cpp:122
Arch
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:65
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:68
The information about a digest instance which is needed to serialize it.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:281
The information about a hash instance which is needed to serialize it.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:289
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:295
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:70
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:78
void forAllEvaluatedBlocks(const IR::Block *block, Func function)
Definition p4RuntimeArchHandler.h:234
std::optional< ExternInstance > getExternInstanceFromProperty(const IR::P4Table *table, const cstring &propertyName, ReferenceMap *refMap, TypeMap *typeMap, bool *isConstructedInPlace)
Definition p4RuntimeArchHandler.cpp:41
bool isExternPropertyConstructedInPlace(const IR::P4Table *table, const cstring &propertyName)
Definition p4RuntimeArchHandler.cpp:77
void addDocumentation(Message *message, const IR::IAnnotated *annotated)
' and '@description' annotations if present.
Definition p4RuntimeArchHandler.h:308
std::optional< Counterlike< Kind > > getDirectCounterlike(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition p4RuntimeArchHandler.h:491
A traits class describing the properties of "counterlike" things.
Definition p4RuntimeArchHandler.h:369
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
void warning(const char *format, Args &&...args)
Report a warning with the given message.
Definition lib/error.h:115
void forAllMatching(const IR::Node *root, Func &&function)
Definition visitor.h:801
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:51
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:243
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:258
The information about a LPF instance which is needed to serialize it.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:432
static std::optional< Lpf > from(const IR::ExternBlock *instance)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:442
static std::optional< Lpf > fromDirect(const P4::ExternInstance &instance, const IR::P4Table *table)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:452
const std::optional< cstring > table
If not none, the instance is a direct resource associated with table.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:436
The architecture handler builder implementation for PSA.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2464
P4::ControlPlaneAPI::P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2465
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:510
The information about a register instance which is needed to serialize it.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:334
static std::optional< Register > fromDirect(const P4::ExternInstance &instance, const IR::P4Table *table, const ReferenceMap *refMap, TypeMap *typeMap, p4configv1::P4TypeInfo *p4RtTypeInfo)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:367
static std::optional< Register > from(const IR::ExternBlock *instance, const ReferenceMap *refMap, TypeMap *typeMap, p4configv1::P4TypeInfo *p4RtTypeInfo)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:343
The information about a register parameter instance which is needed to serialize it.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:396
static std::optional< RegisterParam > from(const IR::ExternBlock *instance, const ReferenceMap *refMap, TypeMap *typeMap, p4configv1::P4TypeInfo *p4RtTypeInfo)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:405
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:518
The architecture handler builder implementation for Tofino.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2455
P4::ControlPlaneAPI::P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2456
The information about a value set instance which is needed to serialize it.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:304
The information about a Wred instance which is needed to serialize it.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:461
static std::optional< Wred > fromDirect(const P4::ExternInstance &instance, const IR::P4Table *table)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:491
const std::optional< cstring > table
If not none, the instance is a direct resource associated with table.
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:467
static std::optional< Wred > from(const IR::ExternBlock *instance)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:473
Definition p4RuntimeArchHandler.h:377
const std::optional< cstring > table
If not none, the instance is a direct resource associated with @table.
Definition p4RuntimeArchHandler.h:387
const cstring name
The name of the instance.
Definition p4RuntimeArchHandler.h:379
const IR::IAnnotated * annotations
If non-null, the instance's annotations.
Definition p4RuntimeArchHandler.h:381
const cstring unit
The units parameter to the instance; valid values vary depending on @Kind.
Definition p4RuntimeArchHandler.h:383
const int64_t size
The size parameter to the instance.
Definition p4RuntimeArchHandler.h:385
Definition p4RuntimeArchHandler.h:204
Definition externInstance.h:51
T * to() noexcept
Definition rtti.h:226
bool is() const noexcept
Definition rtti.h:216