30class ControlConverter :
public Inspector {
38 auto table = node->table;
39 LOG3(
"Processing " << dbp(table));
41 cstring name = table->controlPlaneName();
42 result->emplace(
"name", name);
43 result->emplace(
"id", nextId(
"tables"_cs));
44 result->emplace_non_null(
"source_info"_cs, table->sourceInfoJsonObj());
45 cstring table_match_type = corelib.exactMatch.name;
46 auto key = table->getKey();
47 auto tkey = mkArrayField(result,
"key"_cs);
48 ctxt->conv->simpleExpressionsOnly =
true;
52 for (
auto ke : key->keyElements) {
53 auto expr = ke->expression;
54 auto ket = ctxt->typeMap->getType(expr,
true);
55 if (!ket->is<IR::Type_Bits>() && !ket->is<IR::Type_Boolean>() &&
56 !ket->is<IR::Type_Error>())
58 "%1%: unsupporded key type %2%. "
59 "Supported key types are be bit<> or boolean, or error.",
62 auto match_type = getKeyMatchType(ke);
70 if (match_type == corelib.lpmMatch.name) count_lpm++;
73 "multiple LPM keys in table %1% not supported", table);
74 if (match_type != table_match_type) {
75 if (match_type == BMV2::MatchImplementation::rangeMatchTypeName)
76 table_match_type = BMV2::MatchImplementation::rangeMatchTypeName;
77 if ((match_type == corelib.ternaryMatch.name ||
78 match_type == BMV2::MatchImplementation::optionalMatchTypeName) &&
79 table_match_type != BMV2::MatchImplementation::rangeMatchTypeName)
80 table_match_type = corelib.ternaryMatch.name;
81 if (match_type == corelib.lpmMatch.name &&
82 table_match_type == corelib.exactMatch.name)
83 table_match_type = corelib.lpmMatch.name;
87 if (
auto mexp = expr->to<IR::BAnd>()) {
88 if (mexp->right->is<IR::Constant>()) {
89 mask = mexp->right->to<IR::Constant>()->value;
91 }
else if (mexp->left->is<IR::Constant>()) {
92 mask = mexp->left->to<IR::Constant>()->value;
95 ::P4::error(ErrorType::ERR_EXPECTED,
"%1% must be a constant", expr);
97 }
else if (
auto slice = expr->to<IR::Slice>()) {
99 int h = slice->getH();
100 int l = slice->getL();
101 mask = Util::maskFromSlice(h, l);
108 if (match_type == BMV2::MatchImplementation::optionalMatchTypeName) {
109 keyelement->emplace(
"match_type", corelib.ternaryMatch.name);
111 keyelement->emplace(
"match_type", match_type);
113 if (
auto na = ke->getAnnotation(IR::Annotation::nameAnnotation)) {
114 BUG_CHECK(na->getExpr().size() == 1,
"%1%: expected 1 name", na);
115 auto name = na->getExpr(0)->to<IR::StringLiteral>();
116 BUG_CHECK(name !=
nullptr,
"%1%: expected a string", na);
119 keyelement->emplace(
"name", name->value);
122 auto jk = ctxt->conv->convert(expr);
125 keyelement->emplace(
"mask",
126 stringRepr(mask, ROUNDUP(expr->type->width_bits(), 8)));
128 keyelement->emplace(
"mask", Util::JsonValue::null);
129 tkey->append(keyelement);
132 LOG3(
"table_match_type: " << table_match_type);
133 result->emplace(
"match_type", table_match_type);
134 ctxt->conv->simpleExpressionsOnly =
false;
137 auto impl = table->properties->getProperty(propertyName);
141 auto sz = table->properties->getProperty(
"size");
143 if (sz->value->is<IR::ExpressionValue>()) {
144 auto expr = sz->value->to<IR::ExpressionValue>()->expression;
145 if (!expr->is<IR::Constant>()) {
146 ::P4::error(ErrorType::ERR_EXPECTED,
"%1% must be a constant", sz);
149 size = expr->to<IR::Constant>()->asInt();
152 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a number", sz);
155 if (
auto entries = table->getEntries()) {
156 size = entries->entries.size();
158 if (size == 0) size = BMV2::TableAttributes::defaultTableSize;
160 result->emplace(
"max_size", size);
161 auto ctrs = table->properties->getProperty(
"counters");
162 if (ctrs !=
nullptr) {
166 if (ctrs->value->is<IR::ExpressionValue>()) {
167 auto expr = ctrs->value->to<IR::ExpressionValue>()->expression;
168 if (expr->is<IR::ConstructorCallExpression>()) {
169 auto type = ctxt->typeMap->getType(expr,
true);
170 if (type ==
nullptr)
return result;
171 if (!type->is<IR::Type_Extern>()) {
173 "%1%: Unexpected type %2% for property. "
178 auto te = type->to<IR::Type_Extern>();
179 if (te->name !=
"direct_counter" && te->name !=
"counter") {
181 "%1%: Unexpected type %2% for property. "
182 "Must be 'counter' or 'direct_counter'.",
187 cstring ctrname = ctrs->controlPlaneName(
"counter"_cs);
188 jctr->emplace(
"name", ctrname);
189 jctr->emplace(
"id", nextId(
"counter_arrays"_cs));
190 jctr->emplace_non_null(
"source_info"_cs, ctrs->sourceInfoJsonObj());
193 bool direct = te->name ==
"direct_counter";
194 jctr->emplace(
"is_direct", direct);
195 jctr->emplace(
"binding", table->controlPlaneName());
196 ctxt->json->counters->append(jctr);
197 }
else if (expr->is<IR::PathExpression>()) {
198 auto pe = expr->to<IR::PathExpression>();
199 auto decl = ctxt->refMap->getDeclaration(pe->path,
true);
200 if (!decl->is<IR::Declaration_Instance>()) {
201 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected an instance",
205 cstring ctrname = decl->controlPlaneName();
206 auto it = ctxt->structure->directCounterMap.find(ctrname);
207 LOG3(
"Looking up " << ctrname);
208 if (it != ctxt->structure->directCounterMap.end()) {
210 "%1%: Direct counters cannot be attached to multiple tables"
212 decl, it->second, table);
215 ctxt->structure->directCounterMap.emplace(ctrname, table);
217 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a counter", ctrs);
220 result->emplace(
"with_counters",
true);
222 result->emplace(
"with_counters",
false);
226 auto timeout = table->properties->getProperty(
"support_timeout");
227 if (timeout !=
nullptr) {
228 if (timeout->value->is<IR::ExpressionValue>()) {
229 auto expr = timeout->value->to<IR::ExpressionValue>()->expression;
230 if (!expr->is<IR::BoolLiteral>()) {
231 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: must true/false", timeout);
233 sup_to = expr->to<IR::BoolLiteral>()->value;
236 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a Boolean", timeout);
239 result->emplace(
"support_timeout", sup_to);
241 auto dm = table->properties->getProperty(
"meters");
243 if (dm->value->is<IR::ExpressionValue>()) {
244 auto expr = dm->value->to<IR::ExpressionValue>()->expression;
245 if (!expr->is<IR::PathExpression>()) {
247 "%1%: expected a reference to a meter declaration", expr);
249 auto pe = expr->to<IR::PathExpression>();
250 auto decl = ctxt->refMap->getDeclaration(pe->path,
true);
251 auto type = ctxt->typeMap->getType(expr,
true);
252 if (type ==
nullptr)
return result;
253 if (type->is<IR::Type_SpecializedCanonical>())
254 type = type->to<IR::Type_SpecializedCanonical>()->baseType;
255 if (!type->is<IR::Type_Extern>()) {
257 "%1%: Unexpected type %2% for property", dm, type);
260 auto te = type->to<IR::Type_Extern>();
261 if (te->name !=
"direct_meter") {
263 "%1%: Unexpected type %2% for property", dm, type);
266 if (!decl->is<IR::Declaration_Instance>()) {
267 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected an instance",
271 ctxt->structure->directMeterMap.setTable(decl, table);
272 ctxt->structure->directMeterMap.setSize(decl, size);
273 BUG_CHECK(decl->is<IR::Declaration_Instance>(),
"%1%: expected an instance",
275 cstring name = decl->controlPlaneName();
276 result->emplace(
"direct_meters", name);
279 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a meter", dm);
282 result->emplace(
"direct_meters", Util::JsonValue::null);
285 auto action_ids = mkArrayField(result,
"action_ids"_cs);
286 auto actions = mkArrayField(result,
"actions"_cs);
287 auto al = table->getActionList();
289 std::map<cstring, cstring> useActionName;
290 for (
auto a : al->actionList) {
291 if (a->expression->is<IR::MethodCallExpression>()) {
292 auto mce = a->expression->to<IR::MethodCallExpression>();
293 if (mce->arguments->size() > 0)
295 "%1%: actions in action list with arguments not supported", a);
297 auto decl = ctxt->refMap->getDeclaration(a->getPath(),
true);
298 BUG_CHECK(decl->is<IR::P4Action>(),
"%1%: should be an action name", a);
299 auto action = decl->to<IR::P4Action>();
300 unsigned id = get(ctxt->structure->ids, action, INVALID_ACTION_ID);
301 LOG3(
"look up id " << action <<
" " <<
id);
302 BUG_CHECK(
id != INVALID_ACTION_ID,
"Could not find id for %1%", action);
303 action_ids->append(
id);
304 auto name = action->controlPlaneName();
305 actions->append(name);
306 useActionName.emplace(action->name, name);
312 CFG::Node *defaultLabelDestination =
nullptr;
314 bool hitMiss =
false;
315 for (
auto s : node->successors.edges) {
316 if (s->isUnconditional()) {
317 nextDestination = s->endpoint;
318 LOG3(
"nextDestination " << s->endpoint);
319 }
else if (s->isBool()) {
322 }
else if (s->label ==
"default") {
323 defaultLabelDestination = s->endpoint;
324 LOG3(
"default " << s->endpoint);
330 BUG_CHECK(nextDestination,
"Could not find default destination for %1%",
332 nextLabel = nodeName(nextDestination);
333 result->emplace(
"base_default_next", nextLabel);
336 if (defaultLabelDestination !=
nullptr) nextLabel = nodeName(defaultLabelDestination);
338 result->emplace(
"base_default_next", Util::JsonValue::null);
341 std::set<cstring> labelsDone;
342 for (
auto s : node->successors.edges) {
345 label = s->getBool() ?
"__HIT__"_cs :
"__MISS__"_cs;
346 }
else if (s->isUnconditional()) {
350 if (label ==
"default")
continue;
351 label = ::P4::get(useActionName, label);
353 next_tables->emplace(label, nodeName(s->endpoint));
354 labelsDone.emplace(label);
360 for (
auto a : al->actionList) {
361 cstring name = a->getName().name;
362 cstring label = ::P4::get(useActionName, name);
363 if (labelsDone.find(label) == labelsDone.end())
364 next_tables->emplace(label, nextLabel);
368 result->emplace(
"next_tables", next_tables);
370 table->properties->getProperty(IR::TableProperties::defaultActionPropertyName);
371 if (defact !=
nullptr) {
374 ErrorType::WARN_UNSUPPORTED,
375 "Target does not support default_action for %1% (due to action profiles)",
380 if (!defact->value->is<IR::ExpressionValue>()) {
381 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected an action", defact);
384 auto expr = defact->value->to<IR::ExpressionValue>()->expression;
385 const IR::P4Action *action =
nullptr;
388 if (expr->is<IR::PathExpression>()) {
389 auto path = expr->to<IR::PathExpression>()->path;
390 auto decl = ctxt->refMap->getDeclaration(path,
true);
391 BUG_CHECK(decl->is<IR::P4Action>(),
"%1%: should be an action name", expr);
392 action = decl->to<IR::P4Action>();
393 }
else if (expr->is<IR::MethodCallExpression>()) {
394 auto mce = expr->to<IR::MethodCallExpression>();
396 BUG_CHECK(mi->is<
P4::ActionCall>(),
"%1%: expected an action", expr);
398 args = mce->arguments;
400 BUG(
"%1%: unexpected expression", expr);
403 unsigned actionid = get(ctxt->structure->ids, action, INVALID_ACTION_ID);
404 BUG_CHECK(actionid != INVALID_ACTION_ID,
"Could not find id for %1%", action);
406 entry->emplace(
"action_id", actionid);
407 entry->emplace(
"action_const", defact->isConstant);
408 auto fields = mkArrayField(entry,
"action_data"_cs);
409 if (args !=
nullptr) {
411 for (
auto a : *args) {
412 if (a->expression->is<IR::Constant>()) {
413 cstring repr = stringRepr(a->expression->to<IR::Constant>()->value);
414 fields->append(repr);
417 "%1%: argument must evaluate to a constant integer", a);
422 entry->emplace(
"action_entry_const", defact->isConstant);
423 result->emplace(
"default_entry", entry);
425 convertTableEntries(table, result);
428 void convertTableEntries(
const IR::P4Table *table,
Util::JsonObject *jsonTable) {
429 auto entriesList = table->getEntries();
430 if (entriesList ==
nullptr)
return;
432 auto entries = mkArrayField(jsonTable,
"entries"_cs);
433 int entryPriority = 1;
434 for (
auto e : entriesList->entries) {
436 entry->emplace_non_null(
"source_info"_cs, e->sourceInfoJsonObj());
438 auto keyset = e->getKeys();
439 auto matchKeys = mkArrayField(entry,
"match_key"_cs);
441 for (
auto k : keyset->components) {
443 auto tableKey = table->getKey()->keyElements.at(keyIndex);
445 if (tableKey->expression->type->is<IR::Type_Error>()) {
449 keyWidth = tableKey->expression->type->width_bits();
451 auto k8 = ROUNDUP(keyWidth, 8);
452 auto matchType = getKeyMatchType(tableKey);
456 if (matchType ==
"optional") {
457 key->emplace(
"match_type",
"ternary");
459 key->emplace(
"match_type", matchType);
461 if (matchType == corelib.exactMatch.name) {
462 if (k->is<IR::Constant>())
463 key->emplace(
"key", stringRepr(k->to<IR::Constant>()->value, k8));
464 else if (k->is<IR::BoolLiteral>())
467 stringRepr(k->to<IR::BoolLiteral>()->value ? 1 : 0, k8));
469 ::P4::error(ErrorType::ERR_UNSUPPORTED,
470 "%1%: unsupported exact key expression", k);
471 }
else if (matchType == corelib.ternaryMatch.name) {
472 if (k->is<IR::Mask>()) {
473 auto km = k->to<IR::Mask>();
474 key->emplace(
"key", stringRepr(km->left->to<IR::Constant>()->value, k8));
475 key->emplace(
"mask", stringRepr(km->right->to<IR::Constant>()->value, k8));
476 }
else if (k->is<IR::Constant>()) {
477 key->emplace(
"key", stringRepr(k->to<IR::Constant>()->value, k8));
478 key->emplace(
"mask", stringRepr(Util::mask(keyWidth), k8));
479 }
else if (k->is<IR::BoolLiteral>()) {
481 stringRepr(k->to<IR::BoolLiteral>()->value ? 1 : 0, k8));
482 key->emplace(
"mask", stringRepr(Util::mask(keyWidth), k8));
483 }
else if (k->is<IR::DefaultExpression>()) {
484 key->emplace(
"key", stringRepr(0, k8));
485 key->emplace(
"mask", stringRepr(0, k8));
488 "%1%: unsupported ternary key expression", k);
490 }
else if (matchType == corelib.lpmMatch.name) {
491 if (k->is<IR::Mask>()) {
492 auto km = k->to<IR::Mask>();
493 key->emplace(
"key", stringRepr(km->left->to<IR::Constant>()->value, k8));
494 auto trailing_zeros = [](
unsigned long n,
unsigned long keyWidth) {
495 return n ? __builtin_ctzl(n) :
static_cast<int>(keyWidth);
497 auto count_ones = [](
unsigned long n) {
498 return n ? __builtin_popcountl(n) : 0;
501 static_cast<unsigned long>(km->right->to<IR::Constant>()->value);
502 auto len = trailing_zeros(mask, keyWidth);
503 if (len + count_ones(mask) != keyWidth)
504 ::P4::error(ErrorType::ERR_INVALID,
"%1%: invalid mask for LPM key", k);
506 key->emplace(
"prefix_length", keyWidth - len);
507 }
else if (k->is<IR::Constant>()) {
508 key->emplace(
"key", stringRepr(k->to<IR::Constant>()->value, k8));
509 key->emplace(
"prefix_length", keyWidth);
510 }
else if (k->is<IR::DefaultExpression>()) {
511 key->emplace(
"key", stringRepr(0, k8));
512 key->emplace(
"prefix_length", 0);
515 "%1%: unsupported LPM key expression", k);
517 }
else if (matchType ==
"range") {
518 if (k->is<IR::Range>()) {
519 auto kr = k->to<IR::Range>();
520 key->emplace(
"start", stringRepr(kr->left->to<IR::Constant>()->value, k8));
521 key->emplace(
"end", stringRepr(kr->right->to<IR::Constant>()->value, k8));
522 }
else if (k->is<IR::Constant>()) {
523 key->emplace(
"start", stringRepr(k->to<IR::Constant>()->value, k8));
524 key->emplace(
"end", stringRepr(k->to<IR::Constant>()->value, k8));
525 }
else if (k->is<IR::DefaultExpression>()) {
526 key->emplace(
"start", stringRepr(0, k8));
527 key->emplace(
"end", stringRepr((1 << keyWidth) - 1, k8));
530 "%1% unsupported range key expression", k);
532 }
else if (matchType ==
"optional") {
540 if (k->is<IR::Constant>()) {
541 key->emplace(
"key", stringRepr(k->to<IR::Constant>()->value, k8));
542 key->emplace(
"mask", stringRepr(Util::mask(keyWidth), k8));
543 }
else if (k->is<IR::DefaultExpression>()) {
544 key->emplace(
"key", stringRepr(0, k8));
545 key->emplace(
"mask", stringRepr(0, k8));
548 "%1%: unsupported optional key expression", k);
551 ::P4::error(ErrorType::ERR_UNKNOWN,
"unknown key match type '%2%' for key %1%",
554 matchKeys->append(key);
559 auto actionRef = e->getAction();
560 if (!actionRef->is<IR::MethodCallExpression>())
561 ::P4::error(ErrorType::ERR_INVALID,
"Invalid action '%1%' in entries list.",
563 auto actionCall = actionRef->to<IR::MethodCallExpression>();
564 auto method = actionCall->method->to<IR::PathExpression>()->path;
565 auto decl = ctxt->refMap->getDeclaration(method,
true);
566 auto actionDecl = decl->to<IR::P4Action>();
567 unsigned id = get(ctxt->structure->ids, actionDecl, INVALID_ACTION_ID);
568 BUG_CHECK(
id != INVALID_ACTION_ID,
"Could not find id for %1%", actionDecl);
569 action->emplace(
"action_id",
id);
570 auto actionData = mkArrayField(action,
"action_data"_cs);
571 for (
auto arg : *actionCall->arguments) {
572 actionData->append(stringRepr(arg->expression->to<IR::Constant>()->value, 0));
574 entry->emplace(
"action_entry", action);
576 if (
auto priorityAnnotation = e->getAnnotation(
"priority"_cs)) {
577 const auto &expr = priorityAnnotation->getExpr();
579 ::P4::error(ErrorType::ERR_INVALID,
"Invalid priority value %1%", expr);
580 auto priValue = expr.front();
581 if (!priValue->is<IR::Constant>())
583 "Invalid priority value %1%; must be constant.", expr);
584 entry->emplace(
"priority", priValue->to<IR::Constant>()->value);
586 entry->emplace(
"priority", entryPriority);
590 entries->append(entry);
593 cstring getKeyMatchType(
const IR::KeyElement *ke) {
594 auto path = ke->matchType->path;
595 auto mt = ctxt->refMap->getDeclaration(path,
true)->to<IR::Declaration_ID>();
596 BUG_CHECK(mt !=
nullptr,
"%1%: could not find declaration", ke->matchType);
598 if (mt->name.name == corelib.exactMatch.name ||
599 mt->name.name == corelib.ternaryMatch.name || mt->name.name == corelib.lpmMatch.name ||
600 ctxt->structure->match_kinds.count(mt->name.name)) {
601 return mt->name.name;
604 ::P4::error(ErrorType::ERR_UNSUPPORTED,
"%1%: match type not supported on this target", mt);
611 if (implementation ==
nullptr) {
612 table->emplace(
"type",
"simple");
616 if (!implementation->value->is<IR::ExpressionValue>()) {
617 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected expression for property",
621 auto propv = implementation->value->to<IR::ExpressionValue>();
623 bool isSimpleTable =
true;
627 if (propv->expression->is<IR::ConstructorCallExpression>()) {
629 P4::ConstructorCall::resolve(propv->expression->to<IR::ConstructorCallExpression>(),
630 ctxt->refMap, ctxt->typeMap);
632 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected extern object for property",
637 auto implementationType = ecc->type;
638 auto arguments = ecc->cce->arguments;
639 apname = implementation->controlPlaneName(ctxt->refMap->newName(
"action_profile"));
641 action_profiles->append(action_profile);
642 action_profile->emplace(
"name", apname);
643 action_profile->emplace(
"id", nextId(
"action_profiles"_cs));
644 action_profile->emplace_non_null(
"source_info"_cs,
645 propv->expression->sourceInfoJsonObj());
649 auto add_size = [&action_profile, &arguments](
size_t arg_index) {
650 auto size_expr = arguments->at(arg_index)->expression;
652 if (!size_expr->is<IR::Constant>()) {
653 ::P4::error(ErrorType::ERR_EXPECTED,
"%1% must be a constant", size_expr);
656 size = size_expr->to<IR::Constant>()->asInt();
658 action_profile->emplace(
"max_size", size);
662 if (implementationType->name == actionSelectorName) {
663 BUG_CHECK(arguments->size() == 3,
"%1%: expected 3 arguments", arguments);
664 isSimpleTable =
false;
666 table->emplace(
"type",
"indirect_ws");
667 action_profile->emplace(
"selector"_cs, selector);
669 auto hash = arguments->at(0)->expression;
673 "%1%: hash must be a constant on this target", hash);
676 selector->emplace(
"algo", algo);
678 auto input = mkArrayField(selector,
"input"_cs);
679 for (
auto ke : key->keyElements) {
680 auto mt = ctxt->refMap->getDeclaration(ke->matchType->path,
true)
681 ->to<IR::Declaration_ID>();
682 BUG_CHECK(mt !=
nullptr,
"%1%: could not find declaration", ke->matchType);
685 auto expr = ke->expression;
686 auto jk = ctxt->conv->convert(expr);
689 }
else if (implementationType->name ==
691 isSimpleTable =
false;
692 table->emplace(
"type",
"indirect");
695 ::P4::error(ErrorType::ERR_UNEXPECTED,
"%1%: expected value for property", propv);
697 }
else if (propv->expression->is<IR::PathExpression>()) {
698 auto pathe = propv->expression->to<IR::PathExpression>();
699 auto decl = ctxt->refMap->getDeclaration(pathe->path,
true);
700 if (!decl->is<IR::Declaration_Instance>()) {
701 ::P4::error(ErrorType::ERR_EXPECTED,
"%1%: expected a reference to an instance",
705 apname = decl->controlPlaneName();
706 auto dcltype = ctxt->typeMap->getType(pathe,
true);
707 if (!dcltype->is<IR::Type_Extern>()) {
708 ::P4::error(ErrorType::ERR_UNEXPECTED,
"%1%: unexpected type for implementation",
712 auto type_extern_name = dcltype->to<IR::Type_Extern>()->name;
715 if (type_extern_name == actionProfileName) {
716 table->emplace(
"type",
"indirect");
717 }
else if (type_extern_name == actionSelectorName) {
718 table->emplace(
"type",
"indirect_ws");
720 ::P4::error(ErrorType::ERR_UNEXPECTED,
"%1%: unexpected type for implementation",
724 isSimpleTable =
false;
725 if (ctxt->toplevel->hasValue(decl->getNode())) {
726 auto eb = ctxt->toplevel->getValue(decl->getNode());
727 BUG_CHECK(eb->is<IR::ExternBlock>(),
"Not an extern block?");
728 ExternConverter::cvtExternInstance(ctxt, decl->to<IR::Declaration>(),
729 eb->to<IR::ExternBlock>(), emitExterns);
732 ::P4::error(ErrorType::ERR_UNEXPECTED,
"%1%: unexpected value for property", propv);
735 table->emplace(
"action_profile", apname);
736 return isSimpleTable;
742 result->emplace(
"name", node->name);
743 result->emplace(
"id", nextId(
"conditionals"_cs));
744 result->emplace_non_null(
"source_info"_cs, node->statement->condition->sourceInfoJsonObj());
745 auto j = ctxt->
conv->
convert(node->statement->condition,
true,
false);
747 result->emplace(
"expression"_cs, j);
748 for (
auto e : node->successors.edges) {
750 cstring label = Util::toString(e->getBool());
752 result->emplace(label, dest);
758 const bool emitExterns;
759 bool preorder(
const IR::P4Control *cont)
override {
760 auto result =
new Util::JsonObject();
762 result->emplace(
"name", name);
763 result->emplace(
"id", nextId(
"control"_cs));
764 result->emplace_non_null(
"source_info"_cs, cont->sourceInfoJsonObj());
766 auto cfg =
new CFG();
767 cfg->build(cont, ctxt->
refMap, ctxt->typeMap);
768 bool success = cfg->checkImplementable();
769 if (!success)
return false;
771 if (cfg->entryPoint->successors.size() == 0) {
772 result->emplace(
"init_table", Util::JsonValue::null);
774 BUG_CHECK(cfg->entryPoint->successors.size() == 1,
"Expected 1 start node for %1%",
776 auto start = (*(cfg->entryPoint->successors.edges.begin()))->endpoint;
777 result->emplace(
"init_table", nodeName(start));
780 auto tables = mkArrayField(result,
"tables"_cs);
781 auto action_profiles = mkArrayField(result,
"action_profiles"_cs);
782 auto conditionals = mkArrayField(result,
"conditionals"_cs);
783 ctxt->action_profiles = action_profiles;
785 auto selector_check =
new BMV2::SharedActionSelectorCheck<arch>(ctxt);
786 cont->apply(*selector_check);
788 std::set<const IR::P4Table *> done;
791 for (
auto node : cfg->allNodes) {
792 auto tn = node->
to<CFG::TableNode>();
794 if (done.find(tn->table) != done.end())
799 done.emplace(tn->table);
800 auto j = convertTable(tn, action_profiles, selector_check);
803 }
else if (node->
is<CFG::IfNode>()) {
804 auto j = convertIf(node->
to<CFG::IfNode>(), cont->name);
806 conditionals->append(j);
810 for (
auto c : cont->controlLocals) {
811 if (c->is<IR::Declaration_Constant>() || c->is<IR::Declaration_Variable>() ||
812 c->is<IR::P4Action>() || c->is<IR::P4Table>())
814 if (c->is<IR::Declaration_Instance>()) {
815 auto bl = ctxt->structure->resourceMap.at(c);
817 if (bl->is<IR::ControlBlock>() || bl->is<IR::ParserBlock>())
821 if (bl->is<IR::ExternBlock>()) {
822 auto eb = bl->to<IR::ExternBlock>();
823 ExternConverter::cvtExternInstance(ctxt, c, eb, emitExterns);
827 P4C_UNIMPLEMENTED(
"%1%: not yet handled", c);
830 ctxt->json->pipelines->append(result);
834 explicit ControlConverter(ConversionContext *ctxt, cstring name,
const bool &emitExterns_)
837 corelib(P4::P4CoreLibrary::instance()),
838 emitExterns(emitExterns_) {
839 setName(
"ControlConverter");