P4C
The P4 Compiler
Loading...
Searching...
No Matches
p4RuntimeArchHandler.h
1/*
2Copyright 2018-present Barefoot Networks, Inc.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17#ifndef CONTROL_PLANE_P4RUNTIMEARCHHANDLER_H_
18#define CONTROL_PLANE_P4RUNTIMEARCHHANDLER_H_
19
20#pragma GCC diagnostic push
21#pragma GCC diagnostic ignored "-Wunused-parameter"
22#pragma GCC diagnostic ignored "-Wpedantic"
23#include <google/protobuf/util/json_util.h>
24#pragma GCC diagnostic pop
25
26#include <optional>
27#include <set>
28
29#pragma GCC diagnostic push
30#pragma GCC diagnostic ignored "-Wunused-parameter"
31#pragma GCC diagnostic ignored "-Wpedantic"
32#include "p4/config/v1/p4info.pb.h"
33#include "p4/v1/p4runtime.pb.h"
34#pragma GCC diagnostic pop
35
36#include "frontends/common/resolveReferences/referenceMap.h"
37#include "frontends/p4/externInstance.h"
38#include "frontends/p4/methodInstance.h"
39#include "frontends/p4/typeMap.h"
40#include "ir/ir.h"
41#include "lib/cstring.h"
42#include "lib/ordered_set.h"
43#include "typeSpecConverter.h"
44
45namespace P4 {
46
47using namespace literals;
48
52namespace ControlPlaneAPI {
53
54using p4rt_id_t = uint32_t;
55
64 public:
65 virtual ~P4RuntimeSymbolType() {}
66
70 explicit operator p4rt_id_t() const { return id; }
71
72 static P4RuntimeSymbolType P4RT_ACTION() {
73 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::ACTION);
74 }
75 static P4RuntimeSymbolType P4RT_TABLE() {
76 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::TABLE);
77 }
78 static P4RuntimeSymbolType P4RT_VALUE_SET() {
79 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::VALUE_SET);
80 }
81 static P4RuntimeSymbolType P4RT_CONTROLLER_HEADER() {
82 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::CONTROLLER_HEADER);
83 }
84
85 static P4RuntimeSymbolType P4RT_OTHER_EXTERNS_START() {
86 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::OTHER_EXTERNS_START);
87 }
88
89 bool operator==(const P4RuntimeSymbolType &other) const { return id == other.id; }
90
91 bool operator!=(const P4RuntimeSymbolType &other) const { return !(*this == other); }
92
93 bool operator<(const P4RuntimeSymbolType &other) const { return id < other.id; }
94
95 protected:
96 static P4RuntimeSymbolType make(p4rt_id_t id) { return P4RuntimeSymbolType(id); }
97
98 private:
99 // even if the constructor is protected, the static functions in the derived
100 // classes cannot access it, which is why we use the make factory function
101 explicit constexpr P4RuntimeSymbolType(p4rt_id_t id) noexcept : id(id) {}
102
104 p4rt_id_t id;
105};
106
110 public:
111 virtual ~P4RuntimeSymbolTableIface() {}
113 virtual void add(P4RuntimeSymbolType type, const IR::IDeclaration *declaration) = 0;
115 virtual void add(P4RuntimeSymbolType type, cstring name,
116 std::optional<p4rt_id_t> id = std::nullopt) = 0;
119 virtual p4rt_id_t getId(P4RuntimeSymbolType type,
120 const IR::IDeclaration *declaration) const = 0;
122 virtual p4rt_id_t getId(P4RuntimeSymbolType type, cstring name) const = 0;
127 virtual cstring getAlias(cstring name) const = 0;
128};
129
140 public:
141 virtual ~P4RuntimeArchHandlerIface() {}
143 virtual cstring getControlPlaneName(const IR::Block *block) {
144 auto decl = block->getContainer();
145 return decl ? decl->controlPlaneName() : cstring::empty;
146 }
150 const IR::TableBlock *tableBlock) = 0;
153 const IR::ExternBlock *externBlock) = 0;
156 const IR::AssignmentStatement *assign) = 0;
159 const P4::ExternMethod *externMethod) = 0;
163 const P4::ExternFunction *externFunction) = 0;
166 virtual void collectExtra(P4RuntimeSymbolTableIface *symbols) = 0;
169 virtual void postCollect(const P4RuntimeSymbolTableIface &symbols) = 0;
173 ::p4::config::v1::P4Info *p4info,
174 ::p4::config::v1::Table *table,
175 const IR::TableBlock *tableBlock) = 0;
178 virtual void addExternInstance(const P4RuntimeSymbolTableIface &symbols,
179 ::p4::config::v1::P4Info *p4info,
180 const IR::ExternBlock *externBlock) = 0;
183 virtual void addExternFunction(const P4RuntimeSymbolTableIface &symbols,
184 ::p4::config::v1::P4Info *p4info,
185 const P4::ExternFunction *externFunction) = 0;
188 virtual void postAdd(const P4RuntimeSymbolTableIface &symbols,
189 ::p4::config::v1::P4Info *p4info) = 0;
191 virtual void addExternEntries(const p4::v1::WriteRequest *entries,
192 const P4RuntimeSymbolTableIface &symbols,
193 const IR::ExternBlock *externBlock) = 0;
195 virtual bool filterAnnotations(cstring anno) = 0;
196
198 virtual google::protobuf::util::JsonPrintOptions getJsonPrintOptions() = 0;
199};
200
206
212 ReferenceMap *refMap, TypeMap *typeMap,
213 const IR::ToplevelBlock *evaluatedProgram) const = 0;
214};
215
218namespace Helpers {
219
222std::optional<ExternInstance> getExternInstanceFromProperty(const IR::P4Table *table,
223 const cstring &propertyName,
224 ReferenceMap *refMap, TypeMap *typeMap,
225 bool *isConstructedInPlace = nullptr);
226
229bool isExternPropertyConstructedInPlace(const IR::P4Table *table, const cstring &propertyName);
230
233template <typename Func>
234void forAllEvaluatedBlocks(const IR::Block *block, Func function) {
235 std::set<const IR::Block *> visited;
236 ordered_set<const IR::Block *> frontier{block};
237
238 while (!frontier.empty()) {
239 // Pop a block off the frontier of blocks we haven't yet visited.
240 auto evaluatedBlock = *frontier.begin();
241 frontier.erase(frontier.begin());
242 visited.insert(evaluatedBlock);
243
244 function(evaluatedBlock);
245
246 // Add child blocks to the frontier if we haven't already visited them.
247 for (auto evaluatedChild : evaluatedBlock->constantValue) {
248 // child block may be nullptr due to optional argument.
249 if (!evaluatedChild.second) continue;
250 if (!evaluatedChild.second->is<IR::Block>()) continue;
251 auto evaluatedChildBlock = evaluatedChild.second->to<IR::Block>();
252 if (visited.find(evaluatedChildBlock) != visited.end()) continue;
253 frontier.insert(evaluatedChildBlock);
254 }
255 }
256}
257
259std::string serializeOneAnnotation(const IR::Annotation *annotation);
260
262void serializeOneStructuredAnnotation(const IR::Annotation *annotation,
263 ::p4::config::v1::StructuredAnnotation *structuredAnnotation);
264
270template <typename Message, typename UnaryPredicate>
271void addAnnotations(Message *message, const IR::IAnnotated *annotated, UnaryPredicate p) {
272 CHECK_NULL(message);
273
274 // Synthesized resources may have no annotations.
275 if (annotated == nullptr) return;
276
277 for (const IR::Annotation *annotation : annotated->getAnnotations()->annotations) {
278 // Always add all structured annotations.
279 if (annotation->annotationKind() != IR::Annotation::Kind::Unstructured) {
280 serializeOneStructuredAnnotation(annotation, message->add_structured_annotations());
281 continue;
282 }
283 // Don't output the @name or @id annotations; they're represented
284 // elsewhere in P4Info messages.
285 if (annotation->name == IR::Annotation::nameAnnotation) continue;
286 if (annotation->name == "id") continue;
287
288 // Don't output the @brief or @description annotations; they're
289 // represented using the documentation fields.
290 if (annotation->name == "brief" || annotation->name == "description") continue;
291
292 if (p(annotation->name)) continue;
293
294 message->add_annotations(serializeOneAnnotation(annotation));
295 }
296}
297
299template <typename Message>
300void addAnnotations(Message *message, const IR::IAnnotated *annotated) {
301 addAnnotations(message, annotated, [](cstring) { return false; });
302}
303
306template <typename Message>
307void addDocumentation(Message *message, const IR::IAnnotated *annotated) {
308 CHECK_NULL(message);
309
310 // Synthesized resources may have no annotations.
311 if (annotated == nullptr) return;
312
313 ::p4::config::v1::Documentation doc;
314 bool hasDoc = false;
315
316 // we iterate over all annotations looking for '@brief' and / or
317 // '@description'. As per the P4Runtime spec, we only set the 'doc' field in
318 // the message if at least one of them is present.
319 for (const IR::Annotation *annotation : annotated->getAnnotations()->annotations) {
320 if (annotation->name == "brief") {
321 auto brief = annotation->expr[0]->to<IR::StringLiteral>();
322 // guaranteed by ParseAnnotations pass
323 CHECK_NULL(brief);
324 doc.set_brief(brief->value);
325 hasDoc = true;
326 continue;
327 }
328 if (annotation->name == "description") {
329 auto description = annotation->expr[0]->to<IR::StringLiteral>();
330 // guaranteed by ParseAnnotations pass
331 CHECK_NULL(description);
332 doc.set_description(description->value);
333 hasDoc = true;
334 continue;
335 }
336 }
337
338 if (hasDoc) message->mutable_doc()->CopyFrom(doc);
339}
340
344template <typename UnaryPredicate>
345void setPreamble(::p4::config::v1::Preamble *preamble, p4rt_id_t id, cstring name, cstring alias,
346 const IR::IAnnotated *annotated, UnaryPredicate p) {
347 CHECK_NULL(preamble);
348 preamble->set_id(id);
349 preamble->set_name(name);
350 preamble->set_alias(alias);
351 addAnnotations(preamble, annotated, p);
352 addDocumentation(preamble, annotated);
353}
354
357inline void setPreamble(::p4::config::v1::Preamble *preamble, p4rt_id_t id, cstring name,
358 cstring alias, const IR::IAnnotated *annotated) {
359 setPreamble(preamble, id, name, alias, annotated, [](cstring) { return false; });
360}
361
364int64_t getTableSize(const IR::P4Table *table);
365
367template <typename Kind>
368struct CounterlikeTraits; // IWYU pragma: keep
369
375template <typename Kind>
380 const IR::IAnnotated *annotations;
384 const int64_t size;
386 const std::optional<cstring> table;
390
393 static std::optional<Counterlike<Kind>> from(const IR::ExternBlock *instance,
394 const ReferenceMap *refMap, P4::TypeMap *typeMap,
395 ::p4::config::v1::P4TypeInfo *p4RtTypeInfo) {
396 CHECK_NULL(instance);
397 auto declaration = instance->node->to<IR::Declaration_Instance>();
398
399 // Counter and meter externs refer to their unit as a "type"; this is
400 // (confusingly) unrelated to the "type" field of a counter or meter in
401 // P4Info.
402 auto unit = instance->getParameterValue("type"_cs);
403 if (!unit->is<IR::Declaration_ID>()) {
404 ::P4::error(ErrorType::ERR_INVALID,
405 "%1% '%2%' has a unit type which is not an enum constant: %3%",
406 CounterlikeTraits<Kind>::name(), declaration, unit);
407 return std::nullopt;
408 }
409
410 auto size = instance->getParameterValue(CounterlikeTraits<Kind>::sizeParamName());
411 big_int val;
412 if (size->template is<IR::Constant>()) {
413 val = size->template to<IR::Constant>()->value;
414 } else if (size->template is<IR::SerEnumMember>()) {
415 auto sem = size->template to<IR::SerEnumMember>();
416 val = sem->value->template to<IR::Constant>()->value;
417 } else {
418 ::P4::error(ErrorType::ERR_INVALID, "%1% '%2%' has a non-constant size: %3%",
419 CounterlikeTraits<Kind>::name(), declaration, size);
420 return std::nullopt;
421 }
422
423 cstring index_type_name = nullptr;
424 auto indexTypeParamIdx = CounterlikeTraits<Kind>::indexTypeParamIdx();
425 // In v1model, the index is a bit<32>, in PSA it is determined by a type parameter.
426 if (indexTypeParamIdx != std::nullopt) {
427 // retrieve type parameter for the index.
428 BUG_CHECK(declaration->type->is<IR::Type_Specialized>(),
429 "%1%: expected Type_Specialized", declaration->type);
430 auto type = declaration->type->to<IR::Type_Specialized>();
431 BUG_CHECK(type->arguments->size() > *indexTypeParamIdx,
432 "%1%: expected at least %2% type arguments", instance,
433 *indexTypeParamIdx + 1);
434 auto typeArg = type->arguments->at(*indexTypeParamIdx);
435 // We ignore the return type on purpose, but the call is required to update p4RtTypeInfo
436 // if the index has a user-defined type.
437 TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
438 index_type_name = getTypeName(typeArg, typeMap);
439 }
440
441 return Counterlike<Kind>{declaration->controlPlaneName(),
442 declaration->to<IR::IAnnotated>(),
443 unit->to<IR::Declaration_ID>()->name,
444 int(val),
445 std::nullopt,
447 }
448
452 static std::optional<Counterlike<Kind>> fromDirect(const ExternInstance &instance,
453 const IR::P4Table *table) {
454 CHECK_NULL(table);
455 BUG_CHECK(instance.name != std::nullopt, "Caller should've ensured we have a name");
456
457 if (instance.type->name != CounterlikeTraits<Kind>::directTypeName()) {
458 ::P4::error(ErrorType::ERR_EXPECTED, "Expected a direct %1%: %2%",
459 CounterlikeTraits<Kind>::name(), instance.expression);
460 return std::nullopt;
461 }
462
463 auto unitArgument = instance.substitution.lookupByName("type"_cs)->expression;
464 if (unitArgument == nullptr) {
465 ::P4::error(ErrorType::ERR_EXPECTED,
466 "Direct %1% instance %2% should take a constructor argument",
467 CounterlikeTraits<Kind>::name(), instance.expression);
468 return std::nullopt;
469 }
470 if (!unitArgument->is<IR::Member>()) {
471 ::P4::error(ErrorType::ERR_UNEXPECTED,
472 "Direct %1% instance %2% has an unexpected constructor argument",
473 CounterlikeTraits<Kind>::name(), instance.expression);
474 return std::nullopt;
475 }
476
477 auto unit = unitArgument->to<IR::Member>()->member.name;
478 return Counterlike<Kind>{*instance.name,
479 instance.annotations,
480 unit,
482 table->controlPlaneName(),
483 cstring::empty};
484 }
485};
486
489template <typename Kind>
490std::optional<Counterlike<Kind>> getDirectCounterlike(const IR::P4Table *table,
491 ReferenceMap *refMap, TypeMap *typeMap) {
493 auto instance = getExternInstanceFromProperty(table, propertyName, refMap, typeMap);
494 if (!instance) return std::nullopt;
495 return Counterlike<Kind>::fromDirect(*instance, table);
496}
497
498} // namespace Helpers
499
500} // namespace ControlPlaneAPI
501
502 /* end group control_plane */
503} // namespace P4
504
505#endif /* CONTROL_PLANE_P4RUNTIMEARCHHANDLER_H_ */
Definition p4RuntimeArchHandler.h:139
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 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:143
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 collectAssignmentStatement(P4RuntimeSymbolTableIface *symbols, const IR::AssignmentStatement *assign)=0
Collects architecture-specific used in assignment statements.
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:109
virtual p4rt_id_t getId(P4RuntimeSymbolType type, const IR::IDeclaration *declaration) const =0
virtual cstring getAlias(cstring name) const =0
virtual void add(P4RuntimeSymbolType type, const IR::IDeclaration *declaration)=0
Add a @type symbol, extracting the name and id from @declaration.
Definition p4RuntimeArchHandler.h:63
static const ::p4::config::v1::P4DataTypeSpec * convert(const P4::ReferenceMap *refMap, P4::TypeMap *typeMap, const IR::Type *type, ::p4::config::v1::P4TypeInfo *typeInfo)
Definition typeSpecConverter.cpp:387
Definition methodInstance.h:194
Definition methodInstance.h:168
The Declaration interface, representing objects with names.
Definition declaration.h:26
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition typeMap.h:41
Definition cstring.h:85
Definition ordered_set.h:32
Definition tofino/bf-p4c/control-plane/bfruntime_arch_handler.h:78
void forAllEvaluatedBlocks(const IR::Block *block, Func function)
Definition p4RuntimeArchHandler.h:234
std::string serializeOneAnnotation(const IR::Annotation *annotation)
Serialize an unstructured @annotation to a string.
Definition p4RuntimeArchHandler.cpp:119
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
int64_t getTableSize(const IR::P4Table *table)
Definition p4RuntimeArchHandler.cpp:91
void addDocumentation(Message *message, const IR::IAnnotated *annotated)
' and '@description' annotations if present.
Definition p4RuntimeArchHandler.h:307
std::optional< Counterlike< Kind > > getDirectCounterlike(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition p4RuntimeArchHandler.h:490
A traits class describing the properties of "counterlike" things.
Definition p4RuntimeArchHandler.h:368
cstring getTypeName(const IR::Type *type, TypeMap *typeMap)
Definition typeSpecConverter.cpp:78
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
void error(const char *format, Args &&...args)
Report an error with the given message.
Definition lib/error.h:51
Definition p4RuntimeArchHandler.h:376
const std::optional< cstring > table
If not none, the instance is a direct resource associated with @table.
Definition p4RuntimeArchHandler.h:386
const cstring name
The name of the instance.
Definition p4RuntimeArchHandler.h:378
const IR::IAnnotated * annotations
If non-null, the instance's annotations.
Definition p4RuntimeArchHandler.h:380
static std::optional< Counterlike< Kind > > from(const IR::ExternBlock *instance, const ReferenceMap *refMap, P4::TypeMap *typeMap, ::p4::config::v1::P4TypeInfo *p4RtTypeInfo)
Definition p4RuntimeArchHandler.h:393
const cstring unit
The units parameter to the instance; valid values vary depending on @Kind.
Definition p4RuntimeArchHandler.h:382
const cstring index_type_name
Definition p4RuntimeArchHandler.h:389
static std::optional< Counterlike< Kind > > fromDirect(const ExternInstance &instance, const IR::P4Table *table)
Definition p4RuntimeArchHandler.h:452
const int64_t size
The size parameter to the instance.
Definition p4RuntimeArchHandler.h:384
Definition p4RuntimeArchHandler.h:204
virtual P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const =0
Definition externInstance.h:51