From fee0cf65f13cf65427b9939951b3bd282d7c92ea Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Tue, 30 Jan 2024 11:27:00 -0800 Subject: [PATCH 1/4] Eliminate the majority of `dynamic_cast` usage in the codebase in favor of ICastable interface --- backends/bmv2/simple_switch/simpleSwitch.h | 13 ++- backends/ebpf/ebpfControl.cpp | 4 +- backends/ebpf/ebpfDeparser.cpp | 4 +- backends/ebpf/ebpfParser.cpp | 4 +- backends/ebpf/ebpfTable.cpp | 2 +- backends/ebpf/ebpfType.cpp | 16 ++-- backends/ebpf/ebpfType.h | 40 ++++------ backends/ebpf/psa/ebpfPsaDeparser.cpp | 2 +- backends/ebpf/psa/externs/ebpfPsaCounter.cpp | 2 +- backends/ebpf/psa/externs/ebpfPsaMeter.cpp | 4 +- backends/ebpf/psa/externs/ebpfPsaRegister.cpp | 2 +- .../common/core/abstract_execution_state.cpp | 2 +- backends/tc/ebpfCodeGen.cpp | 54 ++++++------- backends/ubpf/ubpfDeparser.cpp | 4 +- backends/ubpf/ubpfParser.cpp | 6 +- backends/ubpf/ubpfType.cpp | 2 +- backends/ubpf/ubpfType.h | 14 +--- frontends/p4/def_use.cpp | 4 +- frontends/p4/def_use.h | 12 +-- frontends/p4/fromv1.0/programStructure.cpp | 2 +- frontends/p4/methodInstance.h | 2 +- frontends/p4/reassociation.cpp | 2 +- frontends/p4/symbol_table.cpp | 9 ++- frontends/p4/toP4/toP4.cpp | 2 +- frontends/p4/typeChecking/typeUnification.cpp | 5 +- ir/base.def | 4 +- ir/expression.def | 9 +-- ir/ir-inline.h | 16 ++-- ir/json_loader.h | 48 +++++------ ir/json_parser.cpp | 79 ++++++++++--------- ir/namemap.h | 2 +- ir/node.h | 11 --- ir/nodemap.h | 2 +- ir/solver.h | 8 -- ir/visitor.cpp | 4 +- ir/visitor.h | 14 ++-- lib/castable.h | 6 ++ lib/json.h | 6 +- midend/interpreter.h | 21 +---- 39 files changed, 193 insertions(+), 250 deletions(-) diff --git a/backends/bmv2/simple_switch/simpleSwitch.h b/backends/bmv2/simple_switch/simpleSwitch.h index 71bc2c71a56..a17c9b5d46d 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.h +++ b/backends/bmv2/simple_switch/simpleSwitch.h @@ -84,24 +84,23 @@ class SimpleSwitchExpressionConverter : public ExpressionConverter { } bool isStandardMetadataParameter(const IR::Parameter *param) { - auto st = dynamic_cast(structure); - auto params = st->parser->getApplyParameters(); + auto params = structure->parser->getApplyParameters(); if (params->size() != 4) { - modelError("%1%: Expected 4 parameter for parser", st->parser); + modelError("%1%: Expected 4 parameter for parser", structure->parser); return false; } if (params->parameters.at(3) == param) return true; - params = st->ingress->getApplyParameters(); + params = structure->ingress->getApplyParameters(); if (params->size() != 3) { - modelError("%1%: Expected 3 parameter for ingress", st->ingress); + modelError("%1%: Expected 3 parameter for ingress", structure->ingress); return false; } if (params->parameters.at(2) == param) return true; - params = st->egress->getApplyParameters(); + params = structure->egress->getApplyParameters(); if (params->size() != 3) { - modelError("%1%: Expected 3 parameter for egress", st->egress); + modelError("%1%: Expected 3 parameter for egress", structure->egress); return false; } if (params->parameters.at(2) == param) return true; diff --git a/backends/ebpf/ebpfControl.cpp b/backends/ebpf/ebpfControl.cpp index 5f57273de45..31e7b9d51d7 100644 --- a/backends/ebpf/ebpfControl.cpp +++ b/backends/ebpf/ebpfControl.cpp @@ -154,7 +154,7 @@ bool ControlBodyTranslator::preorder(const IR::MethodCallExpression *expression) void ControlBodyTranslator::compileEmitField(const IR::Expression *expr, cstring field, unsigned alignment, EBPFType *type) { - unsigned widthToEmit = dynamic_cast(type)->widthInBits(); + unsigned widthToEmit = type->as().widthInBits(); cstring swap = ""; if (widthToEmit == 16) swap = "htons"; @@ -254,7 +254,7 @@ void ControlBodyTranslator::compileEmit(const IR::Vector *args) { for (auto f : ht->fields) { auto ftype = typeMap->getType(f); auto etype = EBPFTypeFactory::instance->create(ftype); - auto et = dynamic_cast(etype); + auto et = etype->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", f); diff --git a/backends/ebpf/ebpfDeparser.cpp b/backends/ebpf/ebpfDeparser.cpp index 4ba273efd42..4b1423861ad 100644 --- a/backends/ebpf/ebpfDeparser.cpp +++ b/backends/ebpf/ebpfDeparser.cpp @@ -149,7 +149,7 @@ void DeparserHdrEmitTranslator::processMethod(const P4::ExternMethod *method) { for (auto f : headerToEmit->fields) { auto ftype = deparser->program->typeMap->getType(f); auto etype = EBPFTypeFactory::instance->create(ftype); - auto et = dynamic_cast(etype); + auto et = etype->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", f); @@ -171,7 +171,7 @@ void DeparserHdrEmitTranslator::emitField(CodeBuilder *builder, cstring field, EBPF::EBPFType *type) { auto program = deparser->program; - auto et = dynamic_cast(type); + auto et = type->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", hdrExpr); diff --git a/backends/ebpf/ebpfParser.cpp b/backends/ebpf/ebpfParser.cpp index 8637ca370fb..c9c7bff104d 100644 --- a/backends/ebpf/ebpfParser.cpp +++ b/backends/ebpf/ebpfParser.cpp @@ -267,7 +267,7 @@ bool StateTranslationVisitor::preorder(const IR::SelectCase *selectCase) { void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, const IR::StructField *field, unsigned alignment, EBPFType *type) { - unsigned widthToExtract = dynamic_cast(type)->widthInBits(); + unsigned widthToExtract = type->as().widthInBits(); auto program = state->parser->program; cstring msgStr; cstring fieldName = field->name.name; @@ -470,7 +470,7 @@ void StateTranslationVisitor::compileExtract(const IR::Expression *destination) for (auto f : ht->fields) { auto ftype = state->parser->typeMap->getType(f); auto etype = EBPFTypeFactory::instance->create(ftype); - auto et = dynamic_cast(etype); + auto et = etype->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", f); diff --git a/backends/ebpf/ebpfTable.cpp b/backends/ebpf/ebpfTable.cpp index 19eccf1228f..c53ed50f1e4 100644 --- a/backends/ebpf/ebpfTable.cpp +++ b/backends/ebpf/ebpfTable.cpp @@ -541,7 +541,7 @@ void EBPFTable::emitAction(CodeBuilder *builder, cstring valueName, cstring acti builder->target->emitTraceMessage(builder, msgStr.c_str()); for (auto param : *(action->parameters)) { auto etype = EBPFTypeFactory::instance->create(param->type); - unsigned width = dynamic_cast(etype)->widthInBits(); + unsigned width = etype->as().widthInBits(); if (width <= 64) { convStr = Util::printf_format("(unsigned long long) (%s->u.%s.%s)", valueName, name, diff --git a/backends/ebpf/ebpfType.cpp b/backends/ebpf/ebpfType.cpp index 9e45c4ec90c..10c12961eec 100644 --- a/backends/ebpf/ebpfType.cpp +++ b/backends/ebpf/ebpfType.cpp @@ -86,9 +86,11 @@ void EBPFStackType::emitInitializer(CodeBuilder *builder) { builder->append(" }"); } -unsigned EBPFStackType::widthInBits() { return size * elementType->to()->widthInBits(); } +unsigned EBPFStackType::widthInBits() const { + return size * elementType->to()->widthInBits(); +} -unsigned EBPFStackType::implementationWidthInBits() { +unsigned EBPFStackType::implementationWidthInBits() const { return size * elementType->to()->implementationWidthInBits(); } @@ -177,7 +179,7 @@ EBPFStructType::EBPFStructType(const IR::Type_StructLike *strct) : EBPFType(strc for (auto f : strct->fields) { auto type = EBPFTypeFactory::instance->create(f->type); - auto wt = dynamic_cast(type); + auto wt = type->to(); if (wt == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "EBPF: Unsupported type in struct: %s", f->type); @@ -274,8 +276,8 @@ void EBPFTypeName::emitInitializer(CodeBuilder *builder) { if (canonical != nullptr) canonical->emitInitializer(builder); } -unsigned EBPFTypeName::widthInBits() { - auto wt = dynamic_cast(canonical); +unsigned EBPFTypeName::widthInBits() const { + auto wt = canonical->to(); if (wt == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Type %1% does not have a fixed witdh", type); return 0; @@ -283,8 +285,8 @@ unsigned EBPFTypeName::widthInBits() { return wt->widthInBits(); } -unsigned EBPFTypeName::implementationWidthInBits() { - auto wt = dynamic_cast(canonical); +unsigned EBPFTypeName::implementationWidthInBits() const { + auto wt = canonical->to(); if (wt == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Type %1% does not have a fixed witdh", type); return 0; diff --git a/backends/ebpf/ebpfType.h b/backends/ebpf/ebpfType.h index 8d6f134cc2d..94606d12153 100644 --- a/backends/ebpf/ebpfType.h +++ b/backends/ebpf/ebpfType.h @@ -38,24 +38,16 @@ class EBPFType : public EBPFObject { virtual void declareArray(CodeBuilder * /*builder*/, cstring /*id*/, unsigned /*size*/) { BUG("%1%: unsupported array", type); } - template - bool is() const { - return dynamic_cast(this) != nullptr; - } - template - T *to() { - return dynamic_cast(this); - } }; -class IHasWidth { +class IHasWidth : public ICastable { public: virtual ~IHasWidth() {} // P4 width - virtual unsigned widthInBits() = 0; + virtual unsigned widthInBits() const = 0; // Width in the target implementation. // Currently a multiple of 8. - virtual unsigned implementationWidthInBits() = 0; + virtual unsigned implementationWidthInBits() const = 0; }; class EBPFTypeFactory { @@ -78,8 +70,8 @@ class EBPFBoolType : public EBPFType, public IHasWidth { void declare(CodeBuilder *builder, cstring id, bool asPointer) override; void declareInit(CodeBuilder *builder, cstring id, bool asPointer) override; void emitInitializer(CodeBuilder *builder) override { builder->append("0"); } - unsigned widthInBits() override { return 1; } - unsigned implementationWidthInBits() override { return 8; } + unsigned widthInBits() const override { return 1; } + unsigned implementationWidthInBits() const override { return 8; } }; class EBPFStackType : public EBPFType, public IHasWidth { @@ -97,8 +89,8 @@ class EBPFStackType : public EBPFType, public IHasWidth { void declare(CodeBuilder *builder, cstring id, bool asPointer) override; void declareInit(CodeBuilder *builder, cstring id, bool asPointer) override; void emitInitializer(CodeBuilder *builder) override; - unsigned widthInBits() override; - unsigned implementationWidthInBits() override; + unsigned widthInBits() const override; + unsigned implementationWidthInBits() const override; }; class EBPFScalarType : public EBPFType, public IHasWidth { @@ -115,8 +107,8 @@ class EBPFScalarType : public EBPFType, public IHasWidth { void declare(CodeBuilder *builder, cstring id, bool asPointer) override; void declareInit(CodeBuilder *builder, cstring id, bool asPointer) override; void emitInitializer(CodeBuilder *builder) override; - unsigned widthInBits() override { return width; } - unsigned implementationWidthInBits() override { return bytesRequired() * 8; } + unsigned widthInBits() const override { return width; } + unsigned implementationWidthInBits() const override { return bytesRequired() * 8; } // True if this width is small enough to store in a machine scalar static bool generatesScalar(unsigned width) { return width <= 64; } }; @@ -133,13 +125,13 @@ class EBPFTypeName : public EBPFType, public IHasWidth { void declare(CodeBuilder *builder, cstring id, bool asPointer) override; void declareInit(CodeBuilder *builder, cstring id, bool asPointer) override; void emitInitializer(CodeBuilder *builder) override; - unsigned widthInBits() override; - unsigned implementationWidthInBits() override; + unsigned widthInBits() const override; + unsigned implementationWidthInBits() const override; void declareArray(CodeBuilder *builder, cstring id, unsigned size) override; template bool canonicalTypeIs() const { - return dynamic_cast(this->canonical) != nullptr; + return this->canonical->is(); } }; @@ -166,8 +158,8 @@ class EBPFStructType : public EBPFType, public IHasWidth { void declare(CodeBuilder *builder, cstring id, bool asPointer) override; void declareInit(CodeBuilder *builder, cstring id, bool asPointer) override; void emitInitializer(CodeBuilder *builder) override; - unsigned widthInBits() override { return width; } - unsigned implementationWidthInBits() override { return implWidth; } + unsigned widthInBits() const override { return width; } + unsigned implementationWidthInBits() const override { return implWidth; } void emit(CodeBuilder *builder) override; void declareArray(CodeBuilder *builder, cstring id, unsigned size) override; }; @@ -179,8 +171,8 @@ class EBPFEnumType : public EBPFType, public EBPF::IHasWidth { void declare(CodeBuilder *builder, cstring id, bool asPointer) override; void declareInit(CodeBuilder *builder, cstring id, bool asPointer) override; void emitInitializer(CodeBuilder *builder) override { builder->append("0"); } - unsigned widthInBits() override { return 32; } - unsigned implementationWidthInBits() override { return 32; } + unsigned widthInBits() const override { return 32; } + unsigned implementationWidthInBits() const override { return 32; } const IR::Type_Enum *getType() const { return type->to(); } }; diff --git a/backends/ebpf/psa/ebpfPsaDeparser.cpp b/backends/ebpf/psa/ebpfPsaDeparser.cpp index 6c7a719f6d5..8ac4b76218b 100644 --- a/backends/ebpf/psa/ebpfPsaDeparser.cpp +++ b/backends/ebpf/psa/ebpfPsaDeparser.cpp @@ -170,7 +170,7 @@ void TCIngressDeparserPSA::emitPreDeparser(CodeBuilder *builder) { "skipping deparser.."); builder->emitIndent(); CHECK_NULL(program); - auto pipeline = dynamic_cast(program); + auto pipeline = program->checkedTo(); builder->appendFormat("%s->packet_path = RESUBMIT;", pipeline->compilerGlobalMetadata); builder->newline(); builder->emitIndent(); diff --git a/backends/ebpf/psa/externs/ebpfPsaCounter.cpp b/backends/ebpf/psa/externs/ebpfPsaCounter.cpp index af3dc8785f5..d4614990041 100644 --- a/backends/ebpf/psa/externs/ebpfPsaCounter.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaCounter.cpp @@ -196,7 +196,7 @@ void EBPFCounterPSA::emitDirectMethodInvocation(CodeBuilder *builder, BUG_CHECK(method->expr->arguments->size() == 0, "Expected no arguments for %1%", method->expr); cstring target = valuePtr + "->" + instanceName; - auto pipeline = dynamic_cast(program); + auto pipeline = program->to(); CHECK_NULL(pipeline); cstring msgStr = diff --git a/backends/ebpf/psa/externs/ebpfPsaMeter.cpp b/backends/ebpf/psa/externs/ebpfPsaMeter.cpp index 989d6d9ac3a..d640e255a33 100644 --- a/backends/ebpf/psa/externs/ebpfPsaMeter.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaMeter.cpp @@ -158,7 +158,7 @@ void EBPFMeterPSA::emitInstance(CodeBuilder *builder) const { void EBPFMeterPSA::emitExecute(CodeBuilder *builder, const P4::ExternMethod *method, ControlBodyTranslatorPSA *translator) const { - auto pipeline = dynamic_cast(program); + auto pipeline = program->to(); CHECK_NULL(pipeline); cstring functionNameSuffix; @@ -202,7 +202,7 @@ void EBPFMeterPSA::emitIndex(CodeBuilder *builder, const P4::ExternMethod *metho void EBPFMeterPSA::emitDirectExecute(CodeBuilder *builder, const P4::ExternMethod *method, cstring valuePtr) const { - auto pipeline = dynamic_cast(program); + auto pipeline = program->to(); CHECK_NULL(pipeline); cstring functionNameSuffix; diff --git a/backends/ebpf/psa/externs/ebpfPsaRegister.cpp b/backends/ebpf/psa/externs/ebpfPsaRegister.cpp index e75b2e9e2f3..ef89a0a9540 100644 --- a/backends/ebpf/psa/externs/ebpfPsaRegister.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaRegister.cpp @@ -64,7 +64,7 @@ EBPFRegisterPSA::EBPFRegisterPSA(const EBPFProgram *program, cstring instanceNam bool EBPFRegisterPSA::shouldUseArrayMap() { CHECK_NULL(this->keyType); - if (auto wt = dynamic_cast(this->keyType)) { + if (auto wt = this->keyType->to()) { unsigned keyWidth = wt->widthInBits(); // For keys <= 32 bit register is based on array map, // otherwise we use hash map diff --git a/backends/p4tools/common/core/abstract_execution_state.cpp b/backends/p4tools/common/core/abstract_execution_state.cpp index bd754de78e2..d384adc0878 100644 --- a/backends/p4tools/common/core/abstract_execution_state.cpp +++ b/backends/p4tools/common/core/abstract_execution_state.cpp @@ -101,7 +101,7 @@ const IR::Expression *AbstractExecutionState::convertToComplexExpression( IR::Vector components; const auto *elementType = resolveType(ts->elementType); for (size_t idx = 0; idx < ts->getSize(); idx++) { - auto ref = new IR::ArrayIndex(elementType, parent, new IR::Constant(idx)); + auto ref = new IR::ArrayIndex(elementType, parent, new IR::Constant(uint64_t(idx))); if (elementType->is() || elementType->to()) { components.push_back(convertToComplexExpression(ref)); } else { diff --git a/backends/tc/ebpfCodeGen.cpp b/backends/tc/ebpfCodeGen.cpp index 4f035fa78f9..f681af314b2 100644 --- a/backends/tc/ebpfCodeGen.cpp +++ b/backends/tc/ebpfCodeGen.cpp @@ -219,8 +219,8 @@ void TCIngressPipelinePNA::emit(EBPF::CodeBuilder *builder) { "int %s(%s *%s, %s %s *%s, " "struct pna_global_metadata *%s", func_name, builder->target->packetDescriptorType(), model.CPacketName.str(), - parser->headerType->to()->kind, - parser->headerType->to()->name, parser->headers->name.name, + parser->headerType->as().kind, + parser->headerType->as().name, parser->headers->name.name, compilerGlobalMetadata); builder->append(")"); @@ -328,8 +328,8 @@ void TCIngressPipelinePNA::emit(EBPF::CodeBuilder *builder) { builder->appendFormat("ret = %s(skb, ", func_name); builder->appendFormat("(%s %s *) %s, %s);", - parser->headerType->to()->kind, - parser->headerType->to()->name, + parser->headerType->as().kind, + parser->headerType->as().name, parser->headers->name.name, compilerGlobalMetadata); builder->newline(); @@ -370,8 +370,8 @@ void TCIngressPipelinePNA::emit(EBPF::CodeBuilder *builder) { builder->appendFormat("ret = %s(skb, ", func_name); builder->appendFormat("(%s %s *) %s, %s);", - parser->headerType->to()->kind, - parser->headerType->to()->name, + parser->headerType->as().kind, + parser->headerType->as().name, parser->headers->name.name, compilerGlobalMetadata); builder->newline(); @@ -516,7 +516,7 @@ void EBPFPnaParser::emit(EBPF::CodeBuilder *builder) { void PnaStateTranslationVisitor::compileExtractField(const IR::Expression *expr, const IR::StructField *field, unsigned alignment, EBPF::EBPFType *type) { - auto width = dynamic_cast(type); + auto width = type->to(); if (width == nullptr) return; unsigned widthToExtract = width->widthInBits(); auto program = state->parser->program; @@ -684,7 +684,7 @@ void EBPFTablePNA::emitKeyType(EBPF::CodeBuilder *builder) { if (keyGenerator != nullptr) { for (auto c : keyGenerator->keyElements) { auto mtdecl = program->refMap->getDeclaration(c->matchType->path, true); - auto matchType = mtdecl->getNode()->to(); + auto matchType = mtdecl->getNode()->checkedTo(); if (!isMatchTypeSupported(matchType)) { ::error(ErrorType::ERR_UNSUPPORTED, "Match of type %1% not supported", @@ -695,7 +695,7 @@ void EBPFTablePNA::emitKeyType(EBPF::CodeBuilder *builder) { cstring fieldName = ::get(keyFieldNames, c); if (ebpfType->is() && - ebpfType->to()->alignment() > structAlignment) { + ebpfType->as().alignment() > structAlignment) { structAlignment = 8; } @@ -773,7 +773,7 @@ void EBPFTablePNA::emitValueStructStructure(EBPF::CodeBuilder *builder) { for (auto a : actionList->actionList) { auto adecl = program->refMap->getDeclaration(a->getPath(), true); - auto action = adecl->getNode()->to(); + auto action = adecl->getNode()->checkedTo(); if (action->name.originalName == P4::P4CoreLibrary::instance().noAction.name) continue; cstring name = EBPF::EBPFObject::externalName(action); emitActionArguments(builder, action, name); @@ -823,7 +823,7 @@ void EBPFTablePNA::emitAction(EBPF::CodeBuilder *builder, cstring valueName, for (auto a : actionList->actionList) { auto adecl = program->refMap->getDeclaration(a->getPath(), true); - auto action = adecl->getNode()->to(); + auto action = adecl->getNode()->checkedTo(); cstring name = EBPF::EBPFObject::externalName(action), msgStr, convStr; builder->emitIndent(); cstring actionName = p4ActionToActionIDName(action); @@ -835,7 +835,7 @@ void EBPFTablePNA::emitAction(EBPF::CodeBuilder *builder, cstring valueName, builder->target->emitTraceMessage(builder, msgStr.c_str()); for (auto param : *(action->parameters)) { auto etype = EBPF::EBPFTypeFactory::instance->create(param->type); - unsigned width = dynamic_cast(etype)->widthInBits(); + unsigned width = etype->as().widthInBits(); if (width <= 64) { convStr = Util::printf_format("(unsigned long long) (%s->u.%s.%s)", valueName, name, @@ -947,7 +947,7 @@ void EBPFTablePNA::emitValueActionIDNames(EBPF::CodeBuilder *builder) { builder->emitIndent(); for (auto a : actionList->actionList) { auto adecl = program->refMap->getDeclaration(a->getPath(), true); - auto action = adecl->getNode()->to(); + auto action = adecl->getNode()->checkedTo(); unsigned int action_idx = tcIR->getActionId(tcIR->externalName(action)); builder->emitIndent(); builder->appendFormat("#define %s %d", p4ActionToActionIDName(action), action_idx); @@ -982,7 +982,7 @@ bool IngressDeparserPNA::build() { void IngressDeparserPNA::emitPreDeparser(EBPF::CodeBuilder *builder) { builder->emitIndent(); CHECK_NULL(program); - auto pipeline = dynamic_cast(program); + auto pipeline = program->checkedTo(); builder->appendFormat("if (%s->drop) ", pipeline->compilerGlobalMetadata); builder->blockStart(); builder->target->emitTraceMessage(builder, "PreDeparser: dropping packet.."); @@ -1072,7 +1072,7 @@ const PNAEbpfGenerator *ConvertToEbpfPNA::build(const IR::ToplevelBlock *tlb) { /* * PIPELINE */ - auto pipeline = tlb->getMain()->to(); + auto pipeline = tlb->getMain()->checkedTo(); auto pipelineParser = pipeline->getParameterValue("main_parser"); BUG_CHECK(pipelineParser != nullptr, "No parser block found"); auto pipelineControl = pipeline->getParameterValue("main_control"); @@ -1083,9 +1083,9 @@ const PNAEbpfGenerator *ConvertToEbpfPNA::build(const IR::ToplevelBlock *tlb) { auto xdp = new EBPF::XDPHelpProgram(options); auto pipeline_converter = new ConvertToEbpfPipelineTC( - "tc-ingress", EBPF::TC_INGRESS, options, pipelineParser->to(), - pipelineControl->to(), pipelineDeparser->to(), refmap, - typemap, tcIR); + "tc-ingress", EBPF::TC_INGRESS, options, pipelineParser->checkedTo(), + pipelineControl->checkedTo(), + pipelineDeparser->checkedTo(), refmap, typemap, tcIR); pipeline->apply(*pipeline_converter); tlb->getProgram()->apply(*pipeline_converter); auto tcIngress = pipeline_converter->getEbpfPipeline(); @@ -1173,7 +1173,7 @@ bool ConvertToEBPFParserPNA::preorder(const IR::P4ValueSet *pvs) { bool ConvertToEBPFControlPNA::preorder(const IR::ControlBlock *ctrl) { control = new EBPF::EBPFControlPSA(program, ctrl, parserHeaders); program->control = control; - program->to()->control = control; + program->as().control = control; control->hitVariable = refmap->newName("hit"); auto pl = ctrl->container->type->applyParams; unsigned numOfParams = 4; @@ -1205,8 +1205,8 @@ bool ConvertToEBPFControlPNA::preorder(const IR::ControlBlock *ctrl) { for (auto a : ctrl->constantValue) { auto b = a.second; - if (b->is()) { - this->visit(b->to()); + if (auto *block = b->to()) { + this->visit(block); } } return true; @@ -1605,7 +1605,7 @@ ActionTranslationVisitorPNA::ActionTranslationVisitorPNA(const EBPF::EBPFProgram const ConvertToBackendIR *tcIR) : EBPF::CodeGenInspector(program->refMap, program->typeMap), EBPF::ActionTranslationVisitor(valueName, program), - ControlBodyTranslatorPNA(program->to()->control, tcIR, table), + ControlBodyTranslatorPNA(program->as().control, tcIR, table), table(table) {} bool ActionTranslationVisitorPNA::preorder(const IR::PathExpression *pe) { @@ -1639,8 +1639,8 @@ cstring ActionTranslationVisitorPNA::getParamName(const IR::PathExpression *expr EBPF::ActionTranslationVisitor *EBPFTablePNA::createActionTranslationVisitor( cstring valueName, const EBPF::EBPFProgram *program) const { - return new ActionTranslationVisitorPNA(program->to(), valueName, this, - tcIR); + return new ActionTranslationVisitorPNA(program->checkedTo(), valueName, + this, tcIR); } void EBPFTablePNA::validateKeys() const { @@ -1651,7 +1651,7 @@ void EBPFTablePNA::validateKeys() const { [](const IR::KeyElement *key) { return key->matchType->path->name.name != "selector"; }); for (auto it : keyGenerator->keyElements) { auto mtdecl = program->refMap->getDeclaration(it->matchType->path, true); - auto matchType = mtdecl->getNode()->to(); + auto matchType = mtdecl->getNode()->checkedTo(); if (matchType->name.name == P4::P4CoreLibrary::instance().lpmMatch.name) { if (it != *lastKey) { ::error(ErrorType::ERR_UNSUPPORTED, "%1% field key must be at the end of whole key", @@ -1712,7 +1712,7 @@ void DeparserHdrEmitTranslatorPNA::processMethod(const P4::ExternMethod *method) for (auto f : headerToEmit->fields) { auto ftype = deparser->program->typeMap->getType(f); auto etype = EBPF::EBPFTypeFactory::instance->create(ftype); - auto et = dynamic_cast(etype); + auto et = etype->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", f); @@ -1746,7 +1746,7 @@ void DeparserHdrEmitTranslatorPNA::emitField(EBPF::CodeBuilder *builder, cstring EBPF::EBPFType *type, bool noEndiannessConversion) { auto program = deparser->program; - auto et = dynamic_cast(type); + auto et = type->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", hdrExpr); diff --git a/backends/ubpf/ubpfDeparser.cpp b/backends/ubpf/ubpfDeparser.cpp index d3c52cef2f9..cce0e1b4057 100644 --- a/backends/ubpf/ubpfDeparser.cpp +++ b/backends/ubpf/ubpfDeparser.cpp @@ -110,7 +110,7 @@ UBPFDeparserTranslationVisitor::UBPFDeparserTranslationVisitor(const UBPFDeparse void UBPFDeparserTranslationVisitor::compileEmitField(const IR::Expression *expr, cstring field, unsigned alignment, EBPF::EBPFType *type) { - auto et = dynamic_cast(type); + auto et = type->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", expr); @@ -249,7 +249,7 @@ void UBPFDeparserTranslationVisitor::compileEmit(const IR::Vector for (auto f : ht->fields) { auto ftype = typeMap->getType(f); auto etype = UBPFTypeFactory::instance->create(ftype); - auto et = dynamic_cast(etype); + auto et = etype->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", f); diff --git a/backends/ubpf/ubpfParser.cpp b/backends/ubpf/ubpfParser.cpp index ab246e4ed34..ee0f8874669 100644 --- a/backends/ubpf/ubpfParser.cpp +++ b/backends/ubpf/ubpfParser.cpp @@ -192,7 +192,7 @@ bool UBPFStateTranslationVisitor::preorder(const IR::Member *expression) { void UBPFStateTranslationVisitor::compileExtractField(const IR::Expression *expr, cstring field, unsigned alignment, EBPF::EBPFType *type, bool advanceCursor) { - unsigned widthToExtract = dynamic_cast(type)->widthInBits(); + unsigned widthToExtract = type->as().widthInBits(); auto program = state->parser->program; if (widthToExtract <= 64) { @@ -298,7 +298,7 @@ void UBPFStateTranslationVisitor::compileExtract(const IR::Expression *destinati for (auto f : ht->fields) { auto ftype = state->parser->typeMap->getType(f); auto etype = UBPFTypeFactory::instance->create(ftype); - auto et = dynamic_cast(etype); + auto et = etype->to(); if (et == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Only headers with fixed widths supported %1%", f); @@ -323,7 +323,7 @@ void UBPFStateTranslationVisitor::compileLookahead(const IR::Expression *destina if (type->to() == nullptr) BUG("lookahead<%1%>(): only bit type is supported yet", type); - unsigned width = dynamic_cast(etype)->widthInBits(); + unsigned width = etype->as().widthInBits(); if (width > 64) BUG("lookahead<%1%>(): more than 64 bits not supported yet", type); // check packet's length diff --git a/backends/ubpf/ubpfType.cpp b/backends/ubpf/ubpfType.cpp index 381dee757dd..3049fac6e1d 100644 --- a/backends/ubpf/ubpfType.cpp +++ b/backends/ubpf/ubpfType.cpp @@ -179,7 +179,7 @@ UBPFListType::UBPFListType(const IR::Type_List *lst) : EBPFType(lst) { // The first iteration is to compute total width of Type_List. for (auto el : lst->components) { auto ltype = UBPFTypeFactory::instance->create(el); - auto wt = dynamic_cast(ltype); + auto wt = ltype->to(); if (wt == nullptr) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "UBPF: Unsupported type in Type_List: %s", el->getP4Type()); diff --git a/backends/ubpf/ubpfType.h b/backends/ubpf/ubpfType.h index babf21583d5..d82e56c0ecb 100644 --- a/backends/ubpf/ubpfType.h +++ b/backends/ubpf/ubpfType.h @@ -70,21 +70,13 @@ class UBPFEnumType : public EBPF::EBPFEnumType { }; class UBPFListType : public EBPF::EBPFType, public EBPF::IHasWidth { - class UBPFListElement { + class UBPFListElement : public ICastable { public: EBPFType *type; const cstring name; UBPFListElement(EBPFType *type, const cstring name) : type(type), name(name) {} virtual ~UBPFListElement() {} // to make UBPFListElement polymorphic. - template - bool is() const { - return dynamic_cast(this) != nullptr; - } - template - T *to() { - return dynamic_cast(this); - } }; class Padding : public UBPFListElement { @@ -107,8 +99,8 @@ class UBPFListType : public EBPF::EBPFType, public EBPF::IHasWidth { void declare(EBPF::CodeBuilder *builder, cstring id, bool asPointer) override; void declareInit(EBPF::CodeBuilder *builder, cstring id, bool asPointer) override; void emitInitializer(EBPF::CodeBuilder *builder) override; - unsigned widthInBits() override { return width; } - unsigned implementationWidthInBits() override { return implWidth; } + unsigned widthInBits() const override { return width; } + unsigned implementationWidthInBits() const override { return implWidth; } void emit(EBPF::CodeBuilder *builder) override; }; diff --git a/frontends/p4/def_use.cpp b/frontends/p4/def_use.cpp index 64e1ecc7aea..02e5888da9b 100644 --- a/frontends/p4/def_use.cpp +++ b/frontends/p4/def_use.cpp @@ -82,8 +82,8 @@ StorageLocation *StorageFactory::create(const IR::Type *type, cstring name) cons cstring fieldName = name + "." + f->name; auto sl = create(f->type, fieldName); if (globalValid != nullptr) - dynamic_cast(sl)->replaceField(fieldName + "." + validFieldName, - globalValid); + sl->as().replaceField(fieldName + "." + validFieldName, + globalValid); result->createField(f->name.name, sl); } if (st->is()) { diff --git a/frontends/p4/def_use.h b/frontends/p4/def_use.h index 9886fb91828..f65d67a7903 100644 --- a/frontends/p4/def_use.h +++ b/frontends/p4/def_use.h @@ -32,7 +32,7 @@ class StorageFactory; class LocationSet; /// Abstraction for something that is has a left value (variable, parameter) -class StorageLocation : public IHasDbPrint { +class StorageLocation : public IHasDbPrint, public ICastable { static unsigned crtid; public: @@ -43,16 +43,6 @@ class StorageLocation : public IHasDbPrint { StorageLocation(const IR::Type *type, cstring name) : id(crtid++), type(type), name(name) { CHECK_NULL(type); } - template - const T *to() const { - auto result = dynamic_cast(this); - return result; - } - template - bool is() const { - auto result = dynamic_cast(this); - return result != nullptr; - } void dbprint(std::ostream &out) const override { out << id << " " << name; } cstring toString() const { return name; } diff --git a/frontends/p4/fromv1.0/programStructure.cpp b/frontends/p4/fromv1.0/programStructure.cpp index ba9288e797e..1485f55207b 100644 --- a/frontends/p4/fromv1.0/programStructure.cpp +++ b/frontends/p4/fromv1.0/programStructure.cpp @@ -1139,7 +1139,7 @@ static bool sameBitsType(const IR::Node *errorPosition, const IR::Type *left, static bool isSaturatedField(const IR::Expression *expr) { auto member = expr->to(); if (!member) return false; - auto header_type = dynamic_cast(member->expr->type); + auto header_type = member->expr->type->to(); if (!header_type) return false; auto field = header_type->getField(member->member.name); if (field && field->getAnnotation("saturating")) { diff --git a/frontends/p4/methodInstance.h b/frontends/p4/methodInstance.h index ae01631e3d8..ad52f4e3a78 100644 --- a/frontends/p4/methodInstance.h +++ b/frontends/p4/methodInstance.h @@ -130,7 +130,7 @@ class ApplyMethod final : public MethodInstance { public: const IR::IApply *applyObject; - bool isApply() const { return true; } + bool isApply() const override { return true; } bool isTableApply() const { return object->is(); } }; diff --git a/frontends/p4/reassociation.cpp b/frontends/p4/reassociation.cpp index 648f508a03b..ecd5b08b8b6 100644 --- a/frontends/p4/reassociation.cpp +++ b/frontends/p4/reassociation.cpp @@ -25,7 +25,7 @@ const IR::Node *Reassociation::reassociate(IR::Operation_Binary *root) { if (!leftBin) return root; if (leftBin->getStringOp() != root->getStringOp()) return root; if (!leftBin->right->is()) return root; - auto c = dynamic_cast(root->clone()); + auto c = root->clone()->to(); c->left = leftBin->right; c->right = root->right; root->left = leftBin->left; diff --git a/frontends/p4/symbol_table.cpp b/frontends/p4/symbol_table.cpp index 63320fe1980..e0940d67a83 100644 --- a/frontends/p4/symbol_table.cpp +++ b/frontends/p4/symbol_table.cpp @@ -24,7 +24,7 @@ limitations under the License. namespace Util { -class NamedSymbol { +class NamedSymbol : public ICastable { protected: Util::SourceInfo sourceInfo; Namespace *parent; @@ -187,7 +187,8 @@ void ProgramStructure::declareObject(IR::ID id, cstring type) { LOG3("ProgramStructure: adding object " << id << " with type " << type); auto type_sym = lookup(type); auto o = new Object(id.name, id.srcInfo); - if (auto tns = dynamic_cast(type_sym)) o->setNamespace(tns); + if (type_sym) + if (auto tns = type_sym->to()) o->setNamespace(tns); currentNamespace->declare(o); } @@ -235,12 +236,12 @@ NamedSymbol *ProgramStructure::lookup(cstring identifier) { ProgramStructure::SymbolKind ProgramStructure::lookupIdentifier(cstring identifier) { NamedSymbol *ns = lookup(identifier); - if (ns == nullptr || dynamic_cast(ns) != nullptr) { + if (ns == nullptr || ns->is()) { LOG2("Identifier " << identifier); if (ns && ns->template_args) return ProgramStructure::SymbolKind::TemplateIdentifier; return ProgramStructure::SymbolKind::Identifier; } - if (dynamic_cast(ns) != nullptr || dynamic_cast(ns) != nullptr) { + if (ns->is() || ns->is()) { if (ns && ns->template_args) return ProgramStructure::SymbolKind::TemplateType; return ProgramStructure::SymbolKind::Type; LOG2("Type " << identifier); diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index dc2f4ce2ae2..d38bc51b13e 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -589,7 +589,7 @@ bool ToP4::preorder(const IR::Type_Control *t) { /////////////////////// bool ToP4::preorder(const IR::Constant *c) { - const IR::Type_Bits *tb = dynamic_cast(c->type); + const IR::Type_Bits *tb = c->type->to(); unsigned width; bool sign; if (tb == nullptr) { diff --git a/frontends/p4/typeChecking/typeUnification.cpp b/frontends/p4/typeChecking/typeUnification.cpp index 6339bf861a8..2ea76ffd06b 100644 --- a/frontends/p4/typeChecking/typeUnification.cpp +++ b/frontends/p4/typeChecking/typeUnification.cpp @@ -450,9 +450,8 @@ bool TypeUnification::unify(const BinaryConstraint *constraint) { } return constraint->reportError(constraints->getCurrentSubstitution()); } else if (dest->is() && src->is()) { - bool canUnify = typeid(dest) == typeid(src) && dest->to()->name == - src->to()->name; - if (!canUnify) return constraint->reportError(constraints->getCurrentSubstitution()); + if (dest->to()->name != src->to()->name) + return constraint->reportError(constraints->getCurrentSubstitution()); return true; } else if (auto dstack = dest->to()) { if (auto sstack = src->to()) { diff --git a/ir/base.def b/ir/base.def index 2d1eb635859..0ae26b64140 100644 --- a/ir/base.def +++ b/ir/base.def @@ -80,7 +80,7 @@ interface IGeneralNamespace : INamespace { // Note that it might also contain a Simple or General namespace nested in these interface INestedNamespace : INamespace { virtual std::vector getNestedNamespaces() const = 0; - Util::Enumerator *getDeclarations() const; + Util::Enumerator *getDeclarations() const override; } /// Interface implemented by something that can be called @@ -107,7 +107,7 @@ interface IContainer : IMayBeGenericType, IDeclaration, IFunctional { virtual Type_Method getConstructorMethodType() const = 0; virtual ParameterList getConstructorParameters() const = 0; // The IFunctional interface - ParameterList getParameters() const { return getConstructorParameters(); } + ParameterList getParameters() const override { return getConstructorParameters(); } } /// This represents a primitive type diff --git a/ir/expression.def b/ir/expression.def index 6d8886e5ffe..0c3cc972cc7 100644 --- a/ir/expression.def +++ b/ir/expression.def @@ -240,15 +240,14 @@ class Constant : Literal { Constant operator-() const; #end toString { - const IR::Type_Bits* tb = dynamic_cast(type); unsigned width; bool sign; - if (tb == nullptr) { + if (const IR::Type_Bits* tb = type->to()) { + width = tb->size; + sign = tb->isSigned; + } else { width = 0; sign = false; - } else { - width = tb->size; - sign = tb->isSigned; } return Util::toString(value, width, sign, base); } diff --git a/ir/ir-inline.h b/ir/ir-inline.h index 0b8ea0afdb7..2dfce243488 100644 --- a/ir/ir-inline.h +++ b/ir/ir-inline.h @@ -88,20 +88,20 @@ void IR::Vector::visit_children(Visitor &v) { i++; continue; } - if (auto l = dynamic_cast(n)) { + if (auto l = n->template to>()) { i = erase(i); i = insert(i, l->vec.begin(), l->vec.end()); i += l->vec.size(); continue; } - if (const auto *v = dynamic_cast(n)) { + if (const auto *v = n->template to()) { if (v->empty()) { i = erase(i); } else { i = insert(i, v->size() - 1, nullptr); for (const auto *el : *v) { CHECK_NULL(el); - if (auto e = dynamic_cast(el)) { + if (auto e = el->template to()) { *i++ = e; } else { BUG("visitor returned invalid type %s for Vector<%s>", el->node_type_name(), @@ -111,7 +111,7 @@ void IR::Vector::visit_children(Visitor &v) { } continue; } - if (auto e = dynamic_cast(n)) { + if (auto e = n->template to()) { *i++ = e; continue; } @@ -163,13 +163,13 @@ void IR::IndexedVector::visit_children(Visitor &v) { i++; continue; } - if (auto l = dynamic_cast *>(n)) { + if (auto l = n->template to>()) { i = erase(i); i = insert(i, l->begin(), l->end()); i += l->Vector::size(); continue; } - if (auto e = dynamic_cast(n)) { + if (auto e = n->template to()) { i = replace(i, e); continue; } @@ -242,12 +242,12 @@ void IR::NameMap::visit_children(Visitor &v) { i++; continue; } - if (auto m = dynamic_cast(n)) { + if (auto m = n->template to()) { namemap_insert_helper(i, m->symbols.begin(), m->symbols.end(), symbols, new_symbols); i = symbols.erase(i); continue; } - if (auto s = dynamic_cast(n)) { + if (auto s = n->template to()) { if (match_name(i->first, s)) { i->second = s; i++; diff --git a/ir/json_loader.h b/ir/json_loader.h index d3982429313..0cb233514bd 100644 --- a/ir/json_loader.h +++ b/ir/json_loader.h @@ -70,21 +70,21 @@ class JSONLoader { JSONLoader(const JSONLoader &unpacker, const std::string &field) : node_refs(unpacker.node_refs), json(nullptr) { - if (auto obj = dynamic_cast(unpacker.json)) json = get(obj, field); + if (auto *obj = unpacker.json->to()) json = get(obj, field); } private: const IR::Node *get_node() { if (!json || !json->is()) return nullptr; // invalid json exception? - int id = json->to()->get_id(); + int id = json->as().get_id(); if (id >= 0) { if (node_refs.find(id) == node_refs.end()) { - if (auto fn = get(IR::unpacker_table, json->to()->get_type())) { + if (auto fn = get(IR::unpacker_table, json->as().get_type())) { node_refs[id] = fn(*this); // Creating JsonObject from source_info read from jsonFile // and setting SourceInfo for each node // when "--fromJSON" flag is used - JsonObject *obj = new JsonObject(json->to()->get_sourceJson()); + JsonObject *obj = new JsonObject(json->as().get_sourceJson()); if (obj->hasSrcInfo() == true) { node_refs[id]->srcInfo = Util::SourceInfo(obj->get_filename(), obj->get_line(), @@ -102,7 +102,7 @@ class JSONLoader { template void unpack_json(safe_vector &v) { T temp; - for (auto e : *json->to()) { + for (auto e : json->as()) { load(e, temp); v.push_back(temp); } @@ -111,7 +111,7 @@ class JSONLoader { template void unpack_json(std::set &v) { T temp; - for (auto e : *json->to()) { + for (auto e : json->as()) { load(e, temp); v.insert(temp); } @@ -120,7 +120,7 @@ class JSONLoader { template void unpack_json(ordered_set &v) { T temp; - for (auto e : *json->to()) { + for (auto e : json->as()) { load(e, temp); v.insert(temp); } @@ -156,7 +156,7 @@ class JSONLoader { template void unpack_json(std::map &v) { std::pair temp; - for (auto e : *json->to()) { + for (auto e : json->as()) { JsonString *k = new JsonString(e.first); load(k, temp.first); load(e.second, temp.second); @@ -166,7 +166,7 @@ class JSONLoader { template void unpack_json(ordered_map &v) { std::pair temp; - for (auto e : *json->to()) { + for (auto e : json->as()) { JsonString *k = new JsonString(e.first); load(k, temp.first); load(e.second, temp.second); @@ -176,7 +176,7 @@ class JSONLoader { template void unpack_json(std::multimap &v) { std::pair temp; - for (auto e : *json->to()) { + for (auto e : json->as()) { JsonString *k = new JsonString(e.first); load(k, temp.first); load(e.second, temp.second); @@ -187,7 +187,7 @@ class JSONLoader { template void unpack_json(std::vector &v) { T temp; - for (auto e : *json->to()) { + for (auto e : json->as()) { load(e, temp); v.push_back(temp); } @@ -195,14 +195,14 @@ class JSONLoader { template void unpack_json(std::pair &v) { - const JsonObject *obj = json->to(); + const JsonObject *obj = json->checkedTo(); load(::get(obj, "first"), v.first); load(::get(obj, "second"), v.second); } template void unpack_json(std::optional &v) { - const JsonObject *obj = json->to(); + const JsonObject *obj = json->checkedTo(); bool isValid = false; load(::get(obj, "valid"), isValid); if (!isValid) { @@ -213,15 +213,15 @@ class JSONLoader { load(::get(obj, "value"), value), v = std::move(value); } - void unpack_json(bool &v) { v = *json->to(); } + void unpack_json(bool &v) { v = json->as(); } template typename std::enable_if::value>::type unpack_json(T &v) { - v = *json->to(); + v = json->as(); } - void unpack_json(big_int &v) { v = json->to()->val; } + void unpack_json(big_int &v) { v = json->as().val; } void unpack_json(cstring &v) { - std::string tmp = *json->to(); + std::string tmp = json->as(); std::string::size_type p = 0; while ((p = tmp.find('\\', p)) != std::string::npos) { tmp.erase(p, 1); @@ -241,24 +241,24 @@ class JSONLoader { if (!json->is()) v = tmp; } void unpack_json(IR::ID &v) { - if (!json->is()) v.name = *json->to(); + if (!json->is()) v.name = json->as(); } void unpack_json(LTBitMatrix &m) { - if (auto *s = json->to()) s->c_str() >> m; + if (auto *s = json->to()) s->c_str() >> m; } void unpack_json(bitvec &v) { - if (auto *s = json->to()) s->c_str() >> v; + if (auto *s = json->to()) s->c_str() >> v; } template typename std::enable_if::value>::type unpack_json(T &v) { - if (auto *s = json->to()) *s >> v; + if (auto *s = json->to()) *s >> v; } void unpack_json(match_t &v) { - if (auto *s = json->to()) s->c_str() >> v; + if (auto *s = json->to()) s->c_str() >> v; } void unpack_json(UnparsedConstant *&v) { @@ -301,11 +301,11 @@ class JSONLoader { template typename std::enable_if::value>::type unpack_json(T &v) { - v = *(get_node()->to()); + v = get_node()->as(); } template typename std::enable_if::value>::type unpack_json(const T *&v) { - v = get_node()->to(); + v = get_node()->checkedTo(); } template diff --git a/ir/json_parser.cpp b/ir/json_parser.cpp index f578750af6f..9d134785ac7 100644 --- a/ir/json_parser.cpp +++ b/ir/json_parser.cpp @@ -25,55 +25,61 @@ limitations under the License. #include int JsonObject::get_id() const { - if (find("Node_ID") == end()) - return -1; - else - return *(find("Node_ID")->second->to()); + auto it = find("Node_ID"); + if (it == end()) return -1; + + return it->second->as(); } std::string JsonObject::get_type() const { - if (find("Node_Type") == end()) - return ""; - else - return *(dynamic_cast(find("Node_Type")->second)); + auto it = find("Node_Type"); + if (it == end()) return ""; + + return it->second->as(); } std::string JsonObject::get_filename() const { - if (find("filename") == end()) - return ""; - else - return *(dynamic_cast(find("filename")->second)); + auto it = find("filename"); + + if (it == end()) return ""; + + return it->second->as(); } std::string JsonObject::get_sourceFragment() const { - if (find("source_fragment") == end()) - return ""; - else - return *(dynamic_cast(find("source_fragment")->second)); + auto it = find("source_fragment"); + + if (it == end()) return ""; + + return it->second->as(); } int JsonObject::get_line() const { - if (find("line") == end()) - return -1; - else - return *(find("line")->second->to()); + auto it = find("line"); + + if (it == end()) return -1; + + return it->second->as(); } int JsonObject::get_column() const { - if (find("column") == end()) - return -1; - else - return *(find("column")->second->to()); + auto it = find("column"); + + if (it == end()) return -1; + + return it->second->as(); } JsonObject JsonObject::get_sourceJson() const { - if (find("Source_Info") == end()) { + auto it = find("Source_Info"); + + if (it == end()) { JsonObject obj; obj.setSrcInfo(false); return obj; - } else { - return *(dynamic_cast(find("Source_Info")->second)); } + + return it->second->as(); } // Hack to make << operator work multi-threaded @@ -86,8 +92,7 @@ std::string getIndent(int l) { } std::ostream &operator<<(std::ostream &out, JsonData *json) { - if (dynamic_cast(json)) { - auto obj = dynamic_cast *>(json); + if (auto *obj = json->to()) { out << "{"; if (obj->size() > 0) { level++; @@ -97,8 +102,7 @@ std::ostream &operator<<(std::ostream &out, JsonData *json) { out << getIndent(--level); } out << "}"; - } else if (dynamic_cast(json)) { - std::vector *vec = dynamic_cast *>(json); + } else if (auto *vec = json->to()) { out << "["; if (vec->size() > 0) { level++; @@ -109,18 +113,15 @@ std::ostream &operator<<(std::ostream &out, JsonData *json) { out << getIndent(--level); } out << "]"; - } else if (dynamic_cast(json)) { - JsonString *s = dynamic_cast(json); + } else if (auto *s = json->to()) { out << "\"" << s->c_str() << "\""; - } else if (dynamic_cast(json)) { - JsonNumber *num = dynamic_cast(json); + } else if (auto *num = json->to()) { out << num->val; - } else if (dynamic_cast(json)) { - JsonBoolean *b = dynamic_cast(json); + } else if (auto *b = json->to()) { out << (b->val ? "true" : "false"); - } else if (dynamic_cast(json)) { + } else if (json->is()) { out << "null"; } return out; @@ -140,7 +141,7 @@ std::istream &operator>>(std::istream &in, JsonData *&json) { JsonData *key, *val; in >> key >> std::ws >> ch >> std::ws >> val; - obj[*(dynamic_cast(key))] = val; + obj[key->as()] = val; in >> std::ws >> ch; } while (in && ch != '}'); diff --git a/ir/namemap.h b/ir/namemap.h index fd0476bdc6d..43b39aee0ab 100644 --- a/ir/namemap.h +++ b/ir/namemap.h @@ -97,7 +97,7 @@ class NameMap : public Node { template const U *get(cstring name) const { for (auto it = symbols.find(name); it != symbols.end() && it->first == name; it++) - if (auto rv = dynamic_cast(it->second)) return rv; + if (auto rv = it->second->template to()) return rv; return nullptr; } void add(cstring name, const T *n) { diff --git a/ir/node.h b/ir/node.h index fa0c37d7fd6..479a998b1b6 100644 --- a/ir/node.h +++ b/ir/node.h @@ -60,17 +60,6 @@ class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable virtual cstring node_type_name() const = 0; virtual void validate() const {} virtual const Annotation *getAnnotation(cstring) const { return nullptr; } - /// A checked version of INode::to. A BUG occurs if the cast fails. - /// - /// A similar effect can be achieved with `&as()`, but this method - /// produces a message that is easier to debug. - template - const T *checkedTo() const { - const auto *result = to(); - BUG_CHECK(result, "Cast failed: %1% with type %2% is not a %3%.", this, node_type_name(), - T::static_type_name()); - return result; - } }; class Node : public virtual INode { diff --git a/ir/nodemap.h b/ir/nodemap.h index 9b9037f65a2..fe46db088ee 100644 --- a/ir/nodemap.h +++ b/ir/nodemap.h @@ -65,7 +65,7 @@ class NodeMap : public Node { template const U *get(const KEY *k) const { for (auto it = symbols.find(k); it != symbols.end() && it->first == k; it++) - if (auto rv = dynamic_cast(it->second)) return rv; + if (auto rv = it->second->template to()) return rv; return nullptr; } elem_ref operator[](const KEY *k) { return elem_ref(*this, k); } diff --git a/ir/solver.h b/ir/solver.h index 1a2545512ad..dd406a36b2b 100644 --- a/ir/solver.h +++ b/ir/solver.h @@ -62,14 +62,6 @@ class AbstractSolver : public ICastable { /// @returns whether this solver is incremental. [[nodiscard]] virtual bool isInIncrementalMode() const = 0; - - /// Cast an abstract solver to its specific sub type. - /// Casts involving "const" have to explicit in this case. This is necessary because abstract - /// solvers have no straightforward mechanism to support clone operations. - template - T *to() { - return dynamic_cast(this); - } }; #endif /* IR_SOLVER_H_ */ diff --git a/ir/visitor.cpp b/ir/visitor.cpp index 644c7c9c90d..ce0efe575f0 100644 --- a/ir/visitor.cpp +++ b/ir/visitor.cpp @@ -590,7 +590,7 @@ IRNODE_ALL_NON_TEMPLATE_CLASSES(DEFINE_APPLY_FUNCTIONS, , , ) #define DEFINE_VISIT_FUNCTIONS(CLASS, BASE) \ void Visitor::visit(const IR::CLASS *&n, const char *name) { \ auto t = apply_visitor(n, name); \ - n = dynamic_cast(t); \ + n = (t ? t->to() : nullptr); \ if (t && !n) BUG("visitor returned non-" #CLASS " type: %1%", t); \ } \ void Visitor::visit(const IR::CLASS *const &n, const char *name) { \ @@ -600,7 +600,7 @@ IRNODE_ALL_NON_TEMPLATE_CLASSES(DEFINE_APPLY_FUNCTIONS, , , ) void Visitor::visit(const IR::CLASS *&n, const char *name, int cidx) { \ if (ctxt) ctxt->child_index = cidx; \ auto t = apply_visitor(n, name); \ - n = dynamic_cast(t); \ + n = (t ? t->to() : nullptr); \ if (t && !n) BUG("visitor returned non-" #CLASS " type: %1%", t); \ } \ void Visitor::visit(const IR::CLASS *const &n, const char *name, int cidx) { \ diff --git a/ir/visitor.h b/ir/visitor.h index 812c8beddb2..1cd04ac56ef 100644 --- a/ir/visitor.h +++ b/ir/visitor.h @@ -55,7 +55,7 @@ struct Visitor_Context { inline const T *findContext(const Visitor_Context *&c) const { c = this; while ((c = c->parent)) - if (auto *rv = dynamic_cast(c->node)) return rv; + if (auto *rv = c->node->to()) return rv; return nullptr; } template @@ -248,7 +248,7 @@ class Visitor { if (!c) c = ctxt; if (!c) return nullptr; while ((c = c->parent)) - if (auto *rv = dynamic_cast(c->node)) return rv; + if (auto *rv = c->node->to()) return rv; return nullptr; } template @@ -261,7 +261,7 @@ class Visitor { if (!c) c = ctxt; if (!c) return nullptr; while ((c = c->parent)) - if (auto *rv = dynamic_cast(c->original)) return rv; + if (auto *rv = c->original->to()) return rv; return nullptr; } template @@ -684,25 +684,25 @@ class SplitFlowVisitVector : public SplitFlowVisit_base { i = vec->erase(i); } else if (result[idx] == *i) { ++i; - } else if (auto l = dynamic_cast *>(result[idx])) { + } else if (auto l = result[idx]->template to>()) { i = vec->erase(i); i = vec->insert(i, l->begin(), l->end()); i += l->size(); - } else if (auto v = dynamic_cast(result[idx])) { + } else if (auto v = result[idx]->template to()) { if (v->empty()) { i = vec->erase(i); } else { i = vec->insert(i, v->size() - 1, nullptr); for (auto el : *v) { CHECK_NULL(el); - if (auto e = dynamic_cast(el)) + if (auto e = el->template to()) *i++ = e; else BUG("visitor returned invalid type %s for Vector<%s>", el->node_type_name(), N::static_type_name()); } } - } else if (auto e = dynamic_cast(result[idx])) { + } else if (auto e = result[idx]->template to()) { *i++ = e; } else { CHECK_NULL(result[idx]); diff --git a/lib/castable.h b/lib/castable.h index fa9d27ef364..b769672a96e 100644 --- a/lib/castable.h +++ b/lib/castable.h @@ -38,6 +38,12 @@ class ICastable { return dynamic_cast(*this); } + /// Tries to convert the class to type T. Returns a nullptr if the cast fails. + template + T &as() { + return dynamic_cast(*this); + } + /// Tries to convert the class to type T. Returns a nullptr if the cast fails. template T *to() { diff --git a/lib/json.h b/lib/json.h index db3a02ffafb..1d1ff1de8ba 100644 --- a/lib/json.h +++ b/lib/json.h @@ -65,7 +65,7 @@ class JsonValue final : public IJson { JsonValue(cstring s) : tag(Kind::String), str(s) {} // NOLINT JsonValue(const std::string &s) : tag(Kind::String), str(s) {} // NOLINT JsonValue(const char *s) : tag(Kind::String), str(s) {} // NOLINT - void serialize(std::ostream &out) const; + void serialize(std::ostream &out) const override; bool operator==(const big_int &v) const; // is_integral is true for bool @@ -110,7 +110,7 @@ class JsonArray final : public IJson, public std::vector { friend class Test::TestJson; public: - void serialize(std::ostream &out) const; + void serialize(std::ostream &out) const override; JsonArray *clone() const { return new JsonArray(*this); } JsonArray *append(IJson *value); JsonArray *append(big_int v) { @@ -156,7 +156,7 @@ class JsonObject final : public IJson, public ordered_map { public: JsonObject() = default; - void serialize(std::ostream &out) const; + void serialize(std::ostream &out) const override; JsonObject *emplace(cstring label, IJson *value); JsonObject *emplace_non_null(cstring label, IJson *value); JsonObject *emplace(cstring label, big_int v) { diff --git a/midend/interpreter.h b/midend/interpreter.h index 5cd70625c63..a0af0110ddb 100644 --- a/midend/interpreter.h +++ b/midend/interpreter.h @@ -28,7 +28,7 @@ namespace P4 { class SymbolicValueFactory; // Base class for all abstract values -class SymbolicValue : public IHasDbPrint { +class SymbolicValue : public IHasDbPrint, public ICastable { static unsigned crtid; protected: @@ -39,25 +39,6 @@ class SymbolicValue : public IHasDbPrint { const IR::Type *type; virtual bool isScalar() const = 0; virtual void dbprint(std::ostream &out) const = 0; - template - T *to() { - return dynamic_cast(this); - } - template - T *checkedTo() { - auto result = dynamic_cast(this); - CHECK_NULL(result); - return result; - } - template - const T *to() const { - auto result = dynamic_cast(this); - return result; - } - template - bool is() const { - return dynamic_cast(this) != nullptr; - } virtual SymbolicValue *clone() const = 0; virtual void setAllUnknown() = 0; virtual void assign(const SymbolicValue *other) = 0; From b1ff84958ff26535bad48d7d5e80fc68632eb189 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Tue, 30 Jan 2024 14:03:09 -0800 Subject: [PATCH 2/4] Produce slightly better error message in case of failed cast --- ir/node.h | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/ir/node.h b/ir/node.h index 479a998b1b6..43db1e5b526 100644 --- a/ir/node.h +++ b/ir/node.h @@ -50,6 +50,14 @@ class IndexedVector; // IWYU pragma: keep // node interface class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable { + private: + template + struct has_static_type_name : std::false_type {}; + + template + struct has_static_type_name> : std::true_type { + }; + public: virtual ~INode() {} virtual const Node *getNode() const = 0; @@ -60,6 +68,24 @@ class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable virtual cstring node_type_name() const = 0; virtual void validate() const {} virtual const Annotation *getAnnotation(cstring) const { return nullptr; } + + // default checkedTo implementation for nodes: just fallback to generic ICastable method + template + const T *checkedTo( + typename std::enable_if_t::value> * = nullptr) const { + return ICastable::checkedTo(); + } + + // alternative checkedTo implementation to produces slightly better error message + // due to node_type_name() / static_type_name() being available + template + const T *checkedTo( + typename std::enable_if_t::value> * = nullptr) const { + const auto *result = to(); + BUG_CHECK(result, "Cast failed: %1% with type %2% is not a %3%.", this, node_type_name(), + T::static_type_name()); + return result; + } }; class Node : public virtual INode { From 2298ff13bc64fd8d91969937c929bb4487d97a41 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Wed, 31 Jan 2024 03:41:02 -0800 Subject: [PATCH 3/4] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vladimír Štill --- frontends/p4/reassociation.cpp | 2 +- ir/ir-inline.h | 14 +++++++------- ir/node.h | 27 ++++++++++++++------------- lib/castable.h | 4 ++-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/frontends/p4/reassociation.cpp b/frontends/p4/reassociation.cpp index ecd5b08b8b6..b674440a9ed 100644 --- a/frontends/p4/reassociation.cpp +++ b/frontends/p4/reassociation.cpp @@ -25,7 +25,7 @@ const IR::Node *Reassociation::reassociate(IR::Operation_Binary *root) { if (!leftBin) return root; if (leftBin->getStringOp() != root->getStringOp()) return root; if (!leftBin->right->is()) return root; - auto c = root->clone()->to(); + auto c = root->checkedTo()->clone(); c->left = leftBin->right; c->right = root->right; root->left = leftBin->left; diff --git a/ir/ir-inline.h b/ir/ir-inline.h index 2dfce243488..f775285d797 100644 --- a/ir/ir-inline.h +++ b/ir/ir-inline.h @@ -78,7 +78,7 @@ IRNODE_ALL_TEMPLATES(DEFINE_APPLY_FUNCTIONS, inline) template void IR::Vector::visit_children(Visitor &v) { for (auto i = vec.begin(); i != vec.end();) { - auto n = v.apply_visitor(*i); + const IR::Node *n = v.apply_visitor(*i); if (!n && *i) { i = erase(i); continue; @@ -88,13 +88,13 @@ void IR::Vector::visit_children(Visitor &v) { i++; continue; } - if (auto l = n->template to>()) { + if (auto l = n->to>()) { i = erase(i); i = insert(i, l->vec.begin(), l->vec.end()); i += l->vec.size(); continue; } - if (const auto *v = n->template to()) { + if (const auto *v = n->to()) { if (v->empty()) { i = erase(i); } else { @@ -111,7 +111,7 @@ void IR::Vector::visit_children(Visitor &v) { } continue; } - if (auto e = n->template to()) { + if (auto e = n->to()) { *i++ = e; continue; } @@ -232,7 +232,7 @@ template class MA void IR::NameMap::visit_children(Visitor &v) { map_t new_symbols; for (auto i = symbols.begin(); i != symbols.end();) { - auto n = v.apply_visitor(i->second, i->first); + const IR::Node *n = v.apply_visitor(i->second, i->first); if (!n && i->second) { i = symbols.erase(i); continue; @@ -242,12 +242,12 @@ void IR::NameMap::visit_children(Visitor &v) { i++; continue; } - if (auto m = n->template to()) { + if (auto m = n->to()) { namemap_insert_helper(i, m->symbols.begin(), m->symbols.end(), symbols, new_symbols); i = symbols.erase(i); continue; } - if (auto s = n->template to()) { + if (auto s = n->to()) { if (match_name(i->first, s)) { i->second = s; i++; diff --git a/ir/node.h b/ir/node.h index 43db1e5b526..6522c1f2747 100644 --- a/ir/node.h +++ b/ir/node.h @@ -48,16 +48,19 @@ class Vector; // IWYU pragma: keep template class IndexedVector; // IWYU pragma: keep -// node interface -class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable { - private: - template - struct has_static_type_name : std::false_type {}; +/// SFINAE helper to check if given class has a `static_type_name` +/// method. Definite node classes have them while interfaces do not +template +struct has_static_type_name : std::false_type {}; - template - struct has_static_type_name> : std::true_type { - }; +template +struct has_static_type_name> : std::true_type {}; +template +inline constexpr bool has_static_type_name_v = has_static_type_name::value; + +// node interface +class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable { public: virtual ~INode() {} virtual const Node *getNode() const = 0; @@ -71,16 +74,14 @@ class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable // default checkedTo implementation for nodes: just fallback to generic ICastable method template - const T *checkedTo( - typename std::enable_if_t::value> * = nullptr) const { + typename std::enable_if_t, const T *> checkedTo() const { return ICastable::checkedTo(); } - // alternative checkedTo implementation to produces slightly better error message + // alternative checkedTo implementation that produces slightly better error message // due to node_type_name() / static_type_name() being available template - const T *checkedTo( - typename std::enable_if_t::value> * = nullptr) const { + typename std::enable_if_t, const T *> checkedTo() const { const auto *result = to(); BUG_CHECK(result, "Cast failed: %1% with type %2% is not a %3%.", this, node_type_name(), T::static_type_name()); diff --git a/lib/castable.h b/lib/castable.h index b769672a96e..c5ca481e5d3 100644 --- a/lib/castable.h +++ b/lib/castable.h @@ -32,13 +32,13 @@ class ICastable { return to() != nullptr; } - /// Tries to convert the class to type T. Returns a nullptr if the cast fails. + /// Performs a checked cast. A BUG occurs if the cast fails. template const T &as() const { return dynamic_cast(*this); } - /// Tries to convert the class to type T. Returns a nullptr if the cast fails. + /// Performs a checked cast. A BUG occurs if the cast fails. template T &as() { return dynamic_cast(*this); From f5dd68a8eb941bffa8b5842c9e55a095c0a815c7 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Wed, 31 Jan 2024 03:41:02 -0800 Subject: [PATCH 4/4] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Vladimír Štill --- backends/p4tools/common/core/abstract_execution_state.cpp | 3 ++- ir/node.h | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/backends/p4tools/common/core/abstract_execution_state.cpp b/backends/p4tools/common/core/abstract_execution_state.cpp index d384adc0878..01dc9df8008 100644 --- a/backends/p4tools/common/core/abstract_execution_state.cpp +++ b/backends/p4tools/common/core/abstract_execution_state.cpp @@ -101,7 +101,8 @@ const IR::Expression *AbstractExecutionState::convertToComplexExpression( IR::Vector components; const auto *elementType = resolveType(ts->elementType); for (size_t idx = 0; idx < ts->getSize(); idx++) { - auto ref = new IR::ArrayIndex(elementType, parent, new IR::Constant(uint64_t(idx))); + auto ref = new IR::ArrayIndex(elementType, parent, + new IR::Constant(static_cast(idx))); if (elementType->is() || elementType->to()) { components.push_back(convertToComplexExpression(ref)); } else { diff --git a/ir/node.h b/ir/node.h index 6522c1f2747..44d2853d4d7 100644 --- a/ir/node.h +++ b/ir/node.h @@ -74,14 +74,14 @@ class INode : public Util::IHasSourceInfo, public IHasDbPrint, public ICastable // default checkedTo implementation for nodes: just fallback to generic ICastable method template - typename std::enable_if_t, const T *> checkedTo() const { + std::enable_if_t, const T *> checkedTo() const { return ICastable::checkedTo(); } // alternative checkedTo implementation that produces slightly better error message // due to node_type_name() / static_type_name() being available template - typename std::enable_if_t, const T *> checkedTo() const { + std::enable_if_t, const T *> checkedTo() const { const auto *result = to(); BUG_CHECK(result, "Cast failed: %1% with type %2% is not a %3%.", this, node_type_name(), T::static_type_name());