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()) {
278 // Always add all structured annotations.
279 if (annotation->annotationKind() != IR::Annotation::Kind::Unstructured &&
280 annotation->annotationKind() != IR::Annotation::Kind::Unparsed) {
281 serializeOneStructuredAnnotation(annotation, message->add_structured_annotations());
282 continue;
283 }
284 // Don't output the @name or @id annotations; they're represented
285 // elsewhere in P4Info messages.
286 if (annotation->name == IR::Annotation::nameAnnotation) continue;
287 if (annotation->name == "id") continue;
288
289 // Don't output the @brief or @description annotations; they're
290 // represented using the documentation fields.
291 if (annotation->name == "brief" || annotation->name == "description") continue;
292
293 if (p(annotation->name)) continue;
294
295 message->add_annotations(serializeOneAnnotation(annotation));
296 }
297}
298
300template <typename Message>
301void addAnnotations(Message *message, const IR::IAnnotated *annotated) {
302 addAnnotations(message, annotated, [](cstring) { return false; });
303}
304
307template <typename Message>
308void addDocumentation(Message *message, const IR::IAnnotated *annotated) {
309 CHECK_NULL(message);
310
311 // Synthesized resources may have no annotations.
312 if (annotated == nullptr) return;
313
314 ::p4::config::v1::Documentation doc;
315 bool hasDoc = false;
316
317 // we iterate over all annotations looking for '@brief' and / or
318 // '@description'. As per the P4Runtime spec, we only set the 'doc' field in
319 // the message if at least one of them is present.
320 for (const IR::Annotation *annotation : annotated->getAnnotations()) {
321 if (annotation->name == "brief") {
322 auto brief = annotation->getExpr(0)->to<IR::StringLiteral>();
323 // guaranteed by ParseAnnotations pass
324 CHECK_NULL(brief);
325 doc.set_brief(brief->value);
326 hasDoc = true;
327 continue;
328 }
329 if (annotation->name == "description") {
330 auto description = annotation->getExpr(0)->to<IR::StringLiteral>();
331 // guaranteed by ParseAnnotations pass
332 CHECK_NULL(description);
333 doc.set_description(description->value);
334 hasDoc = true;
335 continue;
336 }
337 }
338
339 if (hasDoc) message->mutable_doc()->CopyFrom(doc);
340}
341
345template <typename UnaryPredicate>
346void setPreamble(::p4::config::v1::Preamble *preamble, p4rt_id_t id, cstring name, cstring alias,
347 const IR::IAnnotated *annotated, UnaryPredicate p) {
348 CHECK_NULL(preamble);
349 preamble->set_id(id);
350 preamble->set_name(name);
351 preamble->set_alias(alias);
352 addAnnotations(preamble, annotated, p);
353 addDocumentation(preamble, annotated);
354}
355
358inline void setPreamble(::p4::config::v1::Preamble *preamble, p4rt_id_t id, cstring name,
359 cstring alias, const IR::IAnnotated *annotated) {
360 setPreamble(preamble, id, name, alias, annotated, [](cstring) { return false; });
361}
362
365int64_t getTableSize(const IR::P4Table *table);
366
368template <typename Kind>
369struct CounterlikeTraits; // IWYU pragma: keep
370
376template <typename Kind>
381 const IR::IAnnotated *annotations;
385 const int64_t size;
387 const std::optional<cstring> table;
391
394 static std::optional<Counterlike<Kind>> from(const IR::ExternBlock *instance,
395 const ReferenceMap *refMap, P4::TypeMap *typeMap,
396 ::p4::config::v1::P4TypeInfo *p4RtTypeInfo) {
397 CHECK_NULL(instance);
398 auto declaration = instance->node->to<IR::Declaration_Instance>();
399
400 // Counter and meter externs refer to their unit as a "type"; this is
401 // (confusingly) unrelated to the "type" field of a counter or meter in
402 // P4Info.
403 auto unit = instance->getParameterValue("type"_cs);
404 if (!unit->is<IR::Declaration_ID>()) {
405 ::P4::error(ErrorType::ERR_INVALID,
406 "%1% '%2%' has a unit type which is not an enum constant: %3%",
407 CounterlikeTraits<Kind>::name(), declaration, unit);
408 return std::nullopt;
409 }
410
411 auto size = instance->getParameterValue(CounterlikeTraits<Kind>::sizeParamName());
412 big_int val;
413 if (size->template is<IR::Constant>()) {
414 val = size->template to<IR::Constant>()->value;
415 } else if (size->template is<IR::SerEnumMember>()) {
416 auto sem = size->template to<IR::SerEnumMember>();
417 val = sem->value->template to<IR::Constant>()->value;
418 } else {
419 ::P4::error(ErrorType::ERR_INVALID, "%1% '%2%' has a non-constant size: %3%",
420 CounterlikeTraits<Kind>::name(), declaration, size);
421 return std::nullopt;
422 }
423
424 cstring index_type_name = nullptr;
425 auto indexTypeParamIdx = CounterlikeTraits<Kind>::indexTypeParamIdx();
426 // In v1model, the index is a bit<32>, in PSA it is determined by a type parameter.
427 if (indexTypeParamIdx != std::nullopt) {
428 // retrieve type parameter for the index.
429 BUG_CHECK(declaration->type->is<IR::Type_Specialized>(),
430 "%1%: expected Type_Specialized", declaration->type);
431 auto type = declaration->type->to<IR::Type_Specialized>();
432 BUG_CHECK(type->arguments->size() > *indexTypeParamIdx,
433 "%1%: expected at least %2% type arguments", instance,
434 *indexTypeParamIdx + 1);
435 auto typeArg = type->arguments->at(*indexTypeParamIdx);
436 // We ignore the return type on purpose, but the call is required to update p4RtTypeInfo
437 // if the index has a user-defined type.
438 TypeSpecConverter::convert(refMap, typeMap, typeArg, p4RtTypeInfo);
439 index_type_name = getTypeName(typeArg, typeMap);
440 }
441
442 return Counterlike<Kind>{declaration->controlPlaneName(),
443 declaration->to<IR::IAnnotated>(),
444 unit->to<IR::Declaration_ID>()->name,
445 int(val),
446 std::nullopt,
448 }
449
453 static std::optional<Counterlike<Kind>> fromDirect(const ExternInstance &instance,
454 const IR::P4Table *table) {
455 CHECK_NULL(table);
456 BUG_CHECK(instance.name != std::nullopt, "Caller should've ensured we have a name");
457
458 if (instance.type->name != CounterlikeTraits<Kind>::directTypeName()) {
459 ::P4::error(ErrorType::ERR_EXPECTED, "Expected a direct %1%: %2%",
460 CounterlikeTraits<Kind>::name(), instance.expression);
461 return std::nullopt;
462 }
463
464 auto unitArgument = instance.substitution.lookupByName("type"_cs)->expression;
465 if (unitArgument == nullptr) {
466 ::P4::error(ErrorType::ERR_EXPECTED,
467 "Direct %1% instance %2% should take a constructor argument",
468 CounterlikeTraits<Kind>::name(), instance.expression);
469 return std::nullopt;
470 }
471 if (!unitArgument->is<IR::Member>()) {
472 ::P4::error(ErrorType::ERR_UNEXPECTED,
473 "Direct %1% instance %2% has an unexpected constructor argument",
474 CounterlikeTraits<Kind>::name(), instance.expression);
475 return std::nullopt;
476 }
477
478 auto unit = unitArgument->to<IR::Member>()->member.name;
479 return Counterlike<Kind>{*instance.name,
480 instance.annotations,
481 unit,
483 table->controlPlaneName(),
484 cstring::empty};
485 }
486};
487
490template <typename Kind>
491std::optional<Counterlike<Kind>> getDirectCounterlike(const IR::P4Table *table,
492 ReferenceMap *refMap, TypeMap *typeMap) {
494 auto instance = getExternInstanceFromProperty(table, propertyName, refMap, typeMap);
495 if (!instance) return std::nullopt;
496 return Counterlike<Kind>::fromDirect(*instance, table);
497}
498
499} // namespace Helpers
500
501} // namespace ControlPlaneAPI
502
503 /* end group control_plane */
504} // namespace P4
505
506#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:390
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: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
cstring getTypeName(const IR::Type *type, TypeMap *typeMap)
Definition typeSpecConverter.cpp:81
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: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
static std::optional< Counterlike< Kind > > from(const IR::ExternBlock *instance, const ReferenceMap *refMap, P4::TypeMap *typeMap, ::p4::config::v1::P4TypeInfo *p4RtTypeInfo)
Definition p4RuntimeArchHandler.h:394
const cstring unit
The units parameter to the instance; valid values vary depending on @Kind.
Definition p4RuntimeArchHandler.h:383
const cstring index_type_name
Definition p4RuntimeArchHandler.h:390
static std::optional< Counterlike< Kind > > fromDirect(const ExternInstance &instance, const IR::P4Table *table)
Definition p4RuntimeArchHandler.h:453
const int64_t size
The size parameter to the instance.
Definition p4RuntimeArchHandler.h:385
Definition p4RuntimeArchHandler.h:204
virtual P4RuntimeArchHandlerIface * operator()(ReferenceMap *refMap, TypeMap *typeMap, const IR::ToplevelBlock *evaluatedProgram) const =0
Definition externInstance.h:51