P4C
The P4 Compiler
Loading...
Searching...
No Matches
p4RuntimeArchHandler.h
1/*
2 * SPDX-FileCopyrightText: 2018 Barefoot Networks, Inc.
3 * Copyright 2018-present Barefoot Networks, Inc.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8#ifndef CONTROL_PLANE_P4RUNTIMEARCHHANDLER_H_
9#define CONTROL_PLANE_P4RUNTIMEARCHHANDLER_H_
10
11#pragma GCC diagnostic push
12#pragma GCC diagnostic ignored "-Wunused-parameter"
13#pragma GCC diagnostic ignored "-Wpedantic"
14#include <google/protobuf/util/json_util.h>
15#pragma GCC diagnostic pop
16
17#include <optional>
18#include <set>
19
20#pragma GCC diagnostic push
21#pragma GCC diagnostic ignored "-Wunused-parameter"
22#pragma GCC diagnostic ignored "-Wpedantic"
23#include "p4/config/v1/p4info.pb.h"
24#include "p4/v1/p4runtime.pb.h"
25#pragma GCC diagnostic pop
26
27#include "frontends/common/resolveReferences/referenceMap.h"
28#include "frontends/p4/externInstance.h"
29#include "frontends/p4/methodInstance.h"
30#include "frontends/p4/typeMap.h"
31#include "ir/ir.h"
32#include "lib/cstring.h"
33#include "lib/ordered_set.h"
34#include "typeSpecConverter.h"
35
36namespace P4 {
37
38using namespace literals;
39
43namespace ControlPlaneAPI {
44
45using p4rt_id_t = uint32_t;
46
54class P4RuntimeSymbolType {
55 public:
56 virtual ~P4RuntimeSymbolType() {}
57
61 explicit operator p4rt_id_t() const { return id; }
62
63 static P4RuntimeSymbolType P4RT_ACTION() {
64 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::ACTION);
65 }
66 static P4RuntimeSymbolType P4RT_TABLE() {
67 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::TABLE);
68 }
69 static P4RuntimeSymbolType P4RT_VALUE_SET() {
70 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::VALUE_SET);
71 }
72 static P4RuntimeSymbolType P4RT_CONTROLLER_HEADER() {
73 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::CONTROLLER_HEADER);
74 }
75
76 static P4RuntimeSymbolType P4RT_OTHER_EXTERNS_START() {
77 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::OTHER_EXTERNS_START);
78 }
79
80 bool operator==(const P4RuntimeSymbolType &other) const { return id == other.id; }
81
82 bool operator!=(const P4RuntimeSymbolType &other) const { return !(*this == other); }
83
84 bool operator<(const P4RuntimeSymbolType &other) const { return id < other.id; }
85
86 protected:
87 static P4RuntimeSymbolType make(p4rt_id_t id) { return P4RuntimeSymbolType(id); }
88
89 private:
90 // even if the constructor is protected, the static functions in the derived
91 // classes cannot access it, which is why we use the make factory function
92 explicit constexpr P4RuntimeSymbolType(p4rt_id_t id) noexcept : id(id) {}
93
95 p4rt_id_t id;
96};
97
101 public:
102 virtual ~P4RuntimeSymbolTableIface() {}
104 virtual void add(P4RuntimeSymbolType type, const IR::IDeclaration *declaration) = 0;
106 virtual void add(P4RuntimeSymbolType type, cstring name,
107 std::optional<p4rt_id_t> id = std::nullopt) = 0;
110 virtual p4rt_id_t getId(P4RuntimeSymbolType type,
111 const IR::IDeclaration *declaration) const = 0;
113 virtual p4rt_id_t getId(P4RuntimeSymbolType type, cstring name) const = 0;
118 virtual cstring getAlias(cstring name) const = 0;
119};
120
131 public:
132 virtual ~P4RuntimeArchHandlerIface() {}
134 virtual cstring getControlPlaneName(const IR::Block *block) {
135 auto decl = block->getContainer();
136 return decl ? decl->controlPlaneName() : cstring::empty;
137 }
138
141 const IR::TableBlock *tableBlock) = 0;
144 const IR::ExternBlock *externBlock) = 0;
147 const IR::BaseAssignmentStatement *assign) = 0;
150 const P4::ExternMethod *externMethod) = 0;
154 const P4::ExternFunction *externFunction) = 0;
157 virtual void collectExtra(P4RuntimeSymbolTableIface *symbols) = 0;
160 virtual void postCollect(const P4RuntimeSymbolTableIface &symbols) = 0;
164 ::p4::config::v1::P4Info *p4info,
165 ::p4::config::v1::Table *table,
166 const IR::TableBlock *tableBlock) = 0;
169 virtual void addExternInstance(const P4RuntimeSymbolTableIface &symbols,
170 ::p4::config::v1::P4Info *p4info,
171 const IR::ExternBlock *externBlock) = 0;
174 virtual void addExternFunction(const P4RuntimeSymbolTableIface &symbols,
175 ::p4::config::v1::P4Info *p4info,
176 const P4::ExternFunction *externFunction) = 0;
179 virtual void postAdd(const P4RuntimeSymbolTableIface &symbols,
180 ::p4::config::v1::P4Info *p4info) = 0;
182 virtual void addExternEntries(const p4::v1::WriteRequest *entries,
183 const P4RuntimeSymbolTableIface &symbols,
184 const IR::ExternBlock *externBlock) = 0;
186 virtual bool filterAnnotations(cstring anno) = 0;
187
189 virtual google::protobuf::util::JsonPrintOptions getJsonPrintOptions() = 0;
190};
191
197
203 ReferenceMap *refMap, TypeMap *typeMap,
204 const IR::ToplevelBlock *evaluatedProgram) const = 0;
205};
206
209namespace Helpers {
210
213std::optional<ExternInstance> getExternInstanceFromProperty(const IR::P4Table *table,
214 const cstring &propertyName,
215 ReferenceMap *refMap, TypeMap *typeMap,
216 bool *isConstructedInPlace = nullptr);
217
220bool isExternPropertyConstructedInPlace(const IR::P4Table *table, const cstring &propertyName);
221
224template <typename Func>
225void forAllEvaluatedBlocks(const IR::Block *block, Func function) {
226 std::set<const IR::Block *> visited;
227 ordered_set<const IR::Block *> frontier{block};
228
229 while (!frontier.empty()) {
230 // Pop a block off the frontier of blocks we haven't yet visited.
231 auto evaluatedBlock = *frontier.begin();
232 frontier.erase(frontier.begin());
233 visited.insert(evaluatedBlock);
234
235 function(evaluatedBlock);
236
237 // Add child blocks to the frontier if we haven't already visited them.
238 for (auto evaluatedChild : evaluatedBlock->constantValue) {
239 // child block may be nullptr due to optional argument.
240 if (!evaluatedChild.second) continue;
241 if (!evaluatedChild.second->is<IR::Block>()) continue;
242 auto evaluatedChildBlock = evaluatedChild.second->to<IR::Block>();
243 if (visited.find(evaluatedChildBlock) != visited.end()) continue;
244 frontier.insert(evaluatedChildBlock);
245 }
246 }
247}
248
250std::string serializeOneAnnotation(const IR::Annotation *annotation);
251
253void serializeOneStructuredAnnotation(const IR::Annotation *annotation,
254 ::p4::config::v1::StructuredAnnotation *structuredAnnotation);
255
261template <typename Message, typename UnaryPredicate>
262void addAnnotations(Message *message, const IR::IAnnotated *annotated, UnaryPredicate p) {
263 CHECK_NULL(message);
264
265 // Synthesized resources may have no annotations.
266 if (annotated == nullptr) return;
267
268 for (const IR::Annotation *annotation : annotated->getAnnotations()) {
269 // Always add all structured annotations.
270 if (annotation->annotationKind() != IR::Annotation::Kind::Unstructured &&
271 annotation->annotationKind() != IR::Annotation::Kind::Unparsed) {
272 serializeOneStructuredAnnotation(annotation, message->add_structured_annotations());
273 continue;
274 }
275 // Don't output the @name or @id annotations; they're represented
276 // elsewhere in P4Info messages.
277 if (annotation->name == IR::Annotation::nameAnnotation) continue;
278 if (annotation->name == "id") continue;
279
280 // Don't output the @brief or @description annotations; they're
281 // represented using the documentation fields.
282 if (annotation->name == "brief" || annotation->name == "description") continue;
283
284 if (p(annotation->name)) continue;
285
286 message->add_annotations(serializeOneAnnotation(annotation));
287 }
288}
289
291template <typename Message>
292void addAnnotations(Message *message, const IR::IAnnotated *annotated) {
293 addAnnotations(message, annotated, [](cstring) { return false; });
294}
295
298template <typename Message>
299void addDocumentation(Message *message, const IR::IAnnotated *annotated) {
300 CHECK_NULL(message);
301
302 // Synthesized resources may have no annotations.
303 if (annotated == nullptr) return;
304
305 ::p4::config::v1::Documentation doc;
306 bool hasDoc = false;
307
308 // we iterate over all annotations looking for '@brief' and / or
309 // '@description'. As per the P4Runtime spec, we only set the 'doc' field in
310 // the message if at least one of them is present.
311 for (const IR::Annotation *annotation : annotated->getAnnotations()) {
312 if (annotation->name == "brief") {
313 auto brief = annotation->getExpr(0)->to<IR::StringLiteral>();
314 // guaranteed by ParseAnnotations pass
315 CHECK_NULL(brief);
316 doc.set_brief(brief->value);
317 hasDoc = true;
318 continue;
319 }
320 if (annotation->name == "description") {
321 auto description = annotation->getExpr(0)->to<IR::StringLiteral>();
322 // guaranteed by ParseAnnotations pass
323 CHECK_NULL(description);
324 doc.set_description(description->value);
325 hasDoc = true;
326 continue;
327 }
328 }
329
330 if (hasDoc) message->mutable_doc()->CopyFrom(doc);
331}
332
336template <typename UnaryPredicate>
337void setPreamble(::p4::config::v1::Preamble *preamble, p4rt_id_t id, cstring name, cstring alias,
338 const IR::IAnnotated *annotated, UnaryPredicate p) {
339 CHECK_NULL(preamble);
340 preamble->set_id(id);
341 preamble->set_name(name);
342 preamble->set_alias(alias);
343 addAnnotations(preamble, annotated, p);
344 addDocumentation(preamble, annotated);
345}
346
349inline void setPreamble(::p4::config::v1::Preamble *preamble, p4rt_id_t id, cstring name,
350 cstring alias, const IR::IAnnotated *annotated) {
351 setPreamble(preamble, id, name, alias, annotated, [](cstring) { return false; });
352}
353
356int64_t getTableSize(const IR::P4Table *table);
357
359template <typename Kind>
360struct CounterlikeTraits; // IWYU pragma: keep
361
367template <typename Kind>
372 const IR::IAnnotated *annotations;
376 const int64_t size;
378 const std::optional<cstring> table;
382
385 static std::optional<Counterlike<Kind>> from(const IR::ExternBlock *instance,
386 const ReferenceMap *refMap, P4::TypeMap *typeMap,
387 ::p4::config::v1::P4TypeInfo *p4RtTypeInfo) {
388 CHECK_NULL(instance);
389 auto declaration = instance->node->to<IR::Declaration_Instance>();
390
391 // Counter and meter externs refer to their unit as a "type"; this is
392 // (confusingly) unrelated to the "type" field of a counter or meter in
393 // P4Info.
394 auto unit = instance->getParameterValue("type"_cs);
395 if (!unit->is<IR::Declaration_ID>()) {
396 ::P4::error(ErrorType::ERR_INVALID,
397 "%1% '%2%' has a unit type which is not an enum constant: %3%",
398 CounterlikeTraits<Kind>::name(), declaration, unit);
399 return std::nullopt;
400 }
401
402 auto size = instance->getParameterValue(CounterlikeTraits<Kind>::sizeParamName());
403 big_int val;
404 if (size->template is<IR::Constant>()) {
405 val = size->template to<IR::Constant>()->value;
406 } else if (size->template is<IR::SerEnumMember>()) {
407 auto sem = size->template to<IR::SerEnumMember>();
408 val = sem->value->template to<IR::Constant>()->value;
409 } else {
410 ::P4::error(ErrorType::ERR_INVALID, "%1% '%2%' has a non-constant size: %3%",
411 CounterlikeTraits<Kind>::name(), declaration, size);
412 return std::nullopt;
413 }
414
415 cstring index_type_name = nullptr;
416 auto indexTypeParamIdx = CounterlikeTraits<Kind>::indexTypeParamIdx();
417 // In v1model, the index is a bit<32>, in PSA it is determined by a type parameter.
418 if (indexTypeParamIdx != std::nullopt) {
419 // retrieve type parameter for the index.
420 BUG_CHECK(declaration->type->is<IR::Type_Specialized>(),
421 "%1%: expected Type_Specialized", declaration->type);
422 auto type = declaration->type->to<IR::Type_Specialized>();
423 BUG_CHECK(type->arguments->size() > *indexTypeParamIdx,
424 "%1%: expected at least %2% type arguments", instance,
425 *indexTypeParamIdx + 1);
426 auto typeArg = type->arguments->at(*indexTypeParamIdx);
427 // We ignore the return type on purpose, but the call is required to update p4RtTypeInfo
428 // if the index has a user-defined type.
429 TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
430 index_type_name = getTypeName(typeArg, typeMap);
431 }
432
433 return Counterlike<Kind>{declaration->controlPlaneName(),
434 declaration->to<IR::IAnnotated>(),
435 unit->to<IR::Declaration_ID>()->name,
436 int(val),
437 std::nullopt,
439 }
440
444 static std::optional<Counterlike<Kind>> fromDirect(const ExternInstance &instance,
445 const IR::P4Table *table) {
446 CHECK_NULL(table);
447 BUG_CHECK(instance.name != std::nullopt, "Caller should've ensured we have a name");
448
449 if (instance.type->name != CounterlikeTraits<Kind>::directTypeName()) {
450 ::P4::error(ErrorType::ERR_EXPECTED, "Expected a direct %1%: %2%",
451 CounterlikeTraits<Kind>::name(), instance.expression);
452 return std::nullopt;
453 }
454
455 auto unitArgument = instance.substitution.lookupByName("type"_cs)->expression;
456 if (unitArgument == nullptr) {
457 ::P4::error(ErrorType::ERR_EXPECTED,
458 "Direct %1% instance %2% should take a constructor argument",
459 CounterlikeTraits<Kind>::name(), instance.expression);
460 return std::nullopt;
461 }
462 if (!unitArgument->is<IR::Member>()) {
463 ::P4::error(ErrorType::ERR_UNEXPECTED,
464 "Direct %1% instance %2% has an unexpected constructor argument",
465 CounterlikeTraits<Kind>::name(), instance.expression);
466 return std::nullopt;
467 }
468
469 auto unit = unitArgument->to<IR::Member>()->member.name;
470 return Counterlike<Kind>{*instance.name,
471 instance.annotations,
472 unit,
474 table->controlPlaneName(),
475 cstring::empty};
476 }
477};
478
481template <typename Kind>
482std::optional<Counterlike<Kind>> getDirectCounterlike(const IR::P4Table *table,
483 ReferenceMap *refMap, TypeMap *typeMap) {
485 auto instance = getExternInstanceFromProperty(table, propertyName, refMap, typeMap);
486 if (!instance) return std::nullopt;
487 return Counterlike<Kind>::fromDirect(*instance, table);
488}
489
490} // namespace Helpers
491
492} // namespace ControlPlaneAPI
493 /* end group control_plane */
495} // namespace P4
496
497#endif /* CONTROL_PLANE_P4RUNTIMEARCHHANDLER_H_ */
Definition p4RuntimeArchHandler.h:130
virtual void collectTableProperties(P4RuntimeSymbolTableIface *symbols, const IR::TableBlock *tableBlock)=0
virtual void addExternInstance(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info, const IR::ExternBlock *externBlock)=0
virtual void collectAssignmentStatement(P4RuntimeSymbolTableIface *symbols, const IR::BaseAssignmentStatement *assign)=0
Collects architecture-specific used in assignment statements.
virtual void postAdd(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info)=0
virtual void addTableProperties(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info, ::p4::config::v1::Table *table, const IR::TableBlock *tableBlock)=0
virtual cstring getControlPlaneName(const IR::Block *block)
Get control plane name for @block.
Definition p4RuntimeArchHandler.h:134
virtual void collectExternFunction(P4RuntimeSymbolTableIface *symbols, const P4::ExternFunction *externFunction)=0
virtual void addExternFunction(const P4RuntimeSymbolTableIface &symbols, ::p4::config::v1::P4Info *p4info, const P4::ExternFunction *externFunction)=0
virtual void postCollect(const P4RuntimeSymbolTableIface &symbols)=0
virtual google::protobuf::util::JsonPrintOptions getJsonPrintOptions()=0
Control how JSON is output.
virtual void collectExternInstance(P4RuntimeSymbolTableIface *symbols, const IR::ExternBlock *externBlock)=0
Collects architecture-specific @externBlock instance in @symbols table.
virtual bool filterAnnotations(cstring anno)=0
called when processing annotations via setPreamble
virtual void collectExternMethod(P4RuntimeSymbolTableIface *symbols, const P4::ExternMethod *externMethod)=0
Collects architecture-specific @externMethod instance in @symbols table.
virtual void addExternEntries(const p4::v1::WriteRequest *entries, const P4RuntimeSymbolTableIface &symbols, const IR::ExternBlock *externBlock)=0
This method is called to add target specific extern entries.
virtual void collectExtra(P4RuntimeSymbolTableIface *symbols)=0
Definition p4RuntimeArchHandler.h:100
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:54
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:377
Definition methodInstance.h:194
Definition methodInstance.h:168
The Declaration interface, representing objects with names.
Definition declaration.h:17
Class used to encode maps from paths to declarations.
Definition referenceMap.h:67
Definition typeMap.h:32
Definition cstring.h:85
Definition ordered_set.h:32
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:77
void forAllEvaluatedBlocks(const IR::Block *block, Func function)
Definition p4RuntimeArchHandler.h:225
std::string serializeOneAnnotation(const IR::Annotation *annotation)
Serialize an unstructured @annotation to a string.
Definition p4RuntimeArchHandler.cpp:108
std::optional< ExternInstance > getExternInstanceFromProperty(const IR::P4Table *table, const cstring &propertyName, ReferenceMap *refMap, TypeMap *typeMap, bool *isConstructedInPlace)
Definition p4RuntimeArchHandler.cpp:30
bool isExternPropertyConstructedInPlace(const IR::P4Table *table, const cstring &propertyName)
Definition p4RuntimeArchHandler.cpp:66
int64_t getTableSize(const IR::P4Table *table)
Definition p4RuntimeArchHandler.cpp:80
void addDocumentation(Message *message, const IR::IAnnotated *annotated)
' and '@description' annotations if present.
Definition p4RuntimeArchHandler.h:299
std::optional< Counterlike< Kind > > getDirectCounterlike(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition p4RuntimeArchHandler.h:482
A traits class describing the properties of "counterlike" things.
Definition p4RuntimeArchHandler.h:360
TODO(antonin): High level goals of the generator go here!!
Definition dpdk/control-plane/bfruntime_arch_handler.h:44
cstring getTypeName(const IR::Type *type, TypeMap *typeMap)
Definition typeSpecConverter.cpp:68
Definition cstring.h:80
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:58
Definition p4RuntimeArchHandler.h:368
const std::optional< cstring > table
If not none, the instance is a direct resource associated with @table.
Definition p4RuntimeArchHandler.h:378
const cstring name
The name of the instance.
Definition p4RuntimeArchHandler.h:370
const IR::IAnnotated * annotations
If non-null, the instance's annotations.
Definition p4RuntimeArchHandler.h:372
static std::optional< Counterlike< Kind > > from(const IR::ExternBlock *instance, const ReferenceMap *refMap, P4::TypeMap *typeMap, ::p4::config::v1::P4TypeInfo *p4RtTypeInfo)
Definition p4RuntimeArchHandler.h:385
const cstring unit
The units parameter to the instance; valid values vary depending on @Kind.
Definition p4RuntimeArchHandler.h:374
const cstring index_type_name
Definition p4RuntimeArchHandler.h:381
static std::optional< Counterlike< Kind > > fromDirect(const ExternInstance &instance, const IR::P4Table *table)
Definition p4RuntimeArchHandler.h:444
const int64_t size
The size parameter to the instance.
Definition p4RuntimeArchHandler.h:376
Definition p4RuntimeArchHandler.h:195
virtual P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const =0
Definition externInstance.h:42