39class ControlConverter :
public Inspector {
47 auto table = node->table;
48 LOG3(
"Processing " << dbp(table));
50 cstring name = table->controlPlaneName();
51 result->emplace(
"name", name);
52 result->emplace(
"id", nextId(
"tables"_cs));
53 result->emplace_non_null(
"source_info"_cs, table->sourceInfoJsonObj());
54 cstring table_match_type = corelib.exactMatch.name;
55 auto key = table->getKey();
56 auto tkey = mkArrayField(result,
"key"_cs);
57 ctxt->conv->simpleExpressionsOnly =
true;
61 for (
auto ke : key->keyElements) {
62 auto expr = ke->expression;
63 auto ket = ctxt->typeMap->getType(expr,
true);
64 if (!ket->is<IR::Type_Bits>() && !ket->is<IR::Type_Boolean>() &&
65 !ket->is<IR::Type_Error>())
67 "%1%: unsupporded key type %2%. "
68 "Supported key types are be bit<> or boolean, or error.",
71 auto match_type = getKeyMatchType(ke);
79 if (match_type == corelib.lpmMatch.name) count_lpm++;
82 "multiple LPM keys in table %1% not supported", table);
83 if (match_type != table_match_type) {
84 if (match_type == BMV2::MatchImplementation::rangeMatchTypeName)
85 table_match_type = BMV2::MatchImplementation::rangeMatchTypeName;
86 if ((match_type == corelib.ternaryMatch.name ||
87 match_type == BMV2::MatchImplementation::optionalMatchTypeName) &&
88 table_match_type != BMV2::MatchImplementation::rangeMatchTypeName)
89 table_match_type = corelib.ternaryMatch.name;
90 if (match_type == corelib.lpmMatch.name &&
91 table_match_type == corelib.exactMatch.name)
92 table_match_type = corelib.lpmMatch.name;
96 if (
auto mexp = expr->to<IR::BAnd>()) {
97 if (mexp->right->is<IR::Constant>()) {
98 mask = mexp->right->to<IR::Constant>()->value;
100 }
else if (mexp->left->is<IR::Constant>()) {
101 mask = mexp->left->to<IR::Constant>()->value;
104 ::P4::error(ErrorType::ERR_EXPECTED,
"%1% must be a constant", expr);
106 }
else if (
auto slice = expr->to<IR::Slice>()) {
108 int h = slice->getH();
109 int l = slice->getL();
110 mask = Util::maskFromSlice(h, l);
117 if (match_type == BMV2::MatchImplementation::optionalMatchTypeName) {
118 keyelement->emplace(
"match_type", corelib.ternaryMatch.name);
120 keyelement->emplace(
"match_type", match_type);
122 if (
auto na = ke->getAnnotation(IR::Annotation::nameAnnotation)) {
123 BUG_CHECK(na->getExpr().size() == 1,
"%1%: expected 1 name", na);
124 auto name = na->getExpr(0)->to<IR::StringLiteral>();
125 BUG_CHECK(name !=
nullptr,
"%1%: expected a string", na);
128 keyelement->emplace(
"name", name->value);
131 auto jk = ctxt->conv->convert(expr);
134 keyelement->emplace(
"mask",
135 stringRepr(mask, ROUNDUP(expr->type->width_bits(), 8)));
137 keyelement->emplace(
"mask", Util::JsonValue::null);
138 tkey->append(keyelement);
141 LOG3(
"table_match_type: " << table_match_type);
142 result->emplace(
"match_type", table_match_type);
143 ctxt->conv->simpleExpressionsOnly =
false;
146 auto impl = table->properties->getProperty(propertyName);
150 auto sz = table->properties->getProperty(
"size");
152 if (sz->value->is<IR::ExpressionValue>()) {
153 auto expr = sz->value->to<IR::ExpressionValue>()->expression;
154 if (!expr->is<IR::Constant>()) {
155 ::P4::error(ErrorType::ERR_EXPECTED,
"%1% must be a constant", sz);
158 size = expr->to<IR::Constant>()->asInt();
161 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a number", sz);
164 if (
auto entries = table->getEntries()) {
165 size = entries->entries.size();
167 if (size == 0) size = BMV2::TableAttributes::defaultTableSize;
169 result->emplace(
"max_size", size);
170 auto ctrs = table->properties->getProperty(
"counters");
171 if (ctrs !=
nullptr) {
175 if (ctrs->value->is<IR::ExpressionValue>()) {
176 auto expr = ctrs->value->to<IR::ExpressionValue>()->expression;
177 if (expr->is<IR::ConstructorCallExpression>()) {
178 auto type = ctxt->typeMap->getType(expr,
true);
179 if (type ==
nullptr)
return result;
180 if (!type->is<IR::Type_Extern>()) {
182 "%1%: Unexpected type %2% for property. "
187 auto te = type->to<IR::Type_Extern>();
188 if (te->name !=
"direct_counter" && te->name !=
"counter") {
190 "%1%: Unexpected type %2% for property. "
191 "Must be 'counter' or 'direct_counter'.",
196 cstring ctrname = ctrs->controlPlaneName(
"counter"_cs);
197 jctr->emplace(
"name", ctrname);
198 jctr->emplace(
"id", nextId(
"counter_arrays"_cs));
199 jctr->emplace_non_null(
"source_info"_cs, ctrs->sourceInfoJsonObj());
202 bool direct = te->name ==
"direct_counter";
203 jctr->emplace(
"is_direct", direct);
204 jctr->emplace(
"binding", table->controlPlaneName());
205 ctxt->json->counters->append(jctr);
206 }
else if (expr->is<IR::PathExpression>()) {
207 auto pe = expr->to<IR::PathExpression>();
208 auto decl = ctxt->refMap->getDeclaration(pe->path,
true);
209 if (!decl->is<IR::Declaration_Instance>()) {
210 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected an instance",
214 cstring ctrname = decl->controlPlaneName();
215 auto it = ctxt->structure->directCounterMap.find(ctrname);
216 LOG3(
"Looking up " << ctrname);
217 if (it != ctxt->structure->directCounterMap.end()) {
219 "%1%: Direct counters cannot be attached to multiple tables"
221 decl, it->second, table);
224 ctxt->structure->directCounterMap.emplace(ctrname, table);
226 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a counter", ctrs);
229 result->emplace(
"with_counters",
true);
231 result->emplace(
"with_counters",
false);
235 auto timeout = table->properties->getProperty(
"support_timeout");
236 if (timeout !=
nullptr) {
237 if (timeout->value->is<IR::ExpressionValue>()) {
238 auto expr = timeout->value->to<IR::ExpressionValue>()->expression;
239 if (!expr->is<IR::BoolLiteral>()) {
240 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: must true/false", timeout);
242 sup_to = expr->to<IR::BoolLiteral>()->value;
245 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a Boolean", timeout);
248 result->emplace(
"support_timeout", sup_to);
250 auto dm = table->properties->getProperty(
"meters");
252 if (dm->value->is<IR::ExpressionValue>()) {
253 auto expr = dm->value->to<IR::ExpressionValue>()->expression;
254 if (!expr->is<IR::PathExpression>()) {
256 "%1%: expected a reference to a meter declaration", expr);
258 auto pe = expr->to<IR::PathExpression>();
259 auto decl = ctxt->refMap->getDeclaration(pe->path,
true);
260 auto type = ctxt->typeMap->getType(expr,
true);
261 if (type ==
nullptr)
return result;
262 if (type->is<IR::Type_SpecializedCanonical>())
263 type = type->to<IR::Type_SpecializedCanonical>()->baseType;
264 if (!type->is<IR::Type_Extern>()) {
266 "%1%: Unexpected type %2% for property", dm, type);
269 auto te = type->to<IR::Type_Extern>();
270 if (te->name !=
"direct_meter") {
272 "%1%: Unexpected type %2% for property", dm, type);
275 if (!decl->is<IR::Declaration_Instance>()) {
276 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected an instance",
280 ctxt->structure->directMeterMap.setTable(decl, table);
281 ctxt->structure->directMeterMap.setSize(decl, size);
282 BUG_CHECK(decl->is<IR::Declaration_Instance>(),
"%1%: expected an instance",
284 cstring name = decl->controlPlaneName();
285 result->emplace(
"direct_meters", name);
288 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a meter", dm);
291 result->emplace(
"direct_meters", Util::JsonValue::null);
294 auto action_ids = mkArrayField(result,
"action_ids"_cs);
295 auto actions = mkArrayField(result,
"actions"_cs);
296 auto al = table->getActionList();
298 std::map<cstring, cstring> useActionName;
299 for (
auto a : al->actionList) {
300 if (a->expression->is<IR::MethodCallExpression>()) {
301 auto mce = a->expression->to<IR::MethodCallExpression>();
302 if (mce->arguments->size() > 0)
304 "%1%: actions in action list with arguments not supported", a);
306 auto decl = ctxt->refMap->getDeclaration(a->getPath(),
true);
307 BUG_CHECK(decl->is<IR::P4Action>(),
"%1%: should be an action name", a);
308 auto action = decl->to<IR::P4Action>();
309 unsigned id = get(ctxt->structure->ids, action, INVALID_ACTION_ID);
310 LOG3(
"look up id " << action <<
" " <<
id);
311 BUG_CHECK(
id != INVALID_ACTION_ID,
"Could not find id for %1%", action);
312 action_ids->append(
id);
313 auto name = action->controlPlaneName();
314 actions->append(name);
315 useActionName.emplace(action->name, name);
321 CFG::Node *defaultLabelDestination =
nullptr;
323 bool hitMiss =
false;
324 for (
auto s : node->successors.edges) {
325 if (s->isUnconditional()) {
326 nextDestination = s->endpoint;
327 LOG3(
"nextDestination " << s->endpoint);
328 }
else if (s->isBool()) {
331 }
else if (s->label ==
"default") {
332 defaultLabelDestination = s->endpoint;
333 LOG3(
"default " << s->endpoint);
339 BUG_CHECK(nextDestination,
"Could not find default destination for %1%",
341 nextLabel = nodeName(nextDestination);
342 result->emplace(
"base_default_next", nextLabel);
345 if (defaultLabelDestination !=
nullptr) nextLabel = nodeName(defaultLabelDestination);
347 result->emplace(
"base_default_next", Util::JsonValue::null);
350 std::set<cstring> labelsDone;
351 for (
auto s : node->successors.edges) {
354 label = s->getBool() ?
"__HIT__"_cs :
"__MISS__"_cs;
355 }
else if (s->isUnconditional()) {
359 if (label ==
"default")
continue;
360 label = ::P4::get(useActionName, label);
362 next_tables->emplace(label, nodeName(s->endpoint));
363 labelsDone.emplace(label);
369 for (
auto a : al->actionList) {
370 cstring name = a->getName().name;
371 cstring label = ::P4::get(useActionName, name);
372 if (labelsDone.find(label) == labelsDone.end())
373 next_tables->emplace(label, nextLabel);
377 result->emplace(
"next_tables", next_tables);
379 table->properties->getProperty(IR::TableProperties::defaultActionPropertyName);
380 if (defact !=
nullptr) {
383 ErrorType::WARN_UNSUPPORTED,
384 "Target does not support default_action for %1% (due to action profiles)",
389 if (!defact->value->is<IR::ExpressionValue>()) {
390 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected an action", defact);
393 auto expr = defact->value->to<IR::ExpressionValue>()->expression;
394 const IR::P4Action *action =
nullptr;
397 if (expr->is<IR::PathExpression>()) {
398 auto path = expr->to<IR::PathExpression>()->path;
399 auto decl = ctxt->refMap->getDeclaration(path,
true);
400 BUG_CHECK(decl->is<IR::P4Action>(),
"%1%: should be an action name", expr);
401 action = decl->to<IR::P4Action>();
402 }
else if (expr->is<IR::MethodCallExpression>()) {
403 auto mce = expr->to<IR::MethodCallExpression>();
405 BUG_CHECK(mi->is<
P4::ActionCall>(),
"%1%: expected an action", expr);
407 args = mce->arguments;
409 BUG(
"%1%: unexpected expression", expr);
412 unsigned actionid = get(ctxt->structure->ids, action, INVALID_ACTION_ID);
413 BUG_CHECK(actionid != INVALID_ACTION_ID,
"Could not find id for %1%", action);
415 entry->emplace(
"action_id", actionid);
416 entry->emplace(
"action_const", defact->isConstant);
417 auto fields = mkArrayField(entry,
"action_data"_cs);
418 if (args !=
nullptr) {
420 for (
auto a : *args) {
421 if (a->expression->is<IR::Constant>()) {
422 cstring repr = stringRepr(a->expression->to<IR::Constant>()->value);
423 fields->append(repr);
426 "%1%: argument must evaluate to a constant integer", a);
431 entry->emplace(
"action_entry_const", defact->isConstant);
432 result->emplace(
"default_entry", entry);
434 convertTableEntries(table, result);
437 void convertTableEntries(
const IR::P4Table *table,
Util::JsonObject *jsonTable) {
438 auto entriesList = table->getEntries();
439 if (entriesList ==
nullptr)
return;
441 auto entries = mkArrayField(jsonTable,
"entries"_cs);
442 int entryPriority = 1;
443 for (
auto e : entriesList->entries) {
445 entry->emplace_non_null(
"source_info"_cs, e->sourceInfoJsonObj());
447 auto keyset = e->getKeys();
448 auto matchKeys = mkArrayField(entry,
"match_key"_cs);
450 for (
auto k : keyset->components) {
452 auto tableKey = table->getKey()->keyElements.at(keyIndex);
454 if (tableKey->expression->type->is<IR::Type_Error>()) {
458 keyWidth = tableKey->expression->type->width_bits();
460 auto k8 = ROUNDUP(keyWidth, 8);
461 auto matchType = getKeyMatchType(tableKey);
465 if (matchType ==
"optional") {
466 key->emplace(
"match_type",
"ternary");
468 key->emplace(
"match_type", matchType);
470 if (matchType == corelib.exactMatch.name) {
471 if (k->is<IR::Constant>())
472 key->emplace(
"key", stringRepr(k->to<IR::Constant>()->value, k8));
473 else if (k->is<IR::BoolLiteral>())
476 stringRepr(k->to<IR::BoolLiteral>()->value ? 1 : 0, k8));
478 ::P4::error(ErrorType::ERR_UNSUPPORTED,
479 "%1%: unsupported exact key expression", k);
480 }
else if (matchType == corelib.ternaryMatch.name) {
481 if (k->is<IR::Mask>()) {
482 auto km = k->to<IR::Mask>();
483 key->emplace(
"key", stringRepr(km->left->to<IR::Constant>()->value, k8));
484 key->emplace(
"mask", stringRepr(km->right->to<IR::Constant>()->value, k8));
485 }
else if (k->is<IR::Constant>()) {
486 key->emplace(
"key", stringRepr(k->to<IR::Constant>()->value, k8));
487 key->emplace(
"mask", stringRepr(Util::mask(keyWidth), k8));
488 }
else if (k->is<IR::BoolLiteral>()) {
490 stringRepr(k->to<IR::BoolLiteral>()->value ? 1 : 0, k8));
491 key->emplace(
"mask", stringRepr(Util::mask(keyWidth), k8));
492 }
else if (k->is<IR::DefaultExpression>()) {
493 key->emplace(
"key", stringRepr(0, k8));
494 key->emplace(
"mask", stringRepr(0, k8));
497 "%1%: unsupported ternary key expression", k);
499 }
else if (matchType == corelib.lpmMatch.name) {
500 if (k->is<IR::Mask>()) {
501 auto km = k->to<IR::Mask>();
502 key->emplace(
"key", stringRepr(km->left->to<IR::Constant>()->value, k8));
503 auto trailing_zeros = [](
unsigned long n,
unsigned long keyWidth) {
504 return n ? __builtin_ctzl(n) :
static_cast<int>(keyWidth);
506 auto count_ones = [](
unsigned long n) {
507 return n ? __builtin_popcountl(n) : 0;
510 static_cast<unsigned long>(km->right->to<IR::Constant>()->value);
511 auto len = trailing_zeros(mask, keyWidth);
512 if (len + count_ones(mask) != keyWidth)
513 ::P4::error(ErrorType::ERR_INVALID,
"%1%: invalid mask for LPM key", k);
515 key->emplace(
"prefix_length", keyWidth - len);
516 }
else if (k->is<IR::Constant>()) {
517 key->emplace(
"key", stringRepr(k->to<IR::Constant>()->value, k8));
518 key->emplace(
"prefix_length", keyWidth);
519 }
else if (k->is<IR::DefaultExpression>()) {
520 key->emplace(
"key", stringRepr(0, k8));
521 key->emplace(
"prefix_length", 0);
524 "%1%: unsupported LPM key expression", k);
526 }
else if (matchType ==
"range") {
527 if (k->is<IR::Range>()) {
528 auto kr = k->to<IR::Range>();
529 key->emplace(
"start", stringRepr(kr->left->to<IR::Constant>()->value, k8));
530 key->emplace(
"end", stringRepr(kr->right->to<IR::Constant>()->value, k8));
531 }
else if (k->is<IR::Constant>()) {
532 key->emplace(
"start", stringRepr(k->to<IR::Constant>()->value, k8));
533 key->emplace(
"end", stringRepr(k->to<IR::Constant>()->value, k8));
534 }
else if (k->is<IR::DefaultExpression>()) {
535 key->emplace(
"start", stringRepr(0, k8));
536 key->emplace(
"end", stringRepr((1 << keyWidth) - 1, k8));
539 "%1% unsupported range key expression", k);
541 }
else if (matchType ==
"optional") {
549 if (k->is<IR::Constant>()) {
550 key->emplace(
"key", stringRepr(k->to<IR::Constant>()->value, k8));
551 key->emplace(
"mask", stringRepr(Util::mask(keyWidth), k8));
552 }
else if (k->is<IR::DefaultExpression>()) {
553 key->emplace(
"key", stringRepr(0, k8));
554 key->emplace(
"mask", stringRepr(0, k8));
557 "%1%: unsupported optional key expression", k);
560 ::P4::error(ErrorType::ERR_UNKNOWN,
"unknown key match type '%2%' for key %1%",
563 matchKeys->append(key);
568 auto actionRef = e->getAction();
569 if (!actionRef->is<IR::MethodCallExpression>())
570 ::P4::error(ErrorType::ERR_INVALID,
"Invalid action '%1%' in entries list.",
572 auto actionCall = actionRef->to<IR::MethodCallExpression>();
573 auto method = actionCall->method->to<IR::PathExpression>()->path;
574 auto decl = ctxt->refMap->getDeclaration(method,
true);
575 auto actionDecl = decl->to<IR::P4Action>();
576 unsigned id = get(ctxt->structure->ids, actionDecl, INVALID_ACTION_ID);
577 BUG_CHECK(
id != INVALID_ACTION_ID,
"Could not find id for %1%", actionDecl);
578 action->emplace(
"action_id",
id);
579 auto actionData = mkArrayField(action,
"action_data"_cs);
580 for (
auto arg : *actionCall->arguments) {
581 actionData->append(stringRepr(arg->expression->to<IR::Constant>()->value, 0));
583 entry->emplace(
"action_entry", action);
585 if (
auto priorityAnnotation = e->getAnnotation(
"priority"_cs)) {
586 const auto &expr = priorityAnnotation->getExpr();
588 ::P4::error(ErrorType::ERR_INVALID,
"Invalid priority value %1%", expr);
589 auto priValue = expr.front();
590 if (!priValue->is<IR::Constant>())
592 "Invalid priority value %1%; must be constant.", expr);
593 entry->emplace(
"priority", priValue->to<IR::Constant>()->value);
595 entry->emplace(
"priority", entryPriority);
599 entries->append(entry);
602 cstring getKeyMatchType(
const IR::KeyElement *ke) {
603 auto path = ke->matchType->path;
604 auto mt = ctxt->refMap->getDeclaration(path,
true)->to<IR::Declaration_ID>();
605 BUG_CHECK(mt !=
nullptr,
"%1%: could not find declaration", ke->matchType);
607 if (mt->name.name == corelib.exactMatch.name ||
608 mt->name.name == corelib.ternaryMatch.name || mt->name.name == corelib.lpmMatch.name ||
609 ctxt->structure->match_kinds.count(mt->name.name)) {
610 return mt->name.name;
613 ::P4::error(ErrorType::ERR_UNSUPPORTED,
"%1%: match type not supported on this target", mt);
620 if (implementation ==
nullptr) {
621 table->emplace(
"type",
"simple");
625 if (!implementation->value->is<IR::ExpressionValue>()) {
626 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected expression for property",
630 auto propv = implementation->value->to<IR::ExpressionValue>();
632 bool isSimpleTable =
true;
636 if (propv->expression->is<IR::ConstructorCallExpression>()) {
638 P4::ConstructorCall::resolve(propv->expression->to<IR::ConstructorCallExpression>(),
639 ctxt->refMap, ctxt->typeMap);
641 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected extern object for property",
646 auto implementationType = ecc->type;
647 auto arguments = ecc->cce->arguments;
648 apname = implementation->controlPlaneName(ctxt->refMap->newName(
"action_profile"));
650 action_profiles->append(action_profile);
651 action_profile->emplace(
"name", apname);
652 action_profile->emplace(
"id", nextId(
"action_profiles"_cs));
653 action_profile->emplace_non_null(
"source_info"_cs,
654 propv->expression->sourceInfoJsonObj());
658 auto add_size = [&action_profile, &arguments](
size_t arg_index) {
659 auto size_expr = arguments->at(arg_index)->expression;
661 if (!size_expr->is<IR::Constant>()) {
662 ::P4::error(ErrorType::ERR_EXPECTED,
"%1% must be a constant", size_expr);
665 size = size_expr->to<IR::Constant>()->asInt();
667 action_profile->emplace(
"max_size", size);
671 if (implementationType->name == actionSelectorName) {
672 BUG_CHECK(arguments->size() == 3,
"%1%: expected 3 arguments", arguments);
673 isSimpleTable =
false;
675 table->emplace(
"type",
"indirect_ws");
676 action_profile->emplace(
"selector"_cs, selector);
678 auto hash = arguments->at(0)->expression;
682 "%1%: hash must be a constant on this target", hash);
685 selector->emplace(
"algo", algo);
687 auto input = mkArrayField(selector,
"input"_cs);
688 for (
auto ke : key->keyElements) {
689 auto mt = ctxt->refMap->getDeclaration(ke->matchType->path,
true)
690 ->to<IR::Declaration_ID>();
691 BUG_CHECK(mt !=
nullptr,
"%1%: could not find declaration", ke->matchType);
694 auto expr = ke->expression;
695 auto jk = ctxt->conv->convert(expr);
698 }
else if (implementationType->name ==
700 isSimpleTable =
false;
701 table->emplace(
"type",
"indirect");
704 ::P4::error(ErrorType::ERR_UNEXPECTED,
"%1%: expected value for property", propv);
706 }
else if (propv->expression->is<IR::PathExpression>()) {
707 auto pathe = propv->expression->to<IR::PathExpression>();
708 auto decl = ctxt->refMap->getDeclaration(pathe->path,
true);
709 if (!decl->is<IR::Declaration_Instance>()) {
710 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a reference to an instance",
714 apname = decl->controlPlaneName();
715 auto dcltype = ctxt->typeMap->getType(pathe,
true);
716 if (!dcltype->is<IR::Type_Extern>()) {
717 ::P4::error(ErrorType::ERR_UNEXPECTED,
"%1%: unexpected type for implementation",
721 auto type_extern_name = dcltype->to<IR::Type_Extern>()->name;
724 if (type_extern_name == actionProfileName) {
725 table->emplace(
"type",
"indirect");
726 }
else if (type_extern_name == actionSelectorName) {
727 table->emplace(
"type",
"indirect_ws");
729 ::P4::error(ErrorType::ERR_UNEXPECTED,
"%1%: unexpected type for implementation",
733 isSimpleTable =
false;
734 if (ctxt->toplevel->hasValue(decl->getNode())) {
735 auto eb = ctxt->toplevel->getValue(decl->getNode());
736 BUG_CHECK(eb->is<IR::ExternBlock>(),
"Not an extern block?");
737 ExternConverter::cvtExternInstance(ctxt, decl->to<IR::Declaration>(),
738 eb->to<IR::ExternBlock>(), emitExterns);
741 ::P4::error(ErrorType::ERR_UNEXPECTED,
"%1%: unexpected value for property", propv);
744 table->emplace(
"action_profile", apname);
745 return isSimpleTable;
751 result->emplace(
"name", node->name);
752 result->emplace(
"id", nextId(
"conditionals"_cs));
753 result->emplace_non_null(
"source_info"_cs, node->statement->condition->sourceInfoJsonObj());
754 auto j = ctxt->
conv->
convert(node->statement->condition,
true,
false);
756 result->emplace(
"expression"_cs, j);
757 for (
auto e : node->successors.edges) {
759 cstring label = Util::toString(e->getBool());
761 result->emplace(label, dest);
767 const bool emitExterns;
768 bool preorder(
const IR::P4Control *cont)
override {
769 auto result =
new Util::JsonObject();
771 result->emplace(
"name", name);
772 result->emplace(
"id", nextId(
"control"_cs));
773 result->emplace_non_null(
"source_info"_cs, cont->sourceInfoJsonObj());
775 auto cfg =
new CFG();
776 cfg->build(cont, ctxt->
refMap, ctxt->typeMap);
777 bool success = cfg->checkImplementable();
778 if (!success)
return false;
780 if (cfg->entryPoint->successors.size() == 0) {
781 result->emplace(
"init_table", Util::JsonValue::null);
783 BUG_CHECK(cfg->entryPoint->successors.size() == 1,
"Expected 1 start node for %1%",
785 auto start = (*(cfg->entryPoint->successors.edges.begin()))->endpoint;
786 result->emplace(
"init_table", nodeName(start));
789 auto tables = mkArrayField(result,
"tables"_cs);
790 auto action_profiles = mkArrayField(result,
"action_profiles"_cs);
791 auto conditionals = mkArrayField(result,
"conditionals"_cs);
792 ctxt->action_profiles = action_profiles;
794 auto selector_check =
new BMV2::SharedActionSelectorCheck<arch>(ctxt);
795 cont->apply(*selector_check);
797 std::set<const IR::P4Table *> done;
800 for (
auto node : cfg->allNodes) {
801 auto tn = node->
to<CFG::TableNode>();
803 if (done.find(tn->table) != done.end())
808 done.emplace(tn->table);
809 auto j = convertTable(tn, action_profiles, selector_check);
812 }
else if (node->
is<CFG::IfNode>()) {
813 auto j = convertIf(node->
to<CFG::IfNode>(), cont->name);
815 conditionals->append(j);
819 for (
auto c : cont->controlLocals) {
820 if (c->is<IR::Declaration_Constant>() || c->is<IR::Declaration_Variable>() ||
821 c->is<IR::P4Action>() || c->is<IR::P4Table>())
823 if (c->is<IR::Declaration_Instance>()) {
824 auto bl = ctxt->structure->resourceMap.at(c);
826 if (bl->is<IR::ControlBlock>() || bl->is<IR::ParserBlock>())
830 if (bl->is<IR::ExternBlock>()) {
831 auto eb = bl->to<IR::ExternBlock>();
832 ExternConverter::cvtExternInstance(ctxt, c, eb, emitExterns);
836 P4C_UNIMPLEMENTED(
"%1%: not yet handled", c);
839 ctxt->json->pipelines->append(result);
843 explicit ControlConverter(ConversionContext *ctxt, cstring name,
const bool &emitExterns_)
846 corelib(P4::P4CoreLibrary::instance()),
847 emitExterns(emitExterns_) {
848 setName(
"ControlConverter");