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 "barefoot/p4info.pb.h"
30#include "bf-p4c/arch/fromv1.0/phase0.h"
31#include "bf-p4c/arch/helpers.h"
32#include "bf-p4c/arch/tna.h"
33#include "bf-p4c/common/utils.h"
34#include "bf-p4c/control-plane/bfruntime.h"
35#include "bf-p4c/control-plane/p4runtime_force_std.h"
36#include "bf-p4c/control-plane/runtime.h"
37#include "bf-p4c/device.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 = ""_cs) 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 = ""_cs) 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() : ""_cs;
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 = ""_cs;
712 cstring control_plane_name = ""_cs;
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, cstring blockPrefix = "") {
850 CHECK_NULL(tableBlock);
851 auto tableDeclaration = tableBlock->container;
852
854
855 auto p4RtTypeInfo = p4info->mutable_type_info();
856
857 auto actionProfile = getActionProfile(tableDeclaration, refMap, typeMap);
858 auto actionSelector = getActionSelector(tableDeclaration, refMap, typeMap);
859 auto directCounter =
860 Helpers::getDirectCounterlike<ArchCounterExtern>(tableDeclaration, refMap, typeMap);
861 auto directMeter =
862 Helpers::getDirectCounterlike<ArchMeterExtern>(tableDeclaration, refMap, typeMap);
863 auto directRegister = getDirectRegister(tableDeclaration, refMap, typeMap, p4RtTypeInfo);
864 auto supportsTimeout = getSupportsTimeout(tableDeclaration);
865
866 if (actionProfile) {
867 auto id = actionProfile->getId(symbols, blockPrefix);
868 table->set_implementation_id(id);
869 if (isExternPropertyConstructedInPlace(tableDeclaration, implementationString)) {
870 addActionProfile(symbols, p4info, *actionProfile, blockPrefix);
871 }
872 }
873
874 if (actionSelector) {
875 auto id = actionSelector->getId(symbols, blockPrefix);
876 table->set_implementation_id(id);
877 if (isExternPropertyConstructedInPlace(tableDeclaration, implementationString)) {
878 addActionSelector(symbols, p4info, *actionSelector, blockPrefix);
879 }
880 }
881
882 // Direct resources are handled here. There is no risk to create
883 // duplicates as direct resources cannot be shared across tables. We
884 // could also handle those in addExternInstance but it would not be very
885 // convenient to get a handle on the parent table (the parent table's id
886 // is included in the P4Info message).
887 if (directCounter) {
888 auto id = symbols.getId(SymbolType::P4RT_DIRECT_COUNTER(),
889 prefix(blockPrefix, directCounter->name));
890 table->add_direct_resource_ids(id);
891 addCounter(symbols, p4info, *directCounter, blockPrefix);
892 }
893
894 if (directMeter) {
895 auto id = symbols.getId(SymbolType::P4RT_DIRECT_METER(),
896 prefix(blockPrefix, directMeter->name));
897 table->add_direct_resource_ids(id);
898 addMeter(symbols, p4info, *directMeter, blockPrefix);
899 }
900
901 if (directRegister) {
902 auto id = symbols.getId(SymbolType::P4RT_DIRECT_REGISTER(),
903 prefix(blockPrefix, directRegister->name));
904 table->add_direct_resource_ids(id);
905 addRegister(symbols, p4info, *directRegister, blockPrefix);
906 }
907
908 // TODO: idle timeout may change for TNA in the future and we
909 // may need to rely on P4Info table specific extensions.
910 if (supportsTimeout) {
911 table->set_idle_timeout_behavior(p4configv1::Table::NOTIFY_CONTROL);
912 } else {
913 table->set_idle_timeout_behavior(p4configv1::Table::NO_TIMEOUT);
914 }
915 }
916
919 static bool getSupportsTimeout(const IR::P4Table *table) {
920 auto timeout = table->properties->getProperty("idle_timeout"_cs);
921 if (timeout == nullptr) return false;
922 if (!timeout->value->is<IR::ExpressionValue>()) {
923 error("Unexpected value %1% for idle_timeout on table %2%", timeout, table);
924 return false;
925 }
926
927 auto expr = timeout->value->to<IR::ExpressionValue>()->expression;
928 if (!expr->is<IR::BoolLiteral>()) {
929 error(
930 "Unexpected non-boolean value %1% for idle_timeout "
931 "property on table %2%",
932 timeout, table);
933 return false;
934 }
935
936 return expr->to<IR::BoolLiteral>()->value;
937 }
938
941 static std::optional<Register> getDirectRegister(const IR::P4Table *table, ReferenceMap *refMap,
942 TypeMap *typeMap,
943 p4configv1::P4TypeInfo *p4RtTypeInfo) {
944 auto directRegisterInstance =
945 Helpers::getExternInstanceFromProperty(table, "registers"_cs, refMap, typeMap);
946 if (!directRegisterInstance) return std::nullopt;
947 return Register::fromDirect(*directRegisterInstance, table, refMap, typeMap, p4RtTypeInfo);
948 }
949
950 void addExternInstance(const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
951 const IR::ExternBlock *) override {}
952
953 void addExternInstanceCommon(const P4RuntimeSymbolTableIface &symbols,
954 p4configv1::P4Info *p4info, const IR::ExternBlock *externBlock,
955 cstring pipeName = ""_cs) {
956 Log::TempIndent indent;
957 LOG1("Adding Extern Instances for pipe " << pipeName << indent);
958 auto decl = externBlock->node->to<IR::Declaration_Instance>();
959 // Skip externs instantiated inside table declarations (constructed in
960 // place as properties).
961 if (decl == nullptr) return;
962
964
965 auto p4RtTypeInfo = p4info->mutable_type_info();
966 // Direct resources are handled by addTableProperties.
967 if (externBlock->type->name == "ActionProfile") {
968 auto actionProfile = getActionProfile(externBlock);
969 if (actionProfile) addActionProfile(symbols, p4info, *actionProfile, pipeName);
970 } else if (externBlock->type->name == "ActionSelector") {
971 auto actionSelector = getActionSelector(externBlock);
972 if (actionSelector) addActionSelector(symbols, p4info, *actionSelector, pipeName);
973 } else if (externBlock->type->name == "Counter") {
974 auto counter =
975 Counterlike<ArchCounterExtern>::from(externBlock, refMap, typeMap, p4RtTypeInfo);
976 if (counter) addCounter(symbols, p4info, *counter, pipeName);
977 } else if (externBlock->type->name == "Meter") {
978 auto meter =
979 Counterlike<ArchMeterExtern>::from(externBlock, refMap, typeMap, p4RtTypeInfo);
980 if (meter) addMeter(symbols, p4info, *meter, pipeName);
981 } else if (externBlock->type->name == "Digest") {
982 auto digest = getDigest(decl, p4RtTypeInfo);
983 if (digest) addDigest(symbols, p4info, *digest, pipeName);
984 } else if (externBlock->type->name == "Register") {
985 auto register_ = Register::from(externBlock, refMap, typeMap, p4RtTypeInfo);
986 if (register_) addRegister(symbols, p4info, *register_, pipeName);
987 } else if (externBlock->type->name == "Hash") {
988 auto dynHash = getDynHash(decl, p4RtTypeInfo);
989 if (dynHash) addDynHash(symbols, p4info, *dynHash, pipeName);
990 }
991 }
992
993 void addExternFunction(const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
994 const P4::ExternFunction *) override {}
995
996 void addValueSet(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
997 const ValueSet &valueSetInstance) {
998 ::barefoot::ValueSet valueSet;
999 valueSet.set_size(valueSetInstance.size);
1000 valueSet.mutable_type_spec()->CopyFrom(*valueSetInstance.typeSpec);
1001 addP4InfoExternInstance(symbols, SymbolType::P4RT_VALUE_SET(), "ValueSet"_cs,
1002 valueSetInstance.name, valueSetInstance.annotations, valueSet,
1003 p4info);
1004 LOG2("Added Instance - Value Set " << valueSetInstance.name);
1005 }
1006
1007 void analyzeParser(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
1008 const IR::ParserBlock *parserBlock) {
1009 CHECK_NULL(parserBlock);
1010 auto parser = parserBlock->container;
1011 CHECK_NULL(parser);
1012
1013 for (auto s : parser->parserLocals) {
1014 if (auto inst = s->to<IR::P4ValueSet>()) {
1015 auto valueSet = ValueSet::from(inst->controlPlaneName(), inst, refMap, typeMap,
1016 p4info->mutable_type_info());
1017 if (valueSet) addValueSet(symbols, p4info, *valueSet);
1018 }
1019 }
1020 }
1021
1023 ::p4::config::v1::P4Info *p4info) override {
1024 // Generates Tofino-specific ValueSet P4Info messages. This step is
1025 // required because value set support in "standard" P4Info is currently
1026 // insufficient: the standard ValueSet message restricts the element
1027 // type to a simple binary string (P4Runtime v1.0 limitation).
1028 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1029 if (!block->is<IR::ParserBlock>()) return;
1030 analyzeParser(symbols, p4info, block->to<IR::ParserBlock>());
1031 });
1032 }
1033
1034 void addExternEntries(const p4::v1::WriteRequest *, const P4RuntimeSymbolTableIface &,
1035 const IR::ExternBlock *) override {}
1036
1037 bool filterAnnotations(cstring) override { return false; }
1038
1039 std::optional<Digest> getDigest(const IR::Declaration_Instance *decl,
1040 p4configv1::P4TypeInfo *p4RtTypeInfo) {
1041 std::vector<const P4::ExternMethod *> packCalls;
1042 // Check that the pack method is called exactly once on the digest
1043 // instance. The type of the data being packed used to be a type
1044 // parameter of the pack method itself, and not a type parameter of the
1045 // extern, so the we used to require a reference to the P4::ExternMethod
1046 // for the pack call in order to produce the P4Info type spec. This is
1047 // no longer the case but we keep this code as a sanity check.
1049 decl, [&](const P4::ExternMethod *method) { packCalls.push_back(method); });
1050 if (packCalls.size() == 0) return std::nullopt;
1051 if (packCalls.size() > 1) {
1052 error("Expected single call to pack for digest instance '%1%'", decl);
1053 return std::nullopt;
1054 }
1055 LOG4("Found 'pack' method call for digest instance " << decl->controlPlaneName());
1056
1057 BUG_CHECK(decl->type->is<IR::Type_Specialized>(), "%1%: expected Type_Specialized",
1058 decl->type);
1059 auto type = decl->type->to<IR::Type_Specialized>();
1060 BUG_CHECK(type->arguments->size() == 1, "%1%: expected one type argument", decl);
1061 auto typeArg = type->arguments->at(0);
1062 auto typeSpec =
1063 P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
1064 BUG_CHECK(typeSpec != nullptr,
1065 "P4 type %1% could not be converted to P4Info P4DataTypeSpec");
1066 return Digest{decl->controlPlaneName(), typeSpec, decl->to<IR::IAnnotated>()};
1067 }
1068
1069 std::optional<DynHash> getDynHash(const IR::Declaration_Instance *decl,
1070 p4configv1::P4TypeInfo *p4RtTypeInfo) {
1071 std::vector<const P4::ExternMethod *> hashCalls;
1072 // Get Hash Calls in the program for the declaration.
1074 decl, [&](const P4::ExternMethod *method) { hashCalls.push_back(method); });
1075 if (hashCalls.size() == 0) return std::nullopt;
1076 if (hashCalls.size() > 1) {
1077 warning(
1078 "Expected single call to get for hash instance '%1%'."
1079 "Control plane API is not generated for this hash call",
1080 decl);
1081 return std::nullopt;
1082 }
1083 LOG4("Found 'get' method call for hash instance " << decl->controlPlaneName());
1084
1085 // Extract typeArgs and field Names to be passed on through dynHash
1086 // instance
1087 if (auto *call = hashCalls[0]->expr->to<IR::MethodCallExpression>()) {
1088 int hashWidth = 0;
1089 if (auto t = call->type->to<IR::Type_Bits>()) {
1090 hashWidth = t->width_bits();
1091 }
1092
1093 auto fieldListArg = call->arguments->at(0);
1094 LOG4("FieldList for Hash: " << fieldListArg);
1095 auto *typeArgs = new IR::Vector<IR::Type>();
1096 std::vector<DynHash::hashField> hashFieldInfo;
1097 if (fieldListArg->expression->is<IR::ListExpression>() ||
1098 fieldListArg->expression->is<IR::StructExpression>()) {
1099 for (auto f : *getListExprComponents(*fieldListArg->expression)) {
1100 if (auto c = f->to<IR::Concat>()) {
1101 for (auto e : convertConcatToList(c)) {
1102 hashFieldInfo.push_back({e->toString(), e->is<IR::Constant>()});
1103 typeArgs->push_back(e->type);
1104 }
1105 continue;
1106 }
1107 hashFieldInfo.push_back({f->toString(), f->is<IR::Constant>()});
1108 auto t = f->type->is<IR::Type_SerEnum>() ? f->type->to<IR::Type_SerEnum>()->type
1109 : f->type;
1110 typeArgs->push_back(t);
1111 }
1112 }
1113 auto *typeList = new IR::Type_List(*typeArgs);
1114 auto typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap,
1115 typeList, p4RtTypeInfo);
1116 BUG_CHECK(typeSpec != nullptr,
1117 "P4 type %1% could not be converted to P4Info P4DataTypeSpec");
1118 return DynHash{decl->controlPlaneName(), typeSpec, decl->to<IR::IAnnotated>(),
1119 hashFieldInfo, hashWidth};
1120 }
1121 return std::nullopt;
1122 }
1123
1126 std::optional<ActionProfile> getActionProfile(const IR::P4Table *table, ReferenceMap *refMap,
1127 TypeMap *typeMap) {
1129 auto instance = getExternInstanceFromProperty(table, implementationString, refMap, typeMap);
1130 if (!instance) return std::nullopt;
1131 if (instance->type->name != "ActionProfile") return std::nullopt;
1132 auto size = instance->substitution.lookupByName("size"_cs)->expression;
1133 // size is a bit<32> compile-time value
1134 BUG_CHECK(size->template is<IR::Constant>(), "Non-constant size");
1135 return ActionProfile{*instance->name, size->template to<IR::Constant>()->asInt(),
1136 getTableImplementationAnnotations(table, refMap)};
1137 }
1138
1140 static std::optional<ActionProfile> getActionProfile(const IR::ExternBlock *instance) {
1141 auto decl = instance->node->to<IR::IDeclaration>();
1142 auto size = instance->getParameterValue("size"_cs);
1143 BUG_CHECK(size->is<IR::Constant>(), "Non-constant size");
1144 return ActionProfile{decl->controlPlaneName(), size->to<IR::Constant>()->asInt(),
1145 decl->to<IR::IAnnotated>()};
1146 }
1147
1150 std::optional<ActionSelector> getActionSelector(const IR::P4Table *table, ReferenceMap *refMap,
1151 TypeMap *typeMap) {
1153 auto action_selector = getExternInstanceFromPropertyByTypeName(
1154 table, implementationString, "ActionSelector"_cs, refMap, typeMap);
1155 if (!action_selector) return std::nullopt;
1156 // TODO: remove legacy code
1157 // used to support deprecated ActionSelector constructor.
1158 if (action_selector->substitution.lookupByName("size"_cs)) {
1159 auto size = action_selector->substitution.lookupByName("size"_cs)->expression;
1160 BUG_CHECK(size->template is<IR::Constant>(), "Non-constant size");
1161 return ActionSelector{*action_selector->name,
1162 std::nullopt,
1163 size->template to<IR::Constant>()->asInt(),
1164 defaultMaxGroupSize,
1165 size->template to<IR::Constant>()->asInt(),
1166 getTableImplementationAnnotations(table, refMap),
1167 true /* _sel suffix */};
1168 }
1169 auto maxGroupSize =
1170 action_selector->substitution.lookupByName("max_group_size"_cs)->expression;
1171 auto numGroups = action_selector->substitution.lookupByName("num_groups"_cs)->expression;
1172 // size is a bit<32> compile-time value
1173 BUG_CHECK(maxGroupSize->template is<IR::Constant>(), "Non-constant max group size");
1174 BUG_CHECK(numGroups->template is<IR::Constant>(), "Non-constant num groups");
1175 return ActionSelector{*action_selector->name,
1176 *action_selector->name,
1177 -1 /* size */,
1178 maxGroupSize->template to<IR::Constant>()->asInt(),
1179 numGroups->template to<IR::Constant>()->asInt(),
1180 getTableImplementationAnnotations(table, refMap),
1181 false /* _sel suffix */};
1182 }
1183
1184 std::optional<ActionSelector> getActionSelector(const IR::ExternBlock *instance) {
1185 auto actionSelDecl = instance->node->to<IR::IDeclaration>();
1186 // to be deleted, used to support deprecated ActionSelector constructor.
1187 if (instance->findParameterValue("size"_cs)) {
1188 auto size = instance->getParameterValue("size"_cs);
1189 BUG_CHECK(size->is<IR::Constant>(), "Non-constant size");
1190 return ActionSelector{actionSelDecl->controlPlaneName(),
1191 std::nullopt,
1192 size->to<IR::Constant>()->asInt(),
1193 defaultMaxGroupSize,
1194 size->to<IR::Constant>()->asInt(),
1195 actionSelDecl->to<IR::IAnnotated>(),
1196 false /* sel suffix */};
1197 }
1198 auto maxGroupSize = instance->getParameterValue("max_group_size"_cs);
1199 auto numGroups = instance->getParameterValue("num_groups"_cs);
1200 BUG_CHECK(maxGroupSize->is<IR::Constant>(), "Non-constant max group size");
1201 BUG_CHECK(numGroups->is<IR::Constant>(), "Non-constant num groups");
1202 auto action_profile = instance->getParameterValue("action_profile"_cs);
1203 auto action_profile_decl =
1204 action_profile->to<IR::ExternBlock>()->node->to<IR::IDeclaration>();
1205 return ActionSelector{actionSelDecl->controlPlaneName(),
1206 cstring::to_cstring(action_profile_decl->controlPlaneName()),
1207 -1 /* size */,
1208 maxGroupSize->to<IR::Constant>()->asInt(),
1209 numGroups->to<IR::Constant>()->asInt(),
1210 actionSelDecl->to<IR::IAnnotated>(),
1211 false /* sel suffix */};
1212 }
1213
1214 static p4configv1::Extern *getP4InfoExtern(P4::ControlPlaneAPI::P4RuntimeSymbolType typeId,
1215 cstring typeName, p4configv1::P4Info *p4info) {
1216 for (auto &externType : *p4info->mutable_externs()) {
1217 if (externType.extern_type_id() == static_cast<p4rt_id_t>(typeId)) return &externType;
1218 }
1219 auto *externType = p4info->add_externs();
1220 externType->set_extern_type_id(static_cast<p4rt_id_t>(typeId));
1221 externType->set_extern_type_name(typeName);
1222 return externType;
1223 }
1224
1225 static void addP4InfoExternInstance(const P4RuntimeSymbolTableIface &symbols,
1227 cstring typeName, cstring name,
1228 const IR::IAnnotated *annotations,
1229 const ::google::protobuf::Message &message,
1230 p4configv1::P4Info *p4info) {
1231 auto *externType = getP4InfoExtern(typeId, typeName, p4info);
1232 auto *externInstance = externType->add_instances();
1233 auto *pre = externInstance->mutable_preamble();
1234 pre->set_id(symbols.getId(typeId, name));
1235 pre->set_name(name);
1236 pre->set_alias(symbols.getAlias(name));
1237 Helpers::addAnnotations(pre, annotations);
1238 Helpers::addDocumentation(pre, annotations);
1239 externInstance->mutable_info()->PackFrom(message);
1240 }
1241
1242 void addDigest(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1243 const Digest &digestInstance, cstring pipeName = "") {
1244 ::barefoot::Digest digest;
1245 digest.mutable_type_spec()->CopyFrom(*digestInstance.typeSpec);
1246 auto digestName = prefix(pipeName, digestInstance.name);
1247 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIGEST(), "Digest"_cs, digestName,
1248 digestInstance.annotations, digest, p4Info);
1249 LOG2("Added Instance - Digest " << digestName);
1250 }
1251
1252 void addDynHash(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1253 const DynHash &dynHashInstance, cstring pipeName = "") {
1254 ::barefoot::DynHash dynHash;
1255 dynHash.set_hash_width(dynHashInstance.hashWidth);
1256 dynHash.mutable_type_spec()->CopyFrom(*dynHashInstance.typeSpec);
1257 auto dynHashName = prefix(pipeName, dynHashInstance.name);
1258 for (const auto &f : dynHashInstance.hashFieldInfo) {
1259 auto newF = dynHash.add_field_infos();
1260 newF->set_field_name(f.hashFieldName);
1261 newF->set_is_constant(f.isConstant);
1262 }
1263 addP4InfoExternInstance(symbols, SymbolType::P4RT_HASH(), "DynHash"_cs, dynHashName,
1264 dynHashInstance.annotations, dynHash, p4Info);
1265 LOG2("Added Instance - DynHash " << dynHashName);
1266 }
1267
1268 // For Registers, the table name should have the associated pipe prefix but
1269 // the data field names should not since they have local scope.
1270 void addRegister(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1271 const Register &registerInstance, cstring pipeName = "") {
1272 auto registerName = prefix(pipeName, registerInstance.name);
1273 if (registerInstance.size == 0) {
1274 ::barefoot::DirectRegister register_;
1275 register_.mutable_type_spec()->CopyFrom(*registerInstance.typeSpec);
1276 register_.set_data_field_name(registerInstance.name);
1277 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_REGISTER(),
1278 "DirectRegister"_cs, registerName, registerInstance.annotations,
1279 register_, p4Info);
1280 LOG2("Added Instance - DirectRegister " << registerName);
1281 } else {
1282 ::barefoot::Register register_;
1283 register_.set_size(registerInstance.size);
1284 register_.mutable_type_spec()->CopyFrom(*registerInstance.typeSpec);
1285 register_.set_data_field_name(registerInstance.name);
1286 addP4InfoExternInstance(symbols, SymbolType::P4RT_REGISTER(), "Register"_cs,
1287 registerName, registerInstance.annotations, register_, p4Info);
1288 LOG2("Added Instance - Register " << registerName);
1289 }
1290 }
1291
1293 template <typename Kind>
1294 void setCounterCommon(Kind *counter,
1295 const Helpers::Counterlike<ArchCounterExtern> &counterInstance) {
1296 auto counter_spec = counter->mutable_spec();
1297 counter_spec->set_unit(CounterTraits::mapUnitName(counterInstance.unit));
1298 }
1299
1300 void addCounter(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1301 const Helpers::Counterlike<ArchCounterExtern> &counterInstance,
1302 const cstring blockPrefix = "") {
1303 if (counterInstance.table) {
1304 ::barefoot::DirectCounter counter;
1305 setCounterCommon(&counter, counterInstance);
1306 auto tableName = prefix(blockPrefix, *counterInstance.table);
1307 auto counterName = prefix(blockPrefix, counterInstance.name);
1308 auto tableId =
1309 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
1310 counter.set_direct_table_id(tableId);
1311 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_COUNTER(),
1313 counterName, counterInstance.annotations, counter, p4Info);
1314 LOG2("Added Instance - DirectCounter " << counterName);
1315 } else {
1316 ::barefoot::Counter counter;
1317 setCounterCommon(&counter, counterInstance);
1318 counter.set_size(counterInstance.size);
1319 auto counterName = prefix(blockPrefix, counterInstance.name);
1320 addP4InfoExternInstance(symbols, SymbolType::P4RT_COUNTER(),
1322 counterName, counterInstance.annotations, counter, p4Info);
1323 LOG2("Added Instance - Counter " << counterName);
1324 }
1325 }
1326
1328 template <typename Kind>
1329 void setMeterCommon(Kind *meter, const Helpers::Counterlike<ArchMeterExtern> &meterInstance) {
1330 using ::barefoot::MeterSpec;
1332 auto meter_spec = meter->mutable_spec();
1333 if (colorAwareMeters.find(meterInstance.name) != colorAwareMeters.end()) {
1334 meter_spec->set_type(MeterSpec::COLOR_AWARE);
1335 } else {
1336 meter_spec->set_type(MeterSpec::COLOR_UNAWARE);
1337 }
1338 meter_spec->set_unit(CounterlikeTraits<ArchMeterExtern>::mapUnitName(meterInstance.unit));
1339 }
1340
1341 void addMeter(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1342 const Helpers::Counterlike<ArchMeterExtern> &meterInstance,
1343 const cstring blockPrefix = "") {
1344 auto meterName = prefix(blockPrefix, meterInstance.name);
1345 if (meterInstance.table) {
1346 ::barefoot::DirectMeter meter;
1347 setMeterCommon(&meter, meterInstance);
1348 auto tableName = prefix(blockPrefix, *meterInstance.table);
1349 auto tableId =
1350 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
1351 meter.set_direct_table_id(tableId);
1352 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_METER(),
1354 meterName, meterInstance.annotations, meter, p4Info);
1355 LOG2("Added Instance - DirectMeter " << meterName);
1356 } else {
1357 ::barefoot::Meter meter;
1358 setMeterCommon(&meter, meterInstance);
1359 meter.set_size(meterInstance.size);
1360 addP4InfoExternInstance(symbols, SymbolType::P4RT_METER(),
1362 meterName, meterInstance.annotations, meter, p4Info);
1363 LOG2("Added Instance - Meter " << meterName);
1364 }
1365 }
1366
1367 void addActionProfile(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
1368 const ActionProfile &actionProfile, cstring pipeName = "") {
1369 ::barefoot::ActionProfile profile;
1370 profile.set_size(actionProfile.size);
1371 auto actionProfileName = prefix(pipeName, actionProfile.name);
1372 auto tablesIt = actionProfilesRefs.find(actionProfileName);
1373 if (tablesIt != actionProfilesRefs.end()) {
1374 for (const auto &table : tablesIt->second) {
1375 cstring tableName = table;
1376 if (!pipeName.isNullOrEmpty()) tableName = prefix(pipeName, tableName);
1377 profile.add_table_ids(symbols.getId(
1378 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1379 }
1380 }
1381 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_PROFILE(), "ActionProfile"_cs,
1382 actionProfileName, actionProfile.annotations, profile, p4Info);
1383 LOG2("Added Extern Instance - Action Profile " << actionProfileName);
1384 }
1385
1386 virtual void addActionSelector(const P4RuntimeSymbolTableIface &symbols,
1387 p4configv1::P4Info *p4Info, const ActionSelector &actionSelector,
1388 cstring blockPrefix = "") {
1389 ::barefoot::ActionSelector selector;
1390 selector.set_max_group_size(actionSelector.maxGroupSize);
1391 selector.set_num_groups(actionSelector.numGroups);
1392 cstring actionSelectorName = prefix(blockPrefix, actionSelector.name);
1393 if (actionSelector.actionProfileName) {
1394 selector.set_action_profile_id(
1395 symbols.getId(SymbolType::P4RT_ACTION_PROFILE(),
1396 prefix(blockPrefix, *actionSelector.actionProfileName)));
1397 auto tablesIt = actionProfilesRefs.find(actionSelectorName);
1398 if (tablesIt != actionProfilesRefs.end()) {
1399 for (const auto &table : tablesIt->second) {
1400 cstring tableName = prefix(blockPrefix, table);
1401 selector.add_table_ids(symbols.getId(
1402 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1403 }
1404 }
1405 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_SELECTOR(),
1406 "ActionSelector"_cs, actionSelectorName,
1407 actionSelector.annotations, selector, p4Info);
1408 LOG2("Added Extern Instance - Action Selector " << actionSelectorName);
1409 } else {
1410 ::barefoot::ActionProfile profile;
1411 profile.set_size(actionSelector.size);
1412 auto tablesIt = actionProfilesRefs.find(actionSelectorName);
1413 if (tablesIt != actionProfilesRefs.end()) {
1414 for (const auto &table : tablesIt->second) {
1415 cstring tableName = prefix(blockPrefix, table);
1416 profile.add_table_ids(symbols.getId(
1417 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1418 selector.add_table_ids(symbols.getId(
1419 P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName));
1420 }
1421 }
1422
1423 // We use the ActionSelector name for the action profile, and add a "_sel" suffix for
1424 // the action selector.
1425 cstring profileName = actionSelectorName;
1426 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_PROFILE(), "ActionProfile"_cs,
1427 profileName, actionSelector.annotations, profile, p4Info);
1428 selector.set_action_profile_id(
1429 symbols.getId(SymbolType::P4RT_ACTION_PROFILE(), profileName));
1430 cstring selectorName = profileName + "_sel";
1431 addP4InfoExternInstance(symbols, SymbolType::P4RT_ACTION_SELECTOR(),
1432 "ActionSelector"_cs, selectorName, actionSelector.annotations,
1433 selector, p4Info);
1434 LOG2("Added Extern Instance - Action Selector " << selectorName);
1435 }
1436 }
1437
1439 // TODO: for some reason we sometimes get multiple calls on the
1440 // same extern method (but different IR node), and I haven't found out why
1441 // or when this happens.
1442 template <typename Func>
1443 void forAllExternMethodCalls(const IR::IDeclaration *object, Func function) {
1445 evaluatedProgram->getProgram(), [&](const IR::MethodCallExpression *call) {
1446 auto instance = P4::MethodInstance::resolve(call, refMap, typeMap);
1447 if (instance->is<P4::ExternMethod>() && instance->object == object) {
1448 function(instance->to<P4::ExternMethod>());
1449 }
1450 });
1451 }
1452
1455 const IR::Property *getTableImplementationProperty(const IR::P4Table *table) {
1456 return table->properties->getProperty(implementationString);
1457 }
1458
1459 const IR::IAnnotated *getTableImplementationAnnotations(const IR::P4Table *table,
1460 ReferenceMap *refMap) {
1461 auto impl = getTableImplementationProperty(table);
1462 if (impl == nullptr) return nullptr;
1463 if (!impl->value->template is<IR::ExpressionValue>()) return nullptr;
1464 auto expr = impl->value->template to<IR::ExpressionValue>()->expression;
1465 if (expr->template is<IR::ConstructorCallExpression>())
1466 return impl->template to<IR::IAnnotated>();
1467 if (expr->template is<IR::PathExpression>()) {
1468 auto decl = refMap->getDeclaration(expr->template to<IR::PathExpression>()->path, true);
1469 return decl->template to<IR::IAnnotated>();
1470 }
1471 return nullptr;
1472 }
1473
1474 std::optional<cstring> getTableImplementationName(const IR::P4Table *table,
1475 ReferenceMap *refMap) {
1476 auto impl = getTableImplementationProperty(table);
1477 if (impl == nullptr) return std::nullopt;
1478 if (!impl->value->template is<IR::ExpressionValue>()) {
1479 error("Expected %1% property value for table %2% to be an expression: %2%",
1480 implementationString, table->controlPlaneName(), impl);
1481 return std::nullopt;
1482 }
1483 auto expr = impl->value->template to<IR::ExpressionValue>()->expression;
1484 if (expr->template is<IR::ConstructorCallExpression>()) return impl->controlPlaneName();
1485 if (expr->template is<IR::PathExpression>()) {
1486 auto decl = refMap->getDeclaration(expr->template to<IR::PathExpression>()->path, true);
1487 return decl->controlPlaneName();
1488 }
1489 return std::nullopt;
1490 }
1491
1492 ReferenceMap *refMap;
1493 TypeMap *typeMap;
1494 const IR::ToplevelBlock *evaluatedProgram;
1495
1497 std::unordered_map<cstring, std::set<cstring>> actionProfilesRefs;
1499 std::unordered_set<cstring> colorAwareMeters;
1500
1501 cstring implementationString;
1502 cstring defaultPipeName = "pipe"_cs;
1503
1504 static constexpr int64_t defaultMaxGroupSize = 120;
1505
1506 // JSON printing options for serialization
1507 google::protobuf::util::JsonPrintOptions jsonPrintOptions;
1508
1509 public:
1510 google::protobuf::util::JsonPrintOptions getJsonPrintOptions() override {
1511 return jsonPrintOptions;
1512 }
1513};
1514
1519 public:
1520 template <typename Func>
1521 void forAllPipeBlocks(const IR::ToplevelBlock *evaluatedProgram, Func function) {
1522 auto main = evaluatedProgram->getMain();
1523 if (!main) ::fatal_error("Program does not contain a `main` module");
1524 auto cparams = main->getConstructorParameters();
1525 int index = -1;
1526 for (auto param : main->constantValue) {
1527 index++;
1528 if (!param.second) continue;
1529 auto pipe = param.second;
1530 if (!pipe->is<IR::PackageBlock>()) {
1531 error(ErrorType::ERR_INVALID,
1532 "%1% package block. You are compiling for the %2% "
1533 "P4 architecture.\n"
1534 "Please verify that you included the correct architecture file.",
1535 pipe, BackendOptions().arch);
1536 return;
1537 }
1538 auto idxParam = cparams->getParameter(index);
1539 auto pipeName = idxParam->name;
1540 function(pipeName, pipe->to<IR::PackageBlock>());
1541 }
1542 }
1543
1544 template <typename Func>
1545 void forAllPortMetadataBlocks(const IR::ToplevelBlock *evaluatedProgram, Func function) {
1546 auto main = evaluatedProgram->getMain();
1547 if (!main) ::fatal_error("Program does not contain a `main` module");
1548 if (main->type->name == "MultiParserSwitch") {
1549 int numParsersPerPipe = Device::numParsersPerPipe();
1550 auto parsersName = "ig_prsr"_cs;
1551 forAllPipeBlocks(evaluatedProgram, [&](cstring, const IR::PackageBlock *pkg) {
1552 auto parsers = pkg->findParameterValue(parsersName);
1553 BUG_CHECK(parsers, "Expected Block");
1554 if (!parsers->is<IR::PackageBlock>()) {
1555 error(ErrorType::ERR_INVALID,
1556 "%1% package block. "
1557 "You are compiling for the %2% P4 architecture.\n"
1558 "Please verify that you included the correct architecture file.",
1559 parsers, BackendOptions().arch);
1560 return;
1561 }
1562 auto parsersBlock = parsers->to<IR::PackageBlock>();
1563 for (int idx = 0; idx < numParsersPerPipe; idx++) {
1564 auto mpParserName = "prsr" + std::to_string(idx);
1565 auto parser = parsersBlock->findParameterValue(mpParserName);
1566 if (!parser) break; // all parsers optional except for first one
1567 auto parserBlock = parser->to<IR::ParserBlock>();
1568 if (hasUserPortMetadata.count(parserBlock) == 0) { // no extern, add default
1569 auto portMetadataFullName =
1570 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
1571 function(portMetadataFullName, parserBlock);
1572 }
1573 }
1574 });
1575 } else {
1576 auto parserName = "ingress_parser"_cs;
1577 forAllPipeBlocks(evaluatedProgram, [&](cstring, const IR::PackageBlock *pkg) {
1578 auto *block = pkg->findParameterValue(parserName);
1579 if (!block) return;
1580 if (!block->is<IR::ParserBlock>()) return;
1581 auto parserBlock = block->to<IR::ParserBlock>();
1582 if (hasUserPortMetadata.count(parserBlock) == 0) { // no extern, add default
1583 auto portMetadataFullName =
1584 getFullyQualifiedName(parserBlock, PortMetadata::name());
1585 function(portMetadataFullName, parserBlock);
1586 }
1587 });
1588 }
1589 }
1590
1592 const IR::ToplevelBlock *evaluatedProgram)
1593 : BFRuntimeArchHandlerCommon<Arch::TNA>(refMap, typeMap, evaluatedProgram) {
1594 Log::TempIndent indent;
1595 LOG1("BFRuntimeArchHandlerTofino" << indent);
1596 implementationString = "implementation"_cs;
1597
1598 std::set<cstring> pipes;
1599 LOG2("Populating blockNamePrefixMap" << Log::indent);
1600 // Create a map of all blocks to their pipe names. This map will
1601 // be used during collect and post processing to prefix
1602 // table/extern instances wherever applicable with a fully qualified
1603 // name. This distinction is necessary when the driver looks up
1604 // context.json across multiple pipes for the table name
1605 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
1606 Helpers::forAllEvaluatedBlocks(pkg, [&](const IR::Block *block) {
1607 auto decl = pkg->node->to<IR::Declaration_Instance>();
1608 cstring blockNamePrefix = pipeName;
1609 if (decl) blockNamePrefix = decl->controlPlaneName();
1610 blockNamePrefixMap[block] = blockNamePrefix;
1611 LOG4("Updating blockNamePrefixMap with " << &*block << block->toString() << " : "
1612 << blockNamePrefixMap[block]);
1613 pipes.insert(pipeName);
1614 });
1615 });
1616 LOG2_UNINDENT;
1617
1618 // Update multi parser names
1619 static std::vector<cstring> gressNames = {"ig"_cs, "eg"_cs};
1620 int numParsersPerPipe = Device::numParsersPerPipe();
1621
1622 auto main = evaluatedProgram->getMain();
1623 if (!main) ::fatal_error("Program does not contain a `main` module");
1624
1625 isMultiParser = false;
1626 if (main->type->name == "MultiParserSwitch") {
1627 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
1628 BUG_CHECK(
1629 pkg->type->name == "MultiParserPipeline",
1630 "Only MultiParserPipeline pipes can be used with a MultiParserSwitch switch");
1631 for (auto gressName : gressNames) {
1632 auto parsersName = gressName + "_prsr";
1633 auto parsers = pkg->findParameterValue(parsersName);
1634 BUG_CHECK(parsers && parsers->is<IR::PackageBlock>(), "Expected PackageBlock");
1635 auto parsersBlock = parsers->to<IR::PackageBlock>();
1636 auto decl = parsersBlock->node->to<IR::Declaration_Instance>();
1637 if (decl) parsersName = decl->controlPlaneName();
1638 for (int idx = 0; idx < numParsersPerPipe; idx++) {
1639 auto parserName = "prsr" + std::to_string(idx);
1640 auto parser = parsersBlock->findParameterValue(parserName);
1641 if (!parser) break; // all parsers optional except for first one
1642 BUG_CHECK(parser->is<IR::ParserBlock>(), "Expected ParserBlock");
1643 auto parserBlock = parser->to<IR::ParserBlock>();
1644
1645 // Update Parser Block Names
1646 auto parserFullName = pipeName + "." + parsersName + "." + parserName;
1647 blockNamePrefixMap[parserBlock] = parserFullName;
1648 }
1649 isMultiParser = true;
1650 }
1651 });
1652 }
1653 }
1654
1655 cstring getBlockNamePrefix(const IR::Block *blk) override {
1656 if (blockNamePrefixMap.count(blk) > 0) return blockNamePrefixMap[blk];
1657 return ""_cs;
1658 }
1659
1661 const IR::ExternBlock *externBlock) override {
1662 collectExternInstanceCommon(symbols, externBlock);
1663
1664 CHECK_NULL(externBlock);
1665
1666 auto decl = externBlock->node->to<IR::IDeclaration>();
1667 // Skip externs instantiated inside table declarations (as properties);
1668 // that should only apply to action profiles / selectors since direct
1669 // resources cannot be constructed in place for TNA.
1670 if (decl == nullptr) return;
1671
1672 auto symName = getControlPlaneName(externBlock, decl);
1673 if (externBlock->type->name == "Lpf") {
1674 symbols->add(SymbolType::P4RT_LPF(), symName);
1675 } else if (externBlock->type->name == "DirectLpf") {
1676 symbols->add(SymbolType::P4RT_DIRECT_LPF(), symName);
1677 } else if (externBlock->type->name == "Wred") {
1678 symbols->add(SymbolType::P4RT_WRED(), symName);
1679 } else if (externBlock->type->name == "DirectWred") {
1680 symbols->add(SymbolType::P4RT_DIRECT_WRED(), symName);
1681 } else if (externBlock->type->name == "RegisterParam") {
1682 symbols->add(SymbolType::P4RT_REGISTER_PARAM(), symName);
1683 }
1684 }
1685
1687
1688 void collectPortMetadataExternFunction(P4RuntimeSymbolTableIface *symbols,
1689 const P4::ExternFunction *externFunction,
1690 const IR::ParserBlock *parserBlock) {
1691 auto portMetadata = getPortMetadataExtract(externFunction, refMap, typeMap, nullptr);
1692 if (portMetadata) {
1693 if (hasUserPortMetadata.count(parserBlock)) {
1694 error("Cannot have multiple extern calls for %1%",
1695 BFN::ExternPortMetadataUnpackString);
1696 return;
1697 }
1698 hasUserPortMetadata.insert(parserBlock);
1699 auto portMetadataFullName =
1700 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
1701 symbols->add(SymbolType::P4RT_PORT_METADATA(), portMetadataFullName);
1702 }
1703 }
1704
1705 void collectParserSymbols(P4RuntimeSymbolTableIface *symbols,
1706 const IR::ParserBlock *parserBlock) {
1707 CHECK_NULL(parserBlock);
1708 auto parser = parserBlock->container;
1709 CHECK_NULL(parser);
1710
1711 // Collect any extern functions it may invoke.
1712 for (auto state : parser->states) {
1714 state, [&](const IR::MethodCallExpression *call) {
1715 auto instance = P4::MethodInstance::resolve(call, refMap, typeMap);
1716 if (instance->is<P4::ExternFunction>())
1717 collectPortMetadataExternFunction(
1718 symbols, instance->to<P4::ExternFunction>(), parserBlock);
1719 });
1720 }
1721
1722 for (auto s : parser->parserLocals) {
1723 if (auto inst = s->to<IR::P4ValueSet>()) {
1724 auto name = getFullyQualifiedName(parserBlock, inst->controlPlaneName(), true);
1725 symbols->add(SymbolType::P4RT_VALUE_SET(), name);
1726 }
1727 }
1728
1729 // Extract phase0 ingress intrinsic metadata name provided by user
1730 // (usually ig_intr_md). This value is prefixed to the key name in
1731 // phase0 table in bf-rt.json (e.g. ig_intr_md.ingress_port). TNA
1732 // translation will extract this value during midend and set the key
1733 // name in phase0 table in context.json to be consistent.
1734 auto *params = parser->getApplyParameters();
1735 for (auto p : *params) {
1736 if (p->type->toString() == "ingress_intrinsic_metadata_t") {
1737 BUG_CHECK(
1738 ingressIntrinsicMdParamName.count(parserBlock) == 0 ||
1739 strcmp(ingressIntrinsicMdParamName[parserBlock], p->name.toString()) == 0,
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, SnapshotInfo{pipeName, gressName, 0u, ""_cs, {}});
1774 LOG3("Adding SnapshotInfo for " << control->getName() << " " << gressName
1775 << " on pipe " << pipeName);
1776 }
1777 });
1778 }
1779
1786 void collectSnapshot(P4RuntimeSymbolTableIface *symbols, const IR::ControlBlock *controlBlock,
1787 SnapshotFieldIdTable *fieldIds) {
1788 CHECK_NULL(controlBlock);
1789 auto control = controlBlock->container;
1790 CHECK_NULL(control);
1791 Log::TempIndent indent;
1792 auto sinfoIt = snapshotInfo.find(controlBlock);
1793 // if the block is not in snapshotInfo, it means it is not an ingress or
1794 // egress control.
1795 if (sinfoIt == snapshotInfo.end()) return;
1796 auto snapshot_name = getFullyQualifiedName(controlBlock, control->externalName());
1797 LOG1("Collecting Snapshot for control " << snapshot_name << indent);
1798 // Collect unique snapshot names across pipes, this will ensure there is
1799 // only one snapshot field generated even if the field is replicated
1800 // across pipes. While setting a snapshot the user always provides a
1801 // pipe id so we do not need multiple snapshot entries.
1802 if (snapshots.count(snapshot_name)) {
1803 snapshotInfo.erase(sinfoIt);
1804 return;
1805 }
1806 snapshots.insert(snapshot_name);
1807 sinfoIt->second.name = snapshot_name;
1808 auto snapshotFields = &sinfoIt->second.fields;
1809 auto params = control->getApplyParameters();
1810 for (size_t idx = 0; idx < params->size(); idx++) {
1811 auto p = params->getParameter(idx);
1812 // include validity fields (POV bits) only for user-defined header
1813 // fields (the "hdr" parameter)
1814 auto includeValid = (idx == sinfoIt->second.userHdrParamIdx);
1815 SnapshotFieldFinder::find(typeMap, p->type, p->name, includeValid, snapshotFields,
1816 fieldIds);
1817 }
1818 LOG3("Adding snaphot to bfrt info for control: " << snapshot_name);
1819 symbols->add(SymbolType::P4RT_SNAPSHOT(), snapshot_name);
1820 }
1821
1828 static std::vector<cstring> gressNames = {"ig"_cs, "eg"_cs};
1829 int numParsersPerPipe = Device::numParsersPerPipe();
1830
1831 auto main = evaluatedProgram->getMain();
1832 if (!main) ::fatal_error("Program does not contain a `main` module");
1833 if (main->type->name != "MultiParserSwitch") return;
1834
1835 forAllPipeBlocks(evaluatedProgram, [&](cstring pipeName, const IR::PackageBlock *pkg) {
1836 BUG_CHECK(pkg->type->name == "MultiParserPipeline",
1837 "Only MultiParserPipeline pipes can be used with a MultiParserSwitch switch");
1838 for (auto gressName : gressNames) {
1839 ::barefoot::ParserChoices parserChoices;
1840
1841 if (auto decl = pkg->node->to<IR::Declaration_Instance>()) pipeName = decl->Name();
1842
1843 parserChoices.set_pipe(pipeName);
1844 if (gressName == "ig")
1845 parserChoices.set_direction(::barefoot::DIRECTION_INGRESS);
1846 else
1847 parserChoices.set_direction(::barefoot::DIRECTION_EGRESS);
1848
1849 auto parsersName = gressName + "_prsr";
1850 auto parsers = pkg->findParameterValue(parsersName);
1851 BUG_CHECK(parsers && parsers->is<IR::PackageBlock>(), "Expected PackageBlock");
1852 auto parsersBlock = parsers->to<IR::PackageBlock>();
1853 auto decl = parsersBlock->node->to<IR::Declaration_Instance>();
1854 if (decl) parsersName = decl->controlPlaneName();
1855 for (int idx = 0; idx < numParsersPerPipe; idx++) {
1856 auto parserName = "prsr" + std::to_string(idx);
1857 auto parser = parsersBlock->findParameterValue(parserName);
1858 if (!parser) break; // all parsers optional except for first one
1859 BUG_CHECK(parser->is<IR::ParserBlock>(), "Expected ParserBlock");
1860 auto parserBlock = parser->to<IR::ParserBlock>();
1861 auto decl = parserBlock->node->to<IR::Declaration_Instance>();
1862 auto userName = (decl == nullptr) ? "" : decl->controlPlaneName();
1863
1864 auto choice = parserChoices.add_choices();
1865 auto parserFullName = prefix(parsersName, parserName);
1866 parserFullName = prefix(pipeName, parserFullName);
1867 choice->set_arch_name(parserFullName);
1868 choice->set_type_name(parserBlock->getName().name);
1869 choice->set_user_name(userName);
1870 }
1871 auto parsersFullName = prefix(pipeName, parsersName);
1872 symbols->add(SymbolType::P4RT_PARSER_CHOICES(), parsersFullName);
1873 parserConfiguration.emplace(parsersFullName, parserChoices);
1874 }
1875 });
1876 }
1877
1878 void collectExtra(P4RuntimeSymbolTableIface *symbols) override {
1879 Log::TempIndent indent;
1880 LOG1("BFRuntimeArchHandlerTofino::collectExtra" << indent);
1881 LOG2("Collecting Parser Symbols" << Log::indent);
1882 // Collect value sets. This step is required because value set support
1883 // in "standard" P4Info is currently insufficient.
1884 // Also retrieve user-provided name for ig_intr_md parameter in ingress
1885 // parser to use as key name for phase0 table.
1886 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1887 if (!block->is<IR::ParserBlock>()) return;
1888 collectParserSymbols(symbols, block->to<IR::ParserBlock>());
1889 });
1890 LOG2_UNINDENT;
1891
1892 LOG2("Collecting Snapshot Fields" << Log::indent);
1893 // Collect snapshot fields for each control by populating the
1894 // snapshotInfo map.
1895 getSnapshotControls();
1896 SnapshotFieldIdTable snapshotFieldIds;
1897 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1898 if (!block->is<IR::ControlBlock>()) return;
1899 collectSnapshot(symbols, block->to<IR::ControlBlock>(), &snapshotFieldIds);
1900 });
1901 LOG2_UNINDENT;
1902
1903 LOG2("Collecting Parser Choices" << Log::indent);
1904 collectParserChoices(symbols);
1905 LOG2_UNINDENT;
1906
1907 LOG2("Collecting PortMetadata" << Log::indent);
1908 // Check if each parser block in program has a port metadata extern
1909 // defined, if not we add a default instances to symbol table
1910 forAllPortMetadataBlocks(
1911 evaluatedProgram, [&](cstring portMetadataFullName, const IR::ParserBlock *) {
1912 symbols->add(SymbolType::P4RT_PORT_METADATA(), portMetadataFullName);
1913 LOG3("Adding PortMetadata symbol: " << portMetadataFullName);
1914 });
1915 LOG2_UNINDENT;
1916 }
1917
1918 void postCollect(const P4RuntimeSymbolTableIface &symbols) override {
1919 Log::TempIndent indent;
1920 LOG1("BFRuntimeArchHandlerTofino::postCollect" << indent);
1921 (void)symbols;
1922 // analyze action profiles / selectors and build a mapping from action
1923 // profile / selector name to the set of tables referencing them
1924 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1925 if (!block->is<IR::TableBlock>()) return;
1926 auto table = block->to<IR::TableBlock>()->container;
1927 auto implementation = getTableImplementationName(table, refMap);
1928 if (implementation) {
1929 auto pipeName = blockNamePrefixMap[block];
1930 auto implName = prefix(pipeName, *implementation);
1931 actionProfilesRefs[implName].insert(table->controlPlaneName());
1932 LOG5("Adding action profile : " << implName << " for table "
1933 << table->controlPlaneName());
1934 }
1935 });
1936
1937 // analyze action profile used by action selector and adds the set of
1938 // table referenced by action selector to the action profile.
1939 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1940 if (!block->is<IR::ExternBlock>()) return;
1941 auto selectorExternBlock = block->to<IR::ExternBlock>();
1942 if (selectorExternBlock->type->name != "ActionSelector") return;
1943 auto selectorDecl = selectorExternBlock->node->to<IR::Declaration_Instance>();
1944 CHECK_NULL(selectorDecl);
1945 auto profile = selectorExternBlock->getParameterValue("action_profile"_cs);
1946 if (profile) {
1947 auto profileExternBlock = profile->to<IR::ExternBlock>();
1948 auto profileDecl = profileExternBlock->node->to<IR::Declaration_Instance>();
1949 CHECK_NULL(profileDecl);
1950 auto pipeName = blockNamePrefixMap[selectorExternBlock];
1951 auto profileDeclName = prefix(pipeName, profileDecl->controlPlaneName());
1952 auto selectorDeclName = prefix(pipeName, selectorDecl->controlPlaneName());
1953 actionProfilesRefs[profileDeclName].insert(
1954 actionProfilesRefs[selectorDeclName].begin(),
1955 actionProfilesRefs[selectorDeclName].end());
1956 LOG5("Adding action profile : " << profileDeclName << " for tables "
1957 << actionProfilesRefs[profileDeclName]);
1958 }
1959 });
1960
1961 // Creates a set of color-aware meters by inspecting every call to the
1962 // execute method on each meter instance: if at least one method call
1963 // includes a second argument (pre-color), then the meter is
1964 // color-aware.
1965 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
1966 if (!block->is<IR::ExternBlock>()) return;
1967 auto externBlock = block->to<IR::ExternBlock>();
1968 if (externBlock->type->name != "Meter" && externBlock->type->name != "DirectMeter")
1969 return;
1970 auto decl = externBlock->node->to<IR::Declaration_Instance>();
1971 // Should not happen for TNA: direct meters cannot be constructed
1972 // in-place.
1973 CHECK_NULL(decl);
1974 forAllExternMethodCalls(decl, [&](const P4::ExternMethod *method) {
1975 auto call = method->expr;
1976 if (call->arguments->size() == 2) {
1977 LOG3("Meter " << decl->controlPlaneName() << " is color-aware "
1978 << "because of 2-argument call to execute()");
1979 colorAwareMeters.insert(decl->controlPlaneName());
1980 }
1981 });
1982 });
1983
1984 class RegisterParamFinder : public Inspector {
1986
1987 bool checkExtern(const IR::Declaration_Instance *decl, cstring name) {
1988 if (auto *specialized = decl->type->to<IR::Type_Specialized>())
1989 if (auto *name_type = specialized->baseType->to<IR::Type_Name>())
1990 return name_type->path->name == name;
1991 return false;
1992 }
1993
1994 public:
1995 RegisterParamFinder(BFRuntimeArchHandlerTofino &self) : self(self) {}
1996 bool preorder(const IR::MethodCallExpression *mce) override {
1997 auto method = P4::MethodInstance::resolve(mce, self.refMap, self.typeMap);
1998 CHECK_NULL(method);
1999 if (method->object == nullptr) // extern functions
2000 return true;
2001 auto *reg_param = method->object->to<IR::Declaration_Instance>();
2002 if (reg_param == nullptr) // packet_in packet
2003 return true;
2004 if (!checkExtern(reg_param, "RegisterParam"_cs)) return true;
2005 // Find the declaration of RegisterAction
2006 auto *reg_action = findContext<IR::Declaration_Instance>();
2007 if (reg_action == nullptr) return true;
2008 if (!checkExtern(reg_action, "DirectRegisterAction"_cs) &&
2009 !checkExtern(reg_action, "RegisterAction"_cs))
2010 return true;
2011 BUG_CHECK(reg_action->arguments->size() > 0, "%1%: Missing argument", reg_action);
2012 auto *rap = reg_action->arguments->at(0)->expression->to<IR::PathExpression>();
2013 if (rap == nullptr) return true;
2014 // Find the declaration of Register or DirectRegister
2015 auto *rap_decl = getDeclInst(self.refMap, rap);
2016 if (rap_decl == nullptr) return true;
2017 if (checkExtern(rap_decl, "Register"_cs))
2018 self.registerParam2register[reg_param->controlPlaneName()] =
2019 rap_decl->controlPlaneName();
2020 if (checkExtern(rap_decl, "DirectRegister"_cs))
2021 self.registerParam2table[reg_param->controlPlaneName()] =
2022 rap_decl->controlPlaneName();
2023 return true;
2024 }
2025 void postorder(const IR::P4Table *table) override {
2026 // Find the M/A table with attached direct register that uses a register parameter
2027 auto *registers = table->properties->getProperty("registers"_cs);
2028 if (registers == nullptr) return;
2029 auto *registers_value = registers->value->to<IR::ExpressionValue>();
2030 CHECK_NULL(registers_value);
2031 auto *registers_path = registers_value->expression->to<IR::PathExpression>();
2032 CHECK_NULL(registers_path);
2033 auto *registers_decl = getDeclInst(self.refMap, registers_path);
2034 CHECK_NULL(registers_decl);
2035 // Replace a direct register with a M/A table it is attached to
2036 for (auto r : self.registerParam2table)
2037 if (r.second == registers_decl->controlPlaneName())
2038 self.registerParam2table[r.first] = table->controlPlaneName();
2039 }
2040 };
2041
2042 evaluatedProgram->getProgram()->apply(RegisterParamFinder(*this));
2043 }
2044
2045 void addTableProperties(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
2046 p4configv1::Table *table, const IR::TableBlock *tableBlock) override {
2047 CHECK_NULL(tableBlock);
2048 auto tableDeclaration = tableBlock->container;
2049 auto blockPrefix = blockNamePrefixMap[tableBlock];
2050
2051 addTablePropertiesCommon(symbols, p4info, table, tableBlock, blockPrefix);
2052
2053 auto directLpf = getDirectLpf(tableDeclaration, refMap, typeMap);
2054 if (directLpf) {
2055 auto id =
2056 symbols.getId(SymbolType::P4RT_DIRECT_LPF(), prefix(blockPrefix, directLpf->name));
2057 table->add_direct_resource_ids(id);
2058 addLpf(symbols, p4info, *directLpf, blockPrefix);
2059 }
2060
2061 auto directWred = getDirectWred(tableDeclaration, refMap, typeMap);
2062 if (directWred) {
2063 auto id = symbols.getId(SymbolType::P4RT_DIRECT_WRED(),
2064 prefix(blockPrefix, directWred->name));
2065 table->add_direct_resource_ids(id);
2066 addWred(symbols, p4info, *directWred, blockPrefix);
2067 }
2068 }
2069
2073 template <typename T>
2074 static std::optional<T> getDirectFilter(const IR::P4Table *table, ReferenceMap *refMap,
2075 TypeMap *typeMap, cstring filterType) {
2076 auto directFilterInstance =
2077 Helpers::getExternInstanceFromProperty(table, "filters"_cs, refMap, typeMap);
2078 if (!directFilterInstance) return std::nullopt;
2079 CHECK_NULL(directFilterInstance->type);
2080 if (directFilterInstance->type->name != filterType) return std::nullopt;
2081 return T::fromDirect(*directFilterInstance, table);
2082 }
2083
2086 static std::optional<Lpf> getDirectLpf(const IR::P4Table *table, ReferenceMap *refMap,
2087 TypeMap *typeMap) {
2088 return getDirectFilter<Lpf>(table, refMap, typeMap, "DirectLpf"_cs);
2089 }
2090
2093 static std::optional<Wred> getDirectWred(const IR::P4Table *table, ReferenceMap *refMap,
2094 TypeMap *typeMap) {
2095 return getDirectFilter<Wred>(table, refMap, typeMap, "DirectWred"_cs);
2096 }
2097
2098 void addExternInstance(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
2099 const IR::ExternBlock *externBlock) override {
2100 auto decl = externBlock->node->to<IR::Declaration_Instance>();
2101 // Skip externs instantiated inside table declarations (constructed in
2102 // place as properties).
2103 if (decl == nullptr) return;
2104
2107
2108 auto pipeName = blockNamePrefixMap[externBlock];
2109
2110 addExternInstanceCommon(symbols, p4info, externBlock, pipeName);
2111
2112 auto p4RtTypeInfo = p4info->mutable_type_info();
2113 // Direct resources are handled by addTableProperties.
2114 if (externBlock->type->name == "Lpf") {
2115 auto lpf = Lpf::from(externBlock);
2116 if (lpf) addLpf(symbols, p4info, *lpf, pipeName);
2117 } else if (externBlock->type->name == "Wred") {
2118 auto wred = Wred::from(externBlock);
2119 if (wred) addWred(symbols, p4info, *wred, pipeName);
2120 } else if (externBlock->type->name == "RegisterParam") {
2121 auto register_param_ = RegisterParam::from(externBlock, refMap, typeMap, p4RtTypeInfo);
2122 if (register_param_) addRegisterParam(symbols, p4info, *register_param_, pipeName);
2123 }
2124 }
2125
2126 void addExternFunction(const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
2127 const P4::ExternFunction *) override {}
2128
2129 void addPortMetadataExternFunction(const P4RuntimeSymbolTableIface &symbols,
2130 p4configv1::P4Info *p4info,
2131 const P4::ExternFunction *externFunction,
2132 const IR::ParserBlock *parserBlock) {
2133 auto p4RtTypeInfo = p4info->mutable_type_info();
2134 auto portMetadata = getPortMetadataExtract(externFunction, refMap, typeMap, p4RtTypeInfo);
2135 if (portMetadata) {
2136 if (blockNamePrefixMap.count(parserBlock)) {
2137 auto portMetadataFullName =
2138 getFullyQualifiedName(parserBlock, PortMetadata::name(), isMultiParser);
2139 addPortMetadata(symbols, p4info, *portMetadata, portMetadataFullName, parserBlock);
2140 }
2141 }
2142 }
2143
2144 void analyzeParser(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info,
2145 const IR::ParserBlock *parserBlock) {
2146 CHECK_NULL(parserBlock);
2147 auto parser = parserBlock->container;
2148 CHECK_NULL(parser);
2149
2150 for (auto s : parser->parserLocals) {
2151 if (auto inst = s->to<IR::P4ValueSet>()) {
2152 auto namePrefix =
2153 getFullyQualifiedName(parserBlock, inst->controlPlaneName(), true);
2154 auto valueSet =
2155 ValueSet::from(namePrefix, inst, refMap, typeMap, p4info->mutable_type_info());
2156 if (valueSet) addValueSet(symbols, p4info, *valueSet);
2157 }
2158 }
2159
2160 // Add any extern functions within parser states.
2161 for (auto state : parser->states) {
2163 state, [&](const IR::MethodCallExpression *call) {
2164 auto instance = P4::MethodInstance::resolve(call, refMap, typeMap);
2165 if (instance->is<P4::ExternFunction>())
2166 addPortMetadataExternFunction(
2167 symbols, p4info, instance->to<P4::ExternFunction>(), parserBlock);
2168 });
2169 }
2170 }
2171
2173 ::p4::config::v1::P4Info *p4info) override {
2174 // Generates Tofino-specific ValueSet P4Info messages. This step is
2175 // required because value set support in "standard" P4Info is currently
2176 // insufficient: the standard ValueSet message restricts the element
2177 // type to a simple binary string (P4Runtime v1.0 limitation).
2178 //
2179 // ValueSets created by open-source p4RuntimeSerializer.cpp need
2180 // to be deleted because it creates duplicates when dealing with multipipe programs.
2181 p4info->clear_value_sets();
2182
2183 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
2184 if (!block->is<IR::ParserBlock>()) return;
2185 analyzeParser(symbols, p4info, block->to<IR::ParserBlock>());
2186 });
2187
2188 // Check if each parser block in program has a port metadata extern
2189 // defined, if not we add a default instances
2190 forAllPortMetadataBlocks(evaluatedProgram, [&](cstring portMetadataFullName,
2191 const IR::ParserBlock *parserBlock) {
2192 addPortMetadataDefault(symbols, p4info, portMetadataFullName, parserBlock);
2193 });
2194
2195 for (const auto &snapshot : snapshotInfo) addSnapshot(symbols, p4info, snapshot.second);
2196
2197 for (const auto &parser : parserConfiguration)
2198 addParserChoices(symbols, p4info, parser.first, parser.second);
2199 }
2200
2203 static std::optional<PortMetadata> getPortMetadataExtract(
2204 const P4::ExternFunction *function, ReferenceMap *refMap, TypeMap *typeMap,
2205 p4configv1::P4TypeInfo *p4RtTypeInfo) {
2206 if (function->method->name != BFN::ExternPortMetadataUnpackString) return std::nullopt;
2207
2208 if (auto *call = function->expr->to<IR::MethodCallExpression>()) {
2209 auto *typeArg = call->typeArguments->at(0);
2210 auto typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(refMap, typeMap,
2211 typeArg, p4RtTypeInfo);
2212 return PortMetadata{typeSpec};
2213 }
2214 return std::nullopt;
2215 }
2216
2217 void addPortMetadata(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2218 const PortMetadata &portMetadataExtract, const cstring &name,
2219 const IR::ParserBlock *parserBlock) {
2220 ::barefoot::PortMetadata portMetadata;
2221 portMetadata.mutable_type_spec()->CopyFrom(*portMetadataExtract.typeSpec);
2222 CHECK_NULL(parserBlock);
2223 auto parser = parserBlock->container;
2224 CHECK_NULL(parser);
2225 BUG_CHECK(ingressIntrinsicMdParamName.count(parserBlock),
2226 "%1%: Name of the intrinsic metadata not found for this parser block",
2227 parser->getName());
2228 portMetadata.set_key_name(ingressIntrinsicMdParamName[parserBlock]);
2229 addP4InfoExternInstance(symbols, SymbolType::P4RT_PORT_METADATA(), "PortMetadata"_cs, name,
2230 nullptr, portMetadata, p4Info);
2231 }
2232
2233 void addPortMetadataDefault(const P4RuntimeSymbolTableIface &symbols,
2234 p4configv1::P4Info *p4Info, const cstring &name,
2235 const IR::ParserBlock *parserBlock) {
2236 ::barefoot::PortMetadata portMetadata;
2237 CHECK_NULL(parserBlock);
2238 auto parser = parserBlock->container;
2239 CHECK_NULL(parser);
2240
2241 if (ingressIntrinsicMdParamName.count(parserBlock)) {
2242 portMetadata.set_key_name(ingressIntrinsicMdParamName[parserBlock]);
2243 } else {
2244 // Using the same default name used elsewhere in our toolchain for the "context.json".
2245 auto const DP0TKN = BFN::getDefaultPhase0TableKeyName();
2246 portMetadata.set_key_name(DP0TKN);
2247 }
2248
2249 addP4InfoExternInstance(symbols, SymbolType::P4RT_PORT_METADATA(), "PortMetadata"_cs, name,
2250 nullptr, portMetadata, p4Info);
2251 }
2252
2253 void addSnapshot(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2254 const SnapshotInfo &snapshotInstance) {
2255 ::barefoot::Snapshot snapshot;
2256 snapshot.set_pipe(snapshotInstance.pipe);
2257 if (snapshotInstance.gress == "ingress")
2258 snapshot.set_direction(::barefoot::DIRECTION_INGRESS);
2259 else if (snapshotInstance.gress == "egress")
2260 snapshot.set_direction(::barefoot::DIRECTION_EGRESS);
2261 else
2262 BUG("Invalid gress '%1%'", snapshotInstance.gress);
2263 for (const auto &f : snapshotInstance.fields) {
2264 auto newF = snapshot.add_fields();
2265 newF->set_id(f.id);
2266 newF->set_name(f.name);
2267 newF->set_bitwidth(f.bitwidth);
2268 }
2269 addP4InfoExternInstance(symbols, SymbolType::P4RT_SNAPSHOT(), "Snapshot"_cs,
2270 snapshotInstance.name, nullptr, snapshot, p4Info);
2271 }
2272
2273 void addParserChoices(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2274 cstring name, const ::barefoot::ParserChoices &parserChoices) {
2275 addP4InfoExternInstance(symbols, SymbolType::P4RT_PARSER_CHOICES(), "ParserChoices"_cs,
2276 name, nullptr, parserChoices, p4Info);
2277 }
2278
2279 void addLpf(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2280 const Lpf &lpfInstance, const cstring pipeName) {
2281 auto lpfName = prefix(pipeName, lpfInstance.name);
2282 if (lpfInstance.table) {
2283 ::barefoot::DirectLpf lpf;
2284 auto tableName = prefix(pipeName, *lpfInstance.table);
2285 auto tableId =
2286 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
2287 lpf.set_direct_table_id(tableId);
2288 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_LPF(), "DirectLpf"_cs, lpfName,
2289 lpfInstance.annotations, lpf, p4Info);
2290 LOG2("Added Instance - Direct LPF " << lpfName);
2291 } else {
2292 ::barefoot::Lpf lpf;
2293 lpf.set_size(lpfInstance.size);
2294 addP4InfoExternInstance(symbols, SymbolType::P4RT_LPF(), "Lpf"_cs, lpfName,
2295 lpfInstance.annotations, lpf, p4Info);
2296 LOG2("Added Instance - LPF " << lpfName);
2297 }
2298 }
2299
2301 template <typename Kind>
2302 void setWredCommon(Kind *wred, const Wred &wredInstance) {
2303 using ::barefoot::WredSpec;
2304 auto wred_spec = wred->mutable_spec();
2305 wred_spec->set_drop_value(wredInstance.dropValue);
2306 wred_spec->set_no_drop_value(wredInstance.noDropValue);
2307 }
2308
2309 void addWred(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2310 const Wred &wredInstance, const cstring pipeName) {
2311 auto wredName = prefix(pipeName, wredInstance.name);
2312 if (wredInstance.table) {
2313 ::barefoot::DirectWred wred;
2314 setWredCommon(&wred, wredInstance);
2315 auto tableName = prefix(pipeName, *wredInstance.table);
2316 auto tableId =
2317 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(), tableName);
2318 wred.set_direct_table_id(tableId);
2319 addP4InfoExternInstance(symbols, SymbolType::P4RT_DIRECT_WRED(), "DirectWred"_cs,
2320 wredName, wredInstance.annotations, wred, p4Info);
2321 LOG2("Added Instance - Direct WRED " << wredName);
2322 } else {
2323 ::barefoot::Wred wred;
2324 setWredCommon(&wred, wredInstance);
2325 wred.set_size(wredInstance.size);
2326 addP4InfoExternInstance(symbols, SymbolType::P4RT_WRED(), "Wred"_cs, wredName,
2327 wredInstance.annotations, wred, p4Info);
2328 LOG2("Added Instance - WRED " << wredName);
2329 }
2330 }
2331
2332 // For RegisterParams, the table name should have the associated pipe prefix but
2333 // the data field names should not since they have local scope.
2334 void addRegisterParam(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info,
2335 const RegisterParam &registerParamInstance, cstring pipeName = ""_cs) {
2336 p4rt_id_t tableId = 0;
2337 if (registerParam2register.count(registerParamInstance.name) > 0)
2338 tableId =
2339 symbols.getId(SymbolType::P4RT_REGISTER(),
2340 prefix(pipeName, registerParam2register[registerParamInstance.name]));
2341 else if (registerParam2table.count(registerParamInstance.name) > 0)
2342 tableId =
2343 symbols.getId(P4::ControlPlaneAPI::P4RuntimeSymbolType::P4RT_TABLE(),
2344 prefix(pipeName, registerParam2table[registerParamInstance.name]));
2345 // If a register parameter is not used, it will show up in neither of the maps.
2346 ::barefoot::RegisterParam register_param_;
2347 register_param_.mutable_type_spec()->CopyFrom(*registerParamInstance.typeSpec);
2348 register_param_.set_table_id(tableId);
2349 register_param_.set_initial_value(registerParamInstance.initial_value);
2350 register_param_.set_data_field_name(registerParamInstance.name);
2351 auto registerParamName = prefix(pipeName, registerParamInstance.name);
2352 addP4InfoExternInstance(symbols, SymbolType::P4RT_REGISTER_PARAM(), "RegisterParam"_cs,
2353 registerParamName, registerParamInstance.annotations,
2354 register_param_, p4Info);
2355 LOG2("Added Instance - RegisterParam " << registerParamName);
2356 }
2357
2358 private:
2360 std::unordered_set<cstring> snapshots;
2362 std::unordered_set<const IR::Block *> hasUserPortMetadata;
2363
2366 std::unordered_map<const IR::ParserBlock *, cstring> ingressIntrinsicMdParamName;
2367
2368 using SnapshotInfoMap = std::map<const IR::ControlBlock *, SnapshotInfo>;
2369 SnapshotInfoMap snapshotInfo;
2370
2371 std::unordered_map<const IR::Block *, cstring> blockNamePrefixMap;
2372
2373 std::map<cstring, ::barefoot::ParserChoices> parserConfiguration;
2374
2375 bool isMultiParser;
2376
2378 std::unordered_map<cstring, cstring> registerParam2register;
2380 std::unordered_map<cstring, cstring> registerParam2table;
2381};
2382
2387 public:
2389 const IR::ToplevelBlock *evaluatedProgram)
2390 : BFRuntimeArchHandlerCommon<Arch::PSA>(refMap, typeMap, evaluatedProgram) {
2391 implementationString = "psa_implementation"_cs;
2392 }
2393
2395 (void)symbols;
2396 // analyze action profiles / selectors and build a mapping from action
2397 // profile / selector name to the set of tables referencing them
2398 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
2399 if (!block->is<IR::TableBlock>()) return;
2400 auto table = block->to<IR::TableBlock>()->container;
2401 auto implementation = getTableImplementationName(table, refMap);
2402 if (implementation)
2403 actionProfilesRefs[*implementation].insert(table->controlPlaneName());
2404 });
2405
2406 // Creates a set of color-aware meters by inspecting every call to the
2407 // execute method on each meter instance: if at least one method call
2408 // includes a second argument (pre-color), then the meter is
2409 // color-aware.
2410 Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block *block) {
2411 if (!block->is<IR::ExternBlock>()) return;
2412 auto externBlock = block->to<IR::ExternBlock>();
2413 if (externBlock->type->name != "Meter" && externBlock->type->name != "DirectMeter")
2414 return;
2415 auto decl = externBlock->node->to<IR::Declaration_Instance>();
2416 // Should not happen for TNA: direct meters cannot be constructed
2417 // in-place.
2418 CHECK_NULL(decl);
2419 forAllExternMethodCalls(decl, [&](const P4::ExternMethod *method) {
2420 auto call = method->expr;
2421 if (call->arguments->size() == 2) {
2422 LOG3("Meter " << decl->controlPlaneName() << " is color-aware "
2423 << "because of 2-argument call to execute()");
2424 colorAwareMeters.insert(decl->controlPlaneName());
2425 }
2426 });
2427 });
2428 }
2429
2430 void addTableProperties(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
2431 p4configv1::Table *table, const IR::TableBlock *tableBlock) {
2432 CHECK_NULL(tableBlock);
2433 addTablePropertiesCommon(symbols, p4info, table, tableBlock, defaultPipeName);
2434 }
2435
2437 const IR::ExternBlock *externBlock) override {
2438 collectExternInstanceCommon(symbols, externBlock);
2439 }
2440
2442
2443 void addExternInstance(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4info,
2444 const IR::ExternBlock *externBlock) {
2445 addExternInstanceCommon(symbols, p4info, externBlock, defaultPipeName);
2446 }
2447
2448 void addExternFunction(const P4RuntimeSymbolTableIface &, p4configv1::P4Info *,
2449 const P4::ExternFunction *) {}
2450};
2451
2455 ReferenceMap *refMap, TypeMap *typeMap,
2456 const IR::ToplevelBlock *evaluatedProgram) const override {
2457 return new BFRuntimeArchHandlerTofino(refMap, typeMap, evaluatedProgram);
2458 }
2459};
2460
2464 ReferenceMap *refMap, TypeMap *typeMap,
2465 const IR::ToplevelBlock *evaluatedProgram) const override {
2466 return new BFRuntimeArchHandlerPSA(refMap, typeMap, evaluatedProgram);
2467 }
2468};
2469
2470} // namespace BFN
2471#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:1140
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:1443
static bool getSupportsTimeout(const IR::P4Table *table)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:919
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:1497
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:1510
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:1126
const IR::Property * getTableImplementationProperty(const IR::P4Table *table)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1455
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:1034
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:1499
bool filterAnnotations(cstring) override
called when processing annotations via setPreamble
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1037
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:1150
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:941
void postAdd(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1022
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:1329
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:1294
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2386
void collectExternFunction(P4RuntimeSymbolTableIface *, const P4::ExternFunction *)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2441
void postCollect(const P4RuntimeSymbolTableIface &symbols)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2394
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:2436
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1518
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:2203
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:2172
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:1660
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:2074
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:2302
void collectExternFunction(P4RuntimeSymbolTableIface *, const P4::ExternFunction *) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1686
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:1827
void collectSnapshot(P4RuntimeSymbolTableIface *symbols, const IR::ControlBlock *controlBlock, SnapshotFieldIdTable *fieldIds)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1786
void postCollect(const P4RuntimeSymbolTableIface &symbols) override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:1918
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:1878
static std::optional< Wred > getDirectWred(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2093
static std::optional< Lpf > getDirectLpf(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2086
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:387
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:307
std::optional< Counterlike< Kind > > getDirectCounterlike(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition p4RuntimeArchHandler.h:490
A traits class describing the properties of "counterlike" things.
Definition p4RuntimeArchHandler.h:368
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:2462
P4::ControlPlaneAPI::P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2463
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:2453
P4::ControlPlaneAPI::P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const override
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:2454
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:376
const std::optional< cstring > table
If not none, the instance is a direct resource associated with @table.
Definition p4RuntimeArchHandler.h:386
const cstring name
The name of the instance.
Definition p4RuntimeArchHandler.h:378
const IR::IAnnotated * annotations
If non-null, the instance's annotations.
Definition p4RuntimeArchHandler.h:380
const cstring unit
The units parameter to the instance; valid values vary depending on @Kind.
Definition p4RuntimeArchHandler.h:382
const int64_t size
The size parameter to the instance.
Definition p4RuntimeArchHandler.h:384
Definition p4RuntimeArchHandler.h:204
Definition externInstance.h:51
T * to() noexcept
Definition rtti.h:226
bool is() const noexcept
Definition rtti.h:216