in flexsai/p4/backend/json_stage/control.cpp [24:139]
void ControlConverter::convertTableEntries(const IR::P4Table *table,
Util::JsonObject *jsonTable) {
auto entriesList = table->getEntries();
if (entriesList == nullptr) return;
auto entries = mkArrayField(jsonTable, "entries");
int entryPriority = 1; // default priority is defined by index position
for (auto e : entriesList->entries) {
// TODO(jafingerhut) - add line/col here?
auto entry = new Util::JsonObject();
auto keyset = e->getKeys();
auto matchKeys = mkArrayField(entry, "match_key");
int keyIndex = 0;
for (auto k : keyset->components) {
auto key = new Util::JsonObject();
auto tableKey = table->getKey()->keyElements.at(keyIndex);
auto keyWidth = tableKey->expression->type->width_bits();
auto k8 = ROUNDUP(keyWidth, 8);
auto matchType = getKeyMatchType(tableKey);
key->emplace("match_type", matchType);
if (matchType == backend->getCoreLibrary().exactMatch.name) {
if (k->is<IR::Constant>())
key->emplace("key", stringRepr(k->to<IR::Constant>()->value, k8));
else if (k->is<IR::BoolLiteral>())
// booleans are converted to ints
key->emplace("key", stringRepr(k->to<IR::BoolLiteral>()->value ? 1 : 0, k8));
else
::error("%1% unsupported exact key expression", k);
} else if (matchType == backend->getCoreLibrary().ternaryMatch.name) {
if (k->is<IR::Mask>()) {
auto km = k->to<IR::Mask>();
key->emplace("key", stringRepr(km->left->to<IR::Constant>()->value, k8));
key->emplace("mask", stringRepr(km->right->to<IR::Constant>()->value, k8));
} else if (k->is<IR::Constant>()) {
key->emplace("key", stringRepr(k->to<IR::Constant>()->value, k8));
key->emplace("mask", stringRepr(Util::mask(keyWidth), k8));
} else if (k->is<IR::DefaultExpression>()) {
key->emplace("key", stringRepr(0, k8));
key->emplace("mask", stringRepr(0, k8));
} else {
::error("%1% unsupported ternary key expression", k);
}
// FIXME: ALAN CUSTOM table key offsets
} else if (matchType == backend->getCoreLibrary().lpmMatch.name) {
if (k->is<IR::Mask>()) {
auto km = k->to<IR::Mask>();
key->emplace("key", stringRepr(km->left->to<IR::Constant>()->value, k8));
auto trailing_zeros = [](unsigned long n) { return n ? __builtin_ctzl(n) : 0; };
auto count_ones = [](unsigned long n) { return n ? __builtin_popcountl(n) : 0;};
unsigned long mask = km->right->to<IR::Constant>()->value.get_ui();
auto len = trailing_zeros(mask);
if (len + count_ones(mask) != keyWidth) // any remaining 0s in the prefix?
::error("%1% invalid mask for LPM key", k);
else
key->emplace("prefix_length", keyWidth - len);
} else if (k->is<IR::Constant>()) {
key->emplace("key", stringRepr(k->to<IR::Constant>()->value, k8));
key->emplace("prefix_length", keyWidth);
} else if (k->is<IR::DefaultExpression>()) {
key->emplace("key", stringRepr(0, k8));
key->emplace("prefix_length", 0);
} else {
::error("%1% unsupported LPM key expression", k);
}
} else if (matchType == "range") {
if (k->is<IR::Range>()) {
auto kr = k->to<IR::Range>();
key->emplace("start", stringRepr(kr->left->to<IR::Constant>()->value, k8));
key->emplace("end", stringRepr(kr->right->to<IR::Constant>()->value, k8));
} else if (k->is<IR::DefaultExpression>()) {
key->emplace("start", stringRepr(0, k8));
key->emplace("end", stringRepr((1 << keyWidth)-1, k8)); // 2^N -1
} else {
::error("%1% invalid range key expression", k);
}
} else {
::error("unkown key match type '%1%' for key %2%", matchType, k);
}
matchKeys->append(key);
keyIndex++;
}
auto action = new Util::JsonObject();
auto actionRef = e->getAction();
if (!actionRef->is<IR::MethodCallExpression>())
::error("%1%: invalid action in entries list", actionRef);
auto actionCall = actionRef->to<IR::MethodCallExpression>();
auto method = actionCall->method->to<IR::PathExpression>()->path;
auto decl = refMap->getDeclaration(method, true);
auto actionDecl = decl->to<IR::P4Action>();
unsigned id = get(backend->getStructure().ids, actionDecl);
action->emplace("action_id", id);
auto actionData = mkArrayField(action, "action_data");
for (auto arg : *actionCall->arguments) {
actionData->append(stringRepr(arg->to<IR::Constant>()->value, 0));
}
entry->emplace("action_entry", action);
auto priorityAnnotation = e->getAnnotation("priority");
if (priorityAnnotation != nullptr) {
if (priorityAnnotation->expr.size() > 1)
::error("invalid priority value %1%", priorityAnnotation->expr);
auto priValue = priorityAnnotation->expr.front();
if (!priValue->is<IR::Constant>())
::error("invalid priority value %1%. must be constant", priorityAnnotation->expr);
entry->emplace("priority", priValue->to<IR::Constant>()->value);
} else {
entry->emplace("priority", entryPriority);
}
entryPriority += 1;
entries->append(entry);
}
}