diff --git a/backends/bmv2/common/control.h b/backends/bmv2/common/control.h index d9a8d196a6c..87c18a4ea4e 100644 --- a/backends/bmv2/common/control.h +++ b/backends/bmv2/common/control.h @@ -120,8 +120,8 @@ class ControlConverter : public Inspector { keyelement->emplace("match_type", match_type); } if (auto na = ke->getAnnotation(IR::Annotation::nameAnnotation)) { - BUG_CHECK(na->expr.size() == 1, "%1%: expected 1 name", na); - auto name = na->expr[0]->to(); + BUG_CHECK(na->getExpr().size() == 1, "%1%: expected 1 name", na); + auto name = na->getExpr(0)->to(); BUG_CHECK(name != nullptr, "%1%: expected a string", na); // This is a BMv2 JSON extension: specify a // control-plane name for this key @@ -578,16 +578,14 @@ class ControlConverter : public Inspector { } entry->emplace("action_entry", action); - auto priorityAnnotation = e->getAnnotation("priority"_cs); - if (priorityAnnotation != nullptr) { - if (priorityAnnotation->expr.size() > 1) - ::P4::error(ErrorType::ERR_INVALID, "Invalid priority value %1%", - priorityAnnotation->expr); - auto priValue = priorityAnnotation->expr.front(); + if (auto priorityAnnotation = e->getAnnotation("priority"_cs)) { + const auto &expr = priorityAnnotation->getExpr(); + if (expr.size() > 1) + ::P4::error(ErrorType::ERR_INVALID, "Invalid priority value %1%", expr); + auto priValue = expr.front(); if (!priValue->is()) ::P4::error(ErrorType::ERR_INVALID, - "Invalid priority value %1%; must be constant.", - priorityAnnotation->expr); + "Invalid priority value %1%; must be constant.", expr); entry->emplace("priority", priValue->to()->value); } else { entry->emplace("priority", entryPriority); diff --git a/backends/bmv2/common/header.cpp b/backends/bmv2/common/header.cpp index 48bc6055ddd..e8ccb934382 100644 --- a/backends/bmv2/common/header.cpp +++ b/backends/bmv2/common/header.cpp @@ -292,10 +292,10 @@ void HeaderConverter::addHeaderType(const IR::Type_StructLike *st) { auto alias = new Util::JsonArray(); cstring target_name; if (BMV2Context::get().options().loadIRFromJson == false) { - target_name = aliasAnnotation->expr.front()->to()->value; + target_name = aliasAnnotation->getExpr().front()->to()->value; } else { - if (aliasAnnotation->body.size() != 0) { - target_name = aliasAnnotation->body.at(0)->text; + if (aliasAnnotation->getUnparsed().size() != 0) { + target_name = aliasAnnotation->getUnparsed().at(0)->text; } else { // aliasAnnotation->body is empty or not saved correctly ::P4::error(ErrorType::ERR_INVALID, diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index 815eeda4849..23628091663 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -515,7 +515,7 @@ void ParserConverter::addValueSets(const IR::P4Parser *parser) { auto isExactMatch = [this](const IR::StructField *sf) { auto matchAnnotation = sf->getAnnotation(IR::Annotation::matchAnnotation); if (!matchAnnotation) return true; // default (missing annotation) is exact - auto matchPathExpr = matchAnnotation->expr[0]->to(); + auto matchPathExpr = matchAnnotation->getExpr(0)->to(); CHECK_NULL(matchPathExpr); auto matchTypeDecl = ctxt->refMap->getDeclaration(matchPathExpr->path, true)->to(); diff --git a/backends/bmv2/simple_switch/simpleSwitch.cpp b/backends/bmv2/simple_switch/simpleSwitch.cpp index fd100807e4d..a2e9699161e 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.cpp +++ b/backends/bmv2/simple_switch/simpleSwitch.cpp @@ -1041,7 +1041,7 @@ void SimpleSwitchBackend::createRecirculateFieldsList(ConversionContext *ctxt, auto anno = f->getAnnotation("field_list"_cs); if (anno == nullptr) continue; - for (auto e : anno->expr) { + for (auto e : anno->getExpr()) { auto cst = e->to(); if (cst == nullptr) { ::P4::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, diff --git a/backends/ebpf/target.h b/backends/ebpf/target.h index b624c2718d6..4a8bb813439 100644 --- a/backends/ebpf/target.h +++ b/backends/ebpf/target.h @@ -203,15 +203,16 @@ class KernelSamplesTarget : public Target { class P4TCTarget : public KernelSamplesTarget { public: explicit P4TCTarget(bool emitTrace) : KernelSamplesTarget(emitTrace, "P4TC"_cs) {} - cstring getByteOrderFromAnnotation(const IR::Vector &annotations) const { - for (const auto *anno : annotations) { - if (anno->name != "tc_type") continue; - for (const auto *annoVal : anno->body) { - if (annoVal->text == "macaddr" || annoVal->text == "ipv4" || - annoVal->text == "ipv6" || annoVal->text == "be16" || annoVal->text == "be32" || - annoVal->text == "be64") { - return "NETWORK"_cs; - } + // FIXME: The code is terrible broken: the function is called on both + // *parsed* and *unparsed* annotations (!!!!) + static cstring getByteOrderFromAnnotation(const IR::IAnnotated *node) { + if (const auto *anno = node->getAnnotation("tc_type"_cs)) { + cstring value = anno->needsParsing() + ? anno->getUnparsed().at(0)->text + : anno->getExpr().at(0)->checkedTo()->value; + if (value == "macaddr" || value == "ipv4" || value == "ipv6" || value == "be16" || + value == "be32" || value == "be64") { + return "NETWORK"_cs; } } return "HOST"_cs; @@ -223,14 +224,14 @@ class P4TCTarget : public KernelSamplesTarget { auto type = typeMap->getType(mem->expr, true); if (type->is()) { auto field = type->to()->getField(mem->member); - return getByteOrderFromAnnotation(field->getAnnotations()); + return getByteOrderFromAnnotation(field); } } else if (action) { auto paramList = action->getParameters(); if (paramList != nullptr && !paramList->empty()) { for (auto param : paramList->parameters) { if (param->name.originalName == exp->toString()) { - return getByteOrderFromAnnotation(param->getAnnotations()); + return getByteOrderFromAnnotation(param); } } } diff --git a/backends/p4fmt/p4formatter.cpp b/backends/p4fmt/p4formatter.cpp index ae0968d3b53..6229a16201e 100644 --- a/backends/p4fmt/p4formatter.cpp +++ b/backends/p4fmt/p4formatter.cpp @@ -1100,40 +1100,48 @@ bool P4Formatter::preorder(const IR::Annotation *a) { builder.append(a->name); const char *open = a->structured ? "[" : "("; const char *close = a->structured ? "]" : ")"; - if (!a->expr.empty()) { - builder.append(open); - { - WithSeparator comma(*this, ", "); - preorder(&a->expr); - } - builder.append(close); - } - if (!a->kv.empty()) { - builder.append(open); - visitCollection(a->kv, ", ", [&](const auto &kvp) { - builder.append(kvp->name); - builder.append("="); - visit(kvp->expression); - }); - builder.append(close); - } - if (a->expr.empty() && a->kv.empty() && a->structured) { - builder.append("[]"); - } - if (!a->body.empty() && a->expr.empty() && a->kv.empty()) { - // Have an unparsed annotation. - // We could be prettier here with smarter logic, but let's do the easy - // thing by separating every token with a space. - builder.append(open); - visitCollection(a->body, " ", [&](const auto &tok) { - bool haveStringLiteral = - tok->token_type == P4::P4Parser::token_type::TOK_STRING_LITERAL; - if (haveStringLiteral) builder.append("\""); - builder.append(tok->text); - if (haveStringLiteral) builder.append("\""); - }); - builder.append(close); - } + + std::visit( + [&](const auto &body) { + using T = std::decay_t; + if constexpr (std::is_same_v>) { + // Have an unparsed annotation. + // We could be prettier here with smarter logic, but let's do the easy + // thing by separating every token with a space. + builder.append(open); + visitCollection(body, " ", [&](const auto &tok) { + bool haveStringLiteral = + tok->token_type == P4::P4Parser::token_type::TOK_STRING_LITERAL; + if (haveStringLiteral) builder.append("\""); + builder.append(tok->text); + if (haveStringLiteral) builder.append("\""); + }); + builder.append(close); + } else if constexpr (std::is_same_v>) { + // Do not print () for empty unstructured annotations + if (body.empty() && !a->structured) return; + builder.append(open); + { + WithSeparator comma(*this, ", "); + preorder(&body); + } + builder.append(close); + } else if constexpr (std::is_same_v>) { + // Do not print () for empty unstructured annotations + if (body.empty() && !a->structured) return; + builder.append(open); + visitCollection(body, ", ", [&](const auto &kvp) { + builder.append(kvp->name); + builder.append("="); + visit(kvp->expression); + }); + builder.append(close); + } else { + BUG("Unexpected variant field"); + } + }, + a->body); + return false; } diff --git a/backends/p4tools/common/compiler/reachability.cpp b/backends/p4tools/common/compiler/reachability.cpp index bbe28904493..35604155bd2 100644 --- a/backends/p4tools/common/compiler/reachability.cpp +++ b/backends/p4tools/common/compiler/reachability.cpp @@ -26,12 +26,11 @@ P4ProgramDCGCreator::P4ProgramDCGCreator(NodesCallGraph *dcg) : dcg(dcg), p4prog } bool P4ProgramDCGCreator::preorder(const IR::Annotation *annotation) { - if (annotation->name != IR::Annotation::nameAnnotation) { - return true; - } + if (annotation->name != IR::Annotation::nameAnnotation) return true; + IR::ID name; - if (!annotation->expr.empty()) { - if (const auto *strLit = annotation->expr[0]->to()) { + if (!annotation->getExpr().empty()) { + if (const auto *strLit = annotation->getExpr(0)->to()) { if (strLit->value == ".NoAction") { // Ignore NoAction annotations, because they aren't unique. return true; diff --git a/backends/p4tools/modules/smith/common/table.cpp b/backends/p4tools/modules/smith/common/table.cpp index adad0e4e576..e99043ceee8 100644 --- a/backends/p4tools/modules/smith/common/table.cpp +++ b/backends/p4tools/modules/smith/common/table.cpp @@ -49,7 +49,7 @@ IR::Key *TableGenerator::genKeyElementList(size_t len) { // @name // Tao: actually, this may never happen const auto *keyAnno = key->getAnnotations().at(0); - const auto *annotExpr = keyAnno->expr.at(0); + const auto *annotExpr = keyAnno->getExpr(0); cstring keyAnnotatName; if (annotExpr->is()) { const auto *strExpr = annotExpr->to(); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp b/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp index 8d2c39d26ea..d04b868c352 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp @@ -47,10 +47,9 @@ std::string Bmv2V1ModelExprStepper::getClassName() { return "Bmv2V1ModelExprStep bool Bmv2V1ModelExprStepper::isPartOfFieldList(const IR::StructField *field, uint64_t recirculateIndex) { // Check whether the field has a "field_list" annotation associated with it. - const auto *annotation = field->getAnnotation("field_list"_cs); - if (annotation != nullptr) { + if (const auto *annotation = field->getAnnotation("field_list"_cs)) { // Grab the index of the annotation. - auto annoExprs = annotation->expr; + auto annoExprs = annotation->getExpr(); auto annoExprSize = annoExprs.size(); BUG_CHECK(annoExprSize == 1, "The field list annotation should only have one member. Has %1%.", annoExprSize); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/p4_asserts_parser.cpp b/backends/p4tools/modules/testgen/targets/bmv2/p4_asserts_parser.cpp index ddd7562fdfc..b389cfaf384 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/p4_asserts_parser.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/p4_asserts_parser.cpp @@ -524,7 +524,7 @@ const IR::Node *AssertsParser::postorder(IR::P4Action *actionContext) { typeMap[arg->controlPlaneName()] = arg->type; } - for (const auto *restrStr : annotation->body) { + for (const auto *restrStr : annotation->getUnparsed()) { auto restrictions = genIRStructs(actionContext->controlPlaneName(), restrStr->text, typeMap); // Using Z3Solver, we check the feasibility of restrictions, if they are not @@ -551,7 +551,7 @@ const IR::Node *AssertsParser::postorder(IR::P4Table *tableContext) { } Z3Solver solver; - for (const auto *restrStr : annotation->body) { + for (const auto *restrStr : annotation->getUnparsed()) { auto restrictions = genIRStructs(tableContext->controlPlaneName(), restrStr->text, typeMap); // Using Z3Solver, we check the feasibility of restrictions, if they are not // feasible, we delete keys and entries from the table to execute diff --git a/backends/p4tools/modules/testgen/targets/bmv2/p4_refers_to_parser.cpp b/backends/p4tools/modules/testgen/targets/bmv2/p4_refers_to_parser.cpp index e0a055649c6..771345090ba 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/p4_refers_to_parser.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/p4_refers_to_parser.cpp @@ -91,7 +91,7 @@ const IR::SymbolicVariable *RefersToParser::lookUpKeyInTable(const IR::P4Table & const IR::SymbolicVariable *RefersToParser::getReferencedKey(const IR::P4Control &ctrlContext, const IR::Annotation &refersAnno) { - const auto &annotationList = refersAnno.body; + const auto &annotationList = refersAnno.getUnparsed(); BUG_CHECK(annotationList.size() > 2, "'@refers_to' annotation %1% does not have the correct format.", refersAnno); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp index fdea09165b9..24e421916bd 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp @@ -21,7 +21,7 @@ P4Tools::P4Testgen::Bmv2::PropagateP4RuntimeTranslation::lookupP4RuntimeAnnotati } const auto *p4runtimeAnnotation = annotatedType->getAnnotation("p4runtime_translation"_cs); if (p4runtimeAnnotation != nullptr) { - BUG_CHECK(!p4runtimeAnnotation->needsParsing, + BUG_CHECK(!p4runtimeAnnotation->needsParsing(), "The @p4runtime_translation annotation should have been parsed already."); p4RuntimeAnnotations.push_back(p4runtimeAnnotation); } @@ -29,7 +29,7 @@ P4Tools::P4Testgen::Bmv2::PropagateP4RuntimeTranslation::lookupP4RuntimeAnnotati annotatedType->getAnnotation("p4runtime_translation_mappings"_cs); if (p4runtimeTranslationMappings != nullptr) { BUG_CHECK( - !p4runtimeTranslationMappings->needsParsing, + !p4runtimeTranslationMappings->needsParsing(), "The @p4runtime_translation_mappings annotation should have been parsed already."); p4RuntimeAnnotations.push_back(p4runtimeTranslationMappings); } diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.cpp index a5eb7ac71f9..f3c1fb9a760 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf_ir.cpp @@ -30,7 +30,7 @@ std::optional ProtobufIr::checkForP4RuntimeTranslationAnnotation( if (p4RuntimeTranslationAnnotation == nullptr) { return std::nullopt; } - auto annotationVector = p4RuntimeTranslationAnnotation->expr; + auto annotationVector = p4RuntimeTranslationAnnotation->getExpr(); BUG_CHECK(annotationVector.size() == 2, "Expected size of %1% to be 2. ", annotationVector); const auto *targetValue = annotationVector.at(1); if (targetValue->is()) { @@ -50,9 +50,9 @@ std::map ProtobufIr::getP4RuntimeTranslationMappings(const IR: if (p4RuntimeTranslationMappingAnnotation == nullptr) { return p4RuntimeTranslationMappings; } - BUG_CHECK(!p4RuntimeTranslationMappingAnnotation->needsParsing, + BUG_CHECK(!p4RuntimeTranslationMappingAnnotation->needsParsing(), "The @p4runtime_translation_mappings annotation should have been parsed already."); - auto annotationExpr = p4RuntimeTranslationMappingAnnotation->expr; + auto annotationExpr = p4RuntimeTranslationMappingAnnotation->getExpr(); BUG_CHECK(annotationExpr.size() == 1, "Expected size of %1% to be 1. ", annotationExpr); const auto *exprList = annotationExpr.at(0)->checkedTo(); for (const auto *expr : exprList->components) { @@ -76,8 +76,9 @@ std::string ProtobufIr::getFormatOfNode(const IR::IAnnotated *node) { if (formatAnnotation == nullptr) { return "hex_str"; } - BUG_CHECK(formatAnnotation->body.size() == 1, "@format annotation can only have one member."); - auto annotationFormatString = formatAnnotation->body.at(0)->text; + BUG_CHECK(formatAnnotation->getUnparsed().size() == 1, + "@format annotation can only have one member."); + auto annotationFormatString = formatAnnotation->getUnparsed().at(0)->text; if (annotationFormatString == "IPV4_ADDRESS") { return "ipv4"; } diff --git a/backends/tc/backend.cpp b/backends/tc/backend.cpp index 5f894a5de0b..1d3f93461d7 100644 --- a/backends/tc/backend.cpp +++ b/backends/tc/backend.cpp @@ -247,7 +247,7 @@ void ConvertToBackendIR::postorder(const IR::P4Action *action) { tcActionParam->setBitSize(width); } if (const auto *anno = param->getAnnotation(ParseTCAnnotations::tcType)) { - auto expr = anno->expr[0]; + auto expr = anno->getExpr(0); if (auto typeLiteral = expr->to()) { auto val = getTcType(typeLiteral); if (val != TC::BIT_TYPE) { @@ -302,8 +302,8 @@ void ConvertToBackendIR::updateConstEntries(const IR::P4Table *t, IR::TCTable *t for (size_t itr = 0; itr < keyset->components.size(); itr++) { auto keyElement = keys->keyElements.at(itr); auto keyString = keyElement->expression->toString(); - if (auto anno = keyElement->getAnnotation("name"_cs)) { - keyString = anno->expr.at(0)->to()->value; + if (auto anno = keyElement->getAnnotation(IR::Annotation::nameAnnotation)) { + keyString = anno->getExpr(0)->to()->value; } auto keySetElement = keyset->components.at(itr); auto key = keySetElement->toString(); @@ -714,7 +714,7 @@ std::pair *ConvertToBackendIR::GetAnnotatedAccessPath( const IR::Annotation *anno) { cstring control_path, data_path; if (anno) { - auto expr = anno->expr[0]; + auto expr = anno->getExpr(0); if (auto typeLiteral = expr->to()) { auto permisson_str = typeLiteral->value; auto char_pos = permisson_str.find(":"); @@ -765,7 +765,7 @@ void ConvertToBackendIR::postorder(const IR::P4Table *t) { if (anno->name == ParseTCAnnotations::tc_acl) { tablePermissions.emplace(t->name.originalName, GetAnnotatedAccessPath(anno)); } else if (anno->name == ParseTCAnnotations::numMask) { - auto expr = anno->expr[0]; + auto expr = anno->getExpr(0); if (auto val = expr->to()) { tableDefinition->setNumMask(val->asUint64()); } else { @@ -1007,7 +1007,7 @@ safe_vector ConvertToBackendIR::HandleTypeNameStructField( for (auto f : param_struct->fields) { cstring ptype = absl::StrCat("bit", f->type->width_bits()); if (auto anno = f->getAnnotation(ParseTCAnnotations::tcType)) { - auto expr = anno->expr[0]; + auto expr = anno->getExpr(0); if (auto typeLiteral = expr->to()) { ptype = typeLiteral->value; } @@ -1019,7 +1019,7 @@ safe_vector ConvertToBackendIR::HandleTypeNameStructField( } else { cstring ptype = absl::StrCat("bit", param_val->width_bits()); if (auto anno = field->getAnnotation(ParseTCAnnotations::tcType)) { - auto expr = anno->expr[0]; + auto expr = anno->getExpr(0); if (auto typeLiteral = expr->to()) { ptype = typeLiteral->value; } diff --git a/backends/tc/ebpfCodeGen.cpp b/backends/tc/ebpfCodeGen.cpp index 00d6d66733a..7390f72a4dc 100644 --- a/backends/tc/ebpfCodeGen.cpp +++ b/backends/tc/ebpfCodeGen.cpp @@ -615,22 +615,16 @@ void PnaStateTranslationVisitor::compileExtractField(const IR::Expression *expr, bool noEndiannessConversion = false; if (const auto *anno = field->getAnnotation(ParseTCAnnotations::tcType)) { - auto annoBody = anno->body; - for (auto annoVal : annoBody) { - if (annoVal->text == "macaddr" || annoVal->text == "ipv4" || annoVal->text == "ipv6") { - noEndiannessConversion = true; - break; - } else if (annoVal->text == "be16" || annoVal->text == "be32" || - annoVal->text == "be64") { - std::string sInt = annoVal->text.substr(2).c_str(); - unsigned int width = std::stoi(sInt); - if (widthToExtract != width) { - ::P4::error("Width of the field doesnt match the annotation width. '%1%'", - field); - } - noEndiannessConversion = true; - break; + cstring value = anno->getExpr(0)->checkedTo()->value; + if (value == "macaddr" || value == "ipv4" || value == "ipv6") { + noEndiannessConversion = true; + } else if (value == "be16" || value == "be32" || value == "be64") { + std::string sInt = value.substr(2).c_str(); + unsigned int width = std::stoi(sInt); + if (widthToExtract != width) { + ::P4::error("Width of the field doesnt match the annotation width. '%1%'", field); } + noEndiannessConversion = true; } } @@ -1863,13 +1857,13 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) { cstring swap; auto tcTarget = dynamic_cast(builder->target); - cstring isKeyBigEndian = tcTarget->getByteOrderFromAnnotation(c->getAnnotations()); + cstring isKeyBigEndian = tcTarget->getByteOrderFromAnnotation(c); cstring isDefnBigEndian = "HOST"_cs; if (auto mem = c->expression->to()) { auto type = typeMap->getType(mem->expr, true); if (type->is()) { auto field = type->to()->getField(mem->member); - isDefnBigEndian = tcTarget->getByteOrderFromAnnotation(field->getAnnotations()); + isDefnBigEndian = tcTarget->getByteOrderFromAnnotation(field); } } @@ -2235,14 +2229,10 @@ void DeparserHdrEmitTranslatorPNA::processMethod(const P4::ExternMethod *method) } bool noEndiannessConversion = false; if (const auto *anno = f->getAnnotation(ParseTCAnnotations::tcType)) { - for (auto annoVal : anno->body) { - if (annoVal->text == "macaddr" || annoVal->text == "ipv4" || - annoVal->text == "ipv6" || annoVal->text == "be16" || - annoVal->text == "be32" || annoVal->text == "be64") { - noEndiannessConversion = true; - break; - } - } + cstring value = anno->getExpr(0)->checkedTo()->value; + noEndiannessConversion = value == "macaddr" || value == "ipv4" || + value == "ipv6" || value == "be16" || + value == "be32" || value == "be64"; } emitField(builder, f->name, expr, alignment, etype, noEndiannessConversion); alignment += et->widthInBits(); diff --git a/backends/tc/introspection.cpp b/backends/tc/introspection.cpp index 876b0c81b94..6c246266d75 100644 --- a/backends/tc/introspection.cpp +++ b/backends/tc/introspection.cpp @@ -68,7 +68,7 @@ void IntrospectionGenerator::collectKeyInfo(const IR::Key *key, struct TableAttr keyField->type = "bit" + Util::toString(widthBits); for (auto anno : k->getAnnotations()) { if (anno->name == ParseTCAnnotations::tcType) { - auto expr = anno->expr[0]; + auto expr = anno->getExpr(0); if (auto typeLiteral = expr->to()) { if (auto tcVal = checkValidTcType(typeLiteral)) { auto val = std::move(*tcVal); @@ -83,7 +83,7 @@ void IntrospectionGenerator::collectKeyInfo(const IR::Key *key, struct TableAttr } } if (anno->name == IR::Annotation::nameAnnotation) { - auto expr = anno->expr[0]; + auto expr = anno->getExpr(0); if (auto name = expr->to()) { keyField->name = name->value; } diff --git a/backends/tc/tcAnnotations.h b/backends/tc/tcAnnotations.h index a1830920f73..3433b5ef3fc 100644 --- a/backends/tc/tcAnnotations.h +++ b/backends/tc/tcAnnotations.h @@ -43,13 +43,12 @@ class ParseTCAnnotations : public P4::ParseAnnotations { ParseTCAnnotations() : P4::ParseAnnotations( "TC", true, - {PARSE_EMPTY(defaultHit), PARSE_EMPTY(defaultHitConst), - PARSE_CONSTANT_OR_STRING_LITERAL(tcType), PARSE_CONSTANT_OR_STRING_LITERAL(numMask), - PARSE_EMPTY(tcMayOverride), PARSE_CONSTANT_OR_STRING_LITERAL(tc_acl), - PARSE_EMPTY(tc_md_write), PARSE_EMPTY(tc_md_read), PARSE_EMPTY(tc_md_write), - PARSE_EMPTY(tc_md_exec), PARSE_EMPTY(tc_ControlPath), PARSE_EMPTY(tc_key), - PARSE_EMPTY(tc_data), PARSE_EMPTY(tc_data_scalar), PARSE_EMPTY(tc_init_val), - PARSE_EMPTY(tc_numel)}) {} + {PARSE_EMPTY(defaultHit), PARSE_EMPTY(defaultHitConst), PARSE_STRING_LITERAL(tcType), + PARSE_CONSTANT_OR_STRING_LITERAL(numMask), PARSE_EMPTY(tcMayOverride), + PARSE_STRING_LITERAL(tc_acl), PARSE_EMPTY(tc_md_write), PARSE_EMPTY(tc_md_read), + PARSE_EMPTY(tc_md_write), PARSE_EMPTY(tc_md_exec), PARSE_EMPTY(tc_ControlPath), + PARSE_EMPTY(tc_key), PARSE_EMPTY(tc_data), PARSE_EMPTY(tc_data_scalar), + PARSE_EMPTY(tc_init_val), PARSE_EMPTY(tc_numel)}) {} }; } // namespace P4::TC diff --git a/backends/tofino/bf-p4c/arch/arch.cpp b/backends/tofino/bf-p4c/arch/arch.cpp index 5efccb112b8..8c515f88ae9 100644 --- a/backends/tofino/bf-p4c/arch/arch.cpp +++ b/backends/tofino/bf-p4c/arch/arch.cpp @@ -65,11 +65,11 @@ bool Pipeline::equiv(const Pipeline &other) const { void Pipeline::insertPragmas(const std::vector &all_pragmas) { auto applies = [this](const IR::Annotation *p) { - if (p->expr.empty() || p->expr.at(0) == nullptr) { + if (p->getExpr().empty() || p->getExpr(0) == nullptr) { return true; } - auto arg0 = p->expr.at(0)->to(); + auto arg0 = p->getExpr(0)->to(); // Determine whether the name of a pipe is present as the first argument. // If the pipe name doesn't match, the pragma is to be applied for a different pipe. @@ -118,7 +118,7 @@ bool Architecture::preorder(const IR::PackageBlock *pkg) { found = true; } else if (pkg->type->name == "Switch" || pkg->type->name == "MultiParserSwitch") { if (auto annot = pkg->type->getAnnotation(IR::Annotation::pkginfoAnnotation)) { - for (auto kv : annot->kv) { + for (auto kv : annot->getKV()) { if (kv->name == "arch") { architecture = toArchEnum(kv->expression->to()->value); } else if (kv->name == "version") { @@ -216,7 +216,7 @@ void ParseTna::parsePortMapAnnotation(const IR::PackageBlock *block, DefaultPort if (auto annot = block->node->to()) { if (auto anno = annot->getAnnotation("default_portmap"_cs)) { int index = 0; - for (auto expr : anno->expr) { + for (auto expr : anno->getExpr()) { std::vector ports; if (auto cst = expr->to()) { ports.push_back(cst->asInt()); diff --git a/backends/tofino/bf-p4c/arch/arch.h b/backends/tofino/bf-p4c/arch/arch.h index f4b923e728b..f91da653dd5 100644 --- a/backends/tofino/bf-p4c/arch/arch.h +++ b/backends/tofino/bf-p4c/arch/arch.h @@ -131,7 +131,7 @@ struct RemoveExternMethodCallsExcludedByAnnotation : public Transform { auto *dontTranslate = action->getAnnotation("dont_translate_extern_method"_cs); if (!dontTranslate) return call; - for (auto *excluded : dontTranslate->expr) { + for (auto *excluded : dontTranslate->getExpr()) { auto *excludedMethod = excluded->to(); if (!excludedMethod) { error( diff --git a/backends/tofino/bf-p4c/arch/collect_bridged_fields.cpp b/backends/tofino/bf-p4c/arch/collect_bridged_fields.cpp index 909c9040a97..fda9697ab27 100644 --- a/backends/tofino/bf-p4c/arch/collect_bridged_fields.cpp +++ b/backends/tofino/bf-p4c/arch/collect_bridged_fields.cpp @@ -295,7 +295,7 @@ bool CollectBridgedFields::preorder(const IR::Annotation *annot) { if (pragmaName != "pa_do_not_bridge") return true; LOG4("[CollectBridgedFields] Do Not Bridge pragma: " << annot); - auto &exprs = annot->expr; + auto &exprs = annot->getExpr(); // Check pragma arguments if (exprs.size() != 2) { ::warning( diff --git a/backends/tofino/bf-p4c/arch/fromv1.0/checksum.h b/backends/tofino/bf-p4c/arch/fromv1.0/checksum.h index 0fe606b577e..edeb8b68a54 100644 --- a/backends/tofino/bf-p4c/arch/fromv1.0/checksum.h +++ b/backends/tofino/bf-p4c/arch/fromv1.0/checksum.h @@ -148,7 +148,7 @@ static std::vector getChecksumUpdateLocations(const IR::MethodCallExpre for (auto annot : block->annotations) { if (annot->name.name == pragma) { - auto &exprs = annot->expr; + auto &exprs = annot->getExpr(); auto gress = exprs[0]->to(); auto pCall = exprs[1]->to(); if (pCall && !pCall->equiv(*call)) continue; diff --git a/backends/tofino/bf-p4c/arch/fromv1.0/field_list.cpp b/backends/tofino/bf-p4c/arch/fromv1.0/field_list.cpp index 44c0aef3613..1ad560a1f9c 100644 --- a/backends/tofino/bf-p4c/arch/fromv1.0/field_list.cpp +++ b/backends/tofino/bf-p4c/arch/fromv1.0/field_list.cpp @@ -36,20 +36,21 @@ const IR::Node *P4V1::FieldListConverter::convertFieldList(const IR::Node *node) std::map> field_slices; for (auto anno : fl->annotations) { if (anno->name == pragma_string) { - if (anno->expr.size() != 3) error("Invalid pragma specification -- ", pragma_string); + if (anno->getExpr().size() != 3) + error("Invalid pragma specification -- ", pragma_string); - if (!anno->expr[0]->is()) - error("Invalid field in pragma specification -- ", anno->expr[0]); + if (!anno->getExpr(0)->is()) + error("Invalid field in pragma specification -- ", anno->getExpr(0)); - auto field = anno->expr[0]->to()->value; - if (!anno->expr[1]->is() || !anno->expr[2]->is()) + auto field = anno->getExpr(0)->to()->value; + if (!anno->getExpr()[1]->is() || !anno->getExpr()[2]->is()) error("Invalid slice bit position(s) in pragma specification -- ", pragma_string); if (sliced_fields.count(field)) error("Duplicate slice definition for field ", field); sliced_fields.insert(field); - auto msb = anno->expr[1]->to()->asInt(); - auto lsb = anno->expr[2]->to()->asInt(); + auto msb = anno->getExpr()[1]->to()->asInt(); + auto lsb = anno->getExpr()[2]->to()->asInt(); field_slices.emplace(field, std::make_pair(msb, lsb)); } diff --git a/backends/tofino/bf-p4c/arch/fromv1.0/phase0.cpp b/backends/tofino/bf-p4c/arch/fromv1.0/phase0.cpp index e6a495e74d7..d8fd7e827c2 100644 --- a/backends/tofino/bf-p4c/arch/fromv1.0/phase0.cpp +++ b/backends/tofino/bf-p4c/arch/fromv1.0/phase0.cpp @@ -164,12 +164,12 @@ struct FindPhase0Table : public Inspector { // Pragma value = 0 => Table must be implemented only in MAU bool phase0PragmaSet = false; if (auto s = table->getAnnotation("phase0"_cs)) { - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); ERROR_CHECK( (pragma_val != nullptr), "Invalid Phase0 pragma value. Must be a constant (either 0 or 1) on table - %s", table->name); - if (auto pragma_val = s->expr.at(0)->to()) { + if (auto pragma_val = s->getExpr(0)->to()) { ERROR_CHECK((pragma_val->value == 0) || (pragma_val->value == 1), "Invalid Phase0 pragma value. Must be either 0 or 1 on table - %s", table->name); @@ -732,7 +732,7 @@ bool CheckPhaseZeroExtern::preorder(const IR::MethodCallExpression *expr) { bool CollectPhase0Annotation::preorder(const IR::ParserState *state) { if (auto ann = state->getAnnotation("override_phase0_table_name"_cs)) { - if (auto phase0 = ann->expr.at(0)->to()) { + if (auto phase0 = ann->getExpr(0)->to()) { auto parser = findOrigCtxt(); if (!parser) return false; auto name = parser->externalName(); @@ -740,7 +740,7 @@ bool CollectPhase0Annotation::preorder(const IR::ParserState *state) { } } if (auto ann = state->getAnnotation("override_phase0_action_name"_cs)) { - if (auto phase0 = ann->expr.at(0)->to()) { + if (auto phase0 = ann->getExpr(0)->to()) { auto parser = findOrigCtxt(); if (!parser) return false; auto name = parser->externalName(); diff --git a/backends/tofino/bf-p4c/arch/fromv1.0/programStructure.cpp b/backends/tofino/bf-p4c/arch/fromv1.0/programStructure.cpp index 510fa147d86..363aca7a326 100644 --- a/backends/tofino/bf-p4c/arch/fromv1.0/programStructure.cpp +++ b/backends/tofino/bf-p4c/arch/fromv1.0/programStructure.cpp @@ -421,11 +421,11 @@ IR::BlockStatement *generate_tna_hash_block_statement(P4V1::TnaProgramStructure new IR::Type_Specialized(new IR::Type_Name("Hash"), new IR::Vector({ttype})); IR::Vector annos; if (auto symmetricAnnotation = fl->getAnnotation("symmetric"_cs)) { - if (symmetricAnnotation->expr.size() == 2) { + if (symmetricAnnotation->getExpr().size() == 2) { // auto name1 = symmetricAnnotation->expr[0]; // auto name2 = symmetricAnnotation->expr[1]; IR::Annotations::addOrReplace(annos, "symmetric"_cs, - new IR::ListExpression(symmetricAnnotation->expr)); + new IR::ListExpression(symmetricAnnotation->getExpr())); } else { error("Invalid pragma usage: symmetric"); } @@ -1066,11 +1066,11 @@ const IR::ParserState *TnaProgramStructure::convertParser( auto sizeAnnotation = value_set->getAnnotation("parser_value_set_size"_cs); const IR::Constant *sizeConstant; if (sizeAnnotation) { - if (sizeAnnotation->expr.size() != 1) { + if (sizeAnnotation->getExpr().size() != 1) { error("@size should be an integer for declaration %1%", value_set); return nullptr; } - sizeConstant = sizeAnnotation->expr[0]->to(); + sizeConstant = sizeAnnotation->getExpr(0)->to(); if (sizeConstant == nullptr || !sizeConstant->fitsInt()) { error("@size should be an integer for declaration %1%", value_set); return nullptr; @@ -1772,7 +1772,7 @@ void TnaProgramStructure::parseUpdateLocationAnnotation(std::set &updat const IR::Annotation *annot, cstring pragma) { if (annot->name.name == pragma) { - auto &exprs = annot->expr; + auto &exprs = annot->getExpr(); auto gress = exprs[0]->to(); if (gress->value == "ingress") @@ -2148,8 +2148,8 @@ void TnaProgramStructure::collectBridgedFields() { for (auto it : headers) { auto do_not_bridge = it.first->type->getAnnotation("pa_do_not_bridge"_cs); if (do_not_bridge) { - if (do_not_bridge->expr.size() != 2) continue; - if (auto expr = do_not_bridge->expr.at(1)->to()) { + if (do_not_bridge->getExpr().size() != 2) continue; + if (auto expr = do_not_bridge->getExpr(1)->to()) { auto meta = "meta." + expr->value; if (bridgedFields.count(meta)) { bridgedFields.erase(meta); diff --git a/backends/tofino/bf-p4c/arch/fromv1.0/v1_converters.cpp b/backends/tofino/bf-p4c/arch/fromv1.0/v1_converters.cpp index 00c3fe000ac..61722358cc2 100644 --- a/backends/tofino/bf-p4c/arch/fromv1.0/v1_converters.cpp +++ b/backends/tofino/bf-p4c/arch/fromv1.0/v1_converters.cpp @@ -698,8 +698,8 @@ const IR::Node *MeterConverter::postorder(IR::MethodCallStatement *node) { auto inst = refMap->getDeclaration(meter_pe->path)->to(); auto annot = inst ? inst->getAnnotation("pre_color"_cs) : nullptr; if (annot != nullptr) { - auto size = annot->expr.at(0)->type->width_bits(); - auto expr = annot->expr.at(0); + auto size = annot->getExpr(0)->type->width_bits(); + auto expr = annot->getExpr(0); auto castedExpr = cast_if_needed(expr, size, 8); args->push_back( new IR::Argument("color", new IR::Cast(new IR::Type_Name("MeterColor_t"), castedExpr))); diff --git a/backends/tofino/bf-p4c/arch/intrinsic_metadata.h b/backends/tofino/bf-p4c/arch/intrinsic_metadata.h index 2d29a1e118c..2746ba257d0 100644 --- a/backends/tofino/bf-p4c/arch/intrinsic_metadata.h +++ b/backends/tofino/bf-p4c/arch/intrinsic_metadata.h @@ -198,7 +198,7 @@ class RenameP4StartState : public Transform { IR::ParserState *preorder(IR::ParserState *state) override { auto anno = state->getAnnotation("name"_cs); if (!anno) return state; - auto name = anno->expr.at(0)->to(); + auto name = anno->getExpr(0)->to(); // We want to check if the .start was found, which indicates that // the p4c indeed added start_0 and .$start and we should // therefore rename the generated start state @@ -238,7 +238,7 @@ class AddMetadataFields : public Transform { auto anno = state->getAnnotation("packet_entry"_cs); if (!anno) return state; anno = state->getAnnotation("name"_cs); - auto name = anno->expr.at(0)->to(); + auto name = anno->getExpr(0)->to(); if (name->value == ".start_i2e_mirrored") { start_i2e_mirrored = state; } else if (name->value == ".start_e2e_mirrored") { @@ -255,7 +255,7 @@ class AddMetadataFields : public Transform { IR::ParserState *postorder(IR::ParserState *state) override { auto anno = state->getAnnotation("name"_cs); if (!anno) return state; - auto name = anno->expr.at(0)->to(); + auto name = anno->getExpr(0)->to(); if (name->value == ".start") { LOG1("found start state "); // Frontend renames 'start' to 'start_0' if the '@packet_entry' pragma is used. diff --git a/backends/tofino/bf-p4c/arch/psa/psa.cpp b/backends/tofino/bf-p4c/arch/psa/psa.cpp index c5b1d030fff..98148a78326 100644 --- a/backends/tofino/bf-p4c/arch/psa/psa.cpp +++ b/backends/tofino/bf-p4c/arch/psa/psa.cpp @@ -710,7 +710,7 @@ class TranslateProgram : public Inspector { // selector_mode auto sel_mode = new IR::Member(new IR::TypeNameExpression("SelectorMode_t"), "FAIR"); if (auto anno = node->getAnnotation("mode"_cs)) { - auto mode = anno->expr.at(0)->to(); + auto mode = anno->getExpr(0)->to(); if (mode->value == "resilient") sel_mode->member = IR::ID("RESILIENT"); else if (mode->value != "fair" && mode->value != "non_resilient") diff --git a/backends/tofino/bf-p4c/arch/v1model.cpp b/backends/tofino/bf-p4c/arch/v1model.cpp index 1197c843833..e6eb2e8aa6e 100644 --- a/backends/tofino/bf-p4c/arch/v1model.cpp +++ b/backends/tofino/bf-p4c/arch/v1model.cpp @@ -1808,7 +1808,7 @@ class ConstructSymbolTable : public Inspector { for (auto annot : block->annotations) { if (annot->name.name == "zeros_as_ones") { auto mc = call->methodCall->to(); - if (annot->expr[0]->equiv(*mc)) return true; + if (annot->getExpr()[0]->equiv(*mc)) return true; } } return false; @@ -2012,7 +2012,7 @@ class ConstructSymbolTable : public Inspector { // selector_mode auto sel_mode = new IR::Member(new IR::TypeNameExpression("SelectorMode_t"), "FAIR"); if (auto anno = node->getAnnotation("mode"_cs)) { - auto mode = anno->expr.at(0)->to(); + auto mode = anno->getExpr(0)->to(); if (mode->value == "resilient") sel_mode->member = IR::ID("RESILIENT"); else if (mode->value != "fair" && mode->value != "non_resilient") @@ -2032,7 +2032,7 @@ class ConstructSymbolTable : public Inspector { auto typeArgs = new IR::Vector(); // type if (auto anno = node->getAnnotation("min_width"_cs)) { - auto min_width = anno->expr.at(0)->as().asInt(); + auto min_width = anno->getExpr(0)->as().asInt(); typeArgs->push_back(IR::Type::Bits::get(min_width)); } else { auto min_width = IR::Type::Bits::get(64); // Do not impose LRT @@ -2074,7 +2074,7 @@ class ConstructSymbolTable : public Inspector { void cvtDirectCounterDecl(const IR::Declaration_Instance *node) { auto typeArgs = new IR::Vector(); if (auto anno = node->getAnnotation("min_width"_cs)) { - auto min_width = anno->expr.at(0)->as().asInt(); + auto min_width = anno->getExpr(0)->as().asInt(); typeArgs->push_back(IR::Type::Bits::get(min_width)); } else { // Do not impose LRT @@ -2238,7 +2238,7 @@ class ConstructSymbolTable : public Inspector { // Check the field_list annotation auto anno = f->getAnnotation("field_list"_cs); if (anno == nullptr) continue; - for (auto e : anno->expr) { + for (auto e : anno->getExpr()) { auto cst = e->to(); if (cst == nullptr) { error("%1%: Annotation must be a constant integer", e); diff --git a/backends/tofino/bf-p4c/bf-p4c-options.cpp b/backends/tofino/bf-p4c/bf-p4c-options.cpp index fa855e7108c..c59bba834a3 100644 --- a/backends/tofino/bf-p4c/bf-p4c-options.cpp +++ b/backends/tofino/bf-p4c/bf-p4c-options.cpp @@ -905,10 +905,10 @@ BFNOptionPragmaParser::parseCompilerOption(const IR::Annotation *annotation) { // Parsing of option pragmas is done early in the compiler, before P4₁₆ // annotations are parsed, so we are responsible for doing our own parsing // here. - auto args = &annotation->expr; + auto args = &annotation->getExpr(); if (args->empty()) { auto parseResult = - P4::P4ParserDriver::parseExpressionList(annotation->srcInfo, annotation->body); + P4::P4ParserDriver::parseExpressionList(annotation->srcInfo, annotation->getUnparsed()); if (parseResult != nullptr) { args = parseResult; } diff --git a/backends/tofino/bf-p4c/common/asm_output.cpp b/backends/tofino/bf-p4c/common/asm_output.cpp index 81e5a6f7107..c3aec101a2c 100644 --- a/backends/tofino/bf-p4c/common/asm_output.cpp +++ b/backends/tofino/bf-p4c/common/asm_output.cpp @@ -196,7 +196,7 @@ void emit_user_annotation_context_json(indent_t indent, const IR::IAnnotated *no } bool emitted_elts = false; - for (auto *expr : annotation->expr) { + for (auto *expr : annotation->getExpr()) { auto str = expr->to(); BUG_CHECK(str, "User annotation not a string literal: %1%", expr); diff --git a/backends/tofino/bf-p4c/common/extract_maupipe.cpp b/backends/tofino/bf-p4c/common/extract_maupipe.cpp index 70c90445015..454512ed715 100644 --- a/backends/tofino/bf-p4c/common/extract_maupipe.cpp +++ b/backends/tofino/bf-p4c/common/extract_maupipe.cpp @@ -63,11 +63,11 @@ static int getConstant(const IR::Argument *arg) { } static big_int getBigConstant(const IR::Annotation *annotation) { - if (annotation->expr.size() != 1) { + if (annotation->getExpr().size() != 1) { error("%1% should contain a constant", annotation); return 0; } - auto constant = annotation->expr[0]->to(); + auto constant = annotation->getExpr(0)->to(); if (constant == nullptr) { error("%1% should contain a constant", annotation); return 0; @@ -77,11 +77,11 @@ static big_int getBigConstant(const IR::Annotation *annotation) { static int64_t getConstant(const IR::Annotation *annotation, int64_t min = INT_MIN, uint64_t max = INT_MAX) { - if (annotation->expr.size() != 1) { + if (annotation->getExpr().size() != 1) { error("%1% should contain a constant", annotation); return 0; } - auto constant = annotation->expr[0]->to(); + auto constant = annotation->getExpr(0)->to(); if (constant == nullptr) { error("%1% should contain a constant", annotation); return 0; @@ -97,11 +97,11 @@ static int64_t getConstant(const IR::Annotation *annotation, int64_t min = INT_M } static cstring getString(const IR::Annotation *annotation) { - if (annotation->expr.size() != 1) { + if (annotation->getExpr().size() != 1) { error("%1% should contain a string", annotation); return ""_cs; } - auto str = annotation->expr[0]->to(); + auto str = annotation->getExpr(0)->to(); if (str == nullptr) { error("%1% should contain a string", annotation); return ""_cs; @@ -521,11 +521,11 @@ cstring getTypeName(const IR::Type *type) { static int getSingleAnnotationValue(const cstring name, const IR::MAU::Table *table) { if (table->match_table) { if (auto s = table->match_table->getAnnotation(name)) { - ERROR_CHECK(s->expr.size() >= 1, + ERROR_CHECK(s->getExpr().size() >= 1, "%s: The %s pragma on table %s " "does not have a value", name, table->srcInfo, table->name); - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); if (pragma_val == nullptr) { error("%s: The %s pragma value on table %s is not a constant", name, table->srcInfo, table->name); @@ -792,8 +792,8 @@ static IR::MAU::AttachedMemory *createAttached( ctr->interval = getConstant(anno); else if (anno->name == "true_egress_accounting") ctr->true_egress_accounting = true; - else if ((anno->name == "adjust_byte_count") && anno->expr.size() == 1 && - anno->expr[0]->to()) + else if ((anno->name == "adjust_byte_count") && anno->getExpr().size() == 1 && + anno->getExpr(0)->to()) // Byte count adjustment is always subtracted ctr->bytecount_adjust -= getConstant(anno); } @@ -836,7 +836,7 @@ static IR::MAU::AttachedMemory *createAttached( // annotations are supported for p4-14. for (auto anno : annot) { if (anno->name == "result") - mtr->result = anno->expr.at(0); + mtr->result = anno->getExpr(0); else if (anno->name == "implementation") mtr->implementation = getString(anno); else if (anno->name == "green") @@ -851,8 +851,8 @@ static IR::MAU::AttachedMemory *createAttached( mtr->sweep_interval = getConstant(anno); else if (anno->name == "true_egress_accounting") mtr->true_egress_accounting = true; - else if ((anno->name == "adjust_byte_count") && anno->expr.size() == 1 && - anno->expr[0]->to()) + else if ((anno->name == "adjust_byte_count") && anno->getExpr().size() == 1 && + anno->getExpr(0)->to()) // Byte count adjustment is always subtracted mtr->bytecount_adjust -= getConstant(anno); else @@ -1267,7 +1267,7 @@ void AttachTables::InitializeStatefulAlus ::updateAttachedSalu(const IR::Declara for (auto annot : ext->annotations) { if (annot->name == "name") continue; if (auto old = salu->getAnnotation(annot->name)) { - if (old->expr.equiv(annot->expr)) continue; + if (old->getExpr().equiv(annot->getExpr())) continue; warning("Conflicting annotations %s and %s related to stateful alu %s", annot, old, salu); } @@ -1276,7 +1276,7 @@ void AttachTables::InitializeStatefulAlus ::updateAttachedSalu(const IR::Declara salu->annotations = std::move(new_annot); if (auto red_or = ext->getAnnotation("reduction_or_group"_cs)) { - auto pragma_val = red_or->expr.at(0)->to(); + auto pragma_val = red_or->getExpr(0)->to(); ERROR_CHECK(pragma_val, "%s: Please provide a valid reduction_or_group for, which should " "be a string %s", @@ -1646,7 +1646,7 @@ class GetBackendTables : public MauInspector { std::optional partition_index = std::nullopt; // Fold 'atcam_partition_index' annotation into InputXbarRead IR node. auto s = table->getAnnotation("atcam_partition_index"_cs); - if (s) partition_index = s->expr.at(0)->to()->value; + if (s) partition_index = s->getExpr(0)->to()->value; for (auto key_elem : key->keyElements) { auto key_expr = key_elem->expression; diff --git a/backends/tofino/bf-p4c/common/pragma/collect_global_pragma.cpp b/backends/tofino/bf-p4c/common/pragma/collect_global_pragma.cpp index 64bc7c982d3..90eae757e39 100644 --- a/backends/tofino/bf-p4c/common/pragma/collect_global_pragma.cpp +++ b/backends/tofino/bf-p4c/common/pragma/collect_global_pragma.cpp @@ -52,8 +52,8 @@ const std::vector *CollectGlobalPragma::g_global_pragma_names = cstring CollectGlobalPragma::getStructFieldName(const IR::StructField *s) const { const auto nameAnnotation = s->getAnnotation(IR::Annotation::nameAnnotation); - if (!nameAnnotation || nameAnnotation->expr.size() != 1) return cstring(); - auto structName = nameAnnotation->expr.at(0)->to(); + if (!nameAnnotation || nameAnnotation->getExpr().size() != 1) return cstring(); + auto structName = nameAnnotation->getExpr(0)->to(); if (!structName) return cstring(); return structName->value; } @@ -73,9 +73,9 @@ bool CollectGlobalPragma::preorder(const IR::StructField *s) { BUG("Pragma %1% on Struct Field %2% without a name", ann->name.name, s); // For the notParsedDeparsedAnnotation, create a new annotation that includes // structFieldName. - if (!ann->expr.size()) continue; + if (!ann->getExpr().size()) continue; - auto &exprs = ann->expr; + auto &exprs = ann->getExpr(); const unsigned min_required_arguments = 1; // gress unsigned required_arguments = min_required_arguments; diff --git a/backends/tofino/bf-p4c/ir/mau.cpp b/backends/tofino/bf-p4c/ir/mau.cpp index 93ea06b08d1..341c4848bac 100644 --- a/backends/tofino/bf-p4c/ir/mau.cpp +++ b/backends/tofino/bf-p4c/ir/mau.cpp @@ -720,7 +720,7 @@ IR::Vector &IR::MAU::Table::getAnnotations() { const IR::Expression *IR::MAU::Table::getExprAnnotation(cstring name) const { if (auto annot = getAnnotation(name)) { - if (annot->expr.size() == 1) return annot->expr.at(0); + if (annot->getExpr().size() == 1) return annot->getExpr(0); error(ErrorType::ERR_UNEXPECTED, "%1%: %2% pragma provided to table %3% has multiple " "parameters, while only one is expected", @@ -782,7 +782,7 @@ bool IR::MAU::Table::getAnnotation(cstring name, std::vector &val) const for (auto *annot : match_table->getAnnotations()) { if (annot->name != name) continue; rv = true; // found at least 1 - for (auto *expr : annot->expr) { + for (auto *expr : annot->getExpr()) { if (auto v = expr->to()) val.push_back(*v); else @@ -801,7 +801,7 @@ int IR::MAU::Table::get_placement_priority_int() const { bool val_set = false; for (auto &annot : match_table->getAnnotations()) { if (annot->name != "placement_priority") continue; - for (auto *expr : annot->expr) { + for (auto *expr : annot->getExpr()) { if (auto constant = expr->to()) { if (val_set) error(ErrorType::ERR_INVALID, @@ -821,7 +821,7 @@ std::set IR::MAU::Table::get_placement_priority_string() const { if (!match_table) return rv; for (auto &annot : match_table->getAnnotations()) { if (annot->name != "placement_priority") continue; - for (auto *expr : annot->expr) { + for (auto *expr : annot->getExpr()) { if (auto sl = expr->to()) { rv.insert(sl->value); } @@ -850,7 +850,7 @@ int IR::MAU::Table::get_provided_stage(int geq_stage, int *req_entries, int *fla bool valid_pragma = true; int intvals = 0; int idx = -1; - for (auto *e : annot->expr) { + for (auto *e : annot->getExpr()) { ++idx; if (auto *k = e->to()) { if (k->asInt() < 0) valid_pragma = false; @@ -879,12 +879,12 @@ int IR::MAU::Table::get_provided_stage(int geq_stage, int *req_entries, int *fla for (auto *annot : *stage_annotations) { if (!checkPragma(annot)) return -1; - int curr_stage = annot->expr.at(0)->to()->asInt(); + int curr_stage = annot->getExpr(0)->to()->asInt(); if (curr_stage >= geq_stage) { if (stage_annot == nullptr) { stage_annot = annot; } else { - int min_stage = stage_annot->expr.at(0)->to()->asInt(); + int min_stage = stage_annot->getExpr(0)->to()->asInt(); stage_annot = curr_stage < min_stage ? annot : stage_annot; } } @@ -895,13 +895,14 @@ int IR::MAU::Table::get_provided_stage(int geq_stage, int *req_entries, int *fla if (req_entries) { *req_entries = -1; - for (size_t i = 1; i < stage_annot->expr.size(); ++i) { - if (auto *k = stage_annot->expr.at(i)->to()) *req_entries = k->asInt(); + for (size_t i = 1; i < stage_annot->getExpr().size(); ++i) { + if (auto *k = stage_annot->getExpr().at(i)->to()) + *req_entries = k->asInt(); } } if (flags) { *flags = 0; - for (auto *e : stage_annot->expr) { + for (auto *e : stage_annot->getExpr()) { if (auto *l = e->to()) { if (l->value == "immediate") *flags |= StageFlag::Immediate; @@ -913,7 +914,7 @@ int IR::MAU::Table::get_provided_stage(int geq_stage, int *req_entries, int *fla } } - return stage_annot->expr.at(0)->to()->asInt(); + return stage_annot->getExpr(0)->to()->asInt(); } int IR::MAU::Table::get_random_seed() const { diff --git a/backends/tofino/bf-p4c/mau/asm_output.cpp b/backends/tofino/bf-p4c/mau/asm_output.cpp index 6a0b93fe8e9..f74d9bfaf6e 100644 --- a/backends/tofino/bf-p4c/mau/asm_output.cpp +++ b/backends/tofino/bf-p4c/mau/asm_output.cpp @@ -2450,7 +2450,7 @@ void MauAsmOutput::emit_indirect_res_context_json(std::ostream &, indent_t inden BUG_CHECK((at->is() && at->direct == false) || at->is(), "bind_indirect_res_to_match only allowed on action profiles"); - auto res_name = annot->expr[0]->to()->value; + auto res_name = annot->getExpr(0)->to()->value; // Ignore multiple pragmas for same resource name if (bind_res.count(res_name)) continue; for (auto act : Values(tbl->actions)) { diff --git a/backends/tofino/bf-p4c/mau/dynhash.cpp b/backends/tofino/bf-p4c/mau/dynhash.cpp index e58581f9fd8..8220274dcd9 100644 --- a/backends/tofino/bf-p4c/mau/dynhash.cpp +++ b/backends/tofino/bf-p4c/mau/dynhash.cpp @@ -89,13 +89,13 @@ bool GenerateDynamicHashJson::preorder(const IR::MAU::Table *tbl) { LOG5("Annotations : " << match_table->annotations); for (auto annot : match_table->annotations) { if (annot->name == "action_selector_hash_field_calc_name") - fieldListCalcName = annot->expr[0]->to()->value; + fieldListCalcName = annot->getExpr(0)->to()->value; else if (annot->name == "action_selector_hash_field_list_name") - fieldListName = annot->expr[0]->to()->value; + fieldListName = annot->getExpr(0)->to()->value; else if (annot->name == "action_selector_hash_field_calc_output_width") - hash_bit_width = annot->expr[0]->to()->asInt(); + hash_bit_width = annot->getExpr(0)->to()->asInt(); else if (annot->name == "algorithm") - algorithms.names.push_back(annot->expr[0]->to()->value); + algorithms.names.push_back(annot->getExpr(0)->to()->value); } // If none of the above values are populated dont proceed. LOG5("fieldListCalcName: " << fieldListCalcName << " fieldListName: " << fieldListName diff --git a/backends/tofino/bf-p4c/mau/hash_mask_annotations.h b/backends/tofino/bf-p4c/mau/hash_mask_annotations.h index a1b20763ed8..bfbf415172f 100644 --- a/backends/tofino/bf-p4c/mau/hash_mask_annotations.h +++ b/backends/tofino/bf-p4c/mau/hash_mask_annotations.h @@ -62,11 +62,11 @@ class HashMaskAnnotations { private: bitvec getBitvec(const IR::Annotation *annotation) { bitvec rv; - if (annotation->expr.size() != 1) { + if (annotation->getExpr().size() != 1) { error("%1% should contain a constant", annotation); return rv; } - auto constant = annotation->expr[0]->to(); + auto constant = annotation->getExpr(0)->to(); if (constant == nullptr) { error("%1% should contain a constant", annotation); return rv; diff --git a/backends/tofino/bf-p4c/mau/ixbar_expr.cpp b/backends/tofino/bf-p4c/mau/ixbar_expr.cpp index 0dbcb663690..9455ca2d0e9 100644 --- a/backends/tofino/bf-p4c/mau/ixbar_expr.cpp +++ b/backends/tofino/bf-p4c/mau/ixbar_expr.cpp @@ -109,14 +109,14 @@ bool verifySymmetricHashPairs(const PhvInfo &phv, safe_vectorname != "symmetric") continue; - if (!(annot->expr.size() == 2 && annot->expr.at(0)->is() && - annot->expr.at(1)->is())) { + if (!(annot->getExpr().size() == 2 && annot->getExpr().at(0)->is() && + annot->getExpr().at(1)->is())) { error("%1%: The symmetric annotation requires two string inputs", annot->srcInfo); continue; } - const auto *sl0 = annot->expr.at(0)->to(); - const auto *sl1 = annot->expr.at(1)->to(); + const auto *sl0 = annot->getExpr().at(0)->to(); + const auto *sl1 = annot->getExpr().at(1)->to(); cstring gress_str = (gress == INGRESS ? "ingress::"_cs : "egress::"_cs); auto field0 = phv.field(gress_str + sl0->value); diff --git a/backends/tofino/bf-p4c/mau/resource_estimate.cpp b/backends/tofino/bf-p4c/mau/resource_estimate.cpp index efd7a7b4caa..28c170ee34d 100644 --- a/backends/tofino/bf-p4c/mau/resource_estimate.cpp +++ b/backends/tofino/bf-p4c/mau/resource_estimate.cpp @@ -286,11 +286,11 @@ int SelectorLengthBits(const IR::MAU::Selector *sel) { static int ways_pragma(const IR::MAU::Table *tbl, int min, int max) { if (auto s = tbl->match_table->getAnnotation("ways"_cs)) { - ERROR_CHECK(s->expr.size() >= 1, + ERROR_CHECK(s->getExpr().size() >= 1, "%s: The ways pragma on table %s does not have a " "value", tbl->srcInfo, tbl->name); - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); if (pragma_val == nullptr) { error("%s: The ways pragma value on table %s is not a constant", tbl->srcInfo, tbl->name); @@ -311,11 +311,11 @@ static int ways_pragma(const IR::MAU::Table *tbl, int min, int max) { static int simul_lookups_pragma(const IR::MAU::Table *tbl, int min, int max) { if (auto s = tbl->match_table->getAnnotation("simul_lookups"_cs)) { - ERROR_CHECK(s->expr.size() >= 1, + ERROR_CHECK(s->getExpr().size() >= 1, "%s: The simul_lookups pragma on table %s does not " "have a value", tbl->srcInfo, tbl->name); - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); if (pragma_val == nullptr) { error("%s: The simul_lookups pragma value on table %s is not a constant", tbl->srcInfo, tbl->name); @@ -1662,10 +1662,10 @@ void RangeEntries::postorder(const IR::MAU::Table *tbl) { int range_entries = -1; if (auto s = tbl->match_table->getAnnotation("entries_with_ranges"_cs)) { const IR::Constant *pragma_val = nullptr; - if (s->expr.size() == 0) { + if (s->getExpr().size() == 0) { error("%s: entries_with_ranges pragma on table %s has no value", s->srcInfo, tbl->name); } else { - pragma_val = s->expr.at(0)->to(); + pragma_val = s->getExpr(0)->to(); ERROR_CHECK(pragma_val != nullptr, "%s: the value for the entries_with_ranges " "pragma on table %s is not a constant", diff --git a/backends/tofino/bf-p4c/mau/table_layout.cpp b/backends/tofino/bf-p4c/mau/table_layout.cpp index 7b50bdc9b34..af3521e7331 100644 --- a/backends/tofino/bf-p4c/mau/table_layout.cpp +++ b/backends/tofino/bf-p4c/mau/table_layout.cpp @@ -246,11 +246,11 @@ void TableLayout::check_for_alpm(IR::MAU::Table::Layout &, const IR::MAU::Table void TableLayout::check_for_ternary(IR::MAU::Table::Layout &layout, const IR::MAU::Table *tbl) { if (auto s = tbl->match_table->getAnnotation("ternary"_cs)) { - if (s->expr.size() <= 0) { + if (s->getExpr().size() <= 0) { warning(BFN::ErrorType::WARN_PRAGMA_USE, "Pragma ternary ignored for table %1% because value is undefined", tbl); } else { - auto *pragma_val = s->expr.at(0)->to(); + auto *pragma_val = s->getExpr(0)->to(); ERROR_CHECK(pragma_val != nullptr, ErrorType::ERR_UNKNOWN, "unknown ternary pragma %1% on table %2%.", s, tbl->externalName()); if (pragma_val->asInt() == 1) @@ -283,11 +283,11 @@ void TableLayout::check_for_ternary(IR::MAU::Table::Layout &layout, const IR::MA void DoTableLayout::check_for_proxy_hash(IR::MAU::Table::Layout &layout, const IR::MAU::Table *tbl) { if (auto s = tbl->match_table->getAnnotation("proxy_hash_width"_cs)) { - if (s->expr.size() <= 0) { + if (s->getExpr().size() <= 0) { warning(BFN::ErrorType::WARN_PRAGMA_USE, "Proxy hash pragma ignored for table %1% because value is undefined.", tbl); } else { - auto *pragma_val = s->expr.at(0)->to(); + auto *pragma_val = s->getExpr(0)->to(); ERROR_CHECK(pragma_val != nullptr, ErrorType::ERR_INVALID, "%1%: proxy hash pragma on table %2%. It is not a constant.", s, tbl->externalName()); @@ -322,8 +322,8 @@ bool DoTableLayout::check_for_versioning(const IR::MAU::Table *tbl) { } if (auto s = tbl->match_table->getAnnotation("no_versioning"_cs)) { - if (s->expr.size() > 0) { - auto pragma_val = s->expr.at(0)->to(); + if (s->getExpr().size() > 0) { + auto pragma_val = s->getExpr(0)->to(); if (pragma_val && (pragma_val->asInt() == 1 || pragma_val->asInt() == 0)) { rv = pragma_val->asInt() == 0; } else { @@ -478,7 +478,7 @@ void DoTableLayout::setup_match_layout(IR::MAU::Table::Layout &layout, const IR: if (!layout.exact && tbl->match_table) { auto s = tbl->match_table->getAnnotation("dynamic_table_key_masks"_cs); - ERROR_CHECK(!s || s->expr.size() <= 0, ErrorType::ERR_INVALID, + ERROR_CHECK(!s || s->getExpr().size() <= 0, ErrorType::ERR_INVALID, "Table %1%. @dynamic_table_key_masks annotation only permissible with " "exact matches", tbl->externalName()); @@ -661,9 +661,9 @@ int LayoutChoices::get_pack_pragma_val(const IR::MAU::Table *tbl, int pack_val = 0; if (auto s = tbl->match_table->getAnnotation("pack"_cs)) { - ERROR_CHECK(s->expr.size() > 0, ErrorType::ERR_INVALID, + ERROR_CHECK(s->getExpr().size() > 0, ErrorType::ERR_INVALID, "pack pragma. It has no value for table %1%.", tbl); - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); ERROR_CHECK(pragma_val != nullptr, ErrorType::ERR_INVALID, "pack pragma value for table %1%. Must be a constant.", tbl); if (pragma_val) { @@ -949,7 +949,7 @@ void LayoutChoices::add_hash_action_option(const IR::MAU::Table *tbl, if (!tbl->match_table) return; if (auto s = tbl->match_table->getAnnotation("use_hash_action"_cs)) { - auto pragma_val = s->expr.at(0)->to()->asInt(); + auto pragma_val = s->getExpr(0)->to()->asInt(); ERROR_CHECK(pragma_val == 1 || pragma_val == 0, ErrorType::ERR_INVALID, "%1%: value %3%. Please provide a 1 to enable the use of the hash action " "path, or a 0 to disable the hash action path for for table %2%.", @@ -1056,9 +1056,9 @@ bool DoTableLayout::preorder(IR::MAU::Table *tbl) { if (!not_hash_action) tbl->layout.hash_action = true; if (tbl->match_table) { if (auto s = tbl->match_table->getAnnotation("dynamic_table_key_masks"_cs)) { - ERROR_CHECK(s->expr.size() > 0, ErrorType::ERR_INVALID, + ERROR_CHECK(s->getExpr().size() > 0, ErrorType::ERR_INVALID, "dynamic_table_key_masks pragma. Has no value for table %1%.", tbl); - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); ERROR_CHECK(pragma_val != nullptr, ErrorType::ERR_INVALID, "pack pragma value for table %1%. Must be a constant.", tbl); if (pragma_val) { @@ -1290,9 +1290,9 @@ void AssignCounterLRTValues::ComputeLRT::calculate_lrt_threshold_and_interval( if (cntr->threshold != -1) return; /* calculated already? */ bool lrt_enabled = CounterWidth(cntr) < 64; if (auto s = cntr->getAnnotation("lrt_enable"_cs)) { - ERROR_CHECK(s->expr.size() >= 1, ErrorType::ERR_INVALID, + ERROR_CHECK(s->getExpr().size() >= 1, ErrorType::ERR_INVALID, "lrt_enable pragma on counter %1%. Does not have a value.", cntr); - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); if (pragma_val == nullptr) { error(ErrorType::ERR_INVALID, "lrt_enable value on counter %1%. It is not a constant.", cntr); @@ -1315,7 +1315,7 @@ void AssignCounterLRTValues::ComputeLRT::calculate_lrt_threshold_and_interval( if (lrt_enabled) { auto s = cntr->getAnnotation("lrt_scale"_cs); if (s) { - auto lrt_val = s->expr.at(0)->to(); + auto lrt_val = s->getExpr(0)->to(); if (lrt_val == nullptr) { error(ErrorType::ERR_INVALID, "lrt_scale value on counter %1%. It is not a constant.", cntr); diff --git a/backends/tofino/bf-p4c/mau/tofino/input_xbar.cpp b/backends/tofino/bf-p4c/mau/tofino/input_xbar.cpp index bd011662601..2fc447c294b 100644 --- a/backends/tofino/bf-p4c/mau/tofino/input_xbar.cpp +++ b/backends/tofino/bf-p4c/mau/tofino/input_xbar.cpp @@ -1741,7 +1741,7 @@ void IXBar::determine_proxy_hash_alg(const PhvInfo &phv, const IR::MAU::Table *t int group) { bool hash_function_found = false; if (auto s = tbl->match_table->getAnnotation("proxy_hash_algorithm"_cs)) { - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); if (pragma_val == nullptr) { error(ErrorType::ERR_INVALID, "proxy_hash_algorithm pragma on table %1% must be a string", tbl); diff --git a/backends/tofino/bf-p4c/midend/alpm.cpp b/backends/tofino/bf-p4c/midend/alpm.cpp index a13dd6ad7fd..aa86c8539ab 100644 --- a/backends/tofino/bf-p4c/midend/alpm.cpp +++ b/backends/tofino/bf-p4c/midend/alpm.cpp @@ -394,11 +394,11 @@ const IR::P4Table *SplitAlpm::create_preclassifier_table(const IR::P4Table *tbl, bool SplitAlpm::values_through_pragmas(const IR::P4Table *tbl, int &number_partitions, int &number_subtrees_per_partition) { if (auto s = tbl->getAnnotation(ALGORITHMIC_LPM_PARTITIONS)) { - ERROR_CHECK(s->expr.size() > 0, + ERROR_CHECK(s->getExpr().size() > 0, "%s: Please provide a valid %s " "for table %s", tbl->srcInfo, ALGORITHMIC_LPM_PARTITIONS, tbl->name); - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); ERROR_CHECK(pragma_val != nullptr, "%s: Please provide a valid %s " "for table %s", @@ -416,11 +416,11 @@ bool SplitAlpm::values_through_pragmas(const IR::P4Table *tbl, int &number_parti } if (auto s = tbl->getAnnotation(ALGORITHMIC_LPM_SUBTREES_PER_PARTITION)) { - ERROR_CHECK(s->expr.size() > 0, + ERROR_CHECK(s->getExpr().size() > 0, "%s: Please provide a valid %s " "for table %s", tbl->srcInfo, ALGORITHMIC_LPM_SUBTREES_PER_PARTITION, tbl->name); - auto pragma_val = s->expr.at(0)->to(); + auto pragma_val = s->getExpr(0)->to(); ERROR_CHECK(pragma_val != nullptr, "%s: Please provide a valid %s " "for table %s", @@ -531,7 +531,7 @@ bool SplitAlpm::pragma_exclude_msbs(const IR::P4Table *tbl, // that also works. This is needed for programs translated from p4-14. auto fname_annot = k->getAnnotation("name"_cs); if (fname_annot != nullptr) { - auto fname = fname_annot->expr.at(0)->to()->value; + auto fname = fname_annot->getExpr(0)->to()->value; // if annotation use a different name than the original field. if (field_name_to_width.count(fname) == 0) { analyze_key_name_and_type(k, fname); @@ -540,17 +540,17 @@ bool SplitAlpm::pragma_exclude_msbs(const IR::P4Table *tbl, } for (auto an : tbl->getAnnotations()) { if (an->name != ALGORITHMIC_LPM_ATCAM_EXCLUDE_FIELD_MSBS) continue; - if (an->expr.size() != 1 && an->expr.size() != 2) { + if (an->getExpr().size() != 1 && an->getExpr().size() != 2) { error( "Invalid %s pragma on table %s.\n Expected field name " "and optional msb bits %s", - ALGORITHMIC_LPM_ATCAM_EXCLUDE_FIELD_MSBS, tbl->name, an->expr); + ALGORITHMIC_LPM_ATCAM_EXCLUDE_FIELD_MSBS, tbl->name, an->getExpr()); } cstring fname; - if (auto annot = an->expr.at(0)->to()) { + if (auto annot = an->getExpr(0)->to()) { fname = annot->value; } else { - fname = an->expr.at(0)->toString(); + fname = an->getExpr(0)->toString(); } if (field_name_to_width.find(fname) == field_name_to_width.end()) { error("Invalid %s pragma on table %s.\n Field %s is not part of the table key.", @@ -568,8 +568,8 @@ bool SplitAlpm::pragma_exclude_msbs(const IR::P4Table *tbl, } std::stringstream additional; bool msb_error = false; - if (an->expr.size() == 2) { - auto msb_bits_to_exclude = an->expr.at(1)->to()->value; + if (an->getExpr().size() == 2) { + auto msb_bits_to_exclude = an->getExpr().at(1)->to()->value; if (msb_bits_to_exclude <= 0) { msb_error = true; } else if (msb_bits_to_exclude > field_name_to_width.at(fname)) { @@ -594,7 +594,8 @@ bool SplitAlpm::pragma_exclude_msbs(const IR::P4Table *tbl, "Invalid %s pragma on table %s.\n " " Invalid most significant bits to exclude value of '%s'.\n" "%s", - ALGORITHMIC_LPM_ATCAM_EXCLUDE_FIELD_MSBS, tbl->name, an->expr[0], additional.str()); + ALGORITHMIC_LPM_ATCAM_EXCLUDE_FIELD_MSBS, tbl->name, an->getExpr(0), + additional.str()); } } @@ -777,13 +778,13 @@ void CollectAlpmInfo::postorder(const IR::P4Table *tbl) { // support @alpm(1) or @alpm(true) if (auto s = tbl->getAnnotation(cstring(PragmaAlpm::name))) { - ERROR_CHECK(s->expr.size() > 0, + ERROR_CHECK(s->getExpr().size() > 0, "%s: Please provide a valid alpm " "for table %s", tbl->srcInfo, tbl->name); - if (auto pragma_val = s->expr.at(0)->to()) { + if (auto pragma_val = s->getExpr(0)->to()) { if (pragma_val->asInt()) alpm_table.insert(tbl->name); - } else if (auto pragma_val = s->expr.at(0)->to()) { + } else if (auto pragma_val = s->getExpr(0)->to()) { if (pragma_val->value) alpm_table.insert(tbl->name); } else { error("%s: Please provide a valid alpm for table %s", tbl->srcInfo, tbl->name); diff --git a/backends/tofino/bf-p4c/parde/clot/pragma/do_not_use_clot.cpp b/backends/tofino/bf-p4c/parde/clot/pragma/do_not_use_clot.cpp index 4ec123e221b..1daf341389c 100644 --- a/backends/tofino/bf-p4c/parde/clot/pragma/do_not_use_clot.cpp +++ b/backends/tofino/bf-p4c/parde/clot/pragma/do_not_use_clot.cpp @@ -51,7 +51,7 @@ bool PragmaDoNotUseClot::preorder(const IR::BFN::Pipe *pipe) { for (const auto &annotation : global_pragmas) { if (annotation->name.name != PragmaDoNotUseClot::name) continue; - const IR::Vector &exprs = annotation->expr; + const IR::Vector &exprs = annotation->getExpr(); if (!PHV::Pragmas::checkStringLiteralArgs(exprs)) { continue; diff --git a/backends/tofino/bf-p4c/parde/extract_deparser.cpp b/backends/tofino/bf-p4c/parde/extract_deparser.cpp index 5f019649fd3..ee69aa59a9a 100644 --- a/backends/tofino/bf-p4c/parde/extract_deparser.cpp +++ b/backends/tofino/bf-p4c/parde/extract_deparser.cpp @@ -31,7 +31,7 @@ bool ExtractDeparser::preorder(const IR::Annotation *annot) { if (annot->name == "header_ordering") { auto ordering = new ordered_set; - for (auto expr : annot->expr) { + for (auto expr : annot->getExpr()) { if (auto str = expr->to()) { for (auto &o : userEnforcedHeaderOrdering) { if (o->count(str->value)) diff --git a/backends/tofino/bf-p4c/parde/extract_parser.cpp b/backends/tofino/bf-p4c/parde/extract_parser.cpp index 5e49d076a7a..3cb874e2df9 100644 --- a/backends/tofino/bf-p4c/parde/extract_parser.cpp +++ b/backends/tofino/bf-p4c/parde/extract_parser.cpp @@ -471,8 +471,8 @@ const IR::BFN::Parser *GetBackendParser::createBackendParser() { LOG3("mark " << state->name << " as strided"); } if (auto dontmerge = state->getAnnotation("dontmerge"_cs)) { - if (dontmerge->expr.size()) { - auto gress = dontmerge->expr[0]->to(); + if (dontmerge->getExpr().size()) { + auto gress = dontmerge->getExpr(0)->to(); if (gress->value == toString(parser->thread)) { backendState->dontMerge = true; } @@ -599,7 +599,7 @@ void GetBackendParser::addTransition(IR::BFN::ParserState *state, match_t matchV // overriding the pvs name with the name in the annotation. cstring valueSetName; if (auto anno = valueSet->getAnnotation("pd_pvs_name"_cs)) { - auto name = anno->expr.at(0)->to(); + auto name = anno->getExpr(0)->to(); valueSetName = name->value; } else { valueSetName = valueSet->controlPlaneName(); diff --git a/backends/tofino/bf-p4c/parde/parser_loops_info.cpp b/backends/tofino/bf-p4c/parde/parser_loops_info.cpp index 88723896e1d..620581f4d4d 100644 --- a/backends/tofino/bf-p4c/parde/parser_loops_info.cpp +++ b/backends/tofino/bf-p4c/parde/parser_loops_info.cpp @@ -62,7 +62,7 @@ bool ParserPragmas::preorder(const IR::Annotation *annot) { if (!p || !ps) return false; if (pragma_name == "terminate_parsing") { - auto &exprs = annot->expr; + auto &exprs = annot->getExpr(); if (!checkNumArgs(pragma_name, exprs, 1)) return false; auto gress = exprs[0]->to(); @@ -72,7 +72,7 @@ bool ParserPragmas::preorder(const IR::Annotation *annot) { terminate_parsing.insert(ps); } } else if (pragma_name == "force_shift") { - auto &exprs = annot->expr; + auto &exprs = annot->getExpr(); if (!checkNumArgs(pragma_name, exprs, 2)) return false; auto gress = exprs[0]->to(); @@ -88,7 +88,7 @@ bool ParserPragmas::preorder(const IR::Annotation *annot) { force_shift[ps] = shift_amt->asInt(); } } else if (pragma_name == "max_loop_depth") { - auto &exprs = annot->expr; + auto &exprs = annot->getExpr(); if (!checkNumArgs(pragma_name, exprs, 1)) return false; auto max_loop = exprs[0]->to(); diff --git a/backends/tofino/bf-p4c/phv/analysis/non_mocha_dark_fields.cpp b/backends/tofino/bf-p4c/phv/analysis/non_mocha_dark_fields.cpp index 95c44078de1..3187f2f6f33 100644 --- a/backends/tofino/bf-p4c/phv/analysis/non_mocha_dark_fields.cpp +++ b/backends/tofino/bf-p4c/phv/analysis/non_mocha_dark_fields.cpp @@ -61,7 +61,7 @@ bool NonMochaDarkFields::preorder(const IR::MAU::Action *act) { nonDark[write->id][tbl] = WRITE; if (auto s = tbl->match_table->getAnnotation("use_hash_action"_cs)) { - auto pragma_val = s->expr.at(0)->to()->asInt(); + auto pragma_val = s->getExpr(0)->to()->asInt(); if (pragma_val == 1) { LOG5("\t Field written by action data/constant through hash_action: " << write); diff --git a/backends/tofino/bf-p4c/phv/analysis/parser_critical_path.h b/backends/tofino/bf-p4c/phv/analysis/parser_critical_path.h index 125220bc2a8..3983e343c18 100644 --- a/backends/tofino/bf-p4c/phv/analysis/parser_critical_path.h +++ b/backends/tofino/bf-p4c/phv/analysis/parser_critical_path.h @@ -94,7 +94,7 @@ class CollectUserSpecifiedCriticalStates : public Inspector { for (const auto *p4State : state->p4States) { for (auto annot : p4State->annotations) { if (annot->name.name == "critical") { - auto &exprs = annot->expr; + auto &exprs = annot->getExpr(); if (exprs.size() == 1) { auto gress = exprs[0]->to(); if (!gress) { diff --git a/backends/tofino/bf-p4c/phv/auto_init_metadata.cpp b/backends/tofino/bf-p4c/phv/auto_init_metadata.cpp index 1bb08788250..c6c956a9f57 100644 --- a/backends/tofino/bf-p4c/phv/auto_init_metadata.cpp +++ b/backends/tofino/bf-p4c/phv/auto_init_metadata.cpp @@ -177,16 +177,16 @@ const IR::BFN::Pipe *RemoveMetadataInits::preorder(IR::BFN::Pipe *pipe) { for (auto anno : pipe->global_pragmas) { if (anno->name != PragmaNoInit::name) continue; - BUG_CHECK(anno->expr.size() == 2, "%1% pragma expects two arguments, but got %2%: %3%", - PragmaNoInit::name, anno->expr.size(), anno); + BUG_CHECK(anno->getExpr().size() == 2, "%1% pragma expects two arguments, but got %2%: %3%", + PragmaNoInit::name, anno->getExpr().size(), anno); - auto gress = anno->expr.at(0)->to(); + auto gress = anno->getExpr(0)->to(); BUG_CHECK(gress, "First argument to %1% is not a string: %2%", PragmaNoInit::name, - anno->expr.at(0)); + anno->getExpr(0)); - auto field = anno->expr.at(1)->to(); + auto field = anno->getExpr(1)->to(); BUG_CHECK(field, "Second argument to %1% is not a string: %2%", PragmaNoInit::name, - anno->expr.at(1)); + anno->getExpr().at(1)); pa_no_inits.insert(gress->value + "::" + field->value); } diff --git a/backends/tofino/bf-p4c/phv/phv_spec.cpp b/backends/tofino/bf-p4c/phv/phv_spec.cpp index 682abcb9a1c..7a43f0c578c 100644 --- a/backends/tofino/bf-p4c/phv/phv_spec.cpp +++ b/backends/tofino/bf-p4c/phv/phv_spec.cpp @@ -728,7 +728,7 @@ void PhvSpec::applyGlobalPragmas(const std::vector &glob physicalContainers(); // create the cache if needed PHV::Container startRange, prev; bool negate = false; - for (auto *tok : annot->body) { + for (auto *tok : annot->getUnparsed()) { PHV::Container c(tok->text.c_str(), false); if (startRange) { if (tok->token_type == P4::P4Parser::token_type::TOK_INTEGER) diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_alias.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_alias.cpp index 9da2b7126c1..d4903d7557e 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_alias.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_alias.cpp @@ -221,7 +221,7 @@ void PragmaAlias::postorder(const IR::BFN::Pipe *pipe) { if (annotation->name.name != PragmaAlias::name) continue; LOG3("Annotation: " << annotation); - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); if (!PHV::Pragmas::checkStringLiteralArgs(exprs)) { continue; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_atomic.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_atomic.cpp index 76f0b0a2373..5c6f9502bea 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_atomic.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_atomic.cpp @@ -80,7 +80,7 @@ bool PragmaAtomic::preorder(const IR::BFN::Pipe *pipe) { for (const auto *annotation : global_pragmas) { if (annotation->name.name != PragmaAtomic::name) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); if (!PHV::Pragmas::checkStringLiteralArgs(exprs)) { continue; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_byte_pack.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_byte_pack.cpp index 87c8c2cc760..97a51149954 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_byte_pack.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_byte_pack.cpp @@ -65,7 +65,7 @@ bool PragmaBytePack::preorder(const IR::BFN::Pipe *pipe) { for (const auto *annotation : global_pragmas) { if (annotation->name.name != PragmaBytePack::name) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); const unsigned min_required_arguments = 2; // gress, field1.... unsigned required_arguments = min_required_arguments; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_container_size.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_container_size.cpp index 766478dddd5..97ecf8b1467 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_container_size.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_container_size.cpp @@ -115,7 +115,7 @@ bool PragmaContainerSize::preorder(const IR::BFN::Pipe *pipe) { for (const auto *annotation : global_pragmas) { if (annotation->name.name != PragmaContainerSize::name) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); const unsigned min_required_arguments = 3; // gress, field, size1, ... unsigned required_arguments = min_required_arguments; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_container_type.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_container_type.cpp index a82ddcc5496..24d9e3fe80f 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_container_type.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_container_type.cpp @@ -97,7 +97,7 @@ bool PragmaContainerType::preorder(const IR::BFN::Pipe *pipe) { for (const auto *annotation : global_pragmas) { if (annotation->name.name != PragmaContainerType::name) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); if (!PHV::Pragmas::checkStringLiteralArgs(exprs)) { continue; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_deparser_zero.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_deparser_zero.cpp index 711ad12c99d..6b9c60719c1 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_deparser_zero.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_deparser_zero.cpp @@ -42,7 +42,7 @@ bool PragmaDeparserZero::preorder(const IR::BFN::Pipe *pipe) { supported_pragmas->end()) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); const IR::StringLiteral *pipe_arg = nullptr; if (exprs.at(0)) { diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_mutually_exclusive.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_mutually_exclusive.cpp index d6495118d83..26ec9a11849 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_mutually_exclusive.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_mutually_exclusive.cpp @@ -51,7 +51,7 @@ bool PragmaMutuallyExclusive::preorder(const IR::BFN::Pipe *pipe) { for (const auto &annotation : global_pragmas) { if (annotation->name.name != PragmaMutuallyExclusive::name) continue; - const IR::Vector &exprs = annotation->expr; + const IR::Vector &exprs = annotation->getExpr(); if (!PHV::Pragmas::checkStringLiteralArgs(exprs)) { continue; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_no_init.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_no_init.cpp index 94ce2ca9c36..b99e38b7af4 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_no_init.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_no_init.cpp @@ -65,7 +65,7 @@ bool PragmaNoInit::preorder(const IR::BFN::Pipe *pipe) { for (const auto *annotation : global_pragmas) { if (annotation->name.name != PragmaNoInit::name) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); if (!PHV::Pragmas::checkStringLiteralArgs(exprs)) { continue; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_no_overlay.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_no_overlay.cpp index b2b61005c01..e75ea3b76a4 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_no_overlay.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_no_overlay.cpp @@ -66,7 +66,7 @@ bool PragmaNoOverlay::preorder(const IR::BFN::Pipe *pipe) { for (const auto *annotation : global_pragmas) { if (annotation->name.name != PragmaNoOverlay::name) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); if (!PHV::Pragmas::checkStringLiteralArgs(exprs)) { continue; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_no_pack.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_no_pack.cpp index 79f9dc21e22..40ae928753d 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_no_pack.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_no_pack.cpp @@ -40,7 +40,7 @@ bool PragmaNoPack::preorder(const IR::BFN::Pipe *pipe) { for (const auto *annotation : global_pragmas) { if (annotation->name.name != PragmaNoPack::name) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); const unsigned min_required_arguments = 3; // gress, field1, field2.... unsigned required_arguments = min_required_arguments; diff --git a/backends/tofino/bf-p4c/phv/pragma/pa_solitary.cpp b/backends/tofino/bf-p4c/phv/pragma/pa_solitary.cpp index 905cb6e79dc..d45b6d3aeda 100644 --- a/backends/tofino/bf-p4c/phv/pragma/pa_solitary.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/pa_solitary.cpp @@ -49,7 +49,7 @@ bool PragmaSolitary::preorder(const IR::BFN::Pipe *pipe) { for (const auto *annotation : global_pragmas) { if (annotation->name.name != PragmaSolitary::name) continue; - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); if (!PHV::Pragmas::checkStringLiteralArgs(exprs)) { continue; diff --git a/backends/tofino/bf-p4c/phv/pragma/phv_pragmas.cpp b/backends/tofino/bf-p4c/phv/pragma/phv_pragmas.cpp index 0004fdcbe76..6fa85721169 100644 --- a/backends/tofino/bf-p4c/phv/pragma/phv_pragmas.cpp +++ b/backends/tofino/bf-p4c/phv/pragma/phv_pragmas.cpp @@ -97,7 +97,7 @@ bool PHV::Pragmas::checkStringLiteralArgs(const IR::Vector &expr bool PHV::Pragmas::checkNumberArgs(const IR::Annotation *annotation, unsigned required_args, const unsigned min_required_args, bool exact_number_of_args, cstring pragma_name, cstring pragma_args_wo_pipe) { - auto &exprs = annotation->expr; + auto &exprs = annotation->getExpr(); if ((exact_number_of_args && exprs.size() != required_args) || exprs.size() < required_args) { warning(ErrorType::WARN_INVALID, "%1%: Invalid number of arguments. " diff --git a/backends/tofino/bf-p4c/phv/v2/phv_kit.cpp b/backends/tofino/bf-p4c/phv/v2/phv_kit.cpp index c7f9772343a..d0f43963267 100644 --- a/backends/tofino/bf-p4c/phv/v2/phv_kit.cpp +++ b/backends/tofino/bf-p4c/phv/v2/phv_kit.cpp @@ -390,10 +390,10 @@ void PhvKit::sort_and_merge_alloc_slices(PhvInfo &phv) { bool PhvKit::is_ternary(const IR::MAU::Table *tbl) { if (auto s = tbl->match_table->getAnnotation("ternary"_cs)) { - if (s->expr.size() <= 0) { + if (s->getExpr().size() <= 0) { return false; } else { - auto *pragma_val = s->expr.at(0)->to(); + auto *pragma_val = s->getExpr(0)->to(); ERROR_CHECK(pragma_val != nullptr, ErrorType::ERR_UNKNOWN, "unknown ternary pragma %1% on table %2%.", s, tbl->externalName()); if (pragma_val->asInt() == 1) { diff --git a/control-plane/p4RuntimeArchHandler.cpp b/control-plane/p4RuntimeArchHandler.cpp index bf2bc5a7faa..f8c270aa7ee 100644 --- a/control-plane/p4RuntimeArchHandler.cpp +++ b/control-plane/p4RuntimeArchHandler.cpp @@ -156,26 +156,25 @@ void serializeStructuredKVPair(const IR::NamedExpression *kv, p4configv1::KeyVal void serializeOneStructuredAnnotation(const IR::Annotation *annotation, p4configv1::StructuredAnnotation *structuredAnnotation) { + BUG_CHECK(annotation->structured, "%1%: not a structured annotation", annotation); structuredAnnotation->set_name(annotation->name.name); - switch (annotation->annotationKind()) { - case IR::Annotation::Kind::StructuredEmpty: - // nothing to do, body oneof should be empty. - return; - case IR::Annotation::Kind::StructuredExpressionList: - for (auto *expr : annotation->expr) { - serializeStructuredExpression( - expr, structuredAnnotation->mutable_expression_list()->add_expressions()); - } - return; - case IR::Annotation::Kind::StructuredKVList: - for (auto *kv : annotation->kv) { - serializeStructuredKVPair( - kv, structuredAnnotation->mutable_kv_pair_list()->add_kv_pairs()); + + std::visit( + [&](const auto &body) { + using T = std::decay_t; + if constexpr (std::is_same_v>) { + for (auto *expr : body) + serializeStructuredExpression( + expr, structuredAnnotation->mutable_expression_list()->add_expressions()); + } else if constexpr (std::is_same_v>) { + for (auto *kv : body) + serializeStructuredKVPair( + kv, structuredAnnotation->mutable_kv_pair_list()->add_kv_pairs()); + } else { + BUG("Unexpected variant field"); } - return; - default: - BUG("%1%: not a structured annotation", annotation); - } + }, + annotation->body); } } // namespace Helpers diff --git a/control-plane/p4RuntimeArchHandler.h b/control-plane/p4RuntimeArchHandler.h index 923091a5c89..afe38e1289a 100644 --- a/control-plane/p4RuntimeArchHandler.h +++ b/control-plane/p4RuntimeArchHandler.h @@ -276,7 +276,8 @@ void addAnnotations(Message *message, const IR::IAnnotated *annotated, UnaryPred for (const IR::Annotation *annotation : annotated->getAnnotations()) { // Always add all structured annotations. - if (annotation->annotationKind() != IR::Annotation::Kind::Unstructured) { + if (annotation->annotationKind() != IR::Annotation::Kind::Unstructured && + annotation->annotationKind() != IR::Annotation::Kind::Unparsed) { serializeOneStructuredAnnotation(annotation, message->add_structured_annotations()); continue; } @@ -318,7 +319,7 @@ void addDocumentation(Message *message, const IR::IAnnotated *annotated) { // the message if at least one of them is present. for (const IR::Annotation *annotation : annotated->getAnnotations()) { if (annotation->name == "brief") { - auto brief = annotation->expr[0]->to(); + auto brief = annotation->getExpr(0)->to(); // guaranteed by ParseAnnotations pass CHECK_NULL(brief); doc.set_brief(brief->value); @@ -326,7 +327,7 @@ void addDocumentation(Message *message, const IR::IAnnotated *annotated) { continue; } if (annotation->name == "description") { - auto description = annotation->expr[0]->to(); + auto description = annotation->getExpr(0)->to(); // guaranteed by ParseAnnotations pass CHECK_NULL(description); doc.set_description(description->value); diff --git a/control-plane/p4RuntimeArchStandard.h b/control-plane/p4RuntimeArchStandard.h index 4678af8e8e6..8bff90d615f 100644 --- a/control-plane/p4RuntimeArchStandard.h +++ b/control-plane/p4RuntimeArchStandard.h @@ -780,7 +780,7 @@ class P4RuntimeArchHandlerCommon : public P4RuntimeArchHandlerIface { if (maxGroupSizeAnnotation) { if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR) { auto maxGroupSizeConstant = - maxGroupSizeAnnotation->expr[0]->checkedTo(); + maxGroupSizeAnnotation->getExpr(0)->checkedTo(); CHECK_NULL(maxGroupSizeConstant); profile->set_max_group_size(maxGroupSizeConstant->asInt()); } else { @@ -797,7 +797,7 @@ class P4RuntimeArchHandlerCommon : public P4RuntimeArchHandlerIface { if (selectorSizeSemanticsAnnotation) { if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR) { auto selectorSizeSemantics = - selectorSizeSemanticsAnnotation->expr[0]->checkedTo(); + selectorSizeSemanticsAnnotation->getExpr(0)->checkedTo(); CHECK_NULL(selectorSizeSemantics); // The expression may only contain 'sum_of_weights' or 'sum_of_members' // in any case. @@ -826,7 +826,7 @@ class P4RuntimeArchHandlerCommon : public P4RuntimeArchHandlerIface { if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR && profile->has_sum_of_members()) { auto maxMemberWeightConstant = - maxMemberWeightAnnotation->expr[0]->checkedTo(); + maxMemberWeightAnnotation->getExpr(0)->checkedTo(); CHECK_NULL(maxMemberWeightConstant); profile->mutable_sum_of_members()->set_max_member_weight( maxMemberWeightConstant->asInt()); diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index b17d29cac3b..76c71f9e008 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -83,11 +83,12 @@ using Helpers::setPreamble; static std::optional explicitNameAnnotation(const IR::IAnnotated *item) { auto *anno = item->getAnnotation(IR::Annotation::nameAnnotation); if (!anno) return std::nullopt; - if (anno->expr.size() != 1) { + const auto &expr = anno->getExpr(); + if (expr.size() != 1) { ::P4::error(ErrorType::ERR_INVALID, "A %1% annotation must have one argument", anno); return std::nullopt; } - auto *str = anno->expr[0]->to(); + auto *str = expr[0]->to(); if (!str) { ::P4::error(ErrorType::ERR_INVALID, "An %1% annotation's argument must be a string", anno); return std::nullopt; @@ -605,7 +606,7 @@ class P4RuntimeAnalyzer { auto controllerAnnotation = type->getAnnotation("controller_header"_cs); CHECK_NULL(controllerAnnotation); - auto nameConstant = controllerAnnotation->expr[0]->to(); + auto nameConstant = controllerAnnotation->getExpr(0)->to(); CHECK_NULL(nameConstant); auto controllerName = nameConstant->value; @@ -694,9 +695,9 @@ class P4RuntimeAnalyzer { auto *protoParam = table->mutable_initial_default_action()->mutable_arguments()->Add(); const auto *parameter = defaultAction->action->parameters->parameters.at(parameterIndex++); - const auto *idAnnotation = parameter->getAnnotation("id"_cs); - if (idAnnotation != nullptr) { - protoParam->set_param_id(idAnnotation->expr[0]->checkedTo()->asInt()); + if (const auto *idAnnotation = parameter->getAnnotation("id"_cs)) { + protoParam->set_param_id( + idAnnotation->getExpr(0)->checkedTo()->asInt()); } else { protoParam->set_param_id(parameterId); } @@ -710,8 +711,10 @@ class P4RuntimeAnalyzer { action_ref->set_id(id); addAnnotations(action_ref, action.annotations); // set action ref scope - auto isTableOnly = (action.annotations->getAnnotation("tableonly"_cs) != nullptr); - auto isDefaultOnly = (action.annotations->getAnnotation("defaultonly"_cs) != nullptr); + auto isTableOnly = + action.annotations->hasAnnotation(IR::Annotation::tableOnlyAnnotation); + auto isDefaultOnly = + action.annotations->hasAnnotation(IR::Annotation::defaultOnlyAnnotation); if (isTableOnly && isDefaultOnly) { ::P4::error(ErrorType::ERR_INVALID, "Table '%1%' has an action reference ('%2%') which is annotated " @@ -827,7 +830,7 @@ class P4RuntimeAnalyzer { match->set_match_type(MatchField::MatchTypes::EXACT); // default match type return; } - auto matchPathExpr = matchAnnotation->expr[0]->to(); + auto matchPathExpr = matchAnnotation->getExpr(0)->to(); CHECK_NULL(matchPathExpr); auto matchTypeName = getMatchTypeName(matchPathExpr, refMap); auto matchType = getMatchType(matchTypeName); @@ -938,9 +941,8 @@ class P4RuntimeAnalyzer { std::set keysVisited; // @pkginfo annotation - for (auto *annotation : decl->getAnnotations()) { - if (annotation->name != IR::Annotation::pkginfoAnnotation) continue; - for (auto *kv : annotation->kv) { + if (const auto *annotation = decl->getAnnotation(IR::Annotation::pkginfoAnnotation)) { + for (auto *kv : annotation->getKV()) { auto name = kv->name.name; auto setStringField = [kv, pkginfo, &keysVisited](cstring fName) { auto *v = kv->expression->to(); @@ -981,10 +983,9 @@ class P4RuntimeAnalyzer { } // Parse `@platform_property` annotation into the PkgInfo. - for (auto *annotation : decl->getAnnotations()) { - if (annotation->name != "platform_property") continue; + if (const auto *annotation = decl->getAnnotation("platform_property"_cs)) { auto *platform_properties = pkginfo->mutable_platform_properties(); - for (auto *kv : annotation->kv) { + for (auto *kv : annotation->getKV()) { auto name = kv->name.name; auto setInt32Field = [kv, &platform_properties](cstring fName) { auto *v = kv->expression->to(); diff --git a/control-plane/p4RuntimeSymbolTable.cpp b/control-plane/p4RuntimeSymbolTable.cpp index 898aaf1471e..da157747a52 100644 --- a/control-plane/p4RuntimeSymbolTable.cpp +++ b/control-plane/p4RuntimeSymbolTable.cpp @@ -38,7 +38,7 @@ bool isHidden(const IR::IAnnotated *node) { std::optional getIdAnnotation(const IR::IAnnotated *node) { if (const auto *idAnn = node->getAnnotation(idAnnotation)) { - const auto *idConstant = idAnn->expr.at(0)->to(); + const auto *idConstant = idAnn->getExpr(0)->to(); CHECK_NULL(idConstant); if (!idConstant->fitsUint()) { ::P4::error(ErrorType::ERR_INVALID, "%1%: @id should be an unsigned integer", node); diff --git a/control-plane/typeSpecConverter.cpp b/control-plane/typeSpecConverter.cpp index 50855513db5..e4b1befdf37 100644 --- a/control-plane/typeSpecConverter.cpp +++ b/control-plane/typeSpecConverter.cpp @@ -47,12 +47,13 @@ bool hasTranslationAnnotation(const IR::Type *type, TranslationAnnotation *paylo if (!ann) return false; // Syntax: @pruntime_translation(, ). - BUG_CHECK(ann->expr.size() == 2, + const auto &expr = ann->getExpr(); + BUG_CHECK(expr.size() == 2, "%1%: expected @p4runtime_translation annotation with 2 " "arguments, but found %2% arguments", - type, ann->expr.size()); - const IR::Expression *first_arg = ann->expr[0]; - const IR::Expression *second_arg = ann->expr[1]; + type, expr.size()); + const IR::Expression *first_arg = expr[0]; + const IR::Expression *second_arg = expr[1]; auto uri = first_arg->to(); BUG_CHECK(uri != nullptr, diff --git a/frontends/common/applyOptionsPragmas.cpp b/frontends/common/applyOptionsPragmas.cpp index 07fe9de774c..fab308c2844 100644 --- a/frontends/common/applyOptionsPragmas.cpp +++ b/frontends/common/applyOptionsPragmas.cpp @@ -58,17 +58,18 @@ std::optional P4COptionPragmaParser::pa const IR::Annotation *annotation) { CommandLineOptions newOptions; - auto pragmaArgs = &annotation->expr; - // Parsing of option pragmas is done early in the compiler, before P4₁₆ // annotations are parsed, so we are responsible for doing our own parsing // here. - if (pragmaArgs->empty()) { - auto parseResult = - P4ParserDriver::parseExpressionList(annotation->srcInfo, annotation->body); - if (parseResult != nullptr) { + const IR::Vector *pragmaArgs = nullptr; + if (annotation->needsParsing()) { + // FIXME: Do we need to error? + if (auto *parseResult = P4ParserDriver::parseExpressionList(annotation->srcInfo, + annotation->getUnparsed())) { pragmaArgs = parseResult; } + } else { + pragmaArgs = &annotation->getExpr(); } if (pragmaArgs->size() != 2) { diff --git a/frontends/p4-14/fromv1.0/converters.cpp b/frontends/p4-14/fromv1.0/converters.cpp index 242a56a0772..3e0d69bab7a 100644 --- a/frontends/p4-14/fromv1.0/converters.cpp +++ b/frontends/p4-14/fromv1.0/converters.cpp @@ -410,12 +410,12 @@ const IR::Statement *StatementConverter::convert(const IR::Vectorsize == 0) { if (auto type = findContext()) { - if (auto max = type->getAnnotation(IR::Annotation::maxLengthAnnotation)) { - if (max->expr.size() != 1 || !max->expr[0]->is()) + if (const auto *max = type->getAnnotation(IR::Annotation::maxLengthAnnotation)) { + const auto &expr = max->getExpr(); + if (expr.size() != 1 || !expr[0]->is()) error(ErrorType::ERR_UNSUPPORTED, "%s: max_length must be a constant", max); else - vbtype->size = - 8 * max->expr[0]->to()->asInt() - type->width_bits(); + vbtype->size = 8 * expr[0]->to()->asInt() - type->width_bits(); } } } @@ -460,9 +460,10 @@ const IR::StructField *TypeConverter::postorder(IR::StructField *field) { // given a struct with length and max_length, the // varbit field size is max_length * 8 - struct_size if (field->type->is()) { - if (auto len = type->getAnnotation(IR::Annotation::lengthAnnotation)) { - if (len->expr.size() == 1) { - auto lenexpr = len->expr[0]; + if (const auto *len = type->getAnnotation(IR::Annotation::lengthAnnotation)) { + const auto &expr = len->getExpr(); + if (expr.size() == 1) { + auto lenexpr = expr[0]; ValidateLenExpr vle(type, field); vle.setCalledBy(this); lenexpr->apply(vle); diff --git a/frontends/p4-14/fromv1.0/converters.h b/frontends/p4-14/fromv1.0/converters.h index 6ab05e99b27..696f5df23e0 100644 --- a/frontends/p4-14/fromv1.0/converters.h +++ b/frontends/p4-14/fromv1.0/converters.h @@ -549,8 +549,9 @@ class FixExtracts final : public Transform { // extract length from annotation auto anno = f->getAnnotation(IR::Annotation::lengthAnnotation); BUG_CHECK(anno != nullptr, "No length annotation on varbit field", f); - BUG_CHECK(anno->expr.size() == 1, "Expected exactly 1 argument", anno->expr); - headerLength = anno->expr.at(0); + BUG_CHECK(anno->getExpr().size() == 1, "Expected exactly 1 argument", + anno->getExpr()); + headerLength = anno->getExpr(0); // We keep going through the loop just to check whether there is another // varbit field in the header. } else if (fixedHeaderType == nullptr) { diff --git a/frontends/p4-14/fromv1.0/programStructure.cpp b/frontends/p4-14/fromv1.0/programStructure.cpp index 3be20431833..31eda91beb0 100644 --- a/frontends/p4-14/fromv1.0/programStructure.cpp +++ b/frontends/p4-14/fromv1.0/programStructure.cpp @@ -559,12 +559,13 @@ const IR::ParserState *ProgramStructure::convertParser( const IR::Constant *sizeConstant; if (const auto *sizeAnnotation = value_set->getAnnotation(parserValueSetSizeAnnotation)) { - if (sizeAnnotation->expr.size() != 1) { + const auto &expr = sizeAnnotation->getExpr(); + if (expr.size() != 1) { ::P4::error(ErrorType::ERR_INVALID, "@size should be an integer for declaration %1%", value_set); return nullptr; } - sizeConstant = sizeAnnotation->expr[0]->to(); + sizeConstant = expr[0]->to(); if (sizeConstant == nullptr || !sizeConstant->fitsInt()) { ::P4::error(ErrorType::ERR_INVALID, "@size should be an integer for declaration %1%", value_set); @@ -2572,13 +2573,15 @@ void ProgramStructure::createChecksumUpdates() { } for (auto *annot : cf->annotations) { - auto newAnnot = new IR::Annotation(annot->name, annot->expr, false); - newAnnot->expr.push_back(new IR::StringLiteral(methodCallExpression->toString())); + auto newAnnot = new IR::Annotation(annot->name, annot->getExpr(), false); + newAnnot->getExpr().push_back( + new IR::StringLiteral(methodCallExpression->toString())); body->annotations.push_back(newAnnot); } for (auto *annot : flc->annotations) { - auto newAnnot = new IR::Annotation(annot->name, annot->expr, false); - newAnnot->expr.push_back(new IR::StringLiteral(methodCallExpression->toString())); + auto newAnnot = new IR::Annotation(annot->name, annot->getExpr(), false); + newAnnot->getExpr().push_back( + new IR::StringLiteral(methodCallExpression->toString())); body->annotations.push_back(newAnnot); } diff --git a/frontends/p4-14/header_type.cpp b/frontends/p4-14/header_type.cpp index c6a7a7b6595..18c202ae482 100644 --- a/frontends/p4-14/header_type.cpp +++ b/frontends/p4-14/header_type.cpp @@ -30,7 +30,7 @@ bool HeaderTypeMaxLengthCalculator::preorder(IR::Type_StructLike *hdr_type) { } if (!hdr_type->hasAnnotation(IR::Annotation::lengthAnnotation)) hdr_type->addAnnotation( - new IR::Annotation(IR::Annotation::lengthAnnotation, max_length->expr)); + new IR::Annotation(IR::Annotation::lengthAnnotation, max_length->getExpr())); return false; } diff --git a/frontends/p4/deprecated.cpp b/frontends/p4/deprecated.cpp index 9b20f0b4e69..cbfc5cf558c 100644 --- a/frontends/p4/deprecated.cpp +++ b/frontends/p4/deprecated.cpp @@ -24,7 +24,7 @@ void Deprecated::warnIfDeprecated(const IR::IAnnotated *annotated, const IR::Nod if (anno == nullptr) return; std::string message; - for (const auto *a : anno->expr) { + for (const auto *a : anno->getExpr()) { if (const auto *str = a->to()) message += str->value; } ::P4::warning(ErrorType::WARN_DEPRECATED, "%1%: Using deprecated feature %2%. %3%", errorNode, diff --git a/frontends/p4/hierarchicalNames.cpp b/frontends/p4/hierarchicalNames.cpp index fd8ad42ea82..fff648b407e 100644 --- a/frontends/p4/hierarchicalNames.cpp +++ b/frontends/p4/hierarchicalNames.cpp @@ -20,19 +20,18 @@ limitations under the License. namespace P4 { -cstring HierarchicalNames::getName(const IR::IDeclaration *decl) { return decl->getName(); } - -const IR::Node *HierarchicalNames::postorder(IR::Annotation *annotation) { - if (annotation->name != IR::Annotation::nameAnnotation) return annotation; +void HierarchicalNames::postorder(IR::Annotation *annotation) { + if (annotation->name != IR::Annotation::nameAnnotation) return; cstring name = annotation->getName(); - if (name.startsWith(".")) return annotation; - std::string newName = ""; - for (cstring s : stack) newName += s + "."; - newName += name; + if (name.startsWith(".")) return; + + if (stack.empty()) return; + + std::string newName = absl::StrCat(absl::StrJoin(stack, "."), ".", name); LOG2("Changing " << name << " to " << newName); - annotation = new IR::Annotation(annotation->name, newName); - return annotation; + + annotation->body = IR::Vector(new IR::StringLiteral(cstring(newName))); } } // namespace P4 diff --git a/frontends/p4/hierarchicalNames.h b/frontends/p4/hierarchicalNames.h index 62f4545b517..2abc419b9cf 100644 --- a/frontends/p4/hierarchicalNames.h +++ b/frontends/p4/hierarchicalNames.h @@ -55,46 +55,36 @@ This pass should be run after inlining. It assumes that all externally-visible objects already have @name annotations -- this is done by the UniqueNames front-end pass. */ -class HierarchicalNames : public Transform { +class HierarchicalNames : public Modifier { std::vector stack; - public: - cstring getName(const IR::IDeclaration *decl); + cstring getName(const IR::IDeclaration *decl) const { return decl->getName(); } + public: HierarchicalNames() { setName("HierarchicalNames"); visitDagOnce = false; } - const IR::Node *preorder(IR::P4Parser *parser) override { + bool preorder(IR::P4Parser *parser) override { stack.push_back(getName(parser)); - return parser; - } - const IR::Node *postorder(IR::P4Parser *parser) override { - stack.pop_back(); - return parser; + return true; } + void postorder(IR::P4Parser *) override { stack.pop_back(); } - const IR::Node *preorder(IR::P4Control *control) override { + bool preorder(IR::P4Control *control) override { stack.push_back(getName(control)); - return control; - } - const IR::Node *postorder(IR::P4Control *control) override { - stack.pop_back(); - return control; + return true; } + void postorder(IR::P4Control *) override { stack.pop_back(); } - const IR::Node *preorder(IR::P4Table *table) override { + bool preorder(IR::P4Table *table) override { visit(table->annotations); - prune(); - return table; + return false; } - const IR::Node *postorder(IR::Annotation *annotation) override; + void postorder(IR::Annotation *annotation) override; // Do not change name annotations on parameters - const IR::Node *preorder(IR::Parameter *parameter) override { - prune(); - return parameter; - } + bool preorder(IR::Parameter *) override { return false; } }; } // namespace P4 diff --git a/frontends/p4/methodInstance.cpp b/frontends/p4/methodInstance.cpp index 075b8236964..1835a12e559 100644 --- a/frontends/p4/methodInstance.cpp +++ b/frontends/p4/methodInstance.cpp @@ -207,7 +207,7 @@ std::vector ExternMethod::mayCall() const { for (auto meth : originalExternType->methods) { auto sync = meth->getAnnotation(IR::Annotation::synchronousAnnotation); if (!sync) continue; - for (auto m : sync->expr) { + for (auto m : sync->getExpr()) { auto mname = m->to(); if (!mname || method->name != mname->path->name) continue; if (auto *am = diff --git a/frontends/p4/parseAnnotations.cpp b/frontends/p4/parseAnnotations.cpp index 43566914b51..b6d8ab12459 100644 --- a/frontends/p4/parseAnnotations.cpp +++ b/frontends/p4/parseAnnotations.cpp @@ -57,19 +57,21 @@ ParseAnnotations::HandlerMap ParseAnnotations::standardHandlers() { bool ParseAnnotations::parseSkip(IR::Annotation *) { return false; } bool ParseAnnotations::parseEmpty(IR::Annotation *annotation) { - if (!annotation->body.empty()) { + if (!annotation->getUnparsed().empty()) { ::P4::error(ErrorType::ERR_OVERLIMIT, "%1% should not have any arguments", annotation); return false; } + annotation->body.emplace(); + return true; } bool ParseAnnotations::parseExpressionList(IR::Annotation *annotation) { const IR::Vector *parsed = - P4::P4ParserDriver::parseExpressionList(annotation->srcInfo, annotation->body); + P4::P4ParserDriver::parseExpressionList(annotation->srcInfo, annotation->getUnparsed()); if (parsed != nullptr) { - annotation->expr.append(*parsed); + annotation->body = *parsed; } return parsed != nullptr; @@ -77,9 +79,9 @@ bool ParseAnnotations::parseExpressionList(IR::Annotation *annotation) { bool ParseAnnotations::parseKvList(IR::Annotation *annotation) { const IR::IndexedVector *parsed = - P4::P4ParserDriver::parseKvList(annotation->srcInfo, annotation->body); + P4::P4ParserDriver::parseKvList(annotation->srcInfo, annotation->getUnparsed()); if (parsed != nullptr) { - annotation->kv.append(*parsed); + annotation->body = *parsed; } return parsed != nullptr; @@ -87,19 +89,19 @@ bool ParseAnnotations::parseKvList(IR::Annotation *annotation) { bool ParseAnnotations::parseConstantList(IR::Annotation *annotation) { const IR::Vector *parsed = - P4::P4ParserDriver::parseConstantList(annotation->srcInfo, annotation->body); + P4::P4ParserDriver::parseConstantList(annotation->srcInfo, annotation->getUnparsed()); if (parsed != nullptr) { - annotation->expr.append(*parsed); + annotation->body = *parsed; } return parsed != nullptr; } bool ParseAnnotations::parseConstantOrStringLiteralList(IR::Annotation *annotation) { - const IR::Vector *parsed = - P4::P4ParserDriver::parseConstantOrStringLiteralList(annotation->srcInfo, annotation->body); + const IR::Vector *parsed = P4::P4ParserDriver::parseConstantOrStringLiteralList( + annotation->srcInfo, annotation->getUnparsed()); if (parsed != nullptr) { - annotation->expr.append(*parsed); + annotation->body = *parsed; } return parsed != nullptr; @@ -107,44 +109,37 @@ bool ParseAnnotations::parseConstantOrStringLiteralList(IR::Annotation *annotati bool ParseAnnotations::parseStringLiteralList(IR::Annotation *annotation) { const IR::Vector *parsed = - P4::P4ParserDriver::parseStringLiteralList(annotation->srcInfo, annotation->body); + P4::P4ParserDriver::parseStringLiteralList(annotation->srcInfo, annotation->getUnparsed()); if (parsed != nullptr) { - annotation->expr.append(*parsed); + annotation->body = *parsed; } return parsed != nullptr; } bool ParseAnnotations::parseP4rtTranslationAnnotation(IR::Annotation *annotation) { - const IR::Vector *parsed = - P4::P4ParserDriver::parseP4rtTranslationAnnotation(annotation->srcInfo, annotation->body); + const IR::Vector *parsed = P4::P4ParserDriver::parseP4rtTranslationAnnotation( + annotation->srcInfo, annotation->getUnparsed()); if (parsed != nullptr) { - annotation->expr.append(*parsed); + annotation->body = *parsed; } return parsed != nullptr; } void ParseAnnotations::postorder(IR::Annotation *annotation) { - if (!annotation->needsParsing) { - return; - } - - if (!annotation->expr.empty() || !annotation->kv.empty()) { - BUG("Unparsed annotation with non-empty expr or kv"); - return; - } + if (!annotation->needsParsing()) return; cstring name = annotation->name.name; - if (!handlers.count(name)) { + auto handler = handlers.find(name); + if (handler == handlers.end()) { // Unknown annotation. Leave as is, but warn if desired. - if (warnUnknown && warned.count(name) == 0) { - warned.insert(name); + if (warnUnknown && warned.insert(name).second) { warn(ErrorType::WARN_UNKNOWN, "Unknown annotation: %1%", annotation->name); } return; } - annotation->needsParsing = !handlers[name](annotation); + handler->second(annotation); } } // namespace P4 diff --git a/frontends/p4/parseAnnotations.h b/frontends/p4/parseAnnotations.h index 947c49e0321..5f39813af92 100644 --- a/frontends/p4/parseAnnotations.h +++ b/frontends/p4/parseAnnotations.h @@ -35,16 +35,16 @@ namespace P4 { { aname, &P4::ParseAnnotations::parseEmpty } // Parses an annotation with a single-element body. -#define PARSE(aname, tname) \ - { \ - aname, [](IR::Annotation *annotation) { \ - const IR::tname *parsed = \ - P4::P4ParserDriver::parse##tname(annotation->srcInfo, annotation->body); \ - if (parsed != nullptr) { \ - annotation->expr.push_back(parsed); \ - } \ - return parsed != nullptr; \ - } \ +#define PARSE(aname, tname) \ + { \ + aname, [](IR::Annotation *annotation) { \ + const IR::tname *parsed = \ + P4::P4ParserDriver::parse##tname(annotation->srcInfo, annotation->getUnparsed()); \ + if (parsed != nullptr) { \ + annotation->body.emplace(parsed); \ + } \ + return parsed != nullptr; \ + } \ } // Parses an annotation that is either an integer constant or a string literal. @@ -52,22 +52,46 @@ namespace P4 { { \ aname, [](IR::Annotation *annotation) { \ const IR::Expression *parsed = P4::P4ParserDriver::parseConstantOrStringLiteral( \ - annotation->srcInfo, annotation->body); \ + annotation->srcInfo, annotation->getUnparsed()); \ if (parsed != nullptr) { \ - annotation->expr.push_back(parsed); \ + annotation->body.emplace(parsed); \ } \ return parsed != nullptr; \ } \ } +#define PARSE_CONSTANT(aname) \ + { \ + aname, [](IR::Annotation *annotation) { \ + const IR::Expression *parsed = \ + P4::P4ParserDriver::parseConstant(annotation->srcInfo, annotation->getUnparsed()); \ + if (parsed != nullptr) { \ + annotation->body.emplace(parsed); \ + } \ + return parsed != nullptr; \ + } \ + } + +#define PARSE_STRING_LITERAL(aname) \ + { \ + aname, [](IR::Annotation *annotation) { \ + const IR::Expression *parsed = P4::P4ParserDriver::parseStringLiteral( \ + annotation->srcInfo, annotation->getUnparsed()); \ + if (parsed != nullptr) { \ + annotation->body.emplace(parsed); \ + } \ + return parsed != nullptr; \ + } \ + } + // Parses an annotation whose body is a pair. #define PARSE_PAIR(aname, tname) \ { \ aname, [](IR::Annotation *annotation) { \ - const IR::Vector *parsed = \ - P4::P4ParserDriver::parse##tname##Pair(annotation->srcInfo, annotation->body); \ + const IR::Vector *parsed = P4::P4ParserDriver::parse##tname##Pair( \ + annotation->srcInfo, annotation->getUnparsed()); \ if (parsed != nullptr) { \ - annotation->expr.append(*parsed); \ + annotation->body.emplace(*parsed); \ } \ return parsed != nullptr; \ } \ @@ -77,10 +101,10 @@ namespace P4 { #define PARSE_TRIPLE(aname, tname) \ { \ aname, [](IR::Annotation *annotation) { \ - const IR::Vector *parsed = \ - P4::P4ParserDriver::parse##tname##Triple(annotation->srcInfo, annotation->body); \ + const IR::Vector *parsed = P4::P4ParserDriver::parse##tname##Triple( \ + annotation->srcInfo, annotation->getUnparsed()); \ if (parsed != nullptr) { \ - annotation->expr.append(*parsed); \ + annotation->body.emplace(*parsed); \ } \ return parsed != nullptr; \ } \ diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index 3f211a587fe..0a3c025403a 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -1276,45 +1276,55 @@ bool ToP4::preorder(const IR::Annotation *a) { builder.append(a->name); const char *open = a->structured ? "[" : "("; const char *close = a->structured ? "]" : ")"; - if (!a->expr.empty()) { - builder.append(open); - setVecSep(", "); - preorder(&a->expr); - doneVec(); - builder.append(close); - } - if (!a->kv.empty()) { - builder.append(open); - bool first = true; - for (auto kvp : a->kv) { - if (!first) builder.append(", "); - first = false; - builder.append(kvp->name); - builder.append("="); - visit(kvp->expression); - } - builder.append(close); - } - if (a->expr.empty() && a->kv.empty() && a->structured) { - builder.append("[]"); - } - if (!a->body.empty() && a->expr.empty() && a->kv.empty()) { - // Have an unparsed annotation. - // We could be prettier here with smarter logic, but let's do the easy - // thing by separating every token with a space. - builder.append(open); - bool first = true; - for (auto tok : a->body) { - if (!first) builder.append(" "); - first = false; - bool haveStringLiteral = tok->token_type == P4Parser::token_type::TOK_STRING_LITERAL; - if (haveStringLiteral) builder.append("\""); - builder.append(tok->text); - if (haveStringLiteral) builder.append("\""); - } - builder.append(close); - } + std::visit( + [&](const auto &body) { + using T = std::decay_t; + if constexpr (std::is_same_v>) { + // Do not print () for empty unstructured annotations + if (body.empty()) return; + // Have an unparsed annotation. + // We could be prettier here with smarter logic, but let's do the easy + // thing by separating every token with a space. + builder.append(open); + const char *sep = ""; + for (auto tok : body) { + builder.append(sep); + sep = " "; + + bool haveStringLiteral = + tok->token_type == P4Parser::token_type::TOK_STRING_LITERAL; + if (haveStringLiteral) builder.append("\""); + builder.append(tok->text); + if (haveStringLiteral) builder.append("\""); + } + builder.append(close); + } else if constexpr (std::is_same_v>) { + // Do not print () for empty unstructured annotations + if (body.empty() && !a->structured) return; + builder.append(open); + setVecSep(", "); + preorder(&body); + doneVec(); + builder.append(close); + } else if constexpr (std::is_same_v>) { + if (body.empty() && !a->structured) return; + builder.append(open); + bool first = true; + for (auto kvp : body) { + if (!first) builder.append(", "); + first = false; + builder.append(kvp->name); + builder.append("="); + visit(kvp->expression); + } + builder.append(close); + } else { + BUG("Unexpected variant field"); + } + }, + a->body); + return false; } diff --git a/frontends/p4/typeChecking/typeChecker.cpp b/frontends/p4/typeChecking/typeChecker.cpp index ebc3378f8f5..2147143aef4 100644 --- a/frontends/p4/typeChecking/typeChecker.cpp +++ b/frontends/p4/typeChecking/typeChecker.cpp @@ -709,12 +709,18 @@ const IR::Node *TypeInferenceBase::postorder(const IR::Annotation *annotation) { }; if (annotation->structured) { - // If it happens here it was created in the compiler, so it's a bug, not an error. - BUG_CHECK(annotation->expr.empty() || annotation->kv.empty(), - "%1%: structured annotations cannot contain expressions and kv-pairs", - annotation); - for (auto e : annotation->expr) checkAnnotation(e); - for (auto e : annotation->kv) checkAnnotation(e->expression); + std::visit( + [&](const auto &body) { + using T = std::decay_t; + if constexpr (std::is_same_v>) { + for (const auto *e : body) checkAnnotation(e); + } else if constexpr (std::is_same_v>) { + for (const auto *e : body) checkAnnotation(e->expression); + } else { + BUG("Unexpected variant field"); + } + }, + annotation->body); } return annotation; } diff --git a/frontends/p4/validateMatchAnnotations.h b/frontends/p4/validateMatchAnnotations.h index 0485ca70bb2..1caf59037dc 100644 --- a/frontends/p4/validateMatchAnnotations.h +++ b/frontends/p4/validateMatchAnnotations.h @@ -36,10 +36,12 @@ class ValidateMatchAnnotations final : public Inspector { void postorder(const IR::Annotation *annotation) override { if (annotation->name != IR::Annotation::matchAnnotation) return; if (!findContext()) return; - if (annotation->expr.size() != 1) + // FIXME: Check annotation kind + const auto &expr = annotation->getExpr(); + if (expr.size() != 1) ::P4::error(ErrorType::ERR_INVALID, "%1%: annotation must have exactly 1 argument", annotation); - auto e0 = annotation->expr.at(0); + auto e0 = expr.at(0); auto type = typeMap->getType(e0, true); if (type == nullptr) return; if (!type->is()) diff --git a/frontends/p4/validateStringAnnotations.h b/frontends/p4/validateStringAnnotations.h index def001e4a0d..843d5487528 100644 --- a/frontends/p4/validateStringAnnotations.h +++ b/frontends/p4/validateStringAnnotations.h @@ -36,11 +36,13 @@ class ValidateStringAnnotations final : public Inspector { name != IR::Annotation::noWarnAnnotation) { return; } - if (annotation->expr.size() != 1) { + // FIXME: Validate annotation type + const auto &expr = annotation->getExpr(); + if (expr.size() != 1) { error(ErrorType::ERR_INVALID, "%1%: annotation must have exactly 1 argument", annotation); } - const auto *e0 = annotation->expr.at(0); + const auto *e0 = expr.at(0); if (!e0->is()) { error(ErrorType::ERR_TYPE_ERROR, "%1%: @%2% annotation's value must be a string", e0, annotation->name.originalName); diff --git a/ir/base.cpp b/ir/base.cpp index 26c1aec4b5a..21cc7c2e287 100644 --- a/ir/base.cpp +++ b/ir/base.cpp @@ -27,7 +27,7 @@ namespace P4::IR { cstring Annotation::getName() const { BUG_CHECK(name == IR::Annotation::nameAnnotation, "%1%: Only works on name annotations", this); - if (needsParsing) + if (needsParsing()) // This can happen if this method is invoked before we have parsed // annotation bodies. return name; @@ -35,6 +35,7 @@ cstring Annotation::getName() const { } cstring Annotation::getSingleString() const { + const auto &expr = getExpr(); if (expr.size() != 1) { ::P4::error(ErrorType::ERR_INVALID, "%1%: should contain a string", this); return cstring::empty; diff --git a/ir/base.def b/ir/base.def index fd31ef28035..527e8cb7ce6 100644 --- a/ir/base.def +++ b/ir/base.def @@ -224,42 +224,51 @@ class AnnotationToken { class Annotation { ID name; +#emit + using UnparsedAnnotation = IR::Vector; + using ExpressionAnnotation = IR::Vector; + using KVAnnotation = IR::IndexedVector; +#end Annotation { if (!srcInfo) srcInfo = name.srcInfo; } /// For annotations parsed from P4-16 source. - Annotation(Util::SourceInfo si, ID n, const Vector &a) - : Node(si), name(n), body(a), needsParsing(true), structured(false) {} + inline Annotation(Util::SourceInfo si, ID n, const Vector &a) + : Node(si), name(n), body(a), structured(false) {} // Used by JSON loader - Annotation(Util::SourceInfo si, ID n, const Vector &a, bool structured) - : Node(si), name(n), body(a), needsParsing(true), structured(structured) {} + inline Annotation(Util::SourceInfo si, ID n, const Vector &a, bool structured) + : Node(si), name(n), body(a), structured(structured) {} // The remaining constructors are for compiler-generated annotations. - Annotation(Util::SourceInfo si, ID n, - std::initializer_list a, bool structured = false) - : Node(si), name(n), expr(a), needsParsing(false), structured(structured) {} - Annotation(Util::SourceInfo si, ID n, - const Expression *a, bool structured = false) - : Node(si), name(n), expr(a), needsParsing(false), structured(structured) {} - Annotation(Util::SourceInfo si, ID n, const IR::Vector &a, bool structured = false) - : Node(si), name(n), expr(a), needsParsing(false), structured(structured) {} - Annotation(Util::SourceInfo si, ID n, const IndexedVector &kv, - bool structured = false) - : Node(si), name(n), kv(kv), needsParsing(false), structured(structured) {} - Annotation(ID n, const Expression *a, bool structured = false) - : name(n), expr(a), needsParsing(false), structured(structured) {} - Annotation(ID n, std::initializer_list a, bool structured = false) - : name(n), expr(a), needsParsing(false), structured(structured) {} - Annotation(ID n, const IR::Vector &a, bool structured = false) - : name(n), expr(a), needsParsing(false), structured(structured) {} + inline Annotation(Util::SourceInfo si, ID n, + std::initializer_list a, bool structured = false) + : Node(si), name(n), body(a), structured(structured) {} + inline Annotation(Util::SourceInfo si, ID n, + const Expression *a, bool structured = false) + : Node(si), name(n), body(), structured(structured) { + body.emplace(a); + } + inline Annotation(Util::SourceInfo si, ID n, const IR::Vector &a, bool structured = false) + : Node(si), name(n), body(a), structured(structured) {} + inline Annotation(Util::SourceInfo si, ID n, const IndexedVector &kv, + bool structured = false) + : Node(si), name(n), body(kv), structured(structured) {} + inline Annotation(ID n, const Expression *a, bool structured = false) + : name(n), body(), structured(structured) { + body.emplace(a); + } + inline Annotation(ID n, std::initializer_list a, bool structured = false) + : name(n), body(a), structured(structured) {} + inline Annotation(ID n, const IR::Vector &a, bool structured = false) + : name(n), body(a), structured(structured) {} Annotation(ID n, intmax_t v, bool structured = false) - : name(n), needsParsing(false), structured(structured) { - expr.push_back(new Constant(v)); + : name(n), structured(structured) { + body.emplace(new Constant(v)); } // Cannot use delegating ctors are ir-generator does not support initializer lists // : Annotation(n, { new Constant(v) }, structured) { } Annotation(ID n, cstring v, bool structured = false) - : name(n), needsParsing(false), structured(structured) { - expr.push_back(new StringLiteral(v)); + : name(n), structured(structured) { + body.emplace(new StringLiteral(v)); } // : Annotation(n, { new StringLiteral(v) }, structured) { } @@ -281,58 +290,63 @@ class Annotation { static const cstring fieldListAnnotation; /// Used for recirculate, etc. static const cstring debugLoggingAnnotation; /// Used by compiler implementer to limit debug log to the annotated IR context. static const cstring disableOptimizationAnnotation; /// annotation to disable certain optimization + toString{ return absl::StrCat("@", name); } validate{ BUG_CHECK(!name.name.isNullOrEmpty(), "empty annotation name"); - BUG_CHECK(!(needsParsing && !expr.empty()), - "unparsed annotation body with non-empty expr"); - BUG_CHECK(!(needsParsing && !kv.empty()), - "unparsed annotation body with non-empty kv"); } /// Extracts name value from a name annotation cstring getName() const; /// Extracts a single string argument; error if the argument is not a string cstring getSingleString() const; + /// Whether the annotation body needs to be parsed. + inline bool needsParsing() const { + return std::holds_alternative(body); + } enum class Kind { + Unparsed, Unstructured, - StructuredEmpty, StructuredKVList, StructuredExpressionList } - Kind annotationKind() const { + inline Kind annotationKind() const { + if (needsParsing()) + return Kind::Unparsed; if (!structured) return Kind::Unstructured; - if (expr.size()) + if (std::holds_alternative(body)) return Kind::StructuredExpressionList; - if (kv.size()) + if (std::holds_alternative(body)) return Kind::StructuredKVList; - return Kind::StructuredEmpty; - } - /// An unparsed annotation body - inline Vector body; - - /// Annotations that are simple expressions - inline Vector expr; - - /// Annotations described as key-value pairs - inline IndexedVector kv; + BUG("Invalid annotation kind"); + } -#emit - /// Whether the annotation body needs to be parsed. - /// Invariant: if this is true, then expr and kv must both be empty. If the - /// annotation is compiler-generated (e.g., derived from a P4₁₄ pragma), - /// then needsParsing will be false and the body will be empty, but expr or - /// kv may be populated. - bool needsParsing : 1; + // index = 0: An unparsed annotation body + // index = 1: Annotations that are simple expressions + // index = 2: Annotations described as key-value pairs + variant, + Vector, + IndexedVector> body; + + inline auto &getUnparsed() { return std::get(body); } + inline const auto &getUnparsed() const { return std::get(body); } + inline auto &getExpr() { return std::get(body); } + inline const auto &getExpr() const { return std::get(body); } + inline Expression getExpr(size_t idx) const { + const auto &expr = getExpr(); + BUG_CHECK(idx < expr.size(), "invalid annotation expression index"); + return expr[idx]; + } + inline auto &getKV() { return std::get(body); } + inline const auto &getKV() const { return std::get(body); } /// If this is true this is a structured annotation, and there are some /// constraints on its contents. - bool structured : 1; -#end + bool structured; } /// Implemented by all objects that can have annotations diff --git a/ir/dbprint.cpp b/ir/dbprint.cpp index 6271e52d2fe..e804c86ef00 100644 --- a/ir/dbprint.cpp +++ b/ir/dbprint.cpp @@ -68,12 +68,36 @@ void IR::InstantiatedBlock::dbprint(std::ostream &out) const { void IR::Annotation::dbprint(std::ostream &out) const { out << '@' << name; - const char *sep = "("; - for (auto e : expr) { - out << sep << e; - sep = ", "; - } - if (*sep != '(') out << ')'; + if (needsParsing()) out << ""; + const char *open = structured ? "[" : "("; + const char *close = structured ? "]" : ")"; + + const char *sep = open; + std::visit( + [&](const auto &body) { + using T = std::decay_t; + if constexpr (std::is_same_v>) { + for (auto e : body) { + out << sep << e; + sep = " "; + } + } else if constexpr (std::is_same_v>) { + for (auto e : body) { + out << sep << e; + sep = ", "; + } + } else if constexpr (std::is_same_v>) { + for (auto kvp : body) { + out << sep << kvp->name << " = " << kvp->expression; + sep = ", "; + } + } else { + BUG("Unexpected variant field"); + } + }, + body); + + if (*sep != *open) out << close; } void IR::Block::dbprint_recursive(std::ostream &out) const { @@ -107,6 +131,11 @@ std::ostream &operator<<(std::ostream &out, const IR::Vector &v) return out; } +std::ostream &operator<<(std::ostream &out, const IR::Vector &v) { + for (const auto &a : v) out << a << ' '; + return out; +} + void dbprint(const IR::Node *n) { std::cout << n << std::endl; } void dbprint(const IR::Node &n) { std::cout << n << std::endl; } void dbprint(const std::set s) { diff --git a/ir/ir-inline.h b/ir/ir-inline.h index 1e261cf644e..471d4ce8128 100644 --- a/ir/ir-inline.h +++ b/ir/ir-inline.h @@ -153,6 +153,7 @@ void IR::Vector::toJSON(JSONGenerator &json) const { } std::ostream &operator<<(std::ostream &out, const IR::Vector &v); +std::ostream &operator<<(std::ostream &out, const IR::Vector &v); template void IR::IndexedVector::visit_children(Visitor &v) { diff --git a/ir/json_generator.h b/ir/json_generator.h index 0e565fc4801..68d73d158d5 100644 --- a/ir/json_generator.h +++ b/ir/json_generator.h @@ -20,6 +20,7 @@ limitations under the License. #include #include #include +#include #include "ir/node.h" #include "lib/bitvec.h" @@ -54,6 +55,20 @@ class JSONGenerator { static const bool value = sizeof(test(0)) == sizeof(char); }; + struct variant_generator { + std::ostream &out; + JSONGenerator &generator; + + variant_generator(std::ostream &out, JSONGenerator &generator) + : out(out), generator(generator) {} + + template + void operator()(const T &value) const { + out << R"("value" : )"; + generator.generate(value); + } + }; + public: indent_t indent; @@ -183,14 +198,23 @@ class JSONGenerator { out << "]"; } + template + void generate(const std::variant &v) { + out << "{" << std::endl << ++indent; + out << R"("variant_index" : )" << v.index() << "," << std::endl << indent; + variant_generator generator(out, *this); + std::visit(generator, v); + out << std::endl << --indent << "}"; + } + void generate(bool v) { out << (v ? "true" : "false"); } template - typename std::enable_if::value>::type generate(T v) { + std::enable_if_t> generate(T v) { out << std::to_string(v); } void generate(double v) { out << std::to_string(v); } template - typename std::enable_if::value>::type generate(const T &v) { + std::enable_if_t> generate(const T &v) { out << v; } @@ -202,8 +226,7 @@ class JSONGenerator { } } template - typename std::enable_if::value || std::is_enum::value>::type - generate(T v) { + std::enable_if_t || std::is_enum_v> generate(T v) { out << "\"" << v << "\""; } @@ -217,8 +240,7 @@ class JSONGenerator { } template - typename std::enable_if::value && !std::is_base_of::value>::type - generate(const T &v) { + std::enable_if_t::value && !std::is_base_of_v> generate(const T &v) { ++indent; out << "{" << std::endl; v.toJSON(*this); @@ -241,9 +263,8 @@ class JSONGenerator { } template - typename std::enable_if::value && - has_toJSON::type>::value>::type - generate(T v) { + std::enable_if_t && has_toJSON>::value> generate( + T v) { if (v) generate(*v); else diff --git a/ir/json_loader.h b/ir/json_loader.h index e0a966c73be..b8d027b4b55 100644 --- a/ir/json_loader.h +++ b/ir/json_loader.h @@ -22,6 +22,7 @@ limitations under the License. #include #include #include +#include #include "ir.h" #include "json_parser.h" @@ -223,10 +224,36 @@ class JSONLoader { load(::P4::get(obj, "value"), value), v = std::move(value); } + template + std::enable_if_t> unpack_variant(const JsonObject *, + int /*target*/, + Variant & /*variant*/) { + BUG("Error traversing variant during load"); + } + + template + std::enable_if_t<(N < std::variant_size_v)> unpack_variant(const JsonObject *obj, + int target, + Variant &variant) { + if (N == target) { + variant.template emplace(); + load(P4::get(obj, "value"), std::get(variant)); + } else + unpack_variant(obj, target, variant); + } + + template + void unpack_json(std::variant &v) { + const JsonObject *obj = json->checkedTo(); + int index = -1; + load(P4::get(obj, "variant_index"), index); + unpack_variant<0>(obj, index, v); + } + void unpack_json(bool &v) { v = json->as(); } template - typename std::enable_if::value>::type unpack_json(T &v) { + std::enable_if_t> unpack_json(T &v) { v = json->as(); } void unpack_json(big_int &v) { v = json->as().val; } @@ -263,7 +290,7 @@ class JSONLoader { } template - typename std::enable_if::value>::type unpack_json(T &v) { + std::enable_if_t> unpack_json(T &v) { if (auto *s = json->to()) *s >> v; } @@ -286,35 +313,32 @@ class JSONLoader { } template - typename std::enable_if< - has_fromJSON::value && !std::is_base_of::value && - std::is_pointer()))>::value>::type + std::enable_if_t::value && !std::is_base_of_v && + std::is_pointer_v()))>> unpack_json(T *&v) { v = T::fromJSON(*this); } template - typename std::enable_if< - has_fromJSON::value && !std::is_base_of::value && - std::is_pointer()))>::value>::type + std::enable_if_t::value && !std::is_base_of_v && + std::is_pointer_v()))>> unpack_json(T &v) { v = *(T::fromJSON(*this)); } template - typename std::enable_if< - has_fromJSON::value && !std::is_base_of::value && - !std::is_pointer()))>::value>::type + std::enable_if_t::value && !std::is_base_of::value && + !std::is_pointer_v()))>> unpack_json(T &v) { v = T::fromJSON(*this); } template - typename std::enable_if::value>::type unpack_json(T &v) { + std::enable_if_t> unpack_json(T &v) { v = get_node()->as(); } template - typename std::enable_if::value>::type unpack_json(const T *&v) { + std::enable_if_t> unpack_json(const T *&v) { v = get_node()->checkedTo(); } diff --git a/midend/local_copyprop.cpp b/midend/local_copyprop.cpp index 2a985ea58e5..97d69c2d33b 100644 --- a/midend/local_copyprop.cpp +++ b/midend/local_copyprop.cpp @@ -499,7 +499,7 @@ bool isAsync(const IR::Vector methods, cstring callee, cstring calle if (m->name != callee) continue; auto sync = m->getAnnotation(IR::Annotation::synchronousAnnotation); if (!sync) return true; - for (auto m : sync->expr) { + for (auto m : sync->getExpr()) { auto mname = m->to(); if (mname && mname->path->name == caller) return false; } diff --git a/test/test_fromJSON.p4 b/test/test_fromJSON.p4 index 13f6e050e5d..84d4977c3b0 100644 --- a/test/test_fromJSON.p4 +++ b/test/test_fromJSON.p4 @@ -62,6 +62,7 @@ struct metadata { } struct headers { + @name("foo") ethernet_t ethernet; ipv4_t ipv4; } diff --git a/tools/ir-generator/ir-generator-lex.l b/tools/ir-generator/ir-generator-lex.l index 76435760182..928fbe5e1a5 100644 --- a/tools/ir-generator/ir-generator-lex.l +++ b/tools/ir-generator/ir-generator-lex.l @@ -81,6 +81,7 @@ static std::string comment_block; "protected" { return PROTECTED; } "public" { return PUBLIC; } "static" { return STATIC; } +"variant" { return VARIANT; } "virtual" { return VIRTUAL; } "NullOK" { return NULLOK; } "#apply" { return APPLY; } diff --git a/tools/ir-generator/ir-generator.ypp b/tools/ir-generator/ir-generator.ypp index 294ab363ad8..e31e4b39d42 100644 --- a/tools/ir-generator/ir-generator.ypp +++ b/tools/ir-generator/ir-generator.ypp @@ -80,7 +80,7 @@ static IrNamespace *current_namespace = LookupScope().resolve(0); } %token ABSTRACT APPLY CLASS CONST DBLCOL DEFAULT DELETE ENUM INLINE INTERFACE NAMESPACE - NEW NULLOK OPERATOR OPTIONAL PRIVATE PROTECTED PUBLIC STATIC VIRTUAL + NEW NULLOK OPERATOR OPTIONAL PRIVATE PROTECTED PUBLIC STATIC VARIANT VIRTUAL %token BLOCK COMMENTBLOCK IDENTIFIER INCLUDE INTEGER NO STRING ZERO %token EMITBLOCK @@ -331,6 +331,10 @@ irField { $$ = new IrField(@4, $3, $4, $5, $1 | IrElement::Const); if ($1 & IrElement::Virtual) yyerror("virtual invalid on field %s", $4); } + | modifiers VARIANT '<' type_args '>' fieldName optInitializer ';' + { $$ = new IrVariantField(@6, $4, $6, $7, $1); + if ($1 & IrElement::Virtual) + yyerror("virtual invalid on field %s", $6); } ; modifier diff --git a/tools/ir-generator/irclass.cpp b/tools/ir-generator/irclass.cpp index 96ee569a435..b537dc1dde3 100644 --- a/tools/ir-generator/irclass.cpp +++ b/tools/ir-generator/irclass.cpp @@ -598,7 +598,9 @@ void IrEnumType::generate_hdr(std::ostream &out) const { //////////////////////////////////////////////////////////////////////////////////// -void IrField::resolve() { +void IrField::resolve() { resolveType(type); } + +void IrField::resolveType(const Type *type) { auto tmpl = dynamic_cast(type); const IrClass *cls = type->resolve(clss ? clss->containedIn : nullptr); if (cls) { @@ -662,6 +664,42 @@ void IrField::generate_impl(std::ostream &) const { //////////////////////////////////////////////////////////////////////////////////// +void IrVariantField::resolve() { + for (const Type *type : *types) resolveType(type); +} + +void IrVariantField::generate(std::ostream &out, bool asField) const { + if (asField) { + out << IrClass::indent << "using " << name << "_variant = std::variant<"; + bool first = true; + for (const Type *type : *types) { + if (!first) out << ", "; + + // FIXME: Support variant of IR node pointers + // const IrClass *cls = type->resolve(clss ? clss->containedIn : nullptr); + // if (cls != nullptr) out << "const "; + out << type->toString(); + // if (cls != nullptr) out << "*"; + first = false; + } + out << ">;" << std::endl << IrClass::indent; + + if (isStatic) out << "static "; + if (isConst) out << "const "; + } + + out << name << "_variant " << name; + + if (asField) { + if (!isStatic && !initializer.isNullOrEmpty()) out << " = " << initializer; + + out << ";"; + out << std::endl; + } +} + +//////////////////////////////////////////////////////////////////////////////////// + void ConstFieldInitializer::generate_hdr(std::ostream &out) const { out << IrClass::indent; if (name == "precedence") diff --git a/tools/ir-generator/irclass.h b/tools/ir-generator/irclass.h index d7a316739aa..0588b07a4cf 100644 --- a/tools/ir-generator/irclass.h +++ b/tools/ir-generator/irclass.h @@ -89,7 +89,14 @@ class IrElement : public Util::IHasSourceInfo { virtual void generate_impl(std::ostream &out) const = 0; enum access_t { Public, Protected, Private } access = Public; - enum modifier_t { NullOK = 1, Optional = 2, Inline = 4, Virtual = 8, Static = 16, Const = 32 }; + enum modifier_t { + NullOK = 1 << 0, + Optional = 1 << 1, + Inline = 1 << 2, + Virtual = 1 << 3, + Static = 1 << 4, + Const = 1 << 5, + }; static inline const char *modifier(int m) { if (m & IrElement::NullOK) return "NullOK"; if (m & IrElement::Optional) return "optional"; @@ -169,10 +176,24 @@ class IrField : public IrElement { IrField(const Type *type, cstring name, int flags) : IrField(Util::SourceInfo(), type, name, cstring(), flags) {} void resolve() override; - void generate(std::ostream &out, bool asField) const; + virtual void generate(std::ostream &out, bool asField) const; void generate_hdr(std::ostream &out) const override { generate(out, true); } void generate_impl(std::ostream &) const override; cstring toString() const override { return name; } + + protected: + void resolveType(const Type *type); +}; + +class IrVariantField : public IrField { + public: + std::vector *types; + IrVariantField(Util::SourceInfo info, std::vector *types, cstring name, + cstring init, int flags = 0) + : IrField(info, nullptr, name, init, flags), types(types) {} + + void resolve() override; + void generate(std::ostream &out, bool asField) const override; }; class ConstFieldInitializer : public IrElement { diff --git a/tools/ir-generator/methods.cpp b/tools/ir-generator/methods.cpp index 0c5e84efbc8..5ba1bf436b0 100644 --- a/tools/ir-generator/methods.cpp +++ b/tools/ir-generator/methods.cpp @@ -54,7 +54,8 @@ const ordered_map IrMethod::Generate = { first = false; } for (auto f : *cl->getFields()) { - if (*f->type == NamedType::SourceInfo()) continue; // FIXME -- deal with SourcInfo + if (f->type && *f->type == NamedType::SourceInfo()) + continue; // FIXME -- deal with SourcInfo if (!first) buf << std::endl << cl->indent << cl->indent << "&& "; first = false; if (auto *arr = dynamic_cast(f->type)) { @@ -99,17 +100,49 @@ const ordered_map IrMethod::Generate = { } else { bool first = true; for (auto f : *cl->getFields()) { - if (*f->type == NamedType::SourceInfo()) + if (f->type && *f->type == NamedType::SourceInfo()) continue; // FIXME -- deal with SourcInfo if (first) { buf << cl->indent << cl->indent << "auto &a = static_castname << " &>(a_);\n"; + // See, if we are having any variant fields and therefore need to generate + // equiv visitors + for (const auto *f : *cl->getFields()) { + if (f->type) continue; + const auto *varF = f->to(); + buf << cl->indent << cl->indent << "auto " << f->name + << "_equivVisitor = [&](auto &&variant) -> bool {\n" + << cl->indent << cl->indent << cl->indent + << "using T = std::decay_t;\n"; + bool first = true; + for (const auto *type : *varF->types) { + buf << cl->indent << cl->indent << cl->indent + << (first ? "if constexpr (std::is_same_vtoString() << ">) {"; + if (type->resolve(cl->containedIn)) { + buf << "return variant.equiv(std::get<" << type->toString() + << ">(a." << f->name << ")); "; + } else { + buf << "return variant.equiv(std::get<" << type->toString() + << ">(a." << f->name << ")); "; + } + buf << "}\n"; + first = false; + } + buf << cl->indent << cl->indent << cl->indent + << R"(else { BUG("Unexpected variant field"); } };)" << std::endl; + } + buf << cl->indent << cl->indent << "return "; first = false; } else { buf << std::endl << cl->indent << cl->indent << "&& "; } - if (f->type->resolve(cl->containedIn) == nullptr) { + if (!f->type) { // variant field + buf << f->name << ".index() == a." << f->name << ".index() && " + << "std::visit(" << f->name << "_equivVisitor, " << f->name << ")"; + } else if (f->type->resolve(cl->containedIn) == nullptr) { // This is not an IR pointer buf << f->name << " == a." << f->name; } else if (f->isInline) { @@ -151,15 +184,38 @@ const ordered_map IrMethod::Generate = { buf << cl->indent << parent->qualified_name(cl->containedIn) << "::visit_children(v);" << std::endl; for (auto f : *cl->getFields()) { - if (f->type->resolve(cl->containedIn) == nullptr) - // This is not an IR pointer - continue; - if (f->isInline) - buf << cl->indent << f->name << ".visit_children(v);" << std::endl; - else - buf << cl->indent << "v.visit(" << f->name << ", \"" << f->name << "\");" + if (f->type) { + if (f->type->resolve(cl->containedIn) == nullptr) + // This is not an IR pointer + continue; + if (f->isInline) + buf << cl->indent << f->name << ".visit_children(v);" << std::endl; + else + buf << cl->indent << "v.visit(" << f->name << ", \"" << f->name << "\");" + << std::endl; + needed = true; + } else { + const auto *varF = f->to(); + buf << cl->indent << "std::visit([&](auto &&variant) {\n" + << cl->indent << cl->indent << "using T = std::decay_t;\n"; + bool first = true; + for (const auto *type : *varF->types) { + needed = true; + buf << cl->indent << cl->indent + << (first ? "if constexpr (std::is_same_vtoString() << ">) {"; + if (type->resolve(cl->containedIn)) { + buf << " v.visit(variant, \"" << f->name << "::" << type->toString() + << "\"); "; + } + buf << "}\n"; + first = false; + } + buf << cl->indent << cl->indent + << R"(else { BUG("Unexpected variant field"); } }, )" << f->name << ");" << std::endl; - needed = true; + } } buf << "}"; return needed ? buf : cstring(); @@ -173,16 +229,39 @@ const ordered_map IrMethod::Generate = { std::stringstream buf; buf << "{" << LineDirective(true); for (auto f : *cl->getFields()) { - if (f->type->resolve(cl->containedIn) == nullptr) - // This is not an IR pointer - continue; - if (f->isInline) - buf << std::endl << cl->indent << cl->indent << f->name << ".validate();"; - else if (!f->nullOK) - buf << std::endl << cl->indent << cl->indent << "CHECK_NULL(" << f->name << ");"; - else - continue; - needed = true; + if (f->type) { + if (f->type->resolve(cl->containedIn) == nullptr) + // This is not an IR pointer + continue; + if (f->isInline) + buf << std::endl << cl->indent << cl->indent << f->name << ".validate();"; + else if (!f->nullOK) + buf << std::endl + << cl->indent << cl->indent << "CHECK_NULL(" << f->name << ");"; + else + continue; + needed = true; + } else { + const auto *varF = f->to(); + buf << cl->indent << "std::visit([&](auto &&variant) {\n" + << cl->indent << cl->indent << "using T = std::decay_t;\n"; + bool first = true; + for (const auto *type : *varF->types) { + needed = true; + buf << cl->indent << cl->indent + << (first ? "if constexpr (std::is_same_vtoString() << ">) {"; + if (type->resolve(cl->containedIn)) { + buf << " variant.validate(); "; + } + buf << "}\n"; + first = false; + } + buf << cl->indent << cl->indent + << R"(else { BUG("Unexpected variant field"); } }, )" << f->name << ");" + << std::endl; + } } if (body) { buf << LineDirective(srcInfo, true) << body; @@ -216,15 +295,40 @@ const ordered_map IrMethod::Generate = { buf << cl->indent << parent->qualified_name(cl->containedIn) << "::dump_fields(out);" << std::endl; bool needed = false; - for (auto f : *cl->getFields()) { - if (*f->type == NamedType::SourceInfo()) continue; // FIXME -- deal with SourcInfo - if (f->type->resolve(cl->containedIn) == nullptr && - !dynamic_cast(f->type)) { + auto printField = [&](const Type *type, cstring name, cstring val) { + if (type->resolve(cl->containedIn) == nullptr && + !dynamic_cast(type)) { // not an IR pointer - buf << cl->indent << cl->indent << "out << \" " << f->name << "=\" << " << f->name - << ";" << std::endl; + buf << cl->indent << cl->indent << "out << \" " << name << "=\" << " << val << ";" + << std::endl; needed = true; } + }; + + for (auto f : *cl->getFields()) { + if (f->type && *f->type == NamedType::SourceInfo()) + continue; // FIXME -- deal with SourcInfo + if (f->type) { + printField(f->type, f->name, f->name); + } else { + const auto *varF = f->to(); + buf << cl->indent << "std::visit([&](auto &&variant) {\n" + << cl->indent << cl->indent << "using T = std::decay_t;\n"; + bool first = true; + for (const auto *type : *varF->types) { + needed = true; + buf << cl->indent << cl->indent + << (first ? "if constexpr (std::is_same_vtoString() << ">) {\n"; + printField(type, type->toString(), "variant"_cs); + buf << "} "; + first = false; + } + buf << cl->indent << cl->indent + << R"(else { BUG("Unexpected variant field"); } }, )" << f->name << ");" + << std::endl; + } } buf << "}"; return needed ? buf : cstring(); @@ -240,7 +344,8 @@ const ordered_map IrMethod::Generate = { buf << cl->indent << parent->qualified_name(cl->containedIn) << "::toJSON(json);" << std::endl; for (auto f : *cl->getFields()) { - if (*f->type == NamedType::SourceInfo()) continue; // FIXME -- deal with SourcInfo + if (f->type && *f->type == NamedType::SourceInfo()) + continue; // FIXME -- deal with SourcInfo if (!f->isInline && f->nullOK) buf << cl->indent << "if (" << f->name << " != nullptr) "; buf << cl->indent << "json << \",\" << std::endl << json.indent << \"\\\"" << f->name @@ -259,7 +364,8 @@ const ordered_map IrMethod::Generate = { buf << ": " << parent->qualified_name(cl->containedIn) << "(json)"; buf << " {" << std::endl; for (auto f : *cl->getFields()) { - if (*f->type == NamedType::SourceInfo()) continue; // FIXME -- deal with SourcInfo + if (f->type && *f->type == NamedType::SourceInfo()) + continue; // FIXME -- deal with SourcInfo buf << cl->indent << "json.load(\"" << f->name << "\", " << f->name << ");" << std::endl; }