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