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/ordered_set.h"
42#include "typeSpecConverter.h"
43
44namespace P4 {
45
49namespace ControlPlaneAPI {
50
51using p4rt_id_t = uint32_t;
52
61 public:
62 virtual ~P4RuntimeSymbolType() {}
63
67 explicit operator p4rt_id_t() const { return id; }
68
69 static P4RuntimeSymbolType P4RT_ACTION() {
70 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::ACTION);
71 }
72 static P4RuntimeSymbolType P4RT_TABLE() {
73 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::TABLE);
74 }
75 static P4RuntimeSymbolType P4RT_VALUE_SET() {
76 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::VALUE_SET);
77 }
78 static P4RuntimeSymbolType P4RT_CONTROLLER_HEADER() {
79 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::CONTROLLER_HEADER);
80 }
81
82 static P4RuntimeSymbolType P4RT_OTHER_EXTERNS_START() {
83 return P4RuntimeSymbolType(::p4::config::v1::P4Ids::OTHER_EXTERNS_START);
84 }
85
86 bool operator==(const P4RuntimeSymbolType &other) const { return id == other.id; }
87
88 bool operator!=(const P4RuntimeSymbolType &other) const { return !(*this == other); }
89
90 bool operator<(const P4RuntimeSymbolType &other) const { return id < other.id; }
91
92 protected:
93 static P4RuntimeSymbolType make(p4rt_id_t id) { return P4RuntimeSymbolType(id); }
94
95 private:
96 // even if the constructor is protected, the static functions in the derived
97 // classes cannot access it, which is why we use the make factory function
98 explicit constexpr P4RuntimeSymbolType(p4rt_id_t id) noexcept : id(id) {}
99
101 p4rt_id_t id;
102};
103
107 public:
108 virtual ~P4RuntimeSymbolTableIface() {}
110 virtual void add(P4RuntimeSymbolType type, const IR::IDeclaration *declaration) = 0;
112 virtual void add(P4RuntimeSymbolType type, cstring name,
113 std::optional<p4rt_id_t> id = std::nullopt) = 0;
116 virtual p4rt_id_t getId(P4RuntimeSymbolType type,
117 const IR::IDeclaration *declaration) const = 0;
119 virtual p4rt_id_t getId(P4RuntimeSymbolType type, cstring name) const = 0;
124 virtual cstring getAlias(cstring name) const = 0;
125};
126
137 public:
138 virtual ~P4RuntimeArchHandlerIface() {}
140 virtual cstring getControlPlaneName(const IR::Block *block) {
141 auto decl = block->getContainer();
142 return decl ? decl->controlPlaneName() : "";
143 }
147 const IR::TableBlock *tableBlock) = 0;
150 const IR::ExternBlock *externBlock) = 0;
153 const IR::AssignmentStatement *assign) = 0;
156 const P4::ExternMethod *externMethod) = 0;
160 const P4::ExternFunction *externFunction) = 0;
163 virtual void collectExtra(P4RuntimeSymbolTableIface *symbols) = 0;
166 virtual void postCollect(const P4RuntimeSymbolTableIface &symbols) = 0;
170 ::p4::config::v1::P4Info *p4info,
171 ::p4::config::v1::Table *table,
172 const IR::TableBlock *tableBlock) = 0;
175 virtual void addExternInstance(const P4RuntimeSymbolTableIface &symbols,
176 ::p4::config::v1::P4Info *p4info,
177 const IR::ExternBlock *externBlock) = 0;
180 virtual void addExternFunction(const P4RuntimeSymbolTableIface &symbols,
181 ::p4::config::v1::P4Info *p4info,
182 const P4::ExternFunction *externFunction) = 0;
185 virtual void postAdd(const P4RuntimeSymbolTableIface &symbols,
186 ::p4::config::v1::P4Info *p4info) = 0;
188 virtual void addExternEntries(const p4::v1::WriteRequest *entries,
189 const P4RuntimeSymbolTableIface &symbols,
190 const IR::ExternBlock *externBlock) = 0;
192 virtual bool filterAnnotations(cstring anno) = 0;
193
195 virtual google::protobuf::util::JsonPrintOptions getJsonPrintOptions() = 0;
196};
197
203
209 ReferenceMap *refMap, TypeMap *typeMap,
210 const IR::ToplevelBlock *evaluatedProgram) const = 0;
211};
212
215namespace Helpers {
216
219std::optional<ExternInstance> getExternInstanceFromProperty(const IR::P4Table *table,
220 const cstring &propertyName,
221 ReferenceMap *refMap, TypeMap *typeMap,
222 bool *isConstructedInPlace = nullptr);
223
226bool isExternPropertyConstructedInPlace(const IR::P4Table *table, const cstring &propertyName);
227
230template <typename Func>
231void forAllEvaluatedBlocks(const IR::Block *block, Func function) {
232 std::set<const IR::Block *> visited;
233 ordered_set<const IR::Block *> frontier{block};
234
235 while (!frontier.empty()) {
236 // Pop a block off the frontier of blocks we haven't yet visited.
237 auto evaluatedBlock = *frontier.begin();
238 frontier.erase(frontier.begin());
239 visited.insert(evaluatedBlock);
240
241 function(evaluatedBlock);
242
243 // Add child blocks to the frontier if we haven't already visited them.
244 for (auto evaluatedChild : evaluatedBlock->constantValue) {
245 // child block may be nullptr due to optional argument.
246 if (!evaluatedChild.second) continue;
247 if (!evaluatedChild.second->is<IR::Block>()) continue;
248 auto evaluatedChildBlock = evaluatedChild.second->to<IR::Block>();
249 if (visited.find(evaluatedChildBlock) != visited.end()) continue;
250 frontier.insert(evaluatedChildBlock);
251 }
252 }
253}
254
256std::string serializeOneAnnotation(const IR::Annotation *annotation);
257
259void serializeOneStructuredAnnotation(const IR::Annotation *annotation,
260 ::p4::config::v1::StructuredAnnotation *structuredAnnotation);
261
267template <typename Message, typename UnaryPredicate>
268void addAnnotations(Message *message, const IR::IAnnotated *annotated, UnaryPredicate p) {
269 CHECK_NULL(message);
270
271 // Synthesized resources may have no annotations.
272 if (annotated == nullptr) return;
273
274 for (const IR::Annotation *annotation : annotated->getAnnotations()->annotations) {
275 // Always add all structured annotations.
276 if (annotation->annotationKind() != IR::Annotation::Kind::Unstructured) {
277 serializeOneStructuredAnnotation(annotation, message->add_structured_annotations());
278 continue;
279 }
280 // Don't output the @name or @id annotations; they're represented
281 // elsewhere in P4Info messages.
282 if (annotation->name == IR::Annotation::nameAnnotation) continue;
283 if (annotation->name == "id") continue;
284
285 // Don't output the @brief or @description annotations; they're
286 // represented using the documentation fields.
287 if (annotation->name == "brief" || annotation->name == "description") continue;
288
289 if (p(annotation->name)) continue;
290
291 message->add_annotations(serializeOneAnnotation(annotation));
292 }
293}
294
296template <typename Message>
297void addAnnotations(Message *message, const IR::IAnnotated *annotated) {
298 addAnnotations(message, annotated, [](cstring) { return false; });
299}
300
303template <typename Message>
304void addDocumentation(Message *message, const IR::IAnnotated *annotated) {
305 CHECK_NULL(message);
306
307 // Synthesized resources may have no annotations.
308 if (annotated == nullptr) return;
309
310 ::p4::config::v1::Documentation doc;
311 bool hasDoc = false;
312
313 // we iterate over all annotations looking for '@brief' and / or
314 // '@description'. As per the P4Runtime spec, we only set the 'doc' field in
315 // the message if at least one of them is present.
316 for (const IR::Annotation *annotation : annotated->getAnnotations()->annotations) {
317 if (annotation->name == "brief") {
318 auto brief = annotation->expr[0]->to<IR::StringLiteral>();
319 // guaranteed by ParseAnnotations pass
320 CHECK_NULL(brief);
321 doc.set_brief(brief->value);
322 hasDoc = true;
323 continue;
324 }
325 if (annotation->name == "description") {
326 auto description = annotation->expr[0]->to<IR::StringLiteral>();
327 // guaranteed by ParseAnnotations pass
328 CHECK_NULL(description);
329 doc.set_description(description->value);
330 hasDoc = true;
331 continue;
332 }
333 }
334
335 if (hasDoc) message->mutable_doc()->CopyFrom(doc);
336}
337
341template <typename UnaryPredicate>
342void setPreamble(::p4::config::v1::Preamble *preamble, p4rt_id_t id, cstring name, cstring alias,
343 const IR::IAnnotated *annotated, UnaryPredicate p) {
344 CHECK_NULL(preamble);
345 preamble->set_id(id);
346 preamble->set_name(name);
347 preamble->set_alias(alias);
348 addAnnotations(preamble, annotated, p);
349 addDocumentation(preamble, annotated);
350}
351
354inline void setPreamble(::p4::config::v1::Preamble *preamble, p4rt_id_t id, cstring name,
355 cstring alias, const IR::IAnnotated *annotated) {
356 setPreamble(preamble, id, name, alias, annotated, [](cstring) { return false; });
357}
358
361int64_t getTableSize(const IR::P4Table *table);
362
364template <typename Kind>
365struct CounterlikeTraits; // IWYU pragma: keep
366
372template <typename Kind>
377 const IR::IAnnotated *annotations;
381 const int64_t size;
383 const std::optional<cstring> table;
387
390 static std::optional<Counterlike<Kind>> from(const IR::ExternBlock *instance,
391 const ReferenceMap *refMap, P4::TypeMap *typeMap,
392 ::p4::config::v1::P4TypeInfo *p4RtTypeInfo) {
393 CHECK_NULL(instance);
394 auto declaration = instance->node->to<IR::Declaration_Instance>();
395
396 // Counter and meter externs refer to their unit as a "type"; this is
397 // (confusingly) unrelated to the "type" field of a counter or meter in
398 // P4Info.
399 auto unit = instance->getParameterValue("type");
400 if (!unit->is<IR::Declaration_ID>()) {
401 ::error(ErrorType::ERR_INVALID,
402 "%1% '%2%' has a unit type which is not an enum constant: %3%",
403 CounterlikeTraits<Kind>::name(), declaration, unit);
404 return std::nullopt;
405 }
406
407 auto size = instance->getParameterValue(CounterlikeTraits<Kind>::sizeParamName());
408 big_int val;
409 if (size->template is<IR::Constant>()) {
410 val = size->template to<IR::Constant>()->value;
411 } else if (size->template is<IR::SerEnumMember>()) {
412 auto sem = size->template to<IR::SerEnumMember>();
413 val = sem->value->template to<IR::Constant>()->value;
414 } else {
415 ::error(ErrorType::ERR_INVALID, "%1% '%2%' has a non-constant size: %3%",
416 CounterlikeTraits<Kind>::name(), declaration, size);
417 return std::nullopt;
418 }
419
420 cstring index_type_name = nullptr;
421 auto indexTypeParamIdx = CounterlikeTraits<Kind>::indexTypeParamIdx();
422 // In v1model, the index is a bit<32>, in PSA it is determined by a type parameter.
423 if (indexTypeParamIdx != std::nullopt) {
424 // retrieve type parameter for the index.
425 BUG_CHECK(declaration->type->is<IR::Type_Specialized>(),
426 "%1%: expected Type_Specialized", declaration->type);
427 auto type = declaration->type->to<IR::Type_Specialized>();
428 BUG_CHECK(type->arguments->size() > *indexTypeParamIdx,
429 "%1%: expected at least %2% type arguments", instance,
430 *indexTypeParamIdx + 1);
431 auto typeArg = type->arguments->at(*indexTypeParamIdx);
432 // We ignore the return type on purpose, but the call is required to update p4RtTypeInfo
433 // if the index has a user-defined type.
434 TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
435 index_type_name = getTypeName(typeArg, typeMap);
436 }
437
438 return Counterlike<Kind>{declaration->controlPlaneName(),
439 declaration->to<IR::IAnnotated>(),
440 unit->to<IR::Declaration_ID>()->name,
441 int(val),
442 std::nullopt,
444 }
445
449 static std::optional<Counterlike<Kind>> fromDirect(const ExternInstance &instance,
450 const IR::P4Table *table) {
451 CHECK_NULL(table);
452 BUG_CHECK(instance.name != std::nullopt, "Caller should've ensured we have a name");
453
454 if (instance.type->name != CounterlikeTraits<Kind>::directTypeName()) {
455 ::error(ErrorType::ERR_EXPECTED, "Expected a direct %1%: %2%",
456 CounterlikeTraits<Kind>::name(), instance.expression);
457 return std::nullopt;
458 }
459
460 auto unitArgument = instance.substitution.lookupByName("type")->expression;
461 if (unitArgument == nullptr) {
462 ::error(ErrorType::ERR_EXPECTED,
463 "Direct %1% instance %2% should take a constructor argument",
464 CounterlikeTraits<Kind>::name(), instance.expression);
465 return std::nullopt;
466 }
467 if (!unitArgument->is<IR::Member>()) {
468 ::error(ErrorType::ERR_UNEXPECTED,
469 "Direct %1% instance %2% has an unexpected constructor argument",
470 CounterlikeTraits<Kind>::name(), instance.expression);
471 return std::nullopt;
472 }
473
474 auto unit = unitArgument->to<IR::Member>()->member.name;
475 return Counterlike<Kind>{*instance.name,
476 instance.annotations,
477 unit,
479 table->controlPlaneName(),
480 ""};
481 }
482};
483
486template <typename Kind>
487std::optional<Counterlike<Kind>> getDirectCounterlike(const IR::P4Table *table,
488 ReferenceMap *refMap, TypeMap *typeMap) {
490 auto instance = getExternInstanceFromProperty(table, propertyName, refMap, typeMap);
491 if (!instance) return std::nullopt;
492 return Counterlike<Kind>::fromDirect(*instance, table);
493}
494
495} // namespace Helpers
496
497} // namespace ControlPlaneAPI
498
499 /* end group control_plane */
500} // namespace P4
501
502#endif /* CONTROL_PLANE_P4RUNTIMEARCHHANDLER_H_ */
Definition p4RuntimeArchHandler.h:136
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:140
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:106
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:60
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:386
Definition methodInstance.h:176
Definition methodInstance.h:144
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Definition typeMap.h:42
Definition cstring.h:72
Definition ordered_set.h:30
void forAllEvaluatedBlocks(const IR::Block *block, Func function)
Definition p4RuntimeArchHandler.h:231
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:304
std::optional< Counterlike< Kind > > getDirectCounterlike(const IR::P4Table *table, ReferenceMap *refMap, TypeMap *typeMap)
Definition p4RuntimeArchHandler.h:487
A traits class describing the properties of "counterlike" things.
Definition p4RuntimeArchHandler.h:365
cstring getTypeName(const IR::Type *type, TypeMap *typeMap)
Definition typeSpecConverter.cpp:78
Definition applyOptionsPragmas.cpp:24
Definition p4RuntimeArchHandler.h:373
const std::optional< cstring > table
If not none, the instance is a direct resource associated with @table.
Definition p4RuntimeArchHandler.h:383
const cstring name
The name of the instance.
Definition p4RuntimeArchHandler.h:375
const IR::IAnnotated * annotations
If non-null, the instance's annotations.
Definition p4RuntimeArchHandler.h:377
static std::optional< Counterlike< Kind > > from(const IR::ExternBlock *instance, const ReferenceMap *refMap, P4::TypeMap *typeMap, ::p4::config::v1::P4TypeInfo *p4RtTypeInfo)
Definition p4RuntimeArchHandler.h:390
const cstring unit
The units parameter to the instance; valid values vary depending on @Kind.
Definition p4RuntimeArchHandler.h:379
const cstring index_type_name
Definition p4RuntimeArchHandler.h:386
static std::optional< Counterlike< Kind > > fromDirect(const ExternInstance &instance, const IR::P4Table *table)
Definition p4RuntimeArchHandler.h:449
const int64_t size
The size parameter to the instance.
Definition p4RuntimeArchHandler.h:381
Definition p4RuntimeArchHandler.h:201
virtual P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const =0
Definition externInstance.h:51