void ControlConverter::convertTableEntries()

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);
    }
}