From f2e9be98e885a7e117b0cf4efdfed0eac748ea2d Mon Sep 17 00:00:00 2001 From: Fabian Ruffy <5960321+fruffy@users.noreply.github.com> Date: Thu, 6 Jun 2024 18:16:56 +0200 Subject: [PATCH 1/5] Fix a nullptr access in the DPDK back end. (#4712) * Fix a nullptr access in the DPDK back end. * Need to initialize metaCopyNeeded to false because of a flaw in key traversal. --- backends/dpdk/backend.cpp | 36 ++++++++++++++++++++++++------------ backends/dpdk/dpdkArch.cpp | 10 ++++++---- backends/dpdk/dpdkArch.h | 2 +- 3 files changed, 31 insertions(+), 17 deletions(-) diff --git a/backends/dpdk/backend.cpp b/backends/dpdk/backend.cpp index 01fe4e52bc..815a06c4e6 100644 --- a/backends/dpdk/backend.cpp +++ b/backends/dpdk/backend.cpp @@ -32,6 +32,7 @@ limitations under the License. #include "midend/eliminateTypedefs.h" #include "midend/removeComplexExpressions.h" #include "midend/simplifyKey.h" + namespace DPDK { void DpdkBackend::convert(const IR::ToplevelBlock *tlb) { @@ -129,29 +130,40 @@ void DpdkBackend::convert(const IR::ToplevelBlock *tlb) { }; simplify.addDebugHook(hook, true); program = program->apply(simplify); - ordered_set used_fields; + if (errorCount() > 0) { + return; + } + dpdk_program = convertToDpdk->getDpdkProgram(); - if (!dpdk_program) return; + if (dpdk_program == nullptr) { + return; + } + + PassManager postCodeGen; + ordered_map newNameMap; + ordered_set usedFields; if (structure.p4arch == "pna") { - PassManager post_code_gen = { + postCodeGen.addPasses({ new PrependPassRecircId(), new DirectionToRegRead(), - }; - dpdk_program = dpdk_program->apply(post_code_gen)->to(); + }); } - ordered_map newNameMap; - PassManager post_code_gen = { + postCodeGen.addPasses({ new EliminateUnusedAction(), new DpdkAsmOptimization, new CopyPropagationAndElimination(typeMap), - new CollectUsedMetadataField(used_fields), - new RemoveUnusedMetadataFields(used_fields), + new CollectUsedMetadataField(usedFields), + new RemoveUnusedMetadataFields(usedFields), new ShortenTokenLength(newNameMap), new EmitDpdkTableConfig(refMap, typeMap, newNameMap), - }; - - dpdk_program = dpdk_program->apply(post_code_gen)->to(); + }); + const auto *optimizedProgram = dpdk_program->apply(postCodeGen); + if (errorCount() > 0) { + return; + } + dpdk_program = optimizedProgram->to(); } void DpdkBackend::codegen(std::ostream &out) const { dpdk_program->toSpec(out) << std::endl; } + } // namespace DPDK diff --git a/backends/dpdk/dpdkArch.cpp b/backends/dpdk/dpdkArch.cpp index 0d45e49d11..2fa91d69d1 100644 --- a/backends/dpdk/dpdkArch.cpp +++ b/backends/dpdk/dpdkArch.cpp @@ -1566,6 +1566,11 @@ cstring CopyMatchKeysToSingleStruct::getTableKeyName(const IR::Expression *e) { } const IR::Node *CopyMatchKeysToSingleStruct::preorder(IR::Key *keys) { + // If copyNeeded is false at this point, it means the keys are from same struct. + // Check remaining conditions to see if the copy is needed or not + // TODO: This indirection should not be needed. Instead of using a visitor for IR::KeyElement + // just resolve each key element directly. + metaCopyNeeded = false; // If any key field is from different structure, put all keys in metadata LOG3("Visiting " << keys); bool copyNeeded = false; @@ -1645,10 +1650,6 @@ const IR::Node *CopyMatchKeysToSingleStruct::preorder(IR::Key *keys) { } else { structure->table_type_map.emplace(table->name.name, InternalTableType::WILDCARD); } - - // If copyNeeded is false at this point, it means the keys are from same struct. - // Check remaining conditions to see if the copy is needed or not - metaCopyNeeded = false; if (copyNeeded) contiguous = false; if (!contiguous && @@ -1670,6 +1671,7 @@ const IR::Node *CopyMatchKeysToSingleStruct::preorder(IR::Key *keys) { } return keys; } + const IR::Node *CopyMatchKeysToSingleStruct::postorder(IR::KeyElement *element) { // If we got here we need to put the key element in metadata. LOG3("Extracting key element " << element); diff --git a/backends/dpdk/dpdkArch.h b/backends/dpdk/dpdkArch.h index 26dd960e1f..856d023461 100644 --- a/backends/dpdk/dpdkArch.h +++ b/backends/dpdk/dpdkArch.h @@ -826,7 +826,7 @@ struct keyInfo { class CopyMatchKeysToSingleStruct : public P4::KeySideEffect { IR::IndexedVector decls; DpdkProgramStructure *structure; - bool metaCopyNeeded; + bool metaCopyNeeded = false; public: CopyMatchKeysToSingleStruct(P4::ReferenceMap *refMap, P4::TypeMap *typeMap, From c3c24015fb947287edef938497f251e05d9f8864 Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Thu, 6 Jun 2024 13:03:27 -0700 Subject: [PATCH 2/5] Get rid of implicit char* => cstring conversions (#4694) * Switch to explicit cstring literals * Get rid of implicit char* => cstring conversion. The amount of changes effectively shows how often this was misused. * Unbreak bazel * Allocate string cache data from non-GC arena * Address review comments * Address review feedback --- backends/bmv2/common/JsonObjects.cpp | 226 ++++++------- backends/bmv2/common/action.cpp | 36 +- backends/bmv2/common/annotations.h | 16 +- backends/bmv2/common/backend.h | 7 +- backends/bmv2/common/control.h | 202 +++++------ backends/bmv2/common/controlFlowGraph.cpp | 6 +- backends/bmv2/common/deparser.cpp | 16 +- backends/bmv2/common/deparser.h | 2 +- backends/bmv2/common/expression.cpp | 316 +++++++++--------- backends/bmv2/common/extern.cpp | 75 ++--- backends/bmv2/common/extern.h | 40 +-- backends/bmv2/common/header.cpp | 6 +- backends/bmv2/common/helpers.cpp | 54 +-- backends/bmv2/common/helpers.h | 66 ++-- backends/bmv2/common/midend.h | 2 +- backends/bmv2/common/options.h | 4 +- backends/bmv2/common/parser.cpp | 112 +++---- backends/bmv2/common/parser.h | 2 +- .../bmv2/common/sharedActionSelectorCheck.h | 2 +- backends/bmv2/psa_switch/main.cpp | 2 +- backends/bmv2/psa_switch/midend.cpp | 15 +- backends/bmv2/psa_switch/options.cpp | 4 +- .../bmv2/psa_switch/psaProgramStructure.cpp | 30 +- backends/bmv2/psa_switch/psaSwitch.cpp | 316 +++++++++--------- backends/bmv2/psa_switch/psaSwitch.h | 16 +- backends/bmv2/simple_switch/main.cpp | 2 +- backends/bmv2/simple_switch/midend.cpp | 15 +- backends/bmv2/simple_switch/simpleSwitch.cpp | 248 +++++++------- backends/bmv2/simple_switch/simpleSwitch.h | 12 +- backends/dpdk/constants.h | 5 +- .../control-plane/bfruntime_arch_handler.h | 18 +- backends/dpdk/control-plane/bfruntime_ext.cpp | 97 +++--- backends/dpdk/dpdk.def | 44 +-- backends/dpdk/dpdkArch.cpp | 111 +++--- backends/dpdk/dpdkArch.h | 17 +- backends/dpdk/dpdkAsmOpt.cpp | 10 +- backends/dpdk/dpdkAsmOpt.h | 15 +- backends/dpdk/dpdkCheckExternInvocation.h | 25 +- backends/dpdk/dpdkContext.cpp | 174 +++++----- backends/dpdk/dpdkContext.h | 13 +- backends/dpdk/dpdkHelpers.cpp | 39 ++- backends/dpdk/dpdkMetadata.cpp | 4 +- backends/dpdk/dpdkProgram.cpp | 29 +- backends/dpdk/dpdkProgram.h | 4 +- backends/dpdk/dpdkProgramStructure.cpp | 51 +-- backends/dpdk/dpdkProgramStructure.h | 8 +- backends/dpdk/dpdkUtils.cpp | 13 +- backends/dpdk/dpdkUtils.h | 2 +- backends/dpdk/main.cpp | 8 +- backends/dpdk/midend.cpp | 42 +-- backends/dpdk/options.cpp | 10 +- backends/dpdk/options.h | 20 +- backends/dpdk/spec.cpp | 22 +- backends/dpdk/tdiConf.cpp | 10 +- backends/ebpf/codeGen.cpp | 22 +- backends/ebpf/ebpfControl.cpp | 13 +- backends/ebpf/ebpfDeparser.cpp | 14 +- backends/ebpf/ebpfModel.cpp | 2 +- backends/ebpf/ebpfModel.h | 32 +- backends/ebpf/ebpfOptions.cpp | 4 +- backends/ebpf/ebpfParser.cpp | 2 +- backends/ebpf/ebpfProgram.cpp | 18 +- backends/ebpf/ebpfProgram.h | 26 +- backends/ebpf/ebpfTable.cpp | 37 +- backends/ebpf/ebpfTable.h | 2 +- backends/ebpf/ebpfType.cpp | 17 +- backends/ebpf/midend.cpp | 10 +- backends/ebpf/p4c-ebpf.cpp | 2 +- backends/ebpf/psa/ebpfPipeline.cpp | 16 +- backends/ebpf/psa/ebpfPipeline.h | 50 +-- backends/ebpf/psa/ebpfPsaDeparser.cpp | 8 +- backends/ebpf/psa/ebpfPsaGen.cpp | 109 +++--- backends/ebpf/psa/ebpfPsaTable.cpp | 46 +-- backends/ebpf/psa/ebpfPsaTable.h | 6 +- backends/ebpf/psa/externs/ebpfPsaCounter.cpp | 4 +- backends/ebpf/psa/externs/ebpfPsaDigest.cpp | 2 +- .../ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp | 8 +- .../ebpf/psa/externs/ebpfPsaHashAlgorithm.h | 16 +- backends/ebpf/psa/externs/ebpfPsaMeter.cpp | 45 +-- backends/ebpf/psa/externs/ebpfPsaMeter.h | 4 +- .../externs/ebpfPsaTableImplementation.cpp | 25 +- backends/ebpf/psa/xdpHelpProgram.h | 10 +- backends/ebpf/target.cpp | 33 +- backends/ebpf/target.h | 74 ++-- backends/graphs/controls.cpp | 15 +- backends/graphs/graph_visitor.cpp | 50 +-- backends/graphs/graphs.cpp | 4 +- backends/graphs/graphs.h | 39 ++- backends/graphs/p4c-graphs.cpp | 6 +- backends/graphs/parsers.cpp | 12 +- backends/p4test/midend.cpp | 2 +- backends/p4test/p4test.cpp | 4 +- .../p4tools/common/compiler/reachability.cpp | 4 +- .../p4tools/common/compiler/reachability.h | 2 +- .../control_plane/symbolic_variables.cpp | 4 +- backends/p4tools/common/lib/table_utils.cpp | 10 +- backends/p4tools/common/lib/taint.cpp | 2 +- backends/p4tools/common/lib/util.cpp | 8 +- backends/p4tools/common/lib/util.h | 2 +- backends/p4tools/common/lib/variables.h | 4 +- backends/p4tools/common/options.cpp | 4 +- backends/p4tools/common/options.h | 2 +- .../core/small_step/abstract_stepper.cpp | 2 +- .../testgen/core/small_step/cmd_stepper.cpp | 24 +- .../testgen/core/small_step/expr_stepper.cpp | 2 +- .../core/small_step/extern_stepper.cpp | 86 ++--- .../testgen/core/small_step/table_stepper.cpp | 20 +- .../modules/testgen/lib/execution_state.cpp | 16 +- .../modules/testgen/lib/packet_vars.cpp | 4 +- .../modules/testgen/lib/test_backend.cpp | 14 +- .../modules/testgen/lib/test_framework.h | 11 +- .../p4tools/modules/testgen/lib/test_spec.cpp | 18 +- backends/p4tools/modules/testgen/options.cpp | 18 +- .../testgen/targets/bmv2/cmd_stepper.cpp | 6 +- .../modules/testgen/targets/bmv2/concolic.cpp | 14 +- .../testgen/targets/bmv2/expr_stepper.cpp | 218 ++++++------ .../targets/bmv2/map_direct_externs.cpp | 2 +- .../targets/bmv2/p4_asserts_parser.cpp | 21 +- .../targets/bmv2/p4_refers_to_parser.cpp | 22 +- .../targets/bmv2/p4runtime_translation.cpp | 4 +- .../targets/bmv2/p4runtime_translation.h | 2 + .../testgen/targets/bmv2/program_info.cpp | 46 +-- .../testgen/targets/bmv2/table_stepper.cpp | 27 +- .../modules/testgen/targets/bmv2/target.cpp | 2 +- .../small-step/p4_asserts_parser_test.cpp | 28 +- .../bmv2/test/small-step/reachability.cpp | 16 +- .../targets/bmv2/test/test_backend/ptf.cpp | 56 ++-- .../targets/bmv2/test/test_backend/stf.cpp | 56 ++-- .../bmv2/test/testgen_api/api_test.cpp | 12 +- .../bmv2/test/testgen_api/benchmark.cpp | 10 +- .../testgen_api/control_plane_filter_test.cpp | 17 +- .../test/testgen_api/output_option_test.cpp | 10 +- .../transformations/saturation_arithm.cpp | 4 +- .../bmv2/test/z3-solver/asrt_model.cpp | 4 +- .../bmv2/test/z3-solver/expressions.cpp | 4 +- .../testgen/targets/bmv2/test_backend.cpp | 25 +- .../targets/bmv2/test_backend/common.cpp | 2 +- .../targets/bmv2/test_backend/metadata.cpp | 2 +- .../targets/bmv2/test_backend/protobuf.cpp | 6 +- .../targets/bmv2/test_backend/protobuf_ir.cpp | 10 +- .../testgen/targets/bmv2/test_backend/ptf.cpp | 4 +- .../testgen/targets/bmv2/test_backend/stf.cpp | 2 +- .../testgen/targets/bmv2/test_spec.cpp | 20 +- .../testgen/targets/ebpf/backend/stf/stf.cpp | 2 +- .../testgen/targets/ebpf/expr_stepper.cpp | 22 +- .../testgen/targets/ebpf/program_info.cpp | 10 +- .../testgen/targets/ebpf/test_backend.cpp | 4 +- .../targets/pna/backend/metadata/metadata.cpp | 2 +- .../testgen/targets/pna/backend/ptf/ptf.cpp | 2 +- .../modules/testgen/targets/pna/constants.cpp | 4 +- .../testgen/targets/pna/dpdk/program_info.cpp | 59 ++-- .../targets/pna/shared_expr_stepper.cpp | 20 +- .../targets/pna/shared_table_stepper.cpp | 27 +- .../testgen/targets/pna/test_backend.cpp | 17 +- .../modules/testgen/targets/pna/test_spec.cpp | 14 +- .../modules/testgen/test/small-step/util.h | 6 +- .../testgen/test/z3-solver/constraints.cpp | 37 +- backends/p4tools/modules/testgen/testgen.cpp | 4 +- backends/p4tools/p4tools.def | 14 +- backends/tc/backend.cpp | 66 ++-- backends/tc/backend.h | 2 +- backends/tc/ebpfCodeGen.cpp | 76 ++--- backends/tc/ebpfCodeGen.h | 19 +- backends/tc/introspection.cpp | 94 +++--- backends/tc/introspection.h | 4 +- backends/tc/midend.cpp | 2 +- backends/tc/options.h | 6 +- backends/tc/pnaProgramStructure.cpp | 8 +- backends/tc/tc.def | 12 +- backends/tc/tcAnnotations.cpp | 32 +- backends/ubpf/midend.cpp | 2 +- backends/ubpf/p4c-ubpf.cpp | 2 +- backends/ubpf/target.cpp | 6 +- backends/ubpf/target.h | 20 +- backends/ubpf/ubpfControl.cpp | 8 +- backends/ubpf/ubpfDeparser.cpp | 8 +- backends/ubpf/ubpfModel.cpp | 2 +- backends/ubpf/ubpfModel.h | 39 ++- backends/ubpf/ubpfParser.cpp | 2 +- backends/ubpf/ubpfProgram.cpp | 4 +- backends/ubpf/ubpfProgram.h | 6 +- backends/ubpf/ubpfRegister.cpp | 4 +- backends/ubpf/ubpfTable.cpp | 10 +- backends/ubpf/ubpfType.cpp | 22 +- bazel/example/main.cc | 4 +- control-plane/bfruntime.cpp | 263 +++++++-------- control-plane/bfruntime.h | 65 ++-- control-plane/flattenHeader.cpp | 9 +- control-plane/flattenHeader.h | 2 +- control-plane/p4RuntimeAnnotations.h | 20 +- control-plane/p4RuntimeArchHandler.cpp | 2 +- control-plane/p4RuntimeArchHandler.h | 11 +- control-plane/p4RuntimeArchStandard.h | 122 +++---- control-plane/p4RuntimeSerializer.cpp | 76 ++--- control-plane/p4RuntimeSerializer.h | 4 +- control-plane/p4RuntimeSymbolTable.cpp | 6 +- control-plane/typeSpecConverter.cpp | 2 +- frontends/common/applyOptionsPragmas.cpp | 6 +- frontends/common/constantFolding.h | 4 +- frontends/common/options.cpp | 21 +- frontends/common/parser_options.cpp | 41 +-- frontends/common/parser_options.h | 6 +- frontends/common/programMap.h | 2 +- .../common/resolveReferences/referenceMap.cpp | 26 +- .../common/resolveReferences/referenceMap.h | 6 +- frontends/p4-14/header_type.cpp | 10 +- frontends/p4-14/typecheck.cpp | 6 +- frontends/p4/actionsInlining.cpp | 2 +- frontends/p4/alias.h | 4 +- frontends/p4/callGraph.cpp | 3 +- frontends/p4/callGraph.h | 2 +- frontends/p4/commonInlining.h | 4 +- frontends/p4/coreLibrary.h | 24 +- frontends/p4/createBuiltins.cpp | 4 +- frontends/p4/def_use.cpp | 6 +- frontends/p4/deprecated.cpp | 6 +- frontends/p4/entryPriorities.cpp | 4 +- frontends/p4/fromv1.0/converters.cpp | 18 +- frontends/p4/fromv1.0/converters.h | 36 +- frontends/p4/fromv1.0/programStructure.cpp | 34 +- frontends/p4/fromv1.0/v1model.h | 175 +++++----- frontends/p4/frontend.cpp | 2 +- frontends/p4/functionsInlining.cpp | 2 +- frontends/p4/hierarchicalNames.cpp | 2 +- frontends/p4/inlining.cpp | 10 +- frontends/p4/localizeActions.cpp | 8 +- frontends/p4/moveDeclarations.cpp | 2 +- frontends/p4/parseAnnotations.cpp | 2 +- frontends/p4/reassociation.h | 4 +- frontends/p4/removeReturns.cpp | 8 +- frontends/p4/removeReturns.h | 5 +- frontends/p4/reservedWords.cpp | 23 +- frontends/p4/reservedWords.h | 2 +- frontends/p4/simplifyDefUse.cpp | 10 +- frontends/p4/specialize.cpp | 6 +- frontends/p4/specializeGenericFunctions.h | 2 +- frontends/p4/specializeGenericTypes.cpp | 2 +- frontends/p4/staticAssert.h | 9 +- frontends/p4/strengthReduction.h | 4 +- frontends/p4/symbol_table.cpp | 17 +- frontends/p4/tableKeyNames.cpp | 11 +- frontends/p4/ternaryBool.cpp | 12 +- frontends/p4/toP4/toP4.cpp | 12 +- frontends/p4/typeChecking/typeChecker.cpp | 17 +- frontends/p4/typeChecking/typeChecker.h | 6 +- frontends/p4/typeChecking/typeConstraints.h | 4 +- .../p4/typeChecking/typeSubstitution.cpp | 14 +- frontends/p4/typeChecking/typeUnification.cpp | 4 +- frontends/p4/uniqueNames.h | 4 +- frontends/p4/validateParsedProgram.h | 4 +- frontends/parsers/p4/p4lexer.ll | 22 +- frontends/parsers/p4/p4parser.ypp | 49 +-- frontends/parsers/parserDriver.cpp | 4 +- frontends/parsers/v1/v1lexer.ll | 36 +- frontends/parsers/v1/v1parser.ypp | 8 +- ir/base.cpp | 4 +- ir/base.def | 10 +- ir/dump.cpp | 10 +- ir/expression.def | 26 +- ir/id.h | 6 +- ir/ir.cpp | 26 +- ir/ir.def | 18 +- ir/irutils.cpp | 4 +- ir/loop-visitor.cpp | 16 +- ir/namemap.h | 2 +- ir/node.cpp | 16 +- ir/node.h | 6 +- ir/type.cpp | 58 ++-- ir/type.def | 78 ++--- ir/v1.cpp | 118 +++---- ir/v1.def | 18 +- ir/visitor.cpp | 4 +- ir/visitor.h | 2 +- lib/cstring.cpp | 31 +- lib/cstring.h | 35 +- lib/error.h | 2 +- lib/error_catalog.cpp | 89 ++--- lib/error_catalog.h | 10 +- lib/error_reporter.h | 12 +- lib/json.cpp | 6 +- lib/json.h | 2 +- lib/nullstream.cpp | 1 + lib/options.cpp | 8 +- lib/options.h | 3 +- lib/path.cpp | 2 +- lib/path.h | 7 +- lib/sourceCodeBuilder.h | 4 + lib/source_file.cpp | 28 +- lib/source_file.h | 10 +- midend/actionSynthesis.cpp | 12 +- midend/def_use.cpp | 7 +- midend/eliminateTuples.cpp | 6 +- midend/expr_uses.h | 4 +- midend/flattenHeaders.cpp | 5 +- midend/flattenInterfaceStructs.cpp | 5 +- midend/flattenInterfaceStructs.h | 5 +- midend/global_copyprop.cpp | 4 +- midend/interpreter.h | 4 +- midend/local_copyprop.cpp | 21 +- midend/nestedStructs.cpp | 11 +- midend/parserUnroll.h | 4 +- midend/removeExits.cpp | 2 +- midend/removeExits.h | 2 +- midend/simplifySelectList.cpp | 4 +- midend/simplifySelectList.h | 1 + test/gtest/constant_folding.cpp | 8 +- test/gtest/cstring.cpp | 37 +- test/gtest/equiv_test.cpp | 20 +- test/gtest/expr_uses_test.cpp | 28 +- test/gtest/format_test.cpp | 8 +- test/gtest/indexed_vector.cpp | 18 +- test/gtest/json_test.cpp | 4 +- test/gtest/midend_pass.cpp | 2 +- test/gtest/p4runtime.cpp | 135 ++++---- test/gtest/parser_unroll.cpp | 2 +- test/gtest/path_test.cpp | 6 +- tools/ir-generator/generator.cpp | 6 +- tools/ir-generator/ir-generator-lex.l | 20 +- tools/ir-generator/ir-generator.ypp | 39 ++- tools/ir-generator/irclass.cpp | 47 +-- tools/ir-generator/irclass.h | 8 +- tools/ir-generator/methods.cpp | 52 +-- tools/ir-generator/type.cpp | 36 +- tools/ir-generator/type.h | 8 +- 324 files changed, 3998 insertions(+), 3657 deletions(-) diff --git a/backends/bmv2/common/JsonObjects.cpp b/backends/bmv2/common/JsonObjects.cpp index 18c2ead837..9b81a5e6df 100644 --- a/backends/bmv2/common/JsonObjects.cpp +++ b/backends/bmv2/common/JsonObjects.cpp @@ -27,37 +27,37 @@ const int JSON_MINOR_VERSION = 23; JsonObjects::JsonObjects() { toplevel = new Util::JsonObject(); meta = new Util::JsonObject(); - header_types = insert_array_field(toplevel, "header_types"); - headers = insert_array_field(toplevel, "headers"); - header_stacks = insert_array_field(toplevel, "header_stacks"); - header_union_types = insert_array_field(toplevel, "header_union_types"); - header_unions = insert_array_field(toplevel, "header_unions"); - header_union_stacks = insert_array_field(toplevel, "header_union_stacks"); - field_lists = insert_array_field(toplevel, "field_lists"); - errors = insert_array_field(toplevel, "errors"); - enums = insert_array_field(toplevel, "enums"); - parsers = insert_array_field(toplevel, "parsers"); - parse_vsets = insert_array_field(toplevel, "parse_vsets"); - deparsers = insert_array_field(toplevel, "deparsers"); - meter_arrays = insert_array_field(toplevel, "meter_arrays"); - counters = insert_array_field(toplevel, "counter_arrays"); - register_arrays = insert_array_field(toplevel, "register_arrays"); - calculations = insert_array_field(toplevel, "calculations"); - learn_lists = insert_array_field(toplevel, "learn_lists"); - actions = insert_array_field(toplevel, "actions"); - pipelines = insert_array_field(toplevel, "pipelines"); - checksums = insert_array_field(toplevel, "checksums"); - force_arith = insert_array_field(toplevel, "force_arith"); - externs = insert_array_field(toplevel, "extern_instances"); - field_aliases = insert_array_field(toplevel, "field_aliases"); + header_types = insert_array_field(toplevel, "header_types"_cs); + headers = insert_array_field(toplevel, "headers"_cs); + header_stacks = insert_array_field(toplevel, "header_stacks"_cs); + header_union_types = insert_array_field(toplevel, "header_union_types"_cs); + header_unions = insert_array_field(toplevel, "header_unions"_cs); + header_union_stacks = insert_array_field(toplevel, "header_union_stacks"_cs); + field_lists = insert_array_field(toplevel, "field_lists"_cs); + errors = insert_array_field(toplevel, "errors"_cs); + enums = insert_array_field(toplevel, "enums"_cs); + parsers = insert_array_field(toplevel, "parsers"_cs); + parse_vsets = insert_array_field(toplevel, "parse_vsets"_cs); + deparsers = insert_array_field(toplevel, "deparsers"_cs); + meter_arrays = insert_array_field(toplevel, "meter_arrays"_cs); + counters = insert_array_field(toplevel, "counter_arrays"_cs); + register_arrays = insert_array_field(toplevel, "register_arrays"_cs); + calculations = insert_array_field(toplevel, "calculations"_cs); + learn_lists = insert_array_field(toplevel, "learn_lists"_cs); + actions = insert_array_field(toplevel, "actions"_cs); + pipelines = insert_array_field(toplevel, "pipelines"_cs); + checksums = insert_array_field(toplevel, "checksums"_cs); + force_arith = insert_array_field(toplevel, "force_arith"_cs); + externs = insert_array_field(toplevel, "extern_instances"_cs); + field_aliases = insert_array_field(toplevel, "field_aliases"_cs); } Util::JsonArray *JsonObjects::get_field_list_contents(unsigned id) const { for (auto e : *field_lists) { auto obj = e->to(); - auto val = obj->get("id")->to(); + auto val = obj->get("id"_cs)->to(); if (val != nullptr && val->isNumber() && val->getInt() == static_cast(id)) { - return obj->get("elements")->to(); + return obj->get("elements"_cs)->to(); } } return nullptr; @@ -66,7 +66,7 @@ Util::JsonArray *JsonObjects::get_field_list_contents(unsigned id) const { Util::JsonObject *JsonObjects::find_object_by_name(Util::JsonArray *array, const cstring &name) { for (auto e : *array) { auto obj = e->to(); - auto val = obj->get("name")->to(); + auto val = obj->get("name"_cs)->to(); if (val != nullptr && val->isString() && val->getString() == name) { return obj; } @@ -87,19 +87,19 @@ Util::JsonArray *JsonObjects::append_array(Util::JsonArray *parent) { } Util::JsonArray *JsonObjects::create_parameters(Util::JsonObject *object) { - return insert_array_field(object, "parameters"); + return insert_array_field(object, "parameters"_cs); } -void JsonObjects::add_program_info(const cstring &name) { toplevel->emplace("program", name); } +void JsonObjects::add_program_info(const cstring &name) { toplevel->emplace("program"_cs, name); } void JsonObjects::add_meta_info() { static constexpr int version_major = JSON_MAJOR_VERSION; static constexpr int version_minor = JSON_MINOR_VERSION; - auto version = insert_array_field(meta, "version"); + auto version = insert_array_field(meta, "version"_cs); version->append(version_major); version->append(version_minor); - meta->emplace("compiler", "https://github.com/p4lang/p4c"); - toplevel->emplace("__meta__", meta); + meta->emplace("compiler"_cs, "https://github.com/p4lang/p4c"); + toplevel->emplace("__meta__"_cs, meta); } /// Create a header type in json. /// @param name header name @@ -115,17 +115,17 @@ unsigned JsonObjects::add_header_type(const cstring &name, Util::JsonArray *&fie return header_type_id_it->second; } auto header_type = new Util::JsonObject(); - unsigned id = BMV2::nextId("header_types"); + unsigned id = BMV2::nextId("header_types"_cs); header_type_id[sname] = id; - header_type->emplace("name", name); - header_type->emplace("id", id); + header_type->emplace("name"_cs, name); + header_type->emplace("id"_cs, id); if (fields != nullptr) { - header_type->emplace("fields", fields); + header_type->emplace("fields"_cs, fields); } else { auto temp = new Util::JsonArray(); - header_type->emplace("fields", temp); + header_type->emplace("fields"_cs, temp); } - if (max_length > 0) header_type->emplace("max_length", max_length); + if (max_length > 0) header_type->emplace("max_length"_cs, max_length); header_types->append(header_type); return id; } @@ -135,15 +135,15 @@ unsigned JsonObjects::add_union_type(const cstring &name, Util::JsonArray *&fiel auto it = union_type_id.find(sname); if (it != union_type_id.end()) return it->second; auto union_type = new Util::JsonObject(); - unsigned id = BMV2::nextId("header_union_types"); + unsigned id = BMV2::nextId("header_union_types"_cs); union_type_id[sname] = id; - union_type->emplace("name", name); - union_type->emplace("id", id); + union_type->emplace("name"_cs, name); + union_type->emplace("id"_cs, id); if (fields != nullptr) { - union_type->emplace("headers", fields); + union_type->emplace("headers"_cs, fields); } else { auto temp = new Util::JsonArray(); - union_type->emplace("headers", temp); + union_type->emplace("headers"_cs, temp); } header_union_types->append(union_type); return id; @@ -156,12 +156,12 @@ unsigned JsonObjects::add_header_type(const cstring &name) { return header_type_id_it->second; } auto header_type = new Util::JsonObject(); - unsigned id = BMV2::nextId("header_types"); + unsigned id = BMV2::nextId("header_types"_cs); header_type_id[sname] = id; - header_type->emplace("name", name); - header_type->emplace("id", id); + header_type->emplace("name"_cs, name); + header_type->emplace("id"_cs, id); auto temp = new Util::JsonArray(); - header_type->emplace("fields", temp); + header_type->emplace("fields"_cs, temp); header_types->append(header_type); return id; } @@ -169,20 +169,20 @@ unsigned JsonObjects::add_header_type(const cstring &name) { void JsonObjects::add_header_field(const cstring &name, Util::JsonArray *&field) { CHECK_NULL(field); Util::JsonObject *headerType = find_object_by_name(header_types, name); - Util::JsonArray *fields = headerType->get("fields")->to(); + Util::JsonArray *fields = headerType->get("fields"_cs)->to(); BUG_CHECK(fields != nullptr, "header '%1%' not found", name); fields->append(field); } unsigned JsonObjects::add_header(const cstring &type, const cstring &name) { auto header = new Util::JsonObject(); - unsigned id = BMV2::nextId("headers"); + unsigned id = BMV2::nextId("headers"_cs); LOG1("add header id " << id); - header->emplace("name", name); - header->emplace("id", id); - header->emplace("header_type", type); - header->emplace("metadata", false); - header->emplace("pi_omit", true); + header->emplace("name"_cs, name); + header->emplace("id"_cs, id); + header->emplace("header_type"_cs, type); + header->emplace("metadata"_cs, false); + header->emplace("pi_omit"_cs, true); headers->append(header); return id; } @@ -190,26 +190,26 @@ unsigned JsonObjects::add_header(const cstring &type, const cstring &name) { unsigned JsonObjects::add_union(const cstring &type, Util::JsonArray *&headers, const cstring &name) { auto u = new Util::JsonObject(); - unsigned id = BMV2::nextId("header_unions"); + unsigned id = BMV2::nextId("header_unions"_cs); LOG3("add header_union id " << id); - u->emplace("name", name); - u->emplace("id", id); - u->emplace("union_type", type); - u->emplace("header_ids", headers); - u->emplace("pi_omit", true); + u->emplace("name"_cs, name); + u->emplace("id"_cs, id); + u->emplace("union_type"_cs, type); + u->emplace("header_ids"_cs, headers); + u->emplace("pi_omit"_cs, true); header_unions->append(u); return id; } unsigned JsonObjects::add_metadata(const cstring &type, const cstring &name) { auto header = new Util::JsonObject(); - unsigned id = BMV2::nextId("headers"); + unsigned id = BMV2::nextId("headers"_cs); LOG3("add metadata header id " << id); - header->emplace("name", name); - header->emplace("id", id); - header->emplace("header_type", type); - header->emplace("metadata", true); - header->emplace("pi_omit", true); // Don't expose in PI. + header->emplace("name"_cs, name); + header->emplace("id"_cs, id); + header->emplace("header_type"_cs, type); + header->emplace("metadata"_cs, true); + header->emplace("pi_omit"_cs, true); // Don't expose in PI. headers->append(header); return id; } @@ -217,13 +217,13 @@ unsigned JsonObjects::add_metadata(const cstring &type, const cstring &name) { void JsonObjects::add_header_stack(const cstring &type, const cstring &name, const unsigned size, const std::vector &ids) { auto stack = new Util::JsonObject(); - unsigned id = BMV2::nextId("stack"); - stack->emplace("name", name); - stack->emplace("id", id); - stack->emplace("header_type", type); - stack->emplace("size", size); + unsigned id = BMV2::nextId("stack"_cs); + stack->emplace("name"_cs, name); + stack->emplace("id"_cs, id); + stack->emplace("header_type"_cs, type); + stack->emplace("size"_cs, size); auto members = new Util::JsonArray(); - stack->emplace("header_ids", members); + stack->emplace("header_ids"_cs, members); for (auto id : ids) { members->append(id); } @@ -233,13 +233,13 @@ void JsonObjects::add_header_stack(const cstring &type, const cstring &name, con void JsonObjects::add_header_union_stack(const cstring &type, const cstring &name, const unsigned size, const std::vector &ids) { auto stack = new Util::JsonObject(); - unsigned id = BMV2::nextId("union_stack"); - stack->emplace("name", name); - stack->emplace("id", id); - stack->emplace("union_type", type); - stack->emplace("size", size); + unsigned id = BMV2::nextId("union_stack"_cs); + stack->emplace("name"_cs, name); + stack->emplace("id"_cs, id); + stack->emplace("union_type"_cs, type); + stack->emplace("size"_cs, size); auto members = new Util::JsonArray(); - stack->emplace("header_union_ids", members); + stack->emplace("header_union_ids"_cs, members); for (auto id : ids) { members->append(id); } @@ -258,8 +258,8 @@ void JsonObjects::add_enum(const cstring &enum_name, const cstring &entry_name, Util::JsonObject *enum_json = find_object_by_name(enums, enum_name); if (enum_json == nullptr) { // first entry in a new enum enum_json = new Util::JsonObject(); - enum_json->emplace("name", enum_name); - auto entries = insert_array_field(enum_json, "entries"); + enum_json->emplace("name"_cs, enum_name); + auto entries = insert_array_field(enum_json, "entries"_cs); auto entry = new Util::JsonArray(); entry->append(entry_name); entry->append(entry_value); @@ -267,7 +267,7 @@ void JsonObjects::add_enum(const cstring &enum_name, const cstring &entry_name, enums->append(enum_json); LOG3("new enum object: " << enum_name << " " << entry_name << " " << entry_value); } else { // add entry to existing enum - auto entries = enum_json->get("entries")->to(); + auto entries = enum_json->get("entries"_cs)->to(); auto entry = new Util::JsonArray(); entry->append(entry_name); entry->append(entry_value); @@ -278,12 +278,12 @@ void JsonObjects::add_enum(const cstring &enum_name, const cstring &entry_name, unsigned JsonObjects::add_parser(const cstring &name) { auto parser = new Util::JsonObject(); - unsigned id = BMV2::nextId("parser"); - parser->emplace("name", name); - parser->emplace("id", id); - parser->emplace("init_state", IR::ParserState::start); + unsigned id = BMV2::nextId("parser"_cs); + parser->emplace("name"_cs, name); + parser->emplace("id"_cs, id); + parser->emplace("init_state"_cs, IR::ParserState::start); auto parse_states = new Util::JsonArray(); - parser->emplace("parse_states", parse_states); + parser->emplace("parse_states"_cs, parse_states); parsers->append(parser); map_parser.emplace(id, parser); @@ -293,18 +293,18 @@ unsigned JsonObjects::add_parser(const cstring &name) { unsigned JsonObjects::add_parser_state(const unsigned parser_id, const cstring &state_name) { if (map_parser.find(parser_id) == map_parser.end()) BUG("parser %1% not found.", parser_id); auto parser = map_parser[parser_id]; - auto states = parser->get("parse_states")->to(); + auto states = parser->get("parse_states"_cs)->to(); auto state = new Util::JsonObject(); - unsigned state_id = BMV2::nextId("parse_states"); - state->emplace("name", state_name); - state->emplace("id", state_id); + unsigned state_id = BMV2::nextId("parse_states"_cs); + state->emplace("name"_cs, state_name); + state->emplace("id"_cs, state_id); auto operations = new Util::JsonArray(); - state->emplace("parser_ops", operations); + state->emplace("parser_ops"_cs, operations); auto transitions = new Util::JsonArray(); - state->emplace("transitions", transitions); + state->emplace("transitions"_cs, transitions); states->append(state); auto key = new Util::JsonArray(); - state->emplace("transition_key", key); + state->emplace("transition_key"_cs, key); map_parser_state.emplace(state_id, state); return state_id; @@ -314,7 +314,7 @@ void JsonObjects::add_parser_transition(const unsigned state_id, Util::IJson *tr if (map_parser_state.find(state_id) == map_parser_state.end()) BUG("parser state %1% not found.", state_id); auto state = map_parser_state[state_id]; - auto transitions = state->get("transitions")->to(); + auto transitions = state->get("transitions"_cs)->to(); CHECK_NULL(transitions); auto trans = transition->to(); CHECK_NULL(trans); @@ -325,7 +325,7 @@ void JsonObjects::add_parser_op(const unsigned state_id, Util::IJson *op) { if (map_parser_state.find(state_id) == map_parser_state.end()) BUG("parser state %1% not found.", state_id); auto state = map_parser_state[state_id]; - auto statements = state->get("parser_ops")->to(); + auto statements = state->get("parser_ops"_cs)->to(); CHECK_NULL(statements); statements->append(op); } @@ -333,7 +333,7 @@ void JsonObjects::add_parser_op(const unsigned state_id, Util::IJson *op) { void JsonObjects::add_parser_transition_key(const unsigned state_id, Util::IJson *newKey) { if (map_parser_state.find(state_id) != map_parser_state.end()) { auto state = map_parser_state[state_id]; - auto keys = state->get("transition_key")->to(); + auto keys = state->get("transition_key"_cs)->to(); CHECK_NULL(keys); auto new_keys = newKey->to(); for (auto k : *new_keys) { @@ -345,11 +345,11 @@ void JsonObjects::add_parser_transition_key(const unsigned state_id, Util::IJson void JsonObjects::add_parse_vset(const cstring &name, const unsigned bitwidth, const big_int &size) { auto parse_vset = new Util::JsonObject(); - unsigned id = BMV2::nextId("parse_vsets"); - parse_vset->emplace("name", name); - parse_vset->emplace("id", id); - parse_vset->emplace("compressed_bitwidth", bitwidth); - parse_vset->emplace("max_size", size); + unsigned id = BMV2::nextId("parse_vsets"_cs); + parse_vset->emplace("name"_cs, name); + parse_vset->emplace("id"_cs, id); + parse_vset->emplace("compressed_bitwidth"_cs, bitwidth); + parse_vset->emplace("max_size"_cs, size); parse_vsets->append(parse_vset); } @@ -358,11 +358,11 @@ unsigned JsonObjects::add_action(const cstring &name, Util::JsonArray *¶ms, CHECK_NULL(params); CHECK_NULL(body); auto action = new Util::JsonObject(); - action->emplace("name", name); - unsigned id = BMV2::nextId("actions"); - action->emplace("id", id); - action->emplace("runtime_data", params); - action->emplace("primitives", body); + action->emplace("name"_cs, name); + unsigned id = BMV2::nextId("actions"_cs); + action->emplace("id"_cs, id); + action->emplace("runtime_data"_cs, params); + action->emplace("primitives"_cs, body); actions->append(action); return id; } @@ -370,20 +370,20 @@ unsigned JsonObjects::add_action(const cstring &name, Util::JsonArray *¶ms, void JsonObjects::add_extern_attribute(const cstring &name, const cstring &type, const cstring &value, Util::JsonArray *attributes) { auto attr = new Util::JsonObject(); - attr->emplace("name", name); - attr->emplace("type", type); - attr->emplace("value", value); + attr->emplace("name"_cs, name); + attr->emplace("type"_cs, type); + attr->emplace("value"_cs, value); attributes->append(attr); } void JsonObjects::add_extern(const cstring &name, const cstring &type, Util::JsonArray *attributes) { auto extn = new Util::JsonObject(); - unsigned id = BMV2::nextId("extern_instances"); - extn->emplace("name", name); - extn->emplace("id", id); - extn->emplace("type", type); - extn->emplace("attribute_values", attributes); + unsigned id = BMV2::nextId("extern_instances"_cs); + extn->emplace("name"_cs, name); + extn->emplace("id"_cs, id); + extn->emplace("type"_cs, type); + extn->emplace("attribute_values"_cs, attributes); externs->append(extn); } diff --git a/backends/bmv2/common/action.cpp b/backends/bmv2/common/action.cpp index 82f1f17a45..41af3497cc 100644 --- a/backends/bmv2/common/action.cpp +++ b/backends/bmv2/common/action.cpp @@ -20,18 +20,20 @@ limitations under the License. namespace BMV2 { +using namespace P4::literals; + cstring ActionConverter::jsonAssignment(const IR::Type *type) { - if (type->is()) return "assign_VL"; - if (type->is()) return "assign_union"; - if (type->is() || type->is()) return "assign_header"; + if (type->is()) return "assign_VL"_cs; + if (type->is()) return "assign_union"_cs; + if (type->is() || type->is()) return "assign_header"_cs; if (auto ts = type->to()) { auto et = ts->elementType; if (et->is()) - return "assign_union_stack"; + return "assign_union_stack"_cs; else - return "assign_header_stack"; + return "assign_header_stack"_cs; } - return "assign"; + return "assign"_cs; } void ActionConverter::convertActionBody(const IR::Vector *body, @@ -98,9 +100,9 @@ void ActionConverter::convertActionBody(const IR::Vector *body, } else if (s->is()) { break; } else if (s->is()) { - auto primitive = mkPrimitive("exit", result); + auto primitive = mkPrimitive("exit"_cs, result); (void)mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); break; } else if (s->is()) { const IR::Expression *l, *r; @@ -111,7 +113,7 @@ void ActionConverter::convertActionBody(const IR::Vector *body, cstring operation = jsonAssignment(type); auto primitive = mkPrimitive(operation, result); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", assign->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, assign->sourceInfoJsonObj()); bool convertBool = type->is(); Util::IJson *left; if (ctxt->conv->isArrayIndexRuntime(l)) { @@ -141,25 +143,25 @@ void ActionConverter::convertActionBody(const IR::Vector *body, parameters->append(obj); if (builtin->name == IR::Type_Header::setValid) { - prim = "add_header"; + prim = "add_header"_cs; } else if (builtin->name == IR::Type_Header::setInvalid) { - prim = "remove_header"; + prim = "remove_header"_cs; } else if (builtin->name == IR::Type_Stack::push_front) { BUG_CHECK(mc->arguments->size() == 1, "Expected 1 argument for %1%", mc); auto arg = ctxt->conv->convert(mc->arguments->at(0)->expression); - prim = "push"; + prim = "push"_cs; parameters->append(arg); } else if (builtin->name == IR::Type_Stack::pop_front) { BUG_CHECK(mc->arguments->size() == 1, "Expected 1 argument for %1%", mc); auto arg = ctxt->conv->convert(mc->arguments->at(0)->expression); - prim = "pop"; + prim = "pop"_cs; parameters->append(arg); } else { BUG("%1%: Unexpected built-in method", s); } auto primitive = mkPrimitive(prim, result); - primitive->emplace("parameters", parameters); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace("parameters"_cs, parameters); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); continue; } else if (mi->is()) { auto em = mi->to(); @@ -190,14 +192,14 @@ void ActionConverter::convertActionParams(const IR::ParameterList *parameters, warn(ErrorType::WARN_UNUSED, "Unused action parameter %1%", p); auto param = new Util::JsonObject(); - param->emplace("name", p->externalName()); + param->emplace("name"_cs, p->externalName()); auto type = ctxt->typeMap->getType(p, true); // TODO: added IR::Type_Enum here to support PSA_MeterColor_t // should re-consider how to support action parameters that is neither bit<> nor int<> if (!(type->is() || type->is())) ::error(ErrorType::ERR_INVALID, "%1%: action parameters must be bit<> or int<> on this target", p); - param->emplace("bitwidth", type->width_bits()); + param->emplace("bitwidth"_cs, type->width_bits()); params->append(param); } } diff --git a/backends/bmv2/common/annotations.h b/backends/bmv2/common/annotations.h index dacea7f161..f2354d8268 100644 --- a/backends/bmv2/common/annotations.h +++ b/backends/bmv2/common/annotations.h @@ -22,18 +22,20 @@ limitations under the License. namespace BMV2 { +using namespace P4::literals; + /// Parses BMV2-specific annotations. class ParseAnnotations : public P4::ParseAnnotations { public: ParseAnnotations() - : P4::ParseAnnotations("BMV2", false, + : P4::ParseAnnotations("BMV2"_cs, false, { - PARSE_EMPTY("metadata"), - PARSE_EXPRESSION_LIST("field_list"), - PARSE("alias", StringLiteral), - PARSE("priority", Constant), - PARSE_EXPRESSION_LIST("p4runtime_translation_mappings"), - PARSE_P4RUNTIME_TRANSLATION("p4runtime_translation"), + PARSE_EMPTY("metadata"_cs), + PARSE_EXPRESSION_LIST("field_list"_cs), + PARSE("alias"_cs, StringLiteral), + PARSE("priority"_cs, Constant), + PARSE_EXPRESSION_LIST("p4runtime_translation_mappings"_cs), + PARSE_P4RUNTIME_TRANSLATION("p4runtime_translation"_cs), }) {} }; diff --git a/backends/bmv2/common/backend.h b/backends/bmv2/common/backend.h index 3593dd2dd3..4e4fd50c4a 100644 --- a/backends/bmv2/common/backend.h +++ b/backends/bmv2/common/backend.h @@ -24,6 +24,7 @@ limitations under the License. #include "frontends/p4/coreLibrary.h" #include "helpers.h" #include "ir/ir.h" +#include "lib/cstring.h" #include "lib/error.h" #include "lib/exceptions.h" #include "lib/gc.h" @@ -153,7 +154,7 @@ class RenameUserMetadata : public Transform { IR::IndexedVector fields; for (auto f : type->fields) { auto anno = f->getAnnotation(IR::Annotation::nameAnnotation); - cstring suffix = ""; + cstring suffix = cstring::empty; if (anno != nullptr) suffix = anno->getName(); if (suffix.startsWith(".")) { // We can't change the name of this field. @@ -163,9 +164,9 @@ class RenameUserMetadata : public Transform { } if (!suffix.isNullOrEmpty()) - suffix = cstring(".") + suffix; + suffix = "."_cs + suffix; else - suffix = cstring(".") + f->name; + suffix = "."_cs + f->name; cstring newName = namePrefix + suffix; auto stringLit = new IR::StringLiteral(newName); LOG2("Renaming " << f << " to " << newName); diff --git a/backends/bmv2/common/control.h b/backends/bmv2/common/control.h index f35835564d..f43d9ac36a 100644 --- a/backends/bmv2/common/control.h +++ b/backends/bmv2/common/control.h @@ -48,12 +48,12 @@ class ControlConverter : public Inspector { LOG3("Processing " << dbp(table)); auto result = new Util::JsonObject(); cstring name = table->controlPlaneName(); - result->emplace("name", name); - result->emplace("id", nextId("tables")); - result->emplace_non_null("source_info", table->sourceInfoJsonObj()); + result->emplace("name"_cs, name); + result->emplace("id"_cs, nextId("tables"_cs)); + result->emplace_non_null("source_info"_cs, table->sourceInfoJsonObj()); cstring table_match_type = corelib.exactMatch.name; auto key = table->getKey(); - auto tkey = mkArrayField(result, "key"); + auto tkey = mkArrayField(result, "key"_cs); ctxt->conv->simpleExpressionsOnly = true; if (key != nullptr) { @@ -115,9 +115,9 @@ class ControlConverter : public Inspector { // represented in the BMv2 JSON file the same as a ternary // field would be. if (match_type == BMV2::MatchImplementation::optionalMatchTypeName) { - keyelement->emplace("match_type", corelib.ternaryMatch.name); + keyelement->emplace("match_type"_cs, corelib.ternaryMatch.name); } else { - keyelement->emplace("match_type", match_type); + keyelement->emplace("match_type"_cs, match_type); } if (auto na = ke->getAnnotation(IR::Annotation::nameAnnotation)) { BUG_CHECK(na->expr.size() == 1, "%1%: expected 1 name", na); @@ -125,21 +125,21 @@ class ControlConverter : public Inspector { BUG_CHECK(name != nullptr, "%1%: expected a string", na); // This is a BMv2 JSON extension: specify a // control-plane name for this key - keyelement->emplace("name", name->value); + keyelement->emplace("name"_cs, name->value); } auto jk = ctxt->conv->convert(expr); - keyelement->emplace("target", jk->to()->get("value")); + keyelement->emplace("target"_cs, jk->to()->get("value"_cs)); if (mask != 0) - keyelement->emplace("mask", + keyelement->emplace("mask"_cs, stringRepr(mask, ROUNDUP(expr->type->width_bits(), 8))); else - keyelement->emplace("mask", Util::JsonValue::null); + keyelement->emplace("mask"_cs, Util::JsonValue::null); tkey->append(keyelement); } } LOG3("table_match_type: " << table_match_type); - result->emplace("match_type", table_match_type); + result->emplace("match_type"_cs, table_match_type); ctxt->conv->simpleExpressionsOnly = false; auto propertyName = Standard::ActionProfileTraits::propertyName(); @@ -147,7 +147,7 @@ class ControlConverter : public Inspector { bool simple = handleTableImplementation(impl, key, result, action_profiles, selector_check); unsigned size = 0; - auto sz = table->properties->getProperty("size"); + auto sz = table->properties->getProperty("size"_cs); if (sz != nullptr) { if (sz->value->is()) { auto expr = sz->value->to()->expression; @@ -166,8 +166,8 @@ class ControlConverter : public Inspector { } if (size == 0) size = BMV2::TableAttributes::defaultTableSize; - result->emplace("max_size", size); - auto ctrs = table->properties->getProperty("counters"); + result->emplace("max_size"_cs, size); + auto ctrs = table->properties->getProperty("counters"_cs); if (ctrs != nullptr) { // The counters attribute should list the counters of the table, accessed in // actions of the table. We should be checking that this attribute and the @@ -193,15 +193,15 @@ class ControlConverter : public Inspector { return result; } auto jctr = new Util::JsonObject(); - cstring ctrname = ctrs->controlPlaneName("counter"); - jctr->emplace("name", ctrname); - jctr->emplace("id", nextId("counter_arrays")); - jctr->emplace_non_null("source_info", ctrs->sourceInfoJsonObj()); + cstring ctrname = ctrs->controlPlaneName("counter"_cs); + jctr->emplace("name"_cs, ctrname); + jctr->emplace("id"_cs, nextId("counter_arrays"_cs)); + jctr->emplace_non_null("source_info"_cs, ctrs->sourceInfoJsonObj()); // TODO(jafingerhut) - what kind of P4_16 code causes this // code to run, if any? bool direct = te->name == "direct_counter"; - jctr->emplace("is_direct", direct); - jctr->emplace("binding", table->controlPlaneName()); + jctr->emplace("is_direct"_cs, direct); + jctr->emplace("binding"_cs, table->controlPlaneName()); ctxt->json->counters->append(jctr); } else if (expr->is()) { auto pe = expr->to(); @@ -226,13 +226,13 @@ class ControlConverter : public Inspector { ::error(ErrorType::ERR_EXPECTED, "%1%: expected a counter", ctrs); } } - result->emplace("with_counters", true); + result->emplace("with_counters"_cs, true); } else { - result->emplace("with_counters", false); + result->emplace("with_counters"_cs, false); } bool sup_to = false; - auto timeout = table->properties->getProperty("support_timeout"); + auto timeout = table->properties->getProperty("support_timeout"_cs); if (timeout != nullptr) { if (timeout->value->is()) { auto expr = timeout->value->to()->expression; @@ -245,9 +245,9 @@ class ControlConverter : public Inspector { ::error(ErrorType::ERR_EXPECTED, "%1%: expected a Boolean", timeout); } } - result->emplace("support_timeout", sup_to); + result->emplace("support_timeout"_cs, sup_to); - auto dm = table->properties->getProperty("meters"); + auto dm = table->properties->getProperty("meters"_cs); if (dm != nullptr) { if (dm->value->is()) { auto expr = dm->value->to()->expression; @@ -282,17 +282,17 @@ class ControlConverter : public Inspector { BUG_CHECK(decl->is(), "%1%: expected an instance", decl->getNode()); cstring name = decl->controlPlaneName(); - result->emplace("direct_meters", name); + result->emplace("direct_meters"_cs, name); } } else { ::error(ErrorType::ERR_EXPECTED, "%1%: expected a meter", dm); } } else { - result->emplace("direct_meters", Util::JsonValue::null); + result->emplace("direct_meters"_cs, Util::JsonValue::null); } - auto action_ids = mkArrayField(result, "action_ids"); - auto actions = mkArrayField(result, "actions"); + auto action_ids = mkArrayField(result, "action_ids"_cs); + auto actions = mkArrayField(result, "actions"_cs); auto al = table->getActionList(); std::map useActionName; @@ -339,19 +339,19 @@ class ControlConverter : public Inspector { BUG_CHECK(nextDestination, "Could not find default destination for %1%", node->invocation); nextLabel = nodeName(nextDestination); - result->emplace("base_default_next", nextLabel); + result->emplace("base_default_next"_cs, nextLabel); // So if a "default:" switch case exists we set the nextLabel // to be the destination of the default: label. if (defaultLabelDestination != nullptr) nextLabel = nodeName(defaultLabelDestination); } else { - result->emplace("base_default_next", Util::JsonValue::null); + result->emplace("base_default_next"_cs, Util::JsonValue::null); } std::set labelsDone; for (auto s : node->successors.edges) { cstring label; if (s->isBool()) { - label = s->getBool() ? "__HIT__" : "__MISS__"; + label = s->getBool() ? "__HIT__"_cs : "__MISS__"_cs; } else if (s->isUnconditional()) { continue; } else { @@ -374,7 +374,7 @@ class ControlConverter : public Inspector { } } - result->emplace("next_tables", next_tables); + result->emplace("next_tables"_cs, next_tables); auto defact = table->properties->getProperty(IR::TableProperties::defaultActionPropertyName); if (defact != nullptr) { @@ -411,9 +411,9 @@ class ControlConverter : public Inspector { unsigned actionid = get(ctxt->structure->ids, action, INVALID_ACTION_ID); BUG_CHECK(actionid != INVALID_ACTION_ID, "Could not find id for %1%", action); auto entry = new Util::JsonObject(); - entry->emplace("action_id", actionid); - entry->emplace("action_const", defact->isConstant); - auto fields = mkArrayField(entry, "action_data"); + entry->emplace("action_id"_cs, actionid); + entry->emplace("action_const"_cs, defact->isConstant); + auto fields = mkArrayField(entry, "action_data"_cs); if (args != nullptr) { // TODO: use argument names for (auto a : *args) { @@ -427,8 +427,8 @@ class ControlConverter : public Inspector { } } } - entry->emplace("action_entry_const", defact->isConstant); - result->emplace("default_entry", entry); + entry->emplace("action_entry_const"_cs, defact->isConstant); + result->emplace("default_entry"_cs, entry); } convertTableEntries(table, result); return result; @@ -437,14 +437,14 @@ class ControlConverter : public Inspector { auto entriesList = table->getEntries(); if (entriesList == nullptr) return; - auto entries = mkArrayField(jsonTable, "entries"); + auto entries = mkArrayField(jsonTable, "entries"_cs); int entryPriority = 1; // default priority is defined by index position for (auto e : entriesList->entries) { auto entry = new Util::JsonObject(); - entry->emplace_non_null("source_info", e->sourceInfoJsonObj()); + entry->emplace_non_null("source_info"_cs, e->sourceInfoJsonObj()); auto keyset = e->getKeys(); - auto matchKeys = mkArrayField(entry, "match_key"); + auto matchKeys = mkArrayField(entry, "match_key"_cs); int keyIndex = 0; for (auto k : keyset->components) { auto key = new Util::JsonObject(); @@ -456,16 +456,16 @@ class ControlConverter : public Inspector { // represented in the BMv2 JSON file the same as a ternary // field would be. if (matchType == "optional") { - key->emplace("match_type", "ternary"); + key->emplace("match_type"_cs, "ternary"); } else { - key->emplace("match_type", matchType); + key->emplace("match_type"_cs, matchType); } if (matchType == corelib.exactMatch.name) { if (k->is()) - key->emplace("key", stringRepr(k->to()->value, k8)); + key->emplace("key"_cs, stringRepr(k->to()->value, k8)); else if (k->is()) // booleans are converted to ints - key->emplace("key", + key->emplace("key"_cs, stringRepr(k->to()->value ? 1 : 0, k8)); else ::error(ErrorType::ERR_UNSUPPORTED, "%1%: unsupported exact key expression", @@ -473,14 +473,15 @@ class ControlConverter : public Inspector { } else if (matchType == corelib.ternaryMatch.name) { if (k->is()) { auto km = k->to(); - key->emplace("key", stringRepr(km->left->to()->value, k8)); - key->emplace("mask", stringRepr(km->right->to()->value, k8)); + key->emplace("key"_cs, stringRepr(km->left->to()->value, k8)); + key->emplace("mask"_cs, + stringRepr(km->right->to()->value, k8)); } else if (k->is()) { - key->emplace("key", stringRepr(k->to()->value, k8)); - key->emplace("mask", stringRepr(Util::mask(keyWidth), k8)); + key->emplace("key"_cs, stringRepr(k->to()->value, k8)); + key->emplace("mask"_cs, stringRepr(Util::mask(keyWidth), k8)); } else if (k->is()) { - key->emplace("key", stringRepr(0, k8)); - key->emplace("mask", stringRepr(0, k8)); + key->emplace("key"_cs, stringRepr(0, k8)); + key->emplace("mask"_cs, stringRepr(0, k8)); } else { ::error(ErrorType::ERR_UNSUPPORTED, "%1%: unsupported ternary key expression", k); @@ -488,7 +489,7 @@ class ControlConverter : public Inspector { } else if (matchType == corelib.lpmMatch.name) { if (k->is()) { auto km = k->to(); - key->emplace("key", stringRepr(km->left->to()->value, k8)); + key->emplace("key"_cs, stringRepr(km->left->to()->value, k8)); auto trailing_zeros = [](unsigned long n, unsigned long keyWidth) { return n ? __builtin_ctzl(n) : static_cast(keyWidth); }; @@ -501,13 +502,13 @@ class ControlConverter : public Inspector { if (len + count_ones(mask) != keyWidth) // any remaining 0s in the prefix? ::error(ErrorType::ERR_INVALID, "%1%: invalid mask for LPM key", k); else - key->emplace("prefix_length", keyWidth - len); + key->emplace("prefix_length"_cs, keyWidth - len); } else if (k->is()) { - key->emplace("key", stringRepr(k->to()->value, k8)); - key->emplace("prefix_length", keyWidth); + key->emplace("key"_cs, stringRepr(k->to()->value, k8)); + key->emplace("prefix_length"_cs, keyWidth); } else if (k->is()) { - key->emplace("key", stringRepr(0, k8)); - key->emplace("prefix_length", 0); + key->emplace("key"_cs, stringRepr(0, k8)); + key->emplace("prefix_length"_cs, 0); } else { ::error(ErrorType::ERR_UNSUPPORTED, "%1%: unsupported LPM key expression", k); @@ -515,14 +516,16 @@ class ControlConverter : public Inspector { } else if (matchType == "range") { if (k->is()) { auto kr = k->to(); - key->emplace("start", stringRepr(kr->left->to()->value, k8)); - key->emplace("end", stringRepr(kr->right->to()->value, k8)); + key->emplace("start"_cs, + stringRepr(kr->left->to()->value, k8)); + key->emplace("end"_cs, + stringRepr(kr->right->to()->value, k8)); } else if (k->is()) { - key->emplace("start", stringRepr(k->to()->value, k8)); - key->emplace("end", stringRepr(k->to()->value, k8)); + key->emplace("start"_cs, stringRepr(k->to()->value, k8)); + key->emplace("end"_cs, stringRepr(k->to()->value, k8)); } else if (k->is()) { - key->emplace("start", stringRepr(0, k8)); - key->emplace("end", stringRepr((1 << keyWidth) - 1, k8)); // 2^N -1 + key->emplace("start"_cs, stringRepr(0, k8)); + key->emplace("end"_cs, stringRepr((1 << keyWidth) - 1, k8)); // 2^N -1 } else { ::error(ErrorType::ERR_UNSUPPORTED, "%1% unsupported range key expression", k); @@ -536,11 +539,11 @@ class ControlConverter : public Inspector { // allow exact values or a DefaultExpression (_ or // default), no &&& expression. if (k->is()) { - key->emplace("key", stringRepr(k->to()->value, k8)); - key->emplace("mask", stringRepr(Util::mask(keyWidth), k8)); + key->emplace("key"_cs, stringRepr(k->to()->value, k8)); + key->emplace("mask"_cs, stringRepr(Util::mask(keyWidth), k8)); } else if (k->is()) { - key->emplace("key", stringRepr(0, k8)); - key->emplace("mask", stringRepr(0, k8)); + key->emplace("key"_cs, stringRepr(0, k8)); + key->emplace("mask"_cs, stringRepr(0, k8)); } else { ::error(ErrorType::ERR_UNSUPPORTED, "%1%: unsupported optional key expression", k); @@ -563,14 +566,14 @@ class ControlConverter : public Inspector { auto actionDecl = decl->to(); unsigned id = get(ctxt->structure->ids, actionDecl, INVALID_ACTION_ID); BUG_CHECK(id != INVALID_ACTION_ID, "Could not find id for %1%", actionDecl); - action->emplace("action_id", id); - auto actionData = mkArrayField(action, "action_data"); + action->emplace("action_id"_cs, id); + auto actionData = mkArrayField(action, "action_data"_cs); for (auto arg : *actionCall->arguments) { actionData->append(stringRepr(arg->expression->to()->value, 0)); } - entry->emplace("action_entry", action); + entry->emplace("action_entry"_cs, action); - auto priorityAnnotation = e->getAnnotation("priority"); + auto priorityAnnotation = e->getAnnotation("priority"_cs); if (priorityAnnotation != nullptr) { if (priorityAnnotation->expr.size() > 1) ::error(ErrorType::ERR_INVALID, "Invalid priority value %1%", @@ -579,9 +582,9 @@ class ControlConverter : public Inspector { if (!priValue->is()) ::error(ErrorType::ERR_INVALID, "Invalid priority value %1%; must be constant.", priorityAnnotation->expr); - entry->emplace("priority", priValue->to()->value); + entry->emplace("priority"_cs, priValue->to()->value); } else { - entry->emplace("priority", entryPriority); + entry->emplace("priority"_cs, entryPriority); } entryPriority += 1; @@ -600,14 +603,14 @@ class ControlConverter : public Inspector { } ::error(ErrorType::ERR_UNSUPPORTED, "%1%: match type not supported on this target", mt); - return "invalid"; + return "invalid"_cs; } /// Return 'true' if the table is 'simple' bool handleTableImplementation(const IR::Property *implementation, const IR::Key *key, Util::JsonObject *table, Util::JsonArray *action_profiles, BMV2::SharedActionSelectorCheck *) { if (implementation == nullptr) { - table->emplace("type", "simple"); + table->emplace("type"_cs, "simple"); return true; } @@ -637,9 +640,10 @@ class ControlConverter : public Inspector { apname = implementation->controlPlaneName(ctxt->refMap->newName("action_profile")); action_profile = new Util::JsonObject(); action_profiles->append(action_profile); - action_profile->emplace("name", apname); - action_profile->emplace("id", nextId("action_profiles")); - action_profile->emplace_non_null("source_info", propv->expression->sourceInfoJsonObj()); + action_profile->emplace("name"_cs, apname); + action_profile->emplace("id"_cs, nextId("action_profiles"_cs)); + action_profile->emplace_non_null("source_info"_cs, + propv->expression->sourceInfoJsonObj()); // TODO(jafingerhut) - add line/col here? // TBD what about the else if cases below? @@ -652,7 +656,7 @@ class ControlConverter : public Inspector { } else { size = size_expr->to()->asInt(); } - action_profile->emplace("max_size", size); + action_profile->emplace("max_size"_cs, size); }; auto actionSelectorName = Standard::ActionSelectorTraits::typeName(); @@ -660,8 +664,8 @@ class ControlConverter : public Inspector { BUG_CHECK(arguments->size() == 3, "%1%: expected 3 arguments", arguments); isSimpleTable = false; auto selector = new Util::JsonObject(); - table->emplace("type", "indirect_ws"); - action_profile->emplace("selector", selector); + table->emplace("type"_cs, "indirect_ws"); + action_profile->emplace("selector"_cs, selector); add_size(1); auto hash = arguments->at(0)->expression; auto ei = P4::EnumInstance::resolve(hash, ctxt->typeMap); @@ -670,9 +674,9 @@ class ControlConverter : public Inspector { hash); } else { cstring algo = ei->name; - selector->emplace("algo", algo); + selector->emplace("algo"_cs, algo); } - auto input = mkArrayField(selector, "input"); + auto input = mkArrayField(selector, "input"_cs); for (auto ke : key->keyElements) { auto mt = ctxt->refMap->getDeclaration(ke->matchType->path, true) ->to(); @@ -686,7 +690,7 @@ class ControlConverter : public Inspector { } else if (implementationType->name == Standard::ActionProfileTraits::typeName()) { isSimpleTable = false; - table->emplace("type", "indirect"); + table->emplace("type"_cs, "indirect"); add_size(0); } else { ::error(ErrorType::ERR_UNEXPECTED, "%1%: expected value for property", propv); @@ -709,9 +713,9 @@ class ControlConverter : public Inspector { auto actionProfileName = Standard::ActionProfileTraits::typeName(); auto actionSelectorName = Standard::ActionSelectorTraits::typeName(); if (type_extern_name == actionProfileName) { - table->emplace("type", "indirect"); + table->emplace("type"_cs, "indirect"); } else if (type_extern_name == actionSelectorName) { - table->emplace("type", "indirect_ws"); + table->emplace("type"_cs, "indirect_ws"); } else { ::error(ErrorType::ERR_UNEXPECTED, "%1%: unexpected type for implementation", dcltype); @@ -728,19 +732,19 @@ class ControlConverter : public Inspector { ::error(ErrorType::ERR_UNEXPECTED, "%1%: unexpected value for property", propv); return false; } - table->emplace("action_profile", apname); + table->emplace("action_profile"_cs, apname); return isSimpleTable; } Util::IJson *convertIf(const CFG::IfNode *node, cstring prefix) { (void)prefix; auto result = new Util::JsonObject(); - result->emplace("name", node->name); - result->emplace("id", nextId("conditionals")); - result->emplace_non_null("source_info", node->statement->condition->sourceInfoJsonObj()); + result->emplace("name"_cs, node->name); + result->emplace("id"_cs, nextId("conditionals"_cs)); + result->emplace_non_null("source_info"_cs, node->statement->condition->sourceInfoJsonObj()); auto j = ctxt->conv->convert(node->statement->condition, true, false); CHECK_NULL(j); - result->emplace("expression", j); + result->emplace("expression"_cs, j); for (auto e : node->successors.edges) { Util::IJson *dest = nodeName(e->endpoint); cstring label = Util::toString(e->getBool()); @@ -755,9 +759,9 @@ class ControlConverter : public Inspector { bool preorder(const IR::P4Control *cont) override { auto result = new Util::JsonObject(); - result->emplace("name", name); - result->emplace("id", nextId("control")); - result->emplace_non_null("source_info", cont->sourceInfoJsonObj()); + result->emplace("name"_cs, name); + result->emplace("id"_cs, nextId("control"_cs)); + result->emplace_non_null("source_info"_cs, cont->sourceInfoJsonObj()); auto cfg = new CFG(); cfg->build(cont, ctxt->refMap, ctxt->typeMap); @@ -765,17 +769,17 @@ class ControlConverter : public Inspector { if (!success) return false; if (cfg->entryPoint->successors.size() == 0) { - result->emplace("init_table", Util::JsonValue::null); + result->emplace("init_table"_cs, Util::JsonValue::null); } else { BUG_CHECK(cfg->entryPoint->successors.size() == 1, "Expected 1 start node for %1%", cont); auto start = (*(cfg->entryPoint->successors.edges.begin()))->endpoint; - result->emplace("init_table", nodeName(start)); + result->emplace("init_table"_cs, nodeName(start)); } - auto tables = mkArrayField(result, "tables"); - auto action_profiles = mkArrayField(result, "action_profiles"); - auto conditionals = mkArrayField(result, "conditionals"); + auto tables = mkArrayField(result, "tables"_cs); + auto action_profiles = mkArrayField(result, "action_profiles"_cs); + auto conditionals = mkArrayField(result, "conditionals"_cs); ctxt->action_profiles = action_profiles; auto selector_check = new BMV2::SharedActionSelectorCheck(ctxt); diff --git a/backends/bmv2/common/controlFlowGraph.cpp b/backends/bmv2/common/controlFlowGraph.cpp index 3fde0cffbb..d532f88161 100644 --- a/backends/bmv2/common/controlFlowGraph.cpp +++ b/backends/bmv2/common/controlFlowGraph.cpp @@ -27,6 +27,8 @@ limitations under the License. namespace BMV2 { +using namespace P4::literals; + unsigned CFG::Node::crtId = 0; void CFG::EdgeSet::dbprint(std::ostream &out) const { @@ -260,7 +262,7 @@ class CFGBuilder : public Inspector { for (auto sw : statement->cases) { cstring label; if (sw->label->is()) { - label = "default"; + label = "default"_cs; } else { auto pe = sw->label->to(); CHECK_NULL(pe); @@ -294,7 +296,7 @@ class CFGBuilder : public Inspector { void CFG::build(const IR::P4Control *cc, P4::ReferenceMap *refMap, P4::TypeMap *typeMap) { container = cc; entryPoint = makeNode(cc->name + ".entry"); - exitPoint = makeNode(""); // the only node with an empty name + exitPoint = makeNode(cstring::empty); // the only node with an empty name CFGBuilder builder(this, refMap, typeMap); auto startValue = new CFG::EdgeSet(new CFG::Edge(entryPoint)); diff --git a/backends/bmv2/common/deparser.cpp b/backends/bmv2/common/deparser.cpp index 30124c7a1d..bbd7b9d75a 100644 --- a/backends/bmv2/common/deparser.cpp +++ b/backends/bmv2/common/deparser.cpp @@ -59,9 +59,9 @@ void DeparserConverter::convertDeparserBody(const IR::Vector *bo } else if (assign->right->is()) { ctxt->conv->simpleExpressionsOnly = false; auto json = new Util::JsonObject(); - auto params = mkArrayField(json, "parameters"); + auto params = mkArrayField(json, "parameters"_cs); auto type = ctxt->typeMap->getType(assign->left, true); - json->emplace("op", "set"); + json->emplace("op"_cs, "set"); auto l = ctxt->conv->convertLeftValue(assign->left); bool convertBool = type->is(); auto r = ctxt->conv->convert(assign->right, true, true, convertBool); @@ -85,7 +85,7 @@ void DeparserConverter::convertDeparserBody(const IR::Vector *bo auto type = ctxt->typeMap->getType(arg, true); if (type->is()) { auto j = ctxt->conv->convert(arg->expression); - auto val = j->to()->get("value"); + auto val = j->to()->get("value"_cs); order->append(val); } else { // We don't need to handle other types, @@ -132,11 +132,11 @@ void DeparserConverter::convertDeparserBody(const IR::Vector *bo Util::IJson *DeparserConverter::convertDeparser(const IR::P4Control *ctrl) { auto result = new Util::JsonObject(); - result->emplace("name", name); - result->emplace("id", nextId("deparser")); - result->emplace_non_null("source_info", ctrl->sourceInfoJsonObj()); - auto order = mkArrayField(result, "order"); - auto primitives = mkArrayField(result, "primitives"); + result->emplace("name"_cs, name); + result->emplace("id"_cs, nextId("deparser"_cs)); + result->emplace_non_null("source_info"_cs, ctrl->sourceInfoJsonObj()); + auto order = mkArrayField(result, "order"_cs); + auto primitives = mkArrayField(result, "primitives"_cs); convertDeparserBody(&ctrl->body->components, order, primitives); return result; } diff --git a/backends/bmv2/common/deparser.h b/backends/bmv2/common/deparser.h index 97e0ccc000..f273199454 100644 --- a/backends/bmv2/common/deparser.h +++ b/backends/bmv2/common/deparser.h @@ -39,7 +39,7 @@ class DeparserConverter : public Inspector { public: bool preorder(const IR::P4Control *ctrl) override; - explicit DeparserConverter(ConversionContext *ctxt, cstring name = "deparser") + explicit DeparserConverter(ConversionContext *ctxt, cstring name = "deparser"_cs) : ctxt(ctxt), name(name), corelib(P4::P4CoreLibrary::instance()) { setName("DeparserConverter"); } diff --git a/backends/bmv2/common/expression.cpp b/backends/bmv2/common/expression.cpp index 92212679de..f7de266ee2 100644 --- a/backends/bmv2/common/expression.cpp +++ b/backends/bmv2/common/expression.cpp @@ -99,8 +99,8 @@ Util::IJson *ExpressionConverter::get(const IR::Expression *expression) const { void ExpressionConverter::postorder(const IR::BoolLiteral *expression) { auto result = new Util::JsonObject(); - result->emplace("type", "bool"); - result->emplace("value", expression->value); + result->emplace("type"_cs, "bool"); + result->emplace("value"_cs, expression->value); mapExpression(expression, result); } @@ -116,8 +116,8 @@ void ExpressionConverter::postorder(const IR::MethodCallExpression *expression) int width = typearg->width_bits(); BUG_CHECK(width > 0, "%1%: unknown width", targ); auto j = new Util::JsonObject(); - j->emplace("type", "lookahead"); - auto v = mkArrayField(j, "value"); + j->emplace("type"_cs, "lookahead"); + auto v = mkArrayField(j, "value"_cs); v->append(0); v->append(width); mapExpression(expression, j); @@ -130,18 +130,18 @@ void ExpressionConverter::postorder(const IR::MethodCallExpression *expression) auto l = get(bim->appliedTo); if (!l) return; if (type->is()) { - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); - e->emplace("op", "valid_union"); - e->emplace("left", Util::JsonValue::null); - e->emplace("right", l); + result->emplace("value"_cs, e); + e->emplace("op"_cs, "valid_union"); + e->emplace("left"_cs, Util::JsonValue::null); + e->emplace("right"_cs, l); } else { // Treat this as appliedTo.$valid$ - result->emplace("type", "field"); - auto e = mkArrayField(result, "value"); + result->emplace("type"_cs, "field"); + auto e = mkArrayField(result, "value"_cs); if (l->is()) - e->append(l->to()->get("value")); + e->append(l->to()->get("value"_cs)); else e->append(l); e->append(V1ModelProperties::validField); @@ -150,11 +150,11 @@ void ExpressionConverter::postorder(const IR::MethodCallExpression *expression) // for table keys we don't need the casts. auto cast = new Util::JsonObject(); auto value = new Util::JsonObject(); - cast->emplace("type", "expression"); - cast->emplace("value", value); - value->emplace("op", "d2b"); // data to Boolean cast - value->emplace("left", Util::JsonValue::null); - value->emplace("right", result); + cast->emplace("type"_cs, "expression"); + cast->emplace("value"_cs, value); + value->emplace("op"_cs, "d2b"); // data to Boolean cast + value->emplace("left"_cs, Util::JsonValue::null); + value->emplace("right"_cs, result); result = cast; } } @@ -175,11 +175,11 @@ void ExpressionConverter::postorder(const IR::Cast *expression) { void ExpressionConverter::postorder(const IR::Constant *expression) { auto result = new Util::JsonObject(); - result->emplace("type", "hexstr"); + result->emplace("type"_cs, "hexstr"); auto bitwidth = expression->type->width_bits(); cstring repr = stringRepr(expression->value, ROUNDUP(bitwidth, 8)); - result->emplace("value", repr); - if (withConstantWidths) result->emplace("bitwidth", bitwidth); + result->emplace("value"_cs, repr); + if (withConstantWidths) result->emplace("bitwidth"_cs, bitwidth); mapExpression(expression, result); } @@ -213,21 +213,21 @@ void ExpressionConverter::postorder(const IR::ArrayIndex *expression) { } BUG_CHECK(fresult, "%1%: Runtime array index json generation failed", ex); Util::JsonObject *fres = fresult->to(); - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - e->emplace("op", "dereference_header_stack"); + e->emplace("op"_cs, "dereference_header_stack"); auto l = new Util::JsonObject(); - l->emplace("type", "header_stack"); - l->emplace("value", elementAccess); - e->emplace("left", l); - e->emplace("right", fres); - result->emplace("value", e); + l->emplace("type"_cs, "header_stack"); + l->emplace("value"_cs, elementAccess); + e->emplace("left"_cs, l); + e->emplace("right"_cs, fres); + result->emplace("value"_cs, e); } else { - result->emplace("type", "header"); + result->emplace("type"_cs, "header"); int index = expression->right->to()->asInt(); elementAccess += "[" + Util::toString(index) + "]"; - result->emplace("value", elementAccess); + result->emplace("value"_cs, elementAccess); } mapExpression(expression, result); } @@ -266,12 +266,12 @@ void ExpressionConverter::postorder(const IR::Member *expression) { // handle error if (type->is() && expression->expr->is()) { // this deals with constants that have type 'error' - result->emplace("type", "hexstr"); + result->emplace("type"_cs, "hexstr"); auto decl = type->to()->getDeclByName(expression->member.name); auto errorValue = structure->errorCodesMap.at(decl); // this generates error constant like hex value auto reprValue = stringRepr(errorValue); - result->emplace("value", reprValue); + result->emplace("value"_cs, reprValue); mapExpression(expression, result); return; } @@ -287,27 +287,27 @@ void ExpressionConverter::postorder(const IR::Member *expression) { if (auto st = type->to()) { auto et = typeMap->getTypeType(st->elementType, true); if (et->is()) - result->emplace("type", "header_union_stack"); + result->emplace("type"_cs, "header_union_stack"); else - result->emplace("type", "header_stack"); - result->emplace("value", fieldName); + result->emplace("type"_cs, "header_stack"); + result->emplace("value"_cs, fieldName); } else if (type->is()) { - result->emplace("type", "header_union"); - result->emplace("value", fieldName); + result->emplace("type"_cs, "header_union"); + result->emplace("value"_cs, fieldName); } else if (parentType->is()) { auto l = get(expression->expr); if (!l) return; cstring nestedField = fieldName; if (auto lv = l->to()) { - lv->get("value"); + lv->get("value"_cs); if (lv->is()) { // header in union reference ["u", "f"] => "u.f" cstring prefix = lv->to()->getString(); nestedField = prefix + "." + nestedField; } } - result->emplace("type", "header"); - result->emplace("value", nestedField); + result->emplace("type"_cs, "header"); + result->emplace("value"_cs, nestedField); } else if (parentType->is() && (type->is() || type->is() || type->is())) { @@ -318,32 +318,32 @@ void ExpressionConverter::postorder(const IR::Member *expression) { BUG_CHECK((name != nullptr), "NULL name: %1%", field->name); if (type->is() || type->is() || leftValue || simpleExpressionsOnly) { - result->emplace("type", "field"); - auto e = mkArrayField(result, "value"); + result->emplace("type"_cs, "field"); + auto e = mkArrayField(result, "value"_cs); e->append(scalarsName); e->append(name); } else if (type->is()) { // Boolean variables are stored as ints, so we // have to insert a conversion when reading such a // variable - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); - e->emplace("op", "d2b"); // data to Boolean cast - e->emplace("left", Util::JsonValue::null); + result->emplace("value"_cs, e); + e->emplace("op"_cs, "d2b"); // data to Boolean cast + e->emplace("left"_cs, Util::JsonValue::null); auto r = new Util::JsonObject(); - e->emplace("right", r); + e->emplace("right"_cs, r); - r->emplace("type", "field"); - auto a = mkArrayField(r, "value"); + r->emplace("type"_cs, "field"); + auto a = mkArrayField(r, "value"_cs); a->append(scalarsName); a->append(name); } } else { // This may be wrong, but the caller will handle it properly // (e.g., this can be a method, such as packet.lookahead) - result->emplace("type", "header"); - result->emplace("value", fieldName); + result->emplace("type"_cs, "header"); + result->emplace("value"_cs, fieldName); } mapExpression(expression, result); return; @@ -359,10 +359,10 @@ void ExpressionConverter::postorder(const IR::Member *expression) { if (memtype->is() && mem->member == IR::Type_Stack::last) { auto l = get(mem->expr); if (!l) return; - result->emplace("type", "stack_field"); - auto e = mkArrayField(result, "value"); + result->emplace("type"_cs, "stack_field"); + auto e = mkArrayField(result, "value"_cs); if (l->is()) - e->append(l->to()->get("value")); + e->append(l->to()->get("value"_cs)); else e->append(l); e->append(fieldName); @@ -375,42 +375,42 @@ void ExpressionConverter::postorder(const IR::Member *expression) { if (!l) return; if (parentType->is()) { BUG_CHECK(l->is(), "Not a JsonObject"); - auto lv = l->to()->get("value"); + auto lv = l->to()->get("value"_cs); if (lv->is()) { fieldName = lv->to()->getString() + "." + fieldName; // Each header in a union is allocated a separate header instance. // Refer to that instance directly. - result->emplace("type", "header"); - result->emplace("value", fieldName); + result->emplace("type"_cs, "header"); + result->emplace("value"_cs, fieldName); } else { // lv must be a reference to a union stack field auto a = lv->to()->clone(); CHECK_NULL(a); - result->emplace("type", "union_stack_field"); + result->emplace("type"_cs, "union_stack_field"); a->append(fieldName); - result->emplace("value", a); + result->emplace("value"_cs, a); } } else if (parentType->is() && expression->member == IR::Type_Stack::lastIndex) { auto l = get(expression->expr); if (!l) return; - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); - e->emplace("op", "last_stack_index"); - e->emplace("left", Util::JsonValue::null); - e->emplace("right", l); + result->emplace("value"_cs, e); + e->emplace("op"_cs, "last_stack_index"); + e->emplace("left"_cs, Util::JsonValue::null); + e->emplace("right"_cs, l); } else { const char *fieldRef = parentType->is() ? "stack_field" : "field"; Util::JsonArray *e = nullptr; bool st = isArrayIndexRuntime(expression); if (!st) { - result->emplace("type", fieldRef); - e = mkArrayField(result, "value"); + result->emplace("type"_cs, fieldRef); + e = mkArrayField(result, "value"_cs); } if (l->is()) { - auto lv = l->to()->get("value"); + auto lv = l->to()->get("value"_cs); if (lv->is()) { // TODO: is this case still necessary after eliminating nested structs? // nested struct reference [ ["m", "f"], "x" ] => [ "m", "f.x" ] @@ -436,12 +436,12 @@ void ExpressionConverter::postorder(const IR::Member *expression) { "for runtime index computation %1%", st); } - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); - e->emplace("op", "access_field"); - e->emplace("left", jo); - e->emplace("right", index_pos); + result->emplace("value"_cs, e); + e->emplace("op"_cs, "access_field"); + e->emplace("left"_cs, jo); + e->emplace("right"_cs, index_pos); } } else { BUG("%1%: Unexpected json", lv); @@ -454,11 +454,11 @@ void ExpressionConverter::postorder(const IR::Member *expression) { if (!simpleExpressionsOnly && !leftValue && type->is()) { auto cast = new Util::JsonObject(); auto value = new Util::JsonObject(); - cast->emplace("type", "expression"); - cast->emplace("value", value); - value->emplace("op", "d2b"); // data to Boolean cast - value->emplace("left", Util::JsonValue::null); - value->emplace("right", result); + cast->emplace("type"_cs, "expression"); + cast->emplace("value"_cs, value); + value->emplace("op"_cs, "d2b"); // data to Boolean cast + value->emplace("left"_cs, Util::JsonValue::null); + value->emplace("right"_cs, result); result = cast; } } @@ -469,12 +469,12 @@ void ExpressionConverter::postorder(const IR::Member *expression) { Util::IJson *ExpressionConverter::fixLocal(Util::IJson *json) { if (!json) return new Util::JsonValue(); // null if (auto jo = json->to()) { - auto to = jo->get("type"); + auto to = jo->get("type"_cs); if (to != nullptr && to->to() != nullptr && (*to->to()) == "runtime_data") { auto result = new Util::JsonObject(); - result->emplace("type", "local"); - result->emplace("value", jo->get("value")); + result->emplace("type"_cs, "local"); + result->emplace("value"_cs, jo->get("value"_cs)); return result; } } @@ -490,36 +490,36 @@ void ExpressionConverter::postorder(const IR::Mux *expression) { return; } - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); - e->emplace("op", "?"); + result->emplace("value"_cs, e); + e->emplace("op"_cs, "?"); auto l = get(expression->e1); if (!l) return; - e->emplace("left", fixLocal(l)); + e->emplace("left"_cs, fixLocal(l)); auto r = get(expression->e2); if (!r) return; - e->emplace("right", fixLocal(r)); + e->emplace("right"_cs, fixLocal(r)); auto c = get(expression->e0); if (!c) return; - e->emplace("cond", fixLocal(c)); + e->emplace("cond"_cs, fixLocal(c)); } void ExpressionConverter::postorder(const IR::IntMod *expression) { auto result = new Util::JsonObject(); mapExpression(expression, result); - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); - e->emplace("op", "two_comp_mod"); + result->emplace("value"_cs, e); + e->emplace("op"_cs, "two_comp_mod"); auto l = get(expression->expr); if (!l) return; - e->emplace("left", fixLocal(l)); + e->emplace("left"_cs, fixLocal(l)); auto r = new Util::JsonObject(); - r->emplace("type", "hexstr"); + r->emplace("type"_cs, "hexstr"); cstring repr = stringRepr(expression->width); - r->emplace("value", repr); - e->emplace("right", r); + r->emplace("value"_cs, repr); + e->emplace("right"_cs, r); } void ExpressionConverter::postorder(const IR::Operation_Binary *expression) { binary(expression); } @@ -533,21 +533,21 @@ void ExpressionConverter::binary(const IR::Operation_Binary *expression) { return; } - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); + result->emplace("value"_cs, e); cstring op = expression->getStringOp(); if (op == "&&") - op = "and"; + op = "and"_cs; else if (op == "||") - op = "or"; - e->emplace("op", op); + op = "or"_cs; + e->emplace("op"_cs, op); auto l = get(expression->left); if (!l) return; - e->emplace("left", fixLocal(l)); + e->emplace("left"_cs, fixLocal(l)); auto r = get(expression->right); if (!r) return; - e->emplace("right", fixLocal(r)); + e->emplace("right"_cs, fixLocal(r)); } void ExpressionConverter::saturated_binary(const IR::Operation_Binary *expression) { @@ -556,30 +556,30 @@ void ExpressionConverter::saturated_binary(const IR::Operation_Binary *expressio auto result = new Util::JsonObject(); mapExpression(expression, result); - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); + result->emplace("value"_cs, e); auto eType = expression->type->to(); CHECK_NULL(eType); auto opType = eType->isSigned ? "sat_cast" : "usat_cast"; - e->emplace("op", opType); + e->emplace("op"_cs, opType); // the left operand is the binary expression, but as a simple add/sub auto eLeft = new Util::JsonObject(); - eLeft->emplace("type", "expression"); + eLeft->emplace("type"_cs, "expression"); auto e1 = new Util::JsonObject(); - e1->emplace("op", expression->getStringOp() == "|+|" ? "+" : "-"); - e1->emplace("left", fixLocal(get(expression->left))); - e1->emplace("right", fixLocal(get(expression->right))); - eLeft->emplace("value", e1); - e->emplace("left", eLeft); + e1->emplace("op"_cs, expression->getStringOp() == "|+|" ? "+" : "-"); + e1->emplace("left"_cs, fixLocal(get(expression->left))); + e1->emplace("right"_cs, fixLocal(get(expression->right))); + eLeft->emplace("value"_cs, e1); + e->emplace("left"_cs, eLeft); // the right operand is the width of the type auto r = new Util::JsonObject(); - r->emplace("type", "hexstr"); + r->emplace("type"_cs, "hexstr"); cstring repr = stringRepr(eType->width_bits()); - r->emplace("value", repr); - e->emplace("right", r); + r->emplace("value"_cs, repr); + e->emplace("right"_cs, r); } void ExpressionConverter::postorder(const IR::ListExpression *expression) { @@ -624,16 +624,16 @@ void ExpressionConverter::postorder(const IR::Operation_Unary *expression) { return; } - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); + result->emplace("value"_cs, e); cstring op = expression->getStringOp(); - if (op == "!") op = "not"; - e->emplace("op", op); - e->emplace("left", Util::JsonValue::null); + if (op == "!") op = "not"_cs; + e->emplace("op"_cs, op); + e->emplace("left"_cs, Util::JsonValue::null); auto r = get(expression->expr); if (!r) return; - e->emplace("right", fixLocal(r)); + e->emplace("right"_cs, fixLocal(r)); } void ExpressionConverter::postorder(const IR::PathExpression *expression) { @@ -643,11 +643,11 @@ void ExpressionConverter::postorder(const IR::PathExpression *expression) { if (structure->nonActionParameters.find(param) != structure->nonActionParameters.end()) { auto type = typeMap->getType(param, true); if (type->is()) { - auto result = convertParam(param, ""); + auto result = convertParam(param, cstring::empty); if (result == nullptr) { auto r = new Util::JsonObject(); - r->emplace("type", "header"); - r->emplace("value", param->name.name); + r->emplace("type"_cs, "header"); + r->emplace("value"_cs, param->name.name); result = r; } mapExpression(expression, result); @@ -657,56 +657,56 @@ void ExpressionConverter::postorder(const IR::PathExpression *expression) { return; } auto result = new Util::JsonObject(); - result->emplace("type", "runtime_data"); + result->emplace("type"_cs, "runtime_data"); unsigned paramIndex = ::get(&structure->index, param); - result->emplace("value", paramIndex); + result->emplace("value"_cs, paramIndex); mapExpression(expression, result); } else if (auto var = decl->to()) { LOG3("Variable to json " << var); auto result = new Util::JsonObject(); auto type = typeMap->getType(var, true); if (type->is()) { - result->emplace("type", "header"); - result->emplace("value", var->name); + result->emplace("type"_cs, "header"); + result->emplace("value"_cs, var->name); } else if (type->is() || (type->is() && (leftValue || simpleExpressionsOnly))) { // no conversion d2b when writing (leftValue is true) to a boolean - result->emplace("type", "field"); - auto e = mkArrayField(result, "value"); + result->emplace("type"_cs, "field"); + auto e = mkArrayField(result, "value"_cs); e->append(scalarsName); e->append(var->name); } else if (type->is()) { // varbits are synthesized in separate metadata instances // with a single field each, where the field is named // "field". - result->emplace("type", "field"); - auto e = mkArrayField(result, "value"); + result->emplace("type"_cs, "field"); + auto e = mkArrayField(result, "value"_cs); e->append(var->name); e->append("field"); } else if (type->is()) { // Boolean variables are stored as ints, so we have to insert a conversion when // reading such a variable - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto e = new Util::JsonObject(); - result->emplace("value", e); - e->emplace("op", "d2b"); // data to Boolean cast - e->emplace("left", Util::JsonValue::null); + result->emplace("value"_cs, e); + e->emplace("op"_cs, "d2b"); // data to Boolean cast + e->emplace("left"_cs, Util::JsonValue::null); auto r = new Util::JsonObject(); - e->emplace("right", r); - r->emplace("type", "field"); - auto f = mkArrayField(r, "value"); + e->emplace("right"_cs, r); + r->emplace("type"_cs, "field"); + auto f = mkArrayField(r, "value"_cs); f->append(scalarsName); f->append(var->name); } else if (auto st = type->to()) { auto et = typeMap->getTypeType(st->elementType, true); if (et->is()) - result->emplace("type", "header_union_stack"); + result->emplace("type"_cs, "header_union_stack"); else - result->emplace("type", "header_stack"); - result->emplace("value", var->name); + result->emplace("type"_cs, "header_stack"); + result->emplace("value"_cs, var->name); } else if (type->is()) { - result->emplace("type", "field"); - auto f = mkArrayField(result, "value"); + result->emplace("type"_cs, "field"); + auto f = mkArrayField(result, "value"_cs); f->append(scalarsName); f->append(var->name); } else { @@ -718,8 +718,8 @@ void ExpressionConverter::postorder(const IR::PathExpression *expression) { void ExpressionConverter::postorder(const IR::StringLiteral *expression) { auto result = new Util::JsonObject(); - result->emplace("type", "string"); - result->emplace("value", expression->value); + result->emplace("type"_cs, "string"); + result->emplace("value"_cs, expression->value); mapExpression(expression, result); } @@ -731,18 +731,18 @@ void ExpressionConverter::postorder(const IR::Slice *expression) { int h = expression->getH(); int l = expression->getL(); auto mask = Util::maskFromSlice(h, l); - result->emplace("type", "expression"); + result->emplace("type"_cs, "expression"); auto band = new Util::JsonObject(); - result->emplace("value", band); - band->emplace("op", "&"); + result->emplace("value"_cs, band); + band->emplace("op"_cs, "&"); auto right = new Util::JsonObject(); auto bitwidth = expression->type->width_bits(); - right->emplace("type", "hexstr"); - right->emplace("value", stringRepr(mask, ROUNDUP(bitwidth, 8))); + right->emplace("type"_cs, "hexstr"); + right->emplace("value"_cs, stringRepr(mask, ROUNDUP(bitwidth, 8))); auto le = get(expr); if (!le) return; - band->emplace("left", le); - band->emplace("right", right); + band->emplace("left"_cs, le); + band->emplace("right"_cs, right); mapExpression(expression, result); } @@ -785,27 +785,27 @@ Util::IJson *ExpressionConverter::convert(const IR::Expression *e, bool doFixup, auto type = typeMap->getType(e, true); if (convertBool && type->is()) { auto obj = new Util::JsonObject(); - obj->emplace("type", "expression"); + obj->emplace("type"_cs, "expression"); auto conv = new Util::JsonObject(); - obj->emplace("value", conv); - conv->emplace("op", "b2d"); // boolean to data cast - conv->emplace("left", Util::JsonValue::null); - conv->emplace("right", result); + obj->emplace("value"_cs, conv); + conv->emplace("op"_cs, "b2d"); // boolean to data cast + conv->emplace("left"_cs, Util::JsonValue::null); + conv->emplace("right"_cs, result); result = obj; } - std::set to_wrap({"expression", "stack_field"}); + std::set to_wrap({"expression"_cs, "stack_field"_cs}); // This is weird, but that's how it is: expression and stack_field must be wrapped in // another outer object. In a future version of the bmv2 JSON, this will not be needed // anymore as expressions will be treated in a more uniform way. if (wrap) { if (auto ro = result->to()) { - if (auto to = ro->get("type")) { + if (auto to = ro->get("type"_cs)) { if (auto jv = to->to()) { if (jv->isString() && to_wrap.find(jv->getString()) != to_wrap.end()) { auto rwrap = new Util::JsonObject(); - rwrap->emplace("type", "expression"); - rwrap->emplace("value", result); + rwrap->emplace("type"_cs, "expression"); + rwrap->emplace("value"_cs, result); result = rwrap; } } diff --git a/backends/bmv2/common/extern.cpp b/backends/bmv2/common/extern.cpp index 5af3931084..f7926b5bab 100644 --- a/backends/bmv2/common/extern.cpp +++ b/backends/bmv2/common/extern.cpp @@ -60,10 +60,10 @@ Util::IJson *ExternConverter::convertExternObject(ConversionContext *ctxt, if (emitExterns) { auto primitive = mkPrimitive("_" + em->originalExternType->name + "_" + em->method->name); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", mc->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, mc->sourceInfoJsonObj()); auto etr = new Util::JsonObject(); - etr->emplace("type", "extern"); - etr->emplace("value", em->object->controlPlaneName()); + etr->emplace("type"_cs, "extern"); + etr->emplace("value"_cs, em->object->controlPlaneName()); parameters->append(etr); for (auto arg : *mc->arguments) { auto args = ctxt->conv->convert(arg->expression); @@ -92,10 +92,10 @@ void ExternConverter::convertExternInstance(ConversionContext *ctxt, const IR::D cstring type; cstring value; if (auto cst = val->to()) { - type = "hexstr"; + type = "hexstr"_cs; value = Util::toString(cst->value, 0, false, 16); } else if (auto str = val->to()) { - type = "string"; + type = "string"_cs; value = str->value; } else { modelError("%1%: parameter type not unsupported", param->type); @@ -116,7 +116,7 @@ Util::IJson *ExternConverter::convertExternFunction(ConversionContext *ctxt, return nullptr; } auto primitive = mkPrimitive(ef->method->name); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto parameters = mkParameters(primitive); for (auto arg : *mc->arguments) { auto args = ctxt->conv->convert(arg->expression); @@ -161,14 +161,14 @@ void ExternConverter::addToFieldList(ConversionContext *ctxt, const IR::Expressi auto j = ctxt->conv->convert(expr); ctxt->conv->simpleExpressionsOnly = simple; // restore state if (auto jo = j->to()) { - if (auto t = jo->get("type")) { + if (auto t = jo->get("type"_cs)) { if (auto type = t->to()) { if (*type == "runtime_data") { // Can't have runtime_data in field lists -- need hexstr instead - auto val = jo->get("value")->to(); + auto val = jo->get("value"_cs)->to(); j = jo = new Util::JsonObject(); - jo->emplace("type", "hexstr"); - jo->emplace("value", stringRepr(val->getValue())); + jo->emplace("type"_cs, "hexstr"); + jo->emplace("value"_cs, stringRepr(val->getValue())); } } } @@ -182,10 +182,10 @@ int ExternConverter::createFieldList(ConversionContext *ctxt, const IR::Expressi auto fl = new Util::JsonObject(); field_lists->append(fl); int id = nextId(group); - fl->emplace("id", id); - fl->emplace("name", listName); - fl->emplace_non_null("source_info", expr->sourceInfoJsonObj()); - auto elements = mkArrayField(fl, "elements"); + fl->emplace("id"_cs, id); + fl->emplace("name"_cs, listName); + fl->emplace_non_null("source_info"_cs, expr->sourceInfoJsonObj()); + auto elements = mkArrayField(fl, "elements"_cs); addToFieldList(ctxt, expr, elements); return id; } @@ -196,11 +196,11 @@ cstring ExternConverter::createCalculation(ConversionContext *ctxt, cstring algo const IR::Node *sourcePositionNode = nullptr) { cstring calcName = ctxt->refMap->newName("calc_"); auto calc = new Util::JsonObject(); - calc->emplace("name", calcName); - calc->emplace("id", nextId("calculations")); + calc->emplace("name"_cs, calcName); + calc->emplace("id"_cs, nextId("calculations"_cs)); if (sourcePositionNode != nullptr) - calc->emplace_non_null("source_info", sourcePositionNode->sourceInfoJsonObj()); - calc->emplace("algo", algo); + calc->emplace_non_null("source_info"_cs, sourcePositionNode->sourceInfoJsonObj()); + calc->emplace("algo"_cs, algo); fields = convertToList(fields, ctxt->typeMap); if (!fields) { modelError("%1%: expected a struct", fields); @@ -211,36 +211,27 @@ cstring ExternConverter::createCalculation(ConversionContext *ctxt, cstring algo auto array = jright->to(); BUG_CHECK(array, "expected a JSON array"); auto payload = new Util::JsonObject(); - payload->emplace("type", "payload"); - payload->emplace("value", (Util::IJson *)nullptr); + payload->emplace("type"_cs, "payload"); + payload->emplace("value"_cs, (Util::IJson *)nullptr); array->append(payload); } - calc->emplace("input", jright); + calc->emplace("input"_cs, jright); calculations->append(calc); return calcName; } cstring ExternConverter::convertHashAlgorithm(cstring algorithm) { - cstring result; - if (algorithm == P4V1::V1Model::instance.algorithm.crc32.name) - result = "crc32"; - else if (algorithm == P4V1::V1Model::instance.algorithm.crc32_custom.name) - result = "crc32_custom"; - else if (algorithm == P4V1::V1Model::instance.algorithm.crc16.name) - result = "crc16"; - else if (algorithm == P4V1::V1Model::instance.algorithm.crc16_custom.name) - result = "crc16_custom"; - else if (algorithm == P4V1::V1Model::instance.algorithm.random.name) - result = "random"; - else if (algorithm == P4V1::V1Model::instance.algorithm.identity.name) - result = "identity"; - else if (algorithm == P4V1::V1Model::instance.algorithm.csum16.name) - result = "csum16"; - else if (algorithm == P4V1::V1Model::instance.algorithm.xor16.name) - result = "xor16"; - else - ::error(ErrorType::ERR_UNSUPPORTED, "Unsupported algorithm %1%", algorithm); - return result; + if (algorithm == P4V1::V1Model::instance.algorithm.crc32.name) return "crc32"_cs; + if (algorithm == P4V1::V1Model::instance.algorithm.crc32_custom.name) return "crc32_custom"_cs; + if (algorithm == P4V1::V1Model::instance.algorithm.crc16.name) return "crc16"_cs; + if (algorithm == P4V1::V1Model::instance.algorithm.crc16_custom.name) return "crc16_custom"_cs; + if (algorithm == P4V1::V1Model::instance.algorithm.random.name) return "random"_cs; + if (algorithm == P4V1::V1Model::instance.algorithm.identity.name) return "identity"_cs; + if (algorithm == P4V1::V1Model::instance.algorithm.csum16.name) return "csum16"_cs; + if (algorithm == P4V1::V1Model::instance.algorithm.xor16.name) return "xor16"_cs; + + ::error(ErrorType::ERR_UNSUPPORTED, "Unsupported algorithm %1%", algorithm); + return cstring::empty; } ExternConverter_assert ExternConverter_assert::singleton; @@ -260,7 +251,7 @@ Util::IJson *ExternConverter::convertAssertAssume(ConversionContext *ctxt, // cast the result of expression to b2d auto jsonExpr = ctxt->conv->convert(cond->expression, true, true, true); parameters->append(jsonExpr); - primitive->emplace_non_null("source_info", methodCall->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, methodCall->sourceInfoJsonObj()); return primitive; } diff --git a/backends/bmv2/common/extern.h b/backends/bmv2/common/extern.h index 18dc14054e..463b12b441 100644 --- a/backends/bmv2/common/extern.h +++ b/backends/bmv2/common/extern.h @@ -74,7 +74,7 @@ class ExternConverter { class ExternConverter_##extern_name : public ExternConverter { \ model_type &model_name; \ ExternConverter_##extern_name() : model_name(model_type::instance) { \ - registerExternConverter(#extern_name, this); \ + registerExternConverter(cstring(#extern_name), this); \ } \ static ExternConverter_##extern_name singleton; \ Util::IJson *convertExternFunction(ConversionContext *ctxt, const P4::ExternFunction *ef, \ @@ -85,7 +85,7 @@ class ExternConverter { #define EXTERN_CONVERTER_W_FUNCTION(extern_name) \ class ExternConverter_##extern_name : public ExternConverter { \ - ExternConverter_##extern_name() { registerExternConverter(#extern_name, this); } \ + ExternConverter_##extern_name() { registerExternConverter(cstring(#extern_name), this); } \ static ExternConverter_##extern_name singleton; \ Util::IJson *convertExternFunction(ConversionContext *ctxt, const P4::ExternFunction *ef, \ const IR::MethodCallExpression *mc, \ @@ -97,26 +97,26 @@ class ExternConverter { class ExternConverter_##extern_name : public ExternConverter { \ model_type &model_name; \ ExternConverter_##extern_name() : model_name(model_type::instance) { \ - registerExternConverter(#extern_name, this); \ + registerExternConverter(cstring(#extern_name), this); \ } \ static ExternConverter_##extern_name singleton; \ void convertExternInstance(ConversionContext *ctxt, const IR::Declaration *c, \ const IR::ExternBlock *eb, const bool &emitExterns) override; \ }; -#define EXTERN_CONVERTER_W_INSTANCE(extern_name) \ - class ExternConverter_##extern_name : public ExternConverter { \ - ExternConverter_##extern_name() { registerExternConverter(#extern_name, this); } \ - static ExternConverter_##extern_name singleton; \ - void convertExternInstance(ConversionContext *ctxt, const IR::Declaration *c, \ - const IR::ExternBlock *eb, const bool &emitExterns) override; \ +#define EXTERN_CONVERTER_W_INSTANCE(extern_name) \ + class ExternConverter_##extern_name : public ExternConverter { \ + ExternConverter_##extern_name() { registerExternConverter(cstring(#extern_name), this); } \ + static ExternConverter_##extern_name singleton; \ + void convertExternInstance(ConversionContext *ctxt, const IR::Declaration *c, \ + const IR::ExternBlock *eb, const bool &emitExterns) override; \ }; #define EXTERN_CONVERTER_W_OBJECT_AND_INSTANCE_AND_MODEL(extern_name, type, name) \ class ExternConverter_##extern_name : public ExternConverter { \ type &name; \ ExternConverter_##extern_name() : name(type::instance) { \ - registerExternConverter(#extern_name, this); \ + registerExternConverter(cstring(#extern_name), this); \ } \ static ExternConverter_##extern_name singleton; \ void convertExternInstance(ConversionContext *ctxt, const IR::Declaration *c, \ @@ -127,16 +127,16 @@ class ExternConverter { const bool &emitExterns) override; \ }; -#define EXTERN_CONVERTER_W_OBJECT_AND_INSTANCE(extern_name) \ - class ExternConverter_##extern_name : public ExternConverter { \ - ExternConverter_##extern_name() { registerExternConverter(#extern_name, this); } \ - static ExternConverter_##extern_name singleton; \ - void convertExternInstance(ConversionContext *ctxt, const IR::Declaration *c, \ - const IR::ExternBlock *eb, const bool &emitExterns) override; \ - Util::IJson *convertExternObject(ConversionContext *ctxt, const P4::ExternMethod *em, \ - const IR::MethodCallExpression *mc, \ - const IR::StatOrDecl *s, \ - const bool &emitExterns) override; \ +#define EXTERN_CONVERTER_W_OBJECT_AND_INSTANCE(extern_name) \ + class ExternConverter_##extern_name : public ExternConverter { \ + ExternConverter_##extern_name() { registerExternConverter(cstring(#extern_name), this); } \ + static ExternConverter_##extern_name singleton; \ + void convertExternInstance(ConversionContext *ctxt, const IR::Declaration *c, \ + const IR::ExternBlock *eb, const bool &emitExterns) override; \ + Util::IJson *convertExternObject(ConversionContext *ctxt, const P4::ExternMethod *em, \ + const IR::MethodCallExpression *mc, \ + const IR::StatOrDecl *s, \ + const bool &emitExterns) override; \ }; EXTERN_CONVERTER_W_FUNCTION(assert) diff --git a/backends/bmv2/common/header.cpp b/backends/bmv2/common/header.cpp index 0a059d86bd..ff1b158a3d 100644 --- a/backends/bmv2/common/header.cpp +++ b/backends/bmv2/common/header.cpp @@ -287,7 +287,7 @@ void HeaderConverter::addHeaderType(const IR::Type_StructLike *st) { LOG2("... creating aliases for metadata fields " << st); for (auto f : st->fields) { - if (auto aliasAnnotation = f->getAnnotation("alias")) { + if (auto aliasAnnotation = f->getAnnotation("alias"_cs)) { auto container = new Util::JsonArray(); auto alias = new Util::JsonArray(); auto target_name = ""; @@ -399,7 +399,7 @@ Visitor::profile_t HeaderConverter::init_apply(const IR::Node *node) { // always-have metadata instance ctxt->json->add_metadata(scalarsTypeName, scalarsName); - ctxt->json->add_metadata("standard_metadata", "standard_metadata"); + ctxt->json->add_metadata("standard_metadata"_cs, "standard_metadata"_cs); return Inspector::init_apply(node); } @@ -443,7 +443,7 @@ bool HeaderConverter::preorder(const IR::Parameter *param) { else visitedHeaders.emplace(st->getName()); - if (st->getAnnotation("metadata")) { + if (st->getAnnotation("metadata"_cs)) { addHeaderType(st); } else { auto isHeader = isHeaders(st); diff --git a/backends/bmv2/common/helpers.cpp b/backends/bmv2/common/helpers.cpp index 3fc64dc49b..15cc47bbe8 100644 --- a/backends/bmv2/common/helpers.cpp +++ b/backends/bmv2/common/helpers.cpp @@ -19,12 +19,12 @@ limitations under the License. namespace BMV2 { /// constant definition for bmv2 -const cstring MatchImplementation::selectorMatchTypeName = "selector"; -const cstring MatchImplementation::rangeMatchTypeName = "range"; -const cstring MatchImplementation::optionalMatchTypeName = "optional"; +const cstring MatchImplementation::selectorMatchTypeName = "selector"_cs; +const cstring MatchImplementation::rangeMatchTypeName = "range"_cs; +const cstring MatchImplementation::optionalMatchTypeName = "optional"_cs; const unsigned TableAttributes::defaultTableSize = 1024; -const cstring V1ModelProperties::jsonMetadataParameterName = "standard_metadata"; -const cstring V1ModelProperties::validField = "$valid$"; +const cstring V1ModelProperties::jsonMetadataParameterName = "standard_metadata"_cs; +const cstring V1ModelProperties::validField = "$valid$"_cs; Util::IJson *nodeName(const CFG::Node *node) { if (node->name.isNullOrEmpty()) @@ -40,26 +40,26 @@ Util::JsonArray *mkArrayField(Util::JsonObject *parent, cstring name) { } Util::JsonArray *mkParameters(Util::JsonObject *object) { - return mkArrayField(object, "parameters"); + return mkArrayField(object, "parameters"_cs); } Util::JsonObject *mkPrimitive(cstring name, Util::JsonArray *appendTo) { auto result = new Util::JsonObject(); - result->emplace("op", name); + result->emplace("op"_cs, name); appendTo->append(result); return result; } Util::JsonObject *mkPrimitive(cstring name) { auto result = new Util::JsonObject(); - result->emplace("op", name); + result->emplace("op"_cs, name); return result; } cstring stringRepr(big_int value, unsigned bytes) { - cstring sign = ""; + std::string sign; std::stringstream r; - cstring filler = ""; + std::string filler; if (value < 0) { value = -value; sign = "-"; @@ -109,14 +109,14 @@ void ConversionContext::addToFieldList(const IR::Expression *expr, Util::JsonArr auto j = conv->convert(expr); conv->simpleExpressionsOnly = simple; // restore state if (auto jo = j->to()) { - if (auto t = jo->get("type")) { + if (auto t = jo->get("type"_cs)) { if (auto type = t->to()) { if (*type == "runtime_data") { // Can't have runtime_data in field lists -- need hexstr instead - auto val = jo->get("value")->to(); + auto val = jo->get("value"_cs)->to(); j = jo = new Util::JsonObject(); - jo->emplace("type", "hexstr"); - jo->emplace("value", stringRepr(val->getValue())); + jo->emplace("type"_cs, "hexstr"); + jo->emplace("value"_cs, stringRepr(val->getValue())); } } } @@ -128,17 +128,17 @@ int ConversionContext::createFieldList(const IR::Expression *expr, cstring listN cstring group; auto fl = new Util::JsonObject(); if (learn) { - group = "learn_lists"; + group = "learn_lists"_cs; json->learn_lists->append(fl); } else { - group = "field_lists"; + group = "field_lists"_cs; json->field_lists->append(fl); } int id = nextId(group); - fl->emplace("id", id); - fl->emplace("name", listName); - fl->emplace_non_null("source_info", expr->sourceInfoJsonObj()); - auto elements = mkArrayField(fl, "elements"); + fl->emplace("id"_cs, id); + fl->emplace("name"_cs, listName); + fl->emplace_non_null("source_info"_cs, expr->sourceInfoJsonObj()); + auto elements = mkArrayField(fl, "elements"_cs); addToFieldList(expr, elements); return id; } @@ -153,11 +153,11 @@ cstring ConversionContext::createCalculation(cstring algo, const IR::Expression const IR::Node *sourcePositionNode = nullptr) { cstring calcName = refMap->newName("calc_"); auto calc = new Util::JsonObject(); - calc->emplace("name", calcName); - calc->emplace("id", nextId("calculations")); + calc->emplace("name"_cs, calcName); + calc->emplace("id"_cs, nextId("calculations"_cs)); if (sourcePositionNode != nullptr) - calc->emplace_non_null("source_info", sourcePositionNode->sourceInfoJsonObj()); - calc->emplace("algo", algo); + calc->emplace_non_null("source_info"_cs, sourcePositionNode->sourceInfoJsonObj()); + calc->emplace("algo"_cs, algo); auto listFields = convertToList(fields, typeMap); if (!listFields) { modelError("%1%: expected a struct", fields); @@ -168,11 +168,11 @@ cstring ConversionContext::createCalculation(cstring algo, const IR::Expression auto array = jright->to(); BUG_CHECK(array, "expected a JSON array"); auto payload = new Util::JsonObject(); - payload->emplace("type", "payload"); - payload->emplace("value", (Util::IJson *)nullptr); + payload->emplace("type"_cs, "payload"_cs); + payload->emplace("value"_cs, (Util::IJson *)nullptr); array->append(payload); } - calc->emplace("input", jright); + calc->emplace("input"_cs, jright); calculations->append(calc); return calcName; } diff --git a/backends/bmv2/common/helpers.h b/backends/bmv2/common/helpers.h index c92415257b..6ce84f6d9a 100644 --- a/backends/bmv2/common/helpers.h +++ b/backends/bmv2/common/helpers.h @@ -30,6 +30,8 @@ limitations under the License. namespace BMV2 { +using namespace P4::literals; + #ifndef UNUSED #define UNUSED __attribute__((__unused__)) #endif @@ -75,12 +77,12 @@ struct ActionProfileTraits; template <> struct ActionProfileTraits { - static const cstring name() { return "action profile"; } + static const cstring name() { return "action profile"_cs; } static const cstring propertyName() { return P4V1::V1Model::instance.tableAttributes.tableImplementation.name; } static const cstring typeName() { return P4V1::V1Model::instance.action_profile.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } }; template <> @@ -88,10 +90,10 @@ struct ActionProfileTraits : public ActionProfileTraits struct ActionProfileTraits { - static const cstring name() { return "action profile"; } - static const cstring propertyName() { return "implementation"; } - static const cstring typeName() { return "ActionProfile"; } - static const cstring sizeParamName() { return "size"; } + static const cstring name() { return "action profile"_cs; } + static const cstring propertyName() { return "implementation"_cs; } + static const cstring typeName() { return "ActionProfile"_cs; } + static const cstring sizeParamName() { return "size"_cs; } }; /// Traits for the action selector extern, must be specialized for v1model and @@ -101,7 +103,7 @@ struct ActionSelectorTraits; template <> struct ActionSelectorTraits : public ActionProfileTraits { - static const cstring name() { return "action selector"; } + static const cstring name() { return "action selector"_cs; } static const cstring typeName() { return P4V1::V1Model::instance.action_selector.name; } }; @@ -110,8 +112,8 @@ struct ActionSelectorTraits : public ActionProfileTraits struct ActionSelectorTraits : public ActionProfileTraits { - static const cstring name() { return "action selector"; } - static const cstring typeName() { return "ActionSelector"; } + static const cstring name() { return "action selector"_cs; } + static const cstring typeName() { return "ActionSelector"_cs; } }; /// Traits for the register extern, must be specialized for v1model and PSA. @@ -120,9 +122,9 @@ struct RegisterTraits; template <> struct RegisterTraits { - static const cstring name() { return "register"; } + static const cstring name() { return "register"_cs; } static const cstring typeName() { return P4V1::V1Model::instance.registers.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } /// the index of the type parameter for the data stored in the register, in /// the type parameter list of the extern type declaration. static size_t dataTypeParamIdx() { return 0; } @@ -136,9 +138,9 @@ struct RegisterTraits : public RegisterTraits template <> struct RegisterTraits { - static const cstring name() { return "register"; } - static const cstring typeName() { return "Register"; } - static const cstring sizeParamName() { return "size"; } + static const cstring name() { return "register"_cs; } + static const cstring typeName() { return "Register"_cs; } + static const cstring sizeParamName() { return "size"_cs; } static size_t dataTypeParamIdx() { return 0; } /// the index of the type parameter for the register index, in the type /// parameter list of the extern type declaration. @@ -174,36 +176,36 @@ struct CounterlikeTraits; /// @ref CounterlikeTraits<> specialization for @ref CounterExtern for v1model template <> struct CounterlikeTraits> { - static const cstring name() { return "counter"; } + static const cstring name() { return "counter"_cs; } static const cstring directPropertyName() { return P4V1::V1Model::instance.tableAttributes.counters.name; } static const cstring typeName() { return P4V1::V1Model::instance.counter.name; } static const cstring directTypeName() { return P4V1::V1Model::instance.directCounter.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } static std::optional indexTypeParamIdx() { return std::nullopt; } }; template <> struct CounterlikeTraits> { - static const cstring name() { return "counter"; } + static const cstring name() { return "counter"_cs; } static const cstring directPropertyName() { return P4V1::V1Model::instance.tableAttributes.counters.name; } static const cstring typeName() { return P4V1::V1Model::instance.counter.name; } static const cstring directTypeName() { return P4V1::V1Model::instance.directCounter.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } static std::optional indexTypeParamIdx() { return 0; } }; /// @ref CounterlikeTraits<> specialization for @ref CounterExtern for PSA template <> struct CounterlikeTraits> { - static const cstring name() { return "counter"; } - static const cstring directPropertyName() { return "psa_direct_counter"; } - static const cstring typeName() { return "Counter"; } - static const cstring directTypeName() { return "DirectCounter"; } - static const cstring sizeParamName() { return "n_counters"; } + static const cstring name() { return "counter"_cs; } + static const cstring directPropertyName() { return "psa_direct_counter"_cs; } + static const cstring typeName() { return "Counter"_cs; } + static const cstring directTypeName() { return "DirectCounter"_cs; } + static const cstring sizeParamName() { return "n_counters"_cs; } /// the index of the type parameter for the counter index, in the type /// parameter list of the extern type declaration. static std::optional indexTypeParamIdx() { return 1; } @@ -212,36 +214,36 @@ struct CounterlikeTraits> { /// @ref CounterlikeTraits<> specialization for @ref MeterExtern for v1model template <> struct CounterlikeTraits> { - static const cstring name() { return "meter"; } + static const cstring name() { return "meter"_cs; } static const cstring directPropertyName() { return P4V1::V1Model::instance.tableAttributes.meters.name; } static const cstring typeName() { return P4V1::V1Model::instance.meter.name; } static const cstring directTypeName() { return P4V1::V1Model::instance.directMeter.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } static std::optional indexTypeParamIdx() { return std::nullopt; } }; template <> struct CounterlikeTraits> { - static const cstring name() { return "meter"; } + static const cstring name() { return "meter"_cs; } static const cstring directPropertyName() { return P4V1::V1Model::instance.tableAttributes.meters.name; } static const cstring typeName() { return P4V1::V1Model::instance.meter.name; } static const cstring directTypeName() { return P4V1::V1Model::instance.directMeter.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } static std::optional indexTypeParamIdx() { return 0; } }; /// @ref CounterlikeTraits<> specialization for @ref MeterExtern for PSA template <> struct CounterlikeTraits> { - static const cstring name() { return "meter"; } - static const cstring directPropertyName() { return "psa_direct_meter"; } - static const cstring typeName() { return "Meter"; } - static const cstring directTypeName() { return "DirectMeter"; } - static const cstring sizeParamName() { return "n_meters"; } + static const cstring name() { return "meter"_cs; } + static const cstring directPropertyName() { return "psa_direct_meter"_cs; } + static const cstring typeName() { return "Meter"_cs; } + static const cstring directTypeName() { return "DirectMeter"_cs; } + static const cstring sizeParamName() { return "n_meters"_cs; } /// the index of the type parameter for the meter index, in the type /// parameter list of the extern type declaration. static std::optional indexTypeParamIdx() { return 0; } diff --git a/backends/bmv2/common/midend.h b/backends/bmv2/common/midend.h index f976bec4bf..1a4d7e73b2 100644 --- a/backends/bmv2/common/midend.h +++ b/backends/bmv2/common/midend.h @@ -33,7 +33,7 @@ class EnumOn32Bits : public P4::ChooseEnumRepresentation { bool convert(const IR::Type_Enum *type) const override { if (type->srcInfo.isValid()) { auto sourceFile = type->srcInfo.getSourceFile(); - if (sourceFile.endsWith(filename)) + if (sourceFile.endsWith(filename.string_view())) // Don't convert any of the standard enums return false; } diff --git a/backends/bmv2/common/options.h b/backends/bmv2/common/options.h index 48b12a12b9..108904e0cc 100644 --- a/backends/bmv2/common/options.h +++ b/backends/bmv2/common/options.h @@ -44,7 +44,7 @@ class BMV2Options : public CompilerOptions { registerOption( "-o", "outfile", [this](const char *arg) { - outputFile = arg; + outputFile = cstring(arg); return true; }, "Write output to outfile"); @@ -52,7 +52,7 @@ class BMV2Options : public CompilerOptions { "--fromJSON", "file", [this](const char *arg) { loadIRFromJson = true; - file = arg; + file = cstring(arg); return true; }, "Use IR representation from JsonFile dumped previously," diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index a2a21110fe..4f105f8c42 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -26,23 +26,23 @@ limitations under the License. namespace BMV2 { cstring ParserConverter::jsonAssignment(const IR::Type *type) { - if (type->is()) return "assign_union"; - if (type->is() || type->is()) return "assign_header"; + if (type->is()) return "assign_union"_cs; + if (type->is() || type->is()) return "assign_header"_cs; if (auto ts = type->to()) { auto et = ts->elementType; if (et->is()) - return "assign_union_stack"; + return "assign_union_stack"_cs; else - return "assign_header_stack"; + return "assign_header_stack"_cs; } // Unfortunately set can do some things that assign cannot, e.g., handle // lookahead on the RHS. - return "set"; + return "set"_cs; } Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) { auto result = new Util::JsonObject(); - auto params = mkArrayField(result, "parameters"); + auto params = mkArrayField(result, "parameters"_cs); auto isR = false; IR::MethodCallExpression *mce2 = nullptr; if (stat->is()) { @@ -104,7 +104,7 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) auto assign = stat->to(); auto type = ctxt->typeMap->getType(assign->left, true); cstring operation = jsonAssignment(type); - result->emplace("op", operation); + result->emplace("op"_cs, operation); auto l = ctxt->conv->convertLeftValue(assign->left); bool convertBool = type->is(); auto r = ctxt->conv->convert(assign->right, true, true, convertBool); @@ -114,7 +114,7 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) if (operation != "set") { // must wrap into another outer object auto wrap = new Util::JsonObject(); - wrap->emplace("op", "primitive"); + wrap->emplace("op"_cs, "primitive"); auto params = mkParameters(wrap); params->append(result); result = wrap; @@ -134,8 +134,8 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) return result; } - cstring ename = argCount == 1 ? "extract" : "extract_VL"; - result->emplace("op", ename); + cstring ename = argCount == 1 ? "extract"_cs : "extract_VL"_cs; + result->emplace("op"_cs, ename); auto arg = mce->arguments->at(0); auto argtype = ctxt->typeMap->getType(arg->expression, true); if (!argtype->is()) { @@ -154,7 +154,7 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) if (baseType->is()) { if (mem->member == IR::Type_Stack::next) { // stack.next - type = "stack"; + type = "stack"_cs; j = ctxt->conv->convert(mem->expr); } else { BUG("%1%: unsupported", mem); @@ -166,20 +166,20 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) if (parentType->is()) { // stack.next.unionfield if (parent->member == IR::Type_Stack::next) { - type = "union_stack"; + type = "union_stack"_cs; j = ctxt->conv->convert(parent->expr); Util::JsonArray *a; if (j->is()) { a = j->to()->clone(); } else if (j->is()) { a = new Util::JsonArray(); - a->push_back(j->to()->get("value")); + a->push_back(j->to()->get("value"_cs)); } else { BUG("unexpected"); } a->append(mem->member.name); auto j0 = new Util::JsonObject(); - j = j0->emplace("value", a); + j = j0->emplace("value"_cs, a); } else { BUG("%1%: unsupported", mem); } @@ -188,12 +188,12 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) } } if (j == nullptr) { - type = "regular"; + type = "regular"_cs; j = ctxt->conv->convert(arg->expression); } - auto value = j->to()->get("value"); - param->emplace("type", type); - param->emplace("value", value); + auto value = j->to()->get("value"_cs); + param->emplace("type"_cs, type); + param->emplace("value"_cs, value); if (argCount == 2) { auto arg2 = mce->arguments->at(1); @@ -202,8 +202,8 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) // does not do that. auto jexpr = ctxt->conv->convert(arg2->expression, true, false); auto rwrap = new Util::JsonObject(); - rwrap->emplace("type", "expression"); - rwrap->emplace("value", jexpr); + rwrap->emplace("type"_cs, "expression"); + rwrap->emplace("value"_cs, jexpr); params->append(rwrap); } return result; @@ -218,7 +218,7 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) } auto arg = mce->arguments->at(0); auto jexpr = ctxt->conv->convert(arg->expression, true, false); - result->emplace("op", "advance"); + result->emplace("op"_cs, "advance"); params->append(jexpr); return result; } else if ((extmeth->originalExternType->name == "InternetChecksum" && @@ -236,7 +236,7 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) json = ExternConverter::cvtExternObject(ctxt, extmeth, mce, stat, true); } if (json) { - result->emplace("op", "primitive"); + result->emplace("op"_cs, "primitive"); params->append(json); } return result; @@ -245,7 +245,7 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) auto extfn = minst->to(); auto extFuncName = extfn->method->name.name; if (extFuncName == IR::ParserState::verify) { - result->emplace("op", "verify"); + result->emplace("op"_cs, "verify"); BUG_CHECK(mce->arguments->size() == 2, "%1%: Expected 2 arguments", mce); { auto cond = mce->arguments->at(0); @@ -264,19 +264,19 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) return result; } else if (extFuncName == "assert" || extFuncName == "assume") { BUG_CHECK(mce->arguments->size() == 1, "%1%: Expected 1 argument ", mce); - result->emplace("op", "primitive"); + result->emplace("op"_cs, "primitive"); auto paramValue = new Util::JsonObject(); params->append(paramValue); - auto paramsArray = mkArrayField(paramValue, "parameters"); + auto paramsArray = mkArrayField(paramValue, "parameters"_cs); auto cond = mce->arguments->at(0); auto expr = ctxt->conv->convert(cond->expression, true, true, true); paramsArray->append(expr); - paramValue->emplace("op", extFuncName); - paramValue->emplace_non_null("source_info", mce->sourceInfoJsonObj()); + paramValue->emplace("op"_cs, extFuncName); + paramValue->emplace_non_null("source_info"_cs, mce->sourceInfoJsonObj()); } else if (extFuncName == P4V1::V1Model::instance.log_msg.name) { BUG_CHECK(mce->arguments->size() == 2 || mce->arguments->size() == 1, "%1%: Expected 1 or 2 arguments", mce); - result->emplace("op", "primitive"); + result->emplace("op"_cs, "primitive"); auto ef = minst->to(); auto ijson = ExternConverter::cvtExternFunction(ctxt, ef, mce, stat, false); params->append(ijson); @@ -293,27 +293,27 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) ], "op" : "primitive" } */ - result->emplace("op", "primitive"); + result->emplace("op"_cs, "primitive"); auto bi = minst->to(); cstring primitive; auto paramsValue = new Util::JsonObject(); params->append(paramsValue); - auto pp = mkArrayField(paramsValue, "parameters"); + auto pp = mkArrayField(paramsValue, "parameters"_cs); auto obj = ctxt->conv->convert(bi->appliedTo); pp->append(obj); if (bi->name == IR::Type_Header::setValid) { - primitive = "add_header"; + primitive = "add_header"_cs; } else if (bi->name == IR::Type_Header::setInvalid) { - primitive = "remove_header"; + primitive = "remove_header"_cs; } else if (bi->name == IR::Type_Stack::push_front || bi->name == IR::Type_Stack::pop_front) { if (bi->name == IR::Type_Stack::push_front) - primitive = "push"; + primitive = "push"_cs; else - primitive = "pop"; + primitive = "pop"_cs; BUG_CHECK(mce->arguments->size() == 1, "Expected 1 argument for %1%", mce); auto arg = ctxt->conv->convert(mce->arguments->at(0)->expression); @@ -322,7 +322,7 @@ Util::IJson *ParserConverter::convertParserStatement(const IR::StatOrDecl *stat) BUG("%1%: Unexpected built-in method", bi->name); } - paramsValue->emplace("op", primitive); + paramsValue->emplace("op"_cs, primitive); return result; } } @@ -460,24 +460,24 @@ std::vector ParserConverter::convertSelectExpression( cstring vset_name; unsigned bytes = combine(sc->keyset, se->select, value, mask, is_vset, vset_name); if (is_vset) { - trans->emplace("type", "parse_vset"); - trans->emplace("value", vset_name); - trans->emplace("mask", Util::JsonValue::null); - trans->emplace("next_state", stateName(sc->state->path->name)); + trans->emplace("type"_cs, "parse_vset"); + trans->emplace("value"_cs, vset_name); + trans->emplace("mask"_cs, Util::JsonValue::null); + trans->emplace("next_state"_cs, stateName(sc->state->path->name)); } else { if (mask == 0) { - trans->emplace("type", "default"); - trans->emplace("value", Util::JsonValue::null); - trans->emplace("mask", Util::JsonValue::null); - trans->emplace("next_state", stateName(sc->state->path->name)); + trans->emplace("type"_cs, "default"); + trans->emplace("value"_cs, Util::JsonValue::null); + trans->emplace("mask"_cs, Util::JsonValue::null); + trans->emplace("next_state"_cs, stateName(sc->state->path->name)); } else { - trans->emplace("type", "hexstr"); - trans->emplace("value", stringRepr(value, bytes)); + trans->emplace("type"_cs, "hexstr"); + trans->emplace("value"_cs, stringRepr(value, bytes)); if (mask == -1) - trans->emplace("mask", Util::JsonValue::null); + trans->emplace("mask"_cs, Util::JsonValue::null); else - trans->emplace("mask", stringRepr(mask, bytes)); - trans->emplace("next_state", stateName(sc->state->path->name)); + trans->emplace("mask"_cs, stringRepr(mask, bytes)); + trans->emplace("next_state"_cs, stateName(sc->state->path->name)); } } result.push_back(trans); @@ -494,19 +494,19 @@ Util::IJson *ParserConverter::convertSelectKey(const IR::SelectExpression *expr) Util::IJson *ParserConverter::convertPathExpression(const IR::PathExpression *pe) { auto trans = new Util::JsonObject(); - trans->emplace("type", "default"); - trans->emplace("value", Util::JsonValue::null); - trans->emplace("mask", Util::JsonValue::null); - trans->emplace("next_state", stateName(pe->path->name)); + trans->emplace("type"_cs, "default"); + trans->emplace("value"_cs, Util::JsonValue::null); + trans->emplace("mask"_cs, Util::JsonValue::null); + trans->emplace("next_state"_cs, stateName(pe->path->name)); return trans; } Util::IJson *ParserConverter::createDefaultTransition() { auto trans = new Util::JsonObject(); - trans->emplace("type", "default"); - trans->emplace("value", Util::JsonValue::null); - trans->emplace("mask", Util::JsonValue::null); - trans->emplace("next_state", Util::JsonValue::null); + trans->emplace("type"_cs, "default"); + trans->emplace("value"_cs, Util::JsonValue::null); + trans->emplace("mask"_cs, Util::JsonValue::null); + trans->emplace("next_state"_cs, Util::JsonValue::null); return trans; } diff --git a/backends/bmv2/common/parser.h b/backends/bmv2/common/parser.h index 97e611d1cf..d2c6fe0ee4 100644 --- a/backends/bmv2/common/parser.h +++ b/backends/bmv2/common/parser.h @@ -48,7 +48,7 @@ class ParserConverter : public Inspector { public: bool preorder(const IR::P4Parser *p) override; - explicit ParserConverter(ConversionContext *ctxt, cstring name = "parser") + explicit ParserConverter(ConversionContext *ctxt, cstring name = "parser"_cs) : ctxt(ctxt), name(name), corelib(P4::P4CoreLibrary::instance()) { setName("ParserConverter"); } diff --git a/backends/bmv2/common/sharedActionSelectorCheck.h b/backends/bmv2/common/sharedActionSelectorCheck.h index 0cb68d570b..ed875ecc9c 100644 --- a/backends/bmv2/common/sharedActionSelectorCheck.h +++ b/backends/bmv2/common/sharedActionSelectorCheck.h @@ -69,7 +69,7 @@ class SharedActionSelectorCheck : public Inspector { } bool preorder(const IR::P4Table *table) override { - auto implementation = table->properties->getProperty("implementation"); + auto implementation = table->properties->getProperty("implementation"_cs); if (implementation == nullptr) return false; if (!implementation->value->is()) { ::error(ErrorType::ERR_EXPECTED, "%1%: expected expression for property", diff --git a/backends/bmv2/psa_switch/main.cpp b/backends/bmv2/psa_switch/main.cpp index bbd7604ffb..4694e02fad 100644 --- a/backends/bmv2/psa_switch/main.cpp +++ b/backends/bmv2/psa_switch/main.cpp @@ -43,7 +43,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoPsaSwitchContext(new BMV2::PsaSwitchContext); auto &options = BMV2::PsaSwitchContext::get().options(); options.langVersion = CompilerOptions::FrontendVersion::P4_16; - options.compilerVersion = BMV2_PSA_VERSION_STRING; + options.compilerVersion = cstring(BMV2_PSA_VERSION_STRING); if (options.process(argc, argv) != nullptr) { if (options.loadIRFromJson == false) options.setInputFile(); diff --git a/backends/bmv2/psa_switch/midend.cpp b/backends/bmv2/psa_switch/midend.cpp index f782342be3..be044d82bb 100644 --- a/backends/bmv2/psa_switch/midend.cpp +++ b/backends/bmv2/psa_switch/midend.cpp @@ -64,6 +64,8 @@ limitations under the License. namespace BMV2 { +using namespace P4::literals; + /// This class implements a policy suitable for the ConvertEnums pass. /// The policy is: convert all enums that are not part of the psa. /// Use 32-bit values for all enums. @@ -76,7 +78,7 @@ class PsaEnumOn32Bits : public P4::ChooseEnumRepresentation { if (type->name == "PSA_MeterColor_t") return true; if (type->srcInfo.isValid()) { auto sourceFile = type->srcInfo.getSourceFile(); - if (sourceFile.endsWith(filename)) + if (sourceFile.endsWith(filename.string_view())) // Don't convert any of the standard enums return false; } @@ -90,7 +92,7 @@ class PsaEnumOn32Bits : public P4::ChooseEnumRepresentation { PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStream) : MidEnd(options) { - auto convertEnums = new P4::ConvertEnums(&refMap, &typeMap, new PsaEnumOn32Bits("psa.p4")); + auto convertEnums = new P4::ConvertEnums(&refMap, &typeMap, new PsaEnumOn32Bits("psa.p4"_cs)); auto evaluator = new P4::EvaluatorPass(&refMap, &typeMap); std::function policy = [=](const Context *, const IR::Expression *e) -> bool { @@ -143,8 +145,9 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStre new PassRepeated({new P4::ConstantFolding(&refMap, &typeMap), new P4::StrengthReduction(&refMap, &typeMap)}), new P4::MoveDeclarations(), - new P4::ValidateTableProperties({"psa_implementation", "psa_direct_counter", - "psa_direct_meter", "psa_idle_timeout", "size"}), + new P4::ValidateTableProperties({"psa_implementation"_cs, "psa_direct_counter"_cs, + "psa_direct_meter"_cs, "psa_idle_timeout"_cs, + "size"_cs}), new P4::SimplifyControlFlow(&refMap, &typeMap), new P4::CompileTimeOperations(), new P4::TableHit(&refMap, &typeMap), @@ -157,7 +160,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStre [this, evaluator]() { toplevel = evaluator->getToplevelBlock(); }, }); if (options.listMidendPasses) { - listPasses(*outStream, "\n"); + listPasses(*outStream, cstring::newline); *outStream << std::endl; return; } @@ -165,7 +168,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStre removePasses(options.passesToExcludeMidend); } } else { - auto fillEnumMap = new P4::FillEnumMap(new PsaEnumOn32Bits("psa.p4"), &typeMap); + auto fillEnumMap = new P4::FillEnumMap(new PsaEnumOn32Bits("psa.p4"_cs), &typeMap); addPasses({ new P4::ResolveReferences(&refMap), new P4::TypeChecking(&refMap, &typeMap), diff --git a/backends/bmv2/psa_switch/options.cpp b/backends/bmv2/psa_switch/options.cpp index f1bb1ccf97..d6e7a1a4e3 100644 --- a/backends/bmv2/psa_switch/options.cpp +++ b/backends/bmv2/psa_switch/options.cpp @@ -5,9 +5,11 @@ namespace BMV2 { +using namespace P4::literals; + std::vector *PsaSwitchOptions::process(int argc, char *const argv[]) { searchForIncludePath(p4includePath, - {"p4include/bmv2", "../p4include/bmv2", "../../p4include/bmv2"}, + {"p4include/bmv2"_cs, "../p4include/bmv2"_cs, "../../p4include/bmv2"_cs}, exename(argv[0])); auto remainingOptions = CompilerOptions::process(argc, argv); diff --git a/backends/bmv2/psa_switch/psaProgramStructure.cpp b/backends/bmv2/psa_switch/psaProgramStructure.cpp index f0f64dc5d6..791ce29efb 100644 --- a/backends/bmv2/psa_switch/psaProgramStructure.cpp +++ b/backends/bmv2/psa_switch/psaProgramStructure.cpp @@ -19,6 +19,8 @@ limitations under the License. namespace BMV2 { +using namespace P4::literals; + void InspectPsaProgram::postorder(const IR::Declaration_Instance *di) { if (!pinfo->resourceMap.count(di)) return; auto blk = pinfo->resourceMap.at(di); @@ -204,9 +206,9 @@ void InspectPsaProgram::postorder(const IR::P4Parser *p) { if (pinfo->block_type.count(p)) { auto info = pinfo->block_type.at(p); if (info.first == INGRESS && info.second == PARSER) - pinfo->parsers.emplace("ingress", p); + pinfo->parsers.emplace("ingress"_cs, p); else if (info.first == EGRESS && info.second == PARSER) - pinfo->parsers.emplace("egress", p); + pinfo->parsers.emplace("egress"_cs, p); } } @@ -214,13 +216,13 @@ void InspectPsaProgram::postorder(const IR::P4Control *c) { if (pinfo->block_type.count(c)) { auto info = pinfo->block_type.at(c); if (info.first == INGRESS && info.second == PIPELINE) - pinfo->pipelines.emplace("ingress", c); + pinfo->pipelines.emplace("ingress"_cs, c); else if (info.first == EGRESS && info.second == PIPELINE) - pinfo->pipelines.emplace("egress", c); + pinfo->pipelines.emplace("egress"_cs, c); else if (info.first == INGRESS && info.second == DEPARSER) - pinfo->deparsers.emplace("ingress", c); + pinfo->deparsers.emplace("ingress"_cs, c); else if (info.first == EGRESS && info.second == DEPARSER) - pinfo->deparsers.emplace("egress", c); + pinfo->deparsers.emplace("egress"_cs, c); } } @@ -238,13 +240,13 @@ bool ParsePsaArchitecture::preorder(const IR::ExternBlock *block) { } bool ParsePsaArchitecture::preorder(const IR::PackageBlock *block) { - auto pkg = block->findParameterValue("ingress"); + auto pkg = block->findParameterValue("ingress"_cs); if (pkg == nullptr) { modelError("Package %1% has no parameter named 'ingress'", block); return false; } if (auto ingress = pkg->to()) { - auto p = ingress->findParameterValue("ip"); + auto p = ingress->findParameterValue("ip"_cs); if (p == nullptr) { modelError("'ingress' package %1% has no parameter named 'ip'", block); return false; @@ -254,7 +256,7 @@ bool ParsePsaArchitecture::preorder(const IR::PackageBlock *block) { modelError("%1%: 'ip' argument of 'ingress' should be bound to a parser", block); return false; } - p = ingress->findParameterValue("ig"); + p = ingress->findParameterValue("ig"_cs); if (p == nullptr) { modelError("'ingress' package %1% has no parameter named 'ig'", block); return false; @@ -264,7 +266,7 @@ bool ParsePsaArchitecture::preorder(const IR::PackageBlock *block) { modelError("%1%: 'ig' argument of 'ingress' should be bound to a control", block); return false; } - p = ingress->findParameterValue("id"); + p = ingress->findParameterValue("id"_cs); if (p == nullptr) { modelError("'ingress' package %1% has no parameter named 'id'", block); return false; @@ -283,13 +285,13 @@ bool ParsePsaArchitecture::preorder(const IR::PackageBlock *block) { modelError("'ingress' %1% is not bound to a package", pkg); return false; } - pkg = block->findParameterValue("egress"); + pkg = block->findParameterValue("egress"_cs); if (pkg == nullptr) { modelError("Package %1% has no parameter named 'egress'", block); return false; } if (auto egress = pkg->to()) { - auto p = egress->findParameterValue("ep"); + auto p = egress->findParameterValue("ep"_cs); if (p == nullptr) { modelError("'egress' package %1% has no parameter named 'ep'", block); return false; @@ -299,7 +301,7 @@ bool ParsePsaArchitecture::preorder(const IR::PackageBlock *block) { modelError("%1%: 'ep' argument of 'egress' should be bound to a parser", block); return false; } - p = egress->findParameterValue("eg"); + p = egress->findParameterValue("eg"_cs); if (p == nullptr) { modelError("'egress' package %1% has no parameter named 'eg'", block); return false; @@ -309,7 +311,7 @@ bool ParsePsaArchitecture::preorder(const IR::PackageBlock *block) { modelError("%1%: 'ig' argument of 'egress' should be bound to a control", block); return false; } - p = egress->findParameterValue("ed"); + p = egress->findParameterValue("ed"_cs); if (p == nullptr) { modelError("'egress' package %1% has no parameter named 'ed'", block); return false; diff --git a/backends/bmv2/psa_switch/psaSwitch.cpp b/backends/bmv2/psa_switch/psaSwitch.cpp index 06f0aea149..d3bd0c7853 100644 --- a/backends/bmv2/psa_switch/psaSwitch.cpp +++ b/backends/bmv2/psa_switch/psaSwitch.cpp @@ -21,6 +21,8 @@ limitations under the License. namespace BMV2 { +using namespace P4::literals; + void PsaCodeGenerator::create(ConversionContext *ctxt) { createTypes(ctxt); createHeaders(ctxt); @@ -119,8 +121,8 @@ void PsaCodeGenerator::createTypes(ConversionContext *ctxt) { void PsaCodeGenerator::createScalars(ConversionContext *ctxt) { auto name = scalars.begin()->first; - ctxt->json->add_header("scalars_t", name); - ctxt->json->add_header_type("scalars_t"); + ctxt->json->add_header("scalars_t"_cs, name); + ctxt->json->add_header_type("scalars_t"_cs); unsigned max_length = 0; for (auto kv : scalars) { LOG5("Adding a scalar field " << kv.second << " to generated json"); @@ -139,7 +141,7 @@ void PsaCodeGenerator::createScalars(ConversionContext *ctxt) { } else { BUG_CHECK(kv.second, "%1 is not of Type_Bits or Type_Boolean"); } - ctxt->json->add_header_field("scalars_t", field); + ctxt->json->add_header_field("scalars_t"_cs, field); } // must add padding unsigned padding = max_length % 8; @@ -149,7 +151,7 @@ void PsaCodeGenerator::createScalars(ConversionContext *ctxt) { field->append(name); field->append(8 - padding); field->append(false); - ctxt->json->add_header_field("scalars_t", field); + ctxt->json->add_header_field("scalars_t"_cs, field); } } @@ -186,13 +188,13 @@ void PsaCodeGenerator::createHeaders(ConversionContext *ctxt) { void PsaCodeGenerator::createParsers(ConversionContext *ctxt) { { - auto cvt = new ParserConverter(ctxt, "ingress_parser"); - auto ingress = parsers.at("ingress"); + auto cvt = new ParserConverter(ctxt, "ingress_parser"_cs); + auto ingress = parsers.at("ingress"_cs); ingress->apply(*cvt); } { - auto cvt = new ParserConverter(ctxt, "egress_parser"); - auto ingress = parsers.at("egress"); + auto cvt = new ParserConverter(ctxt, "egress_parser"_cs); + auto ingress = parsers.at("egress"_cs); ingress->apply(*cvt); } } @@ -218,24 +220,24 @@ void PsaCodeGenerator::createActions(ConversionContext *ctxt) { } void PsaCodeGenerator::createControls(ConversionContext *ctxt) { - auto cvt = new BMV2::ControlConverter(ctxt, "ingress", true); - auto ingress = pipelines.at("ingress"); + auto cvt = new BMV2::ControlConverter(ctxt, "ingress"_cs, true); + auto ingress = pipelines.at("ingress"_cs); ingress->apply(*cvt); - cvt = new BMV2::ControlConverter(ctxt, "egress", true); - auto egress = pipelines.at("egress"); + cvt = new BMV2::ControlConverter(ctxt, "egress"_cs, true); + auto egress = pipelines.at("egress"_cs); egress->apply(*cvt); } void PsaCodeGenerator::createDeparsers(ConversionContext *ctxt) { { - auto cvt = new DeparserConverter(ctxt, "ingress_deparser"); - auto ingress = deparsers.at("ingress"); + auto cvt = new DeparserConverter(ctxt, "ingress_deparser"_cs); + auto ingress = deparsers.at("ingress"_cs); ingress->apply(*cvt); } { - auto cvt = new DeparserConverter(ctxt, "egress_deparser"); - auto egress = deparsers.at("egress"); + auto cvt = new DeparserConverter(ctxt, "egress_deparser"_cs); + auto egress = deparsers.at("egress"_cs); egress->apply(*cvt); } } @@ -317,21 +319,23 @@ void PsaSwitchBackend::convert(const IR::ToplevelBlock *tlb) { } cstring PsaCodeGenerator::convertHashAlgorithm(cstring algo) { - cstring result; - if (algo == "CRC16") { - result = "crc16"; - } else if (algo == "CRC16_CUSTOM") { - result = "crc16_custom"; - } else if (algo == "CRC32") { - result = "crc32"; - } else if (algo == "CRC32_CUSTOM") { - result = "crc32_custom"; - } else if (algo == "IDENTITY") { - result = "identity"; + return "crc16"_cs; + } + if (algo == "CRC16_CUSTOM") { + return "crc16_custom"_cs; + } + if (algo == "CRC32") { + return "crc32"_cs; + } + if (algo == "CRC32_CUSTOM") { + return "crc32_custom"_cs; + } + if (algo == "IDENTITY") { + return "identity"_cs; } - return result; + return nullptr; } ExternConverter_Hash ExternConverter_Hash::singleton; @@ -362,26 +366,26 @@ Util::IJson *ExternConverter_Hash::convertExternObject(UNUSED ConversionContext return nullptr; } auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto hash = new Util::JsonObject(); - hash->emplace("type", "extern"); - hash->emplace("value", em->object->controlPlaneName()); + hash->emplace("type"_cs, "extern"); + hash->emplace("value"_cs, em->object->controlPlaneName()); parameters->append(hash); if (mc->arguments->size() == 2) { // get_hash auto dst = ctxt->conv->convertLeftValue(mc->arguments->at(0)->expression); auto fieldList = new Util::JsonObject(); - fieldList->emplace("type", "field_list"); + fieldList->emplace("type"_cs, "field_list"); auto fieldsJson = ctxt->conv->convert(mc->arguments->at(1)->expression, true, false); - fieldList->emplace("value", fieldsJson); + fieldList->emplace("value"_cs, fieldsJson); parameters->append(dst); parameters->append(fieldList); } else { // get_hash with base and mod auto dst = ctxt->conv->convertLeftValue(mc->arguments->at(0)->expression); auto base = ctxt->conv->convert(mc->arguments->at(1)->expression); auto fieldList = new Util::JsonObject(); - fieldList->emplace("type", "field_list"); + fieldList->emplace("type"_cs, "field_list"); auto fieldsJson = ctxt->conv->convert(mc->arguments->at(2)->expression, true, false); - fieldList->emplace("value", fieldsJson); + fieldList->emplace("value"_cs, fieldsJson); auto max = ctxt->conv->convert(mc->arguments->at(3)->expression); parameters->append(dst); parameters->append(base); @@ -395,7 +399,7 @@ Util::IJson *ExternConverter_Checksum::convertExternObject( UNUSED ConversionContext *ctxt, UNUSED const P4::ExternMethod *em, UNUSED const IR::MethodCallExpression *mc, UNUSED const IR::StatOrDecl *s, UNUSED const bool &emitExterns) { - auto primitive = mkPrimitive("Checksum"); + auto primitive = mkPrimitive("Checksum"_cs); return primitive; } @@ -428,16 +432,16 @@ Util::IJson *ExternConverter_InternetChecksum::convertExternObject( primitive = mkPrimitive("_" + em->originalExternType->name + "_" + em->method->name); } auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto cksum = new Util::JsonObject(); - cksum->emplace("type", "extern"); - cksum->emplace("value", em->object->controlPlaneName()); + cksum->emplace("type"_cs, "extern"); + cksum->emplace("value"_cs, em->object->controlPlaneName()); parameters->append(cksum); if (em->method->name == "add" || em->method->name == "subtract") { auto fieldList = new Util::JsonObject(); - fieldList->emplace("type", "field_list"); + fieldList->emplace("type"_cs, "field_list"); auto fieldsJson = ctxt->conv->convert(mc->arguments->at(0)->expression, true, false); - fieldList->emplace("value", fieldsJson); + fieldList->emplace("value"_cs, fieldsJson); parameters->append(fieldList); } else if (em->method->name != "clear") { if (mc->arguments->size() == 2) { // get_verify @@ -464,10 +468,10 @@ Util::IJson *ExternConverter_Counter::convertExternObject(UNUSED ConversionConte } auto primitive = mkPrimitive("_" + em->originalExternType->name + "_" + em->method->name); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto ctr = new Util::JsonObject(); - ctr->emplace("type", "extern"); - ctr->emplace("value", em->object->controlPlaneName()); + ctr->emplace("type"_cs, "extern"); + ctr->emplace("value"_cs, em->object->controlPlaneName()); parameters->append(ctr); auto index = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(index); @@ -497,10 +501,10 @@ Util::IJson *ExternConverter_Meter::convertExternObject(UNUSED ConversionContext } auto primitive = mkPrimitive("_" + em->originalExternType->name + "_" + em->method->name); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto mtr = new Util::JsonObject(); - mtr->emplace("type", "extern"); - mtr->emplace("value", em->object->controlPlaneName()); + mtr->emplace("type"_cs, "extern"); + mtr->emplace("value"_cs, em->object->controlPlaneName()); parameters->append(mtr); if (mc->arguments->size() == 2) { auto result = ctxt->conv->convert(mc->arguments->at(1)->expression); @@ -540,13 +544,13 @@ Util::IJson *ExternConverter_Register::convertExternObject( return nullptr; } auto reg = new Util::JsonObject(); - reg->emplace("type", "register_array"); + reg->emplace("type"_cs, "register_array"); cstring name = em->object->controlPlaneName(); - reg->emplace("value", name); + reg->emplace("value"_cs, name); if (em->method->name == "read") { - auto primitive = mkPrimitive("register_read"); + auto primitive = mkPrimitive("register_read"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto dest = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(dest); parameters->append(reg); @@ -554,9 +558,9 @@ Util::IJson *ExternConverter_Register::convertExternObject( parameters->append(index); return primitive; } else if (em->method->name == "write") { - auto primitive = mkPrimitive("register_write"); + auto primitive = mkPrimitive("register_write"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); parameters->append(reg); auto index = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(index); @@ -576,9 +580,9 @@ Util::IJson *ExternConverter_Random::convertExternObject(UNUSED ConversionContex modelError("Expected 3 arguments for %1%", mc); return nullptr; } - auto primitive = mkPrimitive("modify_field_rng_uniform"); + auto primitive = mkPrimitive("modify_field_rng_uniform"_cs); auto params = mkParameters(primitive); - primitive->emplace_non_null("source_info", em->method->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, em->method->sourceInfoJsonObj()); auto dest = ctxt->conv->convert(mc->arguments->at(0)->expression); /* TODO */ // auto lo = ctxt->conv->convert(mc->arguments->at(1)->expression); @@ -598,10 +602,10 @@ Util::IJson *ExternConverter_Digest::convertExternObject(UNUSED ConversionContex modelError("Expected 1 arguments for %1%", mc); return nullptr; } - auto primitive = mkPrimitive("generate_digest"); + auto primitive = mkPrimitive("generate_digest"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", em->method->sourceInfoJsonObj()); - cstring listName = "digest"; + primitive->emplace_non_null("source_info"_cs, em->method->sourceInfoJsonObj()); + cstring listName = "digest"_cs; // If we are supplied a type argument that is a named type use // that for the list name. if (mc->typeArguments->size() == 1) { @@ -633,10 +637,10 @@ void ExternConverter_Hash::convertExternInstance(ConversionContext *ctxt, const // add hash instance auto jhash = new Util::JsonObject(); - jhash->emplace("name", name); - jhash->emplace("id", nextId("extern_instances")); - jhash->emplace("type", eb->getName()); - jhash->emplace_non_null("source_info", inst->sourceInfoJsonObj()); + jhash->emplace("name"_cs, name); + jhash->emplace("id"_cs, nextId("extern_instances"_cs)); + jhash->emplace("type"_cs, eb->getName()); + jhash->emplace_non_null("source_info"_cs, inst->sourceInfoJsonObj()); ctxt->json->externs->append(jhash); // add attributes @@ -645,9 +649,9 @@ void ExternConverter_Hash::convertExternInstance(ConversionContext *ctxt, const return; } - Util::JsonArray *arr = ctxt->json->insert_array_field(jhash, "attribute_values"); + Util::JsonArray *arr = ctxt->json->insert_array_field(jhash, "attribute_values"_cs); - auto algo = eb->findParameterValue("algo"); + auto algo = eb->findParameterValue("algo"_cs); CHECK_NULL(algo); if (!algo->is()) { modelError("%1%: expected a declaration", algo->getNode()); @@ -656,9 +660,9 @@ void ExternConverter_Hash::convertExternInstance(ConversionContext *ctxt, const cstring algo_name = algo->to()->name; algo_name = psaStructure->convertHashAlgorithm(algo_name); auto k = new Util::JsonObject(); - k->emplace("name", "algo"); - k->emplace("type", "string"); - k->emplace("value", algo_name); + k->emplace("name"_cs, "algo"); + k->emplace("type"_cs, "string"); + k->emplace("value"_cs, algo_name); arr->append(k); } @@ -676,20 +680,20 @@ void ExternConverter_InternetChecksum::convertExternInstance(UNUSED ConversionCo auto trim = inst->controlPlaneName().find("."); auto block = inst->controlPlaneName().trim(trim); auto psaStructure = static_cast(ctxt->structure); - auto ingressParser = psaStructure->parsers.at("ingress")->controlPlaneName(); - auto ingressDeparser = psaStructure->deparsers.at("ingress")->controlPlaneName(); - auto egressParser = psaStructure->parsers.at("egress")->controlPlaneName(); - auto egressDeparser = psaStructure->deparsers.at("egress")->controlPlaneName(); + auto ingressParser = psaStructure->parsers.at("ingress"_cs)->controlPlaneName(); + auto ingressDeparser = psaStructure->deparsers.at("ingress"_cs)->controlPlaneName(); + auto egressParser = psaStructure->parsers.at("egress"_cs)->controlPlaneName(); + auto egressDeparser = psaStructure->deparsers.at("egress"_cs)->controlPlaneName(); if (block != ingressParser && block != ingressDeparser && block != egressParser && block != egressDeparser) { ::error(ErrorType::ERR_UNSUPPORTED, "%1%: not supported in pipeline on this target", eb); } // add checksum instance auto jcksum = new Util::JsonObject(); - jcksum->emplace("name", name); - jcksum->emplace("id", nextId("extern_instances")); - jcksum->emplace("type", eb->getName()); - jcksum->emplace_non_null("source_info", inst->sourceInfoJsonObj()); + jcksum->emplace("name"_cs, name); + jcksum->emplace("id"_cs, nextId("extern_instances"_cs)); + jcksum->emplace("type"_cs, eb->getName()); + jcksum->emplace_non_null("source_info"_cs, inst->sourceInfoJsonObj()); ctxt->json->externs->append(jcksum); } @@ -699,7 +703,7 @@ void ExternConverter_Counter::convertExternInstance(UNUSED ConversionContext *ct UNUSED const bool &emitExterns) { auto inst = c->to(); cstring name = inst->controlPlaneName(); - auto sz = eb->findParameterValue("n_counters"); + auto sz = eb->findParameterValue("n_counters"_cs); CHECK_NULL(sz); if (!sz->is()) { modelError("%1%: expected a constant", sz->getNode()); @@ -708,21 +712,21 @@ void ExternConverter_Counter::convertExternInstance(UNUSED ConversionContext *ct // adding counter instance to counter_arrays[] auto jctr = new Util::JsonObject(); - jctr->emplace("name", name); - jctr->emplace("id", nextId("counter_arrays")); - jctr->emplace_non_null("source_info", eb->sourceInfoJsonObj()); - jctr->emplace("size", sz->to()->value); - jctr->emplace("is_direct", false); + jctr->emplace("name"_cs, name); + jctr->emplace("id"_cs, nextId("counter_arrays"_cs)); + jctr->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); + jctr->emplace("size"_cs, sz->to()->value); + jctr->emplace("is_direct"_cs, false); ctxt->json->counters->append(jctr); // add counter instance to extern_instances auto extern_obj = new Util::JsonObject(); - extern_obj->emplace("name", name); - extern_obj->emplace("id", nextId("extern_instances")); - extern_obj->emplace("type", eb->getName()); - extern_obj->emplace("source_info", inst->sourceInfoJsonObj()); + extern_obj->emplace("name"_cs, name); + extern_obj->emplace("id"_cs, nextId("extern_instances"_cs)); + extern_obj->emplace("type"_cs, eb->getName()); + extern_obj->emplace("source_info"_cs, inst->sourceInfoJsonObj()); ctxt->json->externs->append(extern_obj); - Util::JsonArray *arr = ctxt->json->insert_array_field(extern_obj, "attribute_values"); + Util::JsonArray *arr = ctxt->json->insert_array_field(extern_obj, "attribute_values"_cs); if (eb->getConstructorParameters()->size() != 2) { modelError("%1%: expected two parameters", eb); @@ -735,14 +739,14 @@ void ExternConverter_Counter::convertExternInstance(UNUSED ConversionContext *ct auto param1 = eb->getConstructorParameters()->getParameter(0); auto bitwidth = ctxt->typeMap->widthBits(arg1->type, sz->getNode(), false); cstring repr = BMV2::stringRepr(arg1->value, ROUNDUP(bitwidth, 8)); - attr_obj->emplace("name", param1->toString()); - attr_obj->emplace("type", "hexstr"); - attr_obj->emplace("value", repr); + attr_obj->emplace("name"_cs, param1->toString()); + attr_obj->emplace("type"_cs, "hexstr"); + attr_obj->emplace("value"_cs, repr); arr->append(attr_obj); // second argument is the counter type, this is psa metadata, the converter // in conversion context will handle that for us - auto tp = eb->findParameterValue("type"); + auto tp = eb->findParameterValue("type"_cs); if (!tp || !tp->is()) { modelError("%1%: expected a declaration_id", tp ? tp->getNode() : eb->getNode()); return; @@ -766,26 +770,26 @@ void ExternConverter_DirectCounter::convertExternInstance(UNUSED ConversionConte ::warning(ErrorType::WARN_UNUSED, "%1%: Direct counter not used; ignoring", inst); } else { auto jctr = new Util::JsonObject(); - jctr->emplace("name", name); - jctr->emplace("id", nextId("counter_arrays")); - jctr->emplace_non_null("source_info", eb->sourceInfoJsonObj()); - jctr->emplace("is_direct", true); - jctr->emplace("binding", it->second->controlPlaneName()); + jctr->emplace("name"_cs, name); + jctr->emplace("id"_cs, nextId("counter_arrays"_cs)); + jctr->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); + jctr->emplace("is_direct"_cs, true); + jctr->emplace("binding"_cs, it->second->controlPlaneName()); ctxt->json->counters->append(jctr); // Adding direct counter to EXTERN_INSTANCES auto extern_obj = new Util::JsonObject(); - extern_obj->emplace("name", name); - extern_obj->emplace("id", nextId("extern_instances")); - extern_obj->emplace("type", eb->getName()); - extern_obj->emplace("source_info", inst->sourceInfoJsonObj()); + extern_obj->emplace("name"_cs, name); + extern_obj->emplace("id"_cs, nextId("extern_instances"_cs)); + extern_obj->emplace("type"_cs, eb->getName()); + extern_obj->emplace("source_info"_cs, inst->sourceInfoJsonObj()); ctxt->json->externs->append(extern_obj); - Util::JsonArray *arr = ctxt->json->insert_array_field(extern_obj, "attribute_values"); + Util::JsonArray *arr = ctxt->json->insert_array_field(extern_obj, "attribute_values"_cs); // Direct Counter only has a single argument, which is psa metadata // converter in conversion context will handle this for us - auto tp = eb->findParameterValue("type"); + auto tp = eb->findParameterValue("type"_cs); if (!tp || !tp->is()) { modelError("%1%: expected a declaration_id", tp ? tp->getNode() : eb->getNode()); return; @@ -817,24 +821,24 @@ void ExternConverter_Meter::convertExternInstance(UNUSED ConversionContext *ctxt // adding meter instance into extern_instances auto jext_mtr = new Util::JsonObject(); - jext_mtr->emplace("name", name); - jext_mtr->emplace("id", nextId("extern_instances")); - jext_mtr->emplace("type", eb->getName()); - jext_mtr->emplace_non_null("source_info", eb->sourceInfoJsonObj()); + jext_mtr->emplace("name"_cs, name); + jext_mtr->emplace("id"_cs, nextId("extern_instances"_cs)); + jext_mtr->emplace("type"_cs, eb->getName()); + jext_mtr->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); ctxt->json->externs->append(jext_mtr); // adding attributes to meter extern_instance - Util::JsonArray *arr = ctxt->json->insert_array_field(jext_mtr, "attribute_values"); + Util::JsonArray *arr = ctxt->json->insert_array_field(jext_mtr, "attribute_values"_cs); // is_direct auto is_direct = new Util::JsonObject(); - is_direct->emplace("name", "is_direct"); - is_direct->emplace("type", "hexstr"); - is_direct->emplace("value", 0); + is_direct->emplace("name"_cs, "is_direct"); + is_direct->emplace("type"_cs, "hexstr"); + is_direct->emplace("value"_cs, 0); arr->append(is_direct); // meter_array size - auto sz = eb->findParameterValue("n_meters"); + auto sz = eb->findParameterValue("n_meters"_cs); CHECK_NULL(sz); if (!sz->is()) { modelError("%1%: expected a constant", sz->getNode()); @@ -845,37 +849,37 @@ void ExternConverter_Meter::convertExternInstance(UNUSED ConversionContext *ctxt auto bitwidth = ctxt->typeMap->widthBits(s->type, sz->getNode(), false); cstring val = BMV2::stringRepr(s->value, ROUNDUP(bitwidth, 8)); auto msz = new Util::JsonObject(); - msz->emplace("name", attr_name->toString()); - msz->emplace("type", "hexstr"); - msz->emplace("value", val); + msz->emplace("name"_cs, attr_name->toString()); + msz->emplace("type"_cs, "hexstr"); + msz->emplace("value"_cs, val); arr->append(msz); // rate count auto rc = new Util::JsonObject(); - rc->emplace("name", "rate_count"); - rc->emplace("type", "hexstr"); - rc->emplace("value", 2); + rc->emplace("name"_cs, "rate_count"); + rc->emplace("type"_cs, "hexstr"); + rc->emplace("value"_cs, 2); arr->append(rc); // meter kind - auto mkind = eb->findParameterValue("type"); + auto mkind = eb->findParameterValue("type"_cs); CHECK_NULL(mkind); if (!mkind->is()) { modelError("%1%: expected a member", mkind->getNode()); return; } cstring mkind_name = mkind->to()->name; - cstring type = "?"; + cstring type; if (mkind_name == "PACKETS") - type = "packets"; + type = "packets"_cs; else if (mkind_name == "BYTES") - type = "bytes"; + type = "bytes"_cs; else ::error(ErrorType::ERR_UNEXPECTED, "%1%: unexpected meter type", mkind->getNode()); auto k = new Util::JsonObject(); - k->emplace("name", "type"); - k->emplace("type", "string"); - k->emplace("value", type); + k->emplace("name"_cs, "type"); + k->emplace("type"_cs, "string"); + k->emplace("value"_cs, type); arr->append(k); } @@ -891,33 +895,33 @@ void ExternConverter_DirectMeter::convertExternInstance(UNUSED ConversionContext CHECK_NULL(info->destinationField); auto jmtr = new Util::JsonObject(); - jmtr->emplace("name", name); - jmtr->emplace("id", nextId("meter_arrays")); - jmtr->emplace_non_null("source_info", eb->sourceInfoJsonObj()); - jmtr->emplace("is_direct", true); - jmtr->emplace("rate_count", 2); - auto mkind = eb->findParameterValue("type"); + jmtr->emplace("name"_cs, name); + jmtr->emplace("id"_cs, nextId("meter_arrays"_cs)); + jmtr->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); + jmtr->emplace("is_direct"_cs, true); + jmtr->emplace("rate_count"_cs, 2); + auto mkind = eb->findParameterValue("type"_cs); CHECK_NULL(mkind); if (!mkind->is()) { modelError("%1%: expected a member", mkind->getNode()); return; } cstring mkind_name = mkind->to()->name; - cstring type = "?"; + cstring type; if (mkind_name == "PACKETS") { - type = "packets"; + type = "packets"_cs; } else if (mkind_name == "BYTES") { - type = "bytes"; + type = "bytes"_cs; } else { modelError("%1%: unexpected meter type", mkind->getNode()); return; } - jmtr->emplace("type", type); - jmtr->emplace("size", info->tableSize); + jmtr->emplace("type"_cs, type); + jmtr->emplace("size"_cs, info->tableSize); cstring tblname = info->table->controlPlaneName(); - jmtr->emplace("binding", tblname); + jmtr->emplace("binding"_cs, tblname); auto result = ctxt->conv->convert(info->destinationField); - jmtr->emplace("result_target", result->to()->get("value")); + jmtr->emplace("result_target"_cs, result->to()->get("value"_cs)); ctxt->json->meter_arrays->append(jmtr); } @@ -932,10 +936,10 @@ void ExternConverter_Register::convertExternInstance(UNUSED ConversionContext *c auto inst = c->to(); cstring name = inst->controlPlaneName(); auto jreg = new Util::JsonObject(); - jreg->emplace("name", name); - jreg->emplace("id", nextId("register_arrays")); - jreg->emplace_non_null("source_info", eb->sourceInfoJsonObj()); - auto sz = eb->findParameterValue("size"); + jreg->emplace("name"_cs, name); + jreg->emplace("id"_cs, nextId("register_arrays"_cs)); + jreg->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); + auto sz = eb->findParameterValue("size"_cs); CHECK_NULL(sz); if (!sz->is()) { modelError("%1%: expected a constant", sz->getNode()); @@ -943,7 +947,7 @@ void ExternConverter_Register::convertExternInstance(UNUSED ConversionContext *c } if (sz->to()->value == 0) error(ErrorType::ERR_UNSUPPORTED, "%1%: direct registers are not supported", inst); - jreg->emplace("size", sz->to()->value); + jreg->emplace("size"_cs, sz->to()->value); if (!eb->instanceType->is()) { modelError("%1%: Expected a generic specialized type", eb->instanceType); return; @@ -964,7 +968,7 @@ void ExternConverter_Register::convertExternInstance(UNUSED ConversionContext *c ::error(ErrorType::ERR_UNKNOWN, "%1%: unknown width", st->arguments->at(0)); return; } - jreg->emplace("bitwidth", width); + jreg->emplace("bitwidth"_cs, width); ctxt->json->register_arrays->append(jreg); } @@ -983,18 +987,18 @@ void ExternConverter_ActionProfile::convertExternInstance(UNUSED ConversionConte // once in a pipeline, so only add it to the action_profiles once if (BMV2::JsonObjects::find_object_by_name(ctxt->action_profiles, name)) return; auto action_profile = new Util::JsonObject(); - action_profile->emplace("name", name); - action_profile->emplace("id", nextId("action_profiles")); - action_profile->emplace_non_null("source_info", eb->sourceInfoJsonObj()); + action_profile->emplace("name"_cs, name); + action_profile->emplace("id"_cs, nextId("action_profiles"_cs)); + action_profile->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); - auto sz = eb->findParameterValue("size"); + auto sz = eb->findParameterValue("size"_cs); BUG_CHECK(sz, "%1%Invalid declaration of extern ActionProfile ctor: no size param", eb->constructor->srcInfo); if (!sz->is()) { ::error(ErrorType::ERR_EXPECTED, "%1%: expected a constant", sz); } - action_profile->emplace("max_size", sz->to()->value); + action_profile->emplace("max_size"_cs, sz->to()->value); ctxt->action_profiles->append(action_profile); } @@ -1009,28 +1013,28 @@ void ExternConverter_ActionSelector::convertExternInstance(UNUSED ConversionCont // once in a pipeline, so only add it to the action_profiles once if (BMV2::JsonObjects::find_object_by_name(ctxt->action_profiles, name)) return; auto action_profile = new Util::JsonObject(); - action_profile->emplace("name", name); - action_profile->emplace("id", nextId("action_profiles")); - action_profile->emplace_non_null("source_info", eb->sourceInfoJsonObj()); + action_profile->emplace("name"_cs, name); + action_profile->emplace("id"_cs, nextId("action_profiles"_cs)); + action_profile->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); - auto sz = eb->findParameterValue("size"); + auto sz = eb->findParameterValue("size"_cs); BUG_CHECK(sz, "%1%Invalid declaration of extern ActionSelector: no size param", eb->constructor->srcInfo); if (!sz->is()) { ::error(ErrorType::ERR_EXPECTED, "%1%: expected a constant", sz); return; } - action_profile->emplace("max_size", sz->to()->value); + action_profile->emplace("max_size"_cs, sz->to()->value); auto selector = new Util::JsonObject(); - auto hash = eb->findParameterValue("algo"); + auto hash = eb->findParameterValue("algo"_cs); if (!hash->is()) { modelError("%1%: expected a member", hash->getNode()); return; } auto algo = ExternConverter::convertHashAlgorithm(hash->to()->name); - selector->emplace("algo", algo); + selector->emplace("algo"_cs, algo); auto input = ctxt->get_selector_input(c->to()); if (input == nullptr) { // the selector is never used by any table, we cannot figure out its @@ -1041,12 +1045,12 @@ void ExternConverter_ActionSelector::convertExternInstance(UNUSED ConversionCont c); return; } - auto j_input = mkArrayField(selector, "input"); + auto j_input = mkArrayField(selector, "input"_cs); for (auto expr : *input) { auto jk = ctxt->conv->convert(expr); j_input->append(jk); } - action_profile->emplace("selector", selector); + action_profile->emplace("selector"_cs, selector); ctxt->action_profiles->append(action_profile); } diff --git a/backends/bmv2/psa_switch/psaSwitch.h b/backends/bmv2/psa_switch/psaSwitch.h index 482604bf02..92102fcc08 100644 --- a/backends/bmv2/psa_switch/psaSwitch.h +++ b/backends/bmv2/psa_switch/psaSwitch.h @@ -58,20 +58,20 @@ class PsaSwitchExpressionConverter : public ExpressionConverter { cstring ptName = param->type->toString(); if (PsaProgramStructure::isCounterMetadata(ptName)) { // check if its counter metadata auto jsn = new Util::JsonObject(); - jsn->emplace("name", param->toString()); - jsn->emplace("type", "hexstr"); + jsn->emplace("name"_cs, param->toString()); + jsn->emplace("type"_cs, "hexstr"); auto bitwidth = param->type->width_bits(); // encode the counter type from enum -> int if (fieldName == "BYTES") { cstring repr = BMV2::stringRepr(0, ROUNDUP(bitwidth, 32)); - jsn->emplace("value", repr); + jsn->emplace("value"_cs, repr); } else if (fieldName == "PACKETS") { cstring repr = BMV2::stringRepr(1, ROUNDUP(bitwidth, 32)); - jsn->emplace("value", repr); + jsn->emplace("value"_cs, repr); } else if (fieldName == "PACKETS_AND_BYTES") { cstring repr = BMV2::stringRepr(2, ROUNDUP(bitwidth, 32)); - jsn->emplace("value", repr); + jsn->emplace("value"_cs, repr); } else { modelError("%1%: Exptected a PSA_CounterType_t", fieldName); return nullptr; @@ -81,8 +81,8 @@ class PsaSwitchExpressionConverter : public ExpressionConverter { auto jsn = new Util::JsonObject(); // encode the metadata type and field in json - jsn->emplace("type", "field"); - auto a = mkArrayField(jsn, "value"); + jsn->emplace("type"_cs, "field"); + auto a = mkArrayField(jsn, "value"_cs); a->append(ptName.exceptLast(2)); a->append(fieldName); return jsn; @@ -133,7 +133,7 @@ class ConvertPsaToJson : public Inspector { } void postorder(UNUSED const IR::P4Program *program) override { - cstring scalarsName = "scalars"; + cstring scalarsName = "scalars"_cs; // This visitor is used in multiple passes to convert expression to json auto conv = new PsaSwitchExpressionConverter(refMap, typeMap, structure, scalarsName); auto ctxt = new ConversionContext(refMap, typeMap, toplevel, structure, conv, json); diff --git a/backends/bmv2/simple_switch/main.cpp b/backends/bmv2/simple_switch/main.cpp index cc5493d3c1..cfcfde15ef 100644 --- a/backends/bmv2/simple_switch/main.cpp +++ b/backends/bmv2/simple_switch/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoBMV2Context(new BMV2::SimpleSwitchContext); auto &options = BMV2::SimpleSwitchContext::get().options(); options.langVersion = CompilerOptions::FrontendVersion::P4_16; - options.compilerVersion = BMV2_SIMPLESWITCH_VERSION_STRING; + options.compilerVersion = cstring(BMV2_SIMPLESWITCH_VERSION_STRING); if (options.process(argc, argv) != nullptr) { if (options.loadIRFromJson == false) options.setInputFile(); diff --git a/backends/bmv2/simple_switch/midend.cpp b/backends/bmv2/simple_switch/midend.cpp index e07d23fdd5..3b3035310b 100644 --- a/backends/bmv2/simple_switch/midend.cpp +++ b/backends/bmv2/simple_switch/midend.cpp @@ -30,6 +30,7 @@ limitations under the License. #include "frontends/p4/typeMap.h" #include "frontends/p4/uniqueNames.h" #include "frontends/p4/unusedDeclarations.h" +#include "lib/cstring.h" #include "midend/actionSynthesis.h" #include "midend/checkSize.h" #include "midend/compileTimeOps.h" @@ -67,12 +68,14 @@ limitations under the License. namespace BMV2 { +using namespace P4::literals; + SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *outStream) : MidEnd(options) { auto *evaluator = new P4::EvaluatorPass(&refMap, &typeMap); - if (BMV2::SimpleSwitchContext::get().options().loadIRFromJson == false) { + if (!BMV2::SimpleSwitchContext::get().options().loadIRFromJson) { auto *convertEnums = - new P4::ConvertEnums(&refMap, &typeMap, new EnumOn32Bits("v1model.p4")); + new P4::ConvertEnums(&refMap, &typeMap, new EnumOn32Bits("v1model.p4"_cs)); addPasses( {options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr, new P4::CheckTableSize(), @@ -114,8 +117,8 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *o &refMap, &typeMap, new P4::OrPolicy(new P4::IsValid(&refMap, &typeMap), new P4::IsMask())), new P4::MoveDeclarations(), - new P4::ValidateTableProperties( - {"implementation", "size", "counters", "meters", "support_timeout"}), + new P4::ValidateTableProperties({"implementation"_cs, "size"_cs, "counters"_cs, + "meters"_cs, "support_timeout"_cs}), new P4::SimplifyControlFlow(&refMap, &typeMap), new P4::EliminateTypedef(&refMap, &typeMap), new P4::CompileTimeOperations(), @@ -131,7 +134,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *o [this, evaluator]() { toplevel = evaluator->getToplevelBlock(); }, new P4::MidEndLast()}); if (options.listMidendPasses) { - listPasses(*outStream, "\n"); + listPasses(*outStream, cstring::newline); *outStream << std::endl; return; } @@ -139,7 +142,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *o removePasses(options.passesToExcludeMidend); } } else { - auto *fillEnumMap = new P4::FillEnumMap(new EnumOn32Bits("v1model.p4"), &typeMap); + auto *fillEnumMap = new P4::FillEnumMap(new EnumOn32Bits("v1model.p4"_cs), &typeMap); addPasses({ new P4::ResolveReferences(&refMap), new P4::TypeChecking(&refMap, &typeMap), diff --git a/backends/bmv2/simple_switch/simpleSwitch.cpp b/backends/bmv2/simple_switch/simpleSwitch.cpp index 4959ed8388..e154cedcd5 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.cpp +++ b/backends/bmv2/simple_switch/simpleSwitch.cpp @@ -135,14 +135,14 @@ Util::IJson *ExternConverter_clone::convertExternFunction(ConversionContext *ctx } cstring prim; if (ei->name == "I2E") { - prim = "clone_ingress_pkt_to_egress"; + prim = "clone_ingress_pkt_to_egress"_cs; if (ctxt->blockConverted != BlockConverted::Ingress) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "'clone(I2E, ...) not invoked in ingress %1%", mc); return nullptr; } } else { - prim = "clone_egress_pkt_to_egress"; + prim = "clone_egress_pkt_to_egress"_cs; if (ctxt->blockConverted != BlockConverted::Egress) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "'clone(E2E, ...) not invoked in egress %1%", mc); @@ -153,7 +153,7 @@ Util::IJson *ExternConverter_clone::convertExternFunction(ConversionContext *ctx auto session = ctxt->conv->convert(mc->arguments->at(1)->expression); auto primitive = mkPrimitive(prim); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", mc->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, mc->sourceInfoJsonObj()); parameters->append(session); if (id >= 0) { @@ -172,9 +172,9 @@ static unsigned getFieldListById(ConversionContext *ctxt, unsigned index) { for (auto it : *ctxt->json->field_lists) { auto j = it->to(); CHECK_NULL(j); - auto name = j->get("name")->to()->getString(); + auto name = j->get("name"_cs)->to()->getString(); if (name == search) { - id = j->get("id")->to()->getInt(); + id = j->get("id"_cs)->to()->getInt(); break; } } @@ -206,14 +206,14 @@ Util::IJson *ExternConverter_clone_preserving_field_list::convertExternFunction( } cstring prim; if (ei->name == "I2E") { - prim = "clone_ingress_pkt_to_egress"; + prim = "clone_ingress_pkt_to_egress"_cs; if (ctxt->blockConverted != BlockConverted::Ingress) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "'clone_preserving_field_list(I2E, ...) not invoked in ingress %1%", mc); return nullptr; } } else { - prim = "clone_egress_pkt_to_egress"; + prim = "clone_egress_pkt_to_egress"_cs; if (ctxt->blockConverted != BlockConverted::Egress) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "'clone_preserving_field_list(E2E, ...) not invoked in egress %1%", mc); @@ -223,7 +223,7 @@ Util::IJson *ExternConverter_clone_preserving_field_list::convertExternFunction( auto session = ctxt->conv->convert(mc->arguments->at(1)->expression); auto primitive = mkPrimitive(prim); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", mc->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, mc->sourceInfoJsonObj()); parameters->append(session); auto fl = mc->arguments->at(2); @@ -256,9 +256,9 @@ Util::IJson *ExternConverter_hash::convertExternFunction(ConversionContext *ctxt modelError("Expected 5 arguments for %1%", mc); return nullptr; } - auto primitive = mkPrimitive("modify_field_with_hash_based_offset"); + auto primitive = mkPrimitive("modify_field_with_hash_based_offset"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto dest = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(dest); auto base = ctxt->conv->convert(mc->arguments->at(2)->expression); @@ -273,8 +273,8 @@ Util::IJson *ExternConverter_hash::convertExternFunction(ConversionContext *ctxt auto fields = mc->arguments->at(3); auto calcName = ctxt->createCalculation(ei->name, fields->expression, ctxt->json->calculations, false, nullptr); - calculation->emplace("type", "calculation"); - calculation->emplace("value", calcName); + calculation->emplace("type"_cs, "calculation"); + calculation->emplace("value"_cs, calcName); parameters->append(calculation); auto max = ctxt->conv->convert(mc->arguments->at(4)->expression); parameters->append(max); @@ -290,12 +290,12 @@ Util::IJson *ExternConverter_digest::convertExternFunction(ConversionContext *ct modelError("Expected 2 arguments for %1%", mc); return nullptr; } - auto primitive = mkPrimitive("generate_digest"); + auto primitive = mkPrimitive("generate_digest"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", mc->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, mc->sourceInfoJsonObj()); auto dest = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(dest); - cstring listName = "digest"; + cstring listName = "digest"_cs; // If we are supplied a type argument that is a named type use // that for the list name. if (mc->typeArguments->size() == 1) { @@ -328,9 +328,9 @@ Util::IJson *ExternConverter_resubmit_preserving_field_list::convertExternFuncti return nullptr; } if (mc->arguments->size() == 1) { - auto primitive = mkPrimitive("resubmit"); + auto primitive = mkPrimitive("resubmit"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", mc->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, mc->sourceInfoJsonObj()); auto arg = mc->arguments->at(0); auto cst = arg->expression->to(); if (cst == nullptr) { @@ -359,9 +359,9 @@ Util::IJson *ExternConverter_recirculate_preserving_field_list::convertExternFun return nullptr; } if (mc->arguments->size() == 1) { - auto primitive = mkPrimitive("recirculate"); + auto primitive = mkPrimitive("recirculate"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", mc->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, mc->sourceInfoJsonObj()); auto arg = mc->arguments->at(0); auto cst = arg->expression->to(); if (cst == nullptr) { @@ -389,11 +389,11 @@ Util::IJson *ExternConverter_mark_to_drop::convertExternFunction( modelError("Expected 1 argument for %1%", mc); return nullptr; } - auto primitive = mkPrimitive("mark_to_drop"); + auto primitive = mkPrimitive("mark_to_drop"_cs); auto params = mkParameters(primitive); auto dest = ctxt->conv->convert(mc->arguments->at(0)->expression); params->append(dest); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); return primitive; } @@ -408,7 +408,7 @@ Util::IJson *ExternConverter_random::convertExternFunction(ConversionContext *ct } auto primitive = mkPrimitive(v1model.random.modify_field_rng_uniform.name); auto params = mkParameters(primitive); - primitive->emplace_non_null("source_info", mc->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, mc->sourceInfoJsonObj()); auto dest = ctxt->conv->convert(mc->arguments->at(0)->expression); auto lo = ctxt->conv->convert(mc->arguments->at(1)->expression); auto hi = ctxt->conv->convert(mc->arguments->at(2)->expression); @@ -429,7 +429,7 @@ Util::IJson *ExternConverter_truncate::convertExternFunction(UNUSED ConversionCo } auto primitive = mkPrimitive(v1model.truncate.name); auto params = mkParameters(primitive); - primitive->emplace_non_null("source_info", mc->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, mc->sourceInfoJsonObj()); auto len = ctxt->conv->convert(mc->arguments->at(0)->expression); params->append(len); return primitive; @@ -444,12 +444,12 @@ Util::IJson *ExternConverter_counter::convertExternObject(ConversionContext *ctx modelError("Expected 1 argument for %1%", mc); return nullptr; } - auto primitive = mkPrimitive("count"); + auto primitive = mkPrimitive("count"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto ctr = new Util::JsonObject(); - ctr->emplace("type", "counter_array"); - ctr->emplace("value", em->object->controlPlaneName()); + ctr->emplace("type"_cs, "counter_array"); + ctr->emplace("value"_cs, em->object->controlPlaneName()); parameters->append(ctr); auto index = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(index); @@ -463,17 +463,17 @@ void ExternConverter_counter::convertExternInstance(ConversionContext *ctxt, auto inst = c->to(); cstring name = inst->controlPlaneName(); auto jctr = new Util::JsonObject(); - jctr->emplace("name", name); - jctr->emplace("id", nextId("counter_arrays")); - jctr->emplace_non_null("source_info", eb->sourceInfoJsonObj()); + jctr->emplace("name"_cs, name); + jctr->emplace("id"_cs, nextId("counter_arrays"_cs)); + jctr->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); auto sz = eb->findParameterValue(v1model.counter.sizeParam.name); CHECK_NULL(sz); if (!sz->is()) { modelError("%1%: expected a constant", sz->getNode()); return; } - jctr->emplace("size", sz->to()->value); - jctr->emplace("is_direct", false); + jctr->emplace("size"_cs, sz->to()->value); + jctr->emplace("is_direct"_cs, false); ctxt->json->counters->append(jctr); } @@ -486,12 +486,12 @@ Util::IJson *ExternConverter_meter::convertExternObject(ConversionContext *ctxt, modelError("Expected 2 arguments for %1%", mc); return nullptr; } - auto primitive = mkPrimitive("execute_meter"); + auto primitive = mkPrimitive("execute_meter"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto mtr = new Util::JsonObject(); - mtr->emplace("type", "meter_array"); - mtr->emplace("value", em->object->controlPlaneName()); + mtr->emplace("type"_cs, "meter_array"); + mtr->emplace("value"_cs, em->object->controlPlaneName()); parameters->append(mtr); auto index = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(index); @@ -506,18 +506,18 @@ void ExternConverter_meter::convertExternInstance(ConversionContext *ctxt, const auto inst = c->to(); cstring name = inst->controlPlaneName(); auto jmtr = new Util::JsonObject(); - jmtr->emplace("name", name); - jmtr->emplace("id", nextId("meter_arrays")); - jmtr->emplace_non_null("source_info", eb->sourceInfoJsonObj()); - jmtr->emplace("is_direct", false); + jmtr->emplace("name"_cs, name); + jmtr->emplace("id"_cs, nextId("meter_arrays"_cs)); + jmtr->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); + jmtr->emplace("is_direct"_cs, false); auto sz = eb->findParameterValue(v1model.meter.sizeParam.name); CHECK_NULL(sz); if (!sz->is()) { modelError("%1%: expected a constant", sz->getNode()); return; } - jmtr->emplace("size", sz->to()->value); - jmtr->emplace("rate_count", 2); + jmtr->emplace("size"_cs, sz->to()->value); + jmtr->emplace("rate_count"_cs, 2); auto mkind = eb->findParameterValue(v1model.meter.typeParam.name); CHECK_NULL(mkind); if (!mkind->is()) { @@ -525,15 +525,15 @@ void ExternConverter_meter::convertExternInstance(ConversionContext *ctxt, const return; } cstring mkind_name = mkind->to()->name; - cstring type = "?"; + cstring type = "?"_cs; if (mkind_name == v1model.meter.meterType.packets.name) - type = "packets"; + type = "packets"_cs; else if (mkind_name == v1model.meter.meterType.bytes.name) - type = "bytes"; + type = "bytes"_cs; else ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "Unexpected meter type %1%", mkind->getNode()); - jmtr->emplace("type", type); + jmtr->emplace("type"_cs, type); ctxt->json->meter_arrays->append(jmtr); } @@ -547,13 +547,13 @@ Util::IJson *ExternConverter_register::convertExternObject(ConversionContext *ct return nullptr; } auto reg = new Util::JsonObject(); - reg->emplace("type", "register_array"); + reg->emplace("type"_cs, "register_array"); cstring name = em->object->controlPlaneName(); - reg->emplace("value", name); + reg->emplace("value"_cs, name); if (em->method->name == v1model.registers.read.name) { - auto primitive = mkPrimitive("register_read"); + auto primitive = mkPrimitive("register_read"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto dest = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(dest); parameters->append(reg); @@ -561,9 +561,9 @@ Util::IJson *ExternConverter_register::convertExternObject(ConversionContext *ct parameters->append(index); return primitive; } else if (em->method->name == v1model.registers.write.name) { - auto primitive = mkPrimitive("register_write"); + auto primitive = mkPrimitive("register_write"_cs); auto parameters = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); parameters->append(reg); auto index = ctxt->conv->convert(mc->arguments->at(0)->expression); parameters->append(index); @@ -581,9 +581,9 @@ void ExternConverter_register::convertExternInstance(ConversionContext *ctxt, auto inst = c->to(); cstring name = inst->controlPlaneName(); auto jreg = new Util::JsonObject(); - jreg->emplace("name", name); - jreg->emplace("id", nextId("register_arrays")); - jreg->emplace_non_null("source_info", eb->sourceInfoJsonObj()); + jreg->emplace("name"_cs, name); + jreg->emplace("id"_cs, nextId("register_arrays"_cs)); + jreg->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); auto sz = eb->findParameterValue(v1model.registers.sizeParam.name); CHECK_NULL(sz); if (!sz->is()) { @@ -593,7 +593,7 @@ void ExternConverter_register::convertExternInstance(ConversionContext *ctxt, if (sz->to()->value == 0) error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "%1%: direct registers are not supported in bmv2", inst); - jreg->emplace("size", sz->to()->value); + jreg->emplace("size"_cs, sz->to()->value); if (auto st = eb->instanceType->to()) { if (st->arguments->size() < 1 || st->arguments->size() > 2) { modelError("%1%: expected 1 or 2 type arguments", st); @@ -610,7 +610,7 @@ void ExternConverter_register::convertExternInstance(ConversionContext *ctxt, ::error(ErrorType::ERR_EXPRESSION, "%1%: unknown width", st->arguments->at(0)); return; } - jreg->emplace("bitwidth", width); + jreg->emplace("bitwidth"_cs, width); ctxt->json->register_arrays->append(jreg); } else { modelError("%1%: Expected a generic specialized type", eb->instanceType); @@ -641,11 +641,11 @@ void ExternConverter_direct_counter::convertExternInstance(ConversionContext *ct ::warning(ErrorType::WARN_UNUSED, "%1%: Direct counter not used; ignoring", inst); } else { auto jctr = new Util::JsonObject(); - jctr->emplace("name", name); - jctr->emplace("id", nextId("counter_arrays")); - jctr->emplace("is_direct", true); - jctr->emplace("binding", it->second->controlPlaneName()); - jctr->emplace_non_null("source_info", eb->sourceInfoJsonObj()); + jctr->emplace("name"_cs, name); + jctr->emplace("id"_cs, nextId("counter_arrays"_cs)); + jctr->emplace("is_direct"_cs, true); + jctr->emplace("binding"_cs, it->second->controlPlaneName()); + jctr->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); ctxt->json->counters->append(jctr); } } @@ -696,11 +696,11 @@ void ExternConverter_direct_meter::convertExternInstance(ConversionContext *ctxt CHECK_NULL(info->destinationField); auto jmtr = new Util::JsonObject(); - jmtr->emplace("name", name); - jmtr->emplace("id", nextId("meter_arrays")); - jmtr->emplace_non_null("source_info", eb->sourceInfoJsonObj()); - jmtr->emplace("is_direct", true); - jmtr->emplace("rate_count", 2); + jmtr->emplace("name"_cs, name); + jmtr->emplace("id"_cs, nextId("meter_arrays"_cs)); + jmtr->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); + jmtr->emplace("is_direct"_cs, true); + jmtr->emplace("rate_count"_cs, 2); auto mkind = eb->findParameterValue(v1model.directMeter.typeParam.name); CHECK_NULL(mkind); if (!mkind->is()) { @@ -708,21 +708,21 @@ void ExternConverter_direct_meter::convertExternInstance(ConversionContext *ctxt return; } cstring mkind_name = mkind->to()->name; - cstring type = "?"; + cstring type = "?"_cs; if (mkind_name == v1model.meter.meterType.packets.name) { - type = "packets"; + type = "packets"_cs; } else if (mkind_name == v1model.meter.meterType.bytes.name) { - type = "bytes"; + type = "bytes"_cs; } else { modelError("%1%: unexpected meter type", mkind->getNode()); return; } - jmtr->emplace("type", type); - jmtr->emplace("size", info->tableSize); + jmtr->emplace("type"_cs, type); + jmtr->emplace("size"_cs, info->tableSize); cstring tblname = info->table->controlPlaneName(); - jmtr->emplace("binding", tblname); + jmtr->emplace("binding"_cs, tblname); auto result = ctxt->conv->convert(info->destinationField); - jmtr->emplace("result_target", result->to()->get("value")); + jmtr->emplace("result_target"_cs, result->to()->get("value"_cs)); ctxt->json->meter_arrays->append(jmtr); } @@ -736,9 +736,9 @@ void ExternConverter_action_profile::convertExternInstance(ConversionContext *ct // once in a pipeline, so only add it to the action_profiles once if (BMV2::JsonObjects::find_object_by_name(ctxt->action_profiles, name)) return; auto action_profile = new Util::JsonObject(); - action_profile->emplace("name", name); - action_profile->emplace("id", nextId("action_profiles")); - action_profile->emplace_non_null("source_info", eb->sourceInfoJsonObj()); + action_profile->emplace("name"_cs, name); + action_profile->emplace("id"_cs, nextId("action_profiles"_cs)); + action_profile->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); auto add_size = [&action_profile, &eb](const cstring &pname) { auto sz = eb->findParameterValue(pname); @@ -748,7 +748,7 @@ void ExternConverter_action_profile::convertExternInstance(ConversionContext *ct ::error(ErrorType::ERR_EXPECTED, "%1%: expected a constant", sz); return; } - action_profile->emplace("max_size", sz->to()->value); + action_profile->emplace("max_size"_cs, sz->to()->value); }; if (eb->type->name == v1model.action_profile.name) { @@ -762,7 +762,7 @@ void ExternConverter_action_profile::convertExternInstance(ConversionContext *ct return; } auto algo = ExternConverter::convertHashAlgorithm(hash->to()->name); - selector->emplace("algo", algo); + selector->emplace("algo"_cs, algo); auto input = ctxt->get_selector_input(inst); if (input == nullptr) { // the selector is never used by any table, we cannot figure out its @@ -773,12 +773,12 @@ void ExternConverter_action_profile::convertExternInstance(ConversionContext *ct c); return; } - auto j_input = mkArrayField(selector, "input"); + auto j_input = mkArrayField(selector, "input"_cs); for (auto expr : *input) { auto jk = ctxt->conv->convert(expr); j_input->append(jk); } - action_profile->emplace("selector", selector); + action_profile->emplace("selector"_cs, selector); } ctxt->action_profiles->append(action_profile); @@ -795,9 +795,9 @@ void ExternConverter_action_selector::convertExternInstance(ConversionContext *c // once in a pipeline, so only add it to the action_profiles once if (BMV2::JsonObjects::find_object_by_name(ctxt->action_profiles, name)) return; auto action_profile = new Util::JsonObject(); - action_profile->emplace("name", name); - action_profile->emplace("id", nextId("action_profiles")); - action_profile->emplace_non_null("source_info", eb->sourceInfoJsonObj()); + action_profile->emplace("name"_cs, name); + action_profile->emplace("id"_cs, nextId("action_profiles"_cs)); + action_profile->emplace_non_null("source_info"_cs, eb->sourceInfoJsonObj()); auto add_size = [&action_profile, &eb](const cstring &pname) { auto sz = eb->findParameterValue(pname); @@ -807,7 +807,7 @@ void ExternConverter_action_selector::convertExternInstance(ConversionContext *c ::error(ErrorType::ERR_EXPECTED, "%1%: expected a constant", sz); return; } - action_profile->emplace("max_size", sz->to()->value); + action_profile->emplace("max_size"_cs, sz->to()->value); }; if (eb->type->name == v1model.action_profile.name) { @@ -821,7 +821,7 @@ void ExternConverter_action_selector::convertExternInstance(ConversionContext *c return; } auto algo = ExternConverter::convertHashAlgorithm(hash->to()->name); - selector->emplace("algo", algo); + selector->emplace("algo"_cs, algo); auto input = ctxt->get_selector_input(inst); if (input == nullptr) { // the selector is never used by any table, we cannot figure out its @@ -832,12 +832,12 @@ void ExternConverter_action_selector::convertExternInstance(ConversionContext *c c); return; } - auto j_input = mkArrayField(selector, "input"); + auto j_input = mkArrayField(selector, "input"_cs); for (auto expr : *input) { auto jk = ctxt->conv->convert(expr); j_input->append(jk); } - action_profile->emplace("selector", selector); + action_profile->emplace("selector"_cs, selector); } ctxt->action_profiles->append(action_profile); @@ -852,11 +852,11 @@ Util::IJson *ExternConverter_log_msg::convertExternFunction(ConversionContext *c modelError("Expected 1 or 2 arguments for %1%", mc); return nullptr; } - auto primitive = mkPrimitive("log_msg"); + auto primitive = mkPrimitive("log_msg"_cs); auto params = mkParameters(primitive); - primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + primitive->emplace_non_null("source_info"_cs, s->sourceInfoJsonObj()); auto paramsValue = new Util::JsonObject(); - paramsValue->emplace("type", "parameters_vector"); + paramsValue->emplace("type"_cs, "parameters_vector"); auto str = ctxt->conv->convert(mc->arguments->at(0)->expression); params->append(str); if (mc->arguments->size() == 2) { @@ -882,18 +882,18 @@ Util::IJson *ExternConverter_log_msg::convertExternFunction(ConversionContext *c auto val = ctxt->conv->convert(v, false, true, true); arr->append(val); } - paramsValue->emplace("value", arr); + paramsValue->emplace("value"_cs, arr); } else { auto tmp = new Util::JsonObject(); - paramsValue->emplace("value", tmp); + paramsValue->emplace("value"_cs, tmp); } params->append(paramsValue); return primitive; } void SimpleSwitchBackend::modelError(const char *format, const IR::Node *node) const { - ::error(ErrorType::ERR_MODEL, - (cstring("%1%") + format + "\nAre you using an up-to-date v1model.p4?").c_str(), node); + ::errorWithSuffix(ErrorType::ERR_MODEL, format, "\nAre you using an up-to-date v1model.p4?", + node); } cstring SimpleSwitchBackend::createCalculation(cstring algo, const IR::Expression *fields, @@ -901,11 +901,11 @@ cstring SimpleSwitchBackend::createCalculation(cstring algo, const IR::Expressio const IR::Node *sourcePositionNode = nullptr) { cstring calcName = refMap->newName("calc_"); auto calc = new Util::JsonObject(); - calc->emplace("name", calcName); - calc->emplace("id", nextId("calculations")); + calc->emplace("name"_cs, calcName); + calc->emplace("id"_cs, nextId("calculations"_cs)); if (sourcePositionNode != nullptr) - calc->emplace_non_null("source_info", sourcePositionNode->sourceInfoJsonObj()); - calc->emplace("algo", algo); + calc->emplace_non_null("source_info"_cs, sourcePositionNode->sourceInfoJsonObj()); + calc->emplace("algo"_cs, algo); fields = convertToList(fields, typeMap); if (!fields) { modelError("%1%: expected a struct", fields); @@ -916,11 +916,11 @@ cstring SimpleSwitchBackend::createCalculation(cstring algo, const IR::Expressio auto array = jright->to(); BUG_CHECK(array, "expected a JSON array"); auto payload = new Util::JsonObject(); - payload->emplace("type", "payload"); - payload->emplace("value", (Util::IJson *)nullptr); + payload->emplace("type"_cs, "payload"); + payload->emplace("value"_cs, (Util::IJson *)nullptr); array->append(payload); } - calc->emplace("input", jright); + calc->emplace("input"_cs, jright); calculations->append(calc); return calcName; } @@ -978,18 +978,18 @@ void SimpleSwitchBackend::convertChecksum(const IR::BlockStatement *block, (void)calcExpr->apply(eeis); cstring calcName = createCalculation(algo, calcExpr, calculations, usePayload, mc); - cksum->emplace("name", refMap->newName("cksum_")); - cksum->emplace("id", nextId("checksums")); - cksum->emplace_non_null("source_info", stat->sourceInfoJsonObj()); + cksum->emplace("name"_cs, refMap->newName("cksum_")); + cksum->emplace("id"_cs, nextId("checksums"_cs)); + cksum->emplace_non_null("source_info"_cs, stat->sourceInfoJsonObj()); auto jleft = conv->convert(mi->expr->arguments->at(2)->expression); - cksum->emplace("target", jleft->to()->get("value")); - cksum->emplace("type", "generic"); - cksum->emplace("calculation", calcName); - cksum->emplace("verify", verify); - cksum->emplace("update", !verify); + cksum->emplace("target"_cs, jleft->to()->get("value"_cs)); + cksum->emplace("type"_cs, "generic"); + cksum->emplace("calculation"_cs, calcName); + cksum->emplace("verify"_cs, verify); + cksum->emplace("update"_cs, !verify); auto ifcond = conv->convert(mi->expr->arguments->at(0)->expression, true, false); - cksum->emplace("if_cond", ifcond); + cksum->emplace("if_cond"_cs, ifcond); checksums->append(cksum); continue; } @@ -1037,7 +1037,7 @@ void SimpleSwitchBackend::createRecirculateFieldsList(ConversionContext *ctxt, LOG2("Scanning user metadata fields for annotations"); for (auto f : userMetaType->fields) { LOG3("Scanning field " << f); - auto anno = f->getAnnotations()->getSingle("field_list"); + auto anno = f->getAnnotations()->getSingle("field_list"_cs); if (anno == nullptr) continue; for (auto e : anno->expr) { @@ -1055,23 +1055,23 @@ void SimpleSwitchBackend::createRecirculateFieldsList(ConversionContext *ctxt, fl = new Util::JsonObject(); ctxt->json->field_lists->append(fl); fieldLists.emplace(index, fl); - int id = nextId("field_lists"); - fl->emplace("id", id); - cstring listName = cstring("field_list") + Util::toString(index); - fl->emplace("name", listName); - elements = mkArrayField(fl, "elements"); + int id = nextId("field_lists"_cs); + fl->emplace("id"_cs, id); + cstring listName = "field_list"_cs + Util::toString(index); + fl->emplace("name"_cs, listName); + elements = mkArrayField(fl, "elements"_cs); } else { - elements = fl->get("elements")->to(); + elements = fl->get("elements"_cs)->to(); CHECK_NULL(elements); } auto field = new Util::JsonObject(); - field->emplace("type", "field"); + field->emplace("type"_cs, "field"); auto value = new Util::JsonArray(); value->append(scalarName); auto name = ::get(ctxt->structure->scalarMetadataFields, f); value->append(name); - field->emplace("value", value); + field->emplace("value"_cs, value); elements->append(field); } } @@ -1205,8 +1205,8 @@ void SimpleSwitchBackend::convert(const IR::ToplevelBlock *tlb) { // other objects: they need to start at 1 (not 0) since the id is also used // as a "flag" to indicate that a certain simple_switch primitive has been // called (e.g. resubmit or generate_digest) - BMV2::nextId("field_lists"); - BMV2::nextId("learn_lists"); + BMV2::nextId("field_lists"_cs); + BMV2::nextId("learn_lists"_cs); json->add_program_info(options.file); json->add_meta_info(); @@ -1250,11 +1250,11 @@ void SimpleSwitchBackend::convert(const IR::ToplevelBlock *tlb) { ctxt->blockConverted = BlockConverted::Ingress; auto cconv = - new ControlConverter(ctxt, "ingress", options.emitExterns); + new ControlConverter(ctxt, "ingress"_cs, options.emitExterns); structure->ingress->apply(*cconv); ctxt->blockConverted = BlockConverted::Egress; - cconv = new ControlConverter(ctxt, "egress", options.emitExterns); + cconv = new ControlConverter(ctxt, "egress"_cs, options.emitExterns); structure->egress->apply(*cconv); ctxt->blockConverted = BlockConverted::Deparser; diff --git a/backends/bmv2/simple_switch/simpleSwitch.h b/backends/bmv2/simple_switch/simpleSwitch.h index a17c9b5d46..e0e43fa75a 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.h +++ b/backends/bmv2/simple_switch/simpleSwitch.h @@ -79,8 +79,8 @@ class SimpleSwitchExpressionConverter : public ExpressionConverter { : ExpressionConverter(refMap, typeMap, structure, scalarsName), structure(structure) {} void modelError(const char *format, const IR::Node *node) { - ::error(ErrorType::ERR_MODEL, - (cstring(format) + "\nAre you using an up-to-date v1model.p4?").c_str(), node); + ::errorWithSuffix(ErrorType::ERR_MODEL, format, "\nAre you using an up-to-date v1model.p4?", + node); } bool isStandardMetadataParameter(const IR::Parameter *param) { @@ -112,13 +112,13 @@ class SimpleSwitchExpressionConverter : public ExpressionConverter { if (isStandardMetadataParameter(param)) { auto result = new Util::JsonObject(); if (fieldName != "") { - result->emplace("type", "field"); - auto e = BMV2::mkArrayField(result, "value"); + result->emplace("type"_cs, "field"); + auto e = BMV2::mkArrayField(result, "value"_cs); e->append("standard_metadata"); e->append(fieldName); } else { - result->emplace("type", "header"); - result->emplace("value", "standard_metadata"); + result->emplace("type"_cs, "header"); + result->emplace("value"_cs, "standard_metadata"); } return result; } diff --git a/backends/dpdk/constants.h b/backends/dpdk/constants.h index 0e07bcc2ee..03fe6aa731 100644 --- a/backends/dpdk/constants.h +++ b/backends/dpdk/constants.h @@ -35,10 +35,11 @@ const unsigned default_learner_table_timeout[dpdk_learner_max_configurable_timeo 10, 30, 60, 120, 300, 43200, 120, 120}; /// JSON schema versions -const cstring bfrtSchemaVersion = "1.0.0"; -const cstring tdiSchemaVersion = "0.1"; +const cstring bfrtSchemaVersion = cstring::literal("1.0.0"); +const cstring tdiSchemaVersion = cstring::literal("0.1"); /// HASH Values +// FIXME: These should be enum #define JHASH0 0 #define CRC1 1 #define CRC2 2 diff --git a/backends/dpdk/control-plane/bfruntime_arch_handler.h b/backends/dpdk/control-plane/bfruntime_arch_handler.h index d77d6a9216..ab0b1103db 100644 --- a/backends/dpdk/control-plane/bfruntime_arch_handler.h +++ b/backends/dpdk/control-plane/bfruntime_arch_handler.h @@ -136,7 +136,7 @@ class BFRuntimeArchHandler : public P4RuntimeArchHandlerCommon { cstring getBlockNamePrefix(const IR::Block *blk) { if (blockNamePrefixMap.count(blk) > 0) return blockNamePrefixMap[blk]; - return "pipe"; + return "pipe"_cs; } static p4configv1::Extern *getP4InfoExtern(P4RuntimeSymbolType typeId, cstring typeName, @@ -154,7 +154,8 @@ class BFRuntimeArchHandler : public P4RuntimeArchHandlerCommon { P4RuntimeSymbolType typeId, cstring typeName, cstring name, const IR::IAnnotated *annotations, const ::google::protobuf::Message &message, - p4configv1::P4Info *p4info, cstring pipeName = "") { + p4configv1::P4Info *p4info, + cstring pipeName = cstring::empty) { auto *externType = getP4InfoExtern(typeId, typeName, p4info); auto *externInstance = externType->add_instances(); auto *pre = externInstance->mutable_preamble(); @@ -169,7 +170,7 @@ class BFRuntimeArchHandler : public P4RuntimeArchHandlerCommon { std::optional getActionSelector(const IR::ExternBlock *instance) { auto actionSelDecl = instance->node->to(); // to be deleted, used to support deprecated ActionSelector constructor. - auto size = instance->getParameterValue("size"); + auto size = instance->getParameterValue("size"_cs); BUG_CHECK(size->is(), "Non-constant size"); return ActionSelector{actionSelDecl->controlPlaneName(), size->to()->asInt(), ActionSelector::defaultMaxGroupSize, @@ -178,7 +179,8 @@ class BFRuntimeArchHandler : public P4RuntimeArchHandlerCommon { } void addActionSelector(const P4RuntimeSymbolTableIface &symbols, p4configv1::P4Info *p4Info, - const ActionSelector &actionSelector, cstring pipeName = "") { + const ActionSelector &actionSelector, + cstring pipeName = cstring::empty) { ::dpdk::ActionSelector selector; selector.set_max_group_size(actionSelector.maxGroupSize); selector.set_num_groups(actionSelector.numGroups); @@ -197,9 +199,9 @@ class BFRuntimeArchHandler : public P4RuntimeArchHandlerCommon { selector.set_action_profile_id( symbols.getId(SymbolType::P4RT_ACTION_PROFILE(), profileName)); cstring selectorName = profileName + "_sel"; - addP4InfoExternInstance(symbols, SymbolTypeDPDK::P4RT_ACTION_SELECTOR(), "ActionSelector", - selectorName, actionSelector.annotations, selector, p4Info, - pipeName); + addP4InfoExternInstance(symbols, SymbolTypeDPDK::P4RT_ACTION_SELECTOR(), + "ActionSelector"_cs, selectorName, actionSelector.annotations, + selector, p4Info, pipeName); } void collectExternInstance(P4RuntimeSymbolTableIface *symbols, @@ -316,7 +318,7 @@ class BFRuntimeArchHandler : public P4RuntimeArchHandlerCommon { /// @return true if @table's 'psa_idle_timeout' property exists and is true. This /// indicates that @table supports entry ageing. static bool getSupportsTimeout(const IR::P4Table *table) { - auto timeout = table->properties->getProperty("psa_idle_timeout"); + auto timeout = table->properties->getProperty("psa_idle_timeout"_cs); if (timeout == nullptr) return false; diff --git a/backends/dpdk/control-plane/bfruntime_ext.cpp b/backends/dpdk/control-plane/bfruntime_ext.cpp index f81468cc3c..693735baf5 100644 --- a/backends/dpdk/control-plane/bfruntime_ext.cpp +++ b/backends/dpdk/control-plane/bfruntime_ext.cpp @@ -60,22 +60,22 @@ void BFRuntimeSchemaGenerator::addMatchActionData(const p4configv1::Table &table Util::JsonObject *tableJson, Util::JsonArray *dataJson, P4Id maxActionParamId) const { - cstring tableType = tableJson->get("table_type")->to()->getString(); + cstring tableType = tableJson->get("table_type"_cs)->to()->getString(); if (tableType == "MatchAction_Direct") { - tableJson->emplace("action_specs", makeActionSpecs(table, &maxActionParamId)); + tableJson->emplace("action_specs"_cs, makeActionSpecs(table, &maxActionParamId)); } else if (tableType == "MatchAction_Indirect") { - auto *f = makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID", - makeType("uint32"), false /* repeated */); + auto *f = makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID"_cs, + makeType("uint32"_cs), false /* repeated */); addSingleton(dataJson, f, true /* mandatory */, false /* read-only */); } else if (tableType == "MatchAction_Indirect_Selector") { // action member id and selector group id are mutually-exclusive, so // we use a "oneof" here. auto *choicesDataJson = new Util::JsonArray(); choicesDataJson->append(makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_ID, - "$ACTION_MEMBER_ID", makeType("uint32"), + "$ACTION_MEMBER_ID"_cs, makeType("uint32"_cs), false /* repeated */)); choicesDataJson->append(makeCommonDataField(BF_RT_DATA_SELECTOR_GROUP_ID, - "$SELECTOR_GROUP_ID", makeType("uint32"), + "$SELECTOR_GROUP_ID"_cs, makeType("uint32"_cs), false /* repeated */)); addOneOf(dataJson, choicesDataJson, true /* mandatory */, false /* read-only */); } else { @@ -85,26 +85,27 @@ void BFRuntimeSchemaGenerator::addMatchActionData(const p4configv1::Table &table void BFRuntimeSchemaGenerator::addActionSelectorGetMemberCommon( Util::JsonArray *tablesJson, const ActionSelector &actionSelector) const { - auto *tableJson = initTableJson(actionSelector.get_mem_name, actionSelector.get_mem_id, - "SelectorGetMember", 1 /* size */, actionSelector.annotations); + auto *tableJson = + initTableJson(actionSelector.get_mem_name, actionSelector.get_mem_id, + "SelectorGetMember"_cs, 1 /* size */, actionSelector.annotations); auto *keyJson = new Util::JsonArray(); - addKeyField(keyJson, BF_RT_DATA_SELECTOR_GROUP_ID, "$SELECTOR_GROUP_ID", true /* mandatory */, - "Exact", makeType("uint64")); - addKeyField(keyJson, BF_RT_DATA_HASH_VALUE, "hash_value", true /* mandatory */, "Exact", - makeType("uint64")); - tableJson->emplace("key", keyJson); + addKeyField(keyJson, BF_RT_DATA_SELECTOR_GROUP_ID, "$SELECTOR_GROUP_ID"_cs, + true /* mandatory */, "Exact"_cs, makeType("uint64"_cs)); + addKeyField(keyJson, BF_RT_DATA_HASH_VALUE, "hash_value"_cs, true /* mandatory */, "Exact"_cs, + makeType("uint64"_cs)); + tableJson->emplace("key"_cs, keyJson); auto *dataJson = new Util::JsonArray(); { - auto *f = makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID", - makeType("uint64"), false /* repeated */); + auto *f = makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID"_cs, + makeType("uint64"_cs), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } - tableJson->emplace("data", dataJson); + tableJson->emplace("data"_cs, dataJson); - tableJson->emplace("supported_operations", new Util::JsonArray()); - tableJson->emplace("attributes", new Util::JsonArray()); + tableJson->emplace("supported_operations"_cs, new Util::JsonArray()); + tableJson->emplace("attributes"_cs, new Util::JsonArray()); addToDependsOn(tableJson, actionSelector.id); tablesJson->append(tableJson); @@ -115,35 +116,35 @@ void BFRuntimeSchemaGenerator::addActionSelectorCommon(Util::JsonArray *tablesJs // TODO(antonin): formalize ID allocation for selector tables // repeat same annotations as for action table // the maximum number of groups is the table size for the selector table - auto *tableJson = initTableJson(actionSelector.name, actionSelector.id, "Selector", + auto *tableJson = initTableJson(actionSelector.name, actionSelector.id, "Selector"_cs, actionSelector.num_groups, actionSelector.annotations); auto *keyJson = new Util::JsonArray(); - addKeyField(keyJson, BF_RT_DATA_SELECTOR_GROUP_ID, "$SELECTOR_GROUP_ID", true /* mandatory */, - "Exact", makeType("uint32")); - tableJson->emplace("key", keyJson); + addKeyField(keyJson, BF_RT_DATA_SELECTOR_GROUP_ID, "$SELECTOR_GROUP_ID"_cs, + true /* mandatory */, "Exact"_cs, makeType("uint32"_cs)); + tableJson->emplace("key"_cs, keyJson); auto *dataJson = new Util::JsonArray(); { - auto *f = makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID", - makeType("uint32"), true /* repeated */); + auto *f = makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID"_cs, + makeType("uint32"_cs), true /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } { - auto *f = makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_STATUS, "$ACTION_MEMBER_STATUS", + auto *f = makeCommonDataField(BF_RT_DATA_ACTION_MEMBER_STATUS, "$ACTION_MEMBER_STATUS"_cs, makeTypeBool(), true /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } { - auto *f = makeCommonDataField(BF_RT_DATA_MAX_GROUP_SIZE, "$MAX_GROUP_SIZE", - makeType("uint32", actionSelector.max_group_size), + auto *f = makeCommonDataField(BF_RT_DATA_MAX_GROUP_SIZE, "$MAX_GROUP_SIZE"_cs, + makeType("uint32"_cs, actionSelector.max_group_size), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } - tableJson->emplace("data", dataJson); + tableJson->emplace("data"_cs, dataJson); - tableJson->emplace("supported_operations", new Util::JsonArray()); - tableJson->emplace("attributes", new Util::JsonArray()); + tableJson->emplace("supported_operations"_cs, new Util::JsonArray()); + tableJson->emplace("attributes"_cs, new Util::JsonArray()); addToDependsOn(tableJson, actionSelector.action_profile_id); auto oneTableId = actionSelector.tableIds.at(0); @@ -168,16 +169,16 @@ bool BFRuntimeSchemaGenerator::addActionProfIds(const p4configv1::Table &table, implementationId); return false; } - cstring tableType = ""; + cstring tableType; if (*hasSelector) { - tableType = "MatchAction_Indirect_Selector"; + tableType = "MatchAction_Indirect_Selector"_cs; // actSelectorId & actProfId will be set while visiting action profile externs } else { actProfId = BFRuntimeSchemaGenerator::ActionProf::makeActProfId(implementationId); - tableType = "MatchAction_Indirect"; + tableType = "MatchAction_Indirect"_cs; } - tableJson->erase("table_type"); - tableJson->emplace("table_type", tableType); + tableJson->erase("table_type"_cs); + tableJson->emplace("table_type"_cs, tableType); } if (actProfId > 0) addToDependsOn(tableJson, actProfId); @@ -199,7 +200,7 @@ void BFRuntimeSchemaGenerator::addActionProfs(Util::JsonArray *tablesJson) const bool BFRuntimeSchemaGenerator::addMatchTypePriority(std::optional &matchType) const { if (*matchType == "Ternary" || *matchType == "Range" || *matchType == "Optional") { - *matchType = "Ternary"; + *matchType = "Ternary"_cs; return true; } return false; @@ -224,22 +225,22 @@ const Util::JsonObject *BFRuntimeSchemaGenerator::genSchema() const { auto fileName = progName.findlast('/'); // Handle the case when input file is in the current working directory. // fileName would be null in that case, hence progName should remain unchanged. - if (fileName) progName = fileName; - auto fileext = progName.find("."); - progName = progName.replace(fileext, ""); + if (fileName) progName = cstring(fileName); + auto fileext = cstring(progName.find(".")); + progName = cstring(progName.replace(fileext, cstring::empty)); progName = progName.trim("/\t\n\r"); - json->emplace("program_name", progName); - json->emplace("build_date", cstring(options.getBuildDate())); - json->emplace("compile_command", cstring(options.getCompileCommand())); - json->emplace("compiler_version", cstring(options.compilerVersion)); - json->emplace("schema_version", tdiSchemaVersion); - json->emplace("target", cstring("DPDK")); + json->emplace("program_name"_cs, progName); + json->emplace("build_date"_cs, cstring(options.getBuildDate())); + json->emplace("compile_command"_cs, cstring(options.getCompileCommand())); + json->emplace("compiler_version"_cs, cstring(options.compilerVersion)); + json->emplace("schema_version"_cs, tdiSchemaVersion); + json->emplace("target"_cs, "DPDK"); } else { - json->emplace("schema_version", bfrtSchemaVersion); + json->emplace("schema_version"_cs, bfrtSchemaVersion); } auto *tablesJson = new Util::JsonArray(); - json->emplace("tables", tablesJson); + json->emplace("tables"_cs, tablesJson); addMatchTables(tablesJson); addActionProfs(tablesJson); @@ -248,7 +249,7 @@ const Util::JsonObject *BFRuntimeSchemaGenerator::genSchema() const { addRegisters(tablesJson); auto *learnFiltersJson = new Util::JsonArray(); - json->emplace("learn_filters", learnFiltersJson); + json->emplace("learn_filters"_cs, learnFiltersJson); addLearnFilters(learnFiltersJson); addDPDKExterns(tablesJson, learnFiltersJson); diff --git a/backends/dpdk/dpdk.def b/backends/dpdk/dpdk.def index 02b3a464b7..3e59bb6ff8 100644 --- a/backends/dpdk/dpdk.def +++ b/backends/dpdk/dpdk.def @@ -160,21 +160,21 @@ abstract DpdkJmpStatement : DpdkAsmStatement { class DpdkJmpLabelStatement : DpdkJmpStatement { #noconstructor DpdkJmpLabelStatement(cstring label) : - DpdkJmpStatement("jmp", label) { } + DpdkJmpStatement("jmp"_cs, label) { } } class DpdkJmpHitStatement : DpdkJmpStatement { #nodbprint #noconstructor DpdkJmpHitStatement(cstring label) : - DpdkJmpStatement("jmph", label) { } + DpdkJmpStatement("jmph"_cs, label) { } } class DpdkJmpMissStatement : DpdkJmpStatement { #nodbprint #noconstructor DpdkJmpMissStatement(cstring label) : - DpdkJmpStatement("jmpnh", label) { } + DpdkJmpStatement("jmpnh"_cs, label) { } } abstract DpdkJmpActionStatement : DpdkJmpStatement { @@ -190,14 +190,14 @@ class DpdkJmpIfActionRunStatement : DpdkJmpActionStatement { #nodbprint #noconstructor DpdkJmpIfActionRunStatement(cstring label, cstring act) : - DpdkJmpActionStatement("jmpa", label, act) { } + DpdkJmpActionStatement("jmpa"_cs, label, act) { } } class DpdkJmpIfActionNotRunStatement : DpdkJmpActionStatement { #nodbprint #noconstructor DpdkJmpIfActionNotRunStatement(cstring label, cstring act) : - DpdkJmpActionStatement("jmpna", label, act) { } + DpdkJmpActionStatement("jmpna"_cs, label, act) { } } abstract DpdkJmpHeaderStatement : DpdkJmpStatement { @@ -211,14 +211,14 @@ abstract DpdkJmpHeaderStatement : DpdkJmpStatement { class DpdkJmpIfInvalidStatement : DpdkJmpHeaderStatement { #noconstructor DpdkJmpIfInvalidStatement(cstring label, Expression hdr) : - DpdkJmpHeaderStatement("jmpnv", label, hdr) { } + DpdkJmpHeaderStatement("jmpnv"_cs, label, hdr) { } } class DpdkJmpIfValidStatement : DpdkJmpHeaderStatement { #nodbprint #noconstructor DpdkJmpIfValidStatement(cstring label, Expression hdr) : - DpdkJmpHeaderStatement("jmpv", label, hdr) { } + DpdkJmpHeaderStatement("jmpv"_cs, label, hdr) { } } abstract DpdkJmpCondStatement : DpdkJmpStatement { @@ -232,42 +232,42 @@ abstract DpdkJmpCondStatement : DpdkJmpStatement { class DpdkJmpEqualStatement: DpdkJmpCondStatement, IDPDKNode { DpdkJmpEqualStatement(cstring label, Expression src1, Expression src2) : - DpdkJmpCondStatement("jmpeq", label, src1, src2) { } + DpdkJmpCondStatement("jmpeq"_cs, label, src1, src2) { } #noconstructor } class DpdkJmpNotEqualStatement: DpdkJmpCondStatement, IDPDKNode { #noconstructor DpdkJmpNotEqualStatement(cstring label, Expression src1, Expression src2) : - DpdkJmpCondStatement("jmpneq", label, src1, src2) { } + DpdkJmpCondStatement("jmpneq"_cs, label, src1, src2) { } } class DpdkJmpGreaterEqualStatement: DpdkJmpCondStatement, IDPDKNode { #nodbprint #noconstructor DpdkJmpGreaterEqualStatement(cstring label, Expression src1, Expression src2) : - DpdkJmpCondStatement("jmpge", label, src1, src2) { } + DpdkJmpCondStatement("jmpge"_cs, label, src1, src2) { } } class DpdkJmpGreaterStatement: DpdkJmpCondStatement, IDPDKNode { #nodbprint #noconstructor DpdkJmpGreaterStatement(cstring label, Expression src1, Expression src2) : - DpdkJmpCondStatement("jmpgt", label, src1, src2) { } + DpdkJmpCondStatement("jmpgt"_cs, label, src1, src2) { } } class DpdkJmpLessOrEqualStatement: DpdkJmpCondStatement, IDPDKNode { #nodbprint #noconstructor DpdkJmpLessOrEqualStatement(cstring label, Expression src1, Expression src2) : - DpdkJmpCondStatement("jmple", label, src1, src2) { } + DpdkJmpCondStatement("jmple"_cs, label, src1, src2) { } } class DpdkJmpLessStatement: DpdkJmpCondStatement, IDPDKNode { #nodbprint #noconstructor DpdkJmpLessStatement(cstring label, Expression src1, Expression src2) : - DpdkJmpCondStatement("jmplt", label, src1, src2) { } + DpdkJmpCondStatement("jmplt"_cs, label, src1, src2) { } } class DpdkRxStatement : DpdkAsmStatement, IDPDKNode { @@ -300,7 +300,7 @@ abstract DpdkUnaryStatement : DpdkAssignmentStatement { class DpdkMovStatement : DpdkUnaryStatement { DpdkMovStatement(Expression dst, Expression src) : - DpdkUnaryStatement("mov", dst, src) { } + DpdkUnaryStatement("mov"_cs, dst, src) { } #noconstructor } @@ -317,49 +317,49 @@ class DpdkAddStatement : DpdkBinaryStatement { #nodbprint #noconstructor DpdkAddStatement(Expression dst, Expression src1, Expression src2) : - DpdkBinaryStatement("add", dst, src1, src2) { } + DpdkBinaryStatement("add"_cs, dst, src1, src2) { } } class DpdkAndStatement : DpdkBinaryStatement, IDPDKNode { #nodbprint #noconstructor DpdkAndStatement(Expression dst, Expression src1, Expression src2) : - DpdkBinaryStatement("and", dst, src1, src2) { } + DpdkBinaryStatement("and"_cs, dst, src1, src2) { } } class DpdkShlStatement : DpdkBinaryStatement, IDPDKNode { #nodbprint #noconstructor DpdkShlStatement(Expression dst, Expression src1, Expression src2) : - DpdkBinaryStatement("shl", dst, src1, src2) { } + DpdkBinaryStatement("shl"_cs, dst, src1, src2) { } } class DpdkShrStatement : DpdkBinaryStatement, IDPDKNode { #nodbprint #noconstructor DpdkShrStatement(Expression dst, Expression src1, Expression src2) : - DpdkBinaryStatement("shr", dst, src1, src2) { } + DpdkBinaryStatement("shr"_cs, dst, src1, src2) { } } class DpdkSubStatement : DpdkBinaryStatement, IDPDKNode { #nodbprint #noconstructor DpdkSubStatement(Expression dst, Expression src1, Expression src2) : - DpdkBinaryStatement("sub", dst, src1, src2) { } + DpdkBinaryStatement("sub"_cs, dst, src1, src2) { } } class DpdkOrStatement : DpdkBinaryStatement, IDPDKNode { #nodbprint #noconstructor DpdkOrStatement(Expression dst, Expression src1, Expression src2) : - DpdkBinaryStatement("or", dst, src1, src2) { } + DpdkBinaryStatement("or"_cs, dst, src1, src2) { } } class DpdkXorStatement : DpdkBinaryStatement, IDPDKNode { #nodbprint #noconstructor DpdkXorStatement(Expression dst, Expression src1, Expression src2) : - DpdkBinaryStatement("xor", dst, src1, src2) { } + DpdkBinaryStatement("xor"_cs, dst, src1, src2) { } } class DpdkRecircidStatement : DpdkAsmStatement, IDPDKNode { @@ -499,7 +499,7 @@ class DpdkRegisterReadStatement: DpdkAssignmentStatement { #nodbprint #noconstructor DpdkRegisterReadStatement(Expression dst, cstring reg, Expression index) : - DpdkAssignmentStatement("read", dst), reg(reg), index(index) { } + DpdkAssignmentStatement("read"_cs, dst), reg(reg), index(index) { } } class DpdkRegisterWriteStatement: DpdkAsmStatement, IDPDKNode { diff --git a/backends/dpdk/dpdkArch.cpp b/backends/dpdk/dpdkArch.cpp index 2fa91d69d1..0f774047ee 100644 --- a/backends/dpdk/dpdkArch.cpp +++ b/backends/dpdk/dpdkArch.cpp @@ -29,6 +29,7 @@ limitations under the License. #include "frontends/p4/externInstance.h" #include "frontends/p4/tableApply.h" #include "frontends/p4/typeMap.h" +#include "lib/cstring.h" namespace DPDK { @@ -36,7 +37,7 @@ cstring TypeStruct2Name(const cstring s) { if (isStandardMetadata(s)) { return s.substr(0, s.size() - 2); } else { - return "local_metadata"; + return "local_metadata"_cs; } } @@ -498,7 +499,7 @@ const IR::Node *AlignHdrMetaField::preorder(IR::Type_StructLike *st) { field_name_list.emplace(field->name, obj); } } - cstring modifiedName = ""; + cstring modifiedName = cstring::empty; auto size = field_name_list.size(); unsigned i = 0; // Check if the sum of width of non-aligned field is divisble by 8. @@ -552,7 +553,7 @@ const IR::Node *AlignHdrMetaField::preorder(IR::Type_StructLike *st) { fields->push_back( new IR::StructField(IR::ID(modifiedName), IR::Type_Bits::get(size_sum_so_far))); size_sum_so_far = 0; - modifiedName = ""; + modifiedName = cstring::empty; field_name_list.clear(); } } @@ -592,7 +593,7 @@ const IR::Node *AlignHdrMetaField::preorder(IR::Type_StructLike *st) { if (hdrs.ipv4.flags_fragOffset[15:3] == 4) .... */ const IR::Node *AlignHdrMetaField::preorder(IR::Member *m) { - cstring hdrStrName = ""; + cstring hdrStrName = cstring::empty; // Get the member's header structure name. if ((m != nullptr) && (m->expr != nullptr) && (m->expr->type != nullptr) && (m->expr->type->is())) { @@ -1225,7 +1226,7 @@ const IR::Node *CollectLocalVariables::postorder(IR::P4Parser *p) { /// This function stores the information about parameters of default action /// for each table. void DefActionValue::postorder(const IR::P4Table *t) { - auto default_action = t->properties->getProperty("default_action"); + auto default_action = t->properties->getProperty("default_action"_cs); if (default_action != nullptr && default_action->value->is()) { auto expr = default_action->value->to()->expression; auto mi = @@ -1456,7 +1457,7 @@ const IR::Node *DismantleMuxExpressions::postorder(IR::AssignmentStatement *stat bool CopyMatchKeysToSingleStruct::isLearnerTable(const IR::P4Table *t) { bool use_add_on_miss = false; - auto add_on_miss = t->properties->getProperty("add_on_miss"); + auto add_on_miss = t->properties->getProperty("add_on_miss"_cs); if (add_on_miss == nullptr) return false; if (add_on_miss->value->is()) { auto expr = add_on_miss->value->to()->expression; @@ -1580,7 +1581,7 @@ const IR::Node *CopyMatchKeysToSingleStruct::preorder(IR::Key *keys) { return keys; } - cstring firstKeyStr = ""; + cstring firstKeyStr = cstring::empty; bool firstKeyHdr = false; if (auto firstKeyField = keys->keyElements.at(0)->expression->to()) { @@ -1593,7 +1594,7 @@ const IR::Node *CopyMatchKeysToSingleStruct::preorder(IR::Key *keys) { // Key fields should be part of same header/metadata struct. for (auto key : keys->keyElements) { - cstring keyTypeStr = ""; + cstring keyTypeStr = cstring::empty; if (auto keyField = key->expression->to()) { keyTypeStr = keyField->expr->toString(); } else if (auto m = key->expression->to()) { @@ -1696,19 +1697,19 @@ const IR::Node *CopyMatchKeysToSingleStruct::postorder(IR::KeyElement *element) isHeader = true; keyName = keyName.replace('.', '_'); keyName = - keyName.replace("h_", control->name.toString() + "_" + table->name.toString() + "_"); + keyName.replace("h_"_cs, control->name.toString() + "_" + table->name.toString() + "_"); } else if (metaCopyNeeded) { if (keyName.startsWith("m.")) { keyName = keyName.replace('.', '_'); keyName = keyName.replace( - "m_", control->name.toString() + "_" + table->name.toString() + "_"); + "m_"_cs, control->name.toString() + "_" + table->name.toString() + "_"); } else { keyName = control->name.toString() + "_" + table->name.toString() + "_" + keyName; } } if (isHeader || metaCopyNeeded) { - IR::ID keyNameId(refMap->newName(keyName)); + IR::ID keyNameId(refMap->newName(keyName.string_view())); auto decl = new IR::Declaration_Variable(keyNameId, element->expression->type, nullptr); // Store the compiler generated table keys in Program structure. These will be // inserted to Metadata by CollectLocalVariables pass. @@ -1782,7 +1783,7 @@ std::optional getExternInstanceFromProperty( /// for subsequent table lookup. std::tuple SplitP4TableCommon::create_match_table( const IR::P4Table *tbl) { - cstring grpActionName = "", memActionName; + cstring grpActionName = cstring::empty, memActionName; if (implementation == TableImplementation::ACTION_SELECTOR) { grpActionName = refMap->newName(tbl->name.originalName + "_set_group_id"); memActionName = refMap->newName(tbl->name.originalName + "_set_member_id"); @@ -1814,7 +1815,7 @@ std::tuple SplitP4TableCommon::create_mat } } - auto constDefAction = tbl->properties->getProperty("default_action"); + auto constDefAction = tbl->properties->getProperty("default_action"_cs); bool isConstDefAction = constDefAction ? constDefAction->isConstant : false; IR::IndexedVector properties; @@ -1858,7 +1859,7 @@ const IR::P4Table *SplitP4TableCommon::create_member_table(const IR::P4Table *tb hidden->add(new IR::Annotation(IR::Annotation::hiddenAnnotation, {})); auto nameAnnon = tbl->getAnnotation(IR::Annotation::nameAnnotation); cstring nameA = nameAnnon->getSingleString(); - cstring memName = nameA.replace(nameA.findlast('.'), "." + memberTableName); + cstring memName = nameA.replace(cstring(nameA.findlast('.')), "."_cs + memberTableName); hidden->addAnnotation(IR::Annotation::nameAnnotation, new IR::StringLiteral(memName), false); IR::IndexedVector memberActionList; @@ -1893,7 +1894,7 @@ const IR::P4Table *SplitP4TableCommon::create_group_table(const IR::P4Table *tbl hidden->add(new IR::Annotation(IR::Annotation::hiddenAnnotation, {})); auto nameAnnon = tbl->getAnnotation(IR::Annotation::nameAnnotation); cstring nameA = nameAnnon->getSingleString(); - cstring selName = nameA.replace(nameA.findlast('.'), "." + selectorTableName); + cstring selName = nameA.replace(cstring(nameA.findlast('.')), "."_cs + selectorTableName); hidden->addAnnotation(IR::Annotation::nameAnnotation, new IR::StringLiteral(selName), false); IR::IndexedVector selector_properties; selector_properties.push_back(new IR::Property("selector", new IR::Key(selector_keys), false)); @@ -1917,16 +1918,16 @@ const IR::P4Table *SplitP4TableCommon::create_group_table(const IR::P4Table *tbl const IR::Node *SplitActionSelectorTable::postorder(IR::P4Table *tbl) { bool isConstructedInPlace = false; bool isAsInstanceShared = false; - cstring externName = ""; - cstring prefix = "psa_"; + cstring externName = cstring::empty; + cstring prefix = "psa_"_cs; if (structure->isPNA()) { - prefix = "pna_"; + prefix = "pna_"_cs; } - auto property = tbl->properties->getProperty(prefix + "implementation"); - auto counterProperty = tbl->properties->getProperty(prefix + "direct_counter"); - auto meterProperty = tbl->properties->getProperty(prefix + "direct_meter"); + auto property = tbl->properties->getProperty(prefix + "implementation"_cs); + auto counterProperty = tbl->properties->getProperty(prefix + "direct_counter"_cs); + auto meterProperty = tbl->properties->getProperty(prefix + "direct_meter"_cs); if (property != nullptr && (counterProperty != nullptr || meterProperty != nullptr)) { ::error(ErrorType::ERR_UNEXPECTED, @@ -1973,7 +1974,7 @@ const IR::Node *SplitActionSelectorTable::postorder(IR::P4Table *tbl) { // Remove the control block name prefix from instance name cstring instance_name = *instance->name; - instance_name = instance_name.findlast('.'); + instance_name = cstring(instance_name.findlast('.')); instance_name = instance_name.trim(".\t\n\r"); cstring member_id = instance_name + "_member_id"; @@ -1999,8 +2000,8 @@ const IR::Node *SplitActionSelectorTable::postorder(IR::P4Table *tbl) { cstring grpActionName, memActionName; const IR::P4Table *match_table; std::tie(match_table, grpActionName, memActionName) = create_match_table(tbl); - auto grpAction = create_action(grpActionName, group_id, "group_id"); - auto memAction = create_action(memActionName, member_id, "member_id"); + auto grpAction = create_action(grpActionName, group_id, "group_id"_cs); + auto memAction = create_action(memActionName, member_id, "member_id"_cs); decls->push_back(grpAction); decls->push_back(memAction); decls->push_back(match_table); @@ -2048,10 +2049,10 @@ const IR::Node *SplitActionSelectorTable::postorder(IR::P4Table *tbl) { const IR::Node *SplitActionProfileTable::postorder(IR::P4Table *tbl) { bool isConstructedInPlace = false; bool isApInstanceShared = false; - cstring externName = ""; - cstring implementation = "psa_implementation"; + cstring externName = cstring::empty; + cstring implementation = "psa_implementation"_cs; - if (structure->isPNA()) implementation = "pna_implementation"; + if (structure->isPNA()) implementation = "pna_implementation"_cs; auto instance = Helpers::getExternInstanceFromProperty(tbl, implementation, refMap, typeMap, &isConstructedInPlace, externName); @@ -2071,8 +2072,9 @@ const IR::Node *SplitActionProfileTable::postorder(IR::P4Table *tbl) { } // Remove the control block name prefix from instance name + // FIXME: simplify cstring instance_name = *instance->name; - instance_name = instance_name.findlast('.'); + instance_name = cstring(instance_name.findlast('.')); instance_name = instance_name.trim(".\t\n\r"); auto decls = new IR::IndexedVector(); @@ -2094,7 +2096,7 @@ const IR::Node *SplitActionProfileTable::postorder(IR::P4Table *tbl) { cstring actionName, ignoreGroup; const IR::P4Table *match_table; std::tie(match_table, ignoreGroup, actionName) = create_match_table(tbl); - auto action = create_action(actionName, member_id, "member_id"); + auto action = create_action(actionName, member_id, "member_id"_cs); decls->push_back(action); decls->push_back(match_table); cstring member_table_name = instance_name; @@ -2486,7 +2488,7 @@ bool CollectDirectCounterMeter::preorder(const IR::AssignmentStatement *assn) { bool CollectDirectCounterMeter::ifMethodFound(const IR::P4Action *a, cstring methodName, cstring instance) { - oneInstance = ""; + oneInstance = cstring::empty; instancename = instance; method = methodName; methodCallFound = false; @@ -2498,23 +2500,23 @@ bool CollectDirectCounterMeter::ifMethodFound(const IR::P4Action *a, cstring met /// method calls for only one Direct counter/meter instance. The error for the same is emitted /// in the ifMethodFound function itself and return value is not required to be checked here. bool CollectDirectCounterMeter::preorder(const IR::P4Action *a) { - ifMethodFound(a, "count"); - ifMethodFound(a, "dpdk_execute"); + ifMethodFound(a, "count"_cs); + ifMethodFound(a, "dpdk_execute"_cs); return false; } bool CollectDirectCounterMeter::preorder(const IR::P4Table *tbl) { bool isConstructedInPlace = false; - cstring implementation = "psa_implementation"; - cstring counterExternName = ""; - cstring meterExternName = ""; - cstring direct_counter = "psa_direct_counter"; - cstring direct_meter = "psa_direct_meter"; + cstring implementation = "psa_implementation"_cs; + cstring counterExternName = cstring::empty; + cstring meterExternName = cstring::empty; + cstring direct_counter = "psa_direct_counter"_cs; + cstring direct_meter = "psa_direct_meter"_cs; if (structure->isPNA()) { - implementation = "pna_implementation"; - direct_counter = "pna_direct_counter"; - direct_meter = "pna_direct_meter"; + implementation = "pna_implementation"_cs; + direct_counter = "pna_direct_counter"_cs; + direct_meter = "pna_direct_meter"_cs; } auto counterInstance = Helpers::getExternInstanceFromProperty( @@ -2545,7 +2547,7 @@ bool CollectDirectCounterMeter::preorder(const IR::P4Table *tbl) { BUG_CHECK(path, "Default action path %s cannot be found", default_action); if (auto defaultActionDecl = refMap->getDeclaration(path->path)->to()) { if (defaultActionDecl->name.originalName != "NoAction") { - if (!ifMethodFound(defaultActionDecl, "count", counterExternName)) { + if (!ifMethodFound(defaultActionDecl, "count"_cs, counterExternName)) { if (counterInstance) { ::error(ErrorType::ERR_EXPECTED, "Expected default action %1% to have " @@ -2554,7 +2556,7 @@ bool CollectDirectCounterMeter::preorder(const IR::P4Table *tbl) { return false; } } - if (!ifMethodFound(defaultActionDecl, "dpdk_execute", meterExternName)) { + if (!ifMethodFound(defaultActionDecl, "dpdk_execute"_cs, meterExternName)) { if (meterInstance) { ::error(ErrorType::ERR_EXPECTED, "Expected default action %1% to have " @@ -2640,8 +2642,8 @@ void ValidateDirectCounterMeter::postorder(const IR::MethodCallStatement *mcs) { void CollectAddOnMissTable::postorder(const IR::P4Table *t) { bool use_add_on_miss = false; - auto add_on_miss = t->properties->getProperty("add_on_miss"); - cstring default_actname = "NoAction"; + auto add_on_miss = t->properties->getProperty("add_on_miss"_cs); + cstring default_actname = "NoAction"_cs; if (add_on_miss == nullptr) return; if (add_on_miss->value->is()) { auto expr = add_on_miss->value->to()->expression; @@ -2656,7 +2658,7 @@ void CollectAddOnMissTable::postorder(const IR::P4Table *t) { } // sanity checks - auto default_action = t->properties->getProperty("default_action"); + auto default_action = t->properties->getProperty("default_action"_cs); if (use_add_on_miss && default_action == nullptr) { ::error(ErrorType::ERR_UNEXPECTED, "%1%: add_on_miss property is defined, " @@ -2686,8 +2688,9 @@ void CollectAddOnMissTable::postorder(const IR::P4Table *t) { // Map the compiler generated internal name of action (emitted in .spec file) with // user visible name in P4 program. // To get the user visible name, strip any prefixes from externalName. + // FIXME: Simplify cstring userVisibleName = action_decl->externalName(); - userVisibleName = userVisibleName.findlast('.'); + userVisibleName = cstring(userVisibleName.findlast('.')); userVisibleName = userVisibleName.trim(".\t\n\r"); structure->learner_action_map.emplace(std::make_pair(userVisibleName, default_actname), action_decl->name.name); @@ -2719,7 +2722,7 @@ void CollectAddOnMissTable::postorder(const IR::MethodCallStatement *mcs) { void ValidateAddOnMissExterns::postorder(const IR::MethodCallStatement *mcs) { bool isValidExternCall = false; - cstring propName = ""; + cstring propName = cstring::empty; auto mce = mcs->methodCall; auto mi = P4::MethodInstance::resolve(mce, refMap, typeMap); if (!mi->is()) { @@ -2737,9 +2740,9 @@ void ValidateAddOnMissExterns::postorder(const IR::MethodCallStatement *mcs) { bool use_idle_timeout_with_auto_delete = false; if (tbl) { auto idle_timeout_with_auto_delete = - tbl->properties->getProperty("idle_timeout_with_auto_delete"); + tbl->properties->getProperty("idle_timeout_with_auto_delete"_cs); if (idle_timeout_with_auto_delete != nullptr) { - propName = "idle_timeout_with_auto_delete"; + propName = "idle_timeout_with_auto_delete"_cs; if (idle_timeout_with_auto_delete->value->is()) { auto expr = idle_timeout_with_auto_delete->value->to()->expression; @@ -2763,9 +2766,9 @@ void ValidateAddOnMissExterns::postorder(const IR::MethodCallStatement *mcs) { auto args = mce->arguments; auto at = args->at(0)->expression; auto an = at->to()->value; - auto add_on_miss = tbl->properties->getProperty("add_on_miss"); + auto add_on_miss = tbl->properties->getProperty("add_on_miss"_cs); if (add_on_miss != nullptr) { - propName = "add_on_miss"; + propName = "add_on_miss"_cs; if (add_on_miss->value->is()) { auto expr = add_on_miss->value->to()->expression; if (!expr->is()) { @@ -3048,7 +3051,7 @@ const IR::Node *MoveNonHeaderFieldsToPseudoHeader::postorder(IR::MethodCallState fields.push_back( new IR::StructField(f->name, getEightBitAlignedType(type))); } - auto newName = refMap->newName(tmps0->name); + auto newName = refMap->newName(tmps0->name.name.string_view()); newTname = new IR::Type_Name(newName); auto newStructType = new IR::Type_Struct(tmps0->srcInfo, newName, tmps0->annotations, @@ -3100,7 +3103,7 @@ const IR::Node *MoveNonHeaderFieldsToPseudoHeader::postorder(IR::MethodCallState const IR::Node *AddFieldsToPseudoHeader::preorder(IR::Type_Header *h) { if (is_all_args_header) return h; - auto annon = h->getAnnotation("__pseudo_header__"); + auto annon = h->getAnnotation("__pseudo_header__"_cs); if (annon == nullptr) return h; IR::IndexedVector fields = h->fields; for (auto &p : MoveNonHeaderFieldsToPseudoHeader::pseudoFieldNameType) { @@ -3227,7 +3230,7 @@ IR::IndexedVector *InsertReqDeclForIPSec::addRegDeclInstance( const IR::Node *InsertReqDeclForIPSec::preorder(IR::P4Program *program) { if (!is_ipsec_used) return program; - cstring resName = ""; + cstring resName = cstring::empty; if (!reservedNames(refMap, registerInstanceNames, resName)) { ::error(ErrorType::ERR_RESERVED, "%1% name is reserved for DPDK IPSec port register", resName); diff --git a/backends/dpdk/dpdkArch.h b/backends/dpdk/dpdkArch.h index 856d023461..8d4905915a 100644 --- a/backends/dpdk/dpdkArch.h +++ b/backends/dpdk/dpdkArch.h @@ -31,6 +31,8 @@ limitations under the License. namespace DPDK { +using namespace P4::literals; + cstring TypeStruct2Name(const cstring *s); bool isSimpleExpression(const IR::Expression *e); bool isNonConstantSimpleExpression(const IR::Expression *e); @@ -1009,7 +1011,8 @@ class CollectDirectCounterMeter : public Inspector { cstring oneInstance; bool methodCallFound; int getTableSize(const IR::P4Table *tbl); - bool ifMethodFound(const IR::P4Action *a, cstring method, cstring instancename = ""); + bool ifMethodFound(const IR::P4Action *a, cstring method, + cstring instancename = cstring::empty); void checkMethodCallInAction(const P4::ExternMethod *); public: @@ -1019,9 +1022,9 @@ class CollectDirectCounterMeter : public Inspector { : refMap(refMap), typeMap(typeMap), structure(structure) { setName("CollectDirectCounterMeter"); visitDagOnce = false; - method = ""; - instancename = ""; - oneInstance = ""; + method = cstring::empty; + instancename = cstring::empty; + oneInstance = cstring::empty; methodCallFound = false; } @@ -1502,11 +1505,11 @@ class InsertReqDeclForIPSec : public Transform { DpdkProgramStructure *structure; bool &is_ipsec_used; int &sa_id_width; - cstring newHeaderName = "platform_hdr_t"; + cstring newHeaderName = "platform_hdr_t"_cs; IR::Type_Header *ipsecHeader = nullptr; std::vector registerInstanceNames = { - "ipsec_port_out_inbound", "ipsec_port_out_outbound", "ipsec_port_in_inbound", - "ipsec_port_in_outbound"}; + "ipsec_port_out_inbound"_cs, "ipsec_port_out_outbound"_cs, "ipsec_port_in_inbound"_cs, + "ipsec_port_in_outbound"_cs}; public: InsertReqDeclForIPSec(P4::ReferenceMap *refMap, DpdkProgramStructure *structure, diff --git a/backends/dpdk/dpdkAsmOpt.cpp b/backends/dpdk/dpdkAsmOpt.cpp index 2b8412c6ca..4267c9521f 100644 --- a/backends/dpdk/dpdkAsmOpt.cpp +++ b/backends/dpdk/dpdkAsmOpt.cpp @@ -370,9 +370,11 @@ int EmitDpdkTableConfig::getTypeWidth(const IR::Type *type, P4::TypeMap *typeMap return typeMap->widthBits(type, type->getNode(), false); } -void EmitDpdkTableConfig::print(cstring str, cstring sep) { dpdkTableConfigFile << str << sep; } +void EmitDpdkTableConfig::print(std::string_view str, std::string_view sep) { + dpdkTableConfigFile << str << sep; +} -void EmitDpdkTableConfig::print(big_int str, cstring sep) { +void EmitDpdkTableConfig::print(big_int str, std::string_view sep) { try { dpdkTableConfigFile << "0x" << std::hex << str << sep; } catch (const std::runtime_error &re) { @@ -423,7 +425,7 @@ void EmitDpdkTableConfig::addAction(const IR::Expression *actionRef, P4::Referen actionName = newNameMap[actionDecl->name.name]; else actionName = actionDecl->name.name; - print(actionName, " "); + print(actionName.string_view(), " "); if (actionDecl->parameters->parameters.size() == 1) { std::vector paramNames; std::vector argVals; @@ -455,7 +457,7 @@ void EmitDpdkTableConfig::addAction(const IR::Expression *actionRef, P4::Referen } for (size_t i = 0; i < argVals.size(); i++) { - print(paramNames[i], " "); + print(paramNames[i].string_view(), " "); print(argVals[i], " "); } } diff --git a/backends/dpdk/dpdkAsmOpt.h b/backends/dpdk/dpdkAsmOpt.h index 2d9d3096a1..25c95e642d 100644 --- a/backends/dpdk/dpdkAsmOpt.h +++ b/backends/dpdk/dpdkAsmOpt.h @@ -36,6 +36,9 @@ limitations under the License. #define DPDK_TABLE_MAX_KEY_SIZE 64 * 8 namespace DPDK { + +using namespace P4::literals; + /// This pass removes label that no jmps jump to class RemoveRedundantLabel : public Transform { public: @@ -207,7 +210,7 @@ class ShortenTokenLength : public Transform { } const IR::Node *preorder(IR::DpdkStructType *s) override { - if (s->getAnnotations()->getSingle("__packet_data__")) { + if (s->getAnnotations()->getSingle("__packet_data__"_cs)) { s->name = shortenString(s->name); IR::IndexedVector changedFields; for (auto field : s->fields) { @@ -350,9 +353,9 @@ class CollectUseDefInfo : public Inspector { std::unordered_map dontEliminate; explicit CollectUseDefInfo(P4::TypeMap *typeMap) : typeMap(typeMap) { - dontEliminate["m.pna_main_output_metadata_output_port"] = true; - dontEliminate["m.psa_ingress_output_metadata_drop"] = true; - dontEliminate["m.psa_ingress_output_metadata_egress_port"] = true; + dontEliminate["m.pna_main_output_metadata_output_port"_cs] = true; + dontEliminate["m.psa_ingress_output_metadata_drop"_cs] = true; + dontEliminate["m.psa_ingress_output_metadata_egress_port"_cs] = true; } bool preorder(const IR::DpdkJmpCondStatement *b) override { @@ -624,8 +627,8 @@ class EmitDpdkTableConfig : public Inspector { P4::TypeMap *typeMap); bool tableNeedsPriority(const IR::DpdkTable *table, P4::ReferenceMap *refMap); bool isAllKeysDefaultExpression(const IR::ListExpression *keyset); - void print(cstring str, cstring sep = ""); - void print(big_int, cstring sep = ""); + void print(std::string_view str, std::string_view sep = ""); + void print(big_int, std::string_view sep = ""); public: EmitDpdkTableConfig(P4::ReferenceMap *refMap, P4::TypeMap *typeMap, diff --git a/backends/dpdk/dpdkCheckExternInvocation.h b/backends/dpdk/dpdkCheckExternInvocation.h index 6405556c16..5599470fef 100644 --- a/backends/dpdk/dpdkCheckExternInvocation.h +++ b/backends/dpdk/dpdkCheckExternInvocation.h @@ -17,9 +17,13 @@ limitations under the License. #ifndef BACKENDS_DPDK_DPDKCHECKEXTERNINVOCATION_H_ #define BACKENDS_DPDK_DPDKCHECKEXTERNINVOCATION_H_ +#include + +#include "dpdkProgramStructure.h" #include "frontends/p4/methodInstance.h" #include "ir/ir.h" #include "ir/visitor.h" +#include "lib/cstring.h" #include "midend/checkExternInvocationCommon.h" namespace P4 { @@ -29,6 +33,8 @@ class TypeMap; namespace DPDK { +using namespace P4::literals; + /// @brief Class for checking constraints for invocations of PNA architecture extern /// methods and functions. @@ -46,15 +52,14 @@ class CheckPNAExternInvocation : public P4::CheckExternInvocationCommon { void initPipeConstraints() override { bitvec validInMainControl; validInMainControl.setbit(MAIN_CONTROL); - setPipeConstraints("send_to_port", validInMainControl); - setPipeConstraints("mirror_packet", validInMainControl); + setPipeConstraints("send_to_port"_cs, validInMainControl); + setPipeConstraints("mirror_packet"_cs, validInMainControl); // Add new constraints here } cstring getBlockName(int bit) override { - static const char *lookup[] = {"main parser", "pre control", "main control", - "main deparser"}; - BUG_CHECK(sizeof(lookup) / sizeof(lookup[0]) == BLOCK_COUNT, "Bad lookup table"); + static const std::array lookup = { + "main parser"_cs, "pre control"_cs, "main control"_cs, "main deparser"_cs}; return lookup[bit % BLOCK_COUNT]; } @@ -95,19 +100,19 @@ class CheckPNAExternInvocation : public P4::CheckExternInvocationCommon { LOG4("externType: " << externType << ", externName: " << externName); if (pipeConstraints.count(externType)) { - if (auto block = getParser("MainParserT")) { + if (auto block = getParser("MainParserT"_cs)) { LOG4("MainParser: " << (void *)block << " " << dbp(block)); pos.setbit(MAIN_PARSER); checkPipeConstraints(externType, pos, expr, externName, block->name); - } else if (auto block = getControl("PreControlT")) { + } else if (auto block = getControl("PreControlT"_cs)) { LOG4("PreControl: " << (void *)block << " " << dbp(block)); pos.setbit(PRE_CONTROL); checkPipeConstraints(externType, pos, expr, externName, block->name); - } else if (auto block = getControl("MainControlT")) { + } else if (auto block = getControl("MainControlT"_cs)) { LOG4("MainControl: " << (void *)block << " " << dbp(block)); pos.setbit(MAIN_CONTROL); checkPipeConstraints(externType, pos, expr, externName, block->name); - } else if (auto block = getDeparser("MainDeparserT")) { + } else if (auto block = getDeparser("MainDeparserT"_cs)) { LOG4("MainDeparser: " << (void *)block << " " << dbp(block)); pos.setbit(MAIN_DEPARSER); checkPipeConstraints(externType, pos, expr, externName, block->name); @@ -128,7 +133,7 @@ class CheckPNAExternInvocation : public P4::CheckExternInvocationCommon { void checkExtern(const P4::ExternFunction *extFunction, const IR::MethodCallExpression *expr) override { LOG3("ExternFunction: " << extFunction << ", MethodCallExpression: " << expr); - checkBlock(expr, expr->method->toString(), ""); + checkBlock(expr, expr->method->toString(), cstring::empty); } public: diff --git a/backends/dpdk/dpdkContext.cpp b/backends/dpdk/dpdkContext.cpp index 6cd17ecf24..c418099a61 100644 --- a/backends/dpdk/dpdkContext.cpp +++ b/backends/dpdk/dpdkContext.cpp @@ -24,7 +24,7 @@ namespace DPDK { cstring DpdkContextGenerator::removePipePrefix(cstring tableName) { if (!options.bfRtSchema.isNullOrEmpty() || !options.tdiFile.isNullOrEmpty()) { - cstring tablename = tableName.find('.'); + cstring tablename = cstring(tableName.find('.')); tablename = tablename.trim(".\t\n\r"); return tablename; } @@ -37,11 +37,11 @@ void DpdkContextGenerator::CollectTablesAndSetAttributes() { IR::IndexedVector selector_tables; IR::IndexedVector action_data_tables; for (auto kv : structure->pipelines) { - cstring direction = ""; + cstring direction = cstring::empty; if (kv.first == "Ingress") - direction = "ingress"; + direction = "ingress"_cs; else if (kv.first == "Egress") - direction = "egress"; + direction = "egress"_cs; auto control = kv.second->to(); for (auto d : control->controlLocals) { if (auto tbl = d->to()) { @@ -54,10 +54,10 @@ void DpdkContextGenerator::CollectTablesAndSetAttributes() { tblAttr.size = dpdk_default_table_size; if (size) tblAttr.size = size->asUnsigned(); auto hidden = tbl->annotations->getSingle(IR::Annotation::hiddenAnnotation); - auto selector = tbl->properties->getProperty("selector"); + auto selector = tbl->properties->getProperty("selector"_cs); tblAttr.is_add_on_miss = false; tblAttr.idle_timeout_with_auto_delete = false; - auto add_on_miss = tbl->properties->getProperty("add_on_miss"); + auto add_on_miss = tbl->properties->getProperty("add_on_miss"_cs); if (add_on_miss != nullptr) { if (add_on_miss->value->is()) { auto expr = add_on_miss->value->to()->expression; @@ -72,7 +72,7 @@ void DpdkContextGenerator::CollectTablesAndSetAttributes() { } } auto idle_timeout_with_auto_delete = - tbl->properties->getProperty("idle_timeout_with_auto_delete"); + tbl->properties->getProperty("idle_timeout_with_auto_delete"_cs); if (idle_timeout_with_auto_delete != nullptr) { if (idle_timeout_with_auto_delete->value->is()) { auto expr = idle_timeout_with_auto_delete->value->to() @@ -90,11 +90,11 @@ void DpdkContextGenerator::CollectTablesAndSetAttributes() { } } if (hidden) { - tblAttr.tableType = selector ? "selection" : "action"; + tblAttr.tableType = selector ? "selection"_cs : "action"_cs; tblAttr.isHidden = true; } else { tblAttr.isHidden = false; - tblAttr.tableType = "match"; + tblAttr.tableType = "match"_cs; tblAttr.tableKeys = ::get(structure->key_map, kv.second->name.originalName + "_" + tbl->name.originalName); } @@ -110,7 +110,7 @@ void DpdkContextGenerator::CollectTablesAndSetAttributes() { } for (auto ed : structure->externDecls) { - cstring externTypeName = ""; + cstring externTypeName = cstring::empty; if (auto type = ed->type->to()) { externTypeName = type->path->name.name; } else if (auto type = ed->type->to()) { @@ -137,13 +137,13 @@ void DpdkContextGenerator::CollectTablesAndSetAttributes() { auto value = counter_type->to()->asUnsigned(); switch (value) { case 0: - externAttr.counterType = "packets"; + externAttr.counterType = "packets"_cs; break; case 1: - externAttr.counterType = "bytes"; + externAttr.counterType = "bytes"_cs; break; case 2: - externAttr.counterType = "packets_and_bytes"; + externAttr.counterType = "packets_and_bytes"_cs; break; } } @@ -167,23 +167,23 @@ void DpdkContextGenerator::addKeyField(Util::JsonArray *keyJson, const cstring n const cstring nameAnnotation, const IR::KeyElement *key, int position) { auto *keyField = new Util::JsonObject(); - cstring fieldName = name.findlast('.'); - auto instanceName = name.replace(fieldName, ""); + cstring fieldName = cstring(name.findlast('.')); + auto instanceName = name.replace(fieldName, cstring::empty); fieldName = fieldName.trim(".\t\n\r"); std::string keyName(nameAnnotation); // Replace header stack indices hdr[] with hdr$. std::regex hdrStackRegex(R"(\[([0-9]+)\])"); keyName = std::regex_replace(keyName, hdrStackRegex, "$$$1"); - keyField->emplace("name", keyName); - keyField->emplace("instance_name", instanceName); - keyField->emplace("field_name", fieldName); + keyField->emplace("name"_cs, keyName); + keyField->emplace("instance_name"_cs, instanceName); + keyField->emplace("field_name"_cs, fieldName); auto match_kind = toStr(key->matchType); - if (match_kind == "optional" || match_kind == "range") match_kind = "ternary"; - keyField->emplace("match_type", match_kind); - keyField->emplace("start_bit", 0); - keyField->emplace("bit_width", key->expression->type->width_bits()); - keyField->emplace("bit_width_full", key->expression->type->width_bits()); - keyField->emplace("position", position); + if (match_kind == "optional" || match_kind == "range") match_kind = "ternary"_cs; + keyField->emplace("match_type"_cs, match_kind); + keyField->emplace("start_bit"_cs, 0); + keyField->emplace("bit_width"_cs, key->expression->type->width_bits()); + keyField->emplace("bit_width_full"_cs, key->expression->type->width_bits()); + keyField->emplace("position"_cs, position); keyJson->append(keyField); } @@ -192,15 +192,15 @@ Util::JsonObject *DpdkContextGenerator::initTableCommonJson(const cstring name, const struct TableAttributes &attr) { auto *tableJson = new Util::JsonObject(); cstring tableName = name; - tableJson->emplace("name", attr.externalName); - tableJson->emplace("target_name", tableName); - tableJson->emplace("direction", attr.direction); - tableJson->emplace("handle", attr.tableHandle); - tableJson->emplace("table_type", attr.tableType); - tableJson->emplace("size", attr.size); - tableJson->emplace("p4_hidden", attr.isHidden); - tableJson->emplace("add_on_miss", attr.is_add_on_miss); - tableJson->emplace("idle_timeout_with_auto_delete", attr.idle_timeout_with_auto_delete); + tableJson->emplace("name"_cs, attr.externalName); + tableJson->emplace("target_name"_cs, tableName); + tableJson->emplace("direction"_cs, attr.direction); + tableJson->emplace("handle"_cs, attr.tableHandle); + tableJson->emplace("table_type"_cs, attr.tableType); + tableJson->emplace("size"_cs, attr.size); + tableJson->emplace("p4_hidden"_cs, attr.isHidden); + tableJson->emplace("add_on_miss"_cs, attr.is_add_on_miss); + tableJson->emplace("idle_timeout_with_auto_delete"_cs, attr.idle_timeout_with_auto_delete); return tableJson; } @@ -301,7 +301,7 @@ void DpdkContextGenerator::setActionAttributes(const IR::P4Table *tbl) { // This functions updates the table attribute map entry with default action handle // for the specified table. void DpdkContextGenerator::setDefaultActionHandle(const IR::P4Table *table) { - cstring default_action_name = ""; + cstring default_action_name = cstring::empty; if (table->getDefaultAction()) default_action_name = toStr(table->getDefaultAction()); auto tableAttr = ::get(tableAttrmap, table->name.originalName); @@ -320,9 +320,9 @@ void DpdkContextGenerator::setDefaultActionHandle(const IR::P4Table *table) { void DpdkContextGenerator::addImmediateField(Util::JsonArray *paramJson, const cstring name, int dest_start, int dest_width) { auto *oneParam = new Util::JsonObject(); - oneParam->emplace("param_name", name); - oneParam->emplace("dest_start", dest_start); - oneParam->emplace("dest_width", dest_width); + oneParam->emplace("param_name"_cs, name); + oneParam->emplace("dest_start"_cs, dest_start); + oneParam->emplace("dest_width"_cs, dest_width); paramJson->append(oneParam); } @@ -341,8 +341,8 @@ Util::JsonObject *DpdkContextGenerator::addMatchAttributes(const IR::P4Table *ta if (name != "NoAction") { name = ctrlName + "." + name; } - oneAction->emplace("action_name", name); - oneAction->emplace("action_handle", attr.actionHandle); + oneAction->emplace("action_name"_cs, name); + oneAction->emplace("action_handle"_cs, attr.actionHandle); auto *immFldArray = new Util::JsonArray(); if (attr.params) { int index = 0; @@ -358,12 +358,12 @@ Util::JsonObject *DpdkContextGenerator::addMatchAttributes(const IR::P4Table *ta index += param_width; } } - oneAction->emplace("immediate_fields", immFldArray); + oneAction->emplace("immediate_fields"_cs, immFldArray); actFmtArray->append(oneAction); } - oneStageTbl->emplace("action_format", actFmtArray); + oneStageTbl->emplace("action_format"_cs, actFmtArray); stageTblArray->append(oneStageTbl); - match_attributes->emplace("stage_tables", stageTblArray); + match_attributes->emplace("stage_tables"_cs, stageTblArray); return match_attributes; } @@ -371,11 +371,11 @@ Util::JsonObject *DpdkContextGenerator::addMatchAttributes(const IR::P4Table *ta void DpdkContextGenerator::addActionParam(Util::JsonArray *paramJson, const cstring name, int bitWidth, int position, int byte_array_index) { auto *oneParam = new Util::JsonObject(); - oneParam->emplace("name", name); - oneParam->emplace("start_bit", 0); - oneParam->emplace("bit_width", bitWidth); - oneParam->emplace("position", position); - oneParam->emplace("byte_array_index", byte_array_index); + oneParam->emplace("name"_cs, name); + oneParam->emplace("start_bit"_cs, 0); + oneParam->emplace("bit_width"_cs, bitWidth); + oneParam->emplace("position"_cs, position); + oneParam->emplace("byte_array_index"_cs, byte_array_index); paramJson->append(oneParam); } @@ -395,15 +395,14 @@ Util::JsonArray *DpdkContextGenerator::addActions(const IR::P4Table *table, } else { actName = name; } - act->emplace("name", attr.externalName); - act->emplace("target_name", actName); - act->emplace("handle", attr.actionHandle); + act->emplace("name"_cs, attr.externalName); + act->emplace("target_name"_cs, actName); + act->emplace("handle"_cs, attr.actionHandle); if (isMatch) { - act->emplace("constant_default_action", attr.constant_default_action); - act->emplace("is_compiler_added_action", attr.is_compiler_added_action); - act->emplace("allowed_as_hit_action", attr.allowed_as_hit_action); - act->emplace("allowed_as_default_action", attr.allowed_as_default_action); - ; + act->emplace("constant_default_action"_cs, attr.constant_default_action); + act->emplace("is_compiler_added_action"_cs, attr.is_compiler_added_action); + act->emplace("allowed_as_hit_action"_cs, attr.allowed_as_hit_action); + act->emplace("allowed_as_default_action"_cs, attr.allowed_as_default_action); } auto *paramJson = new Util::JsonArray(); if (attr.params) { @@ -423,7 +422,7 @@ Util::JsonArray *DpdkContextGenerator::addActions(const IR::P4Table *table, position++; } } - act->emplace("p4_parameters", paramJson); + act->emplace("p4_parameters"_cs, paramJson); actArray->append(act); } } @@ -437,9 +436,9 @@ bool DpdkContextGenerator::addRefTables(const cstring tbl_name, const IR::P4Tabl // Below empty arrays are currently required by the control plane software. // May be removed in future. - tableJson->emplace("stateful_table_refs", new Util::JsonArray()); - tableJson->emplace("statistics_table_refs", new Util::JsonArray()); - tableJson->emplace("meter_table_refs", new Util::JsonArray()); + tableJson->emplace("stateful_table_refs"_cs, new Util::JsonArray()); + tableJson->emplace("statistics_table_refs"_cs, new Util::JsonArray()); + tableJson->emplace("meter_table_refs"_cs, new Util::JsonArray()); // Reference to compiler generated member table in case of action profile and action selector. if (structure->member_tables.count(tbl_name)) { @@ -449,10 +448,10 @@ bool DpdkContextGenerator::addRefTables(const cstring tbl_name, const IR::P4Tabl auto *actionDataField = new Util::JsonObject(); auto tableAttr = ::get(tableAttrmap, (*memberTable)->name.originalName); auto tableName = tableAttr.controlName + "." + (*memberTable)->name.originalName; - actionDataField->emplace("name", tableName); - actionDataField->emplace("handle", tableAttr.tableHandle); + actionDataField->emplace("name"_cs, tableName); + actionDataField->emplace("handle"_cs, tableAttr.tableHandle); actionDataJson->append(actionDataField); - tableJson->emplace("action_data_table_refs", actionDataJson); + tableJson->emplace("action_data_table_refs"_cs, actionDataJson); } // Reference to compiler generated group table in case of action selector @@ -463,14 +462,14 @@ bool DpdkContextGenerator::addRefTables(const cstring tbl_name, const IR::P4Tabl auto *selectField = new Util::JsonObject(); auto tableAttr = ::get(tableAttrmap, groupTable->name.originalName); auto tableName = tableAttr.controlName + "." + groupTable->name.originalName; - selectField->emplace("name", tableName); - selectField->emplace("handle", tableAttr.tableHandle); + selectField->emplace("name"_cs, tableName); + selectField->emplace("handle"_cs, tableAttr.tableHandle); selectionJson->append(selectField); - tableJson->emplace("selection_table_refs", selectionJson); + tableJson->emplace("selection_table_refs"_cs, selectionJson); } if (hasActionProfileSelector) { - tableJson->emplace("action_profile", (*memberTable)->name.originalName); + tableJson->emplace("action_profile"_cs, (*memberTable)->name.originalName); } return hasActionProfileSelector; } @@ -496,7 +495,7 @@ void DpdkContextGenerator::addMatchTables(Util::JsonArray *tablesJson) { match_keys->keyElements.at(position), position); position++; } - tableJson->emplace("match_key_fields", keyJson); + tableJson->emplace("match_key_fields"_cs, keyJson); } } // If table implementation is action profile or action selector, all actions from member @@ -512,18 +511,19 @@ void DpdkContextGenerator::addMatchTables(Util::JsonArray *tablesJson) { setDefaultActionHandle(table); tableAttr = ::get(tableAttrmap, table->name.originalName); - tableJson->emplace("actions", addActions(table, tableAttr.controlName, isMatchTable)); + tableJson->emplace("actions"_cs, + addActions(table, tableAttr.controlName, isMatchTable)); if (isMatchTable) { - tableJson->emplace("match_attributes", + tableJson->emplace("match_attributes"_cs, addMatchAttributes(table, tableAttr.controlName)); } - tableJson->emplace("default_action_handle", tableAttr.default_action_handle); + tableJson->emplace("default_action_handle"_cs, tableAttr.default_action_handle); } else { SelectionTable sel; sel.setAttributes(tbl, tableAttrmap); - tableJson->emplace("max_n_groups", sel.max_n_groups); - tableJson->emplace("max_n_members_per_group", sel.max_n_members_per_group); - tableJson->emplace("bound_to_action_data_table_handle", + tableJson->emplace("max_n_groups"_cs, sel.max_n_groups); + tableJson->emplace("max_n_members_per_group"_cs, sel.max_n_members_per_group); + tableJson->emplace("bound_to_action_data_table_handle"_cs, sel.bound_to_action_data_table_handle); } tablesJson->append(tableJson); @@ -535,17 +535,17 @@ void DpdkContextGenerator::addExternInfo(Util::JsonArray *externsJson) { for (auto t : externs) { auto externAttr = ::get(externAttrMap, t->name.name); auto *externJson = new Util::JsonObject(); - externJson->emplace("name", externAttr.externalName); - externJson->emplace("target_name", t->name.name); - externJson->emplace("type", externAttr.externType); + externJson->emplace("name"_cs, externAttr.externalName); + externJson->emplace("target_name"_cs, t->name.name); + externJson->emplace("type"_cs, externAttr.externType); auto *attrJson = new Util::JsonObject(); if (externAttr.externType == "Counter" || externAttr.externType == "DirectCounter") { - attrJson->emplace("type", externAttr.counterType); + attrJson->emplace("type"_cs, externAttr.counterType); } if (externAttr.externType == "DirectCounter" || externAttr.externType == "DirectMeter") { - attrJson->emplace("table_id", externAttr.table_id); + attrJson->emplace("table_id"_cs, externAttr.table_id); } - externJson->emplace("attributes", attrJson); + externJson->emplace("attributes"_cs, attrJson); externsJson->append(externJson); } } @@ -556,15 +556,15 @@ const Util::JsonObject *DpdkContextGenerator::genContextJsonObject() { auto *externsJson = new Util::JsonArray(); struct TopLevelCtxt tlinfo; tlinfo.initTopLevelCtxt(options); - json->emplace("program_name", tlinfo.progName); - json->emplace("build_date", tlinfo.buildDate); - json->emplace("compile_command", tlinfo.compileCommand); - json->emplace("compiler_version", tlinfo.compilerVersion); - json->emplace("schema_version", cstring("0.1")); - json->emplace("target", cstring("DPDK")); - json->emplace("tables", tablesJson); + json->emplace("program_name"_cs, tlinfo.progName); + json->emplace("build_date"_cs, tlinfo.buildDate); + json->emplace("compile_command"_cs, tlinfo.compileCommand); + json->emplace("compiler_version"_cs, tlinfo.compilerVersion); + json->emplace("schema_version"_cs, "0.1"_cs); + json->emplace("target"_cs, "DPDK"_cs); + json->emplace("tables"_cs, tablesJson); addMatchTables(tablesJson); - json->emplace("externs", externsJson); + json->emplace("externs"_cs, externsJson); addExternInfo(externsJson); return json; } diff --git a/backends/dpdk/dpdkContext.h b/backends/dpdk/dpdkContext.h index e04ec8ad86..11e49a218d 100644 --- a/backends/dpdk/dpdkContext.h +++ b/backends/dpdk/dpdkContext.h @@ -22,6 +22,7 @@ limitations under the License. #include "constants.h" #include "control-plane/bfruntime.h" #include "dpdkProgramStructure.h" +#include "lib/cstring.h" #include "lib/json.h" #include "lib/nullstream.h" #include "options.h" @@ -36,6 +37,8 @@ namespace p4configv1 = ::p4::config::v1; namespace DPDK { +using namespace P4::literals; + /// This structure holds table attributes required for context JSON which are not /// part of P4Table. struct TableAttributes { @@ -90,9 +93,9 @@ struct TopLevelCtxt { auto fileName = progName.findlast('/'); // Handle the case when input file is in the current working directory. // fileName would be null in that case, hence progName should remain unchanged. - if (fileName) progName = fileName; + if (fileName) progName = cstring(fileName); auto fileext = progName.find("."); - progName = progName.replace(fileext, ""); + progName = progName.replace(cstring(fileext), cstring::empty); progName = progName.trim("/\t\n\r"); compilerVersion = options.compilerVersion; } @@ -107,19 +110,19 @@ struct SelectionTable { const std::map &tableAttrmap) { max_n_groups = 0; max_n_members_per_group = 0; - auto n_groups = tbl->properties->getProperty("n_groups_max"); + auto n_groups = tbl->properties->getProperty("n_groups_max"_cs); if (n_groups) { auto n_groups_expr = n_groups->value->to()->expression; max_n_groups = n_groups_expr->to()->asInt(); } - auto n_members = tbl->properties->getProperty("n_members_per_group_max"); + auto n_members = tbl->properties->getProperty("n_members_per_group_max"_cs); if (n_members) { auto n_members_expr = n_members->value->to()->expression; max_n_members_per_group = n_members_expr->to()->asInt(); } // Fetch associated member table handle cstring actionDataTableName = tbl->name.originalName; - actionDataTableName = actionDataTableName.replace("_sel", ""); + actionDataTableName = actionDataTableName.replace("_sel"_cs, cstring::empty); auto actionTableAttr = ::get(tableAttrmap, actionDataTableName); bound_to_action_data_table_handle = actionTableAttr.tableHandle; } diff --git a/backends/dpdk/dpdkHelpers.cpp b/backends/dpdk/dpdkHelpers.cpp index 66578ea69b..e8955d2d0f 100644 --- a/backends/dpdk/dpdkHelpers.cpp +++ b/backends/dpdk/dpdkHelpers.cpp @@ -20,9 +20,12 @@ limitations under the License. #include "dpdkUtils.h" #include "frontends/p4/tableApply.h" #include "ir/ir.h" +#include "lib/cstring.h" namespace DPDK { +using namespace P4::literals; + /// convert relation comparison statements into the corresponding branching /// instructions in dpdk. void ConvertStatementToDpdk::process_relation_operation(const IR::Expression *dst, @@ -244,17 +247,17 @@ bool ConvertStatementToDpdk::preorder(const IR::AssignmentStatement *a) { } auto hash_alg = declArgs->at(0)->expression; unsigned hashAlgValue = CRC1; - cstring hashInstr = "hash"; + cstring hashInstr = "hash"_cs; if (hash_alg->is()) hashAlgValue = hash_alg->to()->asUnsigned(); - cstring hashAlgName = "crc32"; + cstring hashAlgName = "crc32"_cs; if (hashAlgValue == JHASH0 || hashAlgValue == JHASH5) - hashAlgName = "jhash"; + hashAlgName = "jhash"_cs; else if (hashAlgValue >= CRC1 && hashAlgValue <= CRC4) - hashAlgName = "crc32"; + hashAlgName = "crc32"_cs; else if (hashAlgValue == TOEPLITZ) { hashAlgName = e->object->getName().name; - hashInstr = "rss"; + hashInstr = "rss"_cs; } IR::Vector components; @@ -345,7 +348,7 @@ bool ConvertStatementToDpdk::preorder(const IR::AssignmentStatement *a) { } else if (e->originalExternType->getName().name == "InternetChecksum") { if (e->method->getName().name == "get") { auto res = structure->csum_map.find(e->object->to()); - cstring intermediate = ""; + cstring intermediate = cstring::empty; if (res != structure->csum_map.end()) { intermediate = res->second; } else { @@ -443,9 +446,9 @@ bool ConvertStatementToDpdk::preorder(const IR::AssignmentStatement *a) { metadataStruct->fields.push_back( new IR::StructField(portInOutbound, IR::Type_Bits::get(32))); add_instr(new IR::DpdkRegisterReadStatement( - port_in_inbound, "ipsec_port_in_inbound", new IR::Constant(0))); + port_in_inbound, "ipsec_port_in_inbound"_cs, new IR::Constant(0))); add_instr(new IR::DpdkRegisterReadStatement( - port_in_outbound, "ipsec_port_in_outbound", new IR::Constant(0))); + port_in_outbound, "ipsec_port_in_outbound"_cs, new IR::Constant(0))); add_instr(new IR::DpdkMovStatement(left, new IR::Constant(false))); auto true_label = refmap->newName("label_true"); auto end_label = refmap->newName("label_end"); @@ -686,7 +689,7 @@ void ConvertStatementToDpdk::updateMdStrAndGenInstr(const IR::Argument *field, /// This function returns the header/metadata structure name cstring ConvertStatementToDpdk::getHdrMdStrName(const IR::Member *mem) { - cstring sName = ""; + cstring sName = cstring::empty; if ((mem != nullptr) && (mem->expr != nullptr) && (mem->expr->type != nullptr)) { if (auto st = mem->expr->type->to()) { sName = st->name.name; @@ -703,9 +706,9 @@ bool ConvertStatementToDpdk::checkIfBelongToSameHdrMdStructure(const IR::Argumen if (auto s = field->expression->to()) { if (s->components.size() == 1) return true; - cstring hdrStrName = ""; + cstring hdrStrName = cstring::empty; for (auto field1 : s->components) { - cstring sName = ""; + cstring sName = cstring::empty; if (auto exp = field1->expression->to()) { auto type = typemap->getType(exp, true); if (type->is()) { @@ -717,7 +720,7 @@ bool ConvertStatementToDpdk::checkIfBelongToSameHdrMdStructure(const IR::Argumen } } - if (hdrStrName == "") + if (hdrStrName.isNullOrEmpty()) hdrStrName = sName; else if (hdrStrName != sName) return false; @@ -745,12 +748,12 @@ bool ConvertStatementToDpdk::checkIfBelongToSameHdrMdStructure(const IR::Argumen bool ConvertStatementToDpdk::checkIfConsecutiveHdrMdfields(const IR::Argument *field) { if (auto s = field->expression->to()) { if (s->components.size() == 1) return true; - cstring stName = ""; + cstring stName = cstring::empty; const IR::Type *hdrMdType = nullptr; std::vector fldList; for (auto field1 : s->components) { if (auto exp = field1->expression->to()) { - if (stName == "") stName = getHdrMdStrName(exp); + if (stName.isNullOrEmpty()) stName = getHdrMdStrName(exp); auto type = typemap->getType(exp, true); if (type->is()) { @@ -1003,7 +1006,7 @@ bool ConvertStatementToDpdk::preorder(const IR::MethodCallStatement *s) { // Checksum function call if (a->originalExternType->getName().name == "InternetChecksum") { auto res = structure->csum_map.find(a->object->to()); - cstring intermediate = ""; + cstring intermediate = cstring::empty; if (res != structure->csum_map.end()) { intermediate = res->second; } else { @@ -1081,9 +1084,9 @@ bool ConvertStatementToDpdk::preorder(const IR::MethodCallStatement *s) { // // @warning If the value is not aligned to 8 bits, the remainder after // division is dropped during runtime (this is a target limitation). - cstring baseName = ""; + cstring baseName; if (length->expression->is()) { - baseName = "varbit"; + baseName = "varbit"_cs; } else if (length->expression->is()) { baseName = length->expression->to()->member.name; } else { @@ -1401,7 +1404,7 @@ bool ConvertStatementToDpdk::preorder(const IR::SwitchStatement *s) { auto size = s->cases.size(); std::vector labels; cstring label; - cstring default_label = ""; + cstring default_label = cstring::empty; auto end_label = refmap->newName("label_endswitch"); if (tc) { add_instr(new IR::DpdkApplyStatement(tc->name.toString())); diff --git a/backends/dpdk/dpdkMetadata.cpp b/backends/dpdk/dpdkMetadata.cpp index 2023aabf65..749942e6cd 100644 --- a/backends/dpdk/dpdkMetadata.cpp +++ b/backends/dpdk/dpdkMetadata.cpp @@ -20,11 +20,13 @@ limitations under the License. namespace DPDK { +using namespace P4::literals; + /// Make sure new decls and fields name are unique. void DirectionToRegRead::uniqueNames(IR::DpdkAsmProgram *p) { // "direction" name is used in dpdk for initialzing direction port mask // make sure no such decls exist with that name - registerInstanceName = "direction"; + registerInstanceName = "direction"_cs; for (auto decl : p->externDeclarations) { usedNames.insert(decl->name); } diff --git a/backends/dpdk/dpdkProgram.cpp b/backends/dpdk/dpdkProgram.cpp index 611f8736b6..c4cc7ca15b 100644 --- a/backends/dpdk/dpdkProgram.cpp +++ b/backends/dpdk/dpdkProgram.cpp @@ -87,7 +87,7 @@ IR::IndexedVector ConvertToDpdkProgram::create_psa_postamb IR::IndexedVector instr; instr.push_back(new IR::DpdkTxStatement( new IR::Member(new IR::PathExpression("m"), "psa_ingress_output_metadata_egress_port"))); - instr.push_back(new IR::DpdkLabelStatement("label_drop")); + instr.push_back(new IR::DpdkLabelStatement("label_drop"_cs)); instr.push_back(new IR::DpdkDropStatement()); return instr; } @@ -253,7 +253,8 @@ cstring ConvertToDpdkParser::append_parser_name(const IR::P4Parser *p, cstring l IR::Declaration_Variable *ConvertToDpdkParser::addNewTmpVarToMetadata(cstring name, const IR::Type *type) { - auto newTmpVar = new IR::Declaration_Variable(IR::ID(refmap->newName(name)), type); + auto newTmpVar = + new IR::Declaration_Variable(IR::ID(refmap->newName(name.string_view())), type); metadataStruct->fields.push_back( new IR::StructField(IR::ID(newTmpVar->name.name), newTmpVar->type)); return newTmpVar; @@ -284,7 +285,7 @@ void ConvertToDpdkParser::getCondVars(const IR::Expression *sv, const IR::Expres auto right = maskexpr->right; unsigned value = right->to()->asUnsigned() & left->to()->asUnsigned(); - auto tmpDecl = addNewTmpVarToMetadata("tmpMask", IR::Type_Bits::get(byteAlignedWidth)); + auto tmpDecl = addNewTmpVarToMetadata("tmpMask"_cs, IR::Type_Bits::get(byteAlignedWidth)); auto tmpMask = new IR::Member(new IR::PathExpression(IR::ID("m")), IR::ID(tmpDecl->name.name)); structure->push_variable(new IR::DpdkDeclaration(tmpDecl)); @@ -363,8 +364,8 @@ bool ConvertToDpdkParser::preorder(const IR::P4Parser *p) { } } } - degree_map.erase("start"); - state_map.erase("start"); + degree_map.erase("start"_cs); + state_map.erase("start"_cs); while (stack.size() > 0) { auto state = stack.back(); @@ -422,7 +423,7 @@ bool ConvertToDpdkParser::preorder(const IR::P4Parser *p) { if (!sc->keyset->is()) { // Create label names, falseLabel for next keyset comparison and // trueLabel for the state to jump on match. - falseLabel = refmap->newName(state->name); + falseLabel = refmap->newName(state->name.name.string_view()); trueLabel = sc->state->path->name; handleTupleExpression(sc->keyset->to(), tupleInputExpr, inputSize, @@ -497,7 +498,7 @@ bool ConvertToDpdkControl::preorder(const IR::P4Action *a) { for (auto i : helper->get_instr()) stmt_list->push_back(i); auto actName = a->name.name; - if (a->name.originalName == "NoAction") actName = "NoAction"; + if (a->name.originalName == "NoAction") actName = a->name.originalName; auto action = new IR::DpdkAction(*stmt_list, actName, *a->parameters); actions.push_back(action); return false; @@ -586,12 +587,12 @@ std::optional ConvertToDpdkControl::getNumberFromProperty(const IR::P4Table bool ConvertToDpdkControl::preorder(const IR::P4Table *t) { if (!checkTableValid(t)) return false; - if (t->properties->getProperty("selector") != nullptr) { - auto group_id = getMemExprFromProperty(t, "group_id"); - auto member_id = getMemExprFromProperty(t, "member_id"); - auto selector_key = t->properties->getProperty("selector"); - auto n_groups_max = getNumberFromProperty(t, "n_groups_max"); - auto n_members_per_group_max = getNumberFromProperty(t, "n_members_per_group_max"); + if (t->properties->getProperty("selector"_cs) != nullptr) { + auto group_id = getMemExprFromProperty(t, "group_id"_cs); + auto member_id = getMemExprFromProperty(t, "member_id"_cs); + auto selector_key = t->properties->getProperty("selector"_cs); + auto n_groups_max = getNumberFromProperty(t, "n_groups_max"_cs); + auto n_members_per_group_max = getNumberFromProperty(t, "n_members_per_group_max"_cs); if (group_id == std::nullopt || member_id == std::nullopt || n_groups_max == std::nullopt || n_members_per_group_max == std::nullopt) @@ -627,7 +628,7 @@ bool ConvertToDpdkControl::preorder(const IR::P4Control *c) { c->body->apply(*helper); if (deparser && structure->isPSA()) { add_inst(new IR::DpdkJmpNotEqualStatement( - "LABEL_DROP", + "LABEL_DROP"_cs, new IR::Member(new IR::PathExpression("m"), "psa_ingress_output_metadata_drop"), new IR::Constant(0))); } diff --git a/backends/dpdk/dpdkProgram.h b/backends/dpdk/dpdkProgram.h index d193825e2e..9a14aa3472 100644 --- a/backends/dpdk/dpdkProgram.h +++ b/backends/dpdk/dpdkProgram.h @@ -35,6 +35,8 @@ limitations under the License. namespace DPDK { +using namespace P4::literals; + class ConvertToDpdkProgram : public Transform { P4::TypeMap *typemap; P4::ReferenceMap *refmap; @@ -135,7 +137,7 @@ class CollectActionUses : public Inspector { if (auto mce = ale->expression->to()) { if (auto path = mce->method->to()) { if (path->path->name.originalName == "NoAction") - actions.insert("NoAction"); + actions.insert("NoAction"_cs); else actions.insert(path->path->name.name); } diff --git a/backends/dpdk/dpdkProgramStructure.cpp b/backends/dpdk/dpdkProgramStructure.cpp index 523067e085..5173f265df 100644 --- a/backends/dpdk/dpdkProgramStructure.cpp +++ b/backends/dpdk/dpdkProgramStructure.cpp @@ -3,6 +3,8 @@ #include "ir/ir.h" #include "options.h" +using namespace P4::literals; + bool ParseDpdkArchitecture::preorder(const IR::ToplevelBlock *block) { // Blocks are not in IR tree, use a custom visitor to traverse. for (auto it : block->constantValue) { @@ -12,89 +14,89 @@ bool ParseDpdkArchitecture::preorder(const IR::ToplevelBlock *block) { } void ParseDpdkArchitecture::parse_pna_block(const IR::PackageBlock *block) { - structure->p4arch = "pna"; - auto p = block->findParameterValue("main_parser"); + structure->p4arch = "pna"_cs; + auto p = block->findParameterValue("main_parser"_cs); if (p == nullptr) { ::error(ErrorType::ERR_MODEL, "Package %1% has no parameter named 'main_parser'", block); return; } auto parser = p->to(); - structure->parsers.emplace("MainParserT", parser->container); - p = block->findParameterValue("pre_control"); + structure->parsers.emplace("MainParserT"_cs, parser->container); + p = block->findParameterValue("pre_control"_cs); auto pre_control = p->to(); - structure->pipelines.emplace("PreControlT", pre_control->container); - p = block->findParameterValue("main_control"); + structure->pipelines.emplace("PreControlT"_cs, pre_control->container); + p = block->findParameterValue("main_control"_cs); auto pipeline = p->to(); - structure->pipelines.emplace("MainControlT", pipeline->container); + structure->pipelines.emplace("MainControlT"_cs, pipeline->container); structure->pipeline_controls.emplace(pipeline->container->name); - p = block->findParameterValue("main_deparser"); + p = block->findParameterValue("main_deparser"_cs); auto deparser = p->to(); - structure->deparsers.emplace("MainDeparserT", deparser->container); + structure->deparsers.emplace("MainDeparserT"_cs, deparser->container); structure->non_pipeline_controls.emplace(deparser->container->name); } void ParseDpdkArchitecture::parse_psa_block(const IR::PackageBlock *block) { - structure->p4arch = "psa"; - auto pkg = block->findParameterValue("ingress"); + structure->p4arch = "psa"_cs; + auto pkg = block->findParameterValue("ingress"_cs); if (pkg == nullptr) { ::error(ErrorType::ERR_MODEL, "Package %1% has no parameter named 'ingress'", block); return; } if (auto ingress = pkg->to()) { - auto p = ingress->findParameterValue("ip"); + auto p = ingress->findParameterValue("ip"_cs); if (!p) { ::error(ErrorType::ERR_MODEL, "'ingress' package %1% has no parameter named 'ip'", block); return; } auto parser = p->to(); - structure->parsers.emplace("IngressParser", parser->container); - p = ingress->findParameterValue("ig"); + structure->parsers.emplace("IngressParser"_cs, parser->container); + p = ingress->findParameterValue("ig"_cs); if (!p) { ::error(ErrorType::ERR_MODEL, "'ingress' package %1% has no parameter named 'ig'", block); return; } auto pipeline = p->to(); - structure->pipelines.emplace("Ingress", pipeline->container); + structure->pipelines.emplace("Ingress"_cs, pipeline->container); structure->pipeline_controls.emplace(pipeline->container->name); - p = ingress->findParameterValue("id"); + p = ingress->findParameterValue("id"_cs); if (!p) { ::error(ErrorType::ERR_MODEL, "'ingress' package %1% has no parameter named 'id'", block); return; } auto deparser = p->to(); - structure->deparsers.emplace("IngressDeparser", deparser->container); + structure->deparsers.emplace("IngressDeparser"_cs, deparser->container); structure->non_pipeline_controls.emplace(deparser->container->name); } - pkg = block->findParameterValue("egress"); + pkg = block->findParameterValue("egress"_cs); if (auto egress = pkg->to()) { - auto p = egress->findParameterValue("ep"); + auto p = egress->findParameterValue("ep"_cs); if (!p) { ::error(ErrorType::ERR_MODEL, "'egress' package %1% has no parameter named 'ep'", block); return; } auto parser = p->to(); - structure->parsers.emplace("EgressParser", parser->container); - p = egress->findParameterValue("eg"); + structure->parsers.emplace("EgressParser"_cs, parser->container); + p = egress->findParameterValue("eg"_cs); if (!p) { ::error(ErrorType::ERR_MODEL, "'egress' package %1% has no parameter named 'eg'", block); return; } auto pipeline = p->to(); - structure->pipelines.emplace("Egress", pipeline->container); + structure->pipelines.emplace("Egress"_cs, pipeline->container); structure->pipeline_controls.emplace(pipeline->container->name); - p = egress->findParameterValue("ed"); + p = egress->findParameterValue("ed"_cs); if (!p) { ::error(ErrorType::ERR_MODEL, "'egress' package %1% has no parameter named 'ed'", block); return; } auto deparser = p->to(); - structure->deparsers.emplace("EgressDeparser", deparser->container); + structure->deparsers.emplace("EgressDeparser"_cs, deparser->container); structure->non_pipeline_controls.emplace(deparser->container->name); } } @@ -237,6 +239,7 @@ void InspectDpdkProgram::addTypesAndInstances(const IR::Type_StructLike *type, b } bool InspectDpdkProgram::isStandardMetadata(cstring ptName) { + // FIXME: do we really need strcmp here? return (!strcmp(ptName, "psa_ingress_parser_input_metadata_t") || !strcmp(ptName, "psa_egress_parser_input_metadata_t") || !strcmp(ptName, "psa_ingress_input_metadata_t") || diff --git a/backends/dpdk/dpdkProgramStructure.h b/backends/dpdk/dpdkProgramStructure.h index 2bd778ccb0..5f05dbd606 100644 --- a/backends/dpdk/dpdkProgramStructure.h +++ b/backends/dpdk/dpdkProgramStructure.h @@ -57,8 +57,8 @@ struct DpdkProgramStructure { IR::Type_Struct *metadataStruct; IR::Expression *ipsec_header; - cstring local_metadata_type = ""; - cstring header_type = ""; + cstring local_metadata_type = cstring::empty; + cstring header_type = cstring::empty; IR::IndexedVector compiler_added_fields; IR::IndexedVector key_fields; IR::Vector used_metadata; @@ -104,8 +104,8 @@ struct hdrFieldInfo { unsigned msb; unsigned fieldWidth; hdrFieldInfo() { - modifiedName = ""; - headerStr = ""; + modifiedName = cstring::empty; + headerStr = cstring::empty; modifiedWidth = 0; offset = 0; lsb = 0; diff --git a/backends/dpdk/dpdkUtils.cpp b/backends/dpdk/dpdkUtils.cpp index 6b06d203bf..1d90f09512 100644 --- a/backends/dpdk/dpdkUtils.cpp +++ b/backends/dpdk/dpdkUtils.cpp @@ -16,6 +16,8 @@ limitations under the License. #include "dpdkUtils.h" namespace DPDK { +using namespace P4::literals; + bool isSimpleExpression(const IR::Expression *e) { if (e->is() || e->is() || e->is() || e->is()) @@ -38,6 +40,7 @@ bool isCommutativeBinaryOperation(const IR::Operation_Binary *bin) { } bool isStandardMetadata(cstring name) { + // FIXME: should be better structured (e.g. a set) bool isStdMeta = name == "psa_ingress_parser_input_metadata_t" || name == "psa_ingress_input_metadata_t" || name == "psa_ingress_output_metadata_t" || name == "psa_egress_parser_input_metadata_t" || @@ -50,13 +53,13 @@ bool isStandardMetadata(cstring name) { bool isHeadersStruct(const IR::Type_Struct *st) { if (!st) return false; - auto annon = st->getAnnotation("__packet_data__"); + auto annon = st->getAnnotation("__packet_data__"_cs); if (annon) return true; return false; } bool isMetadataStruct(const IR::Type_Struct *st) { for (auto anno : st->annotations->annotations) { - if (anno->name == "__metadata__") { + if (anno->name == "__metadata__"_cs) { return true; } } @@ -143,9 +146,9 @@ IR::Declaration_Instance *createRegDeclarationInstance(cstring instanceName, int } /// Check for reserved names for DPDK target. -bool reservedNames(P4::ReferenceMap *refMap, std::vector names, cstring &resName) { - for (auto name : names) { - auto newname = refMap->newName(name); +bool reservedNames(P4::ReferenceMap *refMap, const std::vector &names, cstring &resName) { + for (const auto &name : names) { + auto newname = refMap->newName(name.string_view()); if (newname != name) { resName = name; return false; diff --git a/backends/dpdk/dpdkUtils.h b/backends/dpdk/dpdkUtils.h index 0bdf7a1893..cc9c98ff39 100644 --- a/backends/dpdk/dpdkUtils.h +++ b/backends/dpdk/dpdkUtils.h @@ -37,7 +37,7 @@ int getMetadataFieldWidth(int width); const IR::Type_Bits *getEightBitAlignedType(const IR::Type_Bits *tb); /// Check for reserved names for DPDK target. -bool reservedNames(P4::ReferenceMap *refMap, std::vector names, cstring &resName); +bool reservedNames(P4::ReferenceMap *refMap, const std::vector &names, cstring &resName); /// Creates Register extern declaration for holding persistent information. IR::Declaration_Instance *createRegDeclarationInstance(cstring instanceName, int regSize, int indexBitWidth, int initValBitwidth); diff --git a/backends/dpdk/main.cpp b/backends/dpdk/main.cpp index 7d0e83c8f6..67f4d522b5 100644 --- a/backends/dpdk/main.cpp +++ b/backends/dpdk/main.cpp @@ -40,14 +40,16 @@ limitations under the License. #include "lib/log.h" #include "lib/nullstream.h" +using namespace P4::literals; + void generateTDIBfrtJson(bool isTDI, const IR::P4Program *program, DPDK::DpdkOptions &options) { auto p4RuntimeSerializer = P4::P4RuntimeSerializer::get(); if (options.arch == "psa") p4RuntimeSerializer->registerArch( - "psa", new P4::ControlPlaneAPI::Standard::PSAArchHandlerBuilderForDPDK()); + "psa"_cs, new P4::ControlPlaneAPI::Standard::PSAArchHandlerBuilderForDPDK()); if (options.arch == "pna") p4RuntimeSerializer->registerArch( - "pna", new P4::ControlPlaneAPI::Standard::PNAArchHandlerBuilderForDPDK()); + "pna"_cs, new P4::ControlPlaneAPI::Standard::PNAArchHandlerBuilderForDPDK()); auto p4Runtime = P4::generateP4Runtime(program, options.arch); cstring filename = isTDI ? options.tdiFile : options.bfRtSchema; @@ -66,7 +68,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoDpdkContext(new DPDK::DpdkContext); auto &options = DPDK::DpdkContext::get().options(); options.langVersion = CompilerOptions::FrontendVersion::P4_16; - options.compilerVersion = DPDK_VERSION_STRING; + options.compilerVersion = cstring(DPDK_VERSION_STRING); if (options.process(argc, argv) != nullptr) { if (options.loadIRFromJson == false) options.setInputFile(); diff --git a/backends/dpdk/midend.cpp b/backends/dpdk/midend.cpp index a0245ce17f..39ff4cb4d2 100644 --- a/backends/dpdk/midend.cpp +++ b/backends/dpdk/midend.cpp @@ -30,6 +30,7 @@ limitations under the License. #include "frontends/p4/typeMap.h" #include "frontends/p4/uniqueNames.h" #include "frontends/p4/unusedDeclarations.h" +#include "lib/cstring.h" #include "midend/actionSynthesis.h" #include "midend/compileTimeOps.h" #include "midend/complexComparison.h" @@ -119,17 +120,17 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options, std::ostream *outStream) { cstring externMethod = em->method->getName().name; std::vector> doNotCopyPropList = { - {"Checksum", "update"}, - {"Hash", "get_hash"}, - {"InternetChecksum", "add"}, - {"InternetChecksum", "subtract"}, - {"InternetChecksum", "set_state"}, - {"Register", "read"}, - {"Register", "write"}, - {"Counter", "count"}, - {"Meter", "execute"}, - {"Meter", "dpdk_execute"}, - {"Digest", "pack"}, + {"Checksum"_cs, "update"_cs}, + {"Hash"_cs, "get_hash"_cs}, + {"InternetChecksum"_cs, "add"_cs}, + {"InternetChecksum"_cs, "subtract"_cs}, + {"InternetChecksum"_cs, "set_state"_cs}, + {"Register"_cs, "read"_cs}, + {"Register"_cs, "write"_cs}, + {"Counter"_cs, "count"_cs}, + {"Meter"_cs, "execute"_cs}, + {"Meter"_cs, "dpdk_execute"_cs}, + {"Digest"_cs, "pack"_cs}, }; for (auto f : doNotCopyPropList) { if (externType == f.first && externMethod == f.second) { @@ -139,7 +140,7 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options, std::ostream *outStream) { } else if (auto ef = mi->to()) { cstring externFuncName = ef->method->getName().name; std::vector doNotCopyPropList = { - "verify", + "verify"_cs, }; for (auto f : doNotCopyPropList) { if (externFuncName == f) return false; @@ -152,19 +153,20 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options, std::ostream *outStream) { std::function validateTableProperties = [=](cstring arch) -> Inspector * { if (arch == "pna") { return new P4::ValidateTableProperties( - {"pna_implementation", "pna_direct_counter", "pna_direct_meter", "pna_idle_timeout", - "size", "add_on_miss", "idle_timeout_with_auto_delete", - "default_idle_timeout_for_data_plane_added_entries"}); + {"pna_implementation"_cs, "pna_direct_counter"_cs, "pna_direct_meter"_cs, + "pna_idle_timeout"_cs, "size"_cs, "add_on_miss"_cs, + "idle_timeout_with_auto_delete"_cs, + "default_idle_timeout_for_data_plane_added_entries"_cs}); } else if (arch == "psa") { - return new P4::ValidateTableProperties({"psa_implementation", "psa_direct_counter", - "psa_direct_meter", "psa_idle_timeout", - "size"}); + return new P4::ValidateTableProperties({"psa_implementation"_cs, + "psa_direct_counter"_cs, "psa_direct_meter"_cs, + "psa_idle_timeout"_cs, "size"_cs}); } else { return nullptr; } }; - if (DPDK::DpdkContext::get().options().loadIRFromJson == false) { + if (!DPDK::DpdkContext::get().options().loadIRFromJson) { addPasses({ options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr, new P4::RemoveMiss(&refMap, &typeMap), @@ -225,7 +227,7 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options, std::ostream *outStream) { new VisitFunctor([this, evaluator]() { toplevel = evaluator->getToplevelBlock(); }), }); if (options.listMidendPasses) { - listPasses(*outStream, "\n"); + listPasses(*outStream, cstring::newline); *outStream << std::endl; return; } diff --git a/backends/dpdk/options.cpp b/backends/dpdk/options.cpp index bd8e914990..03275d0fe6 100644 --- a/backends/dpdk/options.cpp +++ b/backends/dpdk/options.cpp @@ -5,9 +5,11 @@ namespace DPDK { +using namespace P4::literals; + std::vector *DpdkOptions::process(int argc, char *const argv[]) { searchForIncludePath(p4includePath, - {"p4include/dpdk", "../p4include/dpdk", "../../p4include/dpdk"}, + {"p4include/dpdk"_cs, "../p4include/dpdk"_cs, "../../p4include/dpdk"_cs}, exename(argv[0])); auto remainingOptions = CompilerOptions::process(argc, argv); @@ -18,11 +20,11 @@ std::vector *DpdkOptions::process(int argc, char *const argv[]) { const char *DpdkOptions::getIncludePath() { char *driverP4IncludePath = isv1() ? getenv("P4C_14_INCLUDE_PATH") : getenv("P4C_16_INCLUDE_PATH"); - cstring path = ""; - if (driverP4IncludePath != nullptr) path += cstring(" -I") + cstring(driverP4IncludePath); + cstring path = cstring::empty; + if (driverP4IncludePath != nullptr) path += " -I"_cs + cstring(driverP4IncludePath); path += cstring(" -I") + (isv1() ? p4_14includePath : p4includePath); - if (!isv1()) path += cstring(" -I") + p4includePath + cstring("/dpdk"); + if (!isv1()) path += " -I"_cs + p4includePath + "/dpdk"_cs; return path.c_str(); } diff --git a/backends/dpdk/options.h b/backends/dpdk/options.h index c50006359c..f4ec5166f6 100644 --- a/backends/dpdk/options.h +++ b/backends/dpdk/options.h @@ -23,15 +23,15 @@ namespace DPDK { class DpdkOptions : public CompilerOptions { public: - cstring bfRtSchema = ""; + cstring bfRtSchema = cstring::empty; /// File to output to. cstring outputFile = nullptr; /// File to output TDI JSON to. - cstring tdiFile = ""; + cstring tdiFile = cstring::empty; /// File to output context JSON to. - cstring ctxtFile = ""; + cstring ctxtFile = cstring::empty; /// File to output the TDI builder configuration to. - cstring tdiBuilderConf = ""; + cstring tdiBuilderConf = cstring::empty; /// Read from JSON. bool loadIRFromJson = false; /// Enable/disable Egress pipeline in PSA. @@ -58,35 +58,35 @@ class DpdkOptions : public CompilerOptions { registerOption( "--bf-rt-schema", "file", [this](const char *arg) { - bfRtSchema = arg; + bfRtSchema = cstring(arg); return true; }, "Generate and write BF-RT JSON schema to the specified file"); registerOption( "-o", "outfile", [this](const char *arg) { - outputFile = arg; + outputFile = cstring(arg); return true; }, "Write output to outfile"); registerOption( "--tdi-builder-conf", "file", [this](const char *arg) { - tdiBuilderConf = arg; + tdiBuilderConf = cstring(arg); return true; }, "Generate and write the TDI builder configuration to the specified file"); registerOption( "--tdi", "file", [this](const char *arg) { - tdiFile = arg; + tdiFile = cstring(arg); return true; }, "Generate and write TDI JSON to the specified file"); registerOption( "--context", "file", [this](const char *arg) { - ctxtFile = arg; + ctxtFile = cstring(arg); return true; }, "Generate and write context JSON to the specified file"); @@ -94,7 +94,7 @@ class DpdkOptions : public CompilerOptions { "--fromJSON", "file", [this](const char *arg) { loadIRFromJson = true; - file = arg; + file = cstring(arg); return true; }, "Use IR representation from JsonFile dumped previously," diff --git a/backends/dpdk/spec.cpp b/backends/dpdk/spec.cpp index b2a66d8d7d..ea6f685925 100644 --- a/backends/dpdk/spec.cpp +++ b/backends/dpdk/spec.cpp @@ -14,7 +14,7 @@ auto &origNameMap = DPDK::ShortenTokenLength::origNameMap; void add_space(std::ostream &out, int size) { out << std::setfill(' ') << std::setw(size) << " "; } -void add_comment(std::ostream &out, cstring str, cstring sep = "") { +void add_comment(std::ostream &out, cstring str, std::string_view sep = "") { if (origNameMap.count(str)) { out << sep << ";oldname:" << origNameMap.at(str) << "\n"; } @@ -211,7 +211,7 @@ std::ostream &IR::DpdkHeaderType::toSpec(std::ostream &out) const { } std::ostream &IR::DpdkStructType::toSpec(std::ostream &out) const { - if (getAnnotations()->getSingle("__packet_data__")) { + if (getAnnotations()->getSingle("__packet_data__"_cs)) { for (auto it = fields.begin(); it != fields.end(); ++it) { add_comment(out, (*it)->name.toString()); if (auto t = (*it)->type->to()) { @@ -258,7 +258,7 @@ std::ostream &IR::DpdkStructType::toSpec(std::ostream &out) const { out << std::endl; } out << "}" << std::endl; - if (getAnnotations()->getSingle("__metadata__")) { + if (getAnnotations()->getSingle("__metadata__"_cs)) { out << "metadata instanceof " << name << std::endl; } } @@ -402,8 +402,8 @@ std::ostream &IR::DpdkTable::toSpec(std::ostream &out) const { } else { out << "\t\t" << DPDK::toStr(action->expression); } - if (action->annotations->getAnnotation("tableonly")) out << " @tableonly"; - if (action->annotations->getAnnotation("defaultonly")) out << " @defaultonly"; + if (action->annotations->getAnnotation("tableonly"_cs)) out << " @tableonly"; + if (action->annotations->getAnnotation("defaultonly"_cs)) out << " @defaultonly"; out << std::endl; } out << "\t}" << std::endl; @@ -444,13 +444,13 @@ std::ostream &IR::DpdkTable::toSpec(std::ostream &out) const { } } } - auto def = properties->getProperty("default_action"); + auto def = properties->getProperty("default_action"_cs); if (def->isConstant) out << "const"; out << std::endl; - if (auto psa_implementation = properties->getProperty("psa_implementation")) { + if (auto psa_implementation = properties->getProperty("psa_implementation"_cs)) { out << "\taction_selector " << DPDK::toStr(psa_implementation->value) << std::endl; } - if (auto size = properties->getProperty("size")) { + if (auto size = properties->getProperty("size"_cs)) { out << "\tsize " << DPDK::toStr(size->value) << "" << std::endl; } else { out << "\tsize 0x10000" << std::endl; @@ -489,8 +489,8 @@ std::ostream &IR::DpdkLearner::toSpec(std::ostream &out) const { out << "\tactions {" << std::endl; for (auto action : actions->actionList) { out << "\t\t" << DPDK::toStr(action->expression); - if (action->getAnnotation("tableonly")) out << " @tableonly"; - if (action->getAnnotation("defaultonly")) out << " @defaultonly"; + if (action->getAnnotation("tableonly"_cs)) out << " @tableonly"; + if (action->getAnnotation("defaultonly"_cs)) out << " @defaultonly"; out << std::endl; } out << "\t}" << std::endl; @@ -502,7 +502,7 @@ std::ostream &IR::DpdkLearner::toSpec(std::ostream &out) const { BUG("non-zero default action arguments not supported yet"); } out << std::endl; - if (auto size = properties->getProperty("size")) { + if (auto size = properties->getProperty("size"_cs)) { out << "\tsize " << DPDK::toStr(size->value) << "" << std::endl; } else { out << "\tsize 0x" << std::hex << std::uppercase << default_learner_table_size << std::endl; diff --git a/backends/dpdk/tdiConf.cpp b/backends/dpdk/tdiConf.cpp index a8eaa79697..cdeef5e60c 100644 --- a/backends/dpdk/tdiConf.cpp +++ b/backends/dpdk/tdiConf.cpp @@ -21,6 +21,8 @@ limitations under the License. namespace DPDK { +using namespace P4::literals; + std::vector TdiBfrtConf::getPipeNames(const IR::Declaration_Instance *main) { std::vector pipeNames; for (const auto *arg : *main->arguments) { @@ -42,11 +44,11 @@ std::optional TdiBfrtConf::findPipeName(const IR::P4Program *prog, DPDK::DpdkOptions &options) { if (options.arch == "pna") { // The PNA pipename is currently fixed to "pipe". - return "pipe"; + return "pipe"_cs; } if (options.arch == "psa") { // We try to infer the pipename by looking up the "main" declaration. - auto *decls = prog->getDeclsByName("main"); + auto *decls = prog->getDeclsByName("main"_cs); const IR::Declaration_Instance *main = nullptr; for (const auto *decl : *decls) { main = decl->checkedTo(); @@ -78,14 +80,14 @@ void TdiBfrtConf::generate(const IR::P4Program *prog, DPDK::DpdkOptions &options auto programName = inputFile.stem(); if (options.bfRtSchema.isNullOrEmpty()) { - options.bfRtSchema = (outDir / programName).replace_filename("json").c_str(); + options.bfRtSchema = cstring((outDir / programName).replace_filename("json").c_str()); ::warning( "BF-Runtime Schema file name not provided, but is required for the TDI builder " "configuration. Generating file %1%", options.bfRtSchema); } if (options.ctxtFile.isNullOrEmpty()) { - options.ctxtFile = (outDir / "context.json").c_str(); + options.ctxtFile = cstring((outDir / "context.json").c_str()); ::warning( "DPDK context file name not provided, but is required for the TDI builder " "configuration. Generating file %1%", diff --git a/backends/ebpf/codeGen.cpp b/backends/ebpf/codeGen.cpp index ebdb8a718c..1fd82e232d 100644 --- a/backends/ebpf/codeGen.cpp +++ b/backends/ebpf/codeGen.cpp @@ -63,7 +63,7 @@ bool CodeGenInspector::preorder(const IR::Declaration_Variable *decl) { static cstring getMask(P4::TypeMap *typeMap, const IR::Node *node) { auto type = typeMap->getType(node, true); - cstring mask = ""; + cstring mask = cstring::empty; if (auto tb = type->to()) { if (tb->size != 8 && tb->size != 16 && tb->size != 32 && tb->size != 64) mask = " & ((1 << " + Util::toString(tb->size) + ") - 1)"; @@ -478,16 +478,16 @@ void CodeGenInspector::emitAndConvertByteOrder(const IR::Expression *expr, cstri auto ftype = typeMap->getType(expr); auto et = EBPFTypeFactory::instance->create(ftype); unsigned widthToEmit = dynamic_cast(et)->widthInBits(); - cstring emit = ""; + cstring emit = cstring::empty; unsigned loadSize = 64; if (widthToEmit <= 16) { - emit = byte_order == "HOST" ? "bpf_ntohs" : "bpf_htons"; + emit = byte_order == "HOST" ? "bpf_ntohs"_cs : "bpf_htons"_cs; loadSize = 16; } else if (widthToEmit <= 32) { - emit = byte_order == "HOST" ? "bpf_ntohl" : "bpf_htonl"; + emit = byte_order == "HOST" ? "bpf_ntohl"_cs : "bpf_htonl"_cs; loadSize = 32; } else if (widthToEmit <= 64) { - emit = byte_order == "HOST" ? "ntohll" : "bpf_cpu_to_be64"; + emit = byte_order == "HOST" ? "ntohll"_cs : "bpf_cpu_to_be64"_cs; loadSize = 64; } unsigned shift = loadSize - widthToEmit; @@ -504,7 +504,7 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool auto action = findContext(); auto tcTarget = dynamic_cast(builder->target); - cstring lByteOrder = "HOST", rByteOrder = "HOST"; + cstring lByteOrder = "HOST"_cs, rByteOrder = "HOST"_cs; if (lexpr) { lByteOrder = tcTarget->getByteOrder(typeMap, action, lexpr); } @@ -532,7 +532,7 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool if (width <= 8) { visit(lexpr); } else { - emitAndConvertByteOrder(lexpr, "NETWORK"); + emitAndConvertByteOrder(lexpr, "NETWORK"_cs); } if (isScalar) { builder->spc(); @@ -561,7 +561,7 @@ void CodeGenInspector::emitTCBinaryOperation(const IR::Operation_Binary *b, bool if (width <= 8) { visit(rexpr); } else { - emitAndConvertByteOrder(rexpr, "NETWORK"); + emitAndConvertByteOrder(rexpr, "NETWORK"_cs); } } return; @@ -571,7 +571,7 @@ void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression const IR::Expression *rexpr) { auto action = findContext(); auto b = dynamic_cast(builder->target); - cstring lByteOrder = "HOST", rByteOrder = "HOST"; + cstring lByteOrder = "HOST"_cs, rByteOrder = "HOST"_cs; if (lexpr) { lByteOrder = b->getByteOrder(typeMap, action, lexpr); } @@ -596,7 +596,7 @@ void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression // select_0 = hdr.ipv4.diffserv // select_0 = bntoh(hdr.ipv4.diffserv) // - emitAndConvertByteOrder(rexpr, "HOST"); + emitAndConvertByteOrder(rexpr, "HOST"_cs); } if (lByteOrder == "NETWORK") { // If left side of assignment is annotated field i.e network endian, we need to convert @@ -605,7 +605,7 @@ void CodeGenInspector::emitTCAssignmentEndianessConversion(const IR::Expression // hdr.opv4.diffserv = 0x1; // hdr.opv4.diffserv = bhton(0x1) // - emitAndConvertByteOrder(rexpr, "NETWORK"); + emitAndConvertByteOrder(rexpr, "NETWORK"_cs); } return; diff --git a/backends/ebpf/ebpfControl.cpp b/backends/ebpf/ebpfControl.cpp index 2c0c8c2c7a..ad4563a8aa 100644 --- a/backends/ebpf/ebpfControl.cpp +++ b/backends/ebpf/ebpfControl.cpp @@ -22,6 +22,7 @@ limitations under the License. #include "frontends/p4/parameterSubstitution.h" #include "frontends/p4/tableApply.h" #include "frontends/p4/typeMap.h" +#include "lib/cstring.h" #include "lib/error.h" namespace EBPF { @@ -67,7 +68,7 @@ void ControlBodyTranslator::processCustomExternFunction(const P4::ExternFunction builder->append("(const "); auto type = typeMap->getType(arg); auto ebpfType = typeFactory->create(type); - ebpfType->declare(builder, "", false); + ebpfType->declare(builder, cstring::empty, false); builder->append(") "); } visit(arg); @@ -156,11 +157,11 @@ void ControlBodyTranslator::compileEmitField(const IR::Expression *expr, cstring unsigned hdrOffsetBits, EBPFType *type) { unsigned alignment = hdrOffsetBits % 8; unsigned widthToEmit = type->as().widthInBits(); - cstring swap = ""; + cstring swap = cstring::empty; if (widthToEmit == 16) - swap = "htons"; + swap = "htons"_cs; else if (widthToEmit == 32) - swap = "htonl"; + swap = "htonl"_cs; if (!swap.isNullOrEmpty()) { builder->emitIndent(); visit(expr); @@ -318,7 +319,7 @@ void ControlBodyTranslator::processApply(const P4::ApplyMethod *method) { builder->blockStart(); BUG_CHECK(method->expr->arguments->size() == 0, "%1%: table apply with arguments", method); - cstring keyname = "key"; + cstring keyname = "key"_cs; if (table->keyGenerator != nullptr) { builder->emitIndent(); builder->appendLine("/* construct key */"); @@ -330,7 +331,7 @@ void ControlBodyTranslator::processApply(const P4::ApplyMethod *method) { builder->emitIndent(); builder->appendLine("/* value */"); builder->emitIndent(); - cstring valueName = "value"; + cstring valueName = "value"_cs; builder->appendFormat("struct %s *%s = NULL", table->valueTypeName.c_str(), valueName.c_str()); builder->endOfStatement(true); diff --git a/backends/ebpf/ebpfDeparser.cpp b/backends/ebpf/ebpfDeparser.cpp index 24a99feccd..41a8b3d424 100644 --- a/backends/ebpf/ebpfDeparser.cpp +++ b/backends/ebpf/ebpfDeparser.cpp @@ -190,7 +190,7 @@ void DeparserHdrEmitTranslator::emitField(CodeBuilder *builder, cstring field, } unsigned widthToEmit = et->widthInBits(); unsigned emitSize = 0; - cstring swap = "", msgStr; + cstring swap = cstring::empty, msgStr; if (widthToEmit <= 64) { if (program->options.emitTraceMessages) { @@ -214,13 +214,13 @@ void DeparserHdrEmitTranslator::emitField(CodeBuilder *builder, cstring field, if (widthToEmit <= 8) { emitSize = 8; } else if (widthToEmit <= 16) { - swap = "bpf_htons"; + swap = "bpf_htons"_cs; emitSize = 16; } else if (widthToEmit <= 32) { - swap = "htonl"; + swap = "htonl"_cs; emitSize = 32; } else if (widthToEmit <= 64) { - swap = "htonll"; + swap = "htonll"_cs; emitSize = 64; } unsigned shift = @@ -329,7 +329,7 @@ void EBPFDeparser::emitBufferAdjusts(CodeBuilder *builder) const { builder->endOfStatement(true); builder->emitIndent(); builder->appendFormat("%s = ", returnCode.c_str()); - program->progTarget->emitResizeBuffer(builder, program->model.CPacketName.str(), + program->progTarget->emitResizeBuffer(builder, program->model.CPacketName.toString(), outerHdrOffsetVar); builder->endOfStatement(true); @@ -371,14 +371,14 @@ void EBPFDeparser::emit(CodeBuilder *builder) { builder->emitIndent(); builder->appendFormat("%s = %s;", program->packetStartVar, - builder->target->dataOffset(program->model.CPacketName.str())); + builder->target->dataOffset(program->model.CPacketName.toString())); builder->newline(); builder->emitIndent(); builder->appendFormat("%s = %s;", program->headerStartVar, program->packetStartVar); builder->newline(); builder->emitIndent(); builder->appendFormat("%s = %s;", program->packetEndVar, - builder->target->dataEnd(program->model.CPacketName.str())); + builder->target->dataEnd(program->model.CPacketName.toString())); builder->newline(); // emit headers diff --git a/backends/ebpf/ebpfModel.cpp b/backends/ebpf/ebpfModel.cpp index 792cde33b1..7476c373be 100644 --- a/backends/ebpf/ebpfModel.cpp +++ b/backends/ebpf/ebpfModel.cpp @@ -18,7 +18,7 @@ limitations under the License. namespace EBPF { -cstring EBPFModel::reservedPrefix = "ebpf_"; +cstring EBPFModel::reservedPrefix = "ebpf_"_cs; EBPFModel EBPFModel::instance; } // namespace EBPF diff --git a/backends/ebpf/ebpfModel.h b/backends/ebpf/ebpfModel.h index 0757027703..9f819e325d 100644 --- a/backends/ebpf/ebpfModel.h +++ b/backends/ebpf/ebpfModel.h @@ -24,18 +24,20 @@ limitations under the License. namespace EBPF { +using namespace P4::literals; + struct TableImpl_Model : public ::Model::Extern_Model { - explicit TableImpl_Model(cstring name) : Extern_Model(name), size("size") {} + explicit TableImpl_Model(cstring name) : Extern_Model(name), size("size"_cs) {} ::Model::Elem size; }; struct CounterArray_Model : public ::Model::Extern_Model { CounterArray_Model() - : Extern_Model("CounterArray"), - increment("increment"), - add("add"), - max_index("max_index"), - sparse("sparse") {} + : Extern_Model("CounterArray"_cs), + increment("increment"_cs), + add("add"_cs), + max_index("max_index"_cs), + sparse("sparse"_cs) {} ::Model::Elem increment; ::Model::Elem add; ::Model::Elem max_index; @@ -48,14 +50,14 @@ enum ModelArchitecture { }; struct Xdp_Model : public ::Model::Elem { - Xdp_Model() : Elem("xdp"), parser("p"), switch_("s"), deparser("d") {} + Xdp_Model() : Elem("xdp"_cs), parser("p"_cs), switch_("s"_cs), deparser("d"_cs) {} ::Model::Elem parser; ::Model::Elem switch_; ::Model::Elem deparser; }; struct Filter_Model : public ::Model::Elem { - Filter_Model() : Elem("ebpf_filter"), parser("prs"), filter("filt") {} + Filter_Model() : Elem("ebpf_filter"_cs), parser("prs"_cs), filter("filt"_cs) {} ::Model::Elem parser; ::Model::Elem filter; }; @@ -65,16 +67,16 @@ class EBPFModel : public ::Model::Model { protected: EBPFModel() : counterArray(), - array_table("array_table"), - hash_table("hash_table"), - tableImplProperty("implementation"), - CPacketName("skb"), - packet("packet", P4::P4CoreLibrary::instance().packetIn, 0), + array_table("array_table"_cs), + hash_table("hash_table"_cs), + tableImplProperty("implementation"_cs), + CPacketName("skb"_cs), + packet("packet"_cs, P4::P4CoreLibrary::instance().packetIn, 0), arch(EbpfFilter), filter(), xdp(), - counterIndexType("u32"), - counterValueType("u32") {} + counterIndexType("u32"_cs), + counterValueType("u32"_cs) {} public: static EBPFModel instance; diff --git a/backends/ebpf/ebpfOptions.cpp b/backends/ebpf/ebpfOptions.cpp index 315fbb2160..fc96635a32 100644 --- a/backends/ebpf/ebpfOptions.cpp +++ b/backends/ebpf/ebpfOptions.cpp @@ -23,7 +23,7 @@ EbpfOptions::EbpfOptions() { registerOption( "-o", "outfile", [this](const char *arg) { - outputFile = arg; + outputFile = cstring(arg); return true; }, "Write output to outfile"); @@ -42,7 +42,7 @@ EbpfOptions::EbpfOptions() { "--fromJSON", "file", [this](const char *arg) { loadIRFromJson = true; - file = arg; + file = cstring(arg); return true; }, "Use IR representation from JsonFile dumped previously," diff --git a/backends/ebpf/ebpfParser.cpp b/backends/ebpf/ebpfParser.cpp index 34297002c3..26bdb52a18 100644 --- a/backends/ebpf/ebpfParser.cpp +++ b/backends/ebpf/ebpfParser.cpp @@ -388,7 +388,7 @@ void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, if (expr->is() && expr->to()->expr->is() && isPointerVariable( expr->to()->expr->to()->path->name.name)) { - exprStr = exprStr.replace(".", "->"); + exprStr = exprStr.replace("."_cs, "->"_cs); } cstring tmp = Util::printf_format("(unsigned long long) %s.%s", exprStr, fieldName); diff --git a/backends/ebpf/ebpfProgram.cpp b/backends/ebpf/ebpfProgram.cpp index 356efb2299..a70883dab3 100644 --- a/backends/ebpf/ebpfProgram.cpp +++ b/backends/ebpf/ebpfProgram.cpp @@ -105,11 +105,11 @@ void EBPFProgram::emitC(CodeBuilder *builder, cstring header) { builder->emitIndent(); // Use different section name for XDP - this is used by the runtime test framework. if (model.arch == ModelArchitecture::XdpSwitch) - builder->target->emitCodeSection(builder, "xdp"); + builder->target->emitCodeSection(builder, "xdp"_cs); else - builder->target->emitCodeSection(builder, "prog"); + builder->target->emitCodeSection(builder, "prog"_cs); builder->emitIndent(); - builder->target->emitMain(builder, functionName, model.CPacketName.str()); + builder->target->emitMain(builder, functionName, model.CPacketName.toString()); builder->blockStart(); emitHeaderInstances(builder); @@ -280,14 +280,14 @@ void EBPFProgram::emitLocalVariables(CodeBuilder *builder) { builder->emitIndent(); builder->appendFormat("void* %s = %s;", packetStartVar.c_str(), - builder->target->dataOffset(model.CPacketName.str()).c_str()); + builder->target->dataOffset(model.CPacketName.toString()).c_str()); builder->newline(); builder->emitIndent(); builder->appendFormat("u8* %s = %s;", headerStartVar.c_str(), packetStartVar.c_str()); builder->newline(); builder->emitIndent(); builder->appendFormat("void* %s = %s;", packetEndVar.c_str(), - builder->target->dataEnd(model.CPacketName.str()).c_str()); + builder->target->dataEnd(model.CPacketName.toString()).c_str()); builder->newline(); if (model.arch == ModelArchitecture::EbpfFilter) { @@ -315,7 +315,7 @@ void EBPFProgram::emitLocalVariables(CodeBuilder *builder) { builder->emitIndent(); builder->appendFormat("u32 %s = %s", lengthVar.c_str(), - builder->target->dataLength(model.CPacketName.str()).c_str()); + builder->target->dataLength(model.CPacketName.toString()).c_str()); builder->endOfStatement(true); } @@ -351,14 +351,14 @@ void EBPFProgram::emitPipeline(CodeBuilder *builder) { } bool EBPFProgram::isLibraryMethod(cstring methodName) { - static std::set DEFAULT_METHODS = {"static_assert", "verify"}; + static std::set DEFAULT_METHODS = {"static_assert"_cs, "verify"_cs}; if (DEFAULT_METHODS.find(methodName) != DEFAULT_METHODS.end() && options.target != "xdp") { return true; } static std::set XDP_METHODS = { - "ebpf_ipv4_checksum", "csum_replace2", "csum_replace4", - "BPF_PERF_EVENT_OUTPUT", "BPF_KTIME_GET_NS", + "ebpf_ipv4_checksum"_cs, "csum_replace2"_cs, "csum_replace4"_cs, + "BPF_PERF_EVENT_OUTPUT"_cs, "BPF_KTIME_GET_NS"_cs, }; return XDP_METHODS.find(methodName) != XDP_METHODS.end(); } diff --git a/backends/ebpf/ebpfProgram.h b/backends/ebpf/ebpfProgram.h index b354ab0282..385f3d412e 100644 --- a/backends/ebpf/ebpfProgram.h +++ b/backends/ebpf/ebpfProgram.h @@ -57,8 +57,8 @@ class EBPFProgram : public EBPFObject { cstring zeroKey, functionName, errorVar; cstring packetStartVar, packetEndVar, byteVar; cstring errorEnum; - cstring license = "GPL"; /// TODO: this should be a compiler option probably - cstring arrayIndexType = "u32"; + cstring license = "GPL"_cs; /// TODO: this should be a compiler option probably + cstring arrayIndexType = "u32"_cs; virtual bool build(); /// return 'true' on success @@ -75,17 +75,17 @@ class EBPFProgram : public EBPFObject { model(EBPFModel::instance), deparser(nullptr) { // NB: offsetVar not used in eBPF backend - uBPF and TC only - offsetVar = EBPFModel::reserved("packetOffsetInBits"); - zeroKey = EBPFModel::reserved("zero"); - functionName = EBPFModel::reserved("filter"); - errorVar = EBPFModel::reserved("errorCode"); - packetStartVar = EBPFModel::reserved("packetStart"); - packetEndVar = EBPFModel::reserved("packetEnd"); - headerStartVar = EBPFModel::reserved("headerStart"); - lengthVar = EBPFModel::reserved("pkt_len"); - byteVar = EBPFModel::reserved("byte"); - endLabel = EBPFModel::reserved("end"); - errorEnum = EBPFModel::reserved("errorCodes"); + offsetVar = EBPFModel::reserved("packetOffsetInBits"_cs); + zeroKey = EBPFModel::reserved("zero"_cs); + functionName = EBPFModel::reserved("filter"_cs); + errorVar = EBPFModel::reserved("errorCode"_cs); + packetStartVar = EBPFModel::reserved("packetStart"_cs); + packetEndVar = EBPFModel::reserved("packetEnd"_cs); + headerStartVar = EBPFModel::reserved("headerStart"_cs); + lengthVar = EBPFModel::reserved("pkt_len"_cs); + byteVar = EBPFModel::reserved("byte"_cs); + endLabel = EBPFModel::reserved("end"_cs); + errorEnum = EBPFModel::reserved("errorCodes"_cs); } protected: diff --git a/backends/ebpf/ebpfTable.cpp b/backends/ebpf/ebpfTable.cpp index fb4ed36adb..2c0c866f4c 100644 --- a/backends/ebpf/ebpfTable.cpp +++ b/backends/ebpf/ebpfTable.cpp @@ -356,7 +356,7 @@ void EBPFTable::emitTernaryInstance(CodeBuilder *builder) { "struct " + valueTypeName + "_mask", size); builder->target->emitMapInMapDecl(builder, instanceName + "_tuple", TableHash, "struct " + keyTypeName, "struct " + valueTypeName, size, - instanceName + "_tuples_map", TableArray, "__u32", size); + instanceName + "_tuples_map", TableArray, "__u32"_cs, size); } void EBPFTable::emitInstance(CodeBuilder *builder) { @@ -471,13 +471,13 @@ void EBPFTable::emitKey(CodeBuilder *builder, cstring keyName) { memcpy = !EBPFScalarType::generatesScalar(width); if (width <= 8) { - swap = ""; // single byte, nothing to swap + swap = cstring::empty; // single byte, nothing to swap } else if (width <= 16) { - swap = "bpf_htons"; + swap = "bpf_htons"_cs; } else if (width <= 32) { - swap = "bpf_htonl"; + swap = "bpf_htonl"_cs; } else if (width <= 64) { - swap = "bpf_htonll"; + swap = "bpf_htonll"_cs; } else { // The code works with fields wider than 64 bits for PSA architecture. It is shared // with filter model, so should work but has not been tested. Error message is @@ -603,10 +603,10 @@ void EBPFTable::emitInitializer(CodeBuilder *builder) { BUG_CHECK(ac != nullptr, "%1%: expected an action call", mce); auto action = ac->action; cstring name = EBPFObject::externalName(action); - cstring fd = "tableFileDescriptor"; + cstring fd = "tableFileDescriptor"_cs; cstring defaultTable = defaultActionMapName; - cstring value = "value"; - cstring key = "key"; + cstring value = "value"_cs; + cstring key = "key"_cs; builder->emitIndent(); builder->blockStart(); @@ -744,7 +744,7 @@ void EBPFTable::emitLookup(CodeBuilder *builder, cstring key, cstring value) { builder->newline(); builder->emitIndent(); builder->appendFormat("struct %s_mask *", valueTypeName); - builder->target->emitTableLookup(builder, instanceName + "_prefixes", "head", "val"); + builder->target->emitTableLookup(builder, instanceName + "_prefixes", "head"_cs, "val"_cs); builder->endOfStatement(true); builder->emitIndent(); builder->append("if (val && val->has_next != 0) "); @@ -759,7 +759,7 @@ void EBPFTable::emitLookup(CodeBuilder *builder, cstring key, cstring value) { builder->blockStart(); builder->emitIndent(); builder->appendFormat("struct %s_mask *", valueTypeName); - builder->target->emitTableLookup(builder, instanceName + "_prefixes", "next", "v"); + builder->target->emitTableLookup(builder, instanceName + "_prefixes", "next"_cs, "v"_cs); builder->endOfStatement(true); builder->emitIndent(); builder->append("if (!v) "); @@ -769,7 +769,7 @@ void EBPFTable::emitLookup(CodeBuilder *builder, cstring key, cstring value) { builder->appendLine("break;"); builder->blockEnd(true); builder->emitIndent(); - cstring new_key = "k"; + cstring new_key = "k"_cs; builder->appendFormat("struct %s %s = {};", keyTypeName, new_key); builder->newline(); builder->emitIndent(); @@ -799,7 +799,8 @@ void EBPFTable::emitLookup(CodeBuilder *builder, cstring key, cstring value) { builder->newline(); builder->emitIndent(); builder->append("struct bpf_elf_map *"); - builder->target->emitTableLookup(builder, instanceName + "_tuples_map", "tuple_id", "tuple"); + builder->target->emitTableLookup(builder, instanceName + "_tuples_map", "tuple_id"_cs, + "tuple"_cs); builder->endOfStatement(true); builder->emitIndent(); builder->append("if (!tuple) "); @@ -855,7 +856,7 @@ void EBPFTable::emitLookup(CodeBuilder *builder, cstring key, cstring value) { cstring EBPFTable::p4ActionToActionIDName(const IR::P4Action *action) const { if (action->name.originalName == P4::P4CoreLibrary::instance().noAction.name) { // NoAction always gets ID=0. - return "0"; + return "0"_cs; } cstring actionName = EBPFObject::externalName(action); @@ -984,7 +985,7 @@ void EBPFCounterTable::emitCounterIncrement(CodeBuilder *builder, builder->appendLine("else"); builder->increaseIndent(); builder->emitIndent(); - builder->target->emitTableUpdate(builder, dataMapName, keyName, "init_val"); + builder->target->emitTableUpdate(builder, dataMapName, keyName, "init_val"_cs); builder->newline(); builder->decreaseIndent(); } @@ -1047,7 +1048,7 @@ void EBPFCounterTable::emitCounterAdd(CodeBuilder *builder, builder->appendLine("else"); builder->increaseIndent(); builder->emitIndent(); - builder->target->emitTableUpdate(builder, dataMapName, keyName, "init_val"); + builder->target->emitTableUpdate(builder, dataMapName, keyName, "init_val"_cs); builder->newline(); builder->decreaseIndent(); } @@ -1082,7 +1083,7 @@ EBPFValueSet::EBPFValueSet(const EBPFProgram *program, const IR::P4ValueSet *p4v cstring instanceName, CodeGenInspector *codeGen) : EBPFTableBase(program, instanceName, codeGen), size(0), pvs(p4vs) { CHECK_NULL(pvs); - valueTypeName = "u32"; // map value is not used, so its type can be anything + valueTypeName = "u32"_cs; // map value is not used, so its type can be anything // validate size if (pvs->size->is()) { @@ -1138,7 +1139,7 @@ void EBPFValueSet::emitTypes(CodeBuilder *builder) { }; if (auto tb = elemType->to()) { - cstring name = "field0"; + cstring name = "field0"_cs; fieldEmitter(tb, name); fieldNames.emplace_back(std::make_pair(name, tb)); } else if (auto tuple = elemType->to()) { @@ -1212,7 +1213,7 @@ void EBPFValueSet::emitKeyInitializer(CodeBuilder *builder, const IR::SelectExpr } void EBPFValueSet::emitLookup(CodeBuilder *builder) { - builder->target->emitTableLookup(builder, instanceName, keyVarName, ""); + builder->target->emitTableLookup(builder, instanceName, keyVarName, cstring::empty); } } // namespace EBPF diff --git a/backends/ebpf/ebpfTable.h b/backends/ebpf/ebpfTable.h index 8dd3108272..8bfaa93e45 100644 --- a/backends/ebpf/ebpfTable.h +++ b/backends/ebpf/ebpfTable.h @@ -97,7 +97,7 @@ class EBPFTable : public EBPFTableBase { /// Use 1024 by default. /// TODO: make it configurable using compiler options. size_t size = 1024; - const cstring prefixFieldName = "prefixlen"; + const cstring prefixFieldName = "prefixlen"_cs; EBPFTable(const EBPFProgram *program, const IR::TableBlock *table, CodeGenInspector *codeGen); EBPFTable(const EBPFProgram *program, CodeGenInspector *codeGen, cstring name); diff --git a/backends/ebpf/ebpfType.cpp b/backends/ebpf/ebpfType.cpp index 9814f46d7c..4305d74a06 100644 --- a/backends/ebpf/ebpfType.cpp +++ b/backends/ebpf/ebpfType.cpp @@ -168,11 +168,11 @@ void EBPFScalarType::emitInitializer(CodeBuilder *builder) { EBPFStructType::EBPFStructType(const IR::Type_StructLike *strct) : EBPFType(strct) { if (strct->is()) - kind = "struct"; + kind = "struct"_cs; else if (strct->is()) - kind = "struct"; + kind = "struct"_cs; else if (strct->is()) - kind = "union"; + kind = "union"_cs; else BUG("Unexpected struct type %1%", strct); name = strct->name.name; @@ -216,7 +216,8 @@ void EBPFStructType::emitInitializer(CodeBuilder *builder) { } } else if (type->is()) { builder->emitIndent(); - builder->appendLine(".ebpf_valid = 0"); + builder->append(".ebpf_valid = 0"); + builder->newline(); } else { BUG("Unexpected type %1%", type); } @@ -251,7 +252,7 @@ void EBPFStructType::emit(CodeBuilder *builder) { builder->emitIndent(); auto type = EBPFTypeFactory::instance->create(IR::Type_Boolean::get()); if (type != nullptr) { - type->declare(builder, "ebpf_valid", false); + type->declare(builder, "ebpf_valid"_cs, false); builder->endOfStatement(true); } } @@ -322,7 +323,8 @@ void EBPFEnumType::emit(EBPF::CodeBuilder *builder) { builder->blockStart(); for (auto m : et->members) { builder->append(m->name); - builder->appendLine(","); + builder->append(","); + builder->newline(); } builder->blockEnd(true); } @@ -348,7 +350,8 @@ void EBPFErrorType::emit(EBPF::CodeBuilder *builder) { builder->blockStart(); for (auto m : et->members) { builder->append(m->name); - builder->appendLine(","); + builder->append(","); + builder->newline(); } builder->blockEnd(true); } diff --git a/backends/ebpf/midend.cpp b/backends/ebpf/midend.cpp index b5b56f2dcb..cef8eee8a8 100644 --- a/backends/ebpf/midend.cpp +++ b/backends/ebpf/midend.cpp @@ -53,6 +53,8 @@ limitations under the License. namespace EBPF { +using namespace P4::literals; + class EnumOn32Bits : public P4::ChooseEnumRepresentation { bool convert(const IR::Type_Enum *type) const override { if (type->srcInfo.isValid()) { @@ -111,14 +113,14 @@ const IR::ToplevelBlock *MidEnd::run(EbpfOptions &options, const IR::P4Program * if (options.arch == "psa") { midEnd.addPasses({new P4::ValidateTableProperties( - {"size", "psa_direct_counter", "psa_direct_meter", "psa_empty_group_action", - "psa_implementation"})}); + {"size"_cs, "psa_direct_counter"_cs, "psa_direct_meter"_cs, + "psa_empty_group_action"_cs, "psa_implementation"_cs})}); } else { - midEnd.addPasses({new P4::ValidateTableProperties({"size", "implementation"})}); + midEnd.addPasses({new P4::ValidateTableProperties({"size"_cs, "implementation"_cs})}); } if (options.listMidendPasses) { - midEnd.listPasses(*outStream, "\n"); + midEnd.listPasses(*outStream, cstring::newline); *outStream << std::endl; } if (options.excludeMidendPasses) { diff --git a/backends/ebpf/p4c-ebpf.cpp b/backends/ebpf/p4c-ebpf.cpp index 83ce91b5e8..1e56271fbe 100644 --- a/backends/ebpf/p4c-ebpf.cpp +++ b/backends/ebpf/p4c-ebpf.cpp @@ -94,7 +94,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoEbpfContext(new EbpfContext); auto &options = EbpfContext::get().options(); - options.compilerVersion = P4C_EBPF_VERSION_STRING; + options.compilerVersion = cstring(P4C_EBPF_VERSION_STRING); if (options.process(argc, argv) != nullptr) { if (options.loadIRFromJson == false) options.setInputFile(); diff --git a/backends/ebpf/psa/ebpfPipeline.cpp b/backends/ebpf/psa/ebpfPipeline.cpp index ce12f25553..f66546875b 100644 --- a/backends/ebpf/psa/ebpfPipeline.cpp +++ b/backends/ebpf/psa/ebpfPipeline.cpp @@ -54,14 +54,14 @@ void EBPFPipeline::emitLocalVariables(CodeBuilder *builder) { builder->newline(); builder->emitIndent(); builder->appendFormat("void* %s = %s;", packetStartVar.c_str(), - builder->target->dataOffset(model.CPacketName.str()).c_str()); + builder->target->dataOffset(model.CPacketName.toString()).c_str()); builder->newline(); builder->emitIndent(); builder->appendFormat("u8* %s = %s;", headerStartVar.c_str(), packetStartVar.c_str()); builder->newline(); builder->emitIndent(); builder->appendFormat("void* %s = %s;", packetEndVar.c_str(), - builder->target->dataEnd(model.CPacketName.str()).c_str()); + builder->target->dataEnd(model.CPacketName.toString()).c_str()); builder->newline(); builder->emitIndent(); builder->appendFormat("u32 %s = 0;", zeroKey.c_str()); @@ -123,7 +123,7 @@ void EBPFPipeline::emitHeaderInstances(CodeBuilder *builder) { void EBPFPipeline::emitCPUMAPLookup(CodeBuilder *builder) { builder->emitIndent(); - builder->target->emitTableLookup(builder, "hdr_md_cpumap", zeroKey.c_str(), "hdrMd"); + builder->target->emitTableLookup(builder, "hdr_md_cpumap"_cs, zeroKey, "hdrMd"_cs); builder->endOfStatement(true); } @@ -391,7 +391,7 @@ void EBPFEgressPipeline::emitPSAControlOutputMetadata(CodeBuilder *builder) { void EBPFEgressPipeline::emitCPUMAPLookup(CodeBuilder *builder) { builder->emitIndent(); - builder->target->emitTableLookup(builder, "hdr_md_cpumap", oneKey.c_str(), "hdrMd"); + builder->target->emitTableLookup(builder, "hdr_md_cpumap"_cs, oneKey, "hdrMd"_cs); builder->endOfStatement(true); } @@ -401,7 +401,7 @@ void EBPFEgressPipeline::emit(CodeBuilder *builder) { builder->newline(); progTarget->emitCodeSection(builder, sectionName); builder->emitIndent(); - progTarget->emitMain(builder, functionName, model.CPacketName.str()); + progTarget->emitMain(builder, functionName, model.CPacketName.toString()); builder->spc(); builder->blockStart(); @@ -773,7 +773,7 @@ void TCTrafficManagerForXDP::emit(CodeBuilder *builder) { cstring msgStr; progTarget->emitCodeSection(builder, sectionName); builder->emitIndent(); - progTarget->emitMain(builder, functionName, model.CPacketName.str()); + progTarget->emitMain(builder, functionName, model.CPacketName.toString()); builder->spc(); builder->blockStart(); emitGlobalMetadataInitializer(builder); @@ -855,8 +855,8 @@ void TCTrafficManagerForXDP::emitReadXDP2TCMetadataFromHead(CodeBuilder *builder void TCTrafficManagerForXDP::emitReadXDP2TCMetadataFromCPUMAP(CodeBuilder *builder) { builder->emitIndent(); - builder->target->emitTableLookup(builder, "xdp2tc_shared_map", this->zeroKey.c_str(), - "struct xdp2tc_metadata *md"); + builder->target->emitTableLookup(builder, "xdp2tc_shared_map"_cs, this->zeroKey, + "struct xdp2tc_metadata *md"_cs); builder->endOfStatement(true); builder->emitIndent(); builder->append("if (!md) "); diff --git a/backends/ebpf/psa/ebpfPipeline.h b/backends/ebpf/psa/ebpfPipeline.h index 85b38de234..31d23629bf 100644 --- a/backends/ebpf/psa/ebpfPipeline.h +++ b/backends/ebpf/psa/ebpfPipeline.h @@ -61,21 +61,21 @@ class EBPFPipeline : public EBPFProgram { control(nullptr), deparser(nullptr) { sectionName = "classifier/" + name; - functionName = name.replace("-", "_") + "_func"; - errorEnum = "ParserError_t"; - packetStartVar = cstring("pkt"); - headerStartVar = cstring("hdr_start"); - contextVar = cstring("skb"); - lengthVar = cstring("pkt_len"); - endLabel = cstring("deparser"); - timestampVar = cstring("tstamp"); - ifindexVar = cstring("skb->ifindex"); - compilerGlobalMetadata = cstring("compiler_meta__"); - packetPathVar = compilerGlobalMetadata + cstring("->packet_path"); - pktInstanceVar = compilerGlobalMetadata + cstring("->instance"); - priorityVar = cstring("skb->priority"); - oneKey = EBPFModel::reserved("one"); - inputPortVar = cstring("ebpf_input_port"); + functionName = name.replace('-', '_') + "_func"; + errorEnum = "ParserError_t"_cs; + packetStartVar = "pkt"_cs; + headerStartVar = "hdr_start"_cs; + contextVar = "skb"_cs; + lengthVar = "pkt_len"_cs; + endLabel = "deparser"_cs; + timestampVar = "tstamp"_cs; + ifindexVar = "skb->ifindex"_cs; + compilerGlobalMetadata = "compiler_meta__"_cs; + packetPathVar = compilerGlobalMetadata + "->packet_path"_cs; + pktInstanceVar = compilerGlobalMetadata + "->instance"_cs; + priorityVar = "skb->priority"_cs; + oneKey = EBPFModel::reserved("one"_cs); + inputPortVar = "ebpf_input_port"_cs; progTarget = new KernelSamplesTarget(options.emitTraceMessages); } @@ -85,19 +85,19 @@ class EBPFPipeline : public EBPFProgram { virtual cstring dropReturnCode() { if (sectionName.startsWith("xdp")) { - return "XDP_DROP"; + return "XDP_DROP"_cs; } // TC is the default hookpoint - return "TC_ACT_SHOT"; + return "TC_ACT_SHOT"_cs; } virtual cstring forwardReturnCode() { if (sectionName.startsWith("xdp")) { - return "XDP_PASS"; + return "XDP_PASS"_cs; } // TC is the default hookpoint - return "TC_ACT_OK"; + return "TC_ACT_OK"_cs; } virtual void emit(CodeBuilder *builder) = 0; @@ -231,8 +231,8 @@ class XDPIngressPipeline : public EBPFIngressPipeline { P4::TypeMap *typeMap) : EBPFIngressPipeline(name, options, refMap, typeMap) { sectionName = "xdp_ingress/" + name; - ifindexVar = cstring("skb->ingress_ifindex"); - packetPathVar = cstring(compilerGlobalMetadata + "->packet_path"); + ifindexVar = "skb->ingress_ifindex"_cs; + packetPathVar = compilerGlobalMetadata + "->packet_path"_cs; progTarget = new XdpTarget(options.emitTraceMessages); } @@ -248,11 +248,11 @@ class XDPEgressPipeline : public EBPFEgressPipeline { P4::TypeMap *typeMap) : EBPFEgressPipeline(name, options, refMap, typeMap) { sectionName = "xdp_devmap/" + name; - ifindexVar = cstring("skb->egress_ifindex"); + ifindexVar = "skb->egress_ifindex"_cs; // we do not support packet path, instance & priority in the XDP egress. - packetPathVar = cstring("0"); - pktInstanceVar = cstring("0"); - priorityVar = cstring("0"); + packetPathVar = "0"_cs; + pktInstanceVar = "0"_cs; + priorityVar = "0"_cs; progTarget = new XdpTarget(options.emitTraceMessages); } diff --git a/backends/ebpf/psa/ebpfPsaDeparser.cpp b/backends/ebpf/psa/ebpfPsaDeparser.cpp index 4f41f9a6db..4c6821e667 100644 --- a/backends/ebpf/psa/ebpfPsaDeparser.cpp +++ b/backends/ebpf/psa/ebpfPsaDeparser.cpp @@ -200,8 +200,8 @@ void XDPIngressDeparserPSA::emitPreDeparser(CodeBuilder *builder) { // resubmitted or multicasted because this check is not at the end of deparser. cstring conditionSendToTC = "if (%s->clone || %s->multicast_group != 0 ||" - " (!%s->drop && %s->egress_port == 0 && !%s->resubmit && %s->multicast_group == 0)) "; - conditionSendToTC = conditionSendToTC.replace("%s", istd->name.name); + " (!%s->drop && %s->egress_port == 0 && !%s->resubmit && %s->multicast_group == 0)) "_cs; + conditionSendToTC = conditionSendToTC.replace("%s"_cs, istd->name); builder->append(conditionSendToTC); builder->blockStart(); builder->emitIndent(); @@ -253,8 +253,8 @@ void XDPIngressDeparserPSA::emitPreDeparser(CodeBuilder *builder) { "&xdp2tc_md, sizeof(struct xdp2tc_metadata));"); } else if (program->options.xdp2tcMode == XDP2TC_CPUMAP) { builder->emitIndent(); - builder->target->emitTableUpdate(builder, "xdp2tc_shared_map", - this->program->zeroKey.c_str(), "xdp2tc_md"); + builder->target->emitTableUpdate(builder, "xdp2tc_shared_map"_cs, this->program->zeroKey, + "xdp2tc_md"_cs); builder->newline(); } builder->target->emitTraceMessage(builder, "Sending packet up to TC for cloning or to kernel"); diff --git a/backends/ebpf/psa/ebpfPsaGen.cpp b/backends/ebpf/psa/ebpfPsaGen.cpp index 2d9b0fe2c4..cccba821cf 100644 --- a/backends/ebpf/psa/ebpfPsaGen.cpp +++ b/backends/ebpf/psa/ebpfPsaGen.cpp @@ -140,13 +140,13 @@ void PSAEbpfGenerator::emitGlobalHeadersMetadata(CodeBuilder *builder) const { builder->blockStart(); builder->emitIndent(); - ingress->parser->headerType->declare(builder, "cpumap_hdr", false); + ingress->parser->headerType->declare(builder, "cpumap_hdr"_cs, false); builder->endOfStatement(true); builder->emitIndent(); auto user_md_type = ingress->typeMap->getType(ingress->control->user_metadata); BUG_CHECK(user_md_type != nullptr, "cannot declare user metadata"); auto userMetadataType = EBPFTypeFactory::instance->create(user_md_type); - userMetadataType->declare(builder, "cpumap_usermeta", false); + userMetadataType->declare(builder, "cpumap_usermeta"_cs, false); builder->endOfStatement(true); // Additional field to avoid compiler errors when both headers and user_metadata are empty. @@ -160,12 +160,12 @@ void PSAEbpfGenerator::emitGlobalHeadersMetadata(CodeBuilder *builder) const { } void PSAEbpfGenerator::emitPacketReplicationTables(CodeBuilder *builder) const { - builder->target->emitMapInMapDecl(builder, "clone_session_tbl_inner", TableHash, "elem_t", - "struct element", MaxClones, "clone_session_tbl", TableArray, - "__u32", MaxCloneSessions); - builder->target->emitMapInMapDecl(builder, "multicast_grp_tbl_inner", TableHash, "elem_t", - "struct element", MaxClones, "multicast_grp_tbl", TableArray, - "__u32", MaxCloneSessions); + builder->target->emitMapInMapDecl(builder, "clone_session_tbl_inner"_cs, TableHash, "elem_t"_cs, + "struct element"_cs, MaxClones, "clone_session_tbl"_cs, + TableArray, "__u32"_cs, MaxCloneSessions); + builder->target->emitMapInMapDecl(builder, "multicast_grp_tbl_inner"_cs, TableHash, "elem_t"_cs, + "struct element"_cs, MaxClones, "multicast_grp_tbl"_cs, + TableArray, "__u32"_cs, MaxCloneSessions); } void PSAEbpfGenerator::emitPipelineInstances(CodeBuilder *builder) const { @@ -176,8 +176,8 @@ void PSAEbpfGenerator::emitPipelineInstances(CodeBuilder *builder) const { egress->parser->emitValueSetInstances(builder); egress->control->emitTableInstances(builder); - builder->target->emitTableDecl(builder, "hdr_md_cpumap", TablePerCPUArray, "u32", - "struct hdr_md", 2); + builder->target->emitTableDecl(builder, "hdr_md_cpumap"_cs, TablePerCPUArray, "u32"_cs, + "struct hdr_md"_cs, 2); } void PSAEbpfGenerator::emitInitializer(CodeBuilder *builder) const { @@ -228,13 +228,13 @@ void PSAEbpfGenerator::emitHelperFunctions(CodeBuilder *builder) const { " next_id = elem->next_id;\n" " }\n" " return 0;\n" - "}"; + "}"_cs; if (options.emitTraceMessages) { forEachFunc = forEachFunc.replace( - "%trace_msg_no_elements%", - " bpf_trace_message(\"do_for_each: No elements found in list\\n\");\n"); + "%trace_msg_no_elements%"_cs, + " bpf_trace_message(\"do_for_each: No elements found in list\\n\");\n"_cs); } else { - forEachFunc = forEachFunc.replace("%trace_msg_no_elements%", ""); + forEachFunc = forEachFunc.replace("%trace_msg_no_elements%"_cs, ""_cs); } builder->appendLine(forEachFunc); builder->newline(); @@ -247,14 +247,14 @@ void PSAEbpfGenerator::emitHelperFunctions(CodeBuilder *builder) const { " struct clone_session_entry *entry = (struct clone_session_entry *) data;\n" "%trace_msg_redirect%" " bpf_clone_redirect(skb, entry->egress_port, 0);\n" - "}"; + "}"_cs; if (options.emitTraceMessages) { cloneFunction = cloneFunction.replace( cstring("%trace_msg_redirect%"), - " bpf_trace_message(\"do_clone: cloning pkt, egress_port=%d, cos=%d\\n\", " - "entry->egress_port, entry->class_of_service);\n"); + " bpf_trace_message(\"do_clone: cloning pkt, egress_port=%d, cos=%d\\n\", "_cs + "entry->egress_port, entry->class_of_service);\n"_cs); } else { - cloneFunction = cloneFunction.replace(cstring("%trace_msg_redirect%"), ""); + cloneFunction = cloneFunction.replace("%trace_msg_redirect%"_cs, ""_cs); } builder->appendLine(cloneFunction); builder->newline(); @@ -281,27 +281,27 @@ void PSAEbpfGenerator::emitHelperFunctions(CodeBuilder *builder) const { " }\n" "%trace_msg_cloning_done%" " return 0;\n" - " }"; + " }"_cs; if (options.emitTraceMessages) { pktClonesFunc = pktClonesFunc.replace( - cstring("%trace_msg_clone_requested%"), + "%trace_msg_clone_requested%"_cs, " bpf_trace_message(\"Clone#%d: pkt clone requested, session=%d\\n\", " - "caller_id, session_id);\n"); + "caller_id, session_id);\n"_cs); pktClonesFunc = pktClonesFunc.replace( - cstring("%trace_msg_clone_failed%"), - " bpf_trace_message(\"Clone#%d: failed to clone packet\", caller_id);\n"); + "%trace_msg_clone_failed%"_cs, + " bpf_trace_message(\"Clone#%d: failed to clone packet\", caller_id);\n"_cs); pktClonesFunc = - pktClonesFunc.replace(cstring("%trace_msg_no_session%"), + pktClonesFunc.replace("%trace_msg_no_session%"_cs, " bpf_trace_message(\"Clone#%d: session_id not found, " - "no clones created\\n\", caller_id);\n"); + "no clones created\\n\", caller_id);\n"_cs); pktClonesFunc = pktClonesFunc.replace( - cstring("%trace_msg_cloning_done%"), - " bpf_trace_message(\"Clone#%d: packet cloning finished\\n\", caller_id);\n"); + "%trace_msg_cloning_done%"_cs, + " bpf_trace_message(\"Clone#%d: packet cloning finished\\n\", caller_id);\n"_cs); } else { - pktClonesFunc = pktClonesFunc.replace(cstring("%trace_msg_clone_requested%"), ""); - pktClonesFunc = pktClonesFunc.replace(cstring("%trace_msg_clone_failed%"), ""); - pktClonesFunc = pktClonesFunc.replace(cstring("%trace_msg_no_session%"), ""); - pktClonesFunc = pktClonesFunc.replace(cstring("%trace_msg_cloning_done%"), ""); + pktClonesFunc = pktClonesFunc.replace("%trace_msg_clone_requested%"_cs, cstring::empty); + pktClonesFunc = pktClonesFunc.replace("%trace_msg_clone_failed%"_cs, cstring::empty); + pktClonesFunc = pktClonesFunc.replace("%trace_msg_no_session%"_cs, cstring::empty); + pktClonesFunc = pktClonesFunc.replace("%trace_msg_cloning_done%"_cs, cstring::empty); } builder->appendLine(pktClonesFunc); @@ -330,14 +330,14 @@ void PSAEbpfGenerator::emitCRC32LookupTableTypes(CodeBuilder *builder) const { } void PSAEbpfGenerator::emitCRC32LookupTableInstance(CodeBuilder *builder) const { - builder->target->emitTableDecl(builder, cstring("crc_lookup_tbl"), TableArray, "u32", + builder->target->emitTableDecl(builder, cstring("crc_lookup_tbl"), TableArray, "u32"_cs, cstring("struct lookup_tbl_val"), 1); } void PSAEbpfGenerator::emitCRC32LookupTableInitializer(CodeBuilder *builder) const { - cstring keyName = "lookup_tbl_key"; - cstring valueName = "lookup_tbl_value"; - cstring instanceName = "crc_lookup_tbl"; + cstring keyName = "lookup_tbl_key"_cs; + cstring valueName = "lookup_tbl_value"_cs; + cstring instanceName = "crc_lookup_tbl"_cs; builder->emitIndent(); builder->appendFormat("u32 %s = 0", keyName.c_str()); @@ -476,7 +476,8 @@ void PSAArchTC::emitInstances(CodeBuilder *builder) const { builder->appendLine("REGISTER_START()"); if (options.xdp2tcMode == XDP2TC_CPUMAP) { - builder->target->emitTableDecl(builder, "xdp2tc_cpumap", TablePerCPUArray, "u32", "u16", 1); + builder->target->emitTableDecl(builder, "xdp2tc_cpumap"_cs, TablePerCPUArray, "u32"_cs, + "u16"_cs, 1); } emitPacketReplicationTables(builder); @@ -547,11 +548,11 @@ void PSAArchXDP::emitInstances(CodeBuilder *builder) const { tcEgressForXDP->control->tables.insert(egress->control->tables.begin(), egress->control->tables.end()); - builder->target->emitTableDecl(builder, "xdp2tc_shared_map", TablePerCPUArray, "u32", - "struct xdp2tc_metadata", 1); + builder->target->emitTableDecl(builder, "xdp2tc_shared_map"_cs, TablePerCPUArray, "u32"_cs, + "struct xdp2tc_metadata"_cs, 1); - builder->target->emitTableDecl(builder, "tx_port", TableDevmap, "u32", "struct bpf_devmap_val", - egressDevmapSize); + builder->target->emitTableDecl(builder, "tx_port"_cs, TableDevmap, "u32"_cs, + "struct bpf_devmap_val"_cs, egressDevmapSize); emitCRC32LookupTableInstance(builder); @@ -617,30 +618,30 @@ const PSAEbpfGenerator *ConvertToEbpfPSA::build(const IR::ToplevelBlock *tlb) { /* * INGRESS */ - auto ingress = tlb->getMain()->getParameterValue("ingress")->to(); - auto ingressParser = ingress->getParameterValue("ip"); + auto ingress = tlb->getMain()->getParameterValue("ingress"_cs)->to(); + auto ingressParser = ingress->getParameterValue("ip"_cs); BUG_CHECK(ingressParser != nullptr, "No ingress parser block found"); - auto ingressControl = ingress->getParameterValue("ig"); + auto ingressControl = ingress->getParameterValue("ig"_cs); BUG_CHECK(ingressControl != nullptr, "No ingress control block found"); - auto ingressDeparser = ingress->getParameterValue("id"); + auto ingressDeparser = ingress->getParameterValue("id"_cs); BUG_CHECK(ingressDeparser != nullptr, "No ingress deparser block found"); /* * EGRESS */ - auto egress = tlb->getMain()->getParameterValue("egress")->to(); - auto egressParser = egress->getParameterValue("ep"); + auto egress = tlb->getMain()->getParameterValue("egress"_cs)->to(); + auto egressParser = egress->getParameterValue("ep"_cs); BUG_CHECK(egressParser != nullptr, "No egress parser block found"); - auto egressControl = egress->getParameterValue("eg"); + auto egressControl = egress->getParameterValue("eg"_cs); BUG_CHECK(egressControl != nullptr, "No egress control block found"); - auto egressDeparser = egress->getParameterValue("ed"); + auto egressDeparser = egress->getParameterValue("ed"_cs); BUG_CHECK(egressDeparser != nullptr, "No egress deparser block found"); if (!options.generateToXDP) { auto xdp = new XDPHelpProgram(options); auto ingress_pipeline_converter = new ConvertToEbpfPipeline( - "tc-ingress", TC_INGRESS, options, ingressParser->to(), + "tc-ingress"_cs, TC_INGRESS, options, ingressParser->to(), ingressControl->to(), ingressDeparser->to(), refmap, typemap); ingress->apply(*ingress_pipeline_converter); @@ -648,7 +649,7 @@ const PSAEbpfGenerator *ConvertToEbpfPSA::build(const IR::ToplevelBlock *tlb) { auto tcIngress = ingress_pipeline_converter->getEbpfPipeline(); auto egress_pipeline_converter = new ConvertToEbpfPipeline( - "tc-egress", TC_EGRESS, options, egressParser->to(), + "tc-egress"_cs, TC_EGRESS, options, egressParser->to(), egressControl->to(), egressDeparser->to(), refmap, typemap); egress->apply(*egress_pipeline_converter); @@ -658,7 +659,7 @@ const PSAEbpfGenerator *ConvertToEbpfPSA::build(const IR::ToplevelBlock *tlb) { return new PSAArchTC(options, ebpfTypes, xdp, tcIngress, tcEgress); } else { auto ingress_pipeline_converter = new ConvertToEbpfPipeline( - "xdp-ingress", XDP_INGRESS, options, ingressParser->to(), + "xdp-ingress"_cs, XDP_INGRESS, options, ingressParser->to(), ingressControl->to(), ingressDeparser->to(), refmap, typemap); ingress->apply(*ingress_pipeline_converter); @@ -667,7 +668,7 @@ const PSAEbpfGenerator *ConvertToEbpfPSA::build(const IR::ToplevelBlock *tlb) { BUG_CHECK(xdpIngress != nullptr, "Cannot create xdpIngress block."); auto egress_pipeline_converter = new ConvertToEbpfPipeline( - "xdp-egress", XDP_EGRESS, options, egressParser->to(), + "xdp-egress"_cs, XDP_EGRESS, options, egressParser->to(), egressControl->to(), egressDeparser->to(), refmap, typemap); egress->apply(*egress_pipeline_converter); @@ -676,7 +677,7 @@ const PSAEbpfGenerator *ConvertToEbpfPSA::build(const IR::ToplevelBlock *tlb) { BUG_CHECK(xdpEgress != nullptr, "Cannot create xdpEgress block."); auto tc_trafficmanager_converter = new ConvertToEbpfPipeline( - "tc-ingress", TC_TRAFFIC_MANAGER, options, ingressParser->to(), + "tc-ingress"_cs, TC_TRAFFIC_MANAGER, options, ingressParser->to(), ingressControl->to(), ingressDeparser->to(), refmap, typemap); ingress->apply(*tc_trafficmanager_converter); @@ -684,7 +685,7 @@ const PSAEbpfGenerator *ConvertToEbpfPSA::build(const IR::ToplevelBlock *tlb) { BUG_CHECK(tcTrafficManager != nullptr, "Cannot create tcTrafficManager block."); auto tc_egress_pipeline_converter = new ConvertToEbpfPipeline( - "tc-egress", TC_EGRESS, options, egressParser->to(), + "tc-egress"_cs, TC_EGRESS, options, egressParser->to(), egressControl->to(), egressDeparser->to(), refmap, typemap); egress->apply(*tc_egress_pipeline_converter); diff --git a/backends/ebpf/psa/ebpfPsaTable.cpp b/backends/ebpf/psa/ebpfPsaTable.cpp index e77101579f..2a53fa8824 100644 --- a/backends/ebpf/psa/ebpfPsaTable.cpp +++ b/backends/ebpf/psa/ebpfPsaTable.cpp @@ -70,7 +70,7 @@ class EBPFTablePSADirectCounterPropertyVisitor : public EBPFTablePsaPropertyVisi } void visitTableProperty() { - EBPFTablePsaPropertyVisitor::visitTableProperty("psa_direct_counter"); + EBPFTablePsaPropertyVisitor::visitTableProperty("psa_direct_counter"_cs); } }; @@ -96,7 +96,7 @@ class EBPFTablePSADirectMeterPropertyVisitor : public EBPFTablePsaPropertyVisito } void visitTableProperty() { - EBPFTablePsaPropertyVisitor::visitTableProperty("psa_direct_meter"); + EBPFTablePsaPropertyVisitor::visitTableProperty("psa_direct_meter"_cs); } }; @@ -133,7 +133,7 @@ class EBPFTablePSAImplementationPropertyVisitor : public EBPFTablePsaPropertyVis } void visitTableProperty() { - EBPFTablePsaPropertyVisitor::visitTableProperty("psa_implementation"); + EBPFTablePsaPropertyVisitor::visitTableProperty("psa_implementation"_cs); } }; @@ -418,7 +418,7 @@ cstring ActionTranslationVisitorPSA::getParamName(const IR::PathExpression *expr EBPFTablePSA::EBPFTablePSA(const EBPFProgram *program, const IR::TableBlock *table, CodeGenInspector *codeGen) : EBPFTable(program, table, codeGen), implementation(nullptr) { - auto sizeProperty = table->container->properties->getProperty("size"); + auto sizeProperty = table->container->properties->getProperty("size"_cs); if (keyGenerator == nullptr && sizeProperty != nullptr) { ::warning(ErrorType::WARN_IGNORE_PROPERTY, "%1%: property ignored because table does not have a key", sizeProperty); @@ -482,7 +482,7 @@ void EBPFTablePSA::initImplementation() { "%1%: implementation not found, ActionSelector is required", selectorKey->matchType); } - auto emptyGroupAction = table->container->properties->getProperty("psa_empty_group_action"); + auto emptyGroupAction = table->container->properties->getProperty("psa_empty_group_action"_cs); if (!hasActionSelector && emptyGroupAction != nullptr) { ::warning(ErrorType::WARN_UNUSED, "%1%: unused property (ActionSelector not provided)", emptyGroupAction); @@ -601,7 +601,7 @@ void EBPFTablePSA::emitConstEntriesInitializer(CodeBuilder *builder) { auto ret = program->refMap->newName("ret"); builder->emitIndent(); builder->appendFormat("int %s = ", ret.c_str()); - builder->target->emitTableUpdate(builder, instanceName, keyName.c_str(), valueName.c_str()); + builder->target->emitTableUpdate(builder, instanceName, keyName, valueName); builder->newline(); emitMapUpdateTraceMsg(builder, instanceName, ret); @@ -619,8 +619,7 @@ void EBPFTablePSA::emitDefaultActionInitializer(CodeBuilder *builder) { auto ret = program->refMap->newName("ret"); builder->emitIndent(); builder->appendFormat("int %s = ", ret.c_str()); - builder->target->emitTableUpdate(builder, defaultActionMapName, program->zeroKey.c_str(), - value.c_str()); + builder->target->emitTableUpdate(builder, defaultActionMapName, program->zeroKey, value); builder->newline(); emitMapUpdateTraceMsg(builder, defaultActionMapName, ret); @@ -931,25 +930,26 @@ cstring EBPFTablePSA::addPrefixFunc(bool trace) { "%trace_msg_tuple_not_found%" " return;\n" " }\n" - "}"; + "}"_cs; if (trace) { addPrefixFunc = addPrefixFunc.replace( - "%trace_msg_prefix_map_fail%", - " bpf_trace_message(\"Prefixes map update failed\\n\");\n"); + "%trace_msg_prefix_map_fail%"_cs, + " bpf_trace_message(\"Prefixes map update failed\\n\");\n"_cs); addPrefixFunc = addPrefixFunc.replace( - "%trace_msg_tuple_update_fail%", - " bpf_trace_message(\"Tuple map update failed\\n\");\n"); + "%trace_msg_tuple_update_fail%"_cs, + " bpf_trace_message(\"Tuple map update failed\\n\");\n"_cs); addPrefixFunc = addPrefixFunc.replace( - "%trace_msg_tuple_update_success%", - " bpf_trace_message(\"Tuple map update succeed\\n\");\n"); - addPrefixFunc = addPrefixFunc.replace( - "%trace_msg_tuple_not_found%", " bpf_trace_message(\"Tuple not found\\n\");\n"); + "%trace_msg_tuple_update_success%"_cs, + " bpf_trace_message(\"Tuple map update succeed\\n\");\n"_cs); + addPrefixFunc = + addPrefixFunc.replace("%trace_msg_tuple_not_found%"_cs, + " bpf_trace_message(\"Tuple not found\\n\");\n"_cs); } else { - addPrefixFunc = addPrefixFunc.replace("%trace_msg_prefix_map_fail%", ""); - addPrefixFunc = addPrefixFunc.replace("%trace_msg_tuple_update_fail%", ""); - addPrefixFunc = addPrefixFunc.replace("%trace_msg_tuple_update_success%", ""); - addPrefixFunc = addPrefixFunc.replace("%trace_msg_tuple_not_found%", ""); + addPrefixFunc = addPrefixFunc.replace("%trace_msg_prefix_map_fail%"_cs, ""_cs); + addPrefixFunc = addPrefixFunc.replace("%trace_msg_tuple_update_fail%"_cs, ""_cs); + addPrefixFunc = addPrefixFunc.replace("%trace_msg_tuple_update_success%"_cs, ""_cs); + addPrefixFunc = addPrefixFunc.replace("%trace_msg_tuple_not_found%"_cs, ""_cs); } return addPrefixFunc; @@ -1012,7 +1012,7 @@ void EBPFTablePSA::emitCacheInstance(CodeBuilder *builder) { } void EBPFTablePSA::emitCacheLookup(CodeBuilder *builder, cstring key, cstring value) { - cstring cacheVal = "cached_value"; + cstring cacheVal = "cached_value"_cs; builder->appendFormat("struct %s* %s = NULL", cacheValueTypeName.c_str(), cacheVal.c_str()); builder->endOfStatement(true); @@ -1048,7 +1048,7 @@ void EBPFTablePSA::emitCacheLookup(CodeBuilder *builder, cstring key, cstring va } void EBPFTablePSA::emitCacheUpdate(CodeBuilder *builder, cstring key, cstring value) { - cstring cacheUpdateVarName = "cache_update"; + cstring cacheUpdateVarName = "cache_update"_cs; builder->emitIndent(); builder->appendFormat("if (%s != NULL) ", value.c_str()); diff --git a/backends/ebpf/psa/ebpfPsaTable.h b/backends/ebpf/psa/ebpfPsaTable.h index 5161e36192..2f3d9e32bd 100644 --- a/backends/ebpf/psa/ebpfPsaTable.h +++ b/backends/ebpf/psa/ebpfPsaTable.h @@ -36,9 +36,9 @@ class EBPFTablePSA : public EBPFTable { typedef std::vector EntriesGroupedByMask_t; EntriesGroupedByMask_t getConstEntriesGroupedByMask(); bool hasConstEntries(); - const cstring addPrefixFunctionName = "add_prefix_and_entries"; - const cstring tuplesMapName = instanceName + "_tuples_map"; - const cstring prefixesMapName = instanceName + "_prefixes"; + const cstring addPrefixFunctionName = "add_prefix_and_entries"_cs; + const cstring tuplesMapName = instanceName + "_tuples_map"_cs; + const cstring prefixesMapName = instanceName + "_prefixes"_cs; protected: ActionTranslationVisitor *createActionTranslationVisitor( diff --git a/backends/ebpf/psa/externs/ebpfPsaCounter.cpp b/backends/ebpf/psa/externs/ebpfPsaCounter.cpp index d461499004..145c9459d1 100644 --- a/backends/ebpf/psa/externs/ebpfPsaCounter.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaCounter.cpp @@ -100,7 +100,7 @@ EBPFCounterPSA::EBPFCounterPSA(const EBPFProgram *program, const IR::Declaration if (isHash) { indexWidthType = EBPFTypeFactory::instance->create(istype); } else { - keyTypeName = "u32"; + keyTypeName = "u32"_cs; } auto declaredSize = di->arguments->at(0)->expression->to(); @@ -204,7 +204,7 @@ void EBPFCounterPSA::emitDirectMethodInvocation(CodeBuilder *builder, cstring varStr = Util::printf_format("%s", pipeline->lengthVar.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, varStr.c_str()); - emitCounterUpdate(builder, target, ""); + emitCounterUpdate(builder, target, ""_cs); msgStr = Util::printf_format("Counter: %s updated", instanceName.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str()); diff --git a/backends/ebpf/psa/externs/ebpfPsaDigest.cpp b/backends/ebpf/psa/externs/ebpfPsaDigest.cpp index aa14abc168..11f91cbc93 100644 --- a/backends/ebpf/psa/externs/ebpfPsaDigest.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaDigest.cpp @@ -126,7 +126,7 @@ void EBPFDigestPSA::emitInstance(CodeBuilder *builder) const { builder->appendFormat("REGISTER_TABLE_NO_KEY_TYPE(%s, BPF_MAP_TYPE_QUEUE, 0, ", instanceName); if (valueTypeName.isNullOrEmpty()) { - valueType->declare(builder, "", false); + valueType->declare(builder, cstring::empty, false); } else { builder->append(valueTypeName); } diff --git a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp index 5375a0dd74..653b6a4a8e 100644 --- a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp @@ -59,7 +59,7 @@ void CRCChecksumAlgorithm::emitUpdateMethod(CodeBuilder *builder, int crcWidth) // incremented. For data shorter than or equal 64 bits, bytes are processed in little endian // byte order - data pointer is decremented by outer loop in this case. // There is no need for lookup table. - cstring code = + const char *code = "static __always_inline\n" "void crc16_update(u16 * reg, const u8 * data, " "u16 data_size, const u16 poly) {\n" @@ -91,7 +91,7 @@ void CRCChecksumAlgorithm::emitUpdateMethod(CodeBuilder *builder, int crcWidth) // 4. Data size more than 8 bytes and not multiply of 8 bytes - calculated using slice-by-8 // and Standard Implementation both in big endian byte order. // Lookup table is necessary for both algorithms. - cstring code = + const char *code = "static __always_inline\n" "void crc32_update(u32 * reg, const u8 * data, u16 data_size, const u32 poly) {\n" " u32* current = (u32*) data;\n" @@ -333,7 +333,7 @@ void CRCChecksumAlgorithm::emitSetInternalState(CodeBuilder *builder, void CRC16ChecksumAlgorithm::emitGlobals(CodeBuilder *builder) { CRCChecksumAlgorithm::emitUpdateMethod(builder, 16); - cstring code = + const char *code = "static __always_inline " "u16 crc16_finalize(u16 reg) {\n" " return reg;\n" @@ -346,7 +346,7 @@ void CRC16ChecksumAlgorithm::emitGlobals(CodeBuilder *builder) { void CRC32ChecksumAlgorithm::emitGlobals(CodeBuilder *builder) { CRCChecksumAlgorithm::emitUpdateMethod(builder, 32); - cstring code = + const char *code = "static __always_inline " "u32 crc32_finalize(u32 reg) {\n" " return reg ^ 0xFFFFFFFF;\n" diff --git a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.h b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.h index ed37042fe3..c56f1c9557 100644 --- a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.h +++ b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.h @@ -110,12 +110,12 @@ class CRC16ChecksumAlgorithm : public CRCChecksumAlgorithm { public: CRC16ChecksumAlgorithm(const EBPFProgram *program, cstring name) : CRCChecksumAlgorithm(program, name, 16) { - initialValue = "0"; + initialValue = "0"_cs; // We use a 0x8005 polynomial. // 0xA001 comes from 0x8005 value bits reflection. - polynomial = "0xA001"; - updateMethod = "crc16_update"; - finalizeMethod = "crc16_finalize"; + polynomial = "0xA001"_cs; + updateMethod = "crc16_update"_cs; + finalizeMethod = "crc16_finalize"_cs; } static void emitGlobals(CodeBuilder *builder); @@ -132,12 +132,12 @@ class CRC32ChecksumAlgorithm : public CRCChecksumAlgorithm { public: CRC32ChecksumAlgorithm(const EBPFProgram *program, cstring name) : CRCChecksumAlgorithm(program, name, 32) { - initialValue = "0xffffffff"; + initialValue = "0xffffffff"_cs; // We use a 0x04C11DB7 polynomial. // 0xEDB88320 comes from 0x04C11DB7 value bits reflection. - polynomial = "0xEDB88320"; - updateMethod = "crc32_update"; - finalizeMethod = "crc32_finalize"; + polynomial = "0xEDB88320"_cs; + updateMethod = "crc32_update"_cs; + finalizeMethod = "crc32_finalize"_cs; } static void emitGlobals(CodeBuilder *builder); diff --git a/backends/ebpf/psa/externs/ebpfPsaMeter.cpp b/backends/ebpf/psa/externs/ebpfPsaMeter.cpp index d640e255a3..b96e001c96 100644 --- a/backends/ebpf/psa/externs/ebpfPsaMeter.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaMeter.cpp @@ -99,11 +99,11 @@ EBPFMeterPSA::MeterType EBPFMeterPSA::toType(const int typeCode) { IR::IndexedVector EBPFMeterPSA::getValueFields() { auto vec = IR::IndexedVector(); auto bits_64 = IR::Type_Bits::get(64, false); - const std::initializer_list fieldsNames = {"pir_period", "pir_unit_per_period", - "cir_period", "cir_unit_per_period", - "pbs", "cbs", - "pbs_left", "cbs_left", - "time_p", "time_c"}; + const std::vector fieldsNames = {"pir_period"_cs, "pir_unit_per_period"_cs, + "cir_period"_cs, "cir_unit_per_period"_cs, + "pbs"_cs, "cbs"_cs, + "pbs_left"_cs, "cbs_left"_cs, + "time_p"_cs, "time_c"_cs}; for (auto fieldName : fieldsNames) { vec.push_back(new IR::StructField(IR::ID(fieldName), bits_64)); } @@ -163,9 +163,9 @@ void EBPFMeterPSA::emitExecute(CodeBuilder *builder, const P4::ExternMethod *met cstring functionNameSuffix; if (method->expr->arguments->size() == 2) { - functionNameSuffix = "_color_aware"; + functionNameSuffix = "_color_aware"_cs; } else { - functionNameSuffix = ""; + functionNameSuffix = ""_cs; } if (type == BYTES) { @@ -207,9 +207,9 @@ void EBPFMeterPSA::emitDirectExecute(CodeBuilder *builder, const P4::ExternMetho cstring functionNameSuffix; if (method->expr->arguments->size() == 1) { - functionNameSuffix = "_color_aware"; + functionNameSuffix = "_color_aware"_cs; } else { - functionNameSuffix = ""; + functionNameSuffix = ""_cs; } cstring lockVar = valuePtr + "->" + spinlockField; @@ -409,36 +409,37 @@ cstring EBPFMeterPSA::meterExecuteFunc(bool trace, P4::ReferenceMap *refMap) { " return meter_execute_packets_value_color_aware(value, ((void *)value) + " "sizeof(%meter_struct%), " "time_ns, color);\n" - "}\n"; + "}\n"_cs; if (trace) { meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_green%"), " bpf_trace_message(\"" - "Meter: GREEN\\n\");\n"); + "Meter: GREEN\\n\");\n"_cs); meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_yellow%"), " bpf_trace_message(\"" - "Meter: YELLOW\\n\");\n"); + "Meter: YELLOW\\n\");\n"_cs); meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_red%"), " bpf_trace_message(\"" - "Meter: RED\\n\");\n"); + "Meter: RED\\n\");\n"_cs); meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_no_value%"), " bpf_trace_message(\"Meter: No meter value! " - "Returning default GREEN\\n\");\n"); + "Returning default GREEN\\n\");\n"_cs); meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_execute_bytes%"), - " bpf_trace_message(\"Meter: execute BYTES\\n\");\n"); + " bpf_trace_message(\"Meter: execute BYTES\\n\");\n"_cs); meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_execute_packets%"), - " bpf_trace_message(\"Meter: execute PACKETS\\n\");\n"); + " bpf_trace_message(\"Meter: execute PACKETS\\n\");\n"_cs); } else { - meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_green%"), ""); - meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_yellow%"), ""); - meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_red%"), ""); - meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_no_value%"), ""); - meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_execute_bytes%"), ""); + meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_green%"), ""_cs); + meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_yellow%"), ""_cs); + meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_red%"), ""_cs); + meterExecuteFunc = meterExecuteFunc.replace(cstring("%trace_msg_meter_no_value%"), ""_cs); meterExecuteFunc = - meterExecuteFunc.replace(cstring("%trace_msg_meter_execute_packets%"), ""); + meterExecuteFunc.replace(cstring("%trace_msg_meter_execute_bytes%"), ""_cs); + meterExecuteFunc = + meterExecuteFunc.replace(cstring("%trace_msg_meter_execute_packets%"), ""_cs); } meterExecuteFunc = meterExecuteFunc.replace(cstring("%meter_struct%"), diff --git a/backends/ebpf/psa/externs/ebpfPsaMeter.h b/backends/ebpf/psa/externs/ebpfPsaMeter.h index 9eca09c9ee..55973ad19c 100644 --- a/backends/ebpf/psa/externs/ebpfPsaMeter.h +++ b/backends/ebpf/psa/externs/ebpfPsaMeter.h @@ -33,8 +33,8 @@ class EBPFMeterPSA : public EBPFTableBase { ControlBodyTranslatorPSA *translator) const; protected: - const cstring indirectValueField = "value"; - const cstring spinlockField = "lock"; + const cstring indirectValueField = "value"_cs; + const cstring spinlockField = "lock"_cs; size_t size{}; EBPFType *keyType{}; diff --git a/backends/ebpf/psa/externs/ebpfPsaTableImplementation.cpp b/backends/ebpf/psa/externs/ebpfPsaTableImplementation.cpp index 0d265576a6..1383e54638 100644 --- a/backends/ebpf/psa/externs/ebpfPsaTableImplementation.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaTableImplementation.cpp @@ -159,8 +159,8 @@ void EBPFActionProfilePSA::emitInstance(CodeBuilder *builder) { // If user change action for given reference to NoAction, it will be hard to // distinguish it from non-existing entry using only key value. auto tableKind = TableHash; - builder->target->emitTableDecl(builder, instanceName, tableKind, "u32", - cstring("struct ") + valueTypeName, size); + builder->target->emitTableDecl(builder, instanceName, tableKind, "u32"_cs, + "struct "_cs + valueTypeName, size); } void EBPFActionProfilePSA::applyImplementation(CodeBuilder *builder, cstring tableValueName, @@ -304,16 +304,17 @@ void EBPFActionSelectorPSA::emitInstance(CodeBuilder *builder) { // group map (group ref -> {action refs}) // TODO: group size (inner size) is assumed to be 128. Make more logic for this. // One additional entry is for group size. - builder->target->emitMapInMapDecl(builder, groupsMapName + "_inner", TableArray, "u32", "u32", - 128 + 1, groupsMapName, TableHash, "u32", groupsMapSize); + builder->target->emitMapInMapDecl(builder, groupsMapName + "_inner", TableArray, "u32"_cs, + "u32"_cs, 128 + 1, groupsMapName, TableHash, "u32"_cs, + groupsMapSize); // default empty group action (0 -> action) builder->target->emitTableDecl(builder, emptyGroupActionMapName, TableArray, - program->arrayIndexType, cstring("struct ") + valueTypeName, 1); + program->arrayIndexType, "struct "_cs + valueTypeName, 1); // action map (ref -> action) - builder->target->emitTableDecl(builder, actionsMapName, TableHash, "u32", - cstring("struct ") + valueTypeName, size); + builder->target->emitTableDecl(builder, actionsMapName, TableHash, "u32"_cs, + "struct "_cs + valueTypeName, size); emitCacheInstance(builder); } @@ -339,8 +340,8 @@ void EBPFActionSelectorPSA::applyImplementation(CodeBuilder *builder, cstring ta cstring innerGroupName = program->refMap->newName("as_group_map"); groupStateVarName = program->refMap->newName("as_group_state"); // these can be hardcoded because they are declared inside of a block - cstring checksumValName = "as_checksum_val"; - cstring mapEntryName = "as_map_entry"; + cstring checksumValName = "as_checksum_val"_cs; + cstring mapEntryName = "as_map_entry"_cs; emitCacheVariables(builder); @@ -547,7 +548,7 @@ void EBPFActionSelectorPSA::registerTable(const EBPFTablePSA *instance) { if (table == nullptr) { selectors = getSelectorsFromTable(instance); emptyGroupAction = - instance->table->container->properties->getProperty("psa_empty_group_action"); + instance->table->container->properties->getProperty("psa_empty_group_action"_cs); groupsMapSize = instance->size; } else { verifyTableSelectorKeySet(instance); @@ -587,7 +588,7 @@ void EBPFActionSelectorPSA::verifyTableSelectorKeySet(const EBPFTablePSA *instan } void EBPFActionSelectorPSA::verifyTableEmptyGroupAction(const EBPFTablePSA *instance) { - auto iega = instance->table->container->properties->getProperty("psa_empty_group_action"); + auto iega = instance->table->container->properties->getProperty("psa_empty_group_action"_cs); if (emptyGroupAction == nullptr && iega == nullptr) return; // nothing to do here if (emptyGroupAction == nullptr && iega != nullptr) { @@ -607,7 +608,7 @@ void EBPFActionSelectorPSA::verifyTableEmptyGroupAction(const EBPFTablePSA *inst } bool same = true; - cstring additionalNote; + const char *additionalNote = ""; if (emptyGroupAction->isConstant != iega->isConstant) { same = false; diff --git a/backends/ebpf/psa/xdpHelpProgram.h b/backends/ebpf/psa/xdpHelpProgram.h index 760e2156a6..f8e44e9028 100644 --- a/backends/ebpf/psa/xdpHelpProgram.h +++ b/backends/ebpf/psa/xdpHelpProgram.h @@ -22,7 +22,7 @@ limitations under the License. namespace EBPF { class XDPHelpProgram : public EBPFProgram { - cstring XDPProgUsingMetaForXDP2TC = + const char *XDPProgUsingMetaForXDP2TC = " void *data_end = (void *)(long)skb->data_end;\n" " struct ethhdr *eth = (struct ethhdr *)(long)skb->data;\n" " if ((void *)((struct ethhdr *) eth + 1) > data_end) {\n" @@ -50,7 +50,7 @@ class XDPHelpProgram : public EBPFProgram { "\n" " return XDP_PASS;"; - cstring XDPProgUsingHeadForXDP2TC = + const char *XDPProgUsingHeadForXDP2TC = " void *data = (void *)(long)skb->data;\n" " void *data_end = (void *)(long)skb->data_end;\n" " struct ethhdr *eth = data;\n" @@ -80,7 +80,7 @@ class XDPHelpProgram : public EBPFProgram { "\n" " return XDP_PASS;"; - cstring XDPProgUsingCPUMAPForXDP2TC = + const char *XDPProgUsingCPUMAPForXDP2TC = " void *data = (void *)(long)skb->data;\n" " void *data_end = (void *)(long)skb->data_end;\n" " struct ethhdr *eth = data;\n" @@ -97,8 +97,8 @@ class XDPHelpProgram : public EBPFProgram { cstring sectionName; explicit XDPHelpProgram(const EbpfOptions &options) : EBPFProgram(options, nullptr, nullptr, nullptr, nullptr) { - sectionName = "xdp/xdp-ingress"; - functionName = "xdp_func"; + sectionName = "xdp/xdp-ingress"_cs; + functionName = "xdp_func"_cs; } void emit(CodeBuilder *builder) { diff --git a/backends/ebpf/target.cpp b/backends/ebpf/target.cpp index df8c974ea6..a00b35f38c 100644 --- a/backends/ebpf/target.cpp +++ b/backends/ebpf/target.cpp @@ -67,8 +67,8 @@ void KernelSamplesTarget::emitTableDecl(Util::SourceCodeBuilder *builder, cstrin TableKind tableKind, cstring keyType, cstring valueType, unsigned size) const { cstring kind, flags; - cstring registerTable = "REGISTER_TABLE(%s, %s, %s, %s, %d)"; - cstring registerTableWithFlags = "REGISTER_TABLE_FLAGS(%s, %s, %s, %s, %d, %s)"; + cstring registerTable = "REGISTER_TABLE(%s, %s, %s, %s, %d)"_cs; + cstring registerTableWithFlags = "REGISTER_TABLE_FLAGS(%s, %s, %s, %s, %d, %s)"_cs; kind = getBPFMapType(tableKind); @@ -77,18 +77,18 @@ void KernelSamplesTarget::emitTableDecl(Util::SourceCodeBuilder *builder, cstrin // as array map must have u32 key type. ::warning(ErrorType::WARN_INVALID, "Invalid key type (%1%) for table kind %2%, replacing with u32", keyType, kind); - keyType = "u32"; + keyType = "u32"_cs; } else if (tableKind == TableProgArray && (keyType != "u32" || valueType != "u32")) { ::warning(ErrorType::WARN_INVALID, "Invalid key type (%1%) or value type (%2%) for table kind %3%, " "replacing with u32", keyType, valueType, kind); - keyType = "u32"; - valueType = "u32"; + keyType = "u32"_cs; + valueType = "u32"_cs; } if (tableKind == TableLPMTrie) { - flags = "BPF_F_NO_PREALLOC"; + flags = "BPF_F_NO_PREALLOC"_cs; } if (flags.isNullOrEmpty()) { @@ -121,8 +121,8 @@ void KernelSamplesTarget::emitMapInMapDecl(Util::SourceCodeBuilder *builder, cst BUG("Unsupported type of outer map for map-in-map"); } - cstring registerOuterTable = "REGISTER_TABLE_OUTER(%s, %s_OF_MAPS, %s, %s, %d, %d, %s)"; - cstring registerInnerTable = "REGISTER_TABLE_INNER(%s, %s, %s, %s, %d, %d, %d)"; + cstring registerOuterTable = "REGISTER_TABLE_OUTER(%s, %s_OF_MAPS, %s, %s, %d, %d, %s)"_cs; + cstring registerInnerTable = "REGISTER_TABLE_INNER(%s, %s, %s, %s, %d, %d, %d)"_cs; innerMapIndex++; @@ -133,11 +133,11 @@ void KernelSamplesTarget::emitMapInMapDecl(Util::SourceCodeBuilder *builder, cst annotateTableWithBTF(builder, innerName, innerKeyType, innerValueType); kind = getBPFMapType(outerTableKind); - cstring keyType = outerTableKind == TableArray ? "__u32" : outerKeyType; + cstring keyType = outerTableKind == TableArray ? "__u32"_cs : outerKeyType; builder->appendFormat(registerOuterTable, outerName, kind, keyType, "__u32", outerSize, innerMapIndex, innerName); builder->newline(); - annotateTableWithBTF(builder, outerName, keyType, "__u32"); + annotateTableWithBTF(builder, outerName, keyType, "__u32"_cs); } void KernelSamplesTarget::emitLicense(Util::SourceCodeBuilder *builder, cstring license) const { @@ -157,7 +157,7 @@ void KernelSamplesTarget::emitMain(Util::SourceCodeBuilder *builder, cstring fun } void KernelSamplesTarget::emitPreamble(Util::SourceCodeBuilder *builder) const { - cstring macro; + const char *macro; if (emitTraceMessages) { macro = "#define bpf_trace_message(fmt, ...) \\\n" @@ -174,11 +174,12 @@ void KernelSamplesTarget::emitPreamble(Util::SourceCodeBuilder *builder) const { builder->newline(); } +// FIXME: Fix terrible implementation void KernelSamplesTarget::emitTraceMessage(Util::SourceCodeBuilder *builder, const char *format, int argc, ...) const { if (!emitTraceMessages) return; - cstring msg = format; + cstring msg = cstring(format); va_list ap; // Older kernels do not append new line when printing message but newer do that, @@ -186,7 +187,7 @@ void KernelSamplesTarget::emitTraceMessage(Util::SourceCodeBuilder *builder, con // will look better than everything in a single line. if (!msg.endsWith("\\n")) msg = msg + "\\n"; - msg = cstring("\"") + msg + "\""; + msg = "\""_cs + msg + "\""_cs; va_start(ap, argc); for (int i = 0; i < argc; ++i) { auto arg = va_arg(ap, const char *); @@ -261,11 +262,11 @@ void BccTarget::emitTableDecl(Util::SourceCodeBuilder *builder, cstring tblName, unsigned size) const { cstring kind; if (tableKind == TableHash) - kind = "hash"; + kind = "hash"_cs; else if (tableKind == TableArray) - kind = "array"; + kind = "array"_cs; else if (tableKind == TableLPMTrie) - kind = "lpm_trie"; + kind = "lpm_trie"_cs; else BUG("%1%: unsupported table kind", tableKind); diff --git a/backends/ebpf/target.h b/backends/ebpf/target.h index b928548eb5..d3c0573593 100644 --- a/backends/ebpf/target.h +++ b/backends/ebpf/target.h @@ -29,6 +29,8 @@ limitations under the License. namespace EBPF { +using namespace P4::literals; + enum TableKind { TableHash, TableArray, @@ -131,19 +133,19 @@ class KernelSamplesTarget : public Target { cstring getBPFMapType(TableKind kind) const { if (kind == TableHash) { - return "BPF_MAP_TYPE_HASH"; + return "BPF_MAP_TYPE_HASH"_cs; } else if (kind == TableArray) { - return "BPF_MAP_TYPE_ARRAY"; + return "BPF_MAP_TYPE_ARRAY"_cs; } else if (kind == TablePerCPUArray) { - return "BPF_MAP_TYPE_PERCPU_ARRAY"; + return "BPF_MAP_TYPE_PERCPU_ARRAY"_cs; } else if (kind == TableLPMTrie) { - return "BPF_MAP_TYPE_LPM_TRIE"; + return "BPF_MAP_TYPE_LPM_TRIE"_cs; } else if (kind == TableHashLRU) { - return "BPF_MAP_TYPE_LRU_HASH"; + return "BPF_MAP_TYPE_LRU_HASH"_cs; } else if (kind == TableProgArray) { - return "BPF_MAP_TYPE_PROG_ARRAY"; + return "BPF_MAP_TYPE_PROG_ARRAY"_cs; } else if (kind == TableDevmap) { - return "BPF_MAP_TYPE_DEVMAP"; + return "BPF_MAP_TYPE_DEVMAP"_cs; } BUG("Unknown table kind"); } @@ -152,7 +154,7 @@ class KernelSamplesTarget : public Target { bool emitTraceMessages; public: - explicit KernelSamplesTarget(bool emitTrace = false, cstring name = "Linux kernel") + explicit KernelSamplesTarget(bool emitTrace = false, cstring name = "Linux kernel"_cs) : Target(name), innerMapIndex(0), emitTraceMessages(emitTrace) {} void emitLicense(Util::SourceCodeBuilder *builder, cstring license) const override; @@ -187,12 +189,12 @@ class KernelSamplesTarget : public Target { return cstring("((void*)(long)") + base + "->data_end)"; } cstring dataLength(cstring base) const override { return cstring(base) + "->len"; } - cstring forwardReturnCode() const override { return "TC_ACT_OK"; } - cstring dropReturnCode() const override { return "TC_ACT_SHOT"; } - cstring abortReturnCode() const override { return "TC_ACT_SHOT"; } - cstring sysMapPath() const override { return "/sys/fs/bpf/tc/globals"; } + cstring forwardReturnCode() const override { return "TC_ACT_OK"_cs; } + cstring dropReturnCode() const override { return "TC_ACT_SHOT"_cs; } + cstring abortReturnCode() const override { return "TC_ACT_SHOT"_cs; } + cstring sysMapPath() const override { return "/sys/fs/bpf/tc/globals"_cs; } - cstring packetDescriptorType() const override { return "struct __sk_buff"; } + cstring packetDescriptorType() const override { return "struct __sk_buff"_cs; } void annotateTableWithBTF(Util::SourceCodeBuilder *builder, cstring name, cstring keyType, cstring valueType) const; @@ -200,7 +202,7 @@ class KernelSamplesTarget : public Target { class P4TCTarget : public KernelSamplesTarget { public: - explicit P4TCTarget(bool emitTrace) : KernelSamplesTarget(emitTrace, "P4TC") {} + explicit P4TCTarget(bool emitTrace) : KernelSamplesTarget(emitTrace, "P4TC"_cs) {} cstring getByteOrderFromAnnotation(const IR::Vector annotations) const { for (auto anno : annotations) { if (anno->name != "tc_type") continue; @@ -208,11 +210,11 @@ class P4TCTarget : public KernelSamplesTarget { if (annoVal->text == "macaddr" || annoVal->text == "ipv4" || annoVal->text == "ipv6" || annoVal->text == "be16" || annoVal->text == "be32" || annoVal->text == "be64") { - return "NETWORK"; + return "NETWORK"_cs; } } } - return "HOST"; + return "HOST"_cs; } cstring getByteOrder(P4::TypeMap *typeMap, const IR::P4Action *action, @@ -233,21 +235,21 @@ class P4TCTarget : public KernelSamplesTarget { } } } - return "HOST"; + return "HOST"_cs; } }; /// Target XDP. class XdpTarget : public KernelSamplesTarget { public: - explicit XdpTarget(bool emitTrace) : KernelSamplesTarget(emitTrace, "XDP") {} + explicit XdpTarget(bool emitTrace) : KernelSamplesTarget(emitTrace, "XDP"_cs) {} - cstring forwardReturnCode() const override { return "XDP_PASS"; } - cstring dropReturnCode() const override { return "XDP_DROP"; } - cstring abortReturnCode() const override { return "XDP_ABORTED"; } - cstring redirectReturnCode() const { return "XDP_REDIRECT"; } - cstring sysMapPath() const override { return "/sys/fs/bpf/xdp/globals"; } - cstring packetDescriptorType() const override { return "struct xdp_md"; } + cstring forwardReturnCode() const override { return "XDP_PASS"_cs; } + cstring dropReturnCode() const override { return "XDP_DROP"_cs; } + cstring abortReturnCode() const override { return "XDP_ABORTED"_cs; } + cstring redirectReturnCode() const { return "XDP_REDIRECT"_cs; } + cstring sysMapPath() const override { return "/sys/fs/bpf/xdp/globals"_cs; } + cstring packetDescriptorType() const override { return "struct xdp_md"_cs; } cstring dataLength(cstring base) const override { return cstring("(") + base + "->data_end - " + base + "->data)"; @@ -264,7 +266,7 @@ class XdpTarget : public KernelSamplesTarget { /// Represents a target compiled by bcc that uses the TC. class BccTarget : public Target { public: - BccTarget() : Target("BCC") {} + BccTarget() : Target("BCC"_cs) {} void emitLicense(Util::SourceCodeBuilder *, cstring) const override {} void emitCodeSection(Util::SourceCodeBuilder *, cstring) const override {} void emitIncludes(Util::SourceCodeBuilder *builder) const override; @@ -284,18 +286,18 @@ class BccTarget : public Target { return cstring("(") + base + " + " + base + "->len)"; } cstring dataLength(cstring base) const override { return cstring(base) + "->len"; } - cstring forwardReturnCode() const override { return "0"; } - cstring dropReturnCode() const override { return "1"; } - cstring abortReturnCode() const override { return "1"; } - cstring sysMapPath() const override { return "/sys/fs/bpf"; } - cstring packetDescriptorType() const override { return "struct __sk_buff"; } + cstring forwardReturnCode() const override { return "0"_cs; } + cstring dropReturnCode() const override { return "1"_cs; } + cstring abortReturnCode() const override { return "1"_cs; } + cstring sysMapPath() const override { return "/sys/fs/bpf"_cs; } + cstring packetDescriptorType() const override { return "struct __sk_buff"_cs; } }; /// A userspace test version with functionality equivalent to the kernel. /// Compiles with GCC. class TestTarget : public EBPF::KernelSamplesTarget { public: - TestTarget() : KernelSamplesTarget(false, "Userspace Test") {} + TestTarget() : KernelSamplesTarget(false, "Userspace Test"_cs) {} void emitResizeBuffer(Util::SourceCodeBuilder *, cstring, cstring) const override {} void emitIncludes(Util::SourceCodeBuilder *builder) const override; @@ -307,11 +309,11 @@ class TestTarget : public EBPF::KernelSamplesTarget { cstring dataEnd(cstring base) const override { return cstring("((void*)(long)(") + base + "->data + " + base + "->len))"; } - cstring forwardReturnCode() const override { return "true"; } - cstring dropReturnCode() const override { return "false"; } - cstring abortReturnCode() const override { return "false"; } - cstring sysMapPath() const override { return "/sys/fs/bpf"; } - cstring packetDescriptorType() const override { return "struct __sk_buff"; } + cstring forwardReturnCode() const override { return "true"_cs; } + cstring dropReturnCode() const override { return "false"_cs; } + cstring abortReturnCode() const override { return "false"_cs; } + cstring sysMapPath() const override { return "/sys/fs/bpf"_cs; } + cstring packetDescriptorType() const override { return "struct __sk_buff"_cs; } }; } // namespace EBPF diff --git a/backends/graphs/controls.cpp b/backends/graphs/controls.cpp index 0e559daae8..a1b75738d2 100644 --- a/backends/graphs/controls.cpp +++ b/backends/graphs/controls.cpp @@ -23,6 +23,7 @@ limitations under the License. #include "frontends/p4/methodInstance.h" #include "frontends/p4/tableApply.h" #include "graphs.h" +#include "lib/cstring.h" #include "lib/log.h" #include "lib/nullstream.h" @@ -33,12 +34,12 @@ using Graph = ControlGraphs::Graph; Graph *ControlGraphs::ControlStack::pushBack(Graph ¤tSubgraph, const cstring &name) { auto &newSubgraph = currentSubgraph.create_subgraph(); auto fullName = getName(name); - boost::get_property(newSubgraph, boost::graph_name) = "cluster" + fullName; - boost::get_property(newSubgraph, boost::graph_graph_attribute)["label"] = + boost::get_property(newSubgraph, boost::graph_name) = "cluster"_cs + fullName; + boost::get_property(newSubgraph, boost::graph_graph_attribute)["label"_cs] = boost::get_property(currentSubgraph, boost::graph_name) + (fullName != "" ? "." + fullName : fullName); - boost::get_property(newSubgraph, boost::graph_graph_attribute)["fontsize"] = "22pt"; - boost::get_property(newSubgraph, boost::graph_graph_attribute)["style"] = "bold"; + boost::get_property(newSubgraph, boost::graph_graph_attribute)["fontsize"_cs] = "22pt"_cs; + boost::get_property(newSubgraph, boost::graph_graph_attribute)["style"_cs] = "bold"_cs; names.push_back(name); subgraphs.push_back(&newSubgraph); return getSubgraph(); @@ -85,9 +86,9 @@ bool ControlGraphs::preorder(const IR::PackageBlock *block) { instanceName = std::nullopt; boost::get_property(*g_, boost::graph_name) = name; BUG_CHECK(controlStack.isEmpty(), "Invalid control stack state"); - g = controlStack.pushBack(*g_, ""); - start_v = add_vertex("__START__", VertexType::OTHER); - exit_v = add_vertex("__EXIT__", VertexType::OTHER); + g = controlStack.pushBack(*g_, cstring::empty); + start_v = add_vertex("__START__"_cs, VertexType::OTHER); + exit_v = add_vertex("__EXIT__"_cs, VertexType::OTHER); parents = {{start_v, new EdgeUnconditional()}}; visit(it.second->getNode()); diff --git a/backends/graphs/graph_visitor.cpp b/backends/graphs/graph_visitor.cpp index 11c01c28b3..39f9810a8e 100644 --- a/backends/graphs/graph_visitor.cpp +++ b/backends/graphs/graph_visitor.cpp @@ -81,17 +81,17 @@ const char *Graph_visitor::getPrevType(const PrevType &prev_type) { void Graph_visitor::forLoopJson(std::vector &graphsArray, PrevType node_type) { for (auto g : graphsArray) { - auto block = new Util::JsonObject(); + auto *block = new Util::JsonObject(); programBlocks->emplace_back(block); - block->emplace("type", getPrevType(node_type)); - block->emplace("name", boost::get_property(*g, boost::graph_name)); + block->emplace("type"_cs, getPrevType(node_type)); + block->emplace("name"_cs, boost::get_property(*g, boost::graph_name)); - auto nodesArray = new Util::JsonArray(); - block->emplace("nodes", nodesArray); + auto *nodesArray = new Util::JsonArray(); + block->emplace("nodes"_cs, nodesArray); - auto parserEdges = new Util::JsonArray(); - block->emplace("transitions", parserEdges); + auto *parserEdges = new Util::JsonArray(); + block->emplace("transitions"_cs, parserEdges); auto subg = *g; @@ -99,13 +99,13 @@ void Graph_visitor::forLoopJson(std::vector &graphsArray, PrevType node for (auto &vit = vertices.first; vit != vertices.second; ++vit) { auto node = new Util::JsonObject(); nodesArray->emplace_back(node); - node->emplace("node_nmb", *vit); + node->emplace("node_nmb"_cs, *vit); const auto &vinfo = subg[*vit]; - node->emplace("name", vinfo.name.escapeJson()); - node->emplace("type", getType(vinfo.type)); - node->emplace("type_enum", (unsigned)vinfo.type); + node->emplace("name"_cs, vinfo.name.escapeJson()); + node->emplace("type"_cs, getType(vinfo.type)); + node->emplace("type_enum"_cs, (unsigned)vinfo.type); } auto edges = boost::edges(subg); @@ -117,10 +117,10 @@ void Graph_visitor::forLoopJson(std::vector &graphsArray, PrevType node auto from = boost::source(*eit, subg); auto to = boost::target(*eit, subg); - edge->emplace("from", from); - edge->emplace("to", to); + edge->emplace("from"_cs, from); + edge->emplace("to"_cs, to); - edge->emplace("cond", boost::get(boost::edge_name, subg, *eit).escapeJson()); + edge->emplace("cond"_cs, boost::get(boost::edge_name, subg, *eit).escapeJson()); } } } @@ -136,10 +136,10 @@ void Graph_visitor::forLoopFullGraph(std::vector &graphsArray, fullGrap // set subg properties boost::get_property(subfg, boost::graph_name) = "cluster" + Util::toString(opts->cluster_i++); - boost::get_property(subfg, boost::graph_graph_attribute)["label"] = + boost::get_property(subfg, boost::graph_graph_attribute)["label"_cs] = boost::get_property(*g_, boost::graph_name); - boost::get_property(subfg, boost::graph_graph_attribute)["style"] = "bold"; - boost::get_property(subfg, boost::graph_graph_attribute)["fontsize"] = "22pt"; + boost::get_property(subfg, boost::graph_graph_attribute)["style"_cs] = "bold"_cs; + boost::get_property(subfg, boost::graph_graph_attribute)["fontsize"_cs] = "22pt"_cs; // No statements in graph, merge "__START__" and "__EXIT__" nodes if (g_->m_global_vertex.size() == 2) { @@ -151,10 +151,10 @@ void Graph_visitor::forLoopFullGraph(std::vector &graphsArray, fullGrap // Connect subgraphs if (opts->cluster_i > 1) { if (prev_type == PrevType::Parser) { - add_edge(opts->node_i - 2, opts->node_i, "", opts->cluster_i); + add_edge(opts->node_i - 2, opts->node_i, cstring::empty, opts->cluster_i); prev_type = PrevType::Control; } else { - add_edge(t_prev_adder, opts->node_i, "", opts->cluster_i); + add_edge(t_prev_adder, opts->node_i, cstring::empty, opts->cluster_i); } } @@ -185,15 +185,15 @@ void Graph_visitor::process(std::vector &controlGraphsArray, if (fullGraph) { fullGraphOpts opts; - boost::get_property(opts.fg, boost::graph_name) = "fullGraph"; + boost::get_property(opts.fg, boost::graph_name) = "fullGraph"_cs; // Enables edges with tails between clusters. - boost::get_property(opts.fg, boost::graph_graph_attribute)["compound"] = "true"; + boost::get_property(opts.fg, boost::graph_graph_attribute)["compound"_cs] = "true"_cs; forLoopFullGraph(parserGraphsArray, &opts, PrevType::Parser); forLoopFullGraph(controlGraphsArray, &opts, PrevType::Parser); GraphAttributeSetter()(opts.fg); - writeGraphToFile(opts.fg, "fullGraph"); + writeGraphToFile(opts.fg, "fullGraph"_cs); } if (jsonOut) { @@ -208,15 +208,15 @@ void Graph_visitor::process(std::vector &controlGraphsArray, file_without_path = file_without_p4.findlast('/') + 1; // char* without '/' } - json->emplace("name", file_without_path); + json->emplace("name"_cs, file_without_path); programBlocks = new Util::JsonArray(); - json->emplace("nodes", programBlocks); + json->emplace("nodes"_cs, programBlocks); forLoopJson(parserGraphsArray, PrevType::Parser); forLoopJson(controlGraphsArray, PrevType::Control); std::ofstream file; - auto path = Util::PathName(graphsDir).join("fullGraph.json"); + auto path = Util::PathName(graphsDir).join("fullGraph.json"_cs); file.open(path.toString()); file << json->toString() << std::endl; file.close(); diff --git a/backends/graphs/graphs.cpp b/backends/graphs/graphs.cpp index 06c3be4879..835bcc6c1a 100644 --- a/backends/graphs/graphs.cpp +++ b/backends/graphs/graphs.cpp @@ -44,8 +44,8 @@ void Graphs::add_edge(const vertex_t &from, const vertex_t &to, const cstring &n auto attrs = boost::get(boost::edge_attribute, g->root()); - attrs[ep.first]["ltail"] = "cluster" + Util::toString(cluster_id - 2); - attrs[ep.first]["lhead"] = "cluster" + Util::toString(cluster_id - 1); + attrs[ep.first]["ltail"_cs] = "cluster"_cs + Util::toString(cluster_id - 2); + attrs[ep.first]["lhead"_cs] = "cluster"_cs + Util::toString(cluster_id - 1); } void Graphs::limitStringSize(std::stringstream &sstream, std::stringstream &helper_sstream) { diff --git a/backends/graphs/graphs.h b/backends/graphs/graphs.h index 4e4b04aff3..28adbbb33a 100644 --- a/backends/graphs/graphs.h +++ b/backends/graphs/graphs.h @@ -18,6 +18,7 @@ limitations under the License. #define BACKENDS_GRAPHS_GRAPHS_H_ #include "config.h" +#include "lib/cstring.h" /// Shouldn't happen as cmake will not try to build this backend if the boost /// graph headers couldn't be found. @@ -47,6 +48,8 @@ class TypeMap; namespace graphs { +using namespace P4::literals; + class EdgeTypeIface { public: virtual ~EdgeTypeIface() {} @@ -56,7 +59,7 @@ class EdgeTypeIface { class EdgeUnconditional : public EdgeTypeIface { public: EdgeUnconditional() = default; - cstring label() const override { return ""; }; + cstring label() const override { return cstring::empty; }; }; class EdgeIf : public EdgeTypeIface { @@ -66,12 +69,12 @@ class EdgeIf : public EdgeTypeIface { cstring label() const override { switch (branch) { case Branch::TRUE: - return "TRUE"; + return "TRUE"_cs; case Branch::FALSE: - return "FALSE"; + return "FALSE"_cs; } BUG("unreachable"); - return ""; + return cstring::empty; }; private: @@ -156,15 +159,15 @@ class Graphs : public Inspector { for (auto &vit = vertices.first; vit != vertices.second; ++vit) { const auto &vinfo = g[*vit]; auto attrs = boost::get(boost::vertex_attribute, g); - attrs[*vit]["label"] = vinfo.name; - attrs[*vit]["style"] = vertexTypeGetStyle(vinfo.type); - attrs[*vit]["shape"] = vertexTypeGetShape(vinfo.type); - attrs[*vit]["margin"] = vertexTypeGetMargin(vinfo.type); + attrs[*vit]["label"_cs] = vinfo.name; + attrs[*vit]["style"_cs] = vertexTypeGetStyle(vinfo.type); + attrs[*vit]["shape"_cs] = vertexTypeGetShape(vinfo.type); + attrs[*vit]["margin"_cs] = vertexTypeGetMargin(vinfo.type); } auto edges = boost::edges(g); for (auto &eit = edges.first; eit != edges.second; ++eit) { auto attrs = boost::get(boost::edge_attribute, g); - attrs[*eit]["label"] = boost::get(boost::edge_name, g, *eit); + attrs[*eit]["label"_cs] = boost::get(boost::edge_name, g, *eit); } } @@ -173,35 +176,35 @@ class Graphs : public Inspector { switch (type) { case VertexType::TABLE: case VertexType::ACTION: - return "ellipse"; + return "ellipse"_cs; default: - return "rectangle"; + return "rectangle"_cs; } BUG("unreachable"); - return ""; + return cstring::empty; } static cstring vertexTypeGetStyle(VertexType type) { switch (type) { case VertexType::CONTROL: - return "dashed"; + return "dashed"_cs; case VertexType::EMPTY: - return "invis"; + return "invis"_cs; case VertexType::KEY: case VertexType::CONDITION: case VertexType::SWITCH: - return "rounded"; + return "rounded"_cs; default: - return "solid"; + return "solid"_cs; } BUG("unreachable"); - return ""; + return cstring::empty; } static cstring vertexTypeGetMargin(VertexType type) { switch (type) { default: - return ""; + return cstring::empty; } } }; // end class GraphAttributeSetter diff --git a/backends/graphs/p4c-graphs.cpp b/backends/graphs/p4c-graphs.cpp index 7fd9f8cddd..a0519aefd4 100644 --- a/backends/graphs/p4c-graphs.cpp +++ b/backends/graphs/p4c-graphs.cpp @@ -71,7 +71,7 @@ class Options : public CompilerOptions { registerOption( "--graphs-dir", "dir", [this](const char *arg) { - graphsDir = arg; + graphsDir = cstring(arg); return true; }, "Use this directory to dump graphs in dot format " @@ -80,7 +80,7 @@ class Options : public CompilerOptions { "--fromJSON", "file", [this](const char *arg) { loadIRFromJson = true; - file = arg; + file = cstring(arg); return true; }, "Use IR representation from JsonFile dumped previously, " @@ -129,7 +129,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoGraphsContext(new ::graphs::GraphsContext); auto &options = ::graphs::GraphsContext::get().options(); options.langVersion = CompilerOptions::FrontendVersion::P4_16; - options.compilerVersion = P4C_GRAPHS_VERSION_STRING; + options.compilerVersion = cstring(P4C_GRAPHS_VERSION_STRING); if (options.process(argc, argv) != nullptr) { if (options.loadIRFromJson == false) options.setInputFile(); diff --git a/backends/graphs/parsers.cpp b/backends/graphs/parsers.cpp index d49680f6ed..862e71b7af 100644 --- a/backends/graphs/parsers.cpp +++ b/backends/graphs/parsers.cpp @@ -36,10 +36,10 @@ static cstring toString(const IR::Expression *expression) { /// We always have only one subgraph. Graph *ParserGraphs::CreateSubGraph(Graph ¤tSubgraph, const cstring &name) { auto &newSubgraph = currentSubgraph.create_subgraph(); - boost::get_property(newSubgraph, boost::graph_name) = "cluster" + name; - boost::get_property(newSubgraph, boost::graph_graph_attribute)["label"] = name; - boost::get_property(newSubgraph, boost::graph_graph_attribute)["fontsize"] = "22pt"; - boost::get_property(newSubgraph, boost::graph_graph_attribute)["style"] = "bold"; + boost::get_property(newSubgraph, boost::graph_name) = "cluster"_cs + name; + boost::get_property(newSubgraph, boost::graph_graph_attribute)["label"_cs] = name; + boost::get_property(newSubgraph, boost::graph_graph_attribute)["fontsize"_cs] = "22pt"_cs; + boost::get_property(newSubgraph, boost::graph_graph_attribute)["style"_cs] = "bold"_cs; return &newSubgraph; } @@ -91,7 +91,7 @@ void ParserGraphs::postorder(const IR::PathExpression *expression) { auto sc = findContext(); cstring label; if (sc == nullptr) { - label = "always"; + label = "always"_cs; } else { label = toString(sc->keyset); } @@ -116,7 +116,7 @@ void ParserGraphs::postorder(const IR::SelectExpression *expression) { auto reject = parser->getDeclByName(IR::ParserState::reject); CHECK_NULL(reject); transitions[parser].push_back( - new TransitionEdge(state, reject->to(), "fallthrough")); + new TransitionEdge(state, reject->to(), "fallthrough"_cs)); } } // namespace graphs diff --git a/backends/p4test/midend.cpp b/backends/p4test/midend.cpp index 050595a99a..29ba7426c5 100644 --- a/backends/p4test/midend.cpp +++ b/backends/p4test/midend.cpp @@ -169,7 +169,7 @@ MidEnd::MidEnd(CompilerOptions &options, std::ostream *outStream) { new P4::SimplifyControlFlow(&refMap, &typeMap), new P4::MidEndLast()}); if (options.listMidendPasses) { - listPasses(*outStream, "\n"); + listPasses(*outStream, cstring::newline); *outStream << std::endl; return; } diff --git a/backends/p4test/p4test.cpp b/backends/p4test/p4test.cpp index 2656084f18..eff0ed611f 100644 --- a/backends/p4test/p4test.cpp +++ b/backends/p4test/p4test.cpp @@ -69,7 +69,7 @@ class P4TestOptions : public CompilerOptions { "--fromJSON", "file", [this](const char *arg) { loadIRFromJson = true; - file = arg; + file = cstring(arg); return true; }, "read previously dumped json instead of P4 source code"); @@ -108,7 +108,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoP4TestContext(new P4TestContext); auto &options = P4TestContext::get().options(); options.langVersion = CompilerOptions::FrontendVersion::P4_16; - options.compilerVersion = P4TEST_VERSION_STRING; + options.compilerVersion = cstring(P4TEST_VERSION_STRING); if (options.process(argc, argv) != nullptr) { if (options.loadIRFromJson == false) options.setInputFile(); diff --git a/backends/p4tools/common/compiler/reachability.cpp b/backends/p4tools/common/compiler/reachability.cpp index bd14be3f89..0dcf3ae58b 100644 --- a/backends/p4tools/common/compiler/reachability.cpp +++ b/backends/p4tools/common/compiler/reachability.cpp @@ -17,6 +17,8 @@ namespace P4Tools { +using namespace P4::literals; + P4ProgramDCGCreator::P4ProgramDCGCreator(NodesCallGraph *dcg) : dcg(dcg), p4program(nullptr) { CHECK_NULL(dcg); setName("P4ProgramDCGCreator"); @@ -125,7 +127,7 @@ bool P4ProgramDCGCreator::preorder(const IR::P4Action *action) { bool P4ProgramDCGCreator::preorder(const IR::P4Parser *parser) { addEdge(parser, parser->name); - visit(parser->states.getDeclaration("start")); + visit(parser->states.getDeclaration("start"_cs)); return false; } diff --git a/backends/p4tools/common/compiler/reachability.h b/backends/p4tools/common/compiler/reachability.h index 188a86cb31..a18bf6fda6 100644 --- a/backends/p4tools/common/compiler/reachability.h +++ b/backends/p4tools/common/compiler/reachability.h @@ -29,7 +29,7 @@ class ExtendedCallGraph : public P4::CallGraph { ReachabilityHashType hash; public: - explicit ExtendedCallGraph(cstring name) : P4::CallGraph(name) {} + explicit ExtendedCallGraph(std::string_view name) : P4::CallGraph(name) {} const ReachabilityHashType &getHash() const { return hash; } /// Function adds current vertex to a hash which allows to get access /// for vertexes from string in DCG. diff --git a/backends/p4tools/common/control_plane/symbolic_variables.cpp b/backends/p4tools/common/control_plane/symbolic_variables.cpp index a1f735faca..0e8e2fe59a 100644 --- a/backends/p4tools/common/control_plane/symbolic_variables.cpp +++ b/backends/p4tools/common/control_plane/symbolic_variables.cpp @@ -46,11 +46,11 @@ const IR::SymbolicVariable *getTableActionChoice(cstring tableName) { namespace Bmv2ControlPlaneState { const IR::SymbolicVariable *getCloneActive() { - return ToolsVariables::getSymbolicVariable(IR::Type_Boolean::get(), "clone_session_active"); + return ToolsVariables::getSymbolicVariable(IR::Type_Boolean::get(), "clone_session_active"_cs); } const IR::SymbolicVariable *getCloneSessionId(const IR::Type *type) { - return ToolsVariables::getSymbolicVariable(type, "clone_session_id"); + return ToolsVariables::getSymbolicVariable(type, "clone_session_id"_cs); } std::pair getTableRange( diff --git a/backends/p4tools/common/lib/table_utils.cpp b/backends/p4tools/common/lib/table_utils.cpp index d003c063ad..73f6e49b22 100644 --- a/backends/p4tools/common/lib/table_utils.cpp +++ b/backends/p4tools/common/lib/table_utils.cpp @@ -4,16 +4,18 @@ namespace P4Tools::TableUtils { +using namespace P4::literals; + void checkTableImmutability(const IR::P4Table &table, TableProperties &properties) { bool isConstant = false; - const auto *entriesAnnotation = table.properties->getProperty("entries"); + const auto *entriesAnnotation = table.properties->getProperty("entries"_cs); if (entriesAnnotation != nullptr) { isConstant = entriesAnnotation->isConstant; } // Also check if the table is invisible to the control plane. // This also implies that it cannot be modified. - properties.tableIsImmutable = isConstant || table.getAnnotation("hidden") != nullptr; - const auto *defaultAction = table.properties->getProperty("default_action"); + properties.tableIsImmutable = isConstant || table.getAnnotation("hidden"_cs) != nullptr; + const auto *defaultAction = table.properties->getProperty("default_action"_cs); CHECK_NULL(defaultAction); properties.defaultIsImmutable = defaultAction->isConstant; } @@ -26,7 +28,7 @@ std::vector buildTableActionList(const IR::P4Tabl } for (size_t idx = 0; idx < actionList->size(); idx++) { const auto *action = actionList->actionList.at(idx); - if (action->getAnnotation("defaultonly") != nullptr) { + if (action->getAnnotation("defaultonly"_cs) != nullptr) { continue; } tableActionList.emplace_back(action); diff --git a/backends/p4tools/common/lib/taint.cpp b/backends/p4tools/common/lib/taint.cpp index 038b024115..10410c4a4f 100644 --- a/backends/p4tools/common/lib/taint.cpp +++ b/backends/p4tools/common/lib/taint.cpp @@ -21,7 +21,7 @@ namespace P4Tools { -const IR::StringLiteral Taint::TAINTED_STRING_LITERAL = IR::StringLiteral(cstring("Taint")); +const IR::StringLiteral Taint::TAINTED_STRING_LITERAL = IR::StringLiteral("Taint"_cs); /// Returns a bitmask that indicates which bits of given expression are tainted given a complex /// expression. diff --git a/backends/p4tools/common/lib/util.cpp b/backends/p4tools/common/lib/util.cpp index 2513191406..c6b6a5df08 100644 --- a/backends/p4tools/common/lib/util.cpp +++ b/backends/p4tools/common/lib/util.cpp @@ -90,17 +90,17 @@ const IR::Constant *Utils::getRandConstantForType(const IR::Type_Bits *type) { * ========================================================================================= */ const IR::MethodCallExpression *Utils::generateInternalMethodCall( - cstring methodName, const std::vector &argVector, + std::string_view methodName, const std::vector &argVector, const IR::Type *returnType, const IR::ParameterList *paramList) { auto *args = new IR::Vector(); for (const auto *expr : argVector) { args->push_back(new IR::Argument(expr)); } + cstring name(methodName); return new IR::MethodCallExpression( returnType, - new IR::Member(new IR::Type_Method(paramList, methodName), - new IR::PathExpression(new IR::Type_Extern("*"), new IR::Path("*")), - methodName), + new IR::Member(new IR::Type_Method(paramList, name), + new IR::PathExpression(new IR::Type_Extern("*"), new IR::Path("*")), name), args); } diff --git a/backends/p4tools/common/lib/util.h b/backends/p4tools/common/lib/util.h index 69d1bdea0a..b007fb67cf 100644 --- a/backends/p4tools/common/lib/util.h +++ b/backends/p4tools/common/lib/util.h @@ -88,7 +88,7 @@ class Utils { /// @returns a method call to an internal extern consumed by the interpreter. The return type /// is typically Type_Void. static const IR::MethodCallExpression *generateInternalMethodCall( - cstring methodName, const std::vector &argVector, + std::string_view methodName, const std::vector &argVector, const IR::Type *returnType = IR::Type_Void::get(), const IR::ParameterList *paramList = new IR::ParameterList()); diff --git a/backends/p4tools/common/lib/variables.h b/backends/p4tools/common/lib/variables.h index 254de3d9e4..f7c90c3588 100644 --- a/backends/p4tools/common/lib/variables.h +++ b/backends/p4tools/common/lib/variables.h @@ -9,6 +9,8 @@ /// variables are also used for SMT solvers as symbolic variables. namespace P4Tools { +using namespace P4::literals; + /// A list of constraints. These constraints may take the form of "x == 8w1","x != y", where "x" and /// "y" are symbolic variables. They are expressed in P4C IR form and may be consumed by SMT or /// similar solvers. @@ -19,7 +21,7 @@ namespace ToolsVariables { /// To represent header validity, we pretend that every header has a field that reflects the /// header's validity state. This is the name of that field. This is not a valid P4 identifier, /// so it is guaranteed to not conflict with any other field in the header. -static const cstring VALID = "*valid"; +static const cstring VALID = "*valid"_cs; /// @returns the variable with the given @type, @incarnation, and @name. /// diff --git a/backends/p4tools/common/options.cpp b/backends/p4tools/common/options.cpp index 710af5ef86..b4671dab6b 100644 --- a/backends/p4tools/common/options.cpp +++ b/backends/p4tools/common/options.cpp @@ -76,7 +76,7 @@ std::optional AbstractP4cToolOptions::process( usage(); return std::nullopt; } - P4CContext::get().options().file = remainingArgs->at(0); + P4CContext::get().options().file = cstring(remainingArgs->at(0)); if (!validateOptions()) { return std::nullopt; @@ -108,7 +108,7 @@ struct InheritedCompilerOptionSpec { std::optional> handler; }; -AbstractP4cToolOptions::AbstractP4cToolOptions(std::string_view toolName, cstring message) +AbstractP4cToolOptions::AbstractP4cToolOptions(std::string_view toolName, std::string_view message) : Options(message), _toolName(toolName) { // Register some common options. registerOption( diff --git a/backends/p4tools/common/options.h b/backends/p4tools/common/options.h index a1b145a743..050ea9f3b8 100644 --- a/backends/p4tools/common/options.h +++ b/backends/p4tools/common/options.h @@ -56,7 +56,7 @@ class AbstractP4cToolOptions : protected Util::Options { /// Converts a vector of command-line arguments into the traditional (argc, argv) format. static std::tuple convertArgs(const std::vector &args); - explicit AbstractP4cToolOptions(std::string_view toolName, cstring message); + explicit AbstractP4cToolOptions(std::string_view toolName, std::string_view message); }; } // namespace P4Tools diff --git a/backends/p4tools/modules/testgen/core/small_step/abstract_stepper.cpp b/backends/p4tools/modules/testgen/core/small_step/abstract_stepper.cpp index 4a907f5df7..b8e8dbb75e 100644 --- a/backends/p4tools/modules/testgen/core/small_step/abstract_stepper.cpp +++ b/backends/p4tools/modules/testgen/core/small_step/abstract_stepper.cpp @@ -83,7 +83,7 @@ bool AbstractStepper::stepToSubexpr( const IR::Expression *subexpr, SmallStepEvaluator::Result &result, const ExecutionState &state, std::function rebuildCmd) { // Create a parameter for the continuation we're about to build. - const auto *v = Continuation::genParameter(subexpr->type, "v", state.getNamespaceContext()); + const auto *v = Continuation::genParameter(subexpr->type, "v"_cs, state.getNamespaceContext()); // Create the continuation itself. Continuation::Body kBody(state.getBody()); diff --git a/backends/p4tools/modules/testgen/core/small_step/cmd_stepper.cpp b/backends/p4tools/modules/testgen/core/small_step/cmd_stepper.cpp index 4b0115a02d..9ffb551e06 100644 --- a/backends/p4tools/modules/testgen/core/small_step/cmd_stepper.cpp +++ b/backends/p4tools/modules/testgen/core/small_step/cmd_stepper.cpp @@ -103,7 +103,7 @@ bool CmdStepper::preorder(const IR::P4Parser *p4parser) { nextState.pushCurrentContinuation(handlers); // Set the start state as the new body. - const auto *startState = p4parser->states.getDeclaration("start"); + const auto *startState = p4parser->states.getDeclaration("start"_cs); std::vector cmds; // Initialize parser-local declarations. @@ -194,14 +194,14 @@ bool CmdStepper::preorder(const IR::IfStatement *ifStatement) { if (Taint::hasTaint(ifStatement->condition)) { auto &nextState = state.clone(); std::vector cmds; - auto currentTaint = state.getProperty("inUndefinedState"); + auto currentTaint = state.getProperty("inUndefinedState"_cs); nextState.add(*new TraceEvents::IfStatementCondition(ifStatement->condition)); - cmds.emplace_back(Continuation::PropertyUpdate("inUndefinedState", true)); + cmds.emplace_back(Continuation::PropertyUpdate("inUndefinedState"_cs, true)); cmds.emplace_back(ifStatement->ifTrue); if (ifStatement->ifFalse != nullptr) { cmds.emplace_back(ifStatement->ifFalse); } - cmds.emplace_back(Continuation::PropertyUpdate("inUndefinedState", currentTaint)); + cmds.emplace_back(Continuation::PropertyUpdate("inUndefinedState"_cs, currentTaint)); nextState.replaceTopBody(&cmds); result->emplace_back(nextState); return false; @@ -376,7 +376,7 @@ bool CmdStepper::preorder(const IR::ParserState *parserState) { if (select->is()) { // Push a new continuation that will take the next state as an argument and execute the // state as a command. Create a parameter for the continuation we're about to build. - const auto *v = Continuation::genParameter(IR::Type_State::get(), "nextState", + const auto *v = Continuation::genParameter(IR::Type_State::get(), "nextState"_cs, state.getNamespaceContext()); // Create the continuation itself. @@ -432,7 +432,7 @@ bool CmdStepper::preorder(const IR::ExitStatement *e) { logStep(e); auto &nextState = state.clone(); nextState.markVisited(e); - nextState.add(*new TraceEvents::Generic("Exit")); + nextState.add(*new TraceEvents::Generic("Exit"_cs)); nextState.replaceTopBody(Continuation::Exception::Exit); result->emplace_back(nextState); return false; @@ -492,15 +492,15 @@ bool CmdStepper::preorder(const IR::SwitchStatement *switchStatement) { // If the switch expression is tainted, we can not predict which case will be chosen. We taint // the program counter and execute all of the statements. if (Taint::hasTaint(switchExpr)) { - auto currentTaint = state.getProperty("inUndefinedState"); - cmds.emplace_back(Continuation::PropertyUpdate("inUndefinedState", true)); + auto currentTaint = state.getProperty("inUndefinedState"_cs); + cmds.emplace_back(Continuation::PropertyUpdate("inUndefinedState"_cs, true)); for (const auto *switchCase : switchCases) { if (switchCase->statement != nullptr) { cmds.emplace_back(switchCase->statement); } } - state.add(*new TraceEvents::Generic("TaintedSwitchCase")); - cmds.emplace_back(Continuation::PropertyUpdate("inUndefinedState", currentTaint)); + state.add(*new TraceEvents::Generic("TaintedSwitchCase"_cs)); + cmds.emplace_back(Continuation::PropertyUpdate("inUndefinedState"_cs, currentTaint)); state.replaceTopBody(&cmds); return false; } @@ -527,7 +527,7 @@ bool CmdStepper::preorder(const IR::SwitchStatement *switchStatement) { collector.updateNodeCoverage(switchCase->statement, coveredNodes); } nextState.add(*new TraceEvents::GenericDescription( - "SwitchCase", switchCase->label->getSourceInfo().toBriefSourceFragment())); + "SwitchCase"_cs, switchCase->label->getSourceInfo().toBriefSourceFragment())); cmds.emplace_back(switchCase->statement); // If the statement is a block, we do not fall through and terminate execution. if (switchCase->statement->is()) { @@ -536,7 +536,7 @@ bool CmdStepper::preorder(const IR::SwitchStatement *switchStatement) { } // The default label must be last. Always break here. if (switchCase->label->is()) { - nextState.add(*new TraceEvents::GenericDescription("SwitchCase", "default")); + nextState.add(*new TraceEvents::GenericDescription("SwitchCase"_cs, "default"_cs)); cmds.emplace_back(switchCase->statement); break; } diff --git a/backends/p4tools/modules/testgen/core/small_step/expr_stepper.cpp b/backends/p4tools/modules/testgen/core/small_step/expr_stepper.cpp index 9b101a52ba..3e3c64dda6 100644 --- a/backends/p4tools/modules/testgen/core/small_step/expr_stepper.cpp +++ b/backends/p4tools/modules/testgen/core/small_step/expr_stepper.cpp @@ -510,7 +510,7 @@ bool ExprStepper::preorder(const IR::Slice *slice) { void ExprStepper::stepNoMatch(std::string traceLog, const IR::Expression *condition) { auto &noMatchState = condition ? state.clone() : state; - noMatchState.add(*new TraceEvents::GenericDescription("NoMatch", traceLog)); + noMatchState.add(*new TraceEvents::GenericDescription("NoMatch"_cs, traceLog)); noMatchState.replaceTopBody(Continuation::Exception::NoMatch); if (condition) { result->emplace_back(condition, state, noMatchState); diff --git a/backends/p4tools/modules/testgen/core/small_step/extern_stepper.cpp b/backends/p4tools/modules/testgen/core/small_step/extern_stepper.cpp index 47f9ef1703..59145092ab 100644 --- a/backends/p4tools/modules/testgen/core/small_step/extern_stepper.cpp +++ b/backends/p4tools/modules/testgen/core/small_step/extern_stepper.cpp @@ -154,8 +154,8 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c * the prepending of metadata that some P4 targets perform. * ====================================================================================== */ - {"*.prepend_to_prog_header", - {"hdr"}, + {"*.prepend_to_prog_header"_cs, + {"hdr"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -164,7 +164,7 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c auto &nextState = state.clone(); const auto *prependType = state.resolveType(prependVar->type); - nextState.add(*new TraceEvents::Expression(prependVar, "PrependToProgramHeader")); + nextState.add(*new TraceEvents::Expression(prependVar, "PrependToProgramHeader"_cs)); // Prepend the field to the packet buffer. if (const auto *structExpr = prependVar->to()) { auto exprList = IR::flattenStructExpression(structExpr); @@ -188,8 +188,8 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c * the appending of metadata that some P4 targets perform. * ====================================================================================== */ - {"*.append_to_prog_header", - {"hdr"}, + {"*.append_to_prog_header"_cs, + {"hdr"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -198,7 +198,7 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c auto &nextState = state.clone(); const auto *appendType = state.resolveType(appendVar->type); - nextState.add(*new TraceEvents::Expression(appendVar, "AppendToProgramHeader")); + nextState.add(*new TraceEvents::Expression(appendVar, "AppendToProgramHeader"_cs)); // Append the field to the packet buffer. if (const auto *structExpr = appendVar->to()) { auto exprList = IR::flattenStructExpression(structExpr); @@ -221,7 +221,7 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c * the output packet, which can either be emitted or forwarded to the next parser. * ====================================================================================== */ - {"*.prepend_emit_buffer", + {"*.prepend_emit_buffer"_cs, {}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, @@ -230,7 +230,7 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c const auto *emitBuffer = state.getEmitBuffer(); nextState.prependToPacketBuffer(emitBuffer); nextState.add( - *new TraceEvents::Generic("Prepending the emit buffer to the program packet")); + *new TraceEvents::Generic("Prepending the emit buffer to the program packet"_cs)); nextState.popBody(); result->emplace_back(nextState); }}, @@ -240,7 +240,7 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c * We do this by clearing the packet variable and pushing an exit continuation. * ====================================================================================== */ - {"*.drop_and_exit", + {"*.drop_and_exit"_cs, {}, [this](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, @@ -253,8 +253,8 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c programInfo.createTargetUninitialized( programInfo.getTargetOutputPortVar()->type, true)); } - nextState.add(*new TraceEvents::Generic("Packet marked dropped")); - nextState.setProperty("drop", true); + nextState.add(*new TraceEvents::Generic("Packet marked dropped"_cs)); + nextState.setProperty("drop"_cs, true); nextState.replaceTopBody(Continuation::Exception::Drop); result->emplace_back(nextState); }}, @@ -265,8 +265,8 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c * appropriately. * ====================================================================================== */ - {"*.copy_in", - {"blockRef"}, + {"*.copy_in"_cs, + {"blockRef"_cs}, [this](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -282,14 +282,14 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c // Copy-in. // Get the current level and disable it for these operations to avoid overtainting. - auto currentTaint = state.getProperty("inUndefinedState"); - nextState.setProperty("inUndefinedState", false); + auto currentTaint = state.getProperty("inUndefinedState"_cs); + nextState.setProperty("inUndefinedState"_cs, false); for (size_t paramIdx = 0; paramIdx < blockParams->size(); ++paramIdx) { const auto *internalParam = blockParams->getParameter(paramIdx); auto externalParamName = archSpec.getParamName(canonicalName, paramIdx); nextState.copyIn(TestgenTarget::get(), internalParam, externalParamName); } - nextState.setProperty("inUndefinedState", currentTaint); + nextState.setProperty("inUndefinedState"_cs, currentTaint); nextState.popBody(); result->emplace_back(nextState); }}, @@ -300,8 +300,8 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c * appropriately. * ====================================================================================== */ - {"*.copy_out", - {"blockRef"}, + {"*.copy_out"_cs, + {"blockRef"_cs}, [this](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -317,14 +317,14 @@ void ExprStepper::evalInternalExternMethodCall(const IR::MethodCallExpression *c // Copy-in. // Get the current level and disable it for these operations to avoid overtainting. - auto currentTaint = state.getProperty("inUndefinedState"); - nextState.setProperty("inUndefinedState", false); + auto currentTaint = state.getProperty("inUndefinedState"_cs); + nextState.setProperty("inUndefinedState"_cs, false); for (size_t paramIdx = 0; paramIdx < blockParams->size(); ++paramIdx) { const auto *internalParam = blockParams->getParameter(paramIdx); auto externalParamName = archSpec.getParamName(canonicalName, paramIdx); nextState.copyOut(internalParam, externalParamName); } - nextState.setProperty("inUndefinedState", currentTaint); + nextState.setProperty("inUndefinedState"_cs, currentTaint); nextState.popBody(); result->emplace_back(nextState); }}, @@ -350,7 +350,7 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * T lookahead(); * ====================================================================================== */ - {"packet_in.lookahead", + {"packet_in.lookahead"_cs, {}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, @@ -376,7 +376,7 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, auto &nextState = state.clone(); // Peek into the buffer, we do NOT slice from it. const auto *lookaheadVar = nextState.peekPacketBuffer(lookaheadSize); - nextState.add(*new TraceEvents::Expression(lookaheadVar, "Lookahead result")); + nextState.add(*new TraceEvents::Expression(lookaheadVar, "Lookahead result"_cs)); // Record the condition we are passing at this at this point. nextState.add(*new TraceEvents::Generic(condStream.str())); nextState.replaceTopBody(Continuation::Return(lookaheadVar)); @@ -386,7 +386,7 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, if (condInfo.advanceFailCond != nullptr) { auto &rejectState = state.clone(); // Record the condition we are failing at this at this point. - rejectState.add(*new TraceEvents::Generic("Lookahead: Packet too short")); + rejectState.add(*new TraceEvents::Generic("Lookahead: Packet too short"_cs)); rejectState.replaceTopBody(Continuation::Exception::PacketTooShort); result->emplace_back(condInfo.advanceFailCond, state, rejectState); } @@ -396,8 +396,8 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * Advance the packet cursor by the specified number of bits. * ====================================================================================== */ - {"packet_in.advance", - {"sizeInBits"}, + {"packet_in.advance"_cs, + {"sizeInBits"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -459,7 +459,7 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, // Advancing by zero can be considered a no-op. if (condInfo.advanceSize == 0) { auto &nextState = state.clone(); - nextState.add(*new TraceEvents::Generic("Advance: 0 bits.")); + nextState.add(*new TraceEvents::Generic("Advance: 0 bits."_cs)); nextState.popBody(); result->emplace_back(nextState); } else { @@ -477,7 +477,7 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, // Handle the case where the packet is too short. auto &rejectState = state.clone(); // Record the condition we are failing at this at this point. - rejectState.add(*new TraceEvents::Generic("Advance: Packet too short")); + rejectState.add(*new TraceEvents::Generic("Advance: Packet too short"_cs)); rejectState.replaceTopBody(Continuation::Exception::PacketTooShort); result->emplace_back(condInfo.advanceFailCond, state, rejectState); } @@ -489,8 +489,8 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * remains in the most recent position until we enter a new start parser. * ====================================================================================== */ - {"packet_in.extract", - {"hdr"}, + {"packet_in.extract"_cs, + {"hdr"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -545,8 +545,8 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, result->emplace_back(condInfo.advanceFailCond, state, rejectState); } }}, - {"packet_in.extract", - {"hdr", "sizeInBits"}, + {"packet_in.extract"_cs, + {"hdr"_cs, "sizeInBits"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -674,7 +674,7 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * some target architectures. * ====================================================================================== */ - {"packet_in.length", + {"packet_in.length"_cs, {}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*name*/, const IR::Vector * /*args*/, @@ -684,7 +684,7 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, const auto *divVar = new IR::Div(lengthVar->type, ExecutionState::getInputPacketSizeVar(), IR::Constant::get(lengthVar->type, 8)); - nextState.add(*new TraceEvents::Expression(divVar, "Return packet length")); + nextState.add(*new TraceEvents::Expression(divVar, "Return packet length"_cs)); nextState.replaceTopBody(Continuation::Return(divVar)); result->emplace_back(std::nullopt, state, nextState); }}, @@ -694,8 +694,8 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * We use a concatenation for this. * ====================================================================================== */ - {"packet_out.emit", - {"hdr"}, + {"packet_out.emit"_cs, + {"hdr"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -774,8 +774,8 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * argument. * ====================================================================================== */ - {"*method.verify", - {"bool", "error"}, + {"*method.verify"_cs, + {"bool"_cs, "error"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*name*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -824,8 +824,8 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, /* ====================================================================================== * assume * ====================================================================================== */ - {"*method.testgen_assume", - {"check"}, + {"*method.testgen_assume"_cs, + {"check"_cs}, [](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -870,8 +870,8 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, /* ====================================================================================== * assert * ====================================================================================== */ - {"*method.testgen_assert", - {"check"}, + {"*method.testgen_assert"_cs, + {"check"_cs}, [](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -917,7 +917,7 @@ void ExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, cond->dbprint(condStream); nextState.add(*new TraceEvents::Generic(condStream.str())); // Do not bother executing further. We have triggered an assertion. - nextState.setProperty("assertionTriggered", true); + nextState.setProperty("assertionTriggered"_cs, true); nextState.replaceTopBody(Continuation::Exception::Abort); result->emplace_back(new IR::LNot(cond), state, nextState); } diff --git a/backends/p4tools/modules/testgen/core/small_step/table_stepper.cpp b/backends/p4tools/modules/testgen/core/small_step/table_stepper.cpp index 2ed93b978f..eab57bc4ea 100644 --- a/backends/p4tools/modules/testgen/core/small_step/table_stepper.cpp +++ b/backends/p4tools/modules/testgen/core/small_step/table_stepper.cpp @@ -68,15 +68,15 @@ const IR::StateVariable &TableStepper::getTableActionVar(const IR::P4Table *tabl size_t max = 255; BUG_CHECK(numActions < max, "Number of actions in the table (%1%) exceeds the maximum of %2%.", numActions, max); - return getTableStateVariable(IR::Type_Bits::get(8), table, "*action"); + return getTableStateVariable(IR::Type_Bits::get(8), table, "*action"_cs); } const IR::StateVariable &TableStepper::getTableResultVar(const IR::P4Table *table) { - return getTableStateVariable(IR::Type::Boolean::get(), table, "*result"); + return getTableStateVariable(IR::Type::Boolean::get(), table, "*result"_cs); } const IR::StateVariable &TableStepper::getTableHitVar(const IR::P4Table *table) { - return getTableStateVariable(IR::Type::Boolean::get(), table, "*hit"); + return getTableStateVariable(IR::Type::Boolean::get(), table, "*hit"_cs); } const IR::Expression *TableStepper::computeTargetMatchType( @@ -272,8 +272,8 @@ void TableStepper::setTableDefaultEntries( // Finally, add all the new rules to the execution stepper->state. auto *tableConfig = new TableConfig(table, {}); // Add the action selector to the table. This signifies a slightly different implementation. - tableConfig->addTableProperty("overriden_default_action", ctrlPlaneActionCall); - nextState.addTestObject("tableconfigs", properties.tableName, tableConfig); + tableConfig->addTableProperty("overriden_default_action"_cs, ctrlPlaneActionCall); + nextState.addTestObject("tableconfigs"_cs, properties.tableName, tableConfig); // Update all the tracking variables for tables. std::vector replacements; @@ -340,7 +340,7 @@ void TableStepper::evalTableControlEntries( auto tableRule = TableRule(matches, TestSpec::LOW_PRIORITY, ctrlPlaneActionCall, TestSpec::TTL); auto *tableConfig = new TableConfig(table, {tableRule}); - nextState.addTestObject("tableconfigs", properties.tableName, tableConfig); + nextState.addTestObject("tableconfigs"_cs, properties.tableName, tableConfig); // Update all the tracking variables for tables. std::vector replacements; @@ -389,8 +389,8 @@ void TableStepper::evalTaintedTable() { // If the table is immutable, we execute all the constant entries in its list. // We get the current value of the inUndefinedState property. - auto currentTaint = stepper->state.getProperty("inUndefinedState"); - replacements.emplace_back(Continuation::PropertyUpdate("inUndefinedState", true)); + auto currentTaint = stepper->state.getProperty("inUndefinedState"_cs); + replacements.emplace_back(Continuation::PropertyUpdate("inUndefinedState"_cs, true)); const auto *entries = table->getEntries(); // Sometimes, there are no entries. Just return. @@ -414,7 +414,7 @@ void TableStepper::evalTaintedTable() { nextState.set(hitVar, stepper->programInfo.createTargetUninitialized(hitVar->type, true)); // Reset the property to its previous stepper->state. - replacements.emplace_back(Continuation::PropertyUpdate("inUndefinedState", currentTaint)); + replacements.emplace_back(Continuation::PropertyUpdate("inUndefinedState"_cs, currentTaint)); nextState.replaceTopBody(&replacements); stepper->result->emplace_back(nextState); } @@ -466,7 +466,7 @@ bool TableStepper::resolveTableKeys() { return true; } - const auto *nameAnnot = keyElement->getAnnotation("name"); + const auto *nameAnnot = keyElement->getAnnotation("name"_cs); // Some hidden tables do not have any key name annotations. BUG_CHECK(nameAnnot != nullptr || properties.tableIsImmutable, "Non-constant table key without an annotation"); diff --git a/backends/p4tools/modules/testgen/lib/execution_state.cpp b/backends/p4tools/modules/testgen/lib/execution_state.cpp index 6fb6c5db01..97e7e4d923 100644 --- a/backends/p4tools/modules/testgen/lib/execution_state.cpp +++ b/backends/p4tools/modules/testgen/lib/execution_state.cpp @@ -70,25 +70,25 @@ ExecutionState::ExecutionState(const IR::P4Program *program) env.set(&PacketVars::INPUT_PACKET_LABEL, IR::Constant::get(IR::Type_Bits::get(0), 0)); env.set(&PacketVars::PACKET_BUFFER_LABEL, IR::Constant::get(IR::Type_Bits::get(0), 0)); // We also add the taint property and set it to false. - setProperty("inUndefinedState", false); + setProperty("inUndefinedState"_cs, false); // Drop is initialized to false, too. - setProperty("drop", false); + setProperty("drop"_cs, false); // If a user-pattern is provided, initialize the reachability engine state. if (!TestgenOptions::get().pattern.empty()) { reachabilityEngineState = ReachabilityEngineState::getInitial(); } // If assertion mode is enabled, set the assertion property to false. if (TestgenOptions::get().assertionModeEnabled) { - setProperty("assertionTriggered", false); + setProperty("assertionTriggered"_cs, false); } } ExecutionState::ExecutionState(Continuation::Body body) : body(std::move(body)), stack(*(new std::stack>())) { // We also add the taint property and set it to false. - setProperty("inUndefinedState", false); + setProperty("inUndefinedState"_cs, false); // Drop is initialized to false, too. - setProperty("drop", false); + setProperty("drop"_cs, false); // If a user-pattern is provided, initialize the reachability engine state. if (!TestgenOptions::get().pattern.empty()) { reachabilityEngineState = ReachabilityEngineState::getInitial(); @@ -200,7 +200,7 @@ void ExecutionState::set(const IR::StateVariable &var, const IR::Expression *val const auto *type = value->type; BUG_CHECK(type && !type->is(), "Cannot set value with unspecified type: %1%", value); - if (getProperty("inUndefinedState")) { + if (getProperty("inUndefinedState"_cs)) { // If we are in an undefined state, the variable we set is tainted. value = ToolsVariables::getTaintExpression(type); } else { @@ -304,7 +304,7 @@ void ExecutionState::pushCurrentContinuation(std::optional par std::optional parameterOpt = std::nullopt; if (parameterType_opt) { const auto *parameter = - Continuation::genParameter(*parameterType_opt, "_", getNamespaceContext()); + Continuation::genParameter(*parameterType_opt, "_"_cs, getNamespaceContext()); parameterOpt = parameter; } @@ -369,7 +369,7 @@ void ExecutionState::pushBranchDecision(uint64_t bIdx) { selectedBranches.push_b const IR::SymbolicVariable *ExecutionState::getInputPacketSizeVar() { return ToolsVariables::getSymbolicVariable(&PacketVars::PACKET_SIZE_VAR_TYPE, - "*packetLen_bits"); + "*packetLen_bits"_cs); } int ExecutionState::getMaxPacketLength() { return TestgenOptions::get().maxPktSize; } diff --git a/backends/p4tools/modules/testgen/lib/packet_vars.cpp b/backends/p4tools/modules/testgen/lib/packet_vars.cpp index fc5ba29268..162a8d7007 100644 --- a/backends/p4tools/modules/testgen/lib/packet_vars.cpp +++ b/backends/p4tools/modules/testgen/lib/packet_vars.cpp @@ -4,6 +4,8 @@ namespace P4Tools::P4Testgen { +using namespace P4::literals; + // The methods in P4's packet_in uses 32-bit values. Conform with this to make it easier to produce // well-typed expressions when manipulating the parser cursor. const IR::Type_Bits PacketVars::PACKET_SIZE_VAR_TYPE = IR::Type_Bits(32, false); @@ -18,6 +20,6 @@ const IR::Member PacketVars::EMIT_BUFFER_LABEL = IR::Member(new IR::PathExpression("*"), "emitBuffer"); const IR::SymbolicVariable PacketVars::PAYLOAD_SYMBOL = - IR::SymbolicVariable(&PacketVars::PACKET_SIZE_VAR_TYPE, "*payload"); + IR::SymbolicVariable(&PacketVars::PACKET_SIZE_VAR_TYPE, "*payload"_cs); } // namespace P4Tools::P4Testgen diff --git a/backends/p4tools/modules/testgen/lib/test_backend.cpp b/backends/p4tools/modules/testgen/lib/test_backend.cpp index b5ab60fa1b..4701ae4b40 100644 --- a/backends/p4tools/modules/testgen/lib/test_backend.cpp +++ b/backends/p4tools/modules/testgen/lib/test_backend.cpp @@ -54,7 +54,7 @@ bool TestBackEnd::run(const FinalState &state) { // produce a test with an output packet. if (testgenOptions.outputPacketOnly) { if (executionState->getPacketBufferSize() <= 0 || - executionState->getProperty("drop")) { + executionState->getProperty("drop"_cs)) { return needsToTerminate(testCount); } } @@ -62,14 +62,14 @@ bool TestBackEnd::run(const FinalState &state) { // Don't increase the test count if --dropped-packet-only is enabled and we produce a test // with an output packet. if (testgenOptions.droppedPacketOnly) { - if (!executionState->getProperty("drop")) { + if (!executionState->getProperty("drop"_cs)) { return needsToTerminate(testCount); } } // If assertion mode is active, ignore any test that does not trigger an assertion. if (testgenOptions.assertionModeEnabled) { - if (!executionState->getProperty("assertionTriggered")) { + if (!executionState->getProperty("assertionTriggered"_cs)) { return needsToTerminate(testCount); } printFeature("test_info", 4, @@ -217,10 +217,10 @@ TestBackEnd::TestInfo TestBackEnd::produceTestInfo( auto inputPortInt = IR::getIntFromLiteral(inputPort); auto outputPortInt = IR::getIntFromLiteral(outputPortVar); - return {inputPacket->checkedTo(), inputPortInt, - outputPacket->checkedTo(), outputPortInt, - evalMask->checkedTo(), *programTraces, - executionState->getProperty("drop")}; + return {inputPacket->checkedTo(), inputPortInt, + outputPacket->checkedTo(), outputPortInt, + evalMask->checkedTo(), *programTraces, + executionState->getProperty("drop"_cs)}; } bool TestBackEnd::printTestInfo(const ExecutionState * /*executionState*/, const TestInfo &testInfo, diff --git a/backends/p4tools/modules/testgen/lib/test_framework.h b/backends/p4tools/modules/testgen/lib/test_framework.h index 516337c079..229edeee7c 100644 --- a/backends/p4tools/modules/testgen/lib/test_framework.h +++ b/backends/p4tools/modules/testgen/lib/test_framework.h @@ -23,6 +23,8 @@ namespace P4Tools::P4Testgen { +using namespace P4::literals; + /// Type definitions for abstract tests. struct AbstractTest : ICastable {}; /// TODO: It would be nice if this were a reference to signal non-nullness. @@ -77,14 +79,14 @@ class TestFramework { template static void checkForTableActionProfile(inja::json &tblJson, std::map &apAsMap, const TableConfig *tblConfig) { - const auto *apObject = tblConfig->getProperty("action_profile", false); + const auto *apObject = tblConfig->getProperty("action_profile"_cs, false); if (apObject != nullptr) { const auto *actionProfile = apObject->checkedTo(); tblJson["has_ap"] = true; // Check if we have an Action Selector too. // TODO: Change this to check in ActionSelector with table // property "action_selectors". - const auto *asObject = tblConfig->getProperty("action_selector", false); + const auto *asObject = tblConfig->getProperty("action_selector"_cs, false); if (asObject != nullptr) { const auto *actionSelector = asObject->checkedTo(); apAsMap[actionProfile->getProfileDecl()->controlPlaneName()] = @@ -97,7 +99,8 @@ class TestFramework { /// Check whether the table object has an overridden default action. /// In this case, we assume there are no keys and we just set the default action of the table. static void checkForDefaultActionOverride(inja::json &tblJson, const TableConfig *tblConfig) { - const auto *defaultOverrideObj = tblConfig->getProperty("overriden_default_action", false); + const auto *defaultOverrideObj = + tblConfig->getProperty("overriden_default_action"_cs, false); if (defaultOverrideObj != nullptr) { const auto *defaultAction = defaultOverrideObj->checkedTo(); inja::json a; @@ -120,7 +123,7 @@ class TestFramework { static void collectActionProfileDeclarations(const TestSpec *testSpec, inja::json &controlPlaneJson, const std::map &apAsMap) { - auto actionProfiles = testSpec->getTestObjectCategory("action_profiles"); + auto actionProfiles = testSpec->getTestObjectCategory("action_profiles"_cs); if (!actionProfiles.empty()) { controlPlaneJson["action_profiles"] = inja::json::array(); } diff --git a/backends/p4tools/modules/testgen/lib/test_spec.cpp b/backends/p4tools/modules/testgen/lib/test_spec.cpp index 4acb1a7e16..2bff6db08f 100644 --- a/backends/p4tools/modules/testgen/lib/test_spec.cpp +++ b/backends/p4tools/modules/testgen/lib/test_spec.cpp @@ -16,6 +16,8 @@ namespace P4Tools::P4Testgen { +using namespace P4::literals; + /* ========================================================================================= * Test Specification Objects * ========================================================================================= */ @@ -23,7 +25,7 @@ namespace P4Tools::P4Testgen { Packet::Packet(int port, const IR::Expression *payload, const IR::Expression *payloadIgnoreMask) : port(port), payload(payload), payloadIgnoreMask(payloadIgnoreMask) {} -cstring Packet::getObjectName() const { return "Packet"; } +cstring Packet::getObjectName() const { return "Packet"_cs; } int Packet::getPort() const { return port; } @@ -74,7 +76,7 @@ const IR::Constant *ActionArg::getEvaluatedValue() const { return constant; } -cstring ActionArg::getObjectName() const { return "ActionArg"; } +cstring ActionArg::getObjectName() const { return "ActionArg"_cs; } const ActionArg *ActionArg::evaluate(const Model &model, bool doComplete) const { const auto &newValue = model.evaluate(value, doComplete); @@ -100,7 +102,7 @@ const ActionCall *ActionCall::evaluate(const Model &model, bool doComplete) cons return new ActionCall(identifier, action, evaluatedArgs); } -cstring ActionCall::getObjectName() const { return "ActionCall"; } +cstring ActionCall::getObjectName() const { return "ActionCall"_cs; } const std::vector *ActionCall::getArgs() const { return &args; } @@ -135,7 +137,7 @@ const Ternary *Ternary::evaluate(const Model &model, bool doComplete) const { return new Ternary(getKey(), evaluatedValue, evaluatedMask); } -cstring Ternary::getObjectName() const { return "Ternary"; } +cstring Ternary::getObjectName() const { return "Ternary"_cs; } LPM::LPM(const IR::KeyElement *key, const IR::Expression *value, const IR::Expression *prefixLength) : TableMatch(key), value(value), prefixLength(prefixLength) {} @@ -164,7 +166,7 @@ const LPM *LPM::evaluate(const Model &model, bool doComplete) const { return new LPM(getKey(), evaluatedValue, evaluatedPrefixLength); } -cstring LPM::getObjectName() const { return "LPM"; } +cstring LPM::getObjectName() const { return "LPM"_cs; } Exact::Exact(const IR::KeyElement *key, const IR::Expression *val) : TableMatch(key), value(val) {} @@ -182,7 +184,7 @@ const Exact *Exact::evaluate(const Model &model, bool doComplete) const { return new Exact(getKey(), evaluatedValue); } -cstring Exact::getObjectName() const { return "Exact"; } +cstring Exact::getObjectName() const { return "Exact"_cs; } TableRule::TableRule(TableMatchMap matches, int priority, ActionCall action, int ttl) : matches(std::move(matches)), priority(priority), action(std::move(action)), ttl(ttl) {} @@ -195,7 +197,7 @@ const ActionCall *TableRule::getActionCall() const { return &action; } int TableRule::getTTL() const { return ttl; } -cstring TableRule::getObjectName() const { return "TableRule"; } +cstring TableRule::getObjectName() const { return "TableRule"_cs; } const TableRule *TableRule::evaluate(const Model &model, bool doComplete) const { TableMatchMap evaluatedMatches; @@ -212,7 +214,7 @@ const TableRule *TableRule::evaluate(const Model &model, bool doComplete) const const IR::P4Table *TableConfig::getTable() const { return table; } -cstring TableConfig::getObjectName() const { return "TableConfig"; } +cstring TableConfig::getObjectName() const { return "TableConfig"_cs; } TableConfig::TableConfig(const IR::P4Table *table, std::vector rules) : table(table), rules(std::move(rules)) {} diff --git a/backends/p4tools/modules/testgen/options.cpp b/backends/p4tools/modules/testgen/options.cpp index faa37f665d..518b92ad45 100644 --- a/backends/p4tools/modules/testgen/options.cpp +++ b/backends/p4tools/modules/testgen/options.cpp @@ -17,6 +17,8 @@ namespace P4Tools::P4Testgen { +using namespace P4::literals; + TestgenOptions &TestgenOptions::get() { static TestgenOptions INSTANCE; return INSTANCE; @@ -26,7 +28,7 @@ const char *TestgenOptions::getIncludePath() { P4C_UNIMPLEMENTED("getIncludePath not implemented for P4Testgen."); } -const std::set TestgenOptions::SUPPORTED_STOP_METRICS = {"MAX_NODE_COVERAGE"}; +const std::set TestgenOptions::SUPPORTED_STOP_METRICS = {"MAX_NODE_COVERAGE"_cs}; TestgenOptions::TestgenOptions() : AbstractP4cToolOptions(TOOL_NAME, "Generate packet tests for a P4 program.") { @@ -182,7 +184,7 @@ TestgenOptions::TestgenOptions() registerOption( "--test-backend", "testBackend", [this](const char *arg) { - testBackend = arg; + testBackend = cstring(arg); testBackend = testBackend.toUpper(); return true; }, @@ -254,9 +256,9 @@ TestgenOptions::TestgenOptions() using P4Testgen::PathSelectionPolicy; static std::map const PATH_SELECTION_OPTIONS = { - {"DEPTH_FIRST", PathSelectionPolicy::DepthFirst}, - {"RANDOM_BACKTRACK", PathSelectionPolicy::RandomBacktrack}, - {"GREEDY_STATEMENT_SEARCH", PathSelectionPolicy::GreedyStmtCoverage}, + {"DEPTH_FIRST"_cs, PathSelectionPolicy::DepthFirst}, + {"RANDOM_BACKTRACK"_cs, PathSelectionPolicy::RandomBacktrack}, + {"GREEDY_STATEMENT_SEARCH"_cs, PathSelectionPolicy::GreedyStmtCoverage}, }; auto selectionString = cstring(arg).toUpper(); auto it = PATH_SELECTION_OPTIONS.find(selectionString); @@ -283,8 +285,8 @@ TestgenOptions::TestgenOptions() registerOption( "--track-coverage", "coverageItem", [this](const char *arg) { - static std::set const COVERAGE_OPTIONS = {"STATEMENTS", "TABLE_ENTRIES", - "ACTIONS"}; + static std::set const COVERAGE_OPTIONS = {"STATEMENTS"_cs, "TABLE_ENTRIES"_cs, + "ACTIONS"_cs}; hasCoverageTracking = true; auto selectionString = cstring(arg).toUpper(); auto it = COVERAGE_OPTIONS.find(selectionString); @@ -398,7 +400,7 @@ TestgenOptions::TestgenOptions() registerOption( "--test-name", "testBaseName", [this](const char *arg) { - testBaseName = arg; + testBaseName = cstring(arg); return true; }, "The base name of the tests which are generated."); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/cmd_stepper.cpp b/backends/p4tools/modules/testgen/targets/bmv2/cmd_stepper.cpp index 3cdcaa272b..02d6e13269 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/cmd_stepper.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/cmd_stepper.cpp @@ -80,7 +80,7 @@ void Bmv2V1ModelCmdStepper::initializeTargetEnvironment(ExecutionState &nextStat const auto *nineBitType = IR::Type_Bits::get(9); const auto *oneBitType = IR::Type_Bits::get(1); nextState.set(programInfo.getTargetInputPortVar(), - ToolsVariables::getSymbolicVariable(nineBitType, "bmv2_ingress_port")); + ToolsVariables::getSymbolicVariable(nineBitType, "bmv2_ingress_port"_cs)); // BMv2 implicitly sets the output port to 0. nextState.set(programInfo.getTargetOutputPortVar(), IR::Constant::get(nineBitType, 0)); // Initialize parser_err with no error. @@ -105,7 +105,7 @@ std::optional Bmv2V1ModelCmdStepper::startParserImpl( const IR::P4Parser *parser, ExecutionState &nextState) const { // We need to explicitly map the parser error const auto *errVar = Bmv2V1ModelProgramInfo::getParserParamVar( - parser, programInfo.getParserErrorType(), 3, "parser_error"); + parser, programInfo.getParserErrorType(), 3, "parser_error"_cs); nextState.setParserErrorLabel(errVar); return std::nullopt; @@ -119,7 +119,7 @@ std::map Bmv2V1ModelCmdStepper::getExcept auto gress = programInfo.getGress(parser); const auto *errVar = Bmv2V1ModelProgramInfo::getParserParamVar( - parser, programInfo.getParserErrorType(), 3, "parser_error"); + parser, programInfo.getParserErrorType(), 3, "parser_error"_cs); switch (gress) { case BMV2_INGRESS: diff --git a/backends/p4tools/modules/testgen/targets/bmv2/concolic.cpp b/backends/p4tools/modules/testgen/targets/bmv2/concolic.cpp index a56d32ce7c..2c37bf3e09 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/concolic.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/concolic.cpp @@ -28,6 +28,8 @@ namespace P4Tools::P4Testgen::Bmv2 { +using namespace P4::literals; + static big_int checksum(Bmv2HashAlgorithm algo, const uint8_t *buf, size_t len) { // Pick a checksum according to the algorithm value. switch (algo) { @@ -97,8 +99,8 @@ const ConcolicMethodImpls::ImplList Bmv2Concolic::BMV2_CONCOLIC_METHOD_IMPLS{ /// int) or varbits. /// @param T Must be a type bit /// @param M Must be a type bit - {"*method_hash", - {"result", "algo", "base", "data", "max"}, + {"*method_hash"_cs, + {"result"_cs, "algo"_cs, "base"_cs, "data"_cs, "max"_cs}, [](cstring /*concolicMethodName*/, const IR::ConcolicVariable *var, const ExecutionState & /*state*/, const Model &finalModel, ConcolicVariableMap *resolvedConcolicVariables) { @@ -163,8 +165,8 @@ const ConcolicMethodImpls::ImplList Bmv2Concolic::BMV2_CONCOLIC_METHOD_IMPLS{ * ====================================================================================== */ /// This method is almost equivalent to the hash method. Except that when the checksum output is /// out of bounds, this method assigns the maximum instead of using a modulo operation. - {"*method_checksum", - {"result", "algo", "data"}, + {"*method_checksum"_cs, + {"result"_cs, "algo"_cs, "data"_cs}, [](cstring /*concolicMethodName*/, const IR::ConcolicVariable *var, const ExecutionState & /*state*/, const Model &finalModel, ConcolicVariableMap *resolvedConcolicVariables) { @@ -212,8 +214,8 @@ const ConcolicMethodImpls::ImplList Bmv2Concolic::BMV2_CONCOLIC_METHOD_IMPLS{ } }}, - {"*method_checksum_with_payload", - {"result", "algo", "data"}, + {"*method_checksum_with_payload"_cs, + {"result"_cs, "algo"_cs, "data"_cs}, [](cstring /*concolicMethodName*/, const IR::ConcolicVariable *var, const ExecutionState & /*state*/, const Model &finalModel, ConcolicVariableMap *resolvedConcolicVariables) { diff --git a/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp b/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp index da83307864..7bf3c39d88 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp @@ -47,7 +47,7 @@ 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"); + const auto *annotation = field->getAnnotation("field_list"_cs); if (annotation != nullptr) { // Grab the index of the annotation. auto annoExprs = annotation->expr; @@ -84,16 +84,17 @@ void Bmv2V1ModelExprStepper::processClone(const ExecutionState &state, SmallStepEvaluator::Result &result) { const auto *progInfo = getProgramInfo().checkedTo(); // Pick a clone port var. It must adhere to the constraints of the target. - const auto *cloneInfo = state.getTestObject("clone_infos", "clone_info"); + const auto *cloneInfo = + state.getTestObject("clone_infos"_cs, "clone_info"_cs); const auto *sessionIdExpr = cloneInfo->getSessionId(); const auto &preserveIndex = cloneInfo->getPreserveIndex(); const auto &egressPortVar = programInfo.getTargetOutputPortVar(); const auto &clonePortVar = - ToolsVariables::getSymbolicVariable(egressPortVar->type, "clone_port_var"); + ToolsVariables::getSymbolicVariable(egressPortVar->type, "clone_port_var"_cs); uint64_t recirculateCount = 0; - if (state.hasProperty("recirculate_count")) { - recirculateCount = state.getProperty("recirculate_count"); + if (state.hasProperty("recirculate_count"_cs)) { + recirculateCount = state.getProperty("recirculate_count"_cs); } // Pick a clone port var. It must adhere to the constraints of the target. @@ -119,13 +120,13 @@ void Bmv2V1ModelExprStepper::processClone(const ExecutionState &state, { auto &defaultState = state.clone(); // Delete the stale clone info to free up some space and reset the clone_active flag. - defaultState.deleteTestObjectCategory("clone_infos"); - defaultState.setProperty("clone_active", false); + defaultState.deleteTestObjectCategory("clone_infos"_cs); + defaultState.setProperty("clone_active"_cs, false); // Increment the recirculation count. - defaultState.setProperty("recirculate_count", ++recirculateCount); + defaultState.setProperty("recirculate_count"_cs, ++recirculateCount); // Attach the clone specification for test generation. const auto *defaultCloneInfo = new Bmv2V1ModelCloneSpec(sessionIdExpr, clonePortVar, false); - defaultState.addTestObject("clone_specs", "clone_spec", defaultCloneInfo); + defaultState.addTestObject("clone_specs"_cs, "clone_spec"_cs, defaultCloneInfo); defaultState.popBody(); result->emplace_back(cond, state, defaultState); } @@ -156,7 +157,7 @@ void Bmv2V1ModelExprStepper::processClone(const ExecutionState &state, // information for that, including the exact parameter names of the ingress // block we are in. Just grab the ingress from the programmable blocks. const auto *programmableBlocks = progInfo->getProgrammableBlocks(); - const auto *typeDecl = programmableBlocks->at("Ingress"); + const auto *typeDecl = programmableBlocks->at("Ingress"_cs); const auto *applyBlock = typeDecl->checkedTo(); const auto *params = applyBlock->getApplyParameters(); auto blockIndex = 2; @@ -195,7 +196,7 @@ void Bmv2V1ModelExprStepper::processClone(const ExecutionState &state, // 0. However, fields in the user metadata that have the field_list // annotation and the appropriate index will not be reset. The user // metadata is the third parameter of the parser control. - const auto *paramPath = progInfo->getBlockParam("Parser", 2); + const auto *paramPath = progInfo->getBlockParam("Parser"_cs, 2); resetPreservingFieldList(*cloneState, paramPath, preserveIndex.value()); } @@ -219,13 +220,13 @@ void Bmv2V1ModelExprStepper::processClone(const ExecutionState &state, TESTGEN_UNIMPLEMENTED("Unsupported clone type %1%.", cloneType); } // Attach the clone specification for test generation. - cloneState->addTestObject("clone_specs", "clone_spec", + cloneState->addTestObject("clone_specs"_cs, "clone_spec"_cs, new Bmv2V1ModelCloneSpec(sessionIdExpr, clonePortVar, true)); // Delete the stale clone info to free up some space and reset the clone_active flag. - cloneState->setProperty("clone_active", false); - cloneState->deleteTestObjectCategory("clone_infos"); + cloneState->setProperty("clone_active"_cs, false); + cloneState->deleteTestObjectCategory("clone_infos"_cs); // Increment the recirculation count. - cloneState->setProperty("recirculate_count", ++recirculateCount); + cloneState->setProperty("recirculate_count"_cs, ++recirculateCount); /// Reset the packet buffer for recirculation. cloneState->resetPacketBuffer(); cloneState->replaceTopBody(&cmds); @@ -234,13 +235,13 @@ void Bmv2V1ModelExprStepper::processClone(const ExecutionState &state, void Bmv2V1ModelExprStepper::processRecirculate(const ExecutionState &state, SmallStepEvaluator::Result &result) { - auto instanceType = state.getProperty("recirculate_instance_type"); + auto instanceType = state.getProperty("recirculate_instance_type"_cs); const auto *progInfo = getProgramInfo().checkedTo(); auto &recState = state.clone(); // Check whether the packet needs to be reset. // If that is the case, reset the packet buffer to the calculated input packet. - auto recirculateReset = state.hasProperty("recirculate_reset_pkt"); + auto recirculateReset = state.hasProperty("recirculate_reset_pkt"_cs); if (recirculateReset) { // Reset the packet buffer, which corresponds to the output packet. recState.resetPacketBuffer(); @@ -257,15 +258,15 @@ void Bmv2V1ModelExprStepper::processRecirculate(const ExecutionState &state, IR::Constant::get(&PacketVars::PACKET_SIZE_VAR_TYPE, recState.getPacketBufferSize() / 8); recState.set(packetSizeVar, packetSizeConst); - if (recState.hasProperty("recirculate_index")) { + if (recState.hasProperty("recirculate_index"_cs)) { // Get the index set by the recirculate/resubmit function. Will fail if no index is // set. - auto recirculateIndex = recState.getProperty("recirculate_index"); + auto recirculateIndex = recState.getProperty("recirculate_index"_cs); // This program segment resets the user metadata of the v1model program to 0. // However, fields in the user metadata that have the field_list annotation and the // appropriate index will not be reset. // The user metadata is the third parameter of the parser control. - const auto *paramPath = progInfo->getBlockParam("Parser", 2); + const auto *paramPath = progInfo->getBlockParam("Parser"_cs, 2); resetPreservingFieldList(recState, paramPath, recirculateIndex); } @@ -276,7 +277,7 @@ void Bmv2V1ModelExprStepper::processRecirculate(const ExecutionState &state, recState.set(instanceTypeVar, IR::Constant::get(bitType, instanceType)); // Set recirculate to false to avoid infinite loops. - recState.setProperty("recirculate_active", false); + recState.setProperty("recirculate_active"_cs, false); // "Recirculate" by attaching the sequence again. // Does NOT initialize state or adds new conditions. @@ -336,8 +337,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * ====================================================================================== */ // TODO: Implement extern path expression calls. - {"*method.mark_to_drop", - {"standard_metadata"}, + {"*method.mark_to_drop"_cs, + {"standard_metadata"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -348,7 +349,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // This variable will be processed in the deparser. const auto *portVar = new IR::Member(nineBitType, metadataLabel->ref, "egress_spec"); nextState.set(portVar, IR::Constant::get(nineBitType, BMv2Constants::DROP_PORT)); - nextState.add(*new TraceEvents::Generic("mark_to_drop executed.")); + nextState.add(*new TraceEvents::Generic("mark_to_drop executed."_cs)); nextState.popBody(); result->emplace_back(nextState); }}, @@ -358,8 +359,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * it to the result parameter. * ====================================================================================== */ - {"*method.random", - {"result", "lo", "hi"}, + {"*method.random"_cs, + {"result"_cs, "lo"_cs, "hi"_cs}, [this](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -421,7 +422,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * is likely that your assumption was wrong, and should be reexamined. * ====================================================================================== */ - {"*method.assume", {"check"}, assertAssumeExecute}, + {"*method.assume"_cs, {"check"_cs}, assertAssumeExecute}, /* ====================================================================================== * assert * Calling assert when the argument is true has no effect, except any @@ -445,7 +446,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * same way when assert statements are removed. * ====================================================================================== */ - {"*method.assert", {"check"}, assertAssumeExecute}, + {"*method.assert"_cs, {"check"_cs}, assertAssumeExecute}, /* ====================================================================================== * log_msg * Log user defined messages @@ -453,8 +454,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * or log_msg("Value1 = {}, Value2 = {}",{value1, value2}); * ====================================================================================== */ - {"*method.log_msg", - {"msg", "args"}, + {"*method.log_msg"_cs, + {"msg"_cs, "args"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -470,12 +471,12 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression assignString.cend()); auto &nextState = state.clone(); - nextState.add(*new TraceEvents::Generic(assignString.c_str())); + nextState.add(*new TraceEvents::Generic(assignString)); nextState.popBody(); result->emplace_back(nextState); }}, - {"*method.log_msg", - {"msg"}, + {"*method.log_msg"_cs, + {"msg"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -501,8 +502,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * @param M Must be a type bit * ====================================================================================== */ - {"*method.hash", - {"result", "algo", "base", "data", "max"}, + {"*method.hash"_cs, + {"result"_cs, "algo"_cs, "base"_cs, "data"_cs, "max"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression *receiver, IR::ID &name, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -558,8 +559,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * * ====================================================================================== */ - {"register.read", - {"result", "index"}, + {"register.read"_cs, + {"result"_cs, "index"_cs}, [this](const IR::MethodCallExpression * /*call*/, const IR::Expression *receiver, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -573,8 +574,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // Retrieve the register state from the object store. If it is already present, just // cast the object to the correct class and retrieve the current value according to the // index. If the register has not been added yet, create a new register object. - const auto *registerState = - state.getTestObject("registervalues", externInstance->controlPlaneName(), false); + const auto *registerState = state.getTestObject( + "registervalues"_cs, externInstance->controlPlaneName(), false); const Bmv2V1ModelRegisterValue *registerValue = nullptr; if (registerState != nullptr) { registerValue = registerState->checkedTo(); @@ -582,7 +583,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression const auto *inputValue = programInfo.createTargetUninitialized(readOutput->type, false); registerValue = new Bmv2V1ModelRegisterValue(inputValue); - nextState.addTestObject("registervalues", externInstance->controlPlaneName(), + nextState.addTestObject("registervalues"_cs, externInstance->controlPlaneName(), registerValue); } const IR::Expression *baseExpr = registerValue->getValueAtIndex(index); @@ -633,8 +634,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * * ====================================================================================== */ - {"register.write", - {"index", "value"}, + {"register.write"_cs, + {"index"_cs, "value"_cs}, [this](const IR::MethodCallExpression * /*call*/, const IR::Expression *receiver, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -661,7 +662,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // "Write" to the register by update the internal test object state. If the register // did not exist previously, update it with the value to write as initial value. const auto *registerState = nextState.getTestObject( - "registervalues", externInstance->controlPlaneName(), false); + "registervalues"_cs, externInstance->controlPlaneName(), false); Bmv2V1ModelRegisterValue *registerValue = nullptr; if (registerState != nullptr) { registerValue = new Bmv2V1ModelRegisterValue( @@ -673,7 +674,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression registerValue = new Bmv2V1ModelRegisterValue(writeValue); registerValue->writeToIndex(index, inputValue); } - nextState.addTestObject("registervalues", externInstance->controlPlaneName(), + nextState.addTestObject("registervalues"_cs, externInstance->controlPlaneName(), registerValue); nextState.popBody(); result->emplace_back(nextState); @@ -706,8 +707,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * ====================================================================================== */ // TODO: Count currently has no effect in the symbolic interpreter. - {"counter.count", - {"index"}, + {"counter.count"_cs, + {"index"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -743,7 +744,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * ====================================================================================== */ // TODO: Count currently has no effect in the symbolic interpreter. - {"direct_counter.count", + {"direct_counter.count"_cs, {}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, @@ -783,8 +784,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * range, the final value of result is not specified, * and should be ignored by the caller. * ====================================================================================== */ - {"meter.execute_meter", - {"index", "result"}, + {"meter.execute_meter"_cs, + {"index"_cs, "result"_cs}, [](const IR::MethodCallExpression *call, const IR::Expression *receiver, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -816,7 +817,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // cast the object to the correct class and retrieve the current value according to the // index. If the meter has not been added had, create a new meter object. const auto *meterState = - state.getTestObject("meter_values", externInstance->controlPlaneName(), false); + state.getTestObject("meter_values"_cs, externInstance->controlPlaneName(), false); Bmv2V1ModelMeterValue *meterValue = nullptr; const auto &inputValue = ToolsVariables::getSymbolicVariable( meterResult->type, "meter_value" + std::to_string(call->clone_id)); @@ -829,7 +830,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression meterValue = new Bmv2V1ModelMeterValue(inputValue, false); } meterValue->writeToIndex(index, inputValue); - nextState.addTestObject("meter_values", externInstance->controlPlaneName(), + nextState.addTestObject("meter_values"_cs, externInstance->controlPlaneName(), meterValue); if (meterResult->type->is()) { @@ -881,8 +882,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * color YELLOW, and 2 for color RED (see RFC 2697 * and RFC 2698 for the meaning of these colors). * ====================================================================================== */ - {"direct_meter.read", - {"result"}, + {"direct_meter.read"_cs, + {"result"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression *receiver, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -892,7 +893,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression const auto *externInstance = state.findDecl(receiverPath); const auto *table = progInfo->getTableofDirectExtern(externInstance); const auto *tableEntry = - state.getTestObject("tableconfigs", table->controlPlaneName(), false); + state.getTestObject("tableconfigs"_cs, table->controlPlaneName(), false); auto &nextState = state.clone(); std::vector replacements; @@ -919,7 +920,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // cast the object to the correct class and retrieve the current value according to the // index. If the meter has not been added had, create a new meter object. const auto *meterState = - state.getTestObject("meter_values", externInstance->controlPlaneName(), false); + state.getTestObject("meter_values"_cs, externInstance->controlPlaneName(), false); Bmv2V1ModelMeterValue *meterValue = nullptr; const auto &inputValue = ToolsVariables::getSymbolicVariable( meterResult->type, "meter_value" + std::to_string(call->clone_id)); @@ -932,7 +933,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression meterValue = new Bmv2V1ModelMeterValue(inputValue, true); } meterValue->writeToIndex(IR::Constant::get(IR::Type_Bits::get(1), 0), inputValue); - nextState.addTestObject("meter_values", externInstance->controlPlaneName(), + nextState.addTestObject("meter_values"_cs, externInstance->controlPlaneName(), meterValue); if (meterResult->type->is()) { @@ -978,8 +979,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * value of the receiver parameter. * ====================================================================================== */ - {"*method.digest", - {"receiver", "data"}, + {"*method.digest"_cs, + {"receiver"_cs, "data"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -1024,16 +1025,16 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * v1model architecture documentation (Note 1) for more details. * ====================================================================================== */ - {"*method.clone_preserving_field_list", - {"type", "session", "data"}, + {"*method.clone_preserving_field_list"_cs, + {"type"_cs, "session"_cs, "data"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { // Grab the recirculate count. Stop after more than 1 circulation loop to avoid // infinite recirculation loops. // TODO: Determine the exact count. - if (state.hasProperty("recirculate_count")) { - if (state.getProperty("recirculate_count") > 0) { + if (state.hasProperty("recirculate_count"_cs)) { + if (state.getProperty("recirculate_count"_cs) > 0) { auto &nextState = state.clone(); ::warning("Only single recirculation supported for now. Dropping packet."); auto *dropStmt = new IR::MethodCallStatement( @@ -1066,9 +1067,9 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression sessionIdExpr, static_cast(cloneType), state.clone(), preserveIndex); auto &nextState = state.clone(); - nextState.addTestObject("clone_infos", "clone_info", cloneInfo); + nextState.addTestObject("clone_infos"_cs, "clone_info"_cs, cloneInfo); // Also set clone as active, which will trigger "processClone" in the deparser. - nextState.setProperty("clone_active", true); + nextState.setProperty("clone_active"_cs, true); nextState.popBody(); result->emplace_back(nextState); }}, @@ -1108,8 +1109,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * resubmit_preserving_field_list(2) will only preserve field y. * ====================================================================================== */ - {"*method.resubmit_preserving_field_list", - {"data"}, + {"*method.resubmit_preserving_field_list"_cs, + {"data"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -1118,8 +1119,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // Grab the recirculate count. Stop after more than 1 circulation loop to avoid // infinite recirculation loops. // TODO: Determine the exact count. - if (state.hasProperty("recirculate_count")) { - recirculateCount = state.getProperty("recirculate_count"); + if (state.hasProperty("recirculate_count"_cs)) { + recirculateCount = state.getProperty("recirculate_count"_cs); if (recirculateCount > 0) { ::warning("Only single resubmit supported for now. Dropping packet."); auto *dropStmt = new IR::MethodCallStatement( @@ -1130,19 +1131,19 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression } } // Increment the recirculation count. - nextState.setProperty("recirculate_count", ++recirculateCount); + nextState.setProperty("recirculate_count"_cs, ++recirculateCount); // Recirculate is now active and "processRecirculate" will be triggered in the // deparser. - nextState.setProperty("recirculate_active", true); + nextState.setProperty("recirculate_active"_cs, true); // Grab the index and save it to the execution state. auto index = args->at(0)->expression->checkedTo()->asUint64(); - nextState.setProperty("recirculate_index", index); + nextState.setProperty("recirculate_index"_cs, index); // Resubmit actually uses the original input packet, not the deparsed packet. // We have to reset the packet content to the input packet in "processRecirculate". - nextState.setProperty("recirculate_reset_pkt", true); + nextState.setProperty("recirculate_reset_pkt"_cs, true); // Set the appropriate instance type, which will be processed by // "processRecirculate". - nextState.setProperty("recirculate_instance_type", + nextState.setProperty("recirculate_instance_type"_cs, BMv2Constants::PKT_INSTANCE_TYPE_RESUBMIT); nextState.popBody(); result->emplace_back(nextState); @@ -1169,8 +1170,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * for more details. * ====================================================================================== */ - {"*method.recirculate_preserving_field_list", - {"index"}, + {"*method.recirculate_preserving_field_list"_cs, + {"index"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -1179,8 +1180,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // Grab the recirculate count. Stop after more than 1 circulation loop to avoid // infinite recirculation loops. // TODO: Determine the exact count. - if (state.hasProperty("recirculate_count")) { - recirculateCount = state.getProperty("recirculate_count"); + if (state.hasProperty("recirculate_count"_cs)) { + recirculateCount = state.getProperty("recirculate_count"_cs); if (recirculateCount > 0) { ::warning("Only single recirculation supported for now. Dropping packet."); auto *dropStmt = new IR::MethodCallStatement( @@ -1191,16 +1192,16 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression } } // Increment the recirculation count. - nextState.setProperty("recirculate_count", ++recirculateCount); + nextState.setProperty("recirculate_count"_cs, ++recirculateCount); // Recirculate is now active and "processRecirculate" will be triggered in the // deparser. - nextState.setProperty("recirculate_active", true); + nextState.setProperty("recirculate_active"_cs, true); // Grab the index and save it to the execution state. auto index = args->at(0)->expression->checkedTo()->asUint64(); - nextState.setProperty("recirculate_index", index); + nextState.setProperty("recirculate_index"_cs, index); // Set the appropriate instance type, which will be processed by // "processRecirculate". - nextState.setProperty("recirculate_instance_type", + nextState.setProperty("recirculate_instance_type"_cs, BMv2Constants::PKT_INSTANCE_TYPE_RECIRC); nextState.popBody(); result->emplace_back(nextState); @@ -1214,16 +1215,16 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * type and session parameter values, with empty data. * ====================================================================================== */ - {"*method.clone", - {"type", "session"}, + {"*method.clone"_cs, + {"type"_cs, "session"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { // Grab the recirculate count. Stop after more than 1 circulation loop to avoid // infinite recirculation loops. // TODO: Determine the exact count. - if (state.hasProperty("recirculate_count")) { - if (state.getProperty("recirculate_count") > 0) { + if (state.hasProperty("recirculate_count"_cs)) { + if (state.getProperty("recirculate_count"_cs) > 0) { auto &nextState = state.clone(); ::warning("Only single recirculation supported for now. Dropping packet."); auto *dropStmt = new IR::MethodCallStatement( @@ -1255,9 +1256,9 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression auto *cloneInfo = new Bmv2V1ModelCloneInfo( sessionIdExpr, static_cast(cloneType), state.clone(), std::nullopt); - nextState.addTestObject("clone_infos", "clone_info", cloneInfo); + nextState.addTestObject("clone_infos"_cs, "clone_info"_cs, cloneInfo); // Also set clone as active, which will trigger "processClone" in the deparser. - nextState.setProperty("clone_active", true); + nextState.setProperty("clone_active"_cs, true); nextState.popBody(); result->emplace_back(nextState); }}, @@ -1267,21 +1268,22 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression */ /// Helper extern that processes the parameters set by the recirculate, clone and resubmit /// externs. This extern assume the TM is executed at the end of the deparser. - {"*.invoke_traffic_manager", + {"*.invoke_traffic_manager"_cs, {}, [this](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, const ExecutionState &state, SmallStepEvaluator::Result &result) { // Check whether the clone variant is active. // Clone triggers a branch and slightly different processing. - if (state.hasProperty("clone_active") && state.getProperty("clone_active")) { + if (state.hasProperty("clone_active"_cs) && + state.getProperty("clone_active"_cs)) { processClone(state, result); return; } // Check whether recirculate is active. - if (state.hasProperty("recirculate_active") && - state.getProperty("recirculate_active")) { + if (state.hasProperty("recirculate_active"_cs) && + state.getProperty("recirculate_active"_cs)) { processRecirculate(state, result); return; } @@ -1294,8 +1296,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * Checksum16.get * ====================================================================================== */ - {"Checksum16.get", - {"data"}, + {"Checksum16.get"_cs, + {"data"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, const ExecutionState & /*state*/, SmallStepEvaluator::Result & /*result*/) { @@ -1325,8 +1327,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * constant. * ====================================================================================== */ - {"*method.verify_checksum", - {"condition", "data", "checksum", "algo"}, + {"*method.verify_checksum"_cs, + {"condition"_cs, "data"_cs, "checksum"_cs, "algo"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -1379,7 +1381,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // Try to force the checksum expression to be equal to the result. auto &nextState = state.clone(); const auto *concolicVar = new IR::ConcolicVariable( - checksumValueType, "*method_checksum", checksumArgs, call->clone_id, 0); + checksumValueType, "*method_checksum"_cs, checksumArgs, call->clone_id, 0); std::vector replacements; // We use a guard to enforce that the match condition after the call is true. auto *checksumMatchCond = new IR::Equ(concolicVar, checksumValue); @@ -1391,8 +1393,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // The condition is true and the checksum does not match. { auto &nextState = state.clone(); - auto *concolicVar = new IR::ConcolicVariable(checksumValueType, "*method_checksum", - checksumArgs, call->clone_id, 0); + auto *concolicVar = new IR::ConcolicVariable( + checksumValueType, "*method_checksum"_cs, checksumArgs, call->clone_id, 0); std::vector replacements; auto *checksumMatchCond = new IR::Neq(concolicVar, checksumValue); @@ -1433,8 +1435,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * constant. * ====================================================================================== */ - {"*method.update_checksum", - {"condition", "data", "checksum", "algo"}, + {"*method.update_checksum"_cs, + {"condition"_cs, "data"_cs, "checksum"_cs, "algo"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -1486,7 +1488,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression auto &nextState = state.clone(); const auto *concolicVar = new IR::ConcolicVariable( - checksumVarType, "*method_checksum", checksumArgs, call->clone_id, 0); + checksumVarType, "*method_checksum"_cs, checksumArgs, call->clone_id, 0); nextState.set(checksumVar, concolicVar); nextState.popBody(); result->emplace_back(updateCond, state, nextState); @@ -1509,8 +1511,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * ComputeChecksum control. * ====================================================================================== */ - {"*method.update_checksum_with_payload", - {"condition", "data", "checksum", "algo"}, + {"*method.update_checksum_with_payload"_cs, + {"condition"_cs, "data"_cs, "checksum"_cs, "algo"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -1548,7 +1550,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression auto &nextState = state.clone(); const auto *concolicVar = - new IR::ConcolicVariable(checksumVarType, "*method_checksum_with_payload", + new IR::ConcolicVariable(checksumVarType, "*method_checksum_with_payload"_cs, checksumArgs, call->clone_id, 0); nextState.set(checksumVar, concolicVar); nextState.popBody(); @@ -1572,8 +1574,8 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression * VerifyChecksum control. * ====================================================================================== */ - {"*method.verify_checksum_with_payload", - {"condition", "data", "checksum", "algo"}, + {"*method.verify_checksum_with_payload"_cs, + {"condition"_cs, "data"_cs, "checksum"_cs, "algo"_cs}, [this](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -1614,7 +1616,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression // Try to force the checksum expression to be equal to the result. auto &nextState = state.clone(); const auto *concolicVar = - new IR::ConcolicVariable(checksumValueType, "*method_checksum_with_payload", + new IR::ConcolicVariable(checksumValueType, "*method_checksum_with_payload"_cs, checksumArgs, call->clone_id, 0); // We use a guard to enforce that the match condition after the call is true. auto *checksumMatchCond = new IR::Equ(concolicVar, checksumValue); @@ -1627,7 +1629,7 @@ void Bmv2V1ModelExprStepper::evalExternMethodCall(const IR::MethodCallExpression { auto &nextState = state.clone(); auto *concolicVar = - new IR::ConcolicVariable(checksumValueType, "*method_checksum_with_payload", + new IR::ConcolicVariable(checksumValueType, "*method_checksum_with_payload"_cs, checksumArgs, call->clone_id, 0); std::vector replacements; auto *checksumMatchCond = new IR::Neq(concolicVar, checksumValue); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/map_direct_externs.cpp b/backends/p4tools/modules/testgen/targets/bmv2/map_direct_externs.cpp index 1bb9202adb..ac2f3bd724 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/map_direct_externs.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/map_direct_externs.cpp @@ -51,7 +51,7 @@ std::optional MapDirectExterns::getExternFromT bool MapDirectExterns::preorder(const IR::P4Table *table) { // Try to get extern implementation properties from the table. for (const auto *tableProperty : kTableExternProperties) { - const auto *impl = table->properties->getProperty(tableProperty); + const auto *impl = table->properties->getProperty(cstring(tableProperty)); if (impl != nullptr) { auto declInstanceOpt = getExternFromTableImplementation(impl); if (declInstanceOpt.has_value()) { 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 e5a4c3a4d1..8348b8926a 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/p4_asserts_parser.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/p4_asserts_parser.cpp @@ -304,7 +304,8 @@ const IR::Expression *getIR(std::vector tokens, const IdenitifierTypeMap std::vector combineTokensToNames(const std::vector &inputVector) { std::vector result; Token prevToken = Token(Token::Kind::Unknown, " ", 1); - cstring txt = ""; + std::string txt; + // FIXME: Can try to use absl::Cord for (const auto &input : inputVector) { if (prevToken.is(Token::Kind::Text) && input.is(Token::Kind::Number)) { txt += std::string(input.lexeme()); @@ -324,7 +325,8 @@ std::vector combineTokensToNames(const std::vector &inputVector) { } } else { if (txt.size() > 0) { - result.emplace_back(Token::Kind::Text, txt, txt.size()); + cstring buf(txt); + result.emplace_back(Token::Kind::Text, buf, buf.size()); txt = ""; } result.push_back(input); @@ -346,7 +348,8 @@ std::vector combineTokensToNames(const std::vector &inputVector) { /// [2(Number), 5(number), 5(number), ==(Equal), 0xff(Text)] -> [255(number), ==(Equal), /// 0xff(Number)] - This example is possible only after executing combineTokensToNames std::vector combineTokensToNumbers(std::vector input) { - cstring numb = ""; + // FIXME: Can try to use absl::cord + std::string numb; std::vector result; for (uint64_t i = 0; i < input.size(); i++) { if (input[i].is(Token::Kind::Minus)) { @@ -376,13 +379,15 @@ std::vector combineTokensToNumbers(std::vector input) { if (input[i].is(Token::Kind::Number)) { numb += std::string(input[i].lexeme()); if (i + 1 == input.size()) { - result.emplace_back(Token::Kind::Number, numb, numb.size()); + cstring cstr(numb); + result.emplace_back(Token::Kind::Number, cstr, cstr.size()); numb = ""; continue; } } else { if (numb.size() > 0) { - result.emplace_back(Token::Kind::Number, numb, numb.size()); + cstring cstr(numb); + result.emplace_back(Token::Kind::Number, cstr, cstr.size()); numb = ""; } result.push_back(input[i]); @@ -509,7 +514,7 @@ std::vector AssertsParser::genIRStructs(cstring tableNam } const IR::Node *AssertsParser::postorder(IR::P4Action *actionContext) { - const auto *annotation = actionContext->getAnnotation("action_restriction"); + const auto *annotation = actionContext->getAnnotation("action_restriction"_cs); if (annotation == nullptr) { return actionContext; } @@ -531,7 +536,7 @@ const IR::Node *AssertsParser::postorder(IR::P4Action *actionContext) { } const IR::Node *AssertsParser::postorder(IR::P4Table *tableContext) { - const auto *annotation = tableContext->getAnnotation("entry_restriction"); + const auto *annotation = tableContext->getAnnotation("entry_restriction"_cs); const auto *key = tableContext->getKey(); if (annotation == nullptr || key == nullptr) { return tableContext; @@ -539,7 +544,7 @@ const IR::Node *AssertsParser::postorder(IR::P4Table *tableContext) { IdenitifierTypeMap typeMap; for (const auto *keyElement : tableContext->getKey()->keyElements) { - const auto *nameAnnot = keyElement->getAnnotation("name"); + const auto *nameAnnot = keyElement->getAnnotation("name"_cs); BUG_CHECK(nameAnnot != nullptr, "%1% table key without a name annotation", annotation->name.name); typeMap[nameAnnot->getName()] = keyElement->expression->type; 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 f9e59ebe0a..e65c9fa682 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 @@ -18,19 +18,19 @@ namespace P4Tools::P4Testgen::Bmv2 { RefersToParser::RefersToParser() { setName("RefersToParser"); } const RefersToParser::RefersToBuiltinMap RefersToParser::REFERS_TO_BUILTIN_MAP = {{ - "multicast_group_table", + "multicast_group_table"_cs, { { - "multicast_group_id", - IR::SymbolicVariable(IR::Type_Bits::get(16), "refers_to_multicast_group_id"), + "multicast_group_id"_cs, + IR::SymbolicVariable(IR::Type_Bits::get(16), "refers_to_multicast_group_id"_cs), }, { - "replica.port", - IR::SymbolicVariable(IR::Type_Bits::get(9), "refers_to_replica.port"), + "replica.port"_cs, + IR::SymbolicVariable(IR::Type_Bits::get(9), "refers_to_replica.port"_cs), }, { - "replica.instance", - IR::SymbolicVariable(IR::Type_Bits::get(16), "refers_to_replica.instance"), + "replica.instance"_cs, + IR::SymbolicVariable(IR::Type_Bits::get(16), "refers_to_replica.instance"_cs), }, }, }}; @@ -53,7 +53,7 @@ const IR::SymbolicVariable *RefersToParser::lookUpBuiltinKey( refersAnno); BUG_CHECK(annotationList.at(1)->text == ":" && annotationList.at(2)->text == ":", "'@refers_to' annotation %1% does not have the correct format.", refersAnno); - cstring tableReference = ""; + cstring tableReference = cstring::empty; size_t offset = 3; for (; offset < annotationList.size(); offset++) { auto token = annotationList[offset]->text; @@ -79,7 +79,7 @@ const IR::SymbolicVariable *RefersToParser::lookUpKeyInTable(const IR::P4Table & BUG_CHECK(key != nullptr, "Table %1% does not have any keys.", srcTable); for (const auto *keyElement : key->keyElements) { auto annotations = keyElement->annotations->annotations; - const auto *nameAnnot = keyElement->getAnnotation("name"); + const auto *nameAnnot = keyElement->getAnnotation("name"_cs); // Some hidden tables do not have any key name annotations. BUG_CHECK(nameAnnot != nullptr, "Refers-to table key without a name annotation"); if (keyReference == nameAnnot->getName()) { @@ -110,7 +110,7 @@ const IR::SymbolicVariable *RefersToParser::getReferencedKey(const IR::P4Control const IR::IDeclaration *tableDeclaration = nullptr; for (const auto *decl : *ctrlContext.getDeclarations()) { auto declName = decl->controlPlaneName(); - if (declName.endsWith(tableReference)) { + if (declName.endsWith(tableReference.string_view())) { tableDeclaration = decl; break; } @@ -134,7 +134,7 @@ bool RefersToParser::preorder(const IR::P4Table *tableContext) { auto annotations = keyElement->annotations->annotations; for (const auto *annotation : annotations) { if (annotation->name.name == "refers_to" || annotation->name.name == "referenced_by") { - const auto *nameAnnot = keyElement->getAnnotation("name"); + const auto *nameAnnot = keyElement->getAnnotation("name"_cs); BUG_CHECK(nameAnnot != nullptr, "%1% table key without a name annotation", annotation->name.name); const auto *srcKey = ControlPlaneState::getTableKey( diff --git a/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp index 1674567593..ecc46dea79 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.cpp @@ -17,14 +17,14 @@ P4Tools::P4Testgen::Bmv2::PropagateP4RuntimeTranslation::lookupP4RuntimeAnnotati if (annotatedType == nullptr) { return p4RuntimeAnnotations; } - const auto *p4runtimeAnnotation = annotatedType->getAnnotation("p4runtime_translation"); + const auto *p4runtimeAnnotation = annotatedType->getAnnotation("p4runtime_translation"_cs); if (p4runtimeAnnotation != nullptr) { BUG_CHECK(!p4runtimeAnnotation->needsParsing, "The @p4runtime_translation annotation should have been parsed already."); p4RuntimeAnnotations.push_back(p4runtimeAnnotation); } const auto *p4runtimeTranslationMappings = - annotatedType->getAnnotation("p4runtime_translation_mappings"); + annotatedType->getAnnotation("p4runtime_translation_mappings"_cs); if (p4runtimeTranslationMappings != nullptr) { BUG_CHECK( !p4runtimeTranslationMappings->needsParsing, diff --git a/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h index d13ea270f1..d1b09c4767 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h +++ b/backends/p4tools/modules/testgen/targets/bmv2/p4runtime_translation.h @@ -8,6 +8,8 @@ namespace P4Tools::P4Testgen::Bmv2 { +using namespace P4::literals; + /// Propagates P4Runtime annotations attached to type definitions to the nodes which use these type /// definitions. For now, this is restricted to key elements and action parameters. class PropagateP4RuntimeTranslation : public Transform { diff --git a/backends/p4tools/modules/testgen/targets/bmv2/program_info.cpp b/backends/p4tools/modules/testgen/targets/bmv2/program_info.cpp index a5ff40602b..0e1e0a8780 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/program_info.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/program_info.cpp @@ -244,32 +244,32 @@ const IR::Member *Bmv2V1ModelProgramInfo::getParserParamVar(const IR::P4Parser * const auto *paramString = parser->getApplyParameters()->parameters.at(paramIndex); structLabel = paramString->name; } else { - structLabel = ARCH_SPEC.getParamName("Parser", paramIndex); + structLabel = ARCH_SPEC.getParamName("Parser"_cs, paramIndex); } return new IR::Member(type, new IR::PathExpression(structLabel), paramLabel); } -const ArchSpec Bmv2V1ModelProgramInfo::ARCH_SPEC = - ArchSpec("V1Switch", {// parser Parser(packet_in b, - // out H parsedHdr, - // inout M meta, - // inout standard_metadata_t standard_metadata); - {"Parser", {nullptr, "*hdr", "*meta", "*standard_metadata"}}, - // control VerifyChecksum(inout H hdr, - // inout M meta); - {"VerifyChecksum", {"*hdr", "*meta"}}, - // control Ingress(inout H hdr, - // inout M meta, - // inout standard_metadata_t standard_metadata); - {"Ingress", {"*hdr", "*meta", "*standard_metadata"}}, - // control Egress(inout H hdr, - // inout M meta, - // inout standard_metadata_t standard_metadata); - {"Egress", {"*hdr", "*meta", "*standard_metadata"}}, - // control ComputeChecksum(inout H hdr, - // inout M meta); - {"ComputeChecksum", {"*hdr", "*meta"}}, - // control Deparser(packet_out b, in H hdr); - {"Deparser", {nullptr, "*hdr"}}}); +const ArchSpec Bmv2V1ModelProgramInfo::ARCH_SPEC = ArchSpec( + "V1Switch"_cs, {// parser Parser(packet_in b, + // out H parsedHdr, + // inout M meta, + // inout standard_metadata_t standard_metadata); + {"Parser"_cs, {nullptr, "*hdr"_cs, "*meta"_cs, "*standard_metadata"_cs}}, + // control VerifyChecksum(inout H hdr, + // inout M meta); + {"VerifyChecksum"_cs, {"*hdr"_cs, "*meta"_cs}}, + // control Ingress(inout H hdr, + // inout M meta, + // inout standard_metadata_t standard_metadata); + {"Ingress"_cs, {"*hdr"_cs, "*meta"_cs, "*standard_metadata"_cs}}, + // control Egress(inout H hdr, + // inout M meta, + // inout standard_metadata_t standard_metadata); + {"Egress"_cs, {"*hdr"_cs, "*meta"_cs, "*standard_metadata"_cs}}, + // control ComputeChecksum(inout H hdr, + // inout M meta); + {"ComputeChecksum"_cs, {"*hdr"_cs, "*meta"_cs}}, + // control Deparser(packet_out b, in H hdr); + {"Deparser"_cs, {nullptr, "*hdr"_cs}}}); } // namespace P4Tools::P4Testgen::Bmv2 diff --git a/backends/p4tools/modules/testgen/targets/bmv2/table_stepper.cpp b/backends/p4tools/modules/testgen/targets/bmv2/table_stepper.cpp index 31d65bf815..c61fb54e3a 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/table_stepper.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/table_stepper.cpp @@ -34,6 +34,8 @@ namespace P4Tools::P4Testgen::Bmv2 { +using namespace P4::literals; + const IR::Expression *Bmv2V1ModelTableStepper::computeTargetMatchType( const TableUtils::KeyProperties &keyProperties, TableMatchMap *matches, const IR::Expression *hitCondition) { @@ -140,7 +142,7 @@ void Bmv2V1ModelTableStepper::evalTableActionProfile( // TODO: Should we check if we exceed the maximum number of possible profile entries? actionProfile->addToActionMap(actionName, ctrlPlaneArgs); // Update the action profile in the execution state. - nextState.addTestObject("action_profile", actionProfile->getObjectName(), actionProfile); + nextState.addTestObject("action_profile"_cs, actionProfile->getObjectName(), actionProfile); // We add the arguments to our action call, effectively creating a const entry call. auto *synthesizedAction = tableAction->clone(); @@ -154,8 +156,8 @@ void Bmv2V1ModelTableStepper::evalTableActionProfile( // Add the action profile to the table. // This implies a slightly different implementation to usual control plane table behavior. - tableConfig->addTableProperty("action_profile", actionProfile); - nextState.addTestObject("tableconfigs", table->controlPlaneName(), tableConfig); + tableConfig->addTableProperty("action_profile"_cs, actionProfile); + nextState.addTestObject("tableconfigs"_cs, table->controlPlaneName(), tableConfig); // Update all the tracking variables for tables. std::vector replacements; @@ -222,9 +224,10 @@ void Bmv2V1ModelTableStepper::evalTableActionSelector( bmv2V1ModelProperties.actionSelector->getSelectorDecl(), actionProfile); // Update the action profile in the execution state. - nextState.addTestObject("action_profile", actionProfile->getObjectName(), actionProfile); + nextState.addTestObject("action_profile"_cs, actionProfile->getObjectName(), actionProfile); // Update the action selector in the execution state. - nextState.addTestObject("action_selector", actionSelector->getObjectName(), actionSelector); + nextState.addTestObject("action_selector"_cs, actionSelector->getObjectName(), + actionSelector); // We add the arguments to our action call, effectively creating a const entry call. auto *synthesizedAction = tableAction->clone(); @@ -237,11 +240,11 @@ void Bmv2V1ModelTableStepper::evalTableActionSelector( auto *tableConfig = new TableConfig(table, {tableRule}); // Add the action profile to the table. This signifies a slightly different implementation. - tableConfig->addTableProperty("action_profile", actionProfile); + tableConfig->addTableProperty("action_profile"_cs, actionProfile); // Add the action selector to the table. This signifies a slightly different implementation. - tableConfig->addTableProperty("action_selector", actionSelector); + tableConfig->addTableProperty("action_selector"_cs, actionSelector); - nextState.addTestObject("tableconfigs", table->controlPlaneName(), tableConfig); + nextState.addTestObject("tableconfigs"_cs, table->controlPlaneName(), tableConfig); // Update all the tracking variables for tables. std::vector replacements; @@ -267,7 +270,7 @@ void Bmv2V1ModelTableStepper::evalTableActionSelector( } bool Bmv2V1ModelTableStepper::checkForActionProfile() { - const auto *impl = table->properties->getProperty("implementation"); + const auto *impl = table->properties->getProperty("implementation"_cs); if (impl == nullptr) { return false; } @@ -295,7 +298,7 @@ bool Bmv2V1ModelTableStepper::checkForActionProfile() { } const auto *testObject = - state->getTestObject("action_profile", implDecl->controlPlaneName(), false); + state->getTestObject("action_profile"_cs, implDecl->controlPlaneName(), false); if (testObject == nullptr) { // This means, for every possible control plane entry (and with that, new execution state) // add the generated action profile. @@ -309,7 +312,7 @@ bool Bmv2V1ModelTableStepper::checkForActionProfile() { } bool Bmv2V1ModelTableStepper::checkForActionSelector() { - const auto *impl = table->properties->getProperty("implementation"); + const auto *impl = table->properties->getProperty("implementation"_cs); if (impl == nullptr) { return false; } @@ -338,7 +341,7 @@ bool Bmv2V1ModelTableStepper::checkForActionSelector() { // Treat action selectors like action profiles for now. // The behavioral model P4Runtime is unclear how to configure action selectors. const auto *testObject = - state->getTestObject("action_profile", selectorDecl->controlPlaneName(), false); + state->getTestObject("action_profile"_cs, selectorDecl->controlPlaneName(), false); if (testObject == nullptr) { // This means, for every possible control plane entry (and with that, new execution state) // add the generated action profile. diff --git a/backends/p4tools/modules/testgen/targets/bmv2/target.cpp b/backends/p4tools/modules/testgen/targets/bmv2/target.cpp index a77168437d..6882b43fe3 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/target.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/target.cpp @@ -48,7 +48,7 @@ CompilerResultOrError Bmv2V1ModelTestgenTarget::runCompilerImpl( } /// After the front end, get the P4Runtime API for the V1model architecture. - auto p4runtimeApi = P4::P4RuntimeSerializer::get()->generateP4Runtime(program, "v1model"); + auto p4runtimeApi = P4::P4RuntimeSerializer::get()->generateP4Runtime(program, "v1model"_cs); if (::errorCount() > 0) { return std::nullopt; diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/small-step/p4_asserts_parser_test.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/small-step/p4_asserts_parser_test.cpp index 5945cfb49b..a0ba39f3a9 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/small-step/p4_asserts_parser_test.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/small-step/p4_asserts_parser_test.cpp @@ -30,6 +30,8 @@ extern const char *sourcePath; extern const char *buildPath; namespace Test { +using namespace P4::literals; + class P4AssertsParserTest : public P4ToolsTest {}; class P4TestOptions : public CompilerOptions { public: @@ -54,11 +56,11 @@ ConstraintsVector loadExample(const char *curFile, bool flag) { auto *originalEnv = getenv("P4C_16_INCLUDE_PATH"); setenv("P4C_16_INCLUDE_PATH", includeDir.c_str(), 1); const IR::P4Program *program = nullptr; - options.file = sourcePath; + options.file = cstring(sourcePath); options.file += curFile; if (access(options.file, 0) != 0) { // Subpath for bf-p4c-compilers. - options.file = sourcePath; + options.file = cstring(sourcePath); options.file += curFile; } program = P4::parseP4File(options); @@ -98,9 +100,9 @@ TEST_F(P4AssertsParserTest, Restrictions) { ASSERT_EQ(parsingResult.size(), (unsigned long)3); { const auto &expr1 = P4Tools::ToolsVariables::getSymbolicVariable( - IR::Type_Bits::get(8), "ingress.ternary_table_mask_h.h.a1"); + IR::Type_Bits::get(8), "ingress.ternary_table_mask_h.h.a1"_cs); const auto &expr2 = P4Tools::ToolsVariables::getSymbolicVariable( - IR::Type_Bits::get(8), "ingress.ternary_table_lpm_prefix_h.h.a1"); + IR::Type_Bits::get(8), "ingress.ternary_table_lpm_prefix_h.h.a1"_cs); const auto *const1 = IR::Constant::get(IR::Type_Bits::get(8), 0); const auto *const2 = IR::Constant::get(IR::Type_Bits::get(8), 64); const auto *operation = @@ -109,14 +111,14 @@ TEST_F(P4AssertsParserTest, Restrictions) { } { const auto &expr1 = P4Tools::ToolsVariables::getSymbolicVariable( - IR::Type_Bits::get(8), "ingress.ternary_table_key_h.h.a1"); + IR::Type_Bits::get(8), "ingress.ternary_table_key_h.h.a1"_cs); const auto *const1 = IR::Constant::get(IR::Type_Bits::get(8), 0); const auto *operation1 = new IR::Neq(expr1, const1); ASSERT_TRUE(parsingResult[1]->equiv(*operation1)); } { const auto &expr1 = P4Tools::ToolsVariables::getSymbolicVariable( - IR::Type_Bits::get(8), "ingress.ternary_table_key_h.h.a"); + IR::Type_Bits::get(8), "ingress.ternary_table_key_h.h.a"_cs); const auto *const2 = IR::Constant::get(IR::Type_Bits::get(8), 255); const auto *operation2 = new IR::Neq(expr1, const2); ASSERT_TRUE(parsingResult[2]->equiv(*operation2)); @@ -128,10 +130,10 @@ TEST_F(P4AssertsParserTest, RestrictionMiddleblockReferToInTable) { "backends/p4tools/modules/testgen/targets/bmv2/test/p4-programs/bmv2_restrictions_2.p4", false); ASSERT_EQ(parsingResult.size(), (unsigned long)3); - const auto &expr1 = P4Tools::ToolsVariables::getSymbolicVariable(IR::Type_Bits::get(8), - "ingress.table_1_key_h.h.a"); - const auto &expr2 = P4Tools::ToolsVariables::getSymbolicVariable(IR::Type_Bits::get(8), - "ingress.table_2_key_h.h.b"); + const auto &expr1 = P4Tools::ToolsVariables::getSymbolicVariable( + IR::Type_Bits::get(8), "ingress.table_1_key_h.h.a"_cs); + const auto &expr2 = P4Tools::ToolsVariables::getSymbolicVariable( + IR::Type_Bits::get(8), "ingress.table_2_key_h.h.b"_cs); const auto *operation = new IR::Equ(expr1, expr2); ASSERT_TRUE(parsingResult[0]->equiv(*operation)); } @@ -142,9 +144,9 @@ TEST_F(P4AssertsParserTest, RestrictionMiddleblockReferToInAction) { false); ASSERT_EQ(parsingResult.size(), (unsigned long)3); const auto *expr1 = P4Tools::ToolsVariables::getSymbolicVariable( - IR::Type_Bits::get(8), "ingress.table_1_ingress.MyAction1_arg_input_val"); - const auto *expr2 = P4Tools::ToolsVariables::getSymbolicVariable(IR::Type_Bits::get(8), - "ingress.table_1_key_h.h.a"); + IR::Type_Bits::get(8), "ingress.table_1_ingress.MyAction1_arg_input_val"_cs); + const auto *expr2 = P4Tools::ToolsVariables::getSymbolicVariable( + IR::Type_Bits::get(8), "ingress.table_1_key_h.h.a"_cs); auto *operation = new IR::Equ(expr1, expr2); ASSERT_TRUE(parsingResult[1]->equiv(*operation)); } diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/small-step/reachability.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/small-step/reachability.cpp index 2cebe93857..4a51c644a1 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/small-step/reachability.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/small-step/reachability.cpp @@ -24,6 +24,8 @@ namespace Test { +using namespace P4::literals; + class P4ReachabilityOptions : public CompilerOptions { public: virtual ~P4ReachabilityOptions() = default; @@ -52,7 +54,7 @@ ReturnedInfo loadExampleForReachability(const char *curFile) { auto *originalEnv = getenv("P4C_16_INCLUDE_PATH"); setenv("P4C_16_INCLUDE_PATH", includeDir.c_str(), 1); const IR::P4Program *program = nullptr; - options.file = sourcePath; + options.file = cstring(sourcePath); options.file += curFile; program = P4::parseP4File(options); if (originalEnv == nullptr) { @@ -109,13 +111,13 @@ TEST_F(P4CReachability, testParserStatesAndAnnotations) { const auto *program = std::get<0>(result); ASSERT_TRUE(program); const auto *dcg = std::get<1>(result); - const auto *parser = getSpecificNode(program, "ParserI"); + const auto *parser = getSpecificNode(program, "ParserI"_cs); ASSERT_TRUE(parser); // Parser ParserI is reachable. ASSERT_TRUE(dcg->isReachable(program, parser)); - const auto *ingress = getSpecificNode(program, "IngressI"); + const auto *ingress = getSpecificNode(program, "IngressI"_cs); ASSERT_TRUE(ingress); - const auto *engress = getSpecificNode(program, "EgressI"); + const auto *engress = getSpecificNode(program, "EgressI"_cs); ASSERT_TRUE(engress); // IngressI is reachable. ASSERT_TRUE(dcg->isReachable(program, ingress)); @@ -126,10 +128,10 @@ TEST_F(P4CReachability, testParserStatesAndAnnotations) { // IgressI is not reachable from EngressI. ASSERT_TRUE(!dcg->isReachable(engress, ingress)); const auto *indirect = - ingress->to()->getDeclByName("indirect_0")->to(); + ingress->to()->getDeclByName("indirect_0"_cs)->to(); ASSERT_TRUE(indirect); const auto *indirectWs = - ingress->to()->getDeclByName("indirect_ws_0")->to(); + ingress->to()->getDeclByName("indirect_ws_0"_cs)->to(); ASSERT_TRUE(indirectWs); // Inderect table is reachable from ingress ASSERT_TRUE(dcg->isReachable(ingress, indirect)); @@ -164,7 +166,7 @@ TEST_F(P4CReachability, testLoops) { const IR::Node *getFromHash(const P4Tools::ReachabilityHashType &hash, const char *name) { CHECK_NULL(name); - auto s = hash.find(name); + auto s = hash.find(cstring(name)); if (s == hash.end()) { std::string nm = name; nm += "_table"; diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/test_backend/ptf.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/test_backend/ptf.cpp index 39fcaf0726..915edf4f6a 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/test_backend/ptf.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/test_backend/ptf.cpp @@ -15,6 +15,8 @@ namespace Test { +using namespace P4::literals; + using ::testing::HasSubstr; TableConfig PTFTest::getForwardTableConfig() { @@ -22,13 +24,13 @@ TableConfig PTFTest::getForwardTableConfig() { IR::Constant::get(IR::Type_Bits::get(9), big_int("0x2"))); std::vector args({port}); const auto hit = ActionCall( - "SwitchIngress.hit", + "SwitchIngress.hit"_cs, new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), args); auto const *exactMatch = new Exact( new IR::KeyElement(new IR::PathExpression("key"), new IR::PathExpression("exact")), IR::Constant::get(IR::Type_Bits::get(48), big_int("0x222222222222"))); - auto matches = TableMatchMap({{"hdr.ethernet.dst_addr", exactMatch}}); + auto matches = TableMatchMap({{"hdr.ethernet.dst_addr"_cs, exactMatch}}); return TableConfig(new IR::P4Table("table", new IR::TableProperties()), {TableRule(matches, TestSpec::NO_PRIORITY, hit, 0)}); @@ -46,7 +48,7 @@ TableConfig PTFTest::getIPRouteTableConfig() { IR::Constant::get(IR::Type_Bits::get(9), big_int("0x2"))); const auto args = std::vector({srcAddr, dstAddr, dstPort}); const auto nat = ActionCall( - "SwitchIngress.nat", + "SwitchIngress.nat"_cs, new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), args); const auto *dipExactMatch = new Exact( @@ -57,7 +59,7 @@ TableConfig PTFTest::getIPRouteTableConfig() { new IR::KeyElement(new IR::PathExpression("key"), new IR::PathExpression("exact")), IR::Constant::get(IR::Type_Bits::get(16), big_int("0x0"))); - TableMatchMap matches({{"vrf", vrfExactMatch}, {"hdr.ipv4.dst_addr", dipExactMatch}}); + TableMatchMap matches({{"vrf"_cs, vrfExactMatch}, {"hdr.ipv4.dst_addr"_cs, dipExactMatch}}); return TableConfig(new IR::P4Table("table", new IR::TableProperties()), {TableRule(matches, TestSpec::NO_PRIORITY, nat, 0)}); @@ -80,11 +82,11 @@ TEST_F(PTFTest, Ptf01) { const auto fwdConfig = getForwardTableConfig(); auto testSpec = TestSpec(ingressPacket, egressPacket, {}); - testSpec.addTestObject("tables", "SwitchIngress.forward", &fwdConfig); + testSpec.addTestObject("tables"_cs, "SwitchIngress.forward"_cs, &fwdConfig); - TestBackendConfiguration testBackendConfiguration{"test01", 1, "test01", 1}; + TestBackendConfiguration testBackendConfiguration{"test01"_cs, 1, "test01", 1}; auto testWriter = PTF(testBackendConfiguration); - testWriter.writeTestToFile(&testSpec, "", 1, 0); + testWriter.writeTestToFile(&testSpec, cstring::empty, 1, 0); } /// Create a test spec with two Exact matches and print an ptf test. @@ -110,12 +112,12 @@ TEST_F(PTFTest, Ptf02) { const auto ipRouteConfig = getIPRouteTableConfig(); auto testSpec = TestSpec(ingressPacket, egressPacket, {}); - testSpec.addTestObject("tables", "SwitchIngress.forward", &fwdConfig); - testSpec.addTestObject("tables", "SwitchIngress.ipRoute", &ipRouteConfig); + testSpec.addTestObject("tables"_cs, "SwitchIngress.forward"_cs, &fwdConfig); + testSpec.addTestObject("tables"_cs, "SwitchIngress.ipRoute"_cs, &ipRouteConfig); - TestBackendConfiguration testBackendConfiguration{"test02", 1, "test02", 2}; + TestBackendConfiguration testBackendConfiguration{"test02"_cs, 1, "test02", 2}; auto testWriter = PTF(testBackendConfiguration); - testWriter.writeTestToFile(&testSpec, "", 2, 0); + testWriter.writeTestToFile(&testSpec, cstring::empty, 2, 0); } TableConfig PTFTest::gettest1TableConfig() { @@ -126,15 +128,15 @@ TableConfig PTFTest::gettest1TableConfig() { IR::Constant::get(IR::Type_Bits::get(9), big_int("0x2"))); const auto args = std::vector({val, port}); const auto setb1 = ActionCall( - "setb1", new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), - args); + "setb1"_cs, + new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), args); const auto *f1TernaryMatch = new Ternary( new IR::KeyElement(new IR::PathExpression("key"), new IR::PathExpression("ternary")), IR::Constant::get(IR::Type_Bits::get(32), big_int("0xABCD0101")), IR::Constant::get(IR::Type_Bits::get(32), big_int("0xFFFF0000"))); - TableMatchMap matches({{"data.f1", f1TernaryMatch}}); + TableMatchMap matches({{"data.f1"_cs, f1TernaryMatch}}); return TableConfig(new IR::P4Table("table", new IR::TableProperties()), {TableRule(matches, TestSpec::LOW_PRIORITY, setb1, 0)}); @@ -157,12 +159,12 @@ TEST_F(PTFTest, Ptf03) { const auto test1Config = gettest1TableConfig(); auto testSpec = TestSpec(ingressPacket, egressPacket, {}); - testSpec.addTestObject("tables", "test1", &test1Config); + testSpec.addTestObject("tables"_cs, "test1"_cs, &test1Config); - TestBackendConfiguration testBackendConfiguration{"test03", 1, "test03", 3}; + TestBackendConfiguration testBackendConfiguration{"test03"_cs, 1, "test03", 3}; auto testWriter = PTF(testBackendConfiguration); try { - testWriter.writeTestToFile(&testSpec, "", 3, 0); + testWriter.writeTestToFile(&testSpec, cstring::empty, 3, 0); } catch (const Util::CompilerBug &e) { EXPECT_THAT(e.what(), HasSubstr("Unimplemented for Ternary FieldMatch")); } @@ -176,8 +178,8 @@ TableConfig PTFTest::gettest1TableConfig2() { IR::Constant::get(IR::Type_Bits::get(9), big_int("0x2"))); const auto args = std::vector({val, port}); const auto setb1 = ActionCall( - "setb1", new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), - args); + "setb1"_cs, + new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), args); const auto *h1ExactMatch = new Exact( new IR::KeyElement(new IR::PathExpression("key"), new IR::PathExpression("exact")), @@ -197,12 +199,12 @@ TableConfig PTFTest::gettest1TableConfig2() { IR::Constant::get(IR::Type_Bits::get(32), big_int("0xABCDD00D")), IR::Constant::get(IR::Type_Bits::get(32), big_int("0x0000FFFF"))); - TableMatchMap matches1({{"data.f1", f1TernaryMatch}}); + TableMatchMap matches1({{"data.f1"_cs, f1TernaryMatch}}); - TableMatchMap matches2({{"data.h1", h1ExactMatch}, - {"data.f1", f1TernaryMatch}, - {"data.b1", b1ExactMatch}, - {"data.f2", f2TernaryMatch}}); + TableMatchMap matches2({{"data.h1"_cs, h1ExactMatch}, + {"data.f1"_cs, f1TernaryMatch}, + {"data.b1"_cs, b1ExactMatch}, + {"data.f2"_cs, f2TernaryMatch}}); return TableConfig(new IR::P4Table("table", new IR::TableProperties()), {TableRule(matches1, TestSpec::LOW_PRIORITY, setb1, 0), @@ -226,12 +228,12 @@ TEST_F(PTFTest, Ptf04) { const auto test1Config = gettest1TableConfig2(); auto testSpec = TestSpec(ingressPacket, egressPacket, {}); - testSpec.addTestObject("tables", "test1", &test1Config); + testSpec.addTestObject("tables"_cs, "test1"_cs, &test1Config); - TestBackendConfiguration testBackendConfiguration{"test04", 1, "test04", 4}; + TestBackendConfiguration testBackendConfiguration{"test04"_cs, 1, "test04", 4}; auto testWriter = PTF(testBackendConfiguration); try { - testWriter.writeTestToFile(&testSpec, "", 4, 0); + testWriter.writeTestToFile(&testSpec, cstring::empty, 4, 0); } catch (const Util::CompilerBug &e) { EXPECT_THAT(e.what(), HasSubstr("Unimplemented for Ternary FieldMatch")); } diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/test_backend/stf.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/test_backend/stf.cpp index 4fce0fcc60..5ead04c78a 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/test_backend/stf.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/test_backend/stf.cpp @@ -15,6 +15,8 @@ namespace Test { +using namespace P4::literals; + using ::testing::HasSubstr; TableConfig STFTest::getForwardTableConfig() { @@ -22,13 +24,13 @@ TableConfig STFTest::getForwardTableConfig() { IR::Constant::get(IR::Type_Bits::get(9), big_int("0x2"))); std::vector args({port}); const auto hit = ActionCall( - "SwitchIngress.hit", + "SwitchIngress.hit"_cs, new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), args); auto const *exactMatch = new Exact( new IR::KeyElement(new IR::PathExpression("key"), new IR::PathExpression("exact")), IR::Constant::get(IR::Type_Bits::get(48), big_int("0x222222222222"))); - auto matches = TableMatchMap({{"hdr.ethernet.dst_addr", exactMatch}}); + auto matches = TableMatchMap({{"hdr.ethernet.dst_addr"_cs, exactMatch}}); return TableConfig(new IR::P4Table("table", new IR::TableProperties()), {TableRule(matches, TestSpec::NO_PRIORITY, hit, 0)}); @@ -46,7 +48,7 @@ TableConfig STFTest::getIPRouteTableConfig() { IR::Constant::get(IR::Type_Bits::get(9), big_int("0x2"))); const auto args = std::vector({srcAddr, dstAddr, dstPort}); const auto nat = ActionCall( - "SwitchIngress.nat", + "SwitchIngress.nat"_cs, new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), args); const auto *dipExactMatch = new Exact( @@ -57,7 +59,7 @@ TableConfig STFTest::getIPRouteTableConfig() { new IR::KeyElement(new IR::PathExpression("key"), new IR::PathExpression("exact")), IR::Constant::get(IR::Type_Bits::get(16), big_int("0x0"))); - TableMatchMap matches({{"vrf", vrfExactMatch}, {"hdr.ipv4.dst_addr", dipExactMatch}}); + TableMatchMap matches({{"vrf"_cs, vrfExactMatch}, {"hdr.ipv4.dst_addr"_cs, dipExactMatch}}); return TableConfig(new IR::P4Table("table", new IR::TableProperties()), {TableRule(matches, TestSpec::NO_PRIORITY, nat, 0)}); @@ -80,11 +82,11 @@ TEST_F(STFTest, Stf01) { const auto fwdConfig = getForwardTableConfig(); auto testSpec = TestSpec(ingressPacket, egressPacket, {}); - testSpec.addTestObject("tables", "SwitchIngress.forward", &fwdConfig); + testSpec.addTestObject("tables"_cs, "SwitchIngress.forward"_cs, &fwdConfig); - TestBackendConfiguration testBackendConfiguration{"test01", 1, "test01", 1}; + TestBackendConfiguration testBackendConfiguration{"test01"_cs, 1, "test01", 1}; auto testWriter = STF(testBackendConfiguration); - testWriter.writeTestToFile(&testSpec, "", 1, 0); + testWriter.writeTestToFile(&testSpec, cstring::empty, 1, 0); } /// Create a test spec with two Exact matches and print an stf test. @@ -110,12 +112,12 @@ TEST_F(STFTest, Stf02) { const auto ipRouteConfig = getIPRouteTableConfig(); auto testSpec = TestSpec(ingressPacket, egressPacket, {}); - testSpec.addTestObject("tables", "SwitchIngress.forward", &fwdConfig); - testSpec.addTestObject("tables", "SwitchIngress.ipRoute", &ipRouteConfig); + testSpec.addTestObject("tables"_cs, "SwitchIngress.forward"_cs, &fwdConfig); + testSpec.addTestObject("tables"_cs, "SwitchIngress.ipRoute"_cs, &ipRouteConfig); - TestBackendConfiguration testBackendConfiguration{"test02", 1, "test02", 2}; + TestBackendConfiguration testBackendConfiguration{"test02"_cs, 1, "test02", 2}; auto testWriter = STF(testBackendConfiguration); - testWriter.writeTestToFile(&testSpec, "", 2, 0); + testWriter.writeTestToFile(&testSpec, cstring::empty, 2, 0); } TableConfig STFTest::gettest1TableConfig() { @@ -126,15 +128,15 @@ TableConfig STFTest::gettest1TableConfig() { IR::Constant::get(IR::Type_Bits::get(9), big_int("0x2"))); const auto args = std::vector({val, port}); const auto setb1 = ActionCall( - "setb1", new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), - args); + "setb1"_cs, + new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), args); const auto *f1TernaryMatch = new Ternary( new IR::KeyElement(new IR::PathExpression("key"), new IR::PathExpression("ternary")), IR::Constant::get(IR::Type_Bits::get(32), big_int("0xABCD0101")), IR::Constant::get(IR::Type_Bits::get(32), big_int("0xFFFF0000"))); - TableMatchMap matches({{"data.f1", f1TernaryMatch}}); + TableMatchMap matches({{"data.f1"_cs, f1TernaryMatch}}); return TableConfig(new IR::P4Table("table", new IR::TableProperties()), {TableRule(matches, TestSpec::LOW_PRIORITY, setb1, 0)}); @@ -157,12 +159,12 @@ TEST_F(STFTest, Stf03) { const auto test1Config = gettest1TableConfig(); auto testSpec = TestSpec(ingressPacket, egressPacket, {}); - testSpec.addTestObject("tables", "test1", &test1Config); + testSpec.addTestObject("tables"_cs, "test1"_cs, &test1Config); - TestBackendConfiguration testBackendConfiguration{"test03", 1, "test03", 3}; + TestBackendConfiguration testBackendConfiguration{"test03"_cs, 1, "test03", 3}; auto testWriter = STF(testBackendConfiguration); try { - testWriter.writeTestToFile(&testSpec, "", 3, 0); + testWriter.writeTestToFile(&testSpec, cstring::empty, 3, 0); } catch (const Util::CompilerBug &e) { EXPECT_THAT(e.what(), HasSubstr("Unimplemented for Ternary FieldMatch")); } @@ -176,8 +178,8 @@ TableConfig STFTest::gettest1TableConfig2() { IR::Constant::get(IR::Type_Bits::get(9), big_int("0x2"))); const auto args = std::vector({val, port}); const auto setb1 = ActionCall( - "setb1", new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), - args); + "setb1"_cs, + new IR::P4Action("dummy", new IR::ParameterList({}, {}), new IR::BlockStatement()), args); const auto *h1ExactMatch = new Exact( new IR::KeyElement(new IR::PathExpression("key"), new IR::PathExpression("exact")), @@ -197,12 +199,12 @@ TableConfig STFTest::gettest1TableConfig2() { IR::Constant::get(IR::Type_Bits::get(32), big_int("0xABCDD00D")), IR::Constant::get(IR::Type_Bits::get(32), big_int("0x0000FFFF"))); - TableMatchMap matches1({{"data.f1", f1TernaryMatch}}); + TableMatchMap matches1({{"data.f1"_cs, f1TernaryMatch}}); - TableMatchMap matches2({{"data.h1", h1ExactMatch}, - {"data.f1", f1TernaryMatch}, - {"data.b1", b1ExactMatch}, - {"data.f2", f2TernaryMatch}}); + TableMatchMap matches2({{"data.h1"_cs, h1ExactMatch}, + {"data.f1"_cs, f1TernaryMatch}, + {"data.b1"_cs, b1ExactMatch}, + {"data.f2"_cs, f2TernaryMatch}}); return TableConfig(new IR::P4Table("table", new IR::TableProperties()), {TableRule(matches1, TestSpec::LOW_PRIORITY, setb1, 0), @@ -226,12 +228,12 @@ TEST_F(STFTest, Stf04) { const auto test1Config = gettest1TableConfig2(); auto testSpec = TestSpec(ingressPacket, egressPacket, {}); - testSpec.addTestObject("tables", "test1", &test1Config); + testSpec.addTestObject("tables"_cs, "test1"_cs, &test1Config); - TestBackendConfiguration testBackendConfiguration{"test04", 1, "test04", 4}; + TestBackendConfiguration testBackendConfiguration{"test04"_cs, 1, "test04", 4}; auto testWriter = STF(testBackendConfiguration); try { - testWriter.writeTestToFile(&testSpec, "", 4, 0); + testWriter.writeTestToFile(&testSpec, cstring::empty, 4, 0); } catch (const Util::CompilerBug &e) { EXPECT_THAT(e.what(), HasSubstr("Unimplemented for Ternary FieldMatch")); } diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/api_test.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/api_test.cpp index af9def86b1..e8cc38ff6b 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/api_test.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/api_test.cpp @@ -10,6 +10,8 @@ namespace Test { +using namespace P4::literals; + TEST(P4TestgenLibrary, GeneratesCorrectProtobufIrTest) { std::stringstream streamTest; streamTest << R"p4( @@ -56,11 +58,11 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa auto source = P4_SOURCE(P4Headers::V1MODEL, streamTest.str().c_str()); auto compilerOptions = P4CContextWithOptions::get().options(); - compilerOptions.target = "bmv2"; - compilerOptions.arch = "v1model"; + compilerOptions.target = "bmv2"_cs; + compilerOptions.arch = "v1model"_cs; auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get(); - testgenOptions.testBackend = "PROTOBUF_IR"; - testgenOptions.testBaseName = "dummy"; + testgenOptions.testBackend = "PROTOBUF_IR"_cs; + testgenOptions.testBaseName = "dummy"_cs; // Create a bespoke packet for the Ethernet extract call. testgenOptions.minPktSize = 112; testgenOptions.maxPktSize = 112; @@ -79,7 +81,7 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa EXPECT_THAT(protobufIrTest->getFormattedTest(), ::testing::HasSubstr(R"(input_packet)")); } /// Now try running again with the test back end set to Protobuf. The result should be the same. - testgenOptions.testBackend = "PROTOBUF"; + testgenOptions.testBackend = "PROTOBUF"_cs; auto testListOpt = P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/benchmark.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/benchmark.cpp index aa48f41825..d726364f1f 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/benchmark.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/benchmark.cpp @@ -10,18 +10,20 @@ namespace Test { +using namespace P4::literals; + TEST(P4TestgenBenchmark, SuccessfullyGenerate1000Tests) { auto compilerOptions = P4CContextWithOptions::get().options(); - compilerOptions.target = "bmv2"; - compilerOptions.arch = "v1model"; + compilerOptions.target = "bmv2"_cs; + compilerOptions.arch = "v1model"_cs; auto includePath = P4CTestEnvironment::getProjectRoot() / "p4include"; compilerOptions.preprocessor_options = "-I" + includePath.string(); auto fabricFile = P4CTestEnvironment::getProjectRoot() / "testdata/p4_16_samples/fabric_20190420/fabric.p4"; compilerOptions.file = fabricFile.string(); auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get(); - testgenOptions.testBackend = "PROTOBUF_IR"; - testgenOptions.testBaseName = "dummy"; + testgenOptions.testBackend = "PROTOBUF_IR"_cs; + testgenOptions.testBaseName = "dummy"_cs; testgenOptions.seed = 1; // Fix the packet size. testgenOptions.minPktSize = 512; diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/control_plane_filter_test.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/control_plane_filter_test.cpp index 2444ffc7d9..114ae02d47 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/control_plane_filter_test.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/control_plane_filter_test.cpp @@ -13,6 +13,8 @@ namespace Test { +using namespace P4::literals; + using testing::Contains; using testing::HasSubstr; using testing::Not; @@ -63,15 +65,15 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa CompilerOptions generateDefaultApiTestCompilerOptions() { auto compilerOptions = P4CContextWithOptions::get().options(); - compilerOptions.target = "bmv2"; - compilerOptions.arch = "v1model"; + compilerOptions.target = "bmv2"_cs; + compilerOptions.arch = "v1model"_cs; return compilerOptions; } P4Tools::P4Testgen::TestgenOptions &generateDefaultApiTestTestgenOptions() { auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get(); - testgenOptions.testBackend = "PROTOBUF_IR"; - testgenOptions.testBaseName = "dummy"; + testgenOptions.testBackend = "PROTOBUF_IR"_cs; + testgenOptions.testBaseName = "dummy"_cs; testgenOptions.seed = 1; testgenOptions.maxTests = 0; // Create a bespoke packet for the Ethernet extract call. @@ -156,7 +158,7 @@ TEST(P4TestgenControlPlaneFilterTest, FiltersControlPlaneEntities) { // We install a filter. // Since we can not generate a config for the table we should only generate one test. - testgenOptions.skippedControlPlaneEntities = {"ingress.drop_table"}; + testgenOptions.skippedControlPlaneEntities = {"ingress.drop_table"_cs}; auto testListOpt = P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); @@ -196,7 +198,7 @@ TEST(P4TestgenControlPlaneFilterTest, IgnoresBogusControlPlaneEntities) { // This is a bogus control plane element, which is ignored. We expect two tests. // One which exercises action acl_drop and one which exercises the default action, NoAction. - testgenOptions.skippedControlPlaneEntities = {"ingress.bogus_table"}; + testgenOptions.skippedControlPlaneEntities = {"ingress.bogus_table"_cs}; auto testListOpt = P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); @@ -262,7 +264,8 @@ TEST(P4TestgenControlPlaneFilterTest, FiltersMultipleControlPlaneEntities) { // We install a filter. // Since we can not generate a config for the table we should only generate one test. - testgenOptions.skippedControlPlaneEntities = {"ingress.drop_table", "ingress.set_eth_table"}; + testgenOptions.skippedControlPlaneEntities = {"ingress.drop_table"_cs, + "ingress.set_eth_table"_cs}; auto testListOpt = P4Tools::P4Testgen::Testgen::generateTests(source, compilerOptions, testgenOptions); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/output_option_test.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/output_option_test.cpp index 7e22f2fadc..1a1c0ba609 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/output_option_test.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/testgen_api/output_option_test.cpp @@ -9,6 +9,8 @@ namespace Test { +using namespace P4::literals; + TEST(P4TestgenOutputOptionTest, GenerateOuputsCorrectly) { std::stringstream streamTest; streamTest << R"p4( @@ -55,11 +57,11 @@ V1Switch(parse(), verifyChecksum(), ingress(), egress(), computeChecksum(), depa auto source = P4_SOURCE(P4Headers::V1MODEL, streamTest.str().c_str()); auto compilerOptions = P4CContextWithOptions::get().options(); - compilerOptions.target = "bmv2"; - compilerOptions.arch = "v1model"; + compilerOptions.target = "bmv2"_cs; + compilerOptions.arch = "v1model"_cs; auto &testgenOptions = P4Tools::P4Testgen::TestgenOptions::get(); - testgenOptions.testBackend = "PROTOBUF_IR"; - testgenOptions.testBaseName = "dummy"; + testgenOptions.testBackend = "PROTOBUF_IR"_cs; + testgenOptions.testBaseName = "dummy"_cs; testgenOptions.seed = 1; testgenOptions.maxTests = 0; // Create a bespoke packet for the Ethernet extract call. diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/transformations/saturation_arithm.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/transformations/saturation_arithm.cpp index 91501e9768..20a0725f1a 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/transformations/saturation_arithm.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/transformations/saturation_arithm.cpp @@ -22,6 +22,8 @@ namespace Test { +using namespace P4::literals; + using P4::SaturationElim; using P4Tools::Model; using P4Tools::Z3Solver; @@ -88,7 +90,7 @@ class Z3SolverSatTests : public ::testing::Test { } // Extract the binary operation from the P4Program - const auto *decl = test->getProgram().getDeclsByName("mau")->single(); + const auto *decl = test->getProgram().getDeclsByName("mau"_cs)->single(); const auto *control = decl->to(); for (const auto *st : control->body->components) { if (const auto *as = st->to()) { diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/z3-solver/asrt_model.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/z3-solver/asrt_model.cpp index ad7d91ae03..60d4027359 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/z3-solver/asrt_model.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/z3-solver/asrt_model.cpp @@ -25,6 +25,8 @@ namespace Test { +using namespace P4::literals; + using P4Tools::Model; using P4Tools::Z3Solver; using P4Tools::Z3SolverAccessor; @@ -93,7 +95,7 @@ class Z3SolverTest : public P4ToolsTest { } // Extract the binary operation from the P4Program - const auto *decl = test->getProgram().getDeclsByName("mau")->single(); + const auto *decl = test->getProgram().getDeclsByName("mau"_cs)->single(); const auto *control = decl->to(); SymbolicConverter converter; for (const auto *st : control->body->components) { diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test/z3-solver/expressions.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test/z3-solver/expressions.cpp index f806bee922..b94f8dff11 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test/z3-solver/expressions.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test/z3-solver/expressions.cpp @@ -17,6 +17,8 @@ namespace Test { +using namespace P4::literals; + using P4Tools::Z3Solver; using P4Tools::P4Testgen::TestgenTarget; using Value = IR::Literal; @@ -87,7 +89,7 @@ class Z3SolverTests : public ::testing::Test { } // Extract the binary operation from the P4Program - const auto *decl = test->getProgram().getDeclsByName("mau")->single(); + const auto *decl = test->getProgram().getDeclsByName("mau"_cs)->single(); const auto *control = decl->to(); for (const auto *st : control->body->components) { if (const auto *as = st->to()) { diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_backend.cpp index 7dc9ddc825..c9fd78b3d7 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend.cpp @@ -103,7 +103,7 @@ const TestSpec *Bmv2TestBackend::createTestSpec(const ExecutionState *executionS if (TestgenOptions::get().testBackend == "METADATA") { auto *metadataCollection = new MetadataCollection(); const auto *bmv2ProgInfo = getProgramInfo().checkedTo(); - const auto *localMetadataVar = bmv2ProgInfo->getBlockParam("Parser", 2); + const auto *localMetadataVar = bmv2ProgInfo->getBlockParam("Parser"_cs, 2); const auto &flatFields = executionState->getFlatFields(localMetadataVar, {}); for (const auto &fieldRef : flatFields) { const auto *fieldVal = finalModel->evaluate(executionState->get(fieldRef), true); @@ -113,51 +113,52 @@ const TestSpec *Bmv2TestBackend::createTestSpec(const ExecutionState *executionS fieldString = fieldString.substr(fieldString.find('.') - fieldString.begin() + 1); metadataCollection->addMetaDataField(fieldString, fieldVal); } - testSpec->addTestObject("metadata_collection", "metadata_collection", metadataCollection); + testSpec->addTestObject("metadata_collection"_cs, "metadata_collection"_cs, + metadataCollection); return testSpec; } // We retrieve the individual table configurations from the execution state. - const auto uninterpretedTableConfigs = executionState->getTestObjectCategory("tableconfigs"); + const auto uninterpretedTableConfigs = executionState->getTestObjectCategory("tableconfigs"_cs); // Since these configurations are uninterpreted we need to convert them. We launch a // helper function to solve the variables involved in each table configuration. for (const auto &tablePair : uninterpretedTableConfigs) { const auto tableName = tablePair.first; const auto *uninterpretedTableConfig = tablePair.second->checkedTo(); const auto *tableConfig = uninterpretedTableConfig->evaluate(*finalModel, true); - testSpec->addTestObject("tables", tableName, tableConfig); + testSpec->addTestObject("tables"_cs, tableName, tableConfig); } - const auto actionProfiles = executionState->getTestObjectCategory("action_profile"); + const auto actionProfiles = executionState->getTestObjectCategory("action_profile"_cs); for (const auto &testObject : actionProfiles) { const auto profileName = testObject.first; const auto *actionProfile = testObject.second->checkedTo(); const auto *evaluatedProfile = actionProfile->evaluate(*finalModel, true); - testSpec->addTestObject("action_profiles", profileName, evaluatedProfile); + testSpec->addTestObject("action_profiles"_cs, profileName, evaluatedProfile); } - const auto actionSelectors = executionState->getTestObjectCategory("action_selector"); + const auto actionSelectors = executionState->getTestObjectCategory("action_selector"_cs); for (const auto &testObject : actionSelectors) { const auto selectorName = testObject.first; const auto *actionSelector = testObject.second->checkedTo(); const auto *evaluatedSelector = actionSelector->evaluate(*finalModel, true); - testSpec->addTestObject("action_selectors", selectorName, evaluatedSelector); + testSpec->addTestObject("action_selectors"_cs, selectorName, evaluatedSelector); } - const auto cloneSpecs = executionState->getTestObjectCategory("clone_specs"); + const auto cloneSpecs = executionState->getTestObjectCategory("clone_specs"_cs); for (const auto &testObject : cloneSpecs) { const auto sessionId = testObject.first; const auto *cloneSpec = testObject.second->checkedTo(); const auto *evaluatedInfo = cloneSpec->evaluate(*finalModel, true); - testSpec->addTestObject("clone_specs", sessionId, evaluatedInfo); + testSpec->addTestObject("clone_specs"_cs, sessionId, evaluatedInfo); } - const auto meterInfos = executionState->getTestObjectCategory("meter_values"); + const auto meterInfos = executionState->getTestObjectCategory("meter_values"_cs); for (const auto &testObject : meterInfos) { const auto meterName = testObject.first; const auto *meterInfo = testObject.second->checkedTo(); const auto *evaluateMeterValue = meterInfo->evaluate(*finalModel, true); - testSpec->addTestObject("meter_values", meterName, evaluateMeterValue); + testSpec->addTestObject("meter_values"_cs, meterName, evaluateMeterValue); } return testSpec; diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/common.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/common.cpp index fb51b6d39a..0208ffad5b 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/common.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/common.cpp @@ -90,7 +90,7 @@ inja::json Bmv2TestFramework::getControlPlane(const TestSpec *testSpec) const { // Map of actionProfiles and actionSelectors for easy reference. std::map apAsMap; - auto tables = testSpec->getTestObjectCategory("tables"); + auto tables = testSpec->getTestObjectCategory("tables"_cs); if (!tables.empty()) { controlPlaneJson["tables"] = inja::json::array(); } diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/metadata.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/metadata.cpp index c1aa5f6857..d0f8e764e4 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/metadata.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/metadata.cpp @@ -110,7 +110,7 @@ void Metadata::emitTestcase(const TestSpec *testSpec, cstring selectedBranches, dataJson["coverage"] = coverageStr.str(); dataJson["metadata_fields"] = inja::json::array(); const auto *metadataCollection = - testSpec->getTestObject("metadata_collection", "metadata_collection", true) + testSpec->getTestObject("metadata_collection"_cs, "metadata_collection"_cs, true) ->checkedTo(); auto offset = 0; for (auto const &metadataField : metadataCollection->getMetadataFields()) { diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf.cpp index cb5fc574d0..2597cf846b 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/protobuf.cpp @@ -40,7 +40,7 @@ inja::json Protobuf::getControlPlane(const TestSpec *testSpec) const { // Map of actionProfiles and actionSelectors for easy reference. std::map apAsMap; - auto tables = testSpec->getTestObjectCategory("tables"); + auto tables = testSpec->getTestObjectCategory("tables"_cs); if (!tables.empty()) { controlPlaneJson["tables"] = inja::json::array(); } @@ -335,11 +335,11 @@ inja::json Protobuf::produceTestCase(const TestSpec *testSpec, cstring selectedB // Check whether this test has a clone configuration. // These are special because they require additional instrumentation and produce two output // packets. - auto cloneSpecs = testSpec->getTestObjectCategory("clone_specs"); + auto cloneSpecs = testSpec->getTestObjectCategory("clone_specs"_cs); if (!cloneSpecs.empty()) { dataJson["clone_specs"] = getClone(cloneSpecs); } - auto meterValues = testSpec->getTestObjectCategory("meter_values"); + auto meterValues = testSpec->getTestObjectCategory("meter_values"_cs); dataJson["meter_values"] = getMeter(meterValues); return dataJson; 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 67f3d32302..5793de6f5c 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 @@ -26,7 +26,7 @@ ProtobufIr::ProtobufIr(const TestBackendConfiguration &testBackendConfiguration, std::optional ProtobufIr::checkForP4RuntimeTranslationAnnotation( const IR::IAnnotated *node) { - const auto *p4RuntimeTranslationAnnotation = node->getAnnotation("p4runtime_translation"); + const auto *p4RuntimeTranslationAnnotation = node->getAnnotation("p4runtime_translation"_cs); if (p4RuntimeTranslationAnnotation == nullptr) { return std::nullopt; } @@ -46,7 +46,7 @@ std::optional ProtobufIr::checkForP4RuntimeTranslationAnnotation( std::map ProtobufIr::getP4RuntimeTranslationMappings(const IR::IAnnotated *node) { std::map p4RuntimeTranslationMappings; const auto *p4RuntimeTranslationMappingAnnotation = - node->getAnnotation("p4runtime_translation_mappings"); + node->getAnnotation("p4runtime_translation_mappings"_cs); if (p4RuntimeTranslationMappingAnnotation == nullptr) { return p4RuntimeTranslationMappings; } @@ -72,7 +72,7 @@ std::string ProtobufIr::getFormatOfNode(const IR::IAnnotated *node) { return p4RuntimeTranslationFormat.value(); } - const auto *formatAnnotation = node->getAnnotation("format"); + const auto *formatAnnotation = node->getAnnotation("format"_cs); if (formatAnnotation == nullptr) { return "hex_str"; } @@ -428,11 +428,11 @@ inja::json ProtobufIr::produceTestCase(const TestSpec *testSpec, cstring selecte // Check whether this test has a clone configuration. // These are special because they require additional instrumentation and produce two output // packets. - auto cloneSpecs = testSpec->getTestObjectCategory("clone_specs"); + auto cloneSpecs = testSpec->getTestObjectCategory("clone_specs"_cs); if (!cloneSpecs.empty()) { dataJson["clone_specs"] = getClone(cloneSpecs); } - auto meterValues = testSpec->getTestObjectCategory("meter_values"); + auto meterValues = testSpec->getTestObjectCategory("meter_values"_cs); dataJson["meter_values"] = getMeter(meterValues); return dataJson; diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/ptf.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/ptf.cpp index c78334acf4..3f462a5867 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/ptf.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/ptf.cpp @@ -283,11 +283,11 @@ void PTF::emitTestcase(const TestSpec *testSpec, cstring selectedBranches, size_ // Check whether this test has a clone configuration. // These are special because they require additional instrumentation and produce two output // packets. - auto cloneSpecs = testSpec->getTestObjectCategory("clone_specs"); + auto cloneSpecs = testSpec->getTestObjectCategory("clone_specs"_cs); if (!cloneSpecs.empty()) { dataJson["clone_specs"] = getClone(cloneSpecs); } - auto meterValues = testSpec->getTestObjectCategory("meter_values"); + auto meterValues = testSpec->getTestObjectCategory("meter_values"_cs); dataJson["meter_values"] = getMeter(meterValues); LOG5("PTF backend: emitting testcase:" << std::setw(4) << dataJson); diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/stf.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/stf.cpp index 11e0773d30..480ea22258 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_backend/stf.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_backend/stf.cpp @@ -226,7 +226,7 @@ void STF::emitTestcase(const TestSpec *testSpec, cstring selectedBranches, size_ // Check whether this test has a clone configuration. // These are special because they require additional instrumentation and produce two output // packets. - auto cloneSpecs = testSpec->getTestObjectCategory("clone_specs"); + auto cloneSpecs = testSpec->getTestObjectCategory("clone_specs"_cs); if (!cloneSpecs.empty()) { dataJson["clone_specs"] = getClone(cloneSpecs); } diff --git a/backends/p4tools/modules/testgen/targets/bmv2/test_spec.cpp b/backends/p4tools/modules/testgen/targets/bmv2/test_spec.cpp index d493a7dde5..4acdc5703e 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/test_spec.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/test_spec.cpp @@ -7,6 +7,8 @@ namespace P4Tools::P4Testgen::Bmv2 { +using namespace P4::literals; + /* ========================================================================================= * IndexExpression * ========================================================================================= */ @@ -32,7 +34,7 @@ const IR::Expression *IndexExpression::getIndex() const { return index; } const IR::Expression *IndexExpression::getValue() const { return value; } -cstring IndexExpression::getObjectName() const { return "IndexExpression"; } +cstring IndexExpression::getObjectName() const { return "IndexExpression"_cs; } const IndexExpression *IndexExpression::evaluate(const Model &model, bool doComplete) const { const auto *evaluatedIndex = model.evaluate(index, doComplete); @@ -89,7 +91,7 @@ const IR::Constant *IndexMap::getEvaluatedInitialValue() const { Bmv2V1ModelRegisterValue::Bmv2V1ModelRegisterValue(const IR::Expression *initialValue) : IndexMap(initialValue) {} -cstring Bmv2V1ModelRegisterValue::getObjectName() const { return "Bmv2V1ModelRegisterValue"; } +cstring Bmv2V1ModelRegisterValue::getObjectName() const { return "Bmv2V1ModelRegisterValue"_cs; } const Bmv2V1ModelRegisterValue *Bmv2V1ModelRegisterValue::evaluate(const Model &model, bool doComplete) const { @@ -110,7 +112,7 @@ const Bmv2V1ModelRegisterValue *Bmv2V1ModelRegisterValue::evaluate(const Model & Bmv2V1ModelMeterValue::Bmv2V1ModelMeterValue(const IR::Expression *initialValue, bool isDirect) : IndexMap(initialValue), isDirect(isDirect) {} -cstring Bmv2V1ModelMeterValue::getObjectName() const { return "Bmv2V1ModelMeterValue"; } +cstring Bmv2V1ModelMeterValue::getObjectName() const { return "Bmv2V1ModelMeterValue"_cs; } const Bmv2V1ModelMeterValue *Bmv2V1ModelMeterValue::evaluate(const Model &model, bool doComplete) const { @@ -171,7 +173,7 @@ Bmv2V1ModelActionSelector::Bmv2V1ModelActionSelector(const IR::IDeclaration *sel const Bmv2V1ModelActionProfile *actionProfile) : selectorDecl(selectorDecl), actionProfile(actionProfile) {} -cstring Bmv2V1ModelActionSelector::getObjectName() const { return "Bmv2V1ModelActionSelector"; } +cstring Bmv2V1ModelActionSelector::getObjectName() const { return "Bmv2V1ModelActionSelector"_cs; } const IR::IDeclaration *Bmv2V1ModelActionSelector::getSelectorDecl() const { return selectorDecl; } @@ -198,7 +200,7 @@ Bmv2V1ModelCloneInfo::Bmv2V1ModelCloneInfo(const IR::Expression *sessionId, clonedState(clonedState), preserveIndex(preserveIndex) {} -cstring Bmv2V1ModelCloneInfo::getObjectName() const { return "Bmv2V1ModelCloneInfo"; } +cstring Bmv2V1ModelCloneInfo::getObjectName() const { return "Bmv2V1ModelCloneInfo"_cs; } BMv2Constants::CloneType Bmv2V1ModelCloneInfo::getCloneType() const { return cloneType; } @@ -221,7 +223,7 @@ Bmv2V1ModelCloneSpec::Bmv2V1ModelCloneSpec(const IR::Expression *sessionId, const IR::Expression *clonePort, bool isClone) : sessionId(sessionId), clonePort(clonePort), isClone(isClone) {} -cstring Bmv2V1ModelCloneSpec::getObjectName() const { return "Bmv2V1ModelCloneSpec"; } +cstring Bmv2V1ModelCloneSpec::getObjectName() const { return "Bmv2V1ModelCloneSpec"_cs; } const IR::Expression *Bmv2V1ModelCloneSpec::getClonePort() const { return clonePort; } @@ -270,7 +272,7 @@ const Optional *Optional::evaluate(const Model &model, bool doComplete) const { return new Optional(getKey(), evaluatedValue, addMatch); } -cstring Optional::getObjectName() const { return "Optional"; } +cstring Optional::getObjectName() const { return "Optional"_cs; } bool Optional::addAsExactMatch() const { return addMatch; } @@ -307,7 +309,7 @@ const Range *Range::evaluate(const Model &model, bool doComplete) const { MetadataCollection::MetadataCollection() = default; -cstring MetadataCollection::getObjectName() const { return "MetadataCollection"; } +cstring MetadataCollection::getObjectName() const { return "MetadataCollection"_cs; } const MetadataCollection *MetadataCollection::evaluate(const Model & /*model*/, bool /*finalModel*/) const { @@ -326,6 +328,6 @@ void MetadataCollection::addMetaDataField(cstring name, const IR::Literal *metad metadataFields[name] = metadataField; } -cstring Range::getObjectName() const { return "Range"; } +cstring Range::getObjectName() const { return "Range"_cs; } } // namespace P4Tools::P4Testgen::Bmv2 diff --git a/backends/p4tools/modules/testgen/targets/ebpf/backend/stf/stf.cpp b/backends/p4tools/modules/testgen/targets/ebpf/backend/stf/stf.cpp index 7072e6ce3f..e2e82bf682 100644 --- a/backends/p4tools/modules/testgen/targets/ebpf/backend/stf/stf.cpp +++ b/backends/p4tools/modules/testgen/targets/ebpf/backend/stf/stf.cpp @@ -40,7 +40,7 @@ inja::json STF::getControlPlane(const TestSpec *testSpec) { // Map of actionProfiles and actionSelectors for easy reference. std::map apAsMap; - auto tables = testSpec->getTestObjectCategory("tables"); + auto tables = testSpec->getTestObjectCategory("tables"_cs); if (!tables.empty()) { controlPlaneJson["tables"] = inja::json::array(); } diff --git a/backends/p4tools/modules/testgen/targets/ebpf/expr_stepper.cpp b/backends/p4tools/modules/testgen/targets/ebpf/expr_stepper.cpp index 734eed8d7f..bc2bf4f800 100644 --- a/backends/p4tools/modules/testgen/targets/ebpf/expr_stepper.cpp +++ b/backends/p4tools/modules/testgen/targets/ebpf/expr_stepper.cpp @@ -45,8 +45,8 @@ void EBPFExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * CounterArray.add: Add value to counter with specified index. * ====================================================================================== */ // TODO: Count currently has no effect in the symbolic interpreter. - {"CounterArray.add", - {"index", "value"}, + {"CounterArray.add"_cs, + {"index"_cs, "value"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -66,8 +66,8 @@ void EBPFExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * CounterArray.increment: Add value to counter with specified index. * ====================================================================================== */ // TODO: Count currently has no effect in the symbolic interpreter. - {"CounterArray.increment", - {"index"}, + {"CounterArray.increment"_cs, + {"index"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -85,8 +85,8 @@ void EBPFExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * @return True if checksum is correct. * Implemented in p4c/testdata/extern_modules/extern-checksum-ebpf.c * ====================================================================================== */ - {"*method.verify_ipv4_checksum", - {"iphdr"}, + {"*method.verify_ipv4_checksum"_cs, + {"iphdr"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -162,19 +162,19 @@ void EBPFExprStepper::evalExternMethodCall(const IR::MethodCallExpression *call, * stateful packet processing. * Implemented in p4c/testdata/extern_modules/extern-conntrack-ebpf.c * ====================================================================================== */ - {"*method.tcp_conntrack", - {"hdrs"}, + {"*method.tcp_conntrack"_cs, + {"hdrs"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { // Input must be the headers struct. const auto *headers = args->at(0)->expression->checkedTo(); - const auto *tcpRef = headers->getField("tcp"); + const auto *tcpRef = headers->getField("tcp"_cs); CHECK_NULL(tcpRef); const auto *tcpHeader = tcpRef->expression->checkedTo(); - const auto *syn = tcpHeader->getField("syn"); + const auto *syn = tcpHeader->getField("syn"_cs); CHECK_NULL(syn); - const auto *ack = tcpHeader->getField("ack"); + const auto *ack = tcpHeader->getField("ack"_cs); CHECK_NULL(ack); const auto *synExpr = syn->expression; const auto *ackExpr = ack->expression; diff --git a/backends/p4tools/modules/testgen/targets/ebpf/program_info.cpp b/backends/p4tools/modules/testgen/targets/ebpf/program_info.cpp index 36147c7bb6..b42aec4427 100644 --- a/backends/p4tools/modules/testgen/targets/ebpf/program_info.cpp +++ b/backends/p4tools/modules/testgen/targets/ebpf/program_info.cpp @@ -26,6 +26,8 @@ namespace P4Tools::P4Testgen::EBPF { +using namespace P4::literals; + const IR::Type_Bits EBPFProgramInfo::PARSER_ERR_BITS = IR::Type_Bits(32, false); EBPFProgramInfo::EBPFProgramInfo(const TestgenCompilerResult &compilerResult, @@ -122,9 +124,9 @@ const IR::Expression *EBPFProgramInfo::dropIsActive() const { const IR::Type_Bits *EBPFProgramInfo::getParserErrorType() const { return &PARSER_ERR_BITS; } const ArchSpec EBPFProgramInfo::ARCH_SPEC = - ArchSpec("ebpfFilter", {// parser parse(packet_in packet, out H headers); - {"parse", {nullptr, "*hdr"}}, - // control filter(inout H headers, out bool accept); - {"filter", {"*hdr", "*accept"}}}); + ArchSpec("ebpfFilter"_cs, {// parser parse(packet_in packet, out H headers); + {"parse"_cs, {nullptr, "*hdr"_cs}}, + // control filter(inout H headers, out bool accept); + {"filter"_cs, {"*hdr"_cs, "*accept"_cs}}}); } // namespace P4Tools::P4Testgen::EBPF diff --git a/backends/p4tools/modules/testgen/targets/ebpf/test_backend.cpp b/backends/p4tools/modules/testgen/targets/ebpf/test_backend.cpp index 0dc5f96a52..6ae78c55f4 100644 --- a/backends/p4tools/modules/testgen/targets/ebpf/test_backend.cpp +++ b/backends/p4tools/modules/testgen/targets/ebpf/test_backend.cpp @@ -92,14 +92,14 @@ const TestSpec *EBPFTestBackend::createTestSpec(const ExecutionState *executionS } testSpec = new TestSpec(ingressPacket, egressPacket, testInfo.programTraces); // We retrieve the individual table configurations from the execution state. - const auto uninterpretedTableConfigs = executionState->getTestObjectCategory("tableconfigs"); + const auto uninterpretedTableConfigs = executionState->getTestObjectCategory("tableconfigs"_cs); // Since these configurations are uninterpreted we need to convert them. We launch a // helper function to solve the variables involved in each table configuration. for (const auto &tablePair : uninterpretedTableConfigs) { const auto tableName = tablePair.first; const auto *uninterpretedTableConfig = tablePair.second->checkedTo(); const auto *const tableConfig = uninterpretedTableConfig->evaluate(*finalModel, true); - testSpec->addTestObject("tables", tableName, tableConfig); + testSpec->addTestObject("tables"_cs, tableName, tableConfig); } return testSpec; } diff --git a/backends/p4tools/modules/testgen/targets/pna/backend/metadata/metadata.cpp b/backends/p4tools/modules/testgen/targets/pna/backend/metadata/metadata.cpp index 7f8b5cce2c..250c7c5669 100644 --- a/backends/p4tools/modules/testgen/targets/pna/backend/metadata/metadata.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/backend/metadata/metadata.cpp @@ -158,7 +158,7 @@ void Metadata::emitTestcase(const TestSpec *testSpec, cstring selectedBranches, dataJson["coverage"] = coverageStr.str(); dataJson["metadata_fields"] = inja::json::array(); const auto *metadataCollection = - testSpec->getTestObject("metadata_collection", "metadata_collection", true) + testSpec->getTestObject("metadata_collection"_cs, "metadata_collection"_cs, true) ->checkedTo(); auto offset = 0; for (auto const &metadataField : metadataCollection->getMetadataFields()) { diff --git a/backends/p4tools/modules/testgen/targets/pna/backend/ptf/ptf.cpp b/backends/p4tools/modules/testgen/targets/pna/backend/ptf/ptf.cpp index 685da61bda..8b1cb98b46 100644 --- a/backends/p4tools/modules/testgen/targets/pna/backend/ptf/ptf.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/backend/ptf/ptf.cpp @@ -58,7 +58,7 @@ inja::json PTF::getControlPlane(const TestSpec *testSpec) { // Map of actionProfiles and actionSelectors for easy reference. std::map apAsMap; - auto tables = testSpec->getTestObjectCategory("tables"); + auto tables = testSpec->getTestObjectCategory("tables"_cs); if (!tables.empty()) { controlPlaneJson["tables"] = inja::json::array(); } diff --git a/backends/p4tools/modules/testgen/targets/pna/constants.cpp b/backends/p4tools/modules/testgen/targets/pna/constants.cpp index 36786f893b..76cde9f0a2 100644 --- a/backends/p4tools/modules/testgen/targets/pna/constants.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/constants.cpp @@ -5,6 +5,8 @@ namespace P4Tools::P4Testgen::Pna { +using namespace P4::literals; + const IR::Member PnaConstants::DROP_VAR = IR::Member(IR::Type_Boolean::get(), new IR::PathExpression("*pna_internal"), "drop_var"); const IR::Member PnaConstants::OUTPUT_PORT_VAR = @@ -14,6 +16,6 @@ const IR::Member PnaConstants::PARSER_ERROR = // TODO: Make this a proper variables variable. // We can not use the utilities because of an issue related to the garbage collector. const IR::SymbolicVariable PnaSymbolicVars::DIRECTION = - IR::SymbolicVariable(IR::Type_Bits::get(32), "direction"); + IR::SymbolicVariable(IR::Type_Bits::get(32), "direction"_cs); } // namespace P4Tools::P4Testgen::Pna diff --git a/backends/p4tools/modules/testgen/targets/pna/dpdk/program_info.cpp b/backends/p4tools/modules/testgen/targets/pna/dpdk/program_info.cpp index 0560e38eda..b5c486b34f 100644 --- a/backends/p4tools/modules/testgen/targets/pna/dpdk/program_info.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/dpdk/program_info.cpp @@ -20,6 +20,8 @@ namespace P4Tools::P4Testgen::Pna { +using namespace P4::literals; + PnaDpdkProgramInfo::PnaDpdkProgramInfo( const TestgenCompilerResult &compilerResult, ordered_map inputBlocks) @@ -111,33 +113,34 @@ std::vector PnaDpdkProgramInfo::processDeclaration( } const ArchSpec PnaDpdkProgramInfo::ARCH_SPEC = ArchSpec( - "PNA_NIC", { - // parser MainParserT( - // packet_in pkt, - // //in PM pre_user_meta, - // out MH main_hdr, - // inout MM main_user_meta, - // in pna_main_parser_input_metadata_t istd); - {"MainParserT", {nullptr, "*main_hdr", "*main_user_meta", "*parser_istd"}}, - // control PreControlT( - // in PH pre_hdr, - // inout PM pre_user_meta, - // in pna_pre_input_metadata_t istd, - // inout pna_pre_output_metadata_t ostd); - {"PreControlT", {"*main_hdr", "*main_user_meta", "*pre_istd", "*pre_ostd"}}, - // control MainControlT( - // //in PM pre_user_meta, - // inout MH main_hdr, - // inout MM main_user_meta, - // in pna_main_input_metadata_t istd, - // inout pna_main_output_metadata_t ostd); - {"MainControlT", {"*main_hdr", "*main_user_meta", "*main_istd", "*ostd"}}, - // control MainDeparserT( - // packet_out pkt, - // in MH main_hdr, - // in MM main_user_meta, - // in pna_main_output_metadata_t ostd); - {"MainDeparserT", {nullptr, "*main_hdr", "*main_user_meta", "*ostd"}}, - }); + "PNA_NIC"_cs, + { + // parser MainParserT( + // packet_in pkt, + // //in PM pre_user_meta, + // out MH main_hdr, + // inout MM main_user_meta, + // in pna_main_parser_input_metadata_t istd); + {"MainParserT"_cs, {nullptr, "*main_hdr"_cs, "*main_user_meta"_cs, "*parser_istd"_cs}}, + // control PreControlT( + // in PH pre_hdr, + // inout PM pre_user_meta, + // in pna_pre_input_metadata_t istd, + // inout pna_pre_output_metadata_t ostd); + {"PreControlT"_cs, {"*main_hdr"_cs, "*main_user_meta"_cs, "*pre_istd"_cs, "*pre_ostd"_cs}}, + // control MainControlT( + // //in PM pre_user_meta, + // inout MH main_hdr, + // inout MM main_user_meta, + // in pna_main_input_metadata_t istd, + // inout pna_main_output_metadata_t ostd); + {"MainControlT"_cs, {"*main_hdr"_cs, "*main_user_meta"_cs, "*main_istd"_cs, "*ostd"_cs}}, + // control MainDeparserT( + // packet_out pkt, + // in MH main_hdr, + // in MM main_user_meta, + // in pna_main_output_metadata_t ostd); + {"MainDeparserT"_cs, {nullptr, "*main_hdr"_cs, "*main_user_meta"_cs, "*ostd"_cs}}, + }); } // namespace P4Tools::P4Testgen::Pna diff --git a/backends/p4tools/modules/testgen/targets/pna/shared_expr_stepper.cpp b/backends/p4tools/modules/testgen/targets/pna/shared_expr_stepper.cpp index 1edfccca12..fc898c346b 100644 --- a/backends/p4tools/modules/testgen/targets/pna/shared_expr_stepper.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/shared_expr_stepper.cpp @@ -37,7 +37,7 @@ const ExternMethodImpls SharedPnaExprStepper::PNA_EXTERN_METHOD_IMPLS({ * drop_packet * drop_packet sets the PNA internal drop variable to true. * ====================================================================================== */ - {"*method.drop_packet", + {"*method.drop_packet"_cs, {}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, @@ -46,7 +46,7 @@ const ExternMethodImpls SharedPnaExprStepper::PNA_EXTERN_METHOD_IMPLS({ // Use an assignment to set drop variable to true. // This variable will be processed in the deparser. nextState.set(&PnaConstants::DROP_VAR, IR::BoolLiteral::get(true)); - nextState.add(*new TraceEvents::Generic("drop_packet executed")); + nextState.add(*new TraceEvents::Generic("drop_packet executed"_cs)); nextState.popBody(); result->emplace_back(nextState); }}, @@ -55,8 +55,8 @@ const ExternMethodImpls SharedPnaExprStepper::PNA_EXTERN_METHOD_IMPLS({ * send_to_port sets the PNA internal egress port variable to true. * ====================================================================================== */ // TODO: Implement extern path expression calls. - {"*method.send_to_port", - {"dest_port"}, + {"*method.send_to_port"_cs, + {"dest_port"_cs}, [](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -79,7 +79,7 @@ const ExternMethodImpls SharedPnaExprStepper::PNA_EXTERN_METHOD_IMPLS({ } // Use an assignment to set the output port to the input. nextState.set(&PnaConstants::OUTPUT_PORT_VAR, destPort); - nextState.add(*new TraceEvents::Generic("send_to_port executed")); + nextState.add(*new TraceEvents::Generic("send_to_port executed"_cs)); nextState.popBody(); result->emplace_back(nextState); }}, @@ -106,8 +106,8 @@ const ExternMethodImpls SharedPnaExprStepper::PNA_EXTERN_METHOD_IMPLS({ * } * } * ====================================================================================== */ - {"*method.SelectByDirection", - {"direction", "n2h_value", "h2n_value"}, + {"*method.SelectByDirection"_cs, + {"direction"_cs, "n2h_value"_cs, "h2n_value"_cs}, [](const IR::MethodCallExpression *call, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector *args, const ExecutionState &state, SmallStepEvaluator::Result &result) { @@ -161,13 +161,13 @@ const ExternMethodImpls SharedPnaExprStepper::PNA_EXTERN_METHOD_IMPLS({ * ====================================================================================== */ // TODO: Currently, this is a no-op. This is because we only test a single packet input. // Implement a way to test add_entry. - {"*method.add_entry", - {"action_name", "action_params", "expire_time_profile_id"}, + {"*method.add_entry"_cs, + {"action_name"_cs, "action_params"_cs, "expire_time_profile_id"_cs}, [](const IR::MethodCallExpression * /*call*/, const IR::Expression * /*receiver*/, IR::ID & /*methodName*/, const IR::Vector * /*args*/, const ExecutionState &state, SmallStepEvaluator::Result &result) { auto &nextState = state.clone(); - nextState.add(*new TraceEvents::Generic("add_entry executed. Currently a no-op.")); + nextState.add(*new TraceEvents::Generic("add_entry executed. Currently a no-op."_cs)); nextState.replaceTopBody(Continuation::Return(IR::BoolLiteral::get(true))); result->emplace_back(nextState); }}, diff --git a/backends/p4tools/modules/testgen/targets/pna/shared_table_stepper.cpp b/backends/p4tools/modules/testgen/targets/pna/shared_table_stepper.cpp index 22185b06a2..57f3d7a300 100644 --- a/backends/p4tools/modules/testgen/targets/pna/shared_table_stepper.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/shared_table_stepper.cpp @@ -32,6 +32,8 @@ namespace P4Tools::P4Testgen::Pna { +using namespace P4::literals; + const IR::Expression *SharedPnaTableStepper::computeTargetMatchType( const TableUtils::KeyProperties &keyProperties, TableMatchMap *matches, const IR::Expression *hitCondition) { @@ -119,7 +121,7 @@ void SharedPnaTableStepper::evalTableActionProfile( // TODO: Should we check if we exceed the maximum number of possible profile entries? actionProfile->addToActionMap(actionName, ctrlPlaneArgs); // Update the action profile in the execution state. - nextState.addTestObject("action_profile", actionProfile->getObjectName(), actionProfile); + nextState.addTestObject("action_profile"_cs, actionProfile->getObjectName(), actionProfile); // We add the arguments to our action call, effectively creating a const entry call. auto *synthesizedAction = tableAction->clone(); @@ -133,8 +135,8 @@ void SharedPnaTableStepper::evalTableActionProfile( // Add the action profile to the table. // This implies a slightly different implementation to usual control plane table behavior. - tableConfig->addTableProperty("action_profile", actionProfile); - nextState.addTestObject("tableconfigs", table->controlPlaneName(), tableConfig); + tableConfig->addTableProperty("action_profile"_cs, actionProfile); + nextState.addTestObject("tableconfigs"_cs, table->controlPlaneName(), tableConfig); // Update all the tracking variables for tables. std::vector replacements; @@ -202,9 +204,10 @@ void SharedPnaTableStepper::evalTableActionSelector( SharedPnaProperties.actionSelector->getSelectorDecl(), actionProfile); // Update the action profile in the execution state. - nextState.addTestObject("action_profile", actionProfile->getObjectName(), actionProfile); + nextState.addTestObject("action_profile"_cs, actionProfile->getObjectName(), actionProfile); // Update the action selector in the execution state. - nextState.addTestObject("action_selector", actionSelector->getObjectName(), actionSelector); + nextState.addTestObject("action_selector"_cs, actionSelector->getObjectName(), + actionSelector); // We add the arguments to our action call, effectively creating a const entry call. auto *synthesizedAction = tableAction->clone(); @@ -217,11 +220,11 @@ void SharedPnaTableStepper::evalTableActionSelector( auto *tableConfig = new TableConfig(table, {tableRule}); // Add the action profile to the table. This signifies a slightly different implementation. - tableConfig->addTableProperty("action_profile", actionProfile); + tableConfig->addTableProperty("action_profile"_cs, actionProfile); // Add the action selector to the table. This signifies a slightly different implementation. - tableConfig->addTableProperty("action_selector", actionSelector); + tableConfig->addTableProperty("action_selector"_cs, actionSelector); - nextState.addTestObject("tableconfigs", table->controlPlaneName(), tableConfig); + nextState.addTestObject("tableconfigs"_cs, table->controlPlaneName(), tableConfig); // Update all the tracking variables for tables. std::vector replacements; @@ -248,7 +251,7 @@ void SharedPnaTableStepper::evalTableActionSelector( } bool SharedPnaTableStepper::checkForActionProfile() { - const auto *impl = table->properties->getProperty("implementation"); + const auto *impl = table->properties->getProperty("implementation"_cs); if (impl == nullptr) { return false; } @@ -276,7 +279,7 @@ bool SharedPnaTableStepper::checkForActionProfile() { } const auto *testObject = - state->getTestObject("action_profile", implExtern->controlPlaneName(), false); + state->getTestObject("action_profile"_cs, implExtern->controlPlaneName(), false); if (testObject == nullptr) { // This means, for every possible control plane entry (and with that, new execution state) // add the generated action profile. @@ -290,7 +293,7 @@ bool SharedPnaTableStepper::checkForActionProfile() { } bool SharedPnaTableStepper::checkForActionSelector() { - const auto *impl = table->properties->getProperty("implementation"); + const auto *impl = table->properties->getProperty("implementation"_cs); if (impl == nullptr) { return false; } @@ -319,7 +322,7 @@ bool SharedPnaTableStepper::checkForActionSelector() { // Treat action selectors like action profiles for now. // The behavioral model P4Runtime is unclear how to configure action selectors. const auto *testObject = - state->getTestObject("action_profile", selectorExtern->controlPlaneName(), false); + state->getTestObject("action_profile"_cs, selectorExtern->controlPlaneName(), false); if (testObject == nullptr) { // This means, for every possible control plane entry (and with that, new execution state) // add the generated action profile. diff --git a/backends/p4tools/modules/testgen/targets/pna/test_backend.cpp b/backends/p4tools/modules/testgen/targets/pna/test_backend.cpp index 587d2ad3df..b138efdc57 100644 --- a/backends/p4tools/modules/testgen/targets/pna/test_backend.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/test_backend.cpp @@ -84,7 +84,7 @@ const TestSpec *PnaTestBackend::createTestSpec(const ExecutionState *executionSt if (TestgenOptions::get().testBackend == "METADATA") { auto *metadataCollection = new MetadataCollection(); const auto *pnaProgInfo = getProgramInfo().checkedTo(); - const auto *localMetadataVar = pnaProgInfo->getBlockParam("MainParserT", 2); + const auto *localMetadataVar = pnaProgInfo->getBlockParam("MainParserT"_cs, 2); const auto &flatFields = executionState->getFlatFields(localMetadataVar, {}); for (const auto &fieldRef : flatFields) { const auto *fieldVal = finalModel->evaluate(executionState->get(fieldRef), true); @@ -94,35 +94,36 @@ const TestSpec *PnaTestBackend::createTestSpec(const ExecutionState *executionSt fieldString = fieldString.substr(fieldString.find('.') - fieldString.begin() + 1); metadataCollection->addMetaDataField(fieldString, fieldVal); } - testSpec->addTestObject("metadata_collection", "metadata_collection", metadataCollection); + testSpec->addTestObject("metadata_collection"_cs, "metadata_collection"_cs, + metadataCollection); return testSpec; } // We retrieve the individual table configurations from the execution state. - const auto uninterpretedTableConfigs = executionState->getTestObjectCategory("tableconfigs"); + const auto uninterpretedTableConfigs = executionState->getTestObjectCategory("tableconfigs"_cs); // Since these configurations are uninterpreted we need to convert them. We launch a // helper function to solve the variables involved in each table configuration. for (const auto &tablePair : uninterpretedTableConfigs) { const auto tableName = tablePair.first; const auto *uninterpretedTableConfig = tablePair.second->checkedTo(); const auto *const tableConfig = uninterpretedTableConfig->evaluate(*finalModel, true); - testSpec->addTestObject("tables", tableName, tableConfig); + testSpec->addTestObject("tables"_cs, tableName, tableConfig); } - const auto actionProfiles = executionState->getTestObjectCategory("action_profile"); + const auto actionProfiles = executionState->getTestObjectCategory("action_profile"_cs); for (const auto &testObject : actionProfiles) { const auto profileName = testObject.first; const auto *actionProfile = testObject.second->checkedTo(); const auto *evaluatedProfile = actionProfile->evaluate(*finalModel, true); - testSpec->addTestObject("action_profiles", profileName, evaluatedProfile); + testSpec->addTestObject("action_profiles"_cs, profileName, evaluatedProfile); } - const auto actionSelectors = executionState->getTestObjectCategory("action_selector"); + const auto actionSelectors = executionState->getTestObjectCategory("action_selector"_cs); for (const auto &testObject : actionSelectors) { const auto selectorName = testObject.first; const auto *actionSelector = testObject.second->checkedTo(); const auto *evaluatedSelector = actionSelector->evaluate(*finalModel, true); - testSpec->addTestObject("action_selectors", selectorName, evaluatedSelector); + testSpec->addTestObject("action_selectors"_cs, selectorName, evaluatedSelector); } return testSpec; diff --git a/backends/p4tools/modules/testgen/targets/pna/test_spec.cpp b/backends/p4tools/modules/testgen/targets/pna/test_spec.cpp index aceaa180a0..e241ee98c4 100644 --- a/backends/p4tools/modules/testgen/targets/pna/test_spec.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/test_spec.cpp @@ -7,6 +7,8 @@ namespace P4Tools::P4Testgen::Pna { +using namespace P4::literals; + /* ========================================================================================= * PnaDpdkRegister * ========================================================================================= */ @@ -20,7 +22,7 @@ void PnaDpdkRegisterValue::addRegisterCondition(PnaDpdkRegisterCondition cond) { const IR::Expression *PnaDpdkRegisterValue::getInitialValue() const { return initialValue; } -cstring PnaDpdkRegisterValue::getObjectName() const { return "PnaDpdkRegisterValue"; } +cstring PnaDpdkRegisterValue::getObjectName() const { return "PnaDpdkRegisterValue"_cs; } const IR::Expression *PnaDpdkRegisterValue::getCurrentValue(const IR::Expression *index) const { const IR::Expression *baseExpr = initialValue; @@ -76,7 +78,7 @@ const PnaDpdkRegisterCondition *PnaDpdkRegisterCondition::evaluate(const Model & return new PnaDpdkRegisterCondition(evaluatedIndex, evaluatedValue); } -cstring PnaDpdkRegisterCondition::getObjectName() const { return "PnaDpdkRegisterCondition"; } +cstring PnaDpdkRegisterCondition::getObjectName() const { return "PnaDpdkRegisterCondition"_cs; } /* ========================================================================================= * PnaDpdkActionProfile @@ -122,7 +124,7 @@ PnaDpdkActionSelector::PnaDpdkActionSelector(const IR::IDeclaration *selectorDec const PnaDpdkActionProfile *actionProfile) : selectorDecl(selectorDecl), actionProfile(actionProfile) {} -cstring PnaDpdkActionSelector::getObjectName() const { return "PnaDpdkActionSelector"; } +cstring PnaDpdkActionSelector::getObjectName() const { return "PnaDpdkActionSelector"_cs; } const IR::IDeclaration *PnaDpdkActionSelector::getSelectorDecl() const { return selectorDecl; } @@ -157,7 +159,7 @@ const Optional *Optional::evaluate(const Model &model, bool doComplete) const { return new Optional(getKey(), evaluatedValue, addMatch); } -cstring Optional::getObjectName() const { return "Optional"; } +cstring Optional::getObjectName() const { return "Optional"_cs; } bool Optional::addAsExactMatch() const { return addMatch; } @@ -194,7 +196,7 @@ const Range *Range::evaluate(const Model &model, bool doComplete) const { MetadataCollection::MetadataCollection() = default; -cstring MetadataCollection::getObjectName() const { return "MetadataCollection"; } +cstring MetadataCollection::getObjectName() const { return "MetadataCollection"_cs; } const MetadataCollection *MetadataCollection::evaluate(const Model & /*model*/, bool /*finalModel*/) const { @@ -213,6 +215,6 @@ void MetadataCollection::addMetaDataField(cstring name, const IR::Literal *metad metadataFields[name] = metadataField; } -cstring Range::getObjectName() const { return "Range"; } +cstring Range::getObjectName() const { return "Range"_cs; } } // namespace P4Tools::P4Testgen::Pna diff --git a/backends/p4tools/modules/testgen/test/small-step/util.h b/backends/p4tools/modules/testgen/test/small-step/util.h index 5f985aab50..673c14cf5e 100644 --- a/backends/p4tools/modules/testgen/test/small-step/util.h +++ b/backends/p4tools/modules/testgen/test/small-step/util.h @@ -46,6 +46,8 @@ class SmallStepTest : public P4ToolsTest { namespace SmallStepUtil { +using namespace P4::literals; + /// Creates a test case with the given header fields for /// stepping on a given expression. std::optional createSmallStepExprTest(const std::string &, @@ -55,7 +57,7 @@ std::optional createSmallStepExprTest(const std::string & template const T *extractExpr(const IR::P4Program &program) { // Get the mau declarations in the P4Program. - auto *decl = program.getDeclsByName("mau")->single(); + auto *decl = program.getDeclsByName("mau"_cs)->single(); // Convert the mau declaration to a control and ensure that // there is a single statement in the body. @@ -86,7 +88,7 @@ void stepAndExamineValue(const T *value, const P4Tools::CompilerResult &compiler ASSERT_TRUE(progInfo); // Create a base state with a parameter continuation to apply the value on. - const auto *v = Continuation::genParameter(value->type, "v", NamespaceContext::Empty); + const auto *v = Continuation::genParameter(value->type, "v"_cs, NamespaceContext::Empty); Body bodyBase({Return(v->param)}); Continuation continuationBase(v, bodyBase); ExecutionState esBase = SmallStepTest::mkState(bodyBase); diff --git a/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp b/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp index 937600d849..8496172cdd 100644 --- a/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp +++ b/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp @@ -10,6 +10,7 @@ #include "lib/cstring.h" namespace Test { +using namespace P4::literals; using ConstraintVector = const std::vector; class Z3SolverSatisfiabilityChecks : public ::testing::Test { @@ -26,8 +27,8 @@ class Z3SolverSatisfiabilityChecks : public ::testing::Test { TEST_F(Z3SolverSatisfiabilityChecks, BitVectors) { const auto *eightBitType = IR::Type_Bits::get(8); - const auto *fooVar = P4Tools::ToolsVariables::getSymbolicVariable(eightBitType, "foo"); - const auto *barVar = P4Tools::ToolsVariables::getSymbolicVariable(eightBitType, "bar"); + const auto *fooVar = P4Tools::ToolsVariables::getSymbolicVariable(eightBitType, "foo"_cs); + const auto *barVar = P4Tools::ToolsVariables::getSymbolicVariable(eightBitType, "bar"_cs); { auto *expression = new IR::Equ(IR::Constant::get(eightBitType, 1), IR::Constant::get(eightBitType, 1)); @@ -81,54 +82,54 @@ TEST_F(Z3SolverSatisfiabilityChecks, BitVectors) { TEST_F(Z3SolverSatisfiabilityChecks, Strings) { const auto *stringType = IR::Type_String::get(); - const auto *fooVar = P4Tools::ToolsVariables::getSymbolicVariable(stringType, "foo"); - const auto *barVar = P4Tools::ToolsVariables::getSymbolicVariable(stringType, "bar"); + const auto *fooVar = P4Tools::ToolsVariables::getSymbolicVariable(stringType, "foo"_cs); + const auto *barVar = P4Tools::ToolsVariables::getSymbolicVariable(stringType, "bar"_cs); { auto *expression = - new IR::Equ(IR::StringLiteral::get("dead"), IR::StringLiteral::get("dead")); + new IR::Equ(IR::StringLiteral::get("dead"_cs), IR::StringLiteral::get("dead"_cs)); ConstraintVector inputExpression = {expression}; testCheckSat(inputExpression, true); } { auto *expression = - new IR::Equ(IR::StringLiteral::get("dead"), IR::StringLiteral::get("beef")); + new IR::Equ(IR::StringLiteral::get("dead"_cs), IR::StringLiteral::get("beef"_cs)); ConstraintVector inputExpression = {expression}; testCheckSat(inputExpression, false); } { - auto *expression = new IR::Equ(fooVar, IR::StringLiteral::get("dead")); + auto *expression = new IR::Equ(fooVar, IR::StringLiteral::get("dead"_cs)); ConstraintVector inputExpression = {expression}; testCheckSat(inputExpression, true); } { - auto *expression = new IR::Equ(fooVar, IR::StringLiteral::get("dead")); - auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("dead")); + auto *expression = new IR::Equ(fooVar, IR::StringLiteral::get("dead"_cs)); + auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("dead"_cs)); ConstraintVector inputExpression = {expression, constraint1}; testCheckSat(inputExpression, true); } { auto *expression = new IR::Equ(fooVar, barVar); - auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("dead")); + auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("dead"_cs)); ConstraintVector inputExpression = {expression, constraint1}; testCheckSat(inputExpression, true); } { auto *expression = new IR::Equ(fooVar, barVar); - auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("dead")); - auto *constraint2 = new IR::Equ(barVar, IR::StringLiteral::get("dead")); + auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("dead"_cs)); + auto *constraint2 = new IR::Equ(barVar, IR::StringLiteral::get("dead"_cs)); ConstraintVector inputExpression = {expression, constraint1, constraint2}; testCheckSat(inputExpression, true); } { - auto *expression = new IR::Equ(fooVar, IR::StringLiteral::get("dead")); - auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("beef")); + auto *expression = new IR::Equ(fooVar, IR::StringLiteral::get("dead"_cs)); + auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("beef"_cs)); ConstraintVector inputExpression = {expression, constraint1}; testCheckSat(inputExpression, false); } { auto *expression = new IR::Equ(fooVar, barVar); - auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("dead")); - auto *constraint2 = new IR::Equ(barVar, IR::StringLiteral::get("beef")); + auto *constraint1 = new IR::Equ(fooVar, IR::StringLiteral::get("dead"_cs)); + auto *constraint2 = new IR::Equ(barVar, IR::StringLiteral::get("beef"_cs)); ConstraintVector inputExpression = {expression, constraint1, constraint2}; testCheckSat(inputExpression, false); } @@ -136,8 +137,8 @@ TEST_F(Z3SolverSatisfiabilityChecks, Strings) { TEST_F(Z3SolverSatisfiabilityChecks, Bools) { const auto *boolType = IR::Type_Boolean::get(); - const auto *fooVar = P4Tools::ToolsVariables::getSymbolicVariable(boolType, "foo"); - const auto *barVar = P4Tools::ToolsVariables::getSymbolicVariable(boolType, "bar"); + const auto *fooVar = P4Tools::ToolsVariables::getSymbolicVariable(boolType, "foo"_cs); + const auto *barVar = P4Tools::ToolsVariables::getSymbolicVariable(boolType, "bar"_cs); { auto *expression = new IR::Equ(IR::BoolLiteral::get(true), IR::BoolLiteral::get(true)); ConstraintVector inputExpression = {expression}; diff --git a/backends/p4tools/modules/testgen/testgen.cpp b/backends/p4tools/modules/testgen/testgen.cpp index e825727bf8..4dc92b80f7 100644 --- a/backends/p4tools/modules/testgen/testgen.cpp +++ b/backends/p4tools/modules/testgen/testgen.cpp @@ -124,8 +124,8 @@ int generateAndWriteAbstractTests(const TestgenOptions &testgenOptions, } // The test name is the stem of the output base path. - TestBackendConfiguration testBackendConfiguration{testPath.c_str(), testgenOptions.maxTests, - testPath, testgenOptions.seed}; + TestBackendConfiguration testBackendConfiguration{ + cstring(testPath.c_str()), testgenOptions.maxTests, testPath, testgenOptions.seed}; // Need to declare the solver here to ensure its lifetime. Z3Solver solver; diff --git a/backends/p4tools/p4tools.def b/backends/p4tools/p4tools.def index 56721564f2..44d55d1db6 100644 --- a/backends/p4tools/p4tools.def +++ b/backends/p4tools/p4tools.def @@ -173,11 +173,11 @@ class Extracted_Varbits : Type_Bits { return size == a.size; } - cstring baseName() const { return "SizedVarbit"; } + cstring baseName() const { return "SizedVarbit"_cs; } toString { - return baseName() + "<" + Util::toString(size) + ">" + "<" + Util::toString(assignedSize) + - ">"; + return baseName() + "<"_cs + Util::toString(size) + ">"_cs + "<"_cs + Util::toString(assignedSize) + + ">"_cs; } dbprint { out << toString(); } @@ -209,11 +209,11 @@ public: optional inline IndexedVector associatedNodes; /// The name of the concolic method that this variable targets. - inline cstring concolicMethodName = ""; + inline cstring concolicMethodName = cstring::empty; toString { - cstring argumentStr = ""; - cstring sep = ""; + std::string argumentStr = ""; + std::string sep = ""; for (const auto *arg : *arguments) { argumentStr += sep + arg->toString(); sep = ", "; @@ -290,7 +290,7 @@ class InOutReference : Expression { Expression(ref.type), ref(ref), resolvedRef(resolvedRef) { validate(); } - toString { return ref->toString() + "(" + resolvedRef->toString() + ")"; } + toString { return ref->toString() + "("_cs + resolvedRef->toString() + ")"_cs; } dbprint { out << ref << "(" << resolvedRef << ")"; } } diff --git a/backends/tc/backend.cpp b/backends/tc/backend.cpp index 662f3eae0f..8b8ac1dfef 100644 --- a/backends/tc/backend.cpp +++ b/backends/tc/backend.cpp @@ -23,19 +23,22 @@ and limitations under the License. namespace TC { -const cstring Extern::dropPacket = "drop_packet"; -const cstring Extern::sendToPort = "send_to_port"; +using namespace P4::literals; -cstring pnaMainParserInputMetaFields[TC::MAX_PNA_PARSER_META] = {"recirculated", "input_port"}; +const cstring Extern::dropPacket = "drop_packet"_cs; +const cstring Extern::sendToPort = "send_to_port"_cs; + +cstring pnaMainParserInputMetaFields[TC::MAX_PNA_PARSER_META] = {"recirculated"_cs, + "input_port"_cs}; cstring pnaMainInputMetaFields[TC::MAX_PNA_INPUT_META] = { - "recirculated", "timestamp", "parser_error", "class_of_service", "input_port"}; + "recirculated"_cs, "timestamp"_cs, "parser_error"_cs, "class_of_service"_cs, "input_port"_cs}; -cstring pnaMainOutputMetaFields[TC::MAX_PNA_OUTPUT_META] = {"class_of_service"}; +cstring pnaMainOutputMetaFields[TC::MAX_PNA_OUTPUT_META] = {"class_of_service"_cs}; -const cstring pnaParserMeta = "pna_main_parser_input_metadata_t"; -const cstring pnaInputMeta = "pna_main_input_metadata_t"; -const cstring pnaOutputMeta = "pna_main_output_metadata_t"; +const cstring pnaParserMeta = "pna_main_parser_input_metadata_t"_cs; +const cstring pnaInputMeta = "pna_main_input_metadata_t"_cs; +const cstring pnaOutputMeta = "pna_main_output_metadata_t"_cs; bool Backend::process() { CHECK_NULL(toplevel); @@ -188,11 +191,11 @@ void ConvertToBackendIR::setPipelineName() { } auto fileName = path.findlast('/'); if (fileName) { - pipelineName = fileName; - pipelineName = pipelineName.replace("/", ""); + pipelineName = cstring(fileName); + pipelineName = pipelineName.replace("/"_cs, ""_cs); } - auto fileext = pipelineName.find("."); - pipelineName = pipelineName.replace(fileext, ""); + auto fileext = cstring(pipelineName.find(".")); + pipelineName = pipelineName.replace(fileext, ""_cs); pipelineName = pipelineName.trim(); } @@ -222,8 +225,8 @@ void ConvertToBackendIR::postorder(const IR::P4Action *action) { if (isDuplicateAction(action)) return; auto actionName = externalName(action); if (actionName == P4::P4CoreLibrary::instance().noAction.name) { - tcPipeline->addNoActionDefinition(new IR::TCAction("NoAction")); - actions.emplace("NoAction", action); + tcPipeline->addNoActionDefinition(new IR::TCAction("NoAction"_cs)); + actions.emplace("NoAction"_cs, action); return; } actions.emplace(actionName, action); @@ -314,14 +317,14 @@ void ConvertToBackendIR::updateConstEntries(const IR::P4Table *t, IR::TCTable *t auto keyString = keyElement->expression->toString(); auto annotations = keyElement->getAnnotations(); if (annotations) { - if (auto anno = annotations->getSingle("name")) { + if (auto anno = annotations->getSingle("name"_cs)) { keyString = anno->expr.at(0)->to()->value; } } auto keySetElement = keyset->components.at(itr); auto key = keySetElement->toString(); if (keySetElement->is()) { - key = "default"; + key = "default"_cs; } else if (keySetElement->is()) { big_int kValue = keySetElement->to()->value; int kBase = keySetElement->to()->base; @@ -348,7 +351,7 @@ void ConvertToBackendIR::updateConstEntries(const IR::P4Table *t, IR::TCTable *t buf.push_front(Util::DigitToChar(digit)); } while (kValue > 0); for (auto ch : buf) value << ch; - key = value.str().c_str(); + key = value.str(); } else if (keySetElement->is()) { auto left = keySetElement->to()->left; auto right = keySetElement->to()->right; @@ -575,7 +578,7 @@ void ConvertToBackendIR::updateAddOnMissTable(const IR::P4Table *t) { } } -unsigned ConvertToBackendIR::GetAccessNumericValue(cstring access) { +unsigned ConvertToBackendIR::GetAccessNumericValue(std::string_view access) { unsigned value = 0; for (auto s : access) { unsigned mask = 0; @@ -626,12 +629,12 @@ cstring ConvertToBackendIR::HandleTableAccessPermission(const IR::P4Table *t) { } // Default access value of Control_path and Data_Path if (control_path.isNullOrEmpty()) { - control_path = IsTableAddOnMiss ? DEFAULT_ADD_ON_MISS_TABLE_CONTROL_PATH_ACCESS - : DEFAULT_TABLE_CONTROL_PATH_ACCESS; + control_path = cstring(IsTableAddOnMiss ? DEFAULT_ADD_ON_MISS_TABLE_CONTROL_PATH_ACCESS + : DEFAULT_TABLE_CONTROL_PATH_ACCESS); } if (data_path.isNullOrEmpty()) { - data_path = IsTableAddOnMiss ? DEFAULT_ADD_ON_MISS_TABLE_DATA_PATH_ACCESS - : DEFAULT_TABLE_DATA_PATH_ACCESS; + data_path = cstring(IsTableAddOnMiss ? DEFAULT_ADD_ON_MISS_TABLE_DATA_PATH_ACCESS + : DEFAULT_TABLE_DATA_PATH_ACCESS); } if (IsTableAddOnMiss) { @@ -643,12 +646,13 @@ cstring ConvertToBackendIR::HandleTableAccessPermission(const IR::P4Table *t) { t->name.originalName); } } - auto access_cp = GetAccessNumericValue(control_path); - auto access_dp = GetAccessNumericValue(data_path); + // FIXME: refactor not to require cstring + auto access_cp = GetAccessNumericValue(control_path.string_view()); + auto access_dp = GetAccessNumericValue(data_path.string_view()); auto access_permisson = (access_cp << 7) | access_dp; std::stringstream value; value << "0x" << std::hex << access_permisson; - return value.str().c_str(); + return value.str(); } std::pair *ConvertToBackendIR::GetAnnotatedAccessPath( @@ -771,17 +775,17 @@ cstring ConvertToBackendIR::processExternPermission(const IR::Type_Extern *ext) } // Default access value of Control_path and Data_Path if (control_path.isNullOrEmpty()) { - control_path = DEFAULT_EXTERN_CONTROL_PATH_ACCESS; + control_path = cstring(DEFAULT_EXTERN_CONTROL_PATH_ACCESS); } if (data_path.isNullOrEmpty()) { - data_path = DEFAULT_EXTERN_DATA_PATH_ACCESS; + data_path = cstring(DEFAULT_EXTERN_DATA_PATH_ACCESS); } - auto access_cp = GetAccessNumericValue(control_path); - auto access_dp = GetAccessNumericValue(data_path); + auto access_cp = GetAccessNumericValue(control_path.string_view()); + auto access_dp = GetAccessNumericValue(data_path.string_view()); auto access_permisson = (access_cp << 7) | access_dp; std::stringstream value; value << "0x" << std::hex << access_permisson; - return value.str().c_str(); + return value.str(); } void ConvertToBackendIR::processExternConstructorAnnotations(const IR::Type_Extern *extn, @@ -835,7 +839,7 @@ safe_vector ConvertToBackendIR::processExternControlPath( annotation->name == ParseTCAnnotations::tc_data_scalar) { annoName = annotation->name; } else if (annotation->name == ParseTCAnnotations::tc_data) { - annoName = "param"; + annoName = "param"_cs; } /* If the field is of Type_Name example 'T' and 'T' is of Type_Struct, extract all fields of structure*/ diff --git a/backends/tc/backend.h b/backends/tc/backend.h index 09722983f0..14b4a21118 100644 --- a/backends/tc/backend.h +++ b/backends/tc/backend.h @@ -99,7 +99,7 @@ class ConvertToBackendIR : public Inspector { safe_vector processExternControlPath(const IR::Type_SpecializedCanonical *ts, const IR::Type_Extern *extn, cstring eName); - unsigned GetAccessNumericValue(cstring access); + unsigned GetAccessNumericValue(std::string_view access); bool isDuplicateAction(const IR::P4Action *action); bool isDuplicateOrNoAction(const IR::P4Action *action); void updateDefaultHitAction(const IR::P4Table *t, IR::TCTable *tdef); diff --git a/backends/tc/ebpfCodeGen.cpp b/backends/tc/ebpfCodeGen.cpp index 6b387ca42f..c6459cb15c 100644 --- a/backends/tc/ebpfCodeGen.cpp +++ b/backends/tc/ebpfCodeGen.cpp @@ -28,7 +28,7 @@ void PNAEbpfGenerator::emitPNAIncludes(EBPF::CodeBuilder *builder) const { cstring PNAEbpfGenerator::getProgramName() const { auto progName = options.file; auto filename = progName.findlast('/'); - if (filename) progName = filename; + if (filename) progName = cstring(filename); progName = progName.exceptLast(3); progName = progName.trim("/\t\n\r"); return progName; @@ -76,13 +76,13 @@ void PNAEbpfGenerator::emitGlobalHeadersMetadata(EBPF::CodeBuilder *builder) con builder->blockStart(); builder->emitIndent(); - pipeline->parser->headerType->declare(builder, "cpumap_hdr", false); + pipeline->parser->headerType->declare(builder, "cpumap_hdr"_cs, false); builder->endOfStatement(true); builder->emitIndent(); auto user_md_type = pipeline->typeMap->getType(pipeline->control->user_metadata); BUG_CHECK(user_md_type != nullptr, "cannot declare user metadata"); auto userMetadataType = EBPF::EBPFTypeFactory::instance->create(user_md_type); - userMetadataType->declare(builder, "cpumap_usermeta", false); + userMetadataType->declare(builder, "cpumap_usermeta"_cs, false); builder->endOfStatement(true); builder->emitIndent(); @@ -169,8 +169,8 @@ void PNAEbpfGenerator::emitPipelineInstances(EBPF::CodeBuilder *builder) const { pipeline->parser->emitValueSetInstances(builder); pipeline->deparser->emitDigestInstances(builder); - builder->target->emitTableDecl(builder, "hdr_md_cpumap", EBPF::TablePerCPUArray, "u32", - "struct hdr_md", 2); + builder->target->emitTableDecl(builder, "hdr_md_cpumap"_cs, EBPF::TablePerCPUArray, "u32"_cs, + "struct hdr_md"_cs, 2); } // =====================PNAArchTC============================= @@ -211,8 +211,8 @@ void PNAArchTC::emitInstances(EBPF::CodeBuilder *builder) const { builder->appendLine("REGISTER_START()"); if (options.xdp2tcMode == XDP2TC_CPUMAP) { - builder->target->emitTableDecl(builder, "xdp2tc_cpumap", EBPF::TablePerCPUArray, "u32", - "u16", 1); + builder->target->emitTableDecl(builder, "xdp2tc_cpumap"_cs, EBPF::TablePerCPUArray, + "u32"_cs, "u16"_cs, 1); } emitPipelineInstances(builder); @@ -235,9 +235,9 @@ void PNAArchTC::emitParser(EBPF::CodeBuilder *builder) const { builder->newline(); builder->appendLine("struct p4tc_filter_fields p4tc_filter_fields;"); builder->newline(); - pipeline->name = "tc-parse"; - pipeline->sectionName = "p4tc/parse"; - pipeline->functionName = pipeline->name.replace("-", "_") + "_func"; + pipeline->name = "tc-parse"_cs; + pipeline->sectionName = "p4tc/parse"_cs; + pipeline->functionName = pipeline->name.replace('-', '_') + "_func"; pipeline->emit(builder); builder->target->emitLicense(builder, pipeline->license); } @@ -267,7 +267,7 @@ void TCIngressPipelinePNA::emit(EBPF::CodeBuilder *builder) { builder->append("static __always_inline"); builder->spc(); // FIXME: use Target to generate metadata type - cstring func_name = (name == "tc-parse") ? "run_parser" : "process"; + cstring func_name = (name == "tc-parse") ? "run_parser"_cs : "process"_cs; builder->appendFormat( "int %s(%s *%s, %s %s *%s, " "struct pna_global_metadata *%s", @@ -526,14 +526,14 @@ void TCIngressPipelinePNA::emitLocalVariables(EBPF::CodeBuilder *builder) { builder->newline(); builder->emitIndent(); builder->appendFormat("void* %s = %s;", packetStartVar.c_str(), - builder->target->dataOffset(model.CPacketName.str()).c_str()); + builder->target->dataOffset(model.CPacketName.toString()).c_str()); builder->newline(); builder->emitIndent(); builder->appendFormat("u8* %s = %s;", headerStartVar.c_str(), packetStartVar.c_str()); builder->newline(); builder->emitIndent(); builder->appendFormat("void* %s = %s;", packetEndVar.c_str(), - builder->target->dataEnd(model.CPacketName.str()).c_str()); + builder->target->dataEnd(model.CPacketName.toString()).c_str()); builder->newline(); builder->emitIndent(); builder->appendFormat("u32 %s = 0;", zeroKey.c_str()); @@ -737,7 +737,7 @@ void PnaStateTranslationVisitor::compileExtractField(const IR::Expression *expr, if (auto member = expr->to()) { if (auto pathExpr = member->expr->to()) { if (isPointerVariable(pathExpr->path->name.name)) { - exprStr = exprStr.replace(".", "->"); + exprStr = exprStr.replace("."_cs, "->"_cs); } } } @@ -1200,11 +1200,11 @@ void IngressDeparserPNA::emit(EBPF::CodeBuilder *builder) { emitBufferAdjusts(builder); builder->emitIndent(); builder->appendFormat("%s = %s;", program->packetStartVar, - builder->target->dataOffset(program->model.CPacketName.str())); + builder->target->dataOffset(program->model.CPacketName.toString())); builder->newline(); builder->emitIndent(); builder->appendFormat("%s = %s;", program->packetEndVar, - builder->target->dataEnd(program->model.CPacketName.str())); + builder->target->dataEnd(program->model.CPacketName.toString())); builder->newline(); builder->emitIndent(); @@ -1249,17 +1249,17 @@ const PNAEbpfGenerator *ConvertToEbpfPNA::build(const IR::ToplevelBlock *tlb) { * PIPELINE */ auto pipeline = tlb->getMain()->checkedTo(); - auto pipelineParser = pipeline->getParameterValue("main_parser"); + auto pipelineParser = pipeline->getParameterValue("main_parser"_cs); BUG_CHECK(pipelineParser != nullptr, "No parser block found"); - auto pipelineControl = pipeline->getParameterValue("main_control"); + auto pipelineControl = pipeline->getParameterValue("main_control"_cs); BUG_CHECK(pipelineControl != nullptr, "No control block found"); - auto pipelineDeparser = pipeline->getParameterValue("main_deparser"); + auto pipelineDeparser = pipeline->getParameterValue("main_deparser"_cs); BUG_CHECK(pipelineDeparser != nullptr, "No deparser block found"); auto xdp = new EBPF::XDPHelpProgram(options); auto pipeline_converter = new ConvertToEbpfPipelineTC( - "tc-ingress", EBPF::TC_INGRESS, options, pipelineParser->checkedTo(), + "tc-ingress"_cs, EBPF::TC_INGRESS, options, pipelineParser->checkedTo(), pipelineControl->checkedTo(), pipelineDeparser->checkedTo(), refmap, typemap, tcIR); pipeline->apply(*pipeline_converter); @@ -1280,7 +1280,7 @@ bool ConvertToEbpfPipelineTC::preorder(const IR::PackageBlock *block) { (void)block; pipeline = new TCIngressPipelinePNA(name, options, refmap, typemap); - pipeline->sectionName = "p4tc/main"; + pipeline->sectionName = "p4tc/main"_cs; auto parser_converter = new ConvertToEBPFParserPNA(pipeline, typemap); parserBlock->apply(*parser_converter); pipeline->parser = parser_converter->getEBPFParser(); @@ -1531,7 +1531,7 @@ cstring ControlBodyTranslatorPNA::getParamName(const IR::PathExpression *expr) { } bool ControlBodyTranslatorPNA::IsTableAddOnMiss(const IR::P4Table *table) { - auto property = table->getBooleanProperty("add_on_miss"); + auto property = table->getBooleanProperty("add_on_miss"_cs); if (property && property->value) { return true; } @@ -1544,7 +1544,7 @@ const IR::P4Action *ControlBodyTranslatorPNA::GetAddOnMissHitAction(cstring acti auto action = adecl->getNode()->to(); if (action->name.originalName == actionName) { auto annotations = a->getAnnotations(); - if (annotations && annotations->getSingle("defaultonly")) { + if (annotations && annotations->getSingle("defaultonly"_cs)) { ::error(ErrorType::ERR_UNEXPECTED, "add_entry hit action %1% cannot be annotated with defaultonly.", actionName); @@ -1766,7 +1766,7 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) { builder->blockStart(); BUG_CHECK(method->expr->arguments->size() == 0, "%1%: table apply with arguments", method); - cstring keyname = "key"; + cstring keyname = "key"_cs; if (table->keyGenerator != nullptr) { builder->emitIndent(); builder->appendLine("/* construct key */"); @@ -1804,7 +1804,7 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) { auto tcTarget = dynamic_cast(builder->target); cstring isKeyBigEndian = tcTarget->getByteOrderFromAnnotation(c->getAnnotations()->annotations); - cstring isDefnBigEndian = "HOST"; + cstring isDefnBigEndian = "HOST"_cs; if (auto mem = c->expression->to()) { auto type = typeMap->getType(mem->expr, true); if (type->is()) { @@ -1821,13 +1821,13 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) { if (isKeyBigEndian == "NETWORK" && isDefnBigEndian == "HOST") { if (width <= 8) { - swap = ""; // single byte, nothing to swap + swap = ""_cs; // single byte, nothing to swap } else if (width <= 16) { - swap = "bpf_htons"; + swap = "bpf_htons"_cs; } else if (width <= 32) { - swap = "bpf_htonl"; + swap = "bpf_htonl"_cs; } else if (width <= 64) { - swap = "bpf_htonll"; + swap = "bpf_htonll"_cs; } /* For width greater than 64 bit, there is no need of conversion. and the value will be copied directly from memory.*/ @@ -1868,7 +1868,7 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) { builder->emitIndent(); builder->appendLine("/* value */"); builder->emitIndent(); - cstring valueName = "value"; + cstring valueName = "value"_cs; builder->appendFormat("struct %s *%s = NULL", table->valueTypeName.c_str(), valueName.c_str()); builder->endOfStatement(true); @@ -2138,7 +2138,7 @@ void DeparserHdrEmitTranslatorPNA::emitField(EBPF::CodeBuilder *builder, cstring } unsigned widthToEmit = et->widthInBits(); unsigned emitSize = 0; - cstring swap = "", msgStr; + cstring swap = ""_cs, msgStr; if (widthToEmit <= 64) { if (program->options.emitTraceMessages) { @@ -2162,13 +2162,13 @@ void DeparserHdrEmitTranslatorPNA::emitField(EBPF::CodeBuilder *builder, cstring if (widthToEmit <= 8) { emitSize = 8; } else if (widthToEmit <= 16) { - swap = "bpf_htons"; + swap = "bpf_htons"_cs; emitSize = 16; } else if (widthToEmit <= 32) { - swap = "htonl"; + swap = "htonl"_cs; emitSize = 32; } else if (widthToEmit <= 64) { - swap = "htonll"; + swap = "htonll"_cs; emitSize = 64; } unsigned shift = @@ -2252,7 +2252,7 @@ void CRCChecksumAlgorithmPNA::emitUpdateMethod(EBPF::CodeBuilder *builder, int c // incremented. For data shorter than or equal 64 bits, bytes are processed in little endian // byte order - data pointer is decremented by outer loop in this case. // There is no need for lookup table. - cstring code = + const char *code = "static __always_inline\n" "void crc16_update(u16 * reg, const u8 * data, " "u16 data_size, const u16 poly) {\n" @@ -2284,7 +2284,7 @@ void CRCChecksumAlgorithmPNA::emitUpdateMethod(EBPF::CodeBuilder *builder, int c // 4. Data size more than 8 bytes and not multiply of 8 bytes - calculated using slice-by-8 // and Standard Implementation both in big endian byte order. // Lookup table is necessary for both algorithms. - cstring code = + const char *code = "static __always_inline\n" "void crc32_update(u32 * reg, const u8 * data, u16 data_size, const u32 poly) {\n" " u32* current = (u32*) data;\n" @@ -2369,7 +2369,7 @@ void CRCChecksumAlgorithmPNA::emitUpdateMethod(EBPF::CodeBuilder *builder, int c void CRC16ChecksumAlgorithmPNA::emitGlobals(EBPF::CodeBuilder *builder) { CRCChecksumAlgorithmPNA::emitUpdateMethod(builder, 16); - cstring code = + const char *code = "static __always_inline " "u16 crc16_finalize(u16 reg) {\n" " return reg;\n" @@ -2382,7 +2382,7 @@ void CRC16ChecksumAlgorithmPNA::emitGlobals(EBPF::CodeBuilder *builder) { void CRC32ChecksumAlgorithmPNA::emitGlobals(EBPF::CodeBuilder *builder) { CRCChecksumAlgorithmPNA::emitUpdateMethod(builder, 32); - cstring code = + const char *code = "static __always_inline " "u32 crc32_finalize(u32 reg) {\n" " return reg ^ 0xFFFFFFFF;\n" diff --git a/backends/tc/ebpfCodeGen.h b/backends/tc/ebpfCodeGen.h index e0975115a9..228741374f 100644 --- a/backends/tc/ebpfCodeGen.h +++ b/backends/tc/ebpfCodeGen.h @@ -17,11 +17,14 @@ and limitations under the License. #ifndef BACKENDS_TC_EBPFCODEGEN_H_ #define BACKENDS_TC_EBPFCODEGEN_H_ +// FIXME: these include each other and present file #include "backend.h" #include "tcExterns.h" namespace TC { +using namespace P4::literals; + class ConvertToBackendIR; class EBPFPnaParser; class EBPFRegisterPNA; @@ -402,12 +405,12 @@ class CRC16ChecksumAlgorithmPNA : public CRCChecksumAlgorithmPNA { public: CRC16ChecksumAlgorithmPNA(const EBPF::EBPFProgram *program, cstring name) : CRCChecksumAlgorithmPNA(program, name, 16) { - initialValue = "0"; + initialValue = "0"_cs; // We use a 0x8005 polynomial. // 0xA001 comes from 0x8005 value bits reflection. - polynomial = "0xA001"; - updateMethod = "crc16_update"; - finalizeMethod = "crc16_finalize"; + polynomial = "0xA001"_cs; + updateMethod = "crc16_update"_cs; + finalizeMethod = "crc16_finalize"_cs; } static void emitGlobals(EBPF::CodeBuilder *builder); @@ -417,12 +420,12 @@ class CRC32ChecksumAlgorithmPNA : public CRCChecksumAlgorithmPNA { public: CRC32ChecksumAlgorithmPNA(const EBPF::EBPFProgram *program, cstring name) : CRCChecksumAlgorithmPNA(program, name, 32) { - initialValue = "0xffffffff"; + initialValue = "0xffffffff"_cs; // We use a 0x04C11DB7 polynomial. // 0xEDB88320 comes from 0x04C11DB7 value bits reflection. - polynomial = "0xEDB88320"; - updateMethod = "crc32_update"; - finalizeMethod = "crc32_finalize"; + polynomial = "0xEDB88320"_cs; + updateMethod = "crc32_update"_cs; + finalizeMethod = "crc32_finalize"_cs; } static void emitGlobals(EBPF::CodeBuilder *builder); diff --git a/backends/tc/introspection.cpp b/backends/tc/introspection.cpp index 181b4d7c93..029395acc3 100644 --- a/backends/tc/introspection.cpp +++ b/backends/tc/introspection.cpp @@ -180,23 +180,23 @@ void IntrospectionGenerator::collectExternInfo() { Util::JsonObject *IntrospectionGenerator::genExternInfo(struct ExternAttributes *extn) { auto externJson = new Util::JsonObject(); - externJson->emplace("name", extn->name); - externJson->emplace("id", extn->id); - externJson->emplace("permissions", extn->permissions); + externJson->emplace("name"_cs, extn->name); + externJson->emplace("id"_cs, extn->id); + externJson->emplace("permissions"_cs, extn->permissions); auto instanceJson = new Util::JsonArray(); for (auto eInstance : extn->instances) { auto eInstanceJson = new Util::JsonObject(); - eInstanceJson->emplace("inst_name", eInstance->name); - eInstanceJson->emplace("inst_id", eInstance->id); + eInstanceJson->emplace("inst_name"_cs, eInstance->name); + eInstanceJson->emplace("inst_id"_cs, eInstance->id); auto paramArray = new Util::JsonArray(); for (auto param : eInstance->keyFields) { auto keyJson = genKeyInfo(param); paramArray->append(keyJson); } - eInstanceJson->emplace("params", paramArray); + eInstanceJson->emplace("params"_cs, paramArray); instanceJson->append(eInstanceJson); } - externJson->emplace("instances", instanceJson); + externJson->emplace("instances"_cs, instanceJson); return externJson; } @@ -216,95 +216,95 @@ void IntrospectionGenerator::genTableJson(Util::JsonArray *tablesJson) { Util::JsonObject *IntrospectionGenerator::genActionInfo(struct ActionAttributes *action) { auto actionJson = new Util::JsonObject(); - actionJson->emplace("id", action->id); - actionJson->emplace("name", action->name); - cstring actionScope = ""; + actionJson->emplace("id"_cs, action->id); + actionJson->emplace("name"_cs, action->name); + cstring actionScope; if (action->scope == TableOnly) { - actionScope = "TableOnly"; + actionScope = "TableOnly"_cs; } else if (action->scope == DefaultOnly) { - actionScope = "DefaultOnly"; + actionScope = "DefaultOnly"_cs; } else { - actionScope = "TableAndDefault"; + actionScope = "TableAndDefault"_cs; } - actionJson->emplace("action_scope", actionScope); + actionJson->emplace("action_scope"_cs, actionScope); auto annoArray = new Util::JsonArray(); for (auto anno : action->annotations) { annoArray->append(anno->name); } - actionJson->emplace("annotations", annoArray); + actionJson->emplace("annotations"_cs, annoArray); auto paramArray = new Util::JsonArray(); for (auto param : action->actionParams) { auto paramJson = new Util::JsonObject(); - paramJson->emplace("id", param->id); - paramJson->emplace("name", param->name); + paramJson->emplace("id"_cs, param->id); + paramJson->emplace("name"_cs, param->name); switch (param->dataType) { case TC::BIT_TYPE: { auto paramtype = "bit" + Util::toString(param->bitwidth); - paramJson->emplace("type", paramtype); + paramJson->emplace("type"_cs, paramtype); break; } case TC::DEV_TYPE: { - paramJson->emplace("type", "dev"); + paramJson->emplace("type"_cs, "dev"); break; } case TC::MACADDR_TYPE: { - paramJson->emplace("type", "macaddr"); + paramJson->emplace("type"_cs, "macaddr"); break; } case TC::IPV4_TYPE: { - paramJson->emplace("type", "ipv4"); + paramJson->emplace("type"_cs, "ipv4"); break; } case TC::IPV6_TYPE: { - paramJson->emplace("type", "ipv6"); + paramJson->emplace("type"_cs, "ipv6"); break; } case TC::BE16_TYPE: { - paramJson->emplace("type", "be16"); + paramJson->emplace("type"_cs, "be16"); break; } case TC::BE32_TYPE: { - paramJson->emplace("type", "be32"); + paramJson->emplace("type"_cs, "be32"); break; } case TC::BE64_TYPE: { - paramJson->emplace("type", "be64"); + paramJson->emplace("type"_cs, "be64"); break; } } - paramJson->emplace("bitwidth", param->bitwidth); + paramJson->emplace("bitwidth"_cs, param->bitwidth); paramArray->append(paramJson); } - actionJson->emplace("params", paramArray); - actionJson->emplace("default_hit_action", action->defaultHit); - actionJson->emplace("default_miss_action", action->defaultMiss); + actionJson->emplace("params"_cs, paramArray); + actionJson->emplace("default_hit_action"_cs, action->defaultHit); + actionJson->emplace("default_miss_action"_cs, action->defaultMiss); return actionJson; } Util::JsonObject *IntrospectionGenerator::genKeyInfo(struct KeyFieldAttributes *keyField) { auto keyJson = new Util::JsonObject(); - keyJson->emplace("id", keyField->id); - keyJson->emplace("name", keyField->name); - keyJson->emplace("type", keyField->type); + keyJson->emplace("id"_cs, keyField->id); + keyJson->emplace("name"_cs, keyField->name); + keyJson->emplace("type"_cs, keyField->type); if (keyField->attribute) { - keyJson->emplace("attr", keyField->attribute); + keyJson->emplace("attr"_cs, keyField->attribute); } if (keyField->matchType) { - keyJson->emplace("match_type", keyField->matchType); + keyJson->emplace("match_type"_cs, keyField->matchType); } - keyJson->emplace("bitwidth", keyField->bitwidth); + keyJson->emplace("bitwidth"_cs, keyField->bitwidth); return keyJson; } Util::JsonObject *IntrospectionGenerator::genTableInfo(struct TableAttributes *tbl) { auto tableJson = new Util::JsonObject(); - tableJson->emplace("name", tbl->name); - tableJson->emplace("id", tbl->id); - tableJson->emplace("tentries", tbl->tentries); - tableJson->emplace("permissions", tbl->permissions); - tableJson->emplace("nummask", tbl->numMask); + tableJson->emplace("name"_cs, tbl->name); + tableJson->emplace("id"_cs, tbl->id); + tableJson->emplace("tentries"_cs, tbl->tentries); + tableJson->emplace("permissions"_cs, tbl->permissions); + tableJson->emplace("nummask"_cs, tbl->numMask); if (tbl->keysize != 0) { - tableJson->emplace("keysize", tbl->keysize); + tableJson->emplace("keysize"_cs, tbl->keysize); } auto keysJson = new Util::JsonArray(); for (auto keyField : tbl->keyFields) { @@ -312,7 +312,7 @@ Util::JsonObject *IntrospectionGenerator::genTableInfo(struct TableAttributes *t keysJson->append(keyJson); } if (keysJson->size() != 0) { - tableJson->emplace("keyfields", keysJson); + tableJson->emplace("keyfields"_cs, keysJson); } auto actionsJson = new Util::JsonArray(); for (auto action : tbl->actions) { @@ -320,7 +320,7 @@ Util::JsonObject *IntrospectionGenerator::genTableInfo(struct TableAttributes *t actionsJson->append(actionJson); } if (actionsJson->size() != 0) { - tableJson->emplace("actions", actionsJson); + tableJson->emplace("actions"_cs, actionsJson); } return tableJson; } @@ -333,12 +333,12 @@ const Util::JsonObject *IntrospectionGenerator::genIntrospectionJson() { collectTableInfo(); collectExternInfo(); introspec.initIntrospectionInfo(tcPipeline); - json->emplace("schema_version", introspec.schemaVersion); - json->emplace("pipeline_name", introspec.pipelineName); + json->emplace("schema_version"_cs, introspec.schemaVersion); + json->emplace("pipeline_name"_cs, introspec.pipelineName); genExternJson(externJson); - json->emplace("externs", externJson); + json->emplace("externs"_cs, externJson); genTableJson(tablesJson); - json->emplace("tables", tablesJson); + json->emplace("tables"_cs, tablesJson); return json; } diff --git a/backends/tc/introspection.h b/backends/tc/introspection.h index 6608e743b9..1a2d72a308 100644 --- a/backends/tc/introspection.h +++ b/backends/tc/introspection.h @@ -30,6 +30,8 @@ and limitations under the License. /// control plane programming by P4TC in Linux kernel namespace TC { +using namespace P4::literals; + struct IntrospectionInfo { cstring schemaVersion; cstring pipelineName; @@ -38,7 +40,7 @@ struct IntrospectionInfo { pipelineName = nullptr; } void initIntrospectionInfo(IR::TCPipeline *tcPipeline) { - schemaVersion = "1.0.0"; + schemaVersion = "1.0.0"_cs; pipelineName = tcPipeline->pipelineName; } }; diff --git a/backends/tc/midend.cpp b/backends/tc/midend.cpp index 469a79dfe6..d7d52001b4 100644 --- a/backends/tc/midend.cpp +++ b/backends/tc/midend.cpp @@ -61,7 +61,7 @@ const IR::ToplevelBlock *MidEnd::run(TCOptions &options, const IR::P4Program *pr evaluator, new P4::MidEndLast()}); if (options.listMidendPasses) { - midEnd.listPasses(*outStream, "\n"); + midEnd.listPasses(*outStream, cstring::newline); *outStream << std::endl; } midEnd.setName("MidEnd"); diff --git a/backends/tc/options.h b/backends/tc/options.h index d3a20b7fad..2051f098ee 100644 --- a/backends/tc/options.h +++ b/backends/tc/options.h @@ -23,10 +23,12 @@ and limitations under the License. namespace TC { +using namespace P4::literals; + class TCOptions : public CompilerOptions { public: // file to output to - cstring outputFolder = nullptr; + cstring outputFolder = ""_cs; bool DebugOn = false; // tracing eBPF code execution bool emitTraceMessages = false; @@ -38,7 +40,7 @@ class TCOptions : public CompilerOptions { registerOption( "-o", "output Directory", [this](const char *arg) { - outputFolder = arg; + outputFolder = cstring(arg); return true; }, "Write pipeline template, introspection json and C output to given directory"); diff --git a/backends/tc/pnaProgramStructure.cpp b/backends/tc/pnaProgramStructure.cpp index bedbda2371..09da41c1c7 100644 --- a/backends/tc/pnaProgramStructure.cpp +++ b/backends/tc/pnaProgramStructure.cpp @@ -18,6 +18,8 @@ and limitations under the License. namespace TC { +using namespace P4::literals; + void InspectPnaProgram::postorder(const IR::Declaration_Instance *di) { if (!pinfo->resourceMap.count(di)) return; auto blk = pinfo->resourceMap.at(di); @@ -231,7 +233,7 @@ bool ParsePnaArchitecture::preorder(const IR::ExternBlock *block) { bool ParsePnaArchitecture::preorder(const IR::PackageBlock *block) { if (auto pna_nic = block->to()) { - auto p = pna_nic->findParameterValue("main_parser"); + auto p = pna_nic->findParameterValue("main_parser"_cs); if (p == nullptr) { modelError("'PNA_NIC' package %1% has no parameter named 'ip'", block); return false; @@ -242,7 +244,7 @@ bool ParsePnaArchitecture::preorder(const IR::PackageBlock *block) { block); return false; } - p = pna_nic->findParameterValue("main_control"); + p = pna_nic->findParameterValue("main_control"_cs); if (p == nullptr) { modelError("'PNA_NIC' package %1% has no parameter named 'main_control'", block); return false; @@ -253,7 +255,7 @@ bool ParsePnaArchitecture::preorder(const IR::PackageBlock *block) { block); return false; } - p = pna_nic->findParameterValue("main_deparser"); + p = pna_nic->findParameterValue("main_deparser"_cs); if (p == nullptr) { modelError("'PNA_NIC' package %1% has no parameter named 'main_deparser'", block); return false; diff --git a/backends/tc/tc.def b/backends/tc/tc.def index ab0752fbb3..58e25f7a5b 100644 --- a/backends/tc/tc.def +++ b/backends/tc/tc.def @@ -171,9 +171,9 @@ class TCAction { optional safe_vector actionParams; cstring getName() const { if (actionName == "NoAction") { - return "NoAction"; + return actionName; } - cstring tcAction = pipelineName; + std::string tcAction = pipelineName.string(); tcAction += "/" + actionName; return tcAction; } @@ -306,16 +306,16 @@ class TCTable { return tableName; } cstring printMatchType(unsigned matchType) const { - cstring matchTypeString = ""; + cstring matchTypeString = cstring::empty; switch(matchType) { case TC::EXACT_TYPE : - matchTypeString = "exact"; + matchTypeString = "exact"_cs; break; case TC::LPM_TYPE : - matchTypeString = "lpm"; + matchTypeString = "lpm"_cs; break; case TC::TERNARY_TYPE : - matchTypeString = "ternary"; + matchTypeString = "ternary"_cs; break; } return matchTypeString; diff --git a/backends/tc/tcAnnotations.cpp b/backends/tc/tcAnnotations.cpp index 9aeb91e760..4cc6b4fb00 100644 --- a/backends/tc/tcAnnotations.cpp +++ b/backends/tc/tcAnnotations.cpp @@ -18,20 +18,22 @@ and limitations under the License. namespace TC { -const cstring ParseTCAnnotations::defaultHit = "default_hit"; -const cstring ParseTCAnnotations::defaultHitConst = "default_hit_const"; -const cstring ParseTCAnnotations::tcType = "tc_type"; -const cstring ParseTCAnnotations::numMask = "nummask"; -const cstring ParseTCAnnotations::tcMayOverride = "tc_may_override"; -const cstring ParseTCAnnotations::tc_md_write = "tc_md_write"; -const cstring ParseTCAnnotations::tc_md_read = "tc_md_read"; -const cstring ParseTCAnnotations::tc_md_exec = "tc_md_exec"; -const cstring ParseTCAnnotations::tc_ControlPath = "tc_ControlPath"; -const cstring ParseTCAnnotations::tc_key = "tc_key"; -const cstring ParseTCAnnotations::tc_data = "tc_data"; -const cstring ParseTCAnnotations::tc_data_scalar = "tc_data_scalar"; -const cstring ParseTCAnnotations::tc_init_val = "tc_init_val"; -const cstring ParseTCAnnotations::tc_numel = "tc_numel"; -const cstring ParseTCAnnotations::tc_acl = "tc_acl"; +using namespace P4::literals; + +const cstring ParseTCAnnotations::defaultHit = "default_hit"_cs; +const cstring ParseTCAnnotations::defaultHitConst = "default_hit_const"_cs; +const cstring ParseTCAnnotations::tcType = "tc_type"_cs; +const cstring ParseTCAnnotations::numMask = "nummask"_cs; +const cstring ParseTCAnnotations::tcMayOverride = "tc_may_override"_cs; +const cstring ParseTCAnnotations::tc_md_write = "tc_md_write"_cs; +const cstring ParseTCAnnotations::tc_md_read = "tc_md_read"_cs; +const cstring ParseTCAnnotations::tc_md_exec = "tc_md_exec"_cs; +const cstring ParseTCAnnotations::tc_ControlPath = "tc_ControlPath"_cs; +const cstring ParseTCAnnotations::tc_key = "tc_key"_cs; +const cstring ParseTCAnnotations::tc_data = "tc_data"_cs; +const cstring ParseTCAnnotations::tc_data_scalar = "tc_data_scalar"_cs; +const cstring ParseTCAnnotations::tc_init_val = "tc_init_val"_cs; +const cstring ParseTCAnnotations::tc_numel = "tc_numel"_cs; +const cstring ParseTCAnnotations::tc_acl = "tc_acl"_cs; } // namespace TC diff --git a/backends/ubpf/midend.cpp b/backends/ubpf/midend.cpp index b0e6760b20..be84d08f31 100644 --- a/backends/ubpf/midend.cpp +++ b/backends/ubpf/midend.cpp @@ -101,7 +101,7 @@ const IR::ToplevelBlock *MidEnd::run(EbpfOptions &options, const IR::P4Program * new P4::RemoveLeftSlices(&refMap, &typeMap), new EBPF::Lower(&refMap, &typeMap), evaluator, new P4::MidEndLast()}); if (options.listMidendPasses) { - midEnd.listPasses(*outStream, "\n"); + midEnd.listPasses(*outStream, cstring::newline); *outStream << std::endl; return nullptr; } diff --git a/backends/ubpf/p4c-ubpf.cpp b/backends/ubpf/p4c-ubpf.cpp index d8e5ca1332..b92cfea7d6 100644 --- a/backends/ubpf/p4c-ubpf.cpp +++ b/backends/ubpf/p4c-ubpf.cpp @@ -70,7 +70,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoEbpfContext(new EbpfContext); auto &options = EbpfContext::get().options(); - options.compilerVersion = P4C_UBPF_VERSION_STRING; + options.compilerVersion = cstring(P4C_UBPF_VERSION_STRING); if (options.process(argc, argv) != nullptr) { options.setInputFile(); diff --git a/backends/ubpf/target.cpp b/backends/ubpf/target.cpp index edbe5d5d06..0158efde30 100644 --- a/backends/ubpf/target.cpp +++ b/backends/ubpf/target.cpp @@ -59,11 +59,11 @@ void UbpfTarget::emitTableDecl(Util::SourceCodeBuilder *builder, cstring tblName cstring type; if (tableKind == EBPF::TableHash) { - type = "UBPF_MAP_TYPE_HASHMAP"; + type = "UBPF_MAP_TYPE_HASHMAP"_cs; } else if (tableKind == EBPF::TableArray) { - type = "UBPF_MAP_TYPE_ARRAY"; + type = "UBPF_MAP_TYPE_ARRAY"_cs; } else if (tableKind == EBPF::TableLPMTrie) { - type = "UBPF_MAP_TYPE_LPM_TRIE"; + type = "UBPF_MAP_TYPE_LPM_TRIE"_cs; } else { BUG("%1%: unsupported table kind", tableKind); } diff --git a/backends/ubpf/target.h b/backends/ubpf/target.h index 723f3f2b3f..596a23eac4 100644 --- a/backends/ubpf/target.h +++ b/backends/ubpf/target.h @@ -23,11 +23,13 @@ limitations under the License. namespace UBPF { +using namespace P4::literals; + class UBPFControlBodyTranslator; class UbpfTarget : public EBPF::Target { public: - UbpfTarget() : EBPF::Target("UBPF") {} + UbpfTarget() : EBPF::Target("UBPF"_cs) {} void emitLicense(Util::SourceCodeBuilder *, cstring) const override {}; void emitCodeSection(Util::SourceCodeBuilder *, cstring) const override {}; @@ -52,14 +54,14 @@ class UbpfTarget : public EBPF::Target { void emitUbpfHelpers(EBPF::CodeBuilder *builder) const; void emitChecksumHelpers(EBPF::CodeBuilder *builder) const; - cstring dataOffset(UNUSED cstring base) const override { return cstring(""); } - cstring dataEnd(UNUSED cstring base) const override { return cstring(""); } - cstring dataLength(UNUSED cstring base) const override { return cstring(""); } - cstring dropReturnCode() const override { return "0"; } - cstring abortReturnCode() const override { return "1"; } - cstring forwardReturnCode() const override { return "1"; } - cstring sysMapPath() const override { return ""; } - cstring packetDescriptorType() const override { return "void"; } + cstring dataOffset(UNUSED cstring base) const override { return ""_cs; } + cstring dataEnd(UNUSED cstring base) const override { return ""_cs; } + cstring dataLength(UNUSED cstring base) const override { return ""_cs; } + cstring dropReturnCode() const override { return "0"_cs; } + cstring abortReturnCode() const override { return "1"_cs; } + cstring forwardReturnCode() const override { return "1"_cs; } + cstring sysMapPath() const override { return ""_cs; } + cstring packetDescriptorType() const override { return "void"_cs; } }; } // namespace UBPF diff --git a/backends/ubpf/ubpfControl.cpp b/backends/ubpf/ubpfControl.cpp index 58784502ad..8698b39a8d 100644 --- a/backends/ubpf/ubpfControl.cpp +++ b/backends/ubpf/ubpfControl.cpp @@ -112,7 +112,7 @@ cstring UBPFControlBodyTranslator::createHashKeyInstance(const P4::ExternFunctio auto ubpfList = atype->to(); ubpfList->name = this->refMap->newName("tuple"); - atype->declare(builder, "", false); + atype->declare(builder, ""_cs, false); builder->blockStart(); atype->emit(builder); builder->blockEnd(false); @@ -182,7 +182,7 @@ void UBPFControlBodyTranslator::processApply(const P4::ApplyMethod *method) { builder->blockStart(); BUG_CHECK(method->expr->arguments->empty(), "%1%: table apply with arguments", method); - cstring keyname = "key"; + cstring keyname = "key"_cs; if (table->keyGenerator != nullptr) { builder->emitIndent(); builder->appendLine("/* construct key */"); @@ -194,7 +194,7 @@ void UBPFControlBodyTranslator::processApply(const P4::ApplyMethod *method) { builder->emitIndent(); builder->appendLine("/* value */"); builder->emitIndent(); - cstring valueName = "value"; + cstring valueName = "value"_cs; builder->appendFormat("struct %s *%s = NULL", table->valueTypeName.c_str(), valueName.c_str()); builder->endOfStatement(true); @@ -532,7 +532,7 @@ bool UBPFControlBodyTranslator::comparison(const IR::Operation_Relation *b) { } bool UBPFControlBodyTranslator::preorder(const IR::Member *expression) { - cstring name = ""; + cstring name = ""_cs; if (expression->expr->is()) { name = expression->expr->to()->path->name.name; } diff --git a/backends/ubpf/ubpfDeparser.cpp b/backends/ubpf/ubpfDeparser.cpp index cce0e1b405..057d028d10 100644 --- a/backends/ubpf/ubpfDeparser.cpp +++ b/backends/ubpf/ubpfDeparser.cpp @@ -120,17 +120,17 @@ void UBPFDeparserTranslationVisitor::compileEmitField(const IR::Expression *expr unsigned widthToEmit = et->widthInBits(); unsigned loadSize = 0; - cstring swap = ""; + cstring swap = ""_cs; if (widthToEmit <= 8) { loadSize = 8; } else if (widthToEmit <= 16) { - swap = "bpf_htons"; + swap = "bpf_htons"_cs; loadSize = 16; } else if (widthToEmit <= 32) { - swap = "htonl"; + swap = "htonl"_cs; loadSize = 32; } else if (widthToEmit <= 64) { - swap = "htonll"; + swap = "htonll"_cs; loadSize = 64; } unsigned bytes = ROUNDUP(widthToEmit, 8); diff --git a/backends/ubpf/ubpfModel.cpp b/backends/ubpf/ubpfModel.cpp index c2aeeb8c52..3986cd89fe 100644 --- a/backends/ubpf/ubpfModel.cpp +++ b/backends/ubpf/ubpfModel.cpp @@ -18,7 +18,7 @@ limitations under the License. namespace UBPF { -cstring UBPFModel::reservedPrefix = "ubpf_"; +cstring UBPFModel::reservedPrefix = "ubpf_"_cs; UBPFModel UBPFModel::instance; } // namespace UBPF diff --git a/backends/ubpf/ubpfModel.h b/backends/ubpf/ubpfModel.h index 7346fe9c68..dc65931ee8 100644 --- a/backends/ubpf/ubpfModel.h +++ b/backends/ubpf/ubpfModel.h @@ -25,8 +25,11 @@ limitations under the License. namespace UBPF { +using namespace P4::literals; + struct Pipeline_Model : public ::Model::Elem { - Pipeline_Model() : Elem("Pipeline"), parser("prs"), control("p"), deparser("dprs") {} + Pipeline_Model() + : Elem("Pipeline"_cs), parser("prs"_cs), control("p"_cs), deparser("dprs"_cs) {} ::Model::Elem parser; ::Model::Elem control; @@ -35,13 +38,13 @@ struct Pipeline_Model : public ::Model::Elem { struct Register_Model : public ::Model::Extern_Model { Register_Model() - : Extern_Model("Register"), - sizeParam("size"), - read("read"), - write("write"), - initial_value("initial_value"), - index("index"), - value("value") {} + : Extern_Model("Register"_cs), + sizeParam("size"_cs), + read("read"_cs), + write("write"_cs), + initial_value("initial_value"_cs), + index("index"_cs), + value("value"_cs) {} ::Model::Elem sizeParam; ::Model::Elem read; @@ -52,28 +55,28 @@ struct Register_Model : public ::Model::Extern_Model { }; struct Algorithm_Model : public ::Model::Enum_Model { - Algorithm_Model() : ::Model::Enum_Model("HashAlgorithm"), lookup3("lookup3") {} + Algorithm_Model() : ::Model::Enum_Model("HashAlgorithm"_cs), lookup3("lookup3"_cs) {} ::Model::Elem lookup3; }; struct Hash_Model : public ::Model::Elem { - Hash_Model() : ::Model::Elem("hash") {} + Hash_Model() : ::Model::Elem("hash"_cs) {} }; class UBPFModel : public ::Model::Model { protected: UBPFModel() - : CPacketName("pkt"), - packet("packet", P4::P4CoreLibrary::instance().packetIn, 0), + : CPacketName("pkt"_cs), + packet("packet"_cs, P4::P4CoreLibrary::instance().packetIn, 0), pipeline(), registerModel(), - drop("mark_to_drop"), - pass("mark_to_pass"), - ubpf_time_get_ns("ubpf_time_get_ns"), - truncate("truncate"), - csum_replace2("csum_replace2"), - csum_replace4("csum_replace4"), + drop("mark_to_drop"_cs), + pass("mark_to_pass"_cs), + ubpf_time_get_ns("ubpf_time_get_ns"_cs), + truncate("truncate"_cs), + csum_replace2("csum_replace2"_cs), + csum_replace4("csum_replace4"_cs), hashAlgorithm(), hash() {} diff --git a/backends/ubpf/ubpfParser.cpp b/backends/ubpf/ubpfParser.cpp index b9cd1137f8..1a4654af52 100644 --- a/backends/ubpf/ubpfParser.cpp +++ b/backends/ubpf/ubpfParser.cpp @@ -334,7 +334,7 @@ void UBPFStateTranslationVisitor::compileLookahead(const IR::Expression *destina builder->append(" "); visit(destination); builder->append(" = "); - compileExtractField(nullptr, "", 0, etype, false); + compileExtractField(nullptr, ""_cs, 0, etype, false); builder->endOfStatement(true); } diff --git a/backends/ubpf/ubpfProgram.cpp b/backends/ubpf/ubpfProgram.cpp index efc732ae12..590cdf8a6e 100644 --- a/backends/ubpf/ubpfProgram.cpp +++ b/backends/ubpf/ubpfProgram.cpp @@ -77,7 +77,7 @@ void UBPFProgram::emitC(UbpfCodeBuilder *builder, cstring headerFile) { builder->target->emitChecksumHelpers(builder); builder->emitIndent(); - builder->target->emitMain(builder, "entry", contextVar.c_str(), stdMetadataVar.c_str()); + builder->target->emitMain(builder, "entry"_cs, contextVar, stdMetadataVar); builder->blockStart(); emitPktVariable(builder); @@ -247,7 +247,7 @@ void UBPFProgram::emitPktVariable(UbpfCodeBuilder *builder) const { void UBPFProgram::emitPacketLengthVariable(UbpfCodeBuilder *builder) const { builder->emitIndent(); builder->appendFormat("uint32_t %s = ", lengthVar.c_str()); - builder->target->emitGetFromStandardMetadata(builder, stdMetadataVar, "packet_length"); + builder->target->emitGetFromStandardMetadata(builder, stdMetadataVar, "packet_length"_cs); builder->endOfStatement(true); } diff --git a/backends/ubpf/ubpfProgram.h b/backends/ubpf/ubpfProgram.h index 71e2b1eb78..82493e009b 100644 --- a/backends/ubpf/ubpfProgram.h +++ b/backends/ubpf/ubpfProgram.h @@ -44,7 +44,7 @@ class UBPFProgram : public EBPF::EBPFProgram { cstring contextVar, outerHdrOffsetVar, outerHdrLengthVar; cstring stdMetadataVar; cstring packetTruncatedSizeVar; - cstring arrayIndexType = "uint32_t"; + cstring arrayIndexType = "uint32_t"_cs; UBPFProgram(const EbpfOptions &options, const IR::P4Program *program, P4::ReferenceMap *refMap, P4::TypeMap *typeMap, const IR::ToplevelBlock *toplevel) @@ -76,8 +76,8 @@ class UBPFProgram : public EBPF::EBPFProgram { bool isLibraryMethod(cstring methodName) override { static std::set DEFAULT_METHODS = { - "mark_to_drop", "mark_to_pass", "ubpf_time_get_ns", "truncate", - "hash", "csum_replace2", "csum_replace4", + "mark_to_drop"_cs, "mark_to_pass"_cs, "ubpf_time_get_ns"_cs, "truncate"_cs, + "hash"_cs, "csum_replace2"_cs, "csum_replace4"_cs, }; return DEFAULT_METHODS.find(methodName) != DEFAULT_METHODS.end() || EBPFProgram::isLibraryMethod(methodName); diff --git a/backends/ubpf/ubpfRegister.cpp b/backends/ubpf/ubpfRegister.cpp index db241817e7..92db34f8a6 100644 --- a/backends/ubpf/ubpfRegister.cpp +++ b/backends/ubpf/ubpfRegister.cpp @@ -112,14 +112,14 @@ void UBPFRegister::emitRegisterRead(EBPF::CodeBuilder *builder, BUG_CHECK(expression->arguments->size() == 1, "Expected 1 argument for %1%", expression); auto target = builder->target; - target->emitTableLookup(builder, dataMapName, last_key_name, ""); + target->emitTableLookup(builder, dataMapName, last_key_name, ""_cs); } void UBPFRegister::emitKeyInstance(EBPF::CodeBuilder *builder, const IR::MethodCallExpression *expression) { auto arg_key = expression->arguments->at(0); - cstring keyName = ""; + cstring keyName = ""_cs; if (arg_key->expression->is()) { keyName = arg_key->expression->to()->path->name.name; diff --git a/backends/ubpf/ubpfTable.cpp b/backends/ubpf/ubpfTable.cpp index b262479b84..10c7454b66 100644 --- a/backends/ubpf/ubpfTable.cpp +++ b/backends/ubpf/ubpfTable.cpp @@ -44,7 +44,7 @@ class UbpfActionTranslationVisitor : public EBPF::CodeGenInspector { } bool preorder(const IR::Member *expression) override { - cstring name = ""; + cstring name = ""_cs; if (expression->expr->is()) { name = expression->expr->to()->path->name.name; } @@ -166,13 +166,13 @@ UBPFTable::UBPFTable(const UBPFProgram *program, const IR::TableBlock *table, EBPF::CodeGenInspector *codeGen) : UBPFTableBase(program, EBPFObject::externalName(table->container), codeGen), table(table) { cstring base = instanceName + "_defaultAction"; - defaultActionMapName = program->refMap->newName(base); + defaultActionMapName = program->refMap->newName(base.string_view()); base = table->container->name.name + "_actions"; - actionEnumName = program->refMap->newName(base); + actionEnumName = program->refMap->newName(base.string_view()); base = instanceName + "_NoAction"; - noActionName = program->refMap->newName(base); + noActionName = program->refMap->newName(base.string_view()); keyGenerator = table->container->getKey(); actionList = table->container->getActionList(); @@ -187,7 +187,7 @@ UBPFTable::UBPFTable(const UBPFProgram *program, const IR::TableBlock *table, void UBPFTable::emitInstance(EBPF::CodeBuilder *builder) { UBPFTableBase::emitInstance(builder, tableKind); builder->target->emitTableDecl(builder, defaultActionMapName, EBPF::TableArray, - program->arrayIndexType, cstring("struct ") + valueTypeName, 1); + program->arrayIndexType, "struct "_cs + valueTypeName, 1); } void UBPFTable::setTableKind() { diff --git a/backends/ubpf/ubpfType.cpp b/backends/ubpf/ubpfType.cpp index b5641d8ba3..cae6034877 100644 --- a/backends/ubpf/ubpfType.cpp +++ b/backends/ubpf/ubpfType.cpp @@ -20,6 +20,8 @@ limitations under the License. namespace UBPF { +using namespace P4::literals; + EBPF::EBPFTypeFactory *instance = UBPFTypeFactory::getInstance(); EBPF::EBPFType *UBPFTypeFactory::create(const IR::Type *type) { @@ -69,16 +71,12 @@ void UBPFScalarType::emit(EBPF::CodeBuilder *builder) { } cstring UBPFScalarType::getAsString() { - if (width <= 8) - return cstring("uint8_t"); - else if (width <= 16) - return cstring("uint16_t"); - else if (width <= 32) - return cstring("uint32_t"); - else if (width <= 64) - return cstring("uint64_t"); - else - return cstring("uint8_t*"); + if (width <= 8) return "uint8_t"_cs; + if (width <= 16) return "uint16_t"_cs; + if (width <= 32) return "uint32_t"_cs; + if (width <= 64) return "uint64_t"_cs; + + return "uint8_t*"_cs; } void UBPFScalarType::declare(EBPF::CodeBuilder *builder, cstring id, bool asPointer) { @@ -138,7 +136,7 @@ void UBPFStructType::emit(EBPF::CodeBuilder *builder) { builder->emitIndent(); auto type = UBPFTypeFactory::instance->create(IR::Type_Boolean::get()); if (type != nullptr) { - type->declare(builder, "ebpf_valid", false); + type->declare(builder, "ebpf_valid"_cs, false); builder->endOfStatement(true); } } @@ -191,7 +189,7 @@ void UBPFErrorType::emit(EBPF::CodeBuilder *builder) { ////////////////////////////////////////////////////////// UBPFListType::UBPFListType(const IR::Type_List *lst) : EBPFType(lst) { - kind = "struct"; + kind = "struct"_cs; width = 0; implWidth = 0; // The first iteration is to compute total width of Type_List. diff --git a/bazel/example/main.cc b/bazel/example/main.cc index 33ebffe57c..e8f8fa66ae 100644 --- a/bazel/example/main.cc +++ b/bazel/example/main.cc @@ -9,6 +9,8 @@ using ::google::protobuf::TextFormat; using ::p4::config::v1::P4Info; +using namespace P4::literals; + const char kP4InfoFile[] = "program.p4info.txt"; int main() { @@ -24,6 +26,6 @@ int main() { std::cout << p4info.DebugString(); // Demonstrate that IR extension is present. - IR::MyCustomStatement statement("Hello, P4 extension world!"); + IR::MyCustomStatement statement("Hello, P4 extension world!"_cs); std::cout << statement << std::endl; } diff --git a/control-plane/bfruntime.cpp b/control-plane/bfruntime.cpp index 1dd99b0d9d..ac3de53b12 100644 --- a/control-plane/bfruntime.cpp +++ b/control-plane/bfruntime.cpp @@ -249,14 +249,14 @@ Util::JsonObject *BFRuntimeGenerator::makeCommonDataField(P4Id id, cstring name, Util::JsonObject *type, bool repeated, Util::JsonArray *annotations) { auto *dataField = new Util::JsonObject(); - dataField->emplace("id", id); - dataField->emplace("name", name); - dataField->emplace("repeated", repeated); + dataField->emplace("id"_cs, id); + dataField->emplace("name"_cs, name); + dataField->emplace("repeated"_cs, repeated); if (annotations != nullptr) - dataField->emplace("annotations", annotations); + dataField->emplace("annotations"_cs, annotations); else - dataField->emplace("annotations", new Util::JsonArray()); - dataField->emplace("type", type); + dataField->emplace("annotations"_cs, new Util::JsonArray()); + dataField->emplace("type"_cs, type); return dataField; } @@ -264,14 +264,14 @@ Util::JsonObject *BFRuntimeGenerator::makeContainerDataField(P4Id id, cstring na Util::JsonArray *items, bool repeated, Util::JsonArray *annotations) { auto *dataField = new Util::JsonObject(); - dataField->emplace("id", id); - dataField->emplace("name", name); - dataField->emplace("repeated", repeated); + dataField->emplace("id"_cs, id); + dataField->emplace("name"_cs, name); + dataField->emplace("repeated"_cs, repeated); if (annotations != nullptr) - dataField->emplace("annotations", annotations); + dataField->emplace("annotations"_cs, annotations); else - dataField->emplace("annotations", new Util::JsonArray()); - dataField->emplace("container", items); + dataField->emplace("annotations"_cs, new Util::JsonArray()); + dataField->emplace("container"_cs, items); return dataField; } @@ -279,16 +279,16 @@ void BFRuntimeGenerator::addActionDataField(Util::JsonArray *dataJson, P4Id id, const std::string &name, bool mandatory, bool read_only, Util::JsonObject *type, Util::JsonArray *annotations) { auto *dataField = new Util::JsonObject(); - dataField->emplace("id", id); - dataField->emplace("name", name); - dataField->emplace("repeated", false); - dataField->emplace("mandatory", mandatory); - dataField->emplace("read_only", read_only); + dataField->emplace("id"_cs, id); + dataField->emplace("name"_cs, name); + dataField->emplace("repeated"_cs, false); + dataField->emplace("mandatory"_cs, mandatory); + dataField->emplace("read_only"_cs, read_only); if (annotations != nullptr) - dataField->emplace("annotations", annotations); + dataField->emplace("annotations"_cs, annotations); else - dataField->emplace("annotations", new Util::JsonArray()); - dataField->emplace("type", type); + dataField->emplace("annotations"_cs, new Util::JsonArray()); + dataField->emplace("type"_cs, type); dataJson->append(dataField); } @@ -296,16 +296,16 @@ void BFRuntimeGenerator::addKeyField(Util::JsonArray *dataJson, P4Id id, cstring bool mandatory, cstring matchType, Util::JsonObject *type, Util::JsonArray *annotations) { auto *dataField = new Util::JsonObject(); - dataField->emplace("id", id); - dataField->emplace("name", name); - dataField->emplace("repeated", false); + dataField->emplace("id"_cs, id); + dataField->emplace("name"_cs, name); + dataField->emplace("repeated"_cs, false); if (annotations != nullptr) - dataField->emplace("annotations", annotations); + dataField->emplace("annotations"_cs, annotations); else - dataField->emplace("annotations", new Util::JsonArray()); - dataField->emplace("mandatory", mandatory); - dataField->emplace("match_type", matchType); - dataField->emplace("type", type); + dataField->emplace("annotations"_cs, new Util::JsonArray()); + dataField->emplace("mandatory"_cs, mandatory); + dataField->emplace("match_type"_cs, matchType); + dataField->emplace("type"_cs, type); dataJson->append(dataField); } @@ -313,17 +313,17 @@ void BFRuntimeGenerator::addKeyField(Util::JsonArray *dataJson, P4Id id, cstring cstring tableType, int64_t size, Util::JsonArray *annotations) { auto *tableJson = new Util::JsonObject(); - tableJson->emplace("name", name); - tableJson->emplace("id", id); - tableJson->emplace("table_type", tableType); - tableJson->emplace("size", size); - if (annotations != nullptr) tableJson->emplace("annotations", annotations); - tableJson->emplace("depends_on", new Util::JsonArray()); + tableJson->emplace("name"_cs, name); + tableJson->emplace("id"_cs, id); + tableJson->emplace("table_type"_cs, tableType); + tableJson->emplace("size"_cs, size); + if (annotations != nullptr) tableJson->emplace("annotations"_cs, annotations); + tableJson->emplace("depends_on"_cs, new Util::JsonArray()); return tableJson; } /* static */ void BFRuntimeGenerator::addToDependsOn(Util::JsonObject *tableJson, P4Id id) { - auto *dependsOnJson = tableJson->get("depends_on")->to(); + auto *dependsOnJson = tableJson->get("depends_on"_cs)->to(); CHECK_NULL(dependsOnJson); // Skip duplicates for (auto *d : *dependsOnJson) { @@ -335,22 +335,22 @@ void BFRuntimeGenerator::addKeyField(Util::JsonArray *dataJson, P4Id id, cstring void BFRuntimeGenerator::addCounterCommon(Util::JsonArray *tablesJson, const Counter &counter) const { auto *tableJson = - initTableJson(counter.name, counter.id, "Counter", counter.size, counter.annotations); + initTableJson(counter.name, counter.id, "Counter"_cs, counter.size, counter.annotations); auto *keyJson = new Util::JsonArray(); - addKeyField(keyJson, TD_DATA_COUNTER_INDEX, "$COUNTER_INDEX", true /* mandatory */, "Exact", - makeType("uint32")); - tableJson->emplace("key", keyJson); + addKeyField(keyJson, TD_DATA_COUNTER_INDEX, "$COUNTER_INDEX"_cs, true /* mandatory */, + "Exact"_cs, makeType("uint32"_cs)); + tableJson->emplace("key"_cs, keyJson); auto *dataJson = new Util::JsonArray(); addCounterDataFields(dataJson, counter); - tableJson->emplace("data", dataJson); + tableJson->emplace("data"_cs, dataJson); auto *operationsJson = new Util::JsonArray(); - operationsJson->append("Sync"); - tableJson->emplace("supported_operations", operationsJson); + operationsJson->append("Sync"_cs); + tableJson->emplace("supported_operations"_cs, operationsJson); - tableJson->emplace("attributes", new Util::JsonArray()); + tableJson->emplace("attributes"_cs, new Util::JsonArray()); tablesJson->append(tableJson); } @@ -360,36 +360,36 @@ void BFRuntimeGenerator::addCounterDataFields(Util::JsonArray *dataJson, static const uint64_t defaultCounterValue = 0u; if (counter.unit == Counter::Unit::BYTES || counter.unit == Counter::Unit::BOTH) { auto *f = - makeCommonDataField(TD_DATA_COUNTER_SPEC_BYTES, "$COUNTER_SPEC_BYTES", - makeType("uint64", defaultCounterValue), false /* repeated */); + makeCommonDataField(TD_DATA_COUNTER_SPEC_BYTES, "$COUNTER_SPEC_BYTES"_cs, + makeType("uint64"_cs, defaultCounterValue), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } if (counter.unit == Counter::Unit::PACKETS || counter.unit == Counter::Unit::BOTH) { auto *f = - makeCommonDataField(TD_DATA_COUNTER_SPEC_PKTS, "$COUNTER_SPEC_PKTS", - makeType("uint64", defaultCounterValue), false /* repeated */); + makeCommonDataField(TD_DATA_COUNTER_SPEC_PKTS, "$COUNTER_SPEC_PKTS"_cs, + makeType("uint64"_cs, defaultCounterValue), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } } void BFRuntimeGenerator::addMeterCommon(Util::JsonArray *tablesJson, const BFRuntimeGenerator::Meter &meter) const { - auto *tableJson = initTableJson(meter.name, meter.id, "Meter", meter.size); + auto *tableJson = initTableJson(meter.name, meter.id, "Meter"_cs, meter.size); auto *keyJson = new Util::JsonArray(); - addKeyField(keyJson, TD_DATA_METER_INDEX, "$METER_INDEX", true /* mandatory */, "Exact", - makeType("uint32")); - tableJson->emplace("key", keyJson); + addKeyField(keyJson, TD_DATA_METER_INDEX, "$METER_INDEX"_cs, true /* mandatory */, "Exact"_cs, + makeType("uint32"_cs)); + tableJson->emplace("key"_cs, keyJson); auto *dataJson = new Util::JsonArray(); addMeterDataFields(dataJson, meter); - tableJson->emplace("data", dataJson); + tableJson->emplace("data"_cs, dataJson); - tableJson->emplace("supported_operations", new Util::JsonArray()); + tableJson->emplace("supported_operations"_cs, new Util::JsonArray()); auto *attributesJson = new Util::JsonArray(); attributesJson->append("MeterByteCountAdjust"); - tableJson->emplace("attributes", attributesJson); + tableJson->emplace("attributes"_cs, attributesJson); tablesJson->append(tableJson); } @@ -411,36 +411,36 @@ void BFRuntimeGenerator::transformTypeSpecToDataFields(Util::JsonArray *fieldsJs void BFRuntimeGenerator::addRegisterDataFields(Util::JsonArray *dataJson, const BFRuntimeGenerator::Register ®ister_, P4Id idOffset) const { - auto parser = TypeSpecParser::make(p4info, register_.typeSpec, "Register", register_.name, - nullptr, "", "", idOffset); + auto parser = TypeSpecParser::make(p4info, register_.typeSpec, "Register"_cs, register_.name, + nullptr, cstring::empty, cstring::empty, idOffset); BUG_CHECK(parser.size() == 1, "Expected only one data field for Register extern %1%", register_.name); for (const auto &f : parser) { auto *fJson = - makeCommonDataField(idOffset, "$REGISTER_INDEX", f.type, false /* repeated */); + makeCommonDataField(idOffset, "$REGISTER_INDEX"_cs, f.type, false /* repeated */); addSingleton(dataJson, fJson, false /* mandatory */, false /* read-only */); } } void BFRuntimeGenerator::addRegisterCommon(Util::JsonArray *tablesJson, const BFRuntimeGenerator::Register ®ister_) const { - auto *tableJson = initTableJson(register_.name, register_.id, "Register", register_.size, + auto *tableJson = initTableJson(register_.name, register_.id, "Register"_cs, register_.size, register_.annotations); auto *keyJson = new Util::JsonArray(); - addKeyField(keyJson, TD_DATA_REGISTER_INDEX, "$REGISTER_INDEX", true /* mandatory */, "Exact", - makeType("uint32")); - tableJson->emplace("key", keyJson); + addKeyField(keyJson, TD_DATA_REGISTER_INDEX, "$REGISTER_INDEX"_cs, true /* mandatory */, + "Exact"_cs, makeType("uint32"_cs)); + tableJson->emplace("key"_cs, keyJson); auto *dataJson = new Util::JsonArray(); addRegisterDataFields(dataJson, register_, TD_DATA_REGISTER_INDEX); - tableJson->emplace("data", dataJson); + tableJson->emplace("data"_cs, dataJson); auto *operationsJson = new Util::JsonArray(); operationsJson->append("Sync"); - tableJson->emplace("supported_operations", operationsJson); + tableJson->emplace("supported_operations"_cs, operationsJson); - tableJson->emplace("attributes", new Util::JsonArray()); + tableJson->emplace("attributes"_cs, new Util::JsonArray()); tablesJson->append(tableJson); } @@ -451,44 +451,44 @@ void BFRuntimeGenerator::addMeterDataFields(Util::JsonArray *dataJson, static const uint64_t maxUint64 = std::numeric_limits::max(); if (meter.unit == Meter::Unit::BYTES) { { - auto *f = makeCommonDataField(TD_DATA_METER_SPEC_CIR_KBPS, "$METER_SPEC_CIR_KBPS", - makeType("uint64", maxUint64), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_METER_SPEC_CIR_KBPS, "$METER_SPEC_CIR_KBPS"_cs, + makeType("uint64"_cs, maxUint64), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } { - auto *f = makeCommonDataField(TD_DATA_METER_SPEC_PIR_KBPS, "$METER_SPEC_PIR_KBPS", - makeType("uint64", maxUint64), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_METER_SPEC_PIR_KBPS, "$METER_SPEC_PIR_KBPS"_cs, + makeType("uint64"_cs, maxUint64), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } { - auto *f = makeCommonDataField(TD_DATA_METER_SPEC_CBS_KBITS, "$METER_SPEC_CBS_KBITS", - makeType("uint64", maxUint64), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_METER_SPEC_CBS_KBITS, "$METER_SPEC_CBS_KBITS"_cs, + makeType("uint64"_cs, maxUint64), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } { - auto *f = makeCommonDataField(TD_DATA_METER_SPEC_PBS_KBITS, "$METER_SPEC_PBS_KBITS", - makeType("uint64", maxUint64), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_METER_SPEC_PBS_KBITS, "$METER_SPEC_PBS_KBITS"_cs, + makeType("uint64"_cs, maxUint64), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } } else if (meter.unit == Meter::Unit::PACKETS) { { - auto *f = makeCommonDataField(TD_DATA_METER_SPEC_CIR_PPS, "$METER_SPEC_CIR_PPS", - makeType("uint64", maxUint64), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_METER_SPEC_CIR_PPS, "$METER_SPEC_CIR_PPS"_cs, + makeType("uint64"_cs, maxUint64), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } { - auto *f = makeCommonDataField(TD_DATA_METER_SPEC_PIR_PPS, "$METER_SPEC_PIR_PPS", - makeType("uint64", maxUint64), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_METER_SPEC_PIR_PPS, "$METER_SPEC_PIR_PPS"_cs, + makeType("uint64"_cs, maxUint64), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } { - auto *f = makeCommonDataField(TD_DATA_METER_SPEC_CBS_PKTS, "$METER_SPEC_CBS_PKTS", - makeType("uint64", maxUint64), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_METER_SPEC_CBS_PKTS, "$METER_SPEC_CBS_PKTS"_cs, + makeType("uint64"_cs, maxUint64), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } { - auto *f = makeCommonDataField(TD_DATA_METER_SPEC_PBS_PKTS, "$METER_SPEC_PBS_PKTS", - makeType("uint64", maxUint64), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_METER_SPEC_PBS_PKTS, "$METER_SPEC_PBS_PKTS"_cs, + makeType("uint64"_cs, maxUint64), false /* repeated */); addSingleton(dataJson, f, false /* mandatory */, false /* read-only */); } } else { @@ -498,13 +498,13 @@ void BFRuntimeGenerator::addMeterDataFields(Util::JsonArray *dataJson, void BFRuntimeGenerator::addActionProfCommon( Util::JsonArray *tablesJson, const BFRuntimeGenerator::ActionProf &actionProf) const { - auto *tableJson = initTableJson(actionProf.name, actionProf.id, "Action", actionProf.size, + auto *tableJson = initTableJson(actionProf.name, actionProf.id, "Action"_cs, actionProf.size, actionProf.annotations); auto *keyJson = new Util::JsonArray(); - addKeyField(keyJson, TD_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID", true /* mandatory */, - "Exact", makeType("uint32")); - tableJson->emplace("key", keyJson); + addKeyField(keyJson, TD_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID"_cs, true /* mandatory */, + "Exact"_cs, makeType("uint32"_cs)); + tableJson->emplace("key"_cs, keyJson); if (actionProf.tableIds.empty()) { ::warning("Action profile '%1%' is not used by any table, skipping it", actionProf.name); @@ -518,12 +518,12 @@ void BFRuntimeGenerator::addActionProfCommon( auto oneTableJson = findJsonTable(tablesJson, oneTable->preamble().name()); addToDependsOn(oneTableJson, actionProf.id); - tableJson->emplace("action_specs", makeActionSpecs(*oneTable)); + tableJson->emplace("action_specs"_cs, makeActionSpecs(*oneTable)); - tableJson->emplace("data", new Util::JsonArray()); + tableJson->emplace("data"_cs, new Util::JsonArray()); - tableJson->emplace("supported_operations", new Util::JsonArray()); - tableJson->emplace("attributes", new Util::JsonArray()); + tableJson->emplace("supported_operations"_cs, new Util::JsonArray()); + tableJson->emplace("attributes"_cs, new Util::JsonArray()); tablesJson->append(tableJson); } @@ -549,17 +549,17 @@ Util::JsonArray *BFRuntimeGenerator::makeActionSpecs(const p4configv1::Table &ta } auto *spec = new Util::JsonObject(); const auto &pre = action->preamble(); - spec->emplace("id", pre.id()); - spec->emplace("name", pre.name()); + spec->emplace("id"_cs, pre.id()); + spec->emplace("name"_cs, pre.name()); switch (action_ref.scope()) { case p4configv1::ActionRef::TABLE_AND_DEFAULT: - spec->emplace("action_scope", "TableAndDefault"); + spec->emplace("action_scope"_cs, "TableAndDefault"); break; case p4configv1::ActionRef::TABLE_ONLY: - spec->emplace("action_scope", "TableOnly"); + spec->emplace("action_scope"_cs, "TableOnly"); break; case p4configv1::ActionRef::DEFAULT_ONLY: - spec->emplace("action_scope", "DefaultOnly"); + spec->emplace("action_scope"_cs, "DefaultOnly"); break; default: ::error(ErrorType::ERR_INVALID, "Invalid action ref scope '%1%' in P4Info", @@ -568,7 +568,7 @@ Util::JsonArray *BFRuntimeGenerator::makeActionSpecs(const p4configv1::Table &ta } auto *annotations = transformAnnotations(action_ref.annotations().begin(), action_ref.annotations().end()); - spec->emplace("annotations", annotations); + spec->emplace("annotations"_cs, annotations); auto *dataJson = new Util::JsonArray(); for (const auto ¶m : action->params()) { @@ -576,8 +576,8 @@ Util::JsonArray *BFRuntimeGenerator::makeActionSpecs(const p4configv1::Table &ta transformAnnotations(param.annotations().begin(), param.annotations().end()); if (param.type_name().name() == "PSA_MeterColor_t") { addActionDataField(dataJson, param.id(), param.name(), true /* mandatory */, - false /* read_only */, makeTypeEnum({"RED", "GREEN", "YELLOW"}), - annotations); + false /* read_only */, + makeTypeEnum({"RED"_cs, "GREEN"_cs, "YELLOW"_cs}), annotations); } else { addActionDataField(dataJson, param.id(), param.name(), true /* mandatory */, false /* read_only */, makeTypeBytes(param.bitwidth()), @@ -585,7 +585,7 @@ Util::JsonArray *BFRuntimeGenerator::makeActionSpecs(const p4configv1::Table &ta } if (param.id() > maxId) maxId = param.id(); } - spec->emplace("data", dataJson); + spec->emplace("data"_cs, dataJson); specs->append(spec); } if (maxActionParamId != nullptr) *maxActionParamId = maxId; @@ -595,13 +595,13 @@ Util::JsonArray *BFRuntimeGenerator::makeActionSpecs(const p4configv1::Table &ta void BFRuntimeGenerator::addLearnFilterCommon(Util::JsonArray *learnFiltersJson, const BFRuntimeGenerator::Digest &digest) const { auto *learnFilterJson = new Util::JsonObject(); - learnFilterJson->emplace("name", digest.name); - learnFilterJson->emplace("id", digest.id); - learnFilterJson->emplace("annotations", digest.annotations); + learnFilterJson->emplace("name"_cs, digest.name); + learnFilterJson->emplace("id"_cs, digest.id); + learnFilterJson->emplace("annotations"_cs, digest.annotations); auto *fieldsJson = new Util::JsonArray(); - transformTypeSpecToDataFields(fieldsJson, digest.typeSpec, "Digest", digest.name); - learnFilterJson->emplace("fields", fieldsJson); + transformTypeSpecToDataFields(fieldsJson, digest.typeSpec, "Digest"_cs, digest.name); + learnFilterJson->emplace("fields"_cs, fieldsJson); learnFiltersJson->append(learnFilterJson); } @@ -663,11 +663,11 @@ void BFRuntimeGenerator::addMatchTables(Util::JsonArray *tablesJson) const { transformAnnotations(pre.annotations().begin(), pre.annotations().end()); auto *tableJson = - initTableJson(pre.name(), pre.id(), "MatchAction_Direct", table.size(), annotations); + initTableJson(pre.name(), pre.id(), "MatchAction_Direct"_cs, table.size(), annotations); if (!addActionProfIds(table, tableJson)) continue; - tableJson->emplace("has_const_default_action", table.const_default_action_id() != 0); + tableJson->emplace("has_const_default_action"_cs, table.const_default_action_id() != 0); // will be set to true by the for loop if the match key includes a // ternary, range or optional match @@ -704,8 +704,8 @@ void BFRuntimeGenerator::addMatchTables(Util::JsonArray *tablesJson) const { std::regex_search(s, sm, sliceRegex); if (sm.size() == 3) { auto *isFieldSliceAnnot = new Util::JsonObject(); - isFieldSliceAnnot->emplace("name", "isFieldSlice"); - isFieldSliceAnnot->emplace("value", "true"); + isFieldSliceAnnot->emplace("name"_cs, "isFieldSlice"); + isFieldSliceAnnot->emplace("value"_cs, "true"); annotations->append(isFieldSliceAnnot); } @@ -741,33 +741,33 @@ void BFRuntimeGenerator::addMatchTables(Util::JsonArray *tablesJson) const { if (needsPriority) { // DRV-3112 - Make key fields not mandatory, this allows user to use a // driver initialized default value (0). - addKeyField(keyJson, TD_DATA_MATCH_PRIORITY, "$MATCH_PRIORITY", false /* mandatory */, - "Exact", makeType("uint32")); + addKeyField(keyJson, TD_DATA_MATCH_PRIORITY, "$MATCH_PRIORITY"_cs, + false /* mandatory */, "Exact"_cs, makeType("uint32"_cs)); } - tableJson->emplace("key", keyJson); + tableJson->emplace("key"_cs, keyJson); auto *dataJson = new Util::JsonArray(); // will be used as an offset for other P4-dependent fields (e.g. direct // register fields). P4Id maxActionParamId = 0; - cstring tableType = tableJson->get("table_type")->to()->getString(); + cstring tableType = tableJson->get("table_type"_cs)->to()->getString(); if (tableType == "MatchAction_Direct") { - tableJson->emplace("action_specs", makeActionSpecs(table, &maxActionParamId)); + tableJson->emplace("action_specs"_cs, makeActionSpecs(table, &maxActionParamId)); } else if (tableType == "MatchAction_Indirect") { - auto *f = makeCommonDataField(TD_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID", - makeType("uint32"), false /* repeated */); + auto *f = makeCommonDataField(TD_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID"_cs, + makeType("uint32"_cs), false /* repeated */); addSingleton(dataJson, f, true /* mandatory */, false /* read-only */); } else if (tableType == "MatchAction_Indirect_Selector") { // action member id and selector group id are mutually-exclusive, so // we use a "oneof" here. auto *choicesDataJson = new Util::JsonArray(); - choicesDataJson->append(makeCommonDataField(TD_DATA_ACTION_MEMBER_ID, - "$ACTION_MEMBER_ID", makeType("uint32"), - false /* repeated */)); - choicesDataJson->append(makeCommonDataField(TD_DATA_SELECTOR_GROUP_ID, - "$SELECTOR_GROUP_ID", makeType("uint32"), - false /* repeated */)); + choicesDataJson->append( + makeCommonDataField(TD_DATA_ACTION_MEMBER_ID, "$ACTION_MEMBER_ID"_cs, + makeType("uint32"_cs), false /* repeated */)); + choicesDataJson->append( + makeCommonDataField(TD_DATA_SELECTOR_GROUP_ID, "$SELECTOR_GROUP_ID"_cs, + makeType("uint32"_cs), false /* repeated */)); addOneOf(dataJson, choicesDataJson, true /* mandatory */, false /* read-only */); } else { BUG("Invalid table type '%1%'", tableType); @@ -796,20 +796,21 @@ void BFRuntimeGenerator::addMatchTables(Util::JsonArray *tablesJson) const { operationsJson->append("UpdateHitState"); attributesJson->append("IdleTimeout"); - auto *fEntryTTL = makeCommonDataField( - TD_DATA_ENTRY_TTL, "$ENTRY_TTL", - makeType("uint32", 0 /* default TTL -> ageing disabled */), false /* repeated */); - auto *fEntryHitState = makeCommonDataField(TD_DATA_ENTRY_HIT_STATE, "$ENTRY_HIT_STATE", - makeTypeEnum({"ENTRY_IDLE", "ENTRY_ACTIVE"}), - false /* repeated */); + auto *fEntryTTL = + makeCommonDataField(TD_DATA_ENTRY_TTL, "$ENTRY_TTL"_cs, + makeType("uint32"_cs, 0 /* default TTL -> ageing disabled */), + false /* repeated */); + auto *fEntryHitState = makeCommonDataField( + TD_DATA_ENTRY_HIT_STATE, "$ENTRY_HIT_STATE"_cs, + makeTypeEnum({"ENTRY_IDLE"_cs, "ENTRY_ACTIVE"_cs}), false /* repeated */); addSingleton(dataJson, fEntryHitState, false /* mandatory */, false /* read-only */); if (!pollModeOnly) addSingleton(dataJson, fEntryTTL, false /* mandatory */, false /* read-only */); } - tableJson->emplace("data", dataJson); - tableJson->emplace("supported_operations", operationsJson); - tableJson->emplace("attributes", attributesJson); + tableJson->emplace("data"_cs, dataJson); + tableJson->emplace("supported_operations"_cs, operationsJson); + tableJson->emplace("attributes"_cs, attributesJson); tablesJson->append(tableJson); } @@ -850,10 +851,10 @@ void BFRuntimeGenerator::addRegisters(Util::JsonArray *tablesJson) const { const Util::JsonObject *BFRuntimeGenerator::genSchema() const { auto *json = new Util::JsonObject(); - json->emplace("schema_version", cstring("1.0.0")); + json->emplace("schema_version"_cs, "1.0.0"_cs); auto *tablesJson = new Util::JsonArray(); - json->emplace("tables", tablesJson); + json->emplace("tables"_cs, tablesJson); addMatchTables(tablesJson); addActionProfs(tablesJson); @@ -862,7 +863,7 @@ const Util::JsonObject *BFRuntimeGenerator::genSchema() const { addRegisters(tablesJson); auto *learnFiltersJson = new Util::JsonArray(); - json->emplace("learn_filters", learnFiltersJson); + json->emplace("learn_filters"_cs, learnFiltersJson); addLearnFilters(learnFiltersJson); return json; diff --git a/control-plane/bfruntime.h b/control-plane/bfruntime.h index c12c6ff4f0..79935e9b24 100644 --- a/control-plane/bfruntime.h +++ b/control-plane/bfruntime.h @@ -55,7 +55,7 @@ static inline constexpr P4Id getIdPrefix(P4Id id) { return ((id >> 24) & 0xff); static inline Util::JsonObject *findJsonTable(Util::JsonArray *tablesJson, cstring tblName) { for (auto *t : *tablesJson) { auto *tblObj = t->to(); - auto tName = tblObj->get("name")->to()->getString(); + auto tName = tblObj->get("name"_cs)->to()->getString(); if (tName == tblName) { return tblObj; } @@ -67,7 +67,7 @@ static inline Util::JsonObject *transformAnnotation(const cstring &annotation) { auto *annotationJson = new Util::JsonObject(); // TODO(antonin): annotation string will need to be parsed so we can have it // in key/value format here. - annotationJson->emplace("name", annotation.escapeJson()); + annotationJson->emplace("name"_cs, annotation.escapeJson()); return annotationJson; } @@ -133,60 +133,60 @@ static inline const p4configv1::DirectMeter *findDirectMeter(const p4configv1::P static inline Util::JsonObject *makeType(cstring type) { auto *typeObj = new Util::JsonObject(); - typeObj->emplace("type", type); + typeObj->emplace("type"_cs, type); return typeObj; } template ::value, int>::type = 0> static inline Util::JsonObject *makeType(cstring type, T defaultValue) { auto *typeObj = new Util::JsonObject(); - typeObj->emplace("type", type); - typeObj->emplace("default_value", defaultValue); + typeObj->emplace("type"_cs, type); + typeObj->emplace("default_value"_cs, defaultValue); return typeObj; } static inline Util::JsonObject *makeTypeBool(std::optional defaultValue = std::nullopt) { auto *typeObj = new Util::JsonObject(); - typeObj->emplace("type", "bool"); - if (defaultValue != std::nullopt) typeObj->emplace("default_value", *defaultValue); + typeObj->emplace("type"_cs, "bool"); + if (defaultValue != std::nullopt) typeObj->emplace("default_value"_cs, *defaultValue); return typeObj; } static inline Util::JsonObject *makeTypeBytes(int width, std::optional defaultValue = std::nullopt) { auto *typeObj = new Util::JsonObject(); - typeObj->emplace("type", "bytes"); - typeObj->emplace("width", width); - if (defaultValue != std::nullopt) typeObj->emplace("default_value", *defaultValue); + typeObj->emplace("type"_cs, "bytes"); + typeObj->emplace("width"_cs, width); + if (defaultValue != std::nullopt) typeObj->emplace("default_value"_cs, *defaultValue); return typeObj; } static inline Util::JsonObject *makeTypeEnum(const std::vector &choices, std::optional defaultValue = std::nullopt) { auto *typeObj = new Util::JsonObject(); - typeObj->emplace("type", "string"); + typeObj->emplace("type"_cs, "string"); auto *choicesArray = new Util::JsonArray(); for (auto choice : choices) choicesArray->append(choice); - typeObj->emplace("choices", choicesArray); - if (defaultValue != std::nullopt) typeObj->emplace("default_value", *defaultValue); + typeObj->emplace("choices"_cs, choicesArray); + if (defaultValue != std::nullopt) typeObj->emplace("default_value"_cs, *defaultValue); return typeObj; } static inline void addSingleton(Util::JsonArray *dataJson, Util::JsonObject *dataField, bool mandatory, bool readOnly) { auto *singletonJson = new Util::JsonObject(); - singletonJson->emplace("mandatory", mandatory); - singletonJson->emplace("read_only", readOnly); - singletonJson->emplace("singleton", dataField); + singletonJson->emplace("mandatory"_cs, mandatory); + singletonJson->emplace("read_only"_cs, readOnly); + singletonJson->emplace("singleton"_cs, dataField); dataJson->append(singletonJson); } static inline void addOneOf(Util::JsonArray *dataJson, Util::JsonArray *choicesJson, bool mandatory, bool readOnly) { auto *oneOfJson = new Util::JsonObject(); - oneOfJson->emplace("mandatory", mandatory); - oneOfJson->emplace("read_only", readOnly); - oneOfJson->emplace("oneof", choicesJson); + oneOfJson->emplace("mandatory"_cs, mandatory); + oneOfJson->emplace("read_only"_cs, readOnly); + oneOfJson->emplace("oneof"_cs, choicesJson); dataJson->append(oneOfJson); } @@ -196,27 +196,25 @@ static inline std::optional transformMatchType( case p4configv1::MatchField_MatchType_UNSPECIFIED: return std::nullopt; case p4configv1::MatchField_MatchType_EXACT: - return cstring("Exact"); + return "Exact"_cs; case p4configv1::MatchField_MatchType_LPM: - return cstring("LPM"); + return "LPM"_cs; case p4configv1::MatchField_MatchType_TERNARY: - return cstring("Ternary"); + return "Ternary"_cs; case p4configv1::MatchField_MatchType_RANGE: - return cstring("Range"); + return "Range"_cs; case p4configv1::MatchField_MatchType_OPTIONAL: - return cstring("Optional"); + return "Optional"_cs; default: return std::nullopt; } } static inline std::optional transformOtherMatchType(std::string matchType) { - if (matchType == "atcam_partition_index") - return cstring("ATCAM"); - else if (matchType == "dleft_hash") - return cstring("DLEFT_HASH"); - else - return std::nullopt; + if (matchType == "atcam_partition_index") return "ATCAM"_cs; + if (matchType == "dleft_hash") return "DLEFT_HASH"_cs; + + return std::nullopt; } template @@ -253,7 +251,8 @@ class TypeSpecParser { const p4configv1::P4DataTypeSpec &typeSpec, cstring instanceType, cstring instanceName, const std::vector *fieldNames = nullptr, - cstring prefix = "", cstring suffix = "", P4Id idOffset = 1); + cstring prefix = cstring::empty, cstring suffix = cstring::empty, + P4Id idOffset = 1); iterator begin() { return fields.begin(); } const_iterator cbegin() { return fields.cbegin(); } @@ -424,8 +423,8 @@ class BFRuntimeGenerator { const p4configv1::P4DataTypeSpec &typeSpec, cstring instanceType, cstring instanceName, const std::vector *fieldNames = nullptr, - cstring prefix = "", cstring suffix = "", - P4Id idOffset = 1) const; + cstring prefix = cstring::empty, + cstring suffix = cstring::empty, P4Id idOffset = 1) const; static void addMeterDataFields(Util::JsonArray *dataJson, const Meter &meter); static Util::JsonObject *makeCommonDataField(P4Id id, cstring name, Util::JsonObject *type, diff --git a/control-plane/flattenHeader.cpp b/control-plane/flattenHeader.cpp index 5713423263..8494fcf4b8 100644 --- a/control-plane/flattenHeader.cpp +++ b/control-plane/flattenHeader.cpp @@ -50,9 +50,12 @@ void FlattenHeader::doFlatten(const IR::Type *type) { } } -cstring FlattenHeader::makeName(cstring sep) const { - cstring name = ""; - for (auto n : nameSegments) name += sep + n; +cstring FlattenHeader::makeName(std::string_view sep) const { + std::string name; + for (auto n : nameSegments) { + name += sep; + name += n; + } return name; } diff --git a/control-plane/flattenHeader.h b/control-plane/flattenHeader.h index 568dddf3ba..9736453411 100644 --- a/control-plane/flattenHeader.h +++ b/control-plane/flattenHeader.h @@ -40,7 +40,7 @@ class FlattenHeader { void doFlatten(const IR::Type *type); - cstring makeName(cstring sep) const; + cstring makeName(std::string_view sep) const; const IR::Annotations *mergeAnnotations() const; public: diff --git a/control-plane/p4RuntimeAnnotations.h b/control-plane/p4RuntimeAnnotations.h index 1a1e223b2f..9c1efd80c4 100644 --- a/control-plane/p4RuntimeAnnotations.h +++ b/control-plane/p4RuntimeAnnotations.h @@ -31,12 +31,12 @@ class ParseP4RuntimeAnnotations : public ParseAnnotations { : ParseAnnotations( "P4Runtime", false, { - PARSE("controller_header", StringLiteral), - PARSE_EMPTY("hidden"), - PARSE("id", Constant), - PARSE("brief", StringLiteral), - PARSE("description", StringLiteral), - PARSE_KV_LIST("platform_property"), + PARSE("controller_header"_cs, StringLiteral), + PARSE_EMPTY("hidden"_cs), + PARSE("id"_cs, Constant), + PARSE("brief"_cs, StringLiteral), + PARSE("description"_cs, StringLiteral), + PARSE_KV_LIST("platform_property"_cs), // These annotations are architecture-specific in theory, but // given that they are "reserved" by the P4Runtime // specification, I don't really have any qualms about adding @@ -50,10 +50,10 @@ class ParseP4RuntimeAnnotations : public ParseAnnotations { // ParseAnnotations instance, or 2) run a ParseAnnotations // pass "locally" (in this case on action profile instances // since these annotations are for them). - PARSE("max_group_size", Constant), - PARSE("selector_size_semantics", StringLiteral), - PARSE("max_member_weight", Constant), - {"p4runtime_translation", &ParseAnnotations::parseP4rtTranslationAnnotation}, + PARSE("max_group_size"_cs, Constant), + PARSE("selector_size_semantics"_cs, StringLiteral), + PARSE("max_member_weight"_cs, Constant), + {"p4runtime_translation"_cs, &ParseAnnotations::parseP4rtTranslationAnnotation}, }) {} }; diff --git a/control-plane/p4RuntimeArchHandler.cpp b/control-plane/p4RuntimeArchHandler.cpp index 7b7104da19..8c8466acff 100644 --- a/control-plane/p4RuntimeArchHandler.cpp +++ b/control-plane/p4RuntimeArchHandler.cpp @@ -94,7 +94,7 @@ int64_t getTableSize(const IR::P4Table *table) { // default table size. const int64_t defaultTableSize = P4V1::V1Model::instance.tableAttributes.defaultTableSize; - auto sizeProperty = table->properties->getProperty("size"); + auto sizeProperty = table->properties->getProperty("size"_cs); if (sizeProperty == nullptr) { return defaultTableSize; } diff --git a/control-plane/p4RuntimeArchHandler.h b/control-plane/p4RuntimeArchHandler.h index 440e0cd264..8c000d7c80 100644 --- a/control-plane/p4RuntimeArchHandler.h +++ b/control-plane/p4RuntimeArchHandler.h @@ -38,11 +38,14 @@ limitations under the License. #include "frontends/p4/methodInstance.h" #include "frontends/p4/typeMap.h" #include "ir/ir.h" +#include "lib/cstring.h" #include "lib/ordered_set.h" #include "typeSpecConverter.h" namespace P4 { +using namespace literals; + /** \addtogroup control_plane * @{ */ @@ -139,7 +142,7 @@ class P4RuntimeArchHandlerIface { /// Get control plane name for @block virtual cstring getControlPlaneName(const IR::Block *block) { auto decl = block->getContainer(); - return decl ? decl->controlPlaneName() : ""; + return decl ? decl->controlPlaneName() : cstring::empty; } /// Collects architecture-specific properties for @tableBlock in @symbols /// table. @@ -396,7 +399,7 @@ struct Counterlike { // Counter and meter externs refer to their unit as a "type"; this is // (confusingly) unrelated to the "type" field of a counter or meter in // P4Info. - auto unit = instance->getParameterValue("type"); + auto unit = instance->getParameterValue("type"_cs); if (!unit->is()) { ::error(ErrorType::ERR_INVALID, "%1% '%2%' has a unit type which is not an enum constant: %3%", @@ -457,7 +460,7 @@ struct Counterlike { return std::nullopt; } - auto unitArgument = instance.substitution.lookupByName("type")->expression; + auto unitArgument = instance.substitution.lookupByName("type"_cs)->expression; if (unitArgument == nullptr) { ::error(ErrorType::ERR_EXPECTED, "Direct %1% instance %2% should take a constructor argument", @@ -477,7 +480,7 @@ struct Counterlike { unit, Helpers::getTableSize(table), table->controlPlaneName(), - ""}; + cstring::empty}; } }; diff --git a/control-plane/p4RuntimeArchStandard.h b/control-plane/p4RuntimeArchStandard.h index 470461db3e..4bd40bfdd3 100644 --- a/control-plane/p4RuntimeArchStandard.h +++ b/control-plane/p4RuntimeArchStandard.h @@ -72,13 +72,13 @@ namespace Helpers { /// @ref CounterlikeTraits<> specialization for @ref CounterExtern for v1model template <> struct CounterlikeTraits> { - static const cstring name() { return "counter"; } + static const cstring name() { return "counter"_cs; } static const cstring directPropertyName() { return P4V1::V1Model::instance.tableAttributes.counters.name; } static const cstring typeName() { return P4V1::V1Model::instance.counter.name; } static const cstring directTypeName() { return P4V1::V1Model::instance.directCounter.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } static p4configv1::CounterSpec::Unit mapUnitName(const cstring name) { using p4configv1::CounterSpec; if (name == "packets") @@ -94,13 +94,13 @@ struct CounterlikeTraits> { template <> struct CounterlikeTraits> { - static const cstring name() { return "counter"; } + static const cstring name() { return "counter"_cs; } static const cstring directPropertyName() { return P4V1::V1Model::instance.tableAttributes.counters.name; } static const cstring typeName() { return P4V1::V1Model::instance.counter.name; } static const cstring directTypeName() { return P4V1::V1Model::instance.directCounter.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } static p4configv1::CounterSpec::Unit mapUnitName(const cstring name) { using p4configv1::CounterSpec; if (name == "packets") @@ -117,11 +117,11 @@ struct CounterlikeTraits> { /// @ref CounterlikeTraits<> specialization for @ref CounterExtern for PSA template <> struct CounterlikeTraits> { - static const cstring name() { return "counter"; } - static const cstring directPropertyName() { return "psa_direct_counter"; } - static const cstring typeName() { return "Counter"; } - static const cstring directTypeName() { return "DirectCounter"; } - static const cstring sizeParamName() { return "n_counters"; } + static const cstring name() { return "counter"_cs; } + static const cstring directPropertyName() { return "psa_direct_counter"_cs; } + static const cstring typeName() { return "Counter"_cs; } + static const cstring directTypeName() { return "DirectCounter"_cs; } + static const cstring sizeParamName() { return "n_counters"_cs; } static p4configv1::CounterSpec::Unit mapUnitName(const cstring name) { using p4configv1::CounterSpec; if (name == "PACKETS") @@ -140,11 +140,11 @@ struct CounterlikeTraits> { /// @ref CounterlikeTraits<> specialization for @ref CounterExtern for PNA template <> struct CounterlikeTraits> { - static const cstring name() { return "counter"; } - static const cstring directPropertyName() { return "pna_direct_counter"; } - static const cstring typeName() { return "Counter"; } - static const cstring directTypeName() { return "DirectCounter"; } - static const cstring sizeParamName() { return "n_counters"; } + static const cstring name() { return "counter"_cs; } + static const cstring directPropertyName() { return "pna_direct_counter"_cs; } + static const cstring typeName() { return "Counter"_cs; } + static const cstring directTypeName() { return "DirectCounter"_cs; } + static const cstring sizeParamName() { return "n_counters"_cs; } static p4configv1::CounterSpec::Unit mapUnitName(const cstring name) { using p4configv1::CounterSpec; if (name == "PACKETS") @@ -163,13 +163,13 @@ struct CounterlikeTraits> { /// @ref CounterlikeTraits<> specialization for @ref MeterExtern for v1model template <> struct CounterlikeTraits> { - static const cstring name() { return "meter"; } + static const cstring name() { return "meter"_cs; } static const cstring directPropertyName() { return P4V1::V1Model::instance.tableAttributes.meters.name; } static const cstring typeName() { return P4V1::V1Model::instance.meter.name; } static const cstring directTypeName() { return P4V1::V1Model::instance.directMeter.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } static p4configv1::MeterSpec::Unit mapUnitName(const cstring name) { using p4configv1::MeterSpec; if (name == "packets") @@ -183,13 +183,13 @@ struct CounterlikeTraits> { template <> struct CounterlikeTraits> { - static const cstring name() { return "meter"; } + static const cstring name() { return "meter"_cs; } static const cstring directPropertyName() { return P4V1::V1Model::instance.tableAttributes.meters.name; } static const cstring typeName() { return P4V1::V1Model::instance.meter.name; } static const cstring directTypeName() { return P4V1::V1Model::instance.directMeter.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } static p4configv1::MeterSpec::Unit mapUnitName(const cstring name) { using p4configv1::MeterSpec; if (name == "packets") @@ -204,11 +204,11 @@ struct CounterlikeTraits> { /// @ref CounterlikeTraits<> specialization for @ref MeterExtern for PSA template <> struct CounterlikeTraits> { - static const cstring name() { return "meter"; } - static const cstring directPropertyName() { return "psa_direct_meter"; } - static const cstring typeName() { return "Meter"; } - static const cstring directTypeName() { return "DirectMeter"; } - static const cstring sizeParamName() { return "n_meters"; } + static const cstring name() { return "meter"_cs; } + static const cstring directPropertyName() { return "psa_direct_meter"_cs; } + static const cstring typeName() { return "Meter"_cs; } + static const cstring directTypeName() { return "DirectMeter"_cs; } + static const cstring sizeParamName() { return "n_meters"_cs; } static p4configv1::MeterSpec::Unit mapUnitName(const cstring name) { using p4configv1::MeterSpec; if (name == "PACKETS") @@ -225,11 +225,11 @@ struct CounterlikeTraits> { /// @ref CounterlikeTraits<> specialization for @ref MeterExtern for PNA template <> struct CounterlikeTraits> { - static const cstring name() { return "meter"; } - static const cstring directPropertyName() { return "pna_direct_meter"; } - static const cstring typeName() { return "Meter"; } - static const cstring directTypeName() { return "DirectMeter"; } - static const cstring sizeParamName() { return "n_meters"; } + static const cstring name() { return "meter"_cs; } + static const cstring directPropertyName() { return "pna_direct_meter"_cs; } + static const cstring typeName() { return "Meter"_cs; } + static const cstring directTypeName() { return "DirectMeter"_cs; } + static const cstring sizeParamName() { return "n_meters"_cs; } static p4configv1::MeterSpec::Unit mapUnitName(const cstring name) { using p4configv1::MeterSpec; if (name == "PACKETS") @@ -308,38 +308,38 @@ struct ActionProfileTraits; template <> struct ActionProfileTraits { - static const cstring name() { return "action profile"; } + static const cstring name() { return "action profile"_cs; } static const cstring propertyName() { return P4V1::V1Model::instance.tableAttributes.tableImplementation.name; } static const cstring typeName() { return P4V1::V1Model::instance.action_profile.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } }; template <> struct ActionProfileTraits { - static const cstring name() { return "action profile"; } + static const cstring name() { return "action profile"_cs; } static const cstring propertyName() { return P4V1::V1Model::instance.tableAttributes.tableImplementation.name; } static const cstring typeName() { return P4V1::V1Model::instance.action_profile.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } }; template <> struct ActionProfileTraits { - static const cstring name() { return "action profile"; } - static const cstring propertyName() { return "psa_implementation"; } - static const cstring typeName() { return "ActionProfile"; } - static const cstring sizeParamName() { return "size"; } + static const cstring name() { return "action profile"_cs; } + static const cstring propertyName() { return "psa_implementation"_cs; } + static const cstring typeName() { return "ActionProfile"_cs; } + static const cstring sizeParamName() { return "size"_cs; } }; template <> struct ActionProfileTraits { - static const cstring name() { return "action profile"; } - static const cstring propertyName() { return "pna_implementation"; } - static const cstring typeName() { return "ActionProfile"; } - static const cstring sizeParamName() { return "size"; } + static const cstring name() { return "action profile"_cs; } + static const cstring propertyName() { return "pna_implementation"_cs; } + static const cstring typeName() { return "ActionProfile"_cs; } + static const cstring sizeParamName() { return "size"_cs; } }; /// Traits for the action selector extern, must be specialized for v1model and @@ -349,26 +349,26 @@ struct ActionSelectorTraits; template <> struct ActionSelectorTraits : public ActionProfileTraits { - static const cstring name() { return "action selector"; } + static const cstring name() { return "action selector"_cs; } static const cstring typeName() { return P4V1::V1Model::instance.action_selector.name; } }; template <> struct ActionSelectorTraits : public ActionProfileTraits { - static const cstring name() { return "action selector"; } + static const cstring name() { return "action selector"_cs; } static const cstring typeName() { return P4V1::V1Model::instance.action_selector.name; } }; template <> struct ActionSelectorTraits : public ActionProfileTraits { - static const cstring name() { return "action selector"; } - static const cstring typeName() { return "ActionSelector"; } + static const cstring name() { return "action selector"_cs; } + static const cstring typeName() { return "ActionSelector"_cs; } }; template <> struct ActionSelectorTraits : public ActionProfileTraits { - static const cstring name() { return "action selector"; } - static const cstring typeName() { return "ActionSelector"; } + static const cstring name() { return "action selector"_cs; } + static const cstring typeName() { return "ActionSelector"_cs; } }; /// Traits for the register extern, must be specialized for v1model and PSA. @@ -377,9 +377,9 @@ struct RegisterTraits; template <> struct RegisterTraits { - static const cstring name() { return "register"; } + static const cstring name() { return "register"_cs; } static const cstring typeName() { return P4V1::V1Model::instance.registers.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } // the index of the type parameter for the data stored in the register, in // the type parameter list of the extern type declaration static size_t dataTypeParamIdx() { return 0; } @@ -388,9 +388,9 @@ struct RegisterTraits { template <> struct RegisterTraits { - static const cstring name() { return "register"; } + static const cstring name() { return "register"_cs; } static const cstring typeName() { return P4V1::V1Model::instance.registers.name; } - static const cstring sizeParamName() { return "size"; } + static const cstring sizeParamName() { return "size"_cs; } // the index of the type parameter for the data stored in the register, in // the type parameter list of the extern type declaration static size_t dataTypeParamIdx() { return 0; } @@ -399,9 +399,9 @@ struct RegisterTraits { template <> struct RegisterTraits { - static const cstring name() { return "register"; } - static const cstring typeName() { return "Register"; } - static const cstring sizeParamName() { return "size"; } + static const cstring name() { return "register"_cs; } + static const cstring typeName() { return "Register"_cs; } + static const cstring sizeParamName() { return "size"_cs; } static size_t dataTypeParamIdx() { return 0; } // the index of the type parameter for the register index, in the type // parameter list of the extern type declaration. @@ -410,9 +410,9 @@ struct RegisterTraits { template <> struct RegisterTraits { - static const cstring name() { return "register"; } - static const cstring typeName() { return "Register"; } - static const cstring sizeParamName() { return "size"; } + static const cstring name() { return "register"_cs; } + static const cstring typeName() { return "Register"_cs; } + static const cstring sizeParamName() { return "size"_cs; } static size_t dataTypeParamIdx() { return 0; } // the index of the type parameter for the register index, in the type // parameter list of the extern type declaration. @@ -448,7 +448,7 @@ struct Register { CHECK_NULL(instance); auto declaration = instance->node->to(); - auto size = instance->getParameterValue("size")->to(); + auto size = instance->getParameterValue("size"_cs)->to(); if (!size->is()) { ::error(ErrorType::ERR_UNSUPPORTED, "Register '%1%' has a non-constant size: %2%", declaration, size); @@ -776,7 +776,7 @@ class P4RuntimeArchHandlerCommon : public P4RuntimeArchHandlerIface { }); profile->set_with_selector(actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR); profile->set_size(actionProfile.size); - auto maxGroupSizeAnnotation = actionProfile.annotations->getAnnotation("max_group_size"); + auto maxGroupSizeAnnotation = actionProfile.annotations->getAnnotation("max_group_size"_cs); if (maxGroupSizeAnnotation) { if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR) { auto maxGroupSizeConstant = @@ -793,7 +793,7 @@ class P4RuntimeArchHandlerCommon : public P4RuntimeArchHandlerIface { // By default, an action profile uses the SumOfWeights semantics. auto selectorSizeSemanticsAnnotation = - actionProfile.annotations->getAnnotation("selector_size_semantics"); + actionProfile.annotations->getAnnotation("selector_size_semantics"_cs); if (selectorSizeSemanticsAnnotation) { if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR) { auto selectorSizeSemantics = @@ -821,7 +821,7 @@ class P4RuntimeArchHandlerCommon : public P4RuntimeArchHandlerIface { // By default, an action profile uses the SumOfWeights semantics. auto maxMemberWeightAnnotation = - actionProfile.annotations->getAnnotation("max_member_weight"); + actionProfile.annotations->getAnnotation("max_member_weight"_cs); if (maxMemberWeightAnnotation) { if (actionProfile.type == ActionProfileType::INDIRECT_WITH_SELECTOR && profile->has_sum_of_members()) { @@ -1058,7 +1058,7 @@ class P4RuntimeArchHandlerPSAPNA : public P4RuntimeArchHandlerCommon { /// @return true if @table's 'psa_idle_timeout' property exists and is true. This /// indicates that @table supports entry ageing. static bool getSupportsTimeout(const IR::P4Table *table) { - auto timeout = table->properties->getProperty("psa_idle_timeout"); + auto timeout = table->properties->getProperty("psa_idle_timeout"_cs); if (timeout == nullptr) return false; diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index bf6d264521..32aef714f0 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -479,18 +479,20 @@ class P4RuntimeAnalyzer { // I considered using Protobuf reflection, but it didn't really make the // code less verbose, and it certainly didn't make it easier to read. - dupCnt += checkForDuplicatesOfSameType(p4Info->tables(), "table", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->actions(), "action", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->action_profiles(), "action profile", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->counters(), "counter", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->direct_counters(), "direct counter", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->meters(), "meter", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->direct_meters(), "direct meter", &ids); + dupCnt += checkForDuplicatesOfSameType(p4Info->tables(), "table"_cs, &ids); + dupCnt += checkForDuplicatesOfSameType(p4Info->actions(), "action"_cs, &ids); + dupCnt += + checkForDuplicatesOfSameType(p4Info->action_profiles(), "action profile"_cs, &ids); + dupCnt += checkForDuplicatesOfSameType(p4Info->counters(), "counter"_cs, &ids); + dupCnt += + checkForDuplicatesOfSameType(p4Info->direct_counters(), "direct counter"_cs, &ids); + dupCnt += checkForDuplicatesOfSameType(p4Info->meters(), "meter"_cs, &ids); + dupCnt += checkForDuplicatesOfSameType(p4Info->direct_meters(), "direct meter"_cs, &ids); dupCnt += checkForDuplicatesOfSameType(p4Info->controller_packet_metadata(), - "controller packet metadata", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->value_sets(), "value set", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->registers(), "register", &ids); - dupCnt += checkForDuplicatesOfSameType(p4Info->digests(), "digest", &ids); + "controller packet metadata"_cs, &ids); + dupCnt += checkForDuplicatesOfSameType(p4Info->value_sets(), "value set"_cs, &ids); + dupCnt += checkForDuplicatesOfSameType(p4Info->registers(), "register"_cs, &ids); + dupCnt += checkForDuplicatesOfSameType(p4Info->digests(), "digest"_cs, &ids); for (const auto &externType : p4Info->externs()) { dupCnt += checkForDuplicatesOfSameType(externType.instances(), @@ -601,7 +603,7 @@ class P4RuntimeAnalyzer { auto id = symbols.getId(P4RuntimeSymbolType::P4RT_CONTROLLER_HEADER(), name); auto annotations = type->to(); - auto controllerAnnotation = type->getAnnotation("controller_header"); + auto controllerAnnotation = type->getAnnotation("controller_header"_cs); CHECK_NULL(controllerAnnotation); auto nameConstant = controllerAnnotation->expr[0]->to(); @@ -683,8 +685,8 @@ class P4RuntimeAnalyzer { action_ref->set_id(id); addAnnotations(action_ref, action.annotations); // set action ref scope - auto isTableOnly = (action.annotations->getAnnotation("tableonly") != nullptr); - auto isDefaultOnly = (action.annotations->getAnnotation("defaultonly") != nullptr); + auto isTableOnly = (action.annotations->getAnnotation("tableonly"_cs) != nullptr); + auto isDefaultOnly = (action.annotations->getAnnotation("defaultonly"_cs) != nullptr); if (isTableOnly && isDefaultOnly) { ::error(ErrorType::ERR_INVALID, "Table '%1%' has an action reference ('%2%') which is annotated " @@ -1080,7 +1082,7 @@ class P4RuntimeEntriesConverter { } } - auto priorityAnnotation = e->getAnnotation("priority"); + auto priorityAnnotation = e->getAnnotation("priority"_cs); if (priorityAnnotation != nullptr) { ::warning(ErrorType::WARN_DEPRECATED, "The @priority annotation on %1% is not part of the P4 specification, " @@ -1527,34 +1529,28 @@ void P4RuntimeAPI::serializeEntriesTo(std::ostream *destination, P4RuntimeFormat static bool parseFileNames(cstring fileNameVector, std::vector &files, std::vector &formats) { - for (auto current = fileNameVector; current;) { + // FIXME: Logic here shoule be refactored. Lots of cstring copies everywhere. + for (auto current = fileNameVector; !current.isNullOrEmpty();) { cstring name = current; const char *comma = current.find(','); if (comma != nullptr) { name = current.before(comma); - current = comma + 1; + current = cstring(comma + 1); } else { - current = cstring(); + current = cstring::empty; } files.push_back(name); - if (cstring suffix = name.findlast('.')) { - if (suffix == ".json") { - formats.push_back(P4::P4RuntimeFormat::JSON); - } else if (suffix == ".bin") { - formats.push_back(P4::P4RuntimeFormat::BINARY); - } else if (suffix == ".txtpb") { - formats.push_back(P4::P4RuntimeFormat::TEXT_PROTOBUF); - } else if (suffix == ".txt") { - ::warning(ErrorType::WARN_DEPRECATED, - ".txt format is being deprecated; use .txtpb instead"); - formats.push_back(P4::P4RuntimeFormat::TEXT); - } else { - ::error(ErrorType::ERR_UNKNOWN, - "%1%: Could not detect p4runtime info file format from file suffix %2%", - name, suffix); - return false; - } + if (name.endsWith(".json")) { + formats.push_back(P4::P4RuntimeFormat::JSON); + } else if (name.endsWith(".bin")) { + formats.push_back(P4::P4RuntimeFormat::BINARY); + } else if (name.endsWith(".txtpb")) { + formats.push_back(P4::P4RuntimeFormat::TEXT_PROTOBUF); + } else if (name.endsWith(".txt")) { + ::warning(ErrorType::WARN_DEPRECATED, + ".txt format is being deprecated; use .txtpb instead"); + formats.push_back(P4::P4RuntimeFormat::TEXT); } else { ::error(ErrorType::ERR_UNKNOWN, "%1%: unknown file kind; known suffixes are .bin, .txt, .json, and .txtpb", @@ -1632,10 +1628,10 @@ void P4RuntimeSerializer::serializeP4RuntimeIfRequired(const P4RuntimeAPI &p4Run } P4RuntimeSerializer::P4RuntimeSerializer() { - registerArch("v1model", new ControlPlaneAPI::Standard::V1ModelArchHandlerBuilder()); - registerArch("psa", new ControlPlaneAPI::Standard::PSAArchHandlerBuilder()); - registerArch("pna", new ControlPlaneAPI::Standard::PNAArchHandlerBuilder()); - registerArch("ubpf", new ControlPlaneAPI::Standard::UBPFArchHandlerBuilder()); + registerArch("v1model"_cs, new ControlPlaneAPI::Standard::V1ModelArchHandlerBuilder()); + registerArch("psa"_cs, new ControlPlaneAPI::Standard::PSAArchHandlerBuilder()); + registerArch("pna"_cs, new ControlPlaneAPI::Standard::PNAArchHandlerBuilder()); + registerArch("ubpf"_cs, new ControlPlaneAPI::Standard::UBPFArchHandlerBuilder()); } P4RuntimeSerializer *P4RuntimeSerializer::get() { @@ -1649,7 +1645,7 @@ cstring P4RuntimeSerializer::resolveArch(const CompilerOptions &options) { } else if (options.arch != nullptr) { return options.arch; } else { - return "v1model"; + return "v1model"_cs; } } diff --git a/control-plane/p4RuntimeSerializer.h b/control-plane/p4RuntimeSerializer.h index e78040dfb2..a50fc42d28 100644 --- a/control-plane/p4RuntimeSerializer.h +++ b/control-plane/p4RuntimeSerializer.h @@ -48,6 +48,8 @@ class CompilerOptions; namespace P4 { +using namespace literals; + /// A P4 program's control-plane API, represented in terms of P4Runtime's data /// structures. Can be inspected or serialized. struct P4RuntimeAPI { @@ -139,7 +141,7 @@ class P4RuntimeSerializer { /// Calls @ref P4RuntimeSerializer::generateP4Runtime on the @ref /// P4RuntimeSerializer singleton. -P4RuntimeAPI generateP4Runtime(const IR::P4Program *program, cstring arch = "v1model"); +P4RuntimeAPI generateP4Runtime(const IR::P4Program *program, cstring arch = "v1model"_cs); /// Calls @ref P4RuntimeSerializer::serializeP4RuntimeIfRequired on the @ref /// P4RuntimeSerializer singleton. diff --git a/control-plane/p4RuntimeSymbolTable.cpp b/control-plane/p4RuntimeSymbolTable.cpp index 555ca6dd30..3249c80c26 100644 --- a/control-plane/p4RuntimeSymbolTable.cpp +++ b/control-plane/p4RuntimeSymbolTable.cpp @@ -26,13 +26,13 @@ namespace P4 { namespace ControlPlaneAPI { bool isControllerHeader(const IR::Type_Header *type) { - return type->getAnnotation("controller_header") != nullptr; + return type->getAnnotation("controller_header"_cs) != nullptr; } -bool isHidden(const IR::Node *node) { return node->getAnnotation("hidden") != nullptr; } +bool isHidden(const IR::Node *node) { return node->getAnnotation("hidden"_cs) != nullptr; } std::optional getIdAnnotation(const IR::IAnnotated *node) { - const auto *idAnnotation = node->getAnnotation("id"); + const auto *idAnnotation = node->getAnnotation("id"_cs); if (idAnnotation == nullptr) { return std::nullopt; } diff --git a/control-plane/typeSpecConverter.cpp b/control-plane/typeSpecConverter.cpp index d771f22a2c..875953bcd0 100644 --- a/control-plane/typeSpecConverter.cpp +++ b/control-plane/typeSpecConverter.cpp @@ -41,7 +41,7 @@ namespace P4 { namespace ControlPlaneAPI { bool hasTranslationAnnotation(const IR::Type *type, TranslationAnnotation *payload) { - auto ann = type->getAnnotation("p4runtime_translation"); + auto ann = type->getAnnotation("p4runtime_translation"_cs); if (!ann) return false; // Syntax: @pruntime_translation(, ). diff --git a/frontends/common/applyOptionsPragmas.cpp b/frontends/common/applyOptionsPragmas.cpp index dc67166067..1ea9288c92 100644 --- a/frontends/common/applyOptionsPragmas.cpp +++ b/frontends/common/applyOptionsPragmas.cpp @@ -86,11 +86,11 @@ std::optional P4COptionPragmaParser::pa cstring diagnosticOption; if (diagnosticAction->value == "disable") { - diagnosticOption = "--Wdisable="; + diagnosticOption = "--Wdisable="_cs; } else if (diagnosticAction->value == "warn") { - diagnosticOption = "--Wwarn="; + diagnosticOption = "--Wwarn="_cs; } else if (diagnosticAction->value == "error") { - diagnosticOption = "--Werror="; + diagnosticOption = "--Werror="_cs; } else { ::warning(ErrorType::WARN_MISMATCH, "@diagnostic's second argument must be 'disable', " diff --git a/frontends/common/constantFolding.h b/frontends/common/constantFolding.h index 832d4be2ff..8a53623926 100644 --- a/frontends/common/constantFolding.h +++ b/frontends/common/constantFolding.h @@ -23,6 +23,8 @@ limitations under the License. namespace P4 { +using namespace literals; + /// A policy for constant folding that allows customization of the folding. /// Currently we only have hook for customizing IR::PathExpression, but more can be added. /// Each hook takes a visitor and a node and is called from the visitor's preorder function on that @@ -163,7 +165,7 @@ class DoConstantFolding : public Transform { const IR::Node *preorder(IR::ArrayIndex *e) override; const IR::Node *preorder(IR::SwitchCase *c) override; const IR::BlockStatement *preorder(IR::BlockStatement *bs) override { - if (bs->annotations->getSingle("disable_optimization")) prune(); + if (bs->annotations->getSingle("disable_optimization"_cs)) prune(); return bs; } }; diff --git a/frontends/common/options.cpp b/frontends/common/options.cpp index b6edfade15..85efbe60c5 100644 --- a/frontends/common/options.cpp +++ b/frontends/common/options.cpp @@ -23,8 +23,9 @@ CompilerOptions::CompilerOptions() : ParserOptions() { "--excludeFrontendPasses", "pass1[,pass2]", [this](const char *arg) { excludeFrontendPasses = true; + // FIXME: just split into string_view's auto copy = strdup(arg); - while (auto pass = strsep(©, ",")) passesToExcludeFrontend.push_back(pass); + while (auto pass = strsep(©, ",")) passesToExcludeFrontend.push_back(cstring(pass)); return true; }, "Exclude passes from frontend passes whose name is equal\n" @@ -44,7 +45,7 @@ CompilerOptions::CompilerOptions() : ParserOptions() { [this](const char *arg) { excludeMidendPasses = true; auto copy = strdup(arg); - while (auto pass = strsep(©, ",")) passesToExcludeMidend.push_back(pass); + while (auto pass = strsep(©, ",")) passesToExcludeMidend.push_back(cstring(pass)); return true; }, "Exclude passes from midend passes whose name is equal\n" @@ -52,7 +53,7 @@ CompilerOptions::CompilerOptions() : ParserOptions() { registerOption( "--toJSON", "file", [this](const char *arg) { - dumpJsonFile = arg; + dumpJsonFile = cstring(arg); return true; }, "Dump the compiler IR after the midend as JSON in the specified file."); @@ -73,14 +74,14 @@ CompilerOptions::CompilerOptions() : ParserOptions() { registerOption( "--pp", "file", [this](const char *arg) { - prettyPrintFile = arg; + prettyPrintFile = cstring(arg); return true; }, "Pretty-print the program in the specified file."); registerOption( "--p4runtime-file", "file", [this](const char *arg) { - p4RuntimeFile = arg; + p4RuntimeFile = cstring(arg); return true; }, "Write a P4Runtime control plane API description to the specified " @@ -89,7 +90,7 @@ CompilerOptions::CompilerOptions() : ParserOptions() { registerOption( "--p4runtime-entries-file", "file", [this](const char *arg) { - p4RuntimeEntriesFile = arg; + p4RuntimeEntriesFile = cstring(arg); return true; }, "Write static table entries as a P4Runtime WriteRequest message" @@ -98,7 +99,7 @@ CompilerOptions::CompilerOptions() : ParserOptions() { registerOption( "--p4runtime-files", "filelist", [this](const char *arg) { - p4RuntimeFiles = arg; + p4RuntimeFiles = cstring(arg); return true; }, "Write the P4Runtime control plane API description to the specified\n" @@ -107,7 +108,7 @@ CompilerOptions::CompilerOptions() : ParserOptions() { registerOption( "--p4runtime-entries-files", "files", [this](const char *arg) { - p4RuntimeEntriesFiles = arg; + p4RuntimeEntriesFiles = cstring(arg); return true; }, "Write static table entries as a P4Runtime WriteRequest message\n" @@ -134,14 +135,14 @@ CompilerOptions::CompilerOptions() : ParserOptions() { registerOption( "--target", "target", [this](const char *arg) { - target = arg; + target = cstring(arg); return true; }, "Compile for the specified target device."); registerOption( "--arch", "arch", [this](const char *arg) { - arch = arg; + arch = cstring(arg); return true; }, "Compile for the specified architecture."); diff --git a/frontends/common/parser_options.cpp b/frontends/common/parser_options.cpp index fe451240e9..1d5e502a52 100644 --- a/frontends/common/parser_options.cpp +++ b/frontends/common/parser_options.cpp @@ -44,6 +44,8 @@ const char *p4_14includePath = CONFIG_PKGDATADIR "/p4_14include"; const char *ParserOptions::defaultMessage = "Compile a P4 program"; +using namespace P4::literals; + ParserOptions::ParserOptions() : Util::Options(defaultMessage) { registerOption( "--help", nullptr, @@ -180,7 +182,7 @@ ParserOptions::ParserOptions() : Util::Options(defaultMessage) { "--disable-annotations", "annotations", [this](const char *arg) { auto copy = strdup(arg); - while (auto name = strsep(©, ",")) disabledAnnotations.insert(name); + while (auto name = strsep(©, ",")) disabledAnnotations.insert(cstring(name)); return true; }, "Specify a (comma separated) list of annotations that should be " @@ -277,7 +279,7 @@ ParserOptions::ParserOptions() : Util::Options(defaultMessage) { "--top4", "pass1[,pass2]", [this](const char *arg) { auto copy = strdup(arg); - while (auto pass = strsep(©, ",")) top4.push_back(pass); + while (auto pass = strsep(©, ",")) top4.push_back(cstring(pass)); return true; }, "[Compiler debugging] Dump the P4 representation after\n" @@ -286,7 +288,7 @@ ParserOptions::ParserOptions() : Util::Options(defaultMessage) { registerOption( "--dump", "folder", [this](const char *arg) { - dumpFolder = arg; + dumpFolder = cstring(arg); return true; }, "[Compiler debugging] Folder where P4 programs are dumped\n"); @@ -308,7 +310,7 @@ ParserOptions::ParserOptions() : Util::Options(defaultMessage) { registerOption( "--doNotEmitIncludes", "condition", [this](const char *arg) { - noIncludes = arg; + noIncludes = cstring(arg); return true; }, "[Compiler debugging] If true do not generate #include statements\n"); @@ -329,7 +331,7 @@ void ParserOptions::setInputFile() { usage(); exit(1); } else { - file = remainingOptions.at(0); + file = cstring(remainingOptions.at(0)); } } @@ -358,7 +360,7 @@ bool ParserOptions::searchForIncludePath(const char *&includePathOut, snprintf(buffer, sizeof(buffer), "%s", exename); if (char *p = strrchr(buffer, '/')) { ++p; - exe_name = p; + exe_name = cstring(p); for (auto path : userSpecifiedPaths) { snprintf(p, buffer + sizeof(buffer) - p, "%s", path.c_str()); @@ -373,10 +375,10 @@ bool ParserOptions::searchForIncludePath(const char *&includePathOut, } std::vector *ParserOptions::process(int argc, char *const argv[]) { - searchForIncludePath(p4includePath, {"p4include", "../p4include", "../../p4include"}, + searchForIncludePath(p4includePath, {"p4include"_cs, "../p4include"_cs, "../../p4include"_cs}, exename(argv[0])); searchForIncludePath(p4_14includePath, - {"p4_14include", "../p4_14include", "../../p4_14include"}, + {"p4_14include"_cs, "../p4_14include"_cs, "../../p4_14include"_cs}, exename(argv[0])); auto remainingOptions = Util::Options::process(argc, argv); @@ -387,15 +389,15 @@ std::vector *ParserOptions::process(int argc, char *const argv[]) void ParserOptions::validateOptions() const {} const char *ParserOptions::getIncludePath() { - cstring path = ""; + cstring path = cstring::empty; // the p4c driver sets environment variables for include // paths. check the environment and add these to the command // line for the preprocessor char *driverP4IncludePath = isv1() ? getenv("P4C_14_INCLUDE_PATH") : getenv("P4C_16_INCLUDE_PATH"); - if (driverP4IncludePath != nullptr) path += (cstring(" -I") + cstring(driverP4IncludePath)); - path += cstring(" -I") + (isv1() ? p4_14includePath : p4includePath); - if (!isv1()) path += cstring(" -I") + p4includePath + cstring("/bmv2"); + if (driverP4IncludePath != nullptr) path += (" -I"_cs + cstring(driverP4IncludePath)); + path += " -I"_cs + (isv1() ? p4_14includePath : p4includePath); + if (!isv1()) path += " -I"_cs + p4includePath + "/bmv2"_cs; return path.c_str(); } @@ -403,7 +405,7 @@ FILE *ParserOptions::preprocess() { FILE *in = nullptr; if (file == "-") { - file = ""; + file = ""_cs; in = stdin; } else { #ifdef __clang__ @@ -412,10 +414,10 @@ FILE *ParserOptions::preprocess() { std::string cmd("cpp"); #endif - if (file == nullptr) file = ""; - if (file.find(' ')) file = cstring("\"") + file + "\""; - cmd += cstring(" -C -undef -nostdinc -x assembler-with-cpp") + " " + preprocessor_options + - getIncludePath() + " " + file; + if (file == nullptr) file = cstring::empty; + if (file.find(' ')) file = "\""_cs + file + "\""_cs; + cmd += " -C -undef -nostdinc -x assembler-with-cpp " + preprocessor_options.string() + + getIncludePath() + " " + file.string(); if (Log::verbose()) std::cerr << "Invoking preprocessor " << std::endl << cmd << std::endl; in = popen(cmd.c_str(), "r"); @@ -483,11 +485,12 @@ void ParserOptions::dumpPass(const char *manager, unsigned seq, const char *pass exit(1); } if (match) { + // FIXME: switch to sane printing via abseil char buf[16]; snprintf(buf, sizeof(buf), "-%04zu-", ++dump_uid); cstring suffix = cstring(buf) + name; cstring filename = file; - if (filename == "-") filename = "tmp.p4"; + if (filename == "-") filename = "tmp.p4"_cs; cstring fileName = makeFileName(dumpFolder, filename, suffix); std::unique_ptr stream{openFile(fileName, true)}; @@ -531,7 +534,7 @@ const P4CConfiguration &P4CContext::getConfig() { bool P4CContext::isRecognizedDiagnostic(cstring diagnostic) { static const std::unordered_set recognizedDiagnostics = { - "uninitialized_out_param", "uninitialized_use", "unknown_diagnostic"}; + "uninitialized_out_param"_cs, "uninitialized_use"_cs, "unknown_diagnostic"_cs}; return recognizedDiagnostics.count(diagnostic); } diff --git a/frontends/common/parser_options.h b/frontends/common/parser_options.h index 893a63933c..1da48b0dee 100644 --- a/frontends/common/parser_options.h +++ b/frontends/common/parser_options.h @@ -61,7 +61,7 @@ class ParserOptions : public Util::Options { // Which language to compile FrontendVersion langVersion = FrontendVersion::P4_16; // options to pass to preprocessor - cstring preprocessor_options = ""; + cstring preprocessor_options = cstring::empty; // file to compile (- for stdin) cstring file = nullptr; // if true preprocess only @@ -73,7 +73,7 @@ class ParserOptions : public Util::Options { // substrings matched against pass names std::vector top4; // debugging dumps of programs written in this folder - cstring dumpFolder = "."; + cstring dumpFolder = cstring::literal("."); // If false, optimization of callee parsers (subparsers) inlining is disabled. bool optimizeParserInlining = false; // Expect that the only remaining argument is the input file. @@ -145,7 +145,7 @@ class P4CContext : public BaseCompileContext { } /// Set the action to take for the given diagnostic. - void setDiagnosticAction(cstring diagnostic, DiagnosticAction action) { + void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action) { errorReporter().setDiagnosticAction(diagnostic, action); } diff --git a/frontends/common/programMap.h b/frontends/common/programMap.h index 4f3e661538..85ea0a2835 100644 --- a/frontends/common/programMap.h +++ b/frontends/common/programMap.h @@ -30,7 +30,7 @@ class ProgramMap : public IHasDbPrint { const IR::P4Program *fake = new IR::P4Program(); const IR::P4Program *program = nullptr; cstring mapKind; - explicit ProgramMap(cstring kind) : mapKind(kind) {} + explicit ProgramMap(std::string_view kind) : mapKind(kind) {} virtual ~ProgramMap() {} public: diff --git a/frontends/common/resolveReferences/referenceMap.cpp b/frontends/common/resolveReferences/referenceMap.cpp index 68469ce9b3..a9ab45663f 100644 --- a/frontends/common/resolveReferences/referenceMap.cpp +++ b/frontends/common/resolveReferences/referenceMap.cpp @@ -93,7 +93,7 @@ void ReferenceMap::dbprint(std::ostream &out) const { for (auto e : pathToDeclaration) out << dbp(e.first) << "->" << dbp(e.second) << std::endl; } -cstring ReferenceMap::newName(cstring base) { +cstring ReferenceMap::newName(std::string_view base) { // Maybe in the future we'll maintain information with per-scope identifiers, // but today we are content to generate globally-unique identifiers. @@ -102,17 +102,20 @@ cstring ReferenceMap::newName(cstring base) { // This will not impact correctness. unsigned len = base.size(); const char digits[] = "0123456789"; - const char *s = base.c_str(); + const char *s = base.data(); while (len > 0 && strchr(digits, s[len - 1])) len--; if (len > 0 && base[len - 1] == '_') base = base.substr(0, len - 1); - cstring name = base; - if (usedNames.count(name)) name = cstring::make_unique(usedNames, name, usedNames[base], '_'); - usedNames.emplace(name, 0); + cstring name(base); + auto [it, inserted] = usedNames.emplace(name, 0); + if (!inserted) { + name = cstring::make_unique(usedNames, name, it->second, '_'); + usedNames.emplace(name, 0); + } return name; } -cstring MinimalNameGenerator::newName(cstring base) { +cstring MinimalNameGenerator::newName(std::string_view base) { // Maybe in the future we'll maintain information with per-scope identifiers, // but today we are content to generate globally-unique identifiers. @@ -121,13 +124,16 @@ cstring MinimalNameGenerator::newName(cstring base) { // This will not impact correctness. unsigned len = base.size(); const char digits[] = "0123456789"; - const char *s = base.c_str(); + const char *s = base.data(); while (len > 0 && strchr(digits, s[len - 1])) len--; if (len > 0 && base[len - 1] == '_') base = base.substr(0, len - 1); - cstring name = base; - if (usedNames.count(name)) name = cstring::make_unique(usedNames, name, usedNames[base], '_'); - usedNames.emplace(name, 0); + cstring name(base); + auto [it, inserted] = usedNames.emplace(name, 0); + if (!inserted) { + name = cstring::make_unique(usedNames, name, it->second, '_'); + usedNames.emplace(name, 0); + } return name; } diff --git a/frontends/common/resolveReferences/referenceMap.h b/frontends/common/resolveReferences/referenceMap.h index c07e2afeab..3c462d5c66 100644 --- a/frontends/common/resolveReferences/referenceMap.h +++ b/frontends/common/resolveReferences/referenceMap.h @@ -28,7 +28,7 @@ namespace P4 { class NameGenerator { public: - virtual cstring newName(cstring base) = 0; + virtual cstring newName(std::string_view base) = 0; }; // replacement for ReferenceMap NameGenerator to make it easier to remove uses of refMap @@ -48,7 +48,7 @@ class MinimalNameGenerator : public NameGenerator, public Inspector { } /// Generate a name from @p base that does not appear in usedNames. - cstring newName(cstring base) override; + cstring newName(std::string_view base) override; }; // FIXME -- temp common base class to allow use of ReferenceMap or ResolutionContext @@ -105,7 +105,7 @@ class ReferenceMap final : public ProgramMap, public NameGenerator, public Decla void setAnyOrder(bool anyOrder) { this->isv1 = anyOrder; } /// Generate a name from @p base that fresh for the program. - cstring newName(cstring base) override; + cstring newName(std::string_view base) override; /// Clear the reference map void clear(); diff --git a/frontends/p4-14/header_type.cpp b/frontends/p4-14/header_type.cpp index fb96a129ff..d2d57e8d67 100644 --- a/frontends/p4-14/header_type.cpp +++ b/frontends/p4-14/header_type.cpp @@ -16,20 +16,22 @@ limitations under the License. #include "header_type.h" +using namespace P4::literals; + bool HeaderTypeMaxLengthCalculator::preorder(IR::Type_StructLike *hdr_type) { IR::Annotations *annot = nullptr; - auto *max_length = hdr_type->getAnnotation("max_length"); + auto *max_length = hdr_type->getAnnotation("max_length"_cs); if (!max_length) { unsigned len = 0; for (auto field : hdr_type->fields) len += field->type->width_bits(); - max_length = new IR::Annotation("max_length", len); + max_length = new IR::Annotation("max_length"_cs, len); if (!annot) annot = hdr_type->annotations->clone(); annot->annotations.push_back(max_length); } - auto *length = hdr_type->getAnnotation("length"); + auto *length = hdr_type->getAnnotation("length"_cs); if (!length) { if (!annot) annot = hdr_type->annotations->clone(); - length = new IR::Annotation("length", max_length->expr); + length = new IR::Annotation("length"_cs, max_length->expr); annot->annotations.push_back(length); } if (annot) hdr_type->annotations = annot; diff --git a/frontends/p4-14/typecheck.cpp b/frontends/p4-14/typecheck.cpp index 6cdac075e1..c7226f56b8 100644 --- a/frontends/p4-14/typecheck.cpp +++ b/frontends/p4-14/typecheck.cpp @@ -19,6 +19,8 @@ limitations under the License. #include "ir/dump.h" #include "lib/log.h" +using namespace P4::literals; + /// P4-14 (v1.0 and v1.1) type checking algorithm /// Initial type setting based on immediate context: /// - replace named reference to ActionParams in the bodies of ActionFunctions with the @@ -181,8 +183,8 @@ class TypeCheck::AssignInitialTypes : public Transform { auto prim = getParent(); // context is a primitive call static const std::set header_prims = { // primitives that operate on headers or header stacks - "add_header", "copy_header", "emit", "extract", - "push", "pop", "remove_header", "valid"}; + "add_header"_cs, "copy_header"_cs, "emit"_cs, "extract"_cs, + "push"_cs, "pop"_cs, "remove_header"_cs, "valid"_cs}; if (hdr && (!obj || preferHdr || (prim && header_prims.count(prim->name)))) { // prefer header to object only if in a simple member reference or in a // header stack reference or a primitive that is valid on headers. diff --git a/frontends/p4/actionsInlining.cpp b/frontends/p4/actionsInlining.cpp index 5dca99a45a..d54f5e5983 100644 --- a/frontends/p4/actionsInlining.cpp +++ b/frontends/p4/actionsInlining.cpp @@ -86,7 +86,7 @@ const IR::Node *ActionsInliner::preorder(IR::MethodCallStatement *statement) { // evaluate in and inout parameters in order for (auto param : callee->parameters->parameters) { auto argument = substitution.lookup(param); - cstring newName = refMap->newName(param->name); + cstring newName = refMap->newName(param->name.name.string_view()); paramRename.emplace(param, newName); if (param->direction == IR::Direction::In || param->direction == IR::Direction::InOut) { auto vardecl = new IR::Declaration_Variable(newName, param->annotations, param->type, diff --git a/frontends/p4/alias.h b/frontends/p4/alias.h index 7c87ac4dea..bdd25c729a 100644 --- a/frontends/p4/alias.h +++ b/frontends/p4/alias.h @@ -33,6 +33,8 @@ limitations under the License. namespace P4 { +using namespace literals; + /// This class represents the path to a location. /// Given a struct S { bit a; bit b; } and a variable S x; /// a path can be x.a, or just x. An array index is represented as a @@ -157,7 +159,7 @@ class ReadsWrites : public Inspector { result = e->append(Util::toString(index)); } else { auto index = ::get(rw, expression->right); - result = e->append("*")->join(index); + result = e->append("*"_cs)->join(index); } rw.emplace(expression, result); } diff --git a/frontends/p4/callGraph.cpp b/frontends/p4/callGraph.cpp index 2e5983c996..1800b9da76 100644 --- a/frontends/p4/callGraph.cpp +++ b/frontends/p4/callGraph.cpp @@ -1,9 +1,10 @@ #include "callGraph.h" namespace P4 { +using namespace literals; cstring cgMakeString(cstring s) { return s; } -cstring cgMakeString(char c) { return cstring("") + c; } +cstring cgMakeString(char c) { return ""_cs + c; } cstring cgMakeString(const IR::Node *node) { return node->toString(); } cstring cgMakeString(const IR::INode *node) { return node->toString(); } diff --git a/frontends/p4/callGraph.h b/frontends/p4/callGraph.h index 0da754f633..d457622ce5 100644 --- a/frontends/p4/callGraph.h +++ b/frontends/p4/callGraph.h @@ -49,7 +49,7 @@ class CallGraph { ordered_set nodes; // all nodes; do not modify this directly typedef typename ordered_map *>::const_iterator const_iterator; - explicit CallGraph(cstring name) : name(name) {} + explicit CallGraph(std::string_view name) : name(name) {} const cstring &getName() const { return name; } diff --git a/frontends/p4/commonInlining.h b/frontends/p4/commonInlining.h index a8623e4d77..69cb16f29b 100644 --- a/frontends/p4/commonInlining.h +++ b/frontends/p4/commonInlining.h @@ -32,6 +32,8 @@ limitations under the License. namespace P4 { +using namespace literals; + template class SimpleCallInfo : public IHasDbPrint { // Callable can be P4Action, Function, P4Control, P4Parser @@ -164,7 +166,7 @@ class InlineDriver : public Visitor { : toInline(toInline), inliner(inliner) { CHECK_NULL(toInline); CHECK_NULL(inliner); - setName((cstring("InlineDriver_") + cstring(inliner->name())).c_str()); + setName(("InlineDriver_"_cs + cstring(inliner->name())).c_str()); } const IR::Node *apply_visitor(const IR::Node *program, const char * = 0) override { LOG2("InlineDriver"); diff --git a/frontends/p4/coreLibrary.h b/frontends/p4/coreLibrary.h index 7ab5126d39..43a99bf310 100644 --- a/frontends/p4/coreLibrary.h +++ b/frontends/p4/coreLibrary.h @@ -64,14 +64,16 @@ inline std::ostream &operator<<(std::ostream &out, P4::StandardExceptions e) { namespace P4 { +using namespace literals; + class PacketIn : public Model::Extern_Model { public: PacketIn() - : Extern_Model("packet_in"), - extract("extract"), - lookahead("lookahead"), - advance("advance"), - length("length") {} + : Extern_Model("packet_in"_cs), + extract("extract"_cs), + lookahead("lookahead"_cs), + advance("advance"_cs), + length("length"_cs) {} Model::Elem extract; Model::Elem lookahead; Model::Elem advance; @@ -81,14 +83,14 @@ class PacketIn : public Model::Extern_Model { class PacketOut : public Model::Extern_Model { public: - PacketOut() : Extern_Model("packet_out"), emit("emit") {} + PacketOut() : Extern_Model("packet_out"_cs), emit("emit"_cs) {} Model::Elem emit; }; class P4Exception_Model : public ::Model::Elem { public: const StandardExceptions exc; - explicit P4Exception_Model(StandardExceptions exc) : ::Model::Elem(""), exc(exc) { + explicit P4Exception_Model(StandardExceptions exc) : ::Model::Elem(cstring::empty), exc(exc) { std::stringstream str; str << exc; name = str.str(); @@ -101,10 +103,10 @@ class P4CoreLibrary : public ::Model::Model { protected: // NOLINTBEGIN(bugprone-throw-keyword-missing) P4CoreLibrary() - : noAction("NoAction"), - exactMatch("exact"), - ternaryMatch("ternary"), - lpmMatch("lpm"), + : noAction("NoAction"_cs), + exactMatch("exact"_cs), + ternaryMatch("ternary"_cs), + lpmMatch("lpm"_cs), noError(StandardExceptions::NoError), packetTooShort(StandardExceptions::PacketTooShort), noMatch(StandardExceptions::NoMatch), diff --git a/frontends/p4/createBuiltins.cpp b/frontends/p4/createBuiltins.cpp index 16bac04341..47360fd7e5 100644 --- a/frontends/p4/createBuiltins.cpp +++ b/frontends/p4/createBuiltins.cpp @@ -23,7 +23,7 @@ limitations under the License. namespace P4 { const IR::Node *CreateBuiltins::preorder(IR::P4Program *program) { - auto decls = program->getDeclsByName(P4::P4CoreLibrary::instance().noAction.str()); + auto decls = program->getDeclsByName(P4::P4CoreLibrary::instance().noAction.toString()); auto vec = decls->toVector(); if (vec.empty()) return program; if (vec.size() > 1) { @@ -118,7 +118,7 @@ const IR::Node *CreateBuiltins::postorder(IR::ParserState *state) { const IR::Node *CreateBuiltins::postorder(IR::ActionList *actions) { if (!addNoAction) return actions; - auto decl = actions->getDeclaration(P4::P4CoreLibrary::instance().noAction.str()); + auto decl = actions->getDeclaration(P4::P4CoreLibrary::instance().noAction.toString()); if (decl != nullptr) return actions; checkGlobalAction(); actions->push_back(new IR::ActionListElement( diff --git a/frontends/p4/def_use.cpp b/frontends/p4/def_use.cpp index 8163202fca..f4d1842c18 100644 --- a/frontends/p4/def_use.cpp +++ b/frontends/p4/def_use.cpp @@ -23,9 +23,11 @@ limitations under the License. namespace P4 { +using namespace literals; + // internal name for header valid bit; used only locally -const cstring StorageFactory::validFieldName = "$valid"; -const cstring StorageFactory::indexFieldName = "$lastIndex"; +const cstring StorageFactory::validFieldName = "$valid"_cs; +const cstring StorageFactory::indexFieldName = "$lastIndex"_cs; const LocationSet *LocationSet::empty = new LocationSet(); ProgramPoint ProgramPoint::beforeStart; diff --git a/frontends/p4/deprecated.cpp b/frontends/p4/deprecated.cpp index 432a531e27..2f8636b2d8 100644 --- a/frontends/p4/deprecated.cpp +++ b/frontends/p4/deprecated.cpp @@ -25,9 +25,9 @@ void CheckDeprecated::warnIfDeprecated(const IR::IAnnotated *annotated, const IR auto anno = annotated->getAnnotations()->getSingle(IR::Annotation::deprecatedAnnotation); if (anno == nullptr) return; - cstring message = ""; - for (auto a : anno->expr) { - if (auto str = a->to()) message += str->value; + std::string message; + for (const auto *a : anno->expr) { + if (const auto *str = a->to()) message += str->value; } ::warning(ErrorType::WARN_DEPRECATED, "%1%: Using deprecated feature %2%. %3%", errorNode, annotated->getNode(), message); diff --git a/frontends/p4/entryPriorities.cpp b/frontends/p4/entryPriorities.cpp index 17bcb238ec..6188376f2c 100644 --- a/frontends/p4/entryPriorities.cpp +++ b/frontends/p4/entryPriorities.cpp @@ -56,9 +56,9 @@ const IR::Node *DoEntryPriorities::preorder(IR::EntriesList *entries) { bool largestWins = true; // default value size_t priorityDelta = 1; // default value - auto largestProp = table->getBooleanProperty("largest_priority_wins"); + auto largestProp = table->getBooleanProperty("largest_priority_wins"_cs); if (largestProp) largestWins = largestProp->value; - auto deltaProp = table->getConstantProperty("priority_delta"); + auto deltaProp = table->getConstantProperty("priority_delta"_cs); if (deltaProp) { if (!deltaProp->fitsUint()) { ::error(ErrorType::ERR_INVALID, "%1% must be a positive value", deltaProp); diff --git a/frontends/p4/fromv1.0/converters.cpp b/frontends/p4/fromv1.0/converters.cpp index def4f61051..a14d730a3c 100644 --- a/frontends/p4/fromv1.0/converters.cpp +++ b/frontends/p4/fromv1.0/converters.cpp @@ -68,7 +68,8 @@ const IR::Node *ExpressionConverter::postorder(IR::Constant *expression) { const IR::Node *ExpressionConverter::postorder(IR::FieldList *fl) { // Field lists may contain other field lists - if (auto func = get(std::type_index(typeid(*fl)).name())) { + cstring name(std::type_index(typeid(*fl)).name()); + if (auto func = get(name)) { return func(fl); } return new IR::ListExpression(fl->srcInfo, fl->fields); @@ -409,7 +410,7 @@ const IR::Statement *StatementConverter::convert(const IR::Vectorsize == 0) { if (auto type = findContext()) { - if (auto max = type->getAnnotation("max_length")) { + if (auto max = type->getAnnotation("max_length"_cs)) { if (max->expr.size() != 1 || !max->expr[0]->is()) error(ErrorType::ERR_UNSUPPORTED, "%s: max_length must be a constant", max); else @@ -458,7 +459,7 @@ 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("length")) { + if (auto len = type->getAnnotation("length"_cs)) { if (len->expr.size() == 1) { auto lenexpr = len->expr[0]; ValidateLenExpr vle(type, field); @@ -468,12 +469,12 @@ const IR::StructField *TypeConverter::postorder(IR::StructField *field) { auto fieldlen = new IR::Sub(scale->srcInfo, scale, new IR::Constant(type->width_bits())); field->annotations = - field->annotations->add(new IR::Annotation("length", {fieldlen})); + field->annotations->add(new IR::Annotation("length"_cs, {fieldlen})); } } } if (auto vec = structure->listIndexes(type->name.name, field->name.name)) - field->annotations = field->annotations->add(new IR::Annotation("field_list", *vec)); + field->annotations = field->annotations->add(new IR::Annotation("field_list"_cs, *vec)); return field; } @@ -522,7 +523,7 @@ class FixupExtern : public Modifier { bool preorder(IR::Parameter *param) override { BUG_CHECK(typeParams, "recursion failure"); if (param->type->is()) { - auto n = new IR::Type_Var(structure->makeUniqueName("FL")); + auto n = new IR::Type_Var(structure->makeUniqueName("FL"_cs)); param->type = n; typeParams->push_back(n); } @@ -592,10 +593,11 @@ ExternConverter *ExternConverter::get(cstring type) { std::map> *PrimitiveConverter::all_converters; -PrimitiveConverter::PrimitiveConverter(cstring name, int prio) : prim_name(name), priority(prio) { +PrimitiveConverter::PrimitiveConverter(std::string_view name, int prio) + : prim_name(name), priority(prio) { static std::map> converters; all_converters = &converters; - auto &vec = converters[name]; + auto &vec = converters[prim_name]; auto it = vec.begin(); while (it != vec.end() && (*it)->priority > prio) ++it; if (it != vec.end() && (*it)->priority == prio) diff --git a/frontends/p4/fromv1.0/converters.h b/frontends/p4/fromv1.0/converters.h index 2b65d65011..400e412c69 100644 --- a/frontends/p4/fromv1.0/converters.h +++ b/frontends/p4/fromv1.0/converters.h @@ -143,7 +143,7 @@ class PrimitiveConverter { int priority; protected: - PrimitiveConverter(cstring name, int prio); + PrimitiveConverter(std::string_view name, int prio); virtual ~PrimitiveConverter(); // helper functions @@ -178,8 +178,9 @@ class DiscoverStructure : public Inspector { ProgramStructure *structure; // These names can only be used for very specific purposes - std::map reserved_names = { - {"standard_metadata_t", "type"}, {"standard_metadata", "metadata"}, {"egress", "control"}}; + std::map reserved_names = {{"standard_metadata_t"_cs, "type"_cs}, + {"standard_metadata"_cs, "metadata"_cs}, + {"egress"_cs, "control"_cs}}; void checkReserved(const IR::Node *node, cstring nodeName, cstring kind) const { auto it = reserved_names.find(nodeName); @@ -203,7 +204,7 @@ class DiscoverStructure : public Inspector { } void postorder(const IR::Metadata *md) override { structure->metadata.emplace(md); - checkReserved(md, md->name, "metadata"); + checkReserved(md, md->name, "metadata"_cs); } void postorder(const IR::Header *hd) override { structure->headers.emplace(hd); @@ -211,11 +212,11 @@ class DiscoverStructure : public Inspector { } void postorder(const IR::Type_StructLike *t) override { structure->types.emplace(t); - checkReserved(t, t->name, "type"); + checkReserved(t, t->name, "type"_cs); } void postorder(const IR::V1Control *control) override { structure->controls.emplace(control); - checkReserved(control, control->name, "control"); + checkReserved(control, control->name, "control"_cs); } void postorder(const IR::V1Parser *parser) override { structure->parserStates.emplace(parser); @@ -537,7 +538,7 @@ class FixExtracts final : public Transform { for (auto f : type->fields) { if (f->type->is()) { - cstring hname = structure->makeUniqueName(type->name); + cstring hname = structure->makeUniqueName(type->name.name); if (fixedHeaderType != nullptr) { ::error(ErrorType::ERR_INVALID, "%1%: header types with multiple varbit fields are not supported", @@ -637,7 +638,7 @@ class FixExtracts final : public Transform { CHECK_NULL(fixed->fixedHeaderType); auto result = new IR::IndexedVector(); - cstring varName = structure->makeUniqueName("tmp_hdr"); + cstring varName = structure->makeUniqueName("tmp_hdr"_cs); auto var = new IR::Declaration_Variable(IR::ID(varName), fixed->fixedHeaderType->to()); varDecls.push_back(var); @@ -796,9 +797,9 @@ class InsertCompilerGeneratedStartState : public Transform { explicit InsertCompilerGeneratedStartState(ProgramStructure *structure) : structure(structure) { setName("InsertCompilerGeneratedStartState"); structure->allNames.insert({IR::ParserState::start, 0}); - structure->allNames.insert({"InstanceType", 0}); + structure->allNames.insert({"InstanceType"_cs, 0}); newStartState = structure->makeUniqueName(IR::ParserState::start); - newInstanceType = structure->makeUniqueName("InstanceType"); + newInstanceType = structure->makeUniqueName("InstanceType"_cs); } const IR::Node *postorder(IR::P4Program *program) override { @@ -841,7 +842,8 @@ class InsertCompilerGeneratedStartState : public Transform { // transition to original start state members.push_back(new IR::SerEnumMember("START", new IR::Constant(0))); selCases.push_back(new IR::SelectCase( - new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(newInstanceType)), "START"), + new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(newInstanceType)), + "START"_cs), new IR::PathExpression(new IR::Path(newStartState)))); // transition to addtional entry points @@ -854,19 +856,19 @@ class InsertCompilerGeneratedStartState : public Transform { new IR::PathExpression(new IR::Path(p.second->name)))); } auto instAnnos = new IR::Annotations(); - instAnnos->add(new IR::Annotation(IR::Annotation::nameAnnotation, ".$InstanceType")); + instAnnos->add(new IR::Annotation(IR::Annotation::nameAnnotation, ".$InstanceType"_cs)); auto instEnum = new IR::Type_SerEnum(newInstanceType, instAnnos, IR::Type_Bits::get(32), members); allTypeDecls.push_back(instEnum); IR::Vector selExpr; - selExpr.push_back( - new IR::Cast(new IR::Type_Name(newInstanceType), - new IR::Member(new IR::PathExpression(new IR::Path("standard_metadata")), - "instance_type"))); + selExpr.push_back(new IR::Cast( + new IR::Type_Name(newInstanceType), + new IR::Member(new IR::PathExpression(new IR::Path("standard_metadata"_cs)), + "instance_type"_cs))); auto selects = new IR::SelectExpression(new IR::ListExpression(selExpr), selCases); auto annos = new IR::Annotations(); - annos->add(new IR::Annotation(IR::Annotation::nameAnnotation, ".$start")); + annos->add(new IR::Annotation(IR::Annotation::nameAnnotation, ".$start"_cs)); auto startState = new IR::ParserState(IR::ParserState::start, annos, selects); parserStates.push_back(startState); diff --git a/frontends/p4/fromv1.0/programStructure.cpp b/frontends/p4/fromv1.0/programStructure.cpp index 1f7542c9be..385aa233d9 100644 --- a/frontends/p4/fromv1.0/programStructure.cpp +++ b/frontends/p4/fromv1.0/programStructure.cpp @@ -31,6 +31,7 @@ limitations under the License. #include "lib/path.h" namespace P4V1 { +using namespace P4::literals; static const IR::IDeclaration *getFirstDeclaration(const IR::Vector *nodes, cstring name) { @@ -90,7 +91,7 @@ const IR::Annotations *ProgramStructure::addNameAnnotation(cstring name, const IR::Annotations *ProgramStructure::addGlobalNameAnnotation(cstring name, const IR::Annotations *annos) { - return addNameAnnotation(cstring(".") + name, annos); + return addNameAnnotation("."_cs + name, annos); } cstring ProgramStructure::makeUniqueName(cstring base) { @@ -199,7 +200,7 @@ cstring ProgramStructure::createType(const IR::Type_StructLike *type, bool heade void ProgramStructure::createTypes() { if (allFieldLists.size()) { // An enum containing the recirculated/cloned/resubmitted field lists - fieldListsEnum = makeUniqueName("FieldLists"); + fieldListsEnum = makeUniqueName("FieldLists"_cs); auto members = new IR::IndexedVector(); unsigned index = 0; P4::MinimalNameGenerator mng; @@ -239,7 +240,7 @@ void ProgramStructure::createTypes() { BUG_CHECK(type->is(), "%1%: unexpected type", type); // Must convert to a struct type - cstring type_name = makeUniqueName(st->name); + cstring type_name = makeUniqueName(st->name.name); // Registers always use struct types auto annos = addNameAnnotation(layoutTypeName, type->annotations); auto newType = new IR::Type_Struct(type->srcInfo, type_name, annos, st->fields); @@ -278,7 +279,7 @@ const IR::Type_Struct *ProgramStructure::createFieldListType(const IR::Expressio return nullptr; } - auto name = makeUniqueName(nr->path->name); + auto name = makeUniqueName(nr->path->name.name); auto annos = addNameAnnotation(nr->path->name); auto result = new IR::Type_Struct(expression->srcInfo, name, annos); std::set fieldNames; @@ -555,7 +556,7 @@ const IR::ParserState *ProgramStructure::convertParser( value_sets_implemented.emplace(first->path->name); auto type = explodeType(fieldTypes); - auto sizeAnnotation = value_set->annotations->getSingle("parser_value_set_size"); + auto sizeAnnotation = value_set->annotations->getSingle("parser_value_set_size"_cs); const IR::Constant *sizeConstant; if (sizeAnnotation) { if (sizeAnnotation->expr.size() != 1) { @@ -896,9 +897,9 @@ const IR::Declaration_Instance *ProgramStructure::convertActionProfile( auto width = new IR::Constant(v1model.action_selector.widthType, flc->output_width); args->push_back(new IR::Argument(width)); if (action_selector->mode) - annos = annos->addAnnotation("mode", new IR::StringLiteral(action_selector->mode)); + annos = annos->addAnnotation("mode"_cs, new IR::StringLiteral(action_selector->mode)); if (action_selector->type) - annos = annos->addAnnotation("type", new IR::StringLiteral(action_selector->type)); + annos = annos->addAnnotation("type"_cs, new IR::StringLiteral(action_selector->type)); auto fl = getFieldLists(flc); for (auto annot : fl->annotations->annotations) { annos = annos->add(annot); @@ -936,7 +937,7 @@ const IR::P4Table *ProgramStructure::convertTable(const IR::V1Table *table, cstr if (mtr != nullptr || ctr != nullptr) { // we must synthesize a new action, which has a writeback to // the meter/counter - newname = makeUniqueName(a); + newname = makeUniqueName(a.name); auto actCont = convertAction(action, newname, mtr, ctr); stateful.push_back(actCont); mapNames[table->name + '.' + a] = newname; @@ -1139,7 +1140,7 @@ static bool isSaturatedField(const IR::Expression *expr) { 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")) { + if (field && field->getAnnotation("saturating"_cs)) { return true; } return false; @@ -1573,7 +1574,7 @@ CONVERT_PRIMITIVE( auto block = new IR::BlockStatement; if (primitive->operands.size() == 3) { mask = conv.convert(primitive->operands.at(2)); - cstring tmpvar = structure->makeUniqueName("tmp"); + cstring tmpvar = structure->makeUniqueName("tmp"_cs); auto decl = new IR::Declaration_Variable(tmpvar, field->type); block->push_back(decl); dest = new IR::PathExpression(field->type, new IR::Path(tmpvar)); @@ -2089,9 +2090,9 @@ const IR::Declaration_Instance *ProgramStructure::convert(const IR::CounterOrMet auto annos = addGlobalNameAnnotation(cm->name, cm->annotations); if (auto *c = cm->to()) { if (c->min_width >= 0) - annos = annos->addAnnotation("min_width", new IR::Constant(c->min_width)); + annos = annos->addAnnotation("min_width"_cs, new IR::Constant(c->min_width)); if (c->max_width >= 0) - annos = annos->addAnnotation("max_width", new IR::Constant(c->max_width)); + annos = annos->addAnnotation("max_width"_cs, new IR::Constant(c->max_width)); } auto decl = new IR::Declaration_Instance(newName, annos, type, args, nullptr); return decl; @@ -2120,7 +2121,7 @@ const IR::Declaration_Instance *ProgramStructure::convertDirectMeter(const IR::M auto annos = addGlobalNameAnnotation(m->name, m->annotations); if (m->pre_color != nullptr) { auto meterPreColor = ExpressionConverter(this).convert(m->pre_color); - if (meterPreColor != nullptr) annos = annos->addAnnotation("pre_color", meterPreColor); + if (meterPreColor != nullptr) annos = annos->addAnnotation("pre_color"_cs, meterPreColor); } auto decl = new IR::Declaration_Instance(newName, annos, specType, args, nullptr); return decl; @@ -2138,9 +2139,9 @@ const IR::Declaration_Instance *ProgramStructure::convertDirectCounter(const IR: args->push_back(new IR::Argument(kindarg)); auto annos = addGlobalNameAnnotation(c->name, c->annotations); if (c->min_width >= 0) - annos = annos->addAnnotation("min_width", new IR::Constant(c->min_width)); + annos = annos->addAnnotation("min_width"_cs, new IR::Constant(c->min_width)); if (c->max_width >= 0) - annos = annos->addAnnotation("max_width", new IR::Constant(c->max_width)); + annos = annos->addAnnotation("max_width"_cs, new IR::Constant(c->max_width)); auto decl = new IR::Declaration_Instance(newName, annos, type, args, nullptr); return decl; } @@ -2626,6 +2627,7 @@ void ProgramStructure::tablesReferred(const IR::V1Control *control, } void ProgramStructure::populateOutputNames() { + // FIXME: modernize static const char *used_names[] = { // core.p4 "packet_in", "packet_out", "NoAction", "exact", "ternary", "lpm", @@ -2643,7 +2645,7 @@ void ProgramStructure::populateOutputNames() { "DeparserImpl", // parameters "packet", "hdr", "meta", nullptr}; - for (const char **c = used_names; *c != nullptr; ++c) allNames.insert({*c, 0}); + for (const char **c = used_names; *c != nullptr; ++c) allNames.emplace(cstring(*c), 0); ; } diff --git a/frontends/p4/fromv1.0/v1model.h b/frontends/p4/fromv1.0/v1model.h index ed84632738..667d7fdd2b 100644 --- a/frontends/p4/fromv1.0/v1model.h +++ b/frontends/p4/fromv1.0/v1model.h @@ -26,6 +26,8 @@ limitations under the License. namespace P4V1 { +using namespace P4::literals; + // This should be kept in sync with p4includes/v1model.p4 // In a perfect world this would be generated automatically from // p4includes/v1model.p4 @@ -33,11 +35,11 @@ namespace P4V1 { struct Parser_Model : public ::Model::Elem { Parser_Model(Model::Type_Model headersType, Model::Type_Model userMetaType, Model::Type_Model standardMetadataType) - : Model::Elem("ParserImpl"), - packetParam("packet", P4::P4CoreLibrary::instance().packetIn, 0), - headersParam("hdr", headersType, 1), - metadataParam("meta", userMetaType, 2), - standardMetadataParam("standard_metadata", standardMetadataType, 3) {} + : Model::Elem("ParserImpl"_cs), + packetParam("packet"_cs, P4::P4CoreLibrary::instance().packetIn, 0), + headersParam("hdr"_cs, headersType, 1), + metadataParam("meta"_cs, userMetaType, 2), + standardMetadataParam("standard_metadata"_cs, standardMetadataType, 3) {} ::Model::Param_Model packetParam; ::Model::Param_Model headersParam; ::Model::Param_Model metadataParam; @@ -46,9 +48,9 @@ struct Parser_Model : public ::Model::Elem { struct Deparser_Model : public ::Model::Elem { explicit Deparser_Model(Model::Type_Model headersType) - : Model::Elem("DeparserImpl"), - packetParam("packet", P4::P4CoreLibrary::instance().packetOut, 0), - headersParam("hdr", headersType, 1) {} + : Model::Elem("DeparserImpl"_cs), + packetParam("packet"_cs, P4::P4CoreLibrary::instance().packetOut, 0), + headersParam("hdr"_cs, headersType, 1) {} ::Model::Param_Model packetParam; ::Model::Param_Model headersParam; }; @@ -58,9 +60,9 @@ struct Control_Model : public ::Model::Elem { Control_Model(cstring name, Model::Type_Model headersType, Model::Type_Model metadataType, Model::Type_Model standardMetadataType) : Model::Elem(name), - headersParam("hdr", headersType, 0), - metadataParam("meta", metadataType, 1), - standardMetadataParam("standard_metadata", standardMetadataType, 2) {} + headersParam("hdr"_cs, headersType, 0), + metadataParam("meta"_cs, metadataType, 1), + standardMetadataParam("standard_metadata"_cs, standardMetadataType, 2) {} ::Model::Param_Model headersParam; ::Model::Param_Model metadataParam; ::Model::Param_Model standardMetadataParam; @@ -68,41 +70,44 @@ struct Control_Model : public ::Model::Elem { struct VerifyUpdate_Model : public ::Model::Elem { VerifyUpdate_Model(cstring name, Model::Type_Model headersType) - : Model::Elem(name), headersParam("hdr", headersType, 0) {} + : Model::Elem(name), headersParam("hdr"_cs, headersType, 0) {} ::Model::Param_Model headersParam; }; struct CounterType_Model : public ::Model::Enum_Model { CounterType_Model() - : ::Model::Enum_Model("CounterType"), - packets("packets"), - bytes("bytes"), - both("packets_and_bytes") {} + : ::Model::Enum_Model("CounterType"_cs), + packets("packets"_cs), + bytes("bytes"_cs), + both("packets_and_bytes"_cs) {} ::Model::Elem packets; ::Model::Elem bytes; ::Model::Elem both; }; struct MeterType_Model : public ::Model::Enum_Model { - MeterType_Model() : ::Model::Enum_Model("MeterType"), packets("packets"), bytes("bytes") {} + MeterType_Model() + : ::Model::Enum_Model("MeterType"_cs), packets("packets"_cs), bytes("bytes"_cs) {} ::Model::Elem packets; ::Model::Elem bytes; }; struct ActionProfile_Model : public ::Model::Extern_Model { ActionProfile_Model() - : Extern_Model("action_profile"), sizeType(IR::Type_Bits::get(32)), sizeParam("size") {} + : Extern_Model("action_profile"_cs), + sizeType(IR::Type_Bits::get(32)), + sizeParam("size"_cs) {} const IR::Type *sizeType; ::Model::Elem sizeParam; }; struct ActionSelector_Model : public ::Model::Extern_Model { ActionSelector_Model() - : Extern_Model("action_selector"), + : Extern_Model("action_selector"_cs), sizeType(IR::Type_Bits::get(32)), - sizeParam("size"), + sizeParam("size"_cs), widthType(IR::Type_Bits::get(32)), - algorithmParam("algorithm") {} + algorithmParam("algorithm"_cs) {} const IR::Type *sizeType; ::Model::Elem sizeParam; const IR::Type *widthType; @@ -110,21 +115,21 @@ struct ActionSelector_Model : public ::Model::Extern_Model { }; struct Random_Model : public ::Model::Elem { - Random_Model() : Elem("random"), modify_field_rng_uniform("modify_field_rng_uniform") {} + Random_Model() : Elem("random"_cs), modify_field_rng_uniform("modify_field_rng_uniform"_cs) {} ::Model::Elem modify_field_rng_uniform; }; class Truncate : public Model::Extern_Model { public: - Truncate() : Extern_Model("truncate"), length_type(IR::Type::Bits::get(32)) {} + Truncate() : Extern_Model("truncate"_cs), length_type(IR::Type::Bits::get(32)) {} const IR::Type *length_type; }; struct CounterOrMeter_Model : public ::Model::Extern_Model { explicit CounterOrMeter_Model(cstring name) : Extern_Model(name), - sizeParam("size"), - typeParam("type"), + sizeParam("size"_cs), + typeParam("type"_cs), size_type(IR::Type_Bits::get(32)) {} ::Model::Elem sizeParam; ::Model::Elem typeParam; @@ -135,10 +140,10 @@ struct CounterOrMeter_Model : public ::Model::Extern_Model { struct Register_Model : public ::Model::Extern_Model { Register_Model() - : Extern_Model("register"), - sizeParam("size"), - read("read"), - write("write"), + : Extern_Model("register"_cs), + sizeParam("size"_cs), + read("read"_cs), + write("write"_cs), size_type(IR::Type_Bits::get(32)) {} ::Model::Elem sizeParam; ::Model::Elem read; @@ -147,58 +152,58 @@ struct Register_Model : public ::Model::Extern_Model { }; struct DigestReceiver_Model : public ::Model::Elem { - DigestReceiver_Model() : Elem("digest"), receiverType(IR::Type_Bits::get(32)) {} + DigestReceiver_Model() : Elem("digest"_cs), receiverType(IR::Type_Bits::get(32)) {} const IR::Type *receiverType; }; struct Counter_Model : public CounterOrMeter_Model { - Counter_Model() : CounterOrMeter_Model("counter"), increment("count") {} + Counter_Model() : CounterOrMeter_Model("counter"_cs), increment("count"_cs) {} ::Model::Elem increment; }; struct Meter_Model : public CounterOrMeter_Model { - Meter_Model() : CounterOrMeter_Model("meter"), executeMeter("execute_meter") {} + Meter_Model() : CounterOrMeter_Model("meter"_cs), executeMeter("execute_meter"_cs) {} ::Model::Elem executeMeter; }; struct DirectMeter_Model : public CounterOrMeter_Model { - DirectMeter_Model() : CounterOrMeter_Model("direct_meter"), read("read") {} + DirectMeter_Model() : CounterOrMeter_Model("direct_meter"_cs), read("read"_cs) {} ::Model::Elem read; }; struct DirectCounter_Model : public CounterOrMeter_Model { - DirectCounter_Model() : CounterOrMeter_Model("direct_counter"), count("count") {} + DirectCounter_Model() : CounterOrMeter_Model("direct_counter"_cs), count("count"_cs) {} ::Model::Elem count; }; struct StandardMetadataType_Model : public ::Model::Type_Model { explicit StandardMetadataType_Model(cstring name) : ::Model::Type_Model(name), - dropBit("drop"), - recirculate("recirculate_port"), - egress_spec("egress_spec") {} + dropBit("drop"_cs), + recirculate("recirculate_port"_cs), + egress_spec("egress_spec"_cs) {} ::Model::Elem dropBit; ::Model::Elem recirculate; ::Model::Elem egress_spec; }; struct CloneType_Model : public ::Model::Enum_Model { - CloneType_Model() : ::Model::Enum_Model("CloneType"), i2e("I2E"), e2e("E2E") {} + CloneType_Model() : ::Model::Enum_Model("CloneType"_cs), i2e("I2E"_cs), e2e("E2E"_cs) {} ::Model::Elem i2e; ::Model::Elem e2e; }; struct Algorithm_Model : public ::Model::Enum_Model { Algorithm_Model() - : ::Model::Enum_Model("HashAlgorithm"), - crc32("crc32"), - crc32_custom("crc32_custom"), - crc16("crc16"), - crc16_custom("crc16_custom"), - random("random"), - identity("identity"), - csum16("csum16"), - xor16("xor16") {} + : ::Model::Enum_Model("HashAlgorithm"_cs), + crc32("crc32"_cs), + crc32_custom("crc32_custom"_cs), + crc16("crc16"_cs), + crc16_custom("crc16_custom"_cs), + random("random"_cs), + identity("identity"_cs), + csum16("csum16"_cs), + xor16("xor16"_cs) {} ::Model::Elem crc32; ::Model::Elem crc32_custom; ::Model::Elem crc16; @@ -210,13 +215,13 @@ struct Algorithm_Model : public ::Model::Enum_Model { }; struct Hash_Model : public ::Model::Elem { - Hash_Model() : ::Model::Elem("hash") {} + Hash_Model() : ::Model::Elem("hash"_cs) {} }; struct Cloner_Model : public ::Model::Extern_Model { Cloner_Model() - : Extern_Model("clone"), - clone3("clone_preserving_field_list"), + : Extern_Model("clone"_cs), + clone3("clone_preserving_field_list"_cs), sessionType(IR::Type_Bits::get(32)) {} ::Model::Elem clone3; @@ -226,13 +231,13 @@ struct Cloner_Model : public ::Model::Extern_Model { struct Switch_Model : public ::Model::Elem { Switch_Model() - : Model::Elem("V1Switch"), - parser("p"), - verify("vr"), - ingress("ig"), - egress("eg"), - compute("ck"), - deparser("dep") {} + : Model::Elem("V1Switch"_cs), + parser("p"_cs), + verify("vr"_cs), + ingress("ig"_cs), + egress("eg"_cs), + compute("ck"_cs), + deparser("dep"_cs) {} ::Model::Elem parser; // names of the package arguments ::Model::Elem verify; ::Model::Elem ingress; @@ -243,11 +248,11 @@ struct Switch_Model : public ::Model::Elem { struct TableAttributes_Model { TableAttributes_Model() - : tableImplementation("implementation"), - counters("counters"), - meters("meters"), - size("size"), - supportTimeout("support_timeout") {} + : tableImplementation("implementation"_cs), + counters("counters"_cs), + meters("meters"_cs), + size("size"_cs), + supportTimeout("support_timeout"_cs) {} ::Model::Elem tableImplementation; ::Model::Elem counters; ::Model::Elem meters; @@ -259,44 +264,44 @@ struct TableAttributes_Model { class V1Model : public ::Model::Model { protected: V1Model() - : file("v1model.p4"), - standardMetadata("standard_metadata"), + : file("v1model.p4"_cs), + standardMetadata("standard_metadata"_cs), // The following 2 are not really docmented in the P4-14 spec. - intrinsicMetadata("intrinsic_metadata"), - queueingMetadata("queueing_metadata"), - headersType("headers"), - metadataType("metadata"), - standardMetadataType("standard_metadata_t"), + intrinsicMetadata("intrinsic_metadata"_cs), + queueingMetadata("queueing_metadata"_cs), + headersType("headers"_cs), + metadataType("metadata"_cs), + standardMetadataType("standard_metadata_t"_cs), parser(headersType, metadataType, standardMetadataType), deparser(headersType), - egress("egress", headersType, metadataType, standardMetadataType), - ingress("ingress", headersType, metadataType, standardMetadataType), + egress("egress"_cs, headersType, metadataType, standardMetadataType), + ingress("ingress"_cs, headersType, metadataType, standardMetadataType), sw(), - counterOrMeter("$"), + counterOrMeter("$"_cs), counter(), meter(), random(), action_profile(), action_selector(), clone(), - resubmit("resubmit_preserving_field_list"), + resubmit("resubmit_preserving_field_list"_cs), tableAttributes(), - rangeMatchType("range"), - optionalMatchType("optional"), - selectorMatchType("selector"), - verify("verifyChecksum", headersType), - compute("computeChecksum", headersType), + rangeMatchType("range"_cs), + optionalMatchType("optional"_cs), + selectorMatchType("selector"_cs), + verify("verifyChecksum"_cs, headersType), + compute("computeChecksum"_cs, headersType), digest_receiver(), hash(), algorithm(), registers(), - drop("mark_to_drop"), - recirculate("recirculate_preserving_field_list"), - verify_checksum("verify_checksum"), - update_checksum("update_checksum"), - verify_checksum_with_payload("verify_checksum_with_payload"), - update_checksum_with_payload("update_checksum_with_payload"), - log_msg("log_msg"), + drop("mark_to_drop"_cs), + recirculate("recirculate_preserving_field_list"_cs), + verify_checksum("verify_checksum"_cs), + update_checksum("update_checksum"_cs), + verify_checksum_with_payload("verify_checksum_with_payload"_cs), + update_checksum_with_payload("update_checksum_with_payload"_cs), + log_msg("log_msg"_cs), directMeter(), directCounter() {} diff --git a/frontends/p4/frontend.cpp b/frontends/p4/frontend.cpp index ca978fafe2..69e1e508e3 100644 --- a/frontends/p4/frontend.cpp +++ b/frontends/p4/frontend.cpp @@ -269,7 +269,7 @@ const IR::P4Program *FrontEnd::run(const CompilerOptions &options, const IR::P4P new FrontEndLast(), }); if (options.listFrontendPasses) { - passes.listPasses(*outStream, "\n"); + passes.listPasses(*outStream, cstring::newline); *outStream << std::endl; return nullptr; } diff --git a/frontends/p4/functionsInlining.cpp b/frontends/p4/functionsInlining.cpp index e25a84ef60..ceaf818ae5 100644 --- a/frontends/p4/functionsInlining.cpp +++ b/frontends/p4/functionsInlining.cpp @@ -177,7 +177,7 @@ const IR::Node *FunctionsInliner::inlineBefore(const IR::Node *calleeNode, // evaluate in and inout parameters in order for (auto param : callee->type->parameters->parameters) { auto argument = substitution.lookup(param); - cstring newName = refMap->newName(param->name); + cstring newName = refMap->newName(param->name.name.string_view()); paramRename.emplace(param, newName); if (param->direction == IR::Direction::In || param->direction == IR::Direction::InOut) { auto vardecl = new IR::Declaration_Variable(newName, param->annotations, param->type, diff --git a/frontends/p4/hierarchicalNames.cpp b/frontends/p4/hierarchicalNames.cpp index 5eb26664f5..fd8ad42ea8 100644 --- a/frontends/p4/hierarchicalNames.cpp +++ b/frontends/p4/hierarchicalNames.cpp @@ -27,7 +27,7 @@ const IR::Node *HierarchicalNames::postorder(IR::Annotation *annotation) { cstring name = annotation->getName(); if (name.startsWith(".")) return annotation; - cstring newName = ""; + std::string newName = ""; for (cstring s : stack) newName += s + "."; newName += name; LOG2("Changing " << name << " to " << newName); diff --git a/frontends/p4/inlining.cpp b/frontends/p4/inlining.cpp index 135dd5d54c..43e25a8f52 100644 --- a/frontends/p4/inlining.cpp +++ b/frontends/p4/inlining.cpp @@ -29,6 +29,8 @@ limitations under the License. namespace P4 { +using namespace literals; + namespace { class FindLocationSets : public Inspector { @@ -570,7 +572,7 @@ void GeneralInliner::inline_subst(P4Block *caller, substs->paramSubst.add(param, initializer); } else { // use a temporary variable - cstring newName = refMap->newName(param->name); + cstring newName = refMap->newName(param->name.name.string_view()); auto path = new IR::PathExpression( param->srcInfo, new IR::Path(param->srcInfo, IR::ID(newName))); substs->paramSubst.add(param, new IR::Argument(path)); @@ -705,7 +707,7 @@ class ComputeNewStateNames : public Inspector { } else if (state->name.name == IR::ParserState::accept) { newName = acceptName; } else { - cstring base = prefix + "_" + state->name.name; + std::string base = prefix + "_" + state->name.name; newName = refMap->newName(base); } stateRenameMap->emplace(state->name.name, newName); @@ -850,7 +852,7 @@ const IR::Node *GeneralInliner::preorder(IR::ParserState *state) { callee = substs->rename(refMap, callee); - cstring nextState = refMap->newName(state->name); + cstring nextState = refMap->newName(state->name.name.string_view()); std::map renameMap; ComputeNewStateNames cnn(refMap, callee->name.name, nextState, &renameMap); cnn.setCalledBy(this); @@ -935,6 +937,6 @@ const IR::Node *GeneralInliner::preorder(IR::P4Parser *caller) { } // set of annotations to _not_ propagate during inlining -std::set Inline::noPropagateAnnotations = {"name"}; +std::set Inline::noPropagateAnnotations = {"name"_cs}; } // namespace P4 diff --git a/frontends/p4/localizeActions.cpp b/frontends/p4/localizeActions.cpp index a95bc8be4a..c7ea68eae5 100644 --- a/frontends/p4/localizeActions.cpp +++ b/frontends/p4/localizeActions.cpp @@ -20,6 +20,8 @@ limitations under the License. namespace P4 { +using namespace literals; + namespace { class ParamCloner : public CloneExpressions { @@ -41,7 +43,7 @@ const IR::Node *TagGlobalActions::preorder(IR::P4Action *action) { if (findContext() == nullptr) { auto annos = action->annotations; if (annos == nullptr) annos = IR::Annotations::empty; - cstring name = cstring(".") + action->name; + cstring name = "."_cs + action->name; annos = annos->addAnnotationIfNew(IR::Annotation::nameAnnotation, new IR::StringLiteral(name), false); action->annotations = annos; @@ -64,7 +66,7 @@ bool FindGlobalActionUses::preorder(const IR::PathExpression *path) { auto control = findContext(); if (control != nullptr) { if (repl->getReplacement(action, control) != nullptr) return false; - auto newName = refMap->newName(action->name); + auto newName = refMap->newName(action->name.name.string_view()); ParamCloner cloner; auto replBody = cloner.clone(action->body); auto params = cloner.clone(action->parameters); @@ -147,7 +149,7 @@ bool FindRepeatedActionUses::preorder(const IR::PathExpression *expression) { LOG1(dbp(expression) << " used by " << dbp(actionUser)); auto replacement = repl->getActionUser(action, actionUser); if (replacement == nullptr) { - auto newName = refMap->newName(action->name); + auto newName = refMap->newName(action->name.name.string_view()); ParamCloner cloner; auto replBody = cloner.clone(action->body); auto annos = action->annotations; diff --git a/frontends/p4/moveDeclarations.cpp b/frontends/p4/moveDeclarations.cpp index dfa9148c1f..12d802893f 100644 --- a/frontends/p4/moveDeclarations.cpp +++ b/frontends/p4/moveDeclarations.cpp @@ -110,7 +110,7 @@ const IR::Node *MoveInitializers::preorder(IR::P4Parser *parser) { } } if (someInitializers) { - newStartName = refMap->newName(IR::ParserState::start); + newStartName = refMap->newName(IR::ParserState::start.string_view()); oldStart = parser->states.getDeclaration(IR::ParserState::start)->to(); CHECK_NULL(oldStart); } diff --git a/frontends/p4/parseAnnotations.cpp b/frontends/p4/parseAnnotations.cpp index e4a5e73301..95e36253db 100644 --- a/frontends/p4/parseAnnotations.cpp +++ b/frontends/p4/parseAnnotations.cpp @@ -28,7 +28,7 @@ ParseAnnotations::HandlerMap ParseAnnotations::standardHandlers() { PARSE_EMPTY(IR::Annotation::optionalAnnotation), PARSE_EMPTY(IR::Annotation::pureAnnotation), PARSE_EMPTY(IR::Annotation::noSideEffectsAnnotation), - PARSE_EMPTY("disable_optimization"), + PARSE_EMPTY("disable_optimization"_cs), // string literal argument. PARSE(IR::Annotation::nameAnnotation, StringLiteral), diff --git a/frontends/p4/reassociation.h b/frontends/p4/reassociation.h index 34b3670f75..c4ae466ad7 100644 --- a/frontends/p4/reassociation.h +++ b/frontends/p4/reassociation.h @@ -22,6 +22,8 @@ limitations under the License. namespace P4 { +using namespace literals; + /** Implements a pass that reorders associative operations when beneficial. * For example, (a + c0) + c1 is rewritten as a + (c0 + c1) when cs are constants. */ @@ -41,7 +43,7 @@ class Reassociation final : public Transform { const IR::Node *postorder(IR::BAnd *expr) override { return reassociate(expr); } const IR::Node *postorder(IR::BXor *expr) override { return reassociate(expr); } const IR::BlockStatement *preorder(IR::BlockStatement *bs) override { - if (bs->annotations->getSingle("disable_optimization")) prune(); + if (bs->annotations->getSingle("disable_optimization"_cs)) prune(); return bs; } }; diff --git a/frontends/p4/removeReturns.cpp b/frontends/p4/removeReturns.cpp index d1fde2a731..5b34c68604 100644 --- a/frontends/p4/removeReturns.cpp +++ b/frontends/p4/removeReturns.cpp @@ -30,7 +30,7 @@ const IR::Node *DoRemoveReturns::preorder(IR::P4Action *action) { return action; } LOG3("Processing " << dbp(action)); - cstring var = refMap->newName(variableName); + cstring var = refMap->newName(variableName.string_view()); returnVar = IR::ID(var, nullptr); auto f = new IR::BoolLiteral(false); auto decl = new IR::Declaration_Variable(returnVar, IR::Type_Boolean::get(), f); @@ -67,11 +67,11 @@ const IR::Node *DoRemoveReturns::preorder(IR::Function *function) { bool returnsVal = function->type->returnType != nullptr && !function->type->returnType->is(); - cstring var = refMap->newName(variableName); + cstring var = refMap->newName(variableName.string_view()); returnVar = IR::ID(var, nullptr); IR::Declaration_Variable *retvalDecl = nullptr; if (returnsVal) { - var = refMap->newName(retValName); + var = refMap->newName(retValName.string_view()); returnedValue = IR::ID(var, nullptr); retvalDecl = new IR::Declaration_Variable(returnedValue, function->type->returnType); } @@ -105,7 +105,7 @@ const IR::Node *DoRemoveReturns::preorder(IR::P4Control *control) { return control; } - cstring var = refMap->newName(variableName); + cstring var = refMap->newName(variableName.string_view()); returnVar = IR::ID(var, nullptr); auto f = new IR::BoolLiteral(false); auto decl = new IR::Declaration_Variable(returnVar, IR::Type_Boolean::get(), f); diff --git a/frontends/p4/removeReturns.h b/frontends/p4/removeReturns.h index 70e949f9b0..9cd8e10b6d 100644 --- a/frontends/p4/removeReturns.h +++ b/frontends/p4/removeReturns.h @@ -23,6 +23,7 @@ limitations under the License. #include "ir/ir.h" namespace P4 { +using namespace literals; /** This inspector detects whether an IR tree contains @@ -77,8 +78,8 @@ class DoRemoveReturns : public Transform { } public: - explicit DoRemoveReturns(P4::ReferenceMap *refMap, cstring varName = "hasReturned", - cstring retValName = "retval") + explicit DoRemoveReturns(P4::ReferenceMap *refMap, cstring varName = "hasReturned"_cs, + cstring retValName = "retval"_cs) : refMap(refMap), variableName(varName), retValName(retValName) { visitDagOnce = false; CHECK_NULL(refMap); diff --git a/frontends/p4/reservedWords.cpp b/frontends/p4/reservedWords.cpp index 9078c1924e..3ef6a7286c 100644 --- a/frontends/p4/reservedWords.cpp +++ b/frontends/p4/reservedWords.cpp @@ -18,16 +18,21 @@ limitations under the License. namespace P4 { +using namespace literals; + // Keep this in sync with the lexer -std::set reservedWords = { - "abstract", // experimental - "action", "actions", "apply", "bool", "bit", "const", "control", "default", - "else", "enum", "error", "exit", "extern", "false", "header", "header_union", - "if", "in", "inout", "int", "key", "match_kind", "out", "parser", - "package", "return", "select", "set", "state", "struct", "switch", "table", - "this", // experimental - "transition", "true", "tuple", "typedef", "varbit", "verify", "void", "_", - "NoAction" // core.p4 +const std::set reservedWords = { + "abstract"_cs, // experimental + "action"_cs, "actions"_cs, "apply"_cs, "bool"_cs, "bit"_cs, "const"_cs, + "control"_cs, "default"_cs, "else"_cs, "enum"_cs, "error"_cs, "exit"_cs, + "extern"_cs, "false"_cs, "header"_cs, "header_union"_cs, "if"_cs, "in"_cs, + "inout"_cs, "int"_cs, "key"_cs, "match_kind"_cs, "out"_cs, "parser"_cs, + "package"_cs, "return"_cs, "select"_cs, "set"_cs, "state"_cs, "struct"_cs, + "switch"_cs, "table"_cs, + "this"_cs, // experimental + "transition"_cs, "true"_cs, "tuple"_cs, "typedef"_cs, "varbit"_cs, "verify"_cs, + "void"_cs, "_"_cs, + "NoAction"_cs // core.p4 }; } // namespace P4 diff --git a/frontends/p4/reservedWords.h b/frontends/p4/reservedWords.h index 5c52724cf3..be4a4c85e2 100644 --- a/frontends/p4/reservedWords.h +++ b/frontends/p4/reservedWords.h @@ -23,7 +23,7 @@ limitations under the License. namespace P4 { -extern std::set reservedWords; +extern const std::set reservedWords; } // namespace P4 diff --git a/frontends/p4/simplifyDefUse.cpp b/frontends/p4/simplifyDefUse.cpp index 85eb04d1ee..579d206093 100644 --- a/frontends/p4/simplifyDefUse.cpp +++ b/frontends/p4/simplifyDefUse.cpp @@ -1035,12 +1035,10 @@ class FindUninitialized : public Inspector { // This could happen if we are writing to an array element // with an unknown index. auto type = typeMap->getType(expression, true); - cstring message; - if (type->is()) - message = "%1% may be uninitialized"; - else - message = "%1% may not be completely initialized"; - warn(ErrorType::WARN_UNINITIALIZED_USE, message, expression); + warn(ErrorType::WARN_UNINITIALIZED_USE, + type->is() ? "%1% may be uninitialized" + : "%1% may not be completely initialized", + expression); } hasUses->add(points); diff --git a/frontends/p4/specialize.cpp b/frontends/p4/specialize.cpp index 7200d9fe31..41643c5e34 100644 --- a/frontends/p4/specialize.cpp +++ b/frontends/p4/specialize.cpp @@ -64,7 +64,7 @@ const IR::Argument *SpecializationMap::convertArgument(const IR::Argument *arg, const IR::Parameter *param) { if (arg->expression->is()) { auto cce = arg->expression->to(); - cstring nName = refMap->newName(param->name); + cstring nName = refMap->newName(param->name.name.string_view()); IR::ID id(param->srcInfo, nName, param->name); auto decl = new IR::Declaration_Instance(param->srcInfo, id, cce->constructedType, cce->arguments); @@ -84,7 +84,7 @@ void SpecializationMap::addSpecialization(const IR::ConstructorCallExpression *i auto spec = new SpecializationInfo(invocation, cont, insertion); auto declaration = cont->to(); CHECK_NULL(declaration); - spec->name = refMap->newName(declaration->getName()); + spec->name = refMap->newName(declaration->getName().name.string_view()); auto cc = ConstructorCall::resolve(invocation, refMap, typeMap); auto ccc = cc->to(); CHECK_NULL(ccc); @@ -107,7 +107,7 @@ void SpecializationMap::addSpecialization(const IR::Declaration_Instance *invoca auto spec = new SpecializationInfo(invocation, cont, insertion); auto declaration = cont->to(); CHECK_NULL(declaration); - spec->name = refMap->newName(declaration->getName()); + spec->name = refMap->newName(declaration->getName().name.string_view()); const IR::Type_Name *type; const IR::Vector *typeArgs; if (invocation->type->is()) { diff --git a/frontends/p4/specializeGenericFunctions.h b/frontends/p4/specializeGenericFunctions.h index 76d321aee9..107342dc77 100644 --- a/frontends/p4/specializeGenericFunctions.h +++ b/frontends/p4/specializeGenericFunctions.h @@ -59,7 +59,7 @@ struct FunctionSpecializationMap { void add(const IR::MethodCallExpression *mce, const IR::Function *func, const IR::Node *insert) { - cstring name = refMap->newName(func->name); + cstring name = refMap->newName(func->name.name.string_view()); FunctionSpecialization *fs = new FunctionSpecialization(name, mce, func, insert); map.emplace(mce, fs); } diff --git a/frontends/p4/specializeGenericTypes.cpp b/frontends/p4/specializeGenericTypes.cpp index 109e99d06a..9ae94c8865 100644 --- a/frontends/p4/specializeGenericTypes.cpp +++ b/frontends/p4/specializeGenericTypes.cpp @@ -49,7 +49,7 @@ void TypeSpecializationMap::add(const IR::Type_Specialized *t, const IR::Type_St } } - cstring name = refMap->newName(decl->getName()); + cstring name = refMap->newName(decl->getName().name.string_view()); LOG3("Found to specialize: " << dbp(t) << "(" << t << ") with name " << name << " insert before " << dbp(insertion)); auto argTypes = new IR::Vector(); diff --git a/frontends/p4/staticAssert.h b/frontends/p4/staticAssert.h index 5bc3424e40..6f00a3dd23 100644 --- a/frontends/p4/staticAssert.h +++ b/frontends/p4/staticAssert.h @@ -23,6 +23,8 @@ limitations under the License. namespace P4 { +using namespace literals; + /** * Evaluates static_assert invocations. * A successful assertion is constant-folded to 'true'. @@ -32,6 +34,9 @@ class DoStaticAssert : public Transform { TypeMap *typeMap; bool removeStatement; + // Cannot go static here as cstring is not constexpr + const cstring staticAssertMethodName = "static_assert"_cs; + public: DoStaticAssert(ReferenceMap *refMap, TypeMap *typeMap) : refMap(refMap), typeMap(typeMap), removeStatement(false) { @@ -42,7 +47,7 @@ class DoStaticAssert : public Transform { const IR::Node *postorder(IR::MethodCallExpression *method) override { MethodInstance *mi = MethodInstance::resolve(method, refMap, typeMap); if (auto ef = mi->to()) { - if (ef->method->name == "static_assert") { + if (ef->method->name == staticAssertMethodName) { auto subst = ef->substitution; auto params = subst.getParametersInOrder(); if (!params->moveNext()) { @@ -56,7 +61,7 @@ class DoStaticAssert : public Transform { CHECK_NULL(arg); if (auto bl = arg->expression->to()) { if (!bl->value) { - cstring message = "static_assert failed"; + cstring message = "static_assert failed"_cs; if (params->moveNext()) { param = params->getCurrent(); CHECK_NULL(param); diff --git a/frontends/p4/strengthReduction.h b/frontends/p4/strengthReduction.h index 0acee86a8e..896c188fe2 100644 --- a/frontends/p4/strengthReduction.h +++ b/frontends/p4/strengthReduction.h @@ -25,6 +25,8 @@ limitations under the License. namespace P4 { +using namespace literals; + /** Implements a pass that replaces expensive arithmetic and boolean * operations with cheaper ones -- i.e., strength reduction * @@ -107,7 +109,7 @@ class DoStrengthReduction final : public Transform { const IR::Node *postorder(IR::ArrayIndex *expr) override; const IR::BlockStatement *preorder(IR::BlockStatement *bs) override { - if (bs->annotations->getSingle("disable_optimization")) prune(); + if (bs->annotations->getSingle("disable_optimization"_cs)) prune(); return bs; } }; diff --git a/frontends/p4/symbol_table.cpp b/frontends/p4/symbol_table.cpp index 86fe3351de..5d64425f07 100644 --- a/frontends/p4/symbol_table.cpp +++ b/frontends/p4/symbol_table.cpp @@ -18,12 +18,15 @@ limitations under the License. #include +#include "lib/cstring.h" #include "lib/error.h" #include "lib/exceptions.h" #include "lib/log.h" namespace Util { +using namespace P4::literals; + class NamedSymbol : public ICastable { protected: Util::SourceInfo sourceInfo; @@ -93,7 +96,7 @@ class Namespace : public NamedSymbol { if (it == contents.end()) return nullptr; return it->second; } - cstring toString() const override { return cstring("Namespace ") + getName(); } + cstring toString() const override { return "Namespace "_cs + getName(); } void dump(std::stringstream &into, unsigned indent) const override { std::string s(indent, ' '); into << s; @@ -108,7 +111,7 @@ class Namespace : public NamedSymbol { DECLARE_TYPEINFO(Namespace, NamedSymbol); }; -const Namespace Namespace::empty("", Util::SourceInfo(), false); +const Namespace Namespace::empty(""_cs, Util::SourceInfo(), false); const Namespace *NamedSymbol::symNamespace() const { return &Namespace::empty; } class Object : public NamedSymbol { @@ -116,7 +119,7 @@ class Object : public NamedSymbol { public: Object(cstring name, Util::SourceInfo si) : NamedSymbol(name, si) {} - cstring toString() const override { return cstring("Object ") + getName(); } + cstring toString() const override { return "Object "_cs + getName(); } const Namespace *symNamespace() const override { return typeNamespace; } void setNamespace(const Namespace *ns) { typeNamespace = ns; } @@ -126,7 +129,7 @@ class Object : public NamedSymbol { class SimpleType : public NamedSymbol { public: SimpleType(cstring name, Util::SourceInfo si) : NamedSymbol(name, si) {} - cstring toString() const override { return cstring("SimpleType ") + getName(); } + cstring toString() const override { return "SimpleType "_cs + getName(); } DECLARE_TYPEINFO(SimpleType, NamedSymbol); }; @@ -136,7 +139,7 @@ class ContainerType : public Namespace { public: ContainerType(cstring name, Util::SourceInfo si, bool allowDuplicates) : Namespace(name, si, allowDuplicates) {} - cstring toString() const override { return cstring("ContainerType ") + getName(); } + cstring toString() const override { return "ContainerType "_cs + getName(); } DECLARE_TYPEINFO(ContainerType, Namespace); }; @@ -145,7 +148,7 @@ class ContainerType : public Namespace { ProgramStructure::ProgramStructure() : debug(false), debugStream(nullptr), rootNamespace(nullptr), currentNamespace(nullptr) { - rootNamespace = new Namespace("", Util::SourceInfo(), true); + rootNamespace = new Namespace(cstring::empty, Util::SourceInfo(), true); currentNamespace = rootNamespace; // We use stderr because we want debugging output // to be the same as the bison debugging output. @@ -164,7 +167,7 @@ void ProgramStructure::push(Namespace *ns) { void ProgramStructure::pushNamespace(SourceInfo si, bool allowDuplicates) { // Today we don't have named namespaces - auto ns = new Util::Namespace("", si, allowDuplicates); + auto ns = new Util::Namespace(cstring::empty, si, allowDuplicates); push(ns); } diff --git a/frontends/p4/tableKeyNames.cpp b/frontends/p4/tableKeyNames.cpp index b5db5ac866..6be5f23fcf 100644 --- a/frontends/p4/tableKeyNames.cpp +++ b/frontends/p4/tableKeyNames.cpp @@ -18,6 +18,8 @@ limitations under the License. namespace P4 { +using namespace literals; + void KeyNameGenerator::error(const IR::Expression *expression) { ::error(ErrorType::ERR_EXPECTED, "%1%: Complex key expression requires a @name annotation", expression); @@ -31,6 +33,11 @@ void KeyNameGenerator::postorder(const IR::PathExpression *expression) { namespace { +// The constants are used below. We use `$valid$` to represent `isValid()` calls +// on headers and header unions; this is what P4Runtime expects. +static const cstring isValid = "isValid"_cs; +static const cstring isValidKey = "$valid$"_cs; + /// @return a canonicalized string representation of the given Member /// expression's right-hand side, suitable for use as part of a key name. cstring keyComponentNameForMember(const IR::Member *expression, const P4::TypeMap *typeMap) { @@ -46,7 +53,7 @@ cstring keyComponentNameForMember(const IR::Member *expression, const P4::TypeMa // SynthesizeValidField, which leaves `isValid()` as-is for header unions, // but that's a BMV2-specific thing. if (type->is() || type->is()) - if (expression->member == "isValid") return "$valid$"; + if (expression->member == isValid) return isValidKey; // If this Member represents a field which has an @name annotation, use it. if (type->is()) { @@ -73,7 +80,7 @@ void KeyNameGenerator::postorder(const IR::Member *expression) { // We can generate a name for the overall Member expression only if we were // able to generate a name for its left-hand side. - if (cstring n = getName(expression->expr)) name.emplace(expression, n + "." + fname); + if (cstring n = getName(expression->expr)) name.emplace(expression, n + "."_cs + fname); } void KeyNameGenerator::postorder(const IR::ArrayIndex *expression) { diff --git a/frontends/p4/ternaryBool.cpp b/frontends/p4/ternaryBool.cpp index c7283c8a4a..0aa136fa91 100644 --- a/frontends/p4/ternaryBool.cpp +++ b/frontends/p4/ternaryBool.cpp @@ -16,19 +16,23 @@ limitations under the License. #include "ternaryBool.h" +#include "lib/cstring.h" + namespace P4 { +using namespace literals; + cstring toString(const TernaryBool &c) { switch (c) { case TernaryBool::Yes: - return "Yes"; + return "Yes"_cs; case TernaryBool::No: - return "No"; + return "No"_cs; ; case TernaryBool::Maybe: - return "Maybe"; + return "Maybe"_cs; } - return ""; + return cstring::empty; } } // namespace P4 diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index a6d312571a..96ddcdcb9a 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -173,15 +173,17 @@ bool ToP4::preorder(const IR::P4Program *program) { program->apply(g); builder.append("#define V1MODEL_VERSION "); builder.append(g.version); - builder.appendLine(""); + builder.newline(); } builder.append("#include <"); builder.append(p); - builder.appendLine(">"); + builder.append(">"); + builder.newline(); } else { builder.append("#include \""); builder.append(sourceFile); - builder.appendLine("\""); + builder.append("\""); + builder.newline(); } includesEmitted.emplace(sourceFile); } @@ -872,8 +874,8 @@ bool ToP4::preorder(const IR::SelectExpression *e) { bool ToP4::preorder(const IR::ListExpression *e) { cstring start, end; if (listTerminators.empty()) { - start = "{ "; - end = " }"; + start = "{ "_cs; + end = " }"_cs; } else { start = listTerminators.back().start; end = listTerminators.back().end; diff --git a/frontends/p4/typeChecking/typeChecker.cpp b/frontends/p4/typeChecking/typeChecker.cpp index 0b04393d3f..530570768c 100644 --- a/frontends/p4/typeChecking/typeChecker.cpp +++ b/frontends/p4/typeChecking/typeChecker.cpp @@ -25,6 +25,7 @@ limitations under the License. #include "frontends/p4/methodInstance.h" #include "frontends/p4/toP4/toP4.h" #include "lib/algorithm.h" +#include "lib/cstring.h" #include "lib/log.h" #include "syntacticEquivalence.h" #include "typeConstraints.h" @@ -220,7 +221,7 @@ void TypeInference::addSubstitutions(const TypeVariableSubstitution *tvs) { TypeVariableSubstitution *TypeInference::unifyBase( bool allowCasts, const IR::Node *errorPosition, const IR::Type *destType, - const IR::Type *srcType, cstring errorFormat, + const IR::Type *srcType, std::string_view errorFormat, std::initializer_list errorArgs) { CHECK_NULL(destType); CHECK_NULL(srcType); @@ -232,7 +233,7 @@ TypeVariableSubstitution *TypeInference::unifyBase( constraint = new CanBeImplicitlyCastConstraint(destType, srcType, errorPosition); else constraint = new EqualityConstraint(destType, srcType, errorPosition); - if (!errorFormat.isNullOrEmpty()) constraint->setError(errorFormat, errorArgs); + if (!errorFormat.empty()) constraint->setError(errorFormat, errorArgs); constraints.add(constraint); auto tvs = constraints.solve(); addSubstitutions(tvs); @@ -788,7 +789,7 @@ const IR::Expression *TypeInference::assignment(const IR::Node *errorPosition, if (src != compI->expression) changes = true; vec.push_back(new IR::NamedExpression(fieldI->name, src)); } - if (hasDots) vec.push_back(si->getField("...")); + if (hasDots) vec.push_back(si->getField("..."_cs)); if (!changes) vec = si->components; if (initType->is() || changes) { sourceExpression = new IR::StructExpression(type, type, vec); @@ -979,7 +980,7 @@ std::pair *> TypeInference::che } // will always be bound to Type_Void. - auto rettype = new IR::Type_Var(IR::ID(refMap->newName("R"), "")); + auto rettype = new IR::Type_Var(IR::ID(refMap->newName("R"), ""_cs)); auto callType = new IR::Type_MethodCall(errorPosition->srcInfo, new IR::Vector(), rettype, args); auto tvs = unify(errorPosition, methodType, callType, @@ -1087,7 +1088,7 @@ bool TypeInference::checkAbstractMethods(const IR::Declaration_Instance *inst, } bool rv = true; for (auto &vm : virt) { - if (!vm.second->annotations->getSingle("optional")) { + if (!vm.second->annotations->getSingle("optional"_cs)) { typeError("%1%: %2% abstract method not implemented", inst, vm.second); rv = false; } @@ -3276,7 +3277,7 @@ const IR::Node *TypeInference::postorder(IR::Member *expression) { } if (type->is()) { - cstring typeStr = "structure "; + std::string typeStr = "structure "; if (type->is() || type->is()) { typeStr = ""; if (inMethod && (member == IR::Type_Header::isValid)) { @@ -3380,7 +3381,7 @@ const IR::Node *TypeInference::postorder(IR::Member *expression) { if (!isLeftValue(expression->expr)) typeError("%1%: must be applied to a left-value", expression); auto params = new IR::IndexedVector(); - auto param = new IR::Parameter(IR::ID("count", nullptr), IR::Direction::None, + auto param = new IR::Parameter(IR::ID("count"_cs, nullptr), IR::Direction::None, IR::Type_InfInt::get()); auto tt = new IR::Type_Type(param->type); setType(param->type, tt); @@ -3700,7 +3701,7 @@ const IR::Node *TypeInference::postorder(IR::MethodCallExpression *expression) { // We build a type for the callExpression and unify it with the method expression // Allocate a fresh variable for the return type; it will be hopefully bound in the process. - auto rettype = new IR::Type_Var(IR::ID(refMap->newName("R"), "")); + auto rettype = new IR::Type_Var(IR::ID(refMap->newName("R"), ""_cs)); auto args = new IR::Vector(); bool constArgs = true; for (auto aarg : *expression->arguments) { diff --git a/frontends/p4/typeChecking/typeChecker.h b/frontends/p4/typeChecking/typeChecker.h index c146284283..d620793a67 100644 --- a/frontends/p4/typeChecking/typeChecker.h +++ b/frontends/p4/typeChecking/typeChecker.h @@ -117,20 +117,20 @@ class TypeInference : public Transform { TypeVariableSubstitution *unifyBase(bool allowCasts, const IR::Node *errorPosition, const IR::Type *destType, const IR::Type *srcType, - cstring errorFormat, + std::string_view errorFormat, std::initializer_list errorArgs); /// Unifies two types. Returns nullptr if unification fails. /// Populates the typeMap with values for the type variables. /// This allows an implicit cast from the right type to the left type. TypeVariableSubstitution *unifyCast(const IR::Node *errorPosition, const IR::Type *destType, - const IR::Type *srcType, cstring errorFormat = nullptr, + const IR::Type *srcType, std::string_view errorFormat = {}, std::initializer_list errorArgs = {}) { return unifyBase(true, errorPosition, destType, srcType, errorFormat, errorArgs); } /// Same as above, not allowing casts TypeVariableSubstitution *unify(const IR::Node *errorPosition, const IR::Type *destType, - const IR::Type *srcType, cstring errorFormat = nullptr, + const IR::Type *srcType, std::string_view errorFormat = {}, std::initializer_list errorArgs = {}) { return unifyBase(false, errorPosition, destType, srcType, errorFormat, errorArgs); } diff --git a/frontends/p4/typeChecking/typeConstraints.h b/frontends/p4/typeChecking/typeConstraints.h index dbafff929f..74319040f0 100644 --- a/frontends/p4/typeChecking/typeConstraints.h +++ b/frontends/p4/typeChecking/typeConstraints.h @@ -80,8 +80,8 @@ class TypeConstraint : public IHasDbPrint, public ICastable { std::string localError(Explain *explainer) const; public: - void setError(cstring format, std::initializer_list nodes) { - errFormat = format; + void setError(std::string_view format, std::initializer_list nodes) { + errFormat = cstring(format); errArguments = nodes; } template diff --git a/frontends/p4/typeChecking/typeSubstitution.cpp b/frontends/p4/typeChecking/typeSubstitution.cpp index e6fd139978..75d3009602 100644 --- a/frontends/p4/typeChecking/typeSubstitution.cpp +++ b/frontends/p4/typeChecking/typeSubstitution.cpp @@ -17,14 +17,18 @@ limitations under the License. #include "typeSubstitution.h" #include "frontends/p4/typeMap.h" +#include "lib/cstring.h" #include "typeConstraints.h" #include "typeSubstitutionVisitor.h" namespace P4 { +using namespace literals; + +// FIXME: see if we can not return format string as cstring here cstring TypeVariableSubstitution::compose(const IR::ITypeVar *var, const IR::Type *substitution) { LOG3("Adding " << var << "->" << dbp(substitution) << "=" << substitution << " to substitution"); - if (substitution->is()) return ""; + if (substitution->is()) return cstring::empty; // Type variables that represent Type_InfInt can only be unified to bit<> types // or to other Type_InfInt types. @@ -35,7 +39,7 @@ cstring TypeVariableSubstitution::compose(const IR::ITypeVar *var, const IR::Typ if (!substitution->is() && !substitution->is() && !substitution->is()) { return "'%1%' type can only be unified with 'int', 'bit<>', or 'signed<>' types, " - "not with '%2%'"; + "not with '%2%'"_cs; } } @@ -43,7 +47,7 @@ cstring TypeVariableSubstitution::compose(const IR::ITypeVar *var, const IR::Typ // It is not if var occurs in substitution TypeOccursVisitor occurs(var); substitution->apply(occurs); - if (occurs.occurs) return "'%1%' cannot be replaced with '%2%' which already contains it"; + if (occurs.occurs) return "'%1%' cannot be replaced with '%2%' which already contains it"_cs; // Check to see whether we already have a binding for this variable if (containsKey(var)) { @@ -62,7 +66,7 @@ cstring TypeVariableSubstitution::compose(const IR::ITypeVar *var, const IR::Typ for (auto &bound : binding) { const IR::Type *type = bound.second; const IR::Node *newType = type->apply(visitor); - if (newType == nullptr) return "Could not replace '%1%' with '%2%'"; + if (newType == nullptr) return "Could not replace '%1%' with '%2%'"_cs; if (newType == type) continue; if (bound.first->asType() == newType) { @@ -81,7 +85,7 @@ cstring TypeVariableSubstitution::compose(const IR::ITypeVar *var, const IR::Typ success = setBinding(var, substitution); if (!success) BUG("Failed to insert binding"); } - return ""; + return cstring::empty; } void TypeVariableSubstitution::simpleCompose(const TypeVariableSubstitution *other) { diff --git a/frontends/p4/typeChecking/typeUnification.cpp b/frontends/p4/typeChecking/typeUnification.cpp index a0d11510e0..fcbe426cd9 100644 --- a/frontends/p4/typeChecking/typeUnification.cpp +++ b/frontends/p4/typeChecking/typeUnification.cpp @@ -22,6 +22,8 @@ limitations under the License. namespace P4 { +using namespace literals; + /// Unifies a call with a prototype. bool TypeUnification::unifyCall(const BinaryConstraint *constraint) { // These are canonical types. @@ -408,7 +410,7 @@ bool TypeUnification::unify(const BinaryConstraint *constraint) { } if (stHasDots) { auto dotsType = new IR::Type_UnknownStruct(st->name, *missingFields); - auto dotsField = st->getField("..."); + auto dotsField = st->getField("..."_cs); CHECK_NULL(dotsField); auto partial = new IR::Type_Fragment(dotsType); constraints->add(new EqualityConstraint(dotsField->type, partial, constraint)); diff --git a/frontends/p4/uniqueNames.h b/frontends/p4/uniqueNames.h index 039c4b5511..4c5a5bc5f7 100644 --- a/frontends/p4/uniqueNames.h +++ b/frontends/p4/uniqueNames.h @@ -90,7 +90,7 @@ class FindSymbols : public Inspector { setName("FindSymbols"); } void doDecl(const IR::Declaration *decl) { - cstring newName = refMap->newName(decl->getName()); + cstring newName = refMap->newName(decl->getName().name.string_view()); renameMap->setNewName(decl, newName); } void postorder(const IR::Declaration_Variable *decl) override { doDecl(decl); } @@ -166,7 +166,7 @@ class FindParameters : public Inspector { void doParameters(const IR::ParameterList *pl) { for (auto p : pl->parameters) { - cstring newName = refMap->newName(p->name); + cstring newName = refMap->newName(p->name.name.string_view()); renameMap->setNewName(p, newName); } } diff --git a/frontends/p4/validateParsedProgram.h b/frontends/p4/validateParsedProgram.h index 22f8955869..62d1ac41be 100644 --- a/frontends/p4/validateParsedProgram.h +++ b/frontends/p4/validateParsedProgram.h @@ -22,6 +22,8 @@ limitations under the License. namespace P4 { +using namespace literals; + /** This pass performs some simple semantic checks on the program; since the grammar accepts many programs that are actually illegal, @@ -81,7 +83,7 @@ class ValidateParsedProgram final : public Inspector { control->getConstructorParameters()); } void postorder(const IR::P4Parser *parser) override { - auto start = parser->states.getDeclaration("start"); + auto start = parser->states.getDeclaration(IR::ParserState::start); if (!start) { ::error(ErrorType::ERR_INVALID, "Parser %1% has no 'start' state", parser); } diff --git a/frontends/parsers/p4/p4lexer.ll b/frontends/parsers/p4/p4lexer.ll index 78bad60e35..c4143540b6 100644 --- a/frontends/parsers/p4/p4lexer.ll +++ b/frontends/parsers/p4/p4lexer.ll @@ -204,7 +204,7 @@ using Parser = P4::P4Parser; [A-Za-z_][A-Za-z0-9_]* { BEGIN(driver.saveState); driver.template_args = false; - cstring name = yytext; + cstring name = cstring(yytext); Util::ProgramStructure::SymbolKind kind = driver.structure->lookupIdentifier(name); switch (kind) @@ -229,44 +229,44 @@ using Parser = P4::P4Parser; 0[xX][0-9a-fA-F_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 2, 16, false}; + UnparsedConstant constant{cstring(yytext), 2, 16, false}; return Parser::make_INTEGER(constant, driver.yylloc); } 0[dD][0-9_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 2, 10, false}; + UnparsedConstant constant{cstring(yytext), 2, 10, false}; return Parser::make_INTEGER(constant, driver.yylloc); } 0[oO][0-7_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 2, 8, false}; + UnparsedConstant constant{cstring(yytext), 2, 8, false}; return Parser::make_INTEGER(constant, driver.yylloc); } 0[bB][01_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 2, 2, false}; + UnparsedConstant constant{cstring(yytext), 2, 2, false}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9][0-9_]* { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 0, 10, false}; + UnparsedConstant constant{cstring(yytext), 0, 10, false}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws]0[xX][0-9a-fA-F_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 2, 16, true}; + UnparsedConstant constant{cstring(yytext), 2, 16, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws]0[dD][0-9_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 2, 10, true}; + UnparsedConstant constant{cstring(yytext), 2, 10, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws]0[oO][0-7_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 2, 8, true}; + UnparsedConstant constant{cstring(yytext), 2, 8, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws]0[bB][01_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 2, 2, true}; + UnparsedConstant constant{cstring(yytext), 2, 2, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws][0-9_]+ { BEGIN(driver.saveState); driver.template_args = false; - UnparsedConstant constant{yytext, 0, 10, true}; + UnparsedConstant constant{cstring(yytext), 0, 10, true}; return Parser::make_INTEGER(constant, driver.yylloc); } "&&&" { BEGIN(driver.saveState); driver.template_args = false; return makeToken(MASK); } diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index b3d9857aa3..85e7b9a287 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -94,14 +94,17 @@ typedef const IR::Type ConstType; #define YY_NULLPTR nullptr namespace P4 { +using namespace literals; + class Token { public: int type; cstring text; UnparsedConstant* unparsedConstant; - Token() : Token(0, "", nullptr) { } + Token() : Token(0, cstring::empty, nullptr) { } Token(int type, cstring text) : Token(type, text, nullptr) { } + Token(int type, const char* text) : Token(type, cstring(text), nullptr) { } Token(int type, UnparsedConstant unparsedConstant) : Token(type, unparsedConstant.text, new UnparsedConstant(unparsedConstant)) { } @@ -440,7 +443,7 @@ fragment // TODO: Could this be redesigned to avoid this hack? p4rtControllerType : STRING - { $$ = new IR::StringLiteral(@1, ""); } + { $$ = new IR::StringLiteral(@1, ""_cs); } | BIT l_angle INTEGER r_angle { $$ = new IR::Constant(parseConstantChecked(@3, $3)); } // Legacy syntax; to be removed in P4RT 2.0 @@ -471,28 +474,28 @@ declaration nonTypeName : IDENTIFIER { $$ = new IR::ID(@1, $1); } - | APPLY { $$ = new IR::ID(@1, "apply"); } - | KEY { $$ = new IR::ID(@1, "key"); } - | ACTIONS { $$ = new IR::ID(@1, "actions"); } - | STATE { $$ = new IR::ID(@1, "state"); } - | ENTRIES { $$ = new IR::ID(@1, "entries"); } - | TYPE { $$ = new IR::ID(@1, "type"); } - | PRIORITY { $$ = new IR::ID(@1, "priority"); } + | APPLY { $$ = new IR::ID(@1, "apply"_cs); } + | KEY { $$ = new IR::ID(@1, "key"_cs); } + | ACTIONS { $$ = new IR::ID(@1, "actions"_cs); } + | STATE { $$ = new IR::ID(@1, "state"_cs); } + | ENTRIES { $$ = new IR::ID(@1, "entries"_cs); } + | TYPE { $$ = new IR::ID(@1, "type"_cs); } + | PRIORITY { $$ = new IR::ID(@1, "priority"_cs); } ; name : nonTypeName { $$ = $1; } - | LIST { $$ = new IR::ID(@1, "list"); } + | LIST { $$ = new IR::ID(@1, "list"_cs); } | TYPE_IDENTIFIER { $$ = new IR::ID(@1, $1); } ; nonTableKwName : IDENTIFIER { $$ = new IR::ID(@1, $1); } | TYPE_IDENTIFIER { $$ = new IR::ID(@1, $1); } - | APPLY { $$ = new IR::ID(@1, "apply"); } - | STATE { $$ = new IR::ID(@1, "state"); } - | TYPE { $$ = new IR::ID(@1, "type"); } - | PRIORITY { $$ = new IR::ID(@1, "priority"); } + | APPLY { $$ = new IR::ID(@1, "apply"_cs); } + | STATE { $$ = new IR::ID(@1, "state"_cs); } + | TYPE { $$ = new IR::ID(@1, "type"_cs); } + | PRIORITY { $$ = new IR::ID(@1, "priority"_cs); } ; optCONST @@ -1021,7 +1024,7 @@ specializedType baseType : BOOL { $$ = IR::Type_Boolean::get(@1); } | MATCH_KIND { $$ = IR::Type_MatchKind::get(@1); } - | ERROR { $$ = new IR::Type_Name(@1, new IR::Path(IR::ID(@1, "error"))); } + | ERROR { $$ = new IR::Type_Name(@1, new IR::Path(IR::ID(@1, "error"_cs))); } | BIT { $$ = IR::Type::Bits::get(@1, 1); } | STRING { $$ = IR::Type::String::get(@1); } | INT { $$ = IR::Type_InfInt::get(@1); } @@ -1160,7 +1163,7 @@ specifiedIdentifier errorDeclaration : ERROR "{" identifierList "}" - { $$ = new IR::Type_Error(@1 + @4, IR::ID(@1, "error"), *$3); } + { $$ = new IR::Type_Error(@1 + @4, IR::ID(@1, "error"_cs), *$3); } ; matchKindDeclaration @@ -1239,12 +1242,12 @@ continueStatement directApplication : typeName "." APPLY "(" argumentList ")" ";" { auto method = new IR::Member( - @1 + @3, new IR::TypeNameExpression($1), IR::ID(@3, "apply")); + @1 + @3, new IR::TypeNameExpression($1), IR::ID(@3, "apply"_cs)); auto mce = new IR::MethodCallExpression(@1 + @6, method, $5); $$ = new IR::MethodCallStatement(@1 + @6, mce); } | specializedType "." APPLY "(" argumentList ")" ";" { auto method = new IR::Member( - @1 + @3, new IR::TypeNameExpression($1), IR::ID(@3, "apply")); + @1 + @3, new IR::TypeNameExpression($1), IR::ID(@3, "apply"_cs)); auto mce = new IR::MethodCallExpression(@1 + @6, method, $5); $$ = new IR::MethodCallStatement(@1 + @6, mce); } ; @@ -1369,15 +1372,15 @@ tablePropertyList tableProperty : KEY "=" "{" keyElementList "}" { auto v = new IR::Key(@4, *$4); - auto id = IR::ID(@1, "key"); + auto id = IR::ID(@1, "key"_cs); $$ = new IR::Property( @1 + @5, id, v, false); } | ACTIONS "=" "{" actionList "}" { auto v = new IR::ActionList(@4, *$4); - auto id = IR::ID(@1, "actions"); + auto id = IR::ID(@1, "actions"_cs); $$ = new IR::Property(@1 + @5, id, v, false); } | optAnnotations optCONST ENTRIES "=" "{" entriesList "}" { auto l = new IR::EntriesList(@3, *$6); - auto id = IR::ID(@3+@7, "entries"); + auto id = IR::ID(@3+@7, "entries"_cs); $$ = new IR::Property(@3, id, $1, l, $2.isConst); } | optAnnotations optCONST nonTableKwName "=" initializer ";" { auto v = new IR::ExpressionValue(@5, $5); @@ -1569,7 +1572,7 @@ expression | typeName dot_name %prec DOT { $$ = new IR::Member(@1 + @2, new IR::TypeNameExpression(@1, $1), *$2); } | ERROR "." name - { auto typeName = new IR::Type_Name(@1, new IR::Path(IR::ID(@1, "error"))); + { auto typeName = new IR::Type_Name(@1, new IR::Path(IR::ID(@1, "error"_cs))); $$ = new IR::Member(@1+@3, new IR::TypeNameExpression(@1+@3, typeName), *$3); } | expression dot_name %prec DOT { $$ = new IR::Member(@1 + @2, $1, *$2); } | expression "*" expression { $$ = new IR::Mul(@1 + @3, $1, $3); } @@ -1622,7 +1625,7 @@ nonBraceExpression | typeName dot_name %prec DOT { $$ = new IR::Member(@1 + @2, new IR::TypeNameExpression(@1, $1), *$2); } | ERROR "." name - { auto typeName = new IR::Type_Name(@1, new IR::Path(IR::ID(@1, "error"))); + { auto typeName = new IR::Type_Name(@1, new IR::Path(IR::ID(@1, "error"_cs))); $$ = new IR::Member(@1+@3, new IR::TypeNameExpression(@1+@3, typeName), *$3); } | nonBraceExpression dot_name %prec DOT { $$ = new IR::Member(@1 + @2, $1, *$2); } | nonBraceExpression "*" expression { $$ = new IR::Mul(@1 + @3, $1, $3); } diff --git a/frontends/parsers/parserDriver.cpp b/frontends/parsers/parserDriver.cpp index 01a2f622a3..0734b0c85a 100644 --- a/frontends/parsers/parserDriver.cpp +++ b/frontends/parsers/parserDriver.cpp @@ -88,12 +88,12 @@ void AbstractParserDriver::onReadLineNumber(const char *text) { } void AbstractParserDriver::onReadComment(const char *text, bool lineComment) { - sources->addComment(yylloc, lineComment, text); + sources->addComment(yylloc, lineComment, cstring(text)); } void AbstractParserDriver::onReadFileName(const char *text) { lineDirectiveFile = cstring(text); - sources->mapLine(lineDirectiveFile, lineDirectiveLine); + sources->mapLine(text, lineDirectiveLine); } void AbstractParserDriver::onReadIdentifier(cstring id) { lastIdentifier = id; } diff --git a/frontends/parsers/v1/v1lexer.ll b/frontends/parsers/v1/v1lexer.ll index 564f8bcb0d..7688281df0 100644 --- a/frontends/parsers/v1/v1lexer.ll +++ b/frontends/parsers/v1/v1lexer.ll @@ -70,7 +70,7 @@ using Parser = V1::V1Parser; BEGIN((driver.saveState = PRAGMA_LINE)); return Parser::make_PRAGMA(cstring(V1Lexer::trim(yytext+7)), driver.yylloc); } "@pragma"[ \t]* { BEGIN((driver.saveState = PRAGMA_LINE)); - return Parser::make_PRAGMA("pragma", driver.yylloc); } + return Parser::make_PRAGMA(cstring::literal("pragma"), driver.yylloc); } "action" { BEGIN(driver.saveState); return Parser::make_ACTION(cstring(yytext), driver.yylloc); } @@ -253,65 +253,65 @@ using Parser = V1::V1Parser; return Parser::make_WRITES(cstring(yytext), driver.yylloc); } [A-Za-z_][A-Za-z0-9_]* { BEGIN(driver.saveState); - cstring name = yytext; + cstring name = cstring(yytext); driver.onReadIdentifier(name); return Parser::make_IDENTIFIER(name, driver.yylloc); } 0[xX][0-9a-fA-F_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 16, false}; + UnparsedConstant constant{cstring(yytext), 2, 16, false}; return Parser::make_INTEGER(constant, driver.yylloc); } 0[dD][0-9_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 10, false}; + UnparsedConstant constant{cstring(yytext), 2, 10, false}; return Parser::make_INTEGER(constant, driver.yylloc); } 0[oO][0-7_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 8, false}; + UnparsedConstant constant{cstring(yytext), 2, 8, false}; return Parser::make_INTEGER(constant, driver.yylloc); } 0[bB][01_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 2, false}; + UnparsedConstant constant{cstring(yytext), 2, 2, false}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 0, 10, false}; + UnparsedConstant constant{cstring(yytext), 0, 10, false}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws']0[xX][0-9a-fA-F_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 16, true}; + UnparsedConstant constant{cstring(yytext), 2, 16, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws']0[dD][0-9_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 10, true}; + UnparsedConstant constant{cstring(yytext), 2, 10, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws']0[oO][0-7_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 8, true}; + UnparsedConstant constant{cstring(yytext), 2, 8, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws']0[bB][01_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 2, true}; + UnparsedConstant constant{cstring(yytext), 2, 2, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ws'][0-9]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 0, 10, true}; + UnparsedConstant constant{cstring(yytext), 0, 10, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ \t\r]*['][ \t\r]*0[xX][0-9a-fA-F_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 16, true}; + UnparsedConstant constant{cstring(yytext), 2, 16, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ \t\r]*['][ \t\r]*0[dD][0-9_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 10, true}; + UnparsedConstant constant{cstring(yytext), 2, 10, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ \t\r]*['][ \t\r]*0[oO][0-7_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 8, true}; + UnparsedConstant constant{cstring(yytext), 2, 8, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ \t\r]*['][ \t\r]*0[bB][01_]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 2, 2, true}; + UnparsedConstant constant{cstring(yytext), 2, 2, true}; return Parser::make_INTEGER(constant, driver.yylloc); } [0-9]+[ \t\r]*['][ \t\r]*[0-9]+ { BEGIN(driver.saveState); - UnparsedConstant constant{yytext, 0, 10, true}; + UnparsedConstant constant{cstring(yytext), 0, 10, true}; return Parser::make_INTEGER(constant, driver.yylloc); } -[^ \t\r\n,][^ \t\r\n,]* { return Parser::make_STRING_LITERAL(yytext, driver.yylloc); } +[^ \t\r\n,][^ \t\r\n,]* { return Parser::make_STRING_LITERAL(cstring(yytext), driver.yylloc); } "<<" { BEGIN(driver.saveState); return Parser::make_SHL(driver.yylloc); } ">>" { BEGIN(driver.saveState); return Parser::make_SHR(driver.yylloc); } diff --git a/frontends/parsers/v1/v1parser.ypp b/frontends/parsers/v1/v1parser.ypp index 415050c832..189ed441e4 100644 --- a/frontends/parsers/v1/v1parser.ypp +++ b/frontends/parsers/v1/v1parser.ypp @@ -42,6 +42,8 @@ namespace V1 { class V1Lexer; class V1ParserDriver; +using namespace P4::literals; + struct BBoxType { IR::Vector* methods; IR::NameMap* attribs; @@ -500,7 +502,7 @@ parser_statement_list: /* epsilon */ | parser_statement_list SET_METADATA "(" expression "," expression ")" ";" { ($$=$1)->stmts.push_back(new IR::Primitive(@2+@7, $2, $4, $6)); } | parser_statement_list expression "=" expression ";" - { ($$=$1)->stmts.push_back(new IR::Primitive(@3, "set_metadata", $2, $4)); } + { ($$=$1)->stmts.push_back(new IR::Primitive(@3, "set_metadata"_cs, $2, $4)); } | parser_statement_list RETURN name ";" { ($$=$1)->default_return = IR::ID(@3, $3); } | parser_statement_list RETURN SELECT "(" expression_list ")" "{" case_entry_list "}" @@ -698,7 +700,7 @@ action_statement_list: /* epsilon */ | action_statement_list name "(" opt_expression_list ")" ";" { ($$ = $1)->action.push_back(new IR::Primitive(@2+@5, $2, $4)); } | action_statement_list field_ref "=" expression ";" - { ($$ = $1)->action.push_back(new IR::Primitive(@3, "modify_field", $2, $4)); } + { ($$ = $1)->action.push_back(new IR::Primitive(@3, "modify_field"_cs, $2, $4)); } | action_statement_list field_ref "(" opt_expression_list ")" ";" { ($$ = $1)->action.push_back(new IR::Primitive(@2+@5, $2->member, $2->expr, $4)); } | action_statement_list error ";" @@ -855,7 +857,7 @@ apply_case_list: /* epsilon */ { $$ = new IR::Apply; } } $$ = $1; } | apply_case_list DEFAULT control_statement - { ($$=$1)->actions["default"] = $3; } + { ($$=$1)->actions["default"_cs] = $3; } ; /************/ diff --git a/ir/base.cpp b/ir/base.cpp index 1e5b46d5a2..1511224024 100644 --- a/ir/base.cpp +++ b/ir/base.cpp @@ -37,12 +37,12 @@ cstring Annotation::getName() const { cstring Annotation::getSingleString() const { if (expr.size() != 1) { ::error(ErrorType::ERR_INVALID, "%1%: should contain a string", this); - return ""; + return cstring::empty; } auto str = expr[0]->to(); if (str == nullptr) { ::error(ErrorType::ERR_INVALID, "%1%: should contain a string", this); - return ""; + return cstring::empty; } return str->value; } diff --git a/ir/base.def b/ir/base.def index 02c3f49a31..68500cb97b 100644 --- a/ir/base.def +++ b/ir/base.def @@ -121,7 +121,7 @@ class Type_Unknown : Type_Base { #nodbprint static Type_Unknown get(); static Type_Unknown get(const Util::SourceInfo &si); - toString{ return "Unknown type"; } + toString{ return "Unknown type"_cs; } } /// A statement or a declaration @@ -191,13 +191,13 @@ class Path { toString{ // This is the ORIGINAL name the user used if (absolute) - return cstring(".") + name.toString(); + return "."_cs + name.toString(); return name.toString(); } cstring asString() const { // The CURRENT internal name if (absolute) - return cstring(".") + name; + return "."_cs + name; return name; } dbprint { out << name; } @@ -289,7 +289,7 @@ class Annotation { static const cstring matchAnnotation; /// Match annotation (for value sets). 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. - toString{ return cstring("@") + name; } + toString{ return "@"_cs + name; } validate{ BUG_CHECK(!name.name.isNullOrEmpty(), "empty annotation name"); BUG_CHECK(!(needsParsing && !expr.empty()), @@ -394,7 +394,7 @@ class Argument { dbprint { out << (name.name.isNullOrEmpty() ? "" : name.name + " = ") << expression; } validate { CHECK_NULL(expression); } toString{ - cstring result = ""; + std::string result = ""; if (!name.name.isNullOrEmpty()) result = name.toString() + " = "; return result + expression->toString(); diff --git a/ir/dump.cpp b/ir/dump.cpp index 7510d55cea..e161ea29a4 100644 --- a/ir/dump.cpp +++ b/ir/dump.cpp @@ -25,6 +25,8 @@ limitations under the License. #include "lib/indent.h" #include "lib/source_file.h" +using namespace P4::literals; + namespace { class IRDumper : public Inspector { std::ostream &out; @@ -81,19 +83,19 @@ void dump(const IR::Node *n) { dump(n, ~0U); } void dump(const IR::INode *n, unsigned maxdepth) { dump(std::cout, n->getNode(), maxdepth); } void dump(const IR::INode *n) { dump(n, ~0U); } void dump_notype(const IR::Node *n, unsigned maxdepth) { - n->apply(IRDumper(std::cout, maxdepth, "type", false)); + n->apply(IRDumper(std::cout, maxdepth, "type"_cs, false)); } void dump_notype(const IR::Node *n) { dump_notype(n, ~0U); } void dump_notype(const IR::INode *n, unsigned maxdepth) { - n->getNode()->apply(IRDumper(std::cout, maxdepth, "type", false)); + n->getNode()->apply(IRDumper(std::cout, maxdepth, "type"_cs, false)); } void dump_notype(const IR::INode *n) { dump_notype(n, ~0U); } void dump_src(const IR::Node *n, unsigned maxdepth) { - n->apply(IRDumper(std::cout, maxdepth, "type", true)); + n->apply(IRDumper(std::cout, maxdepth, "type"_cs, true)); } void dump_src(const IR::Node *n) { dump_src(n, ~0U); } void dump_src(const IR::INode *n, unsigned maxdepth) { - n->getNode()->apply(IRDumper(std::cout, maxdepth, "type", true)); + n->getNode()->apply(IRDumper(std::cout, maxdepth, "type"_cs, true)); } void dump_src(const IR::INode *n) { dump_src(n, ~0U); } diff --git a/ir/expression.def b/ir/expression.def index b3559a1fc0..c6b61cd17a 100644 --- a/ir/expression.def +++ b/ir/expression.def @@ -166,17 +166,17 @@ class LOr : Operation_Binary { /// Represents the ... default initializer expression class Dots : Expression { dbprint { out << "..."; } - toString { return "..."; } + toString { return "..."_cs; } } /// Represents the ... default initializer expression /// when used in a StructExpression. class NamedDots : NamedExpression { NamedDots() : NamedExpression("...", new Dots()) {} - NamedDots(Util::SourceInfo srcInfo, Dots dots) : NamedExpression(srcInfo, "...", dots) { CHECK_NULL(dots); } + NamedDots(Util::SourceInfo srcInfo, Dots dots) : NamedExpression(srcInfo, "..."_cs, dots) { CHECK_NULL(dots); } NamedDots(Util::SourceInfo srcInfo) : NamedExpression(srcInfo, "...", new Dots()) {} dbprint { out << "..."; } - toString { return "..."; } + toString { return "..."_cs; } } abstract Literal : Expression, CompileTimeValue {} @@ -283,7 +283,7 @@ class Constant : Literal { class BoolLiteral : Literal { bool value; - toString{ return value ? "true" : "false"; } + toString{ return value ? "true"_cs : "false"_cs; } /// @return a bool literal. Both booleans are interned. static const BoolLiteral *get(bool value, const Util::SourceInfo &si = {}); @@ -292,7 +292,7 @@ class BoolLiteral : Literal { class StringLiteral : Literal { cstring value; validate{ if (value.isNull()) BUG("null StringLiteral"); } - toString{ return cstring("\"") + value.escapeJson() + "\""; } + toString{ return "\""_cs + value.escapeJson() + "\""_cs; } StringLiteral(ID v) : Literal(v.srcInfo), value(v.name) {} #emit operator IR::ID() const { return IR::ID(srcInfo, value); } @@ -327,7 +327,7 @@ class TypeNameExpression : Expression { class Slice : Operation_Ternary { precedence = DBPrint::Prec_Postfix; stringOp = "[:]"; - toString{ return e0->toString() + "[" + e1->toString() + ":" + e2->toString() + "]"; } + toString{ return e0->toString() + "["_cs + e1->toString() + ":"_cs + e2->toString() + "]"_cs; } // After type checking e1 and e2 will be constants unsigned getH() const { return e1->to()->asUnsigned(); } unsigned getL() const { return e2->to()->asUnsigned(); } @@ -349,7 +349,7 @@ class Member : Operation_Unary { int lsb() const; int msb() const; stringOp = "."; - toString{ return expr->toString() + "." + member; } + toString{ return expr->toString() + "."_cs + member; } } class Concat : Operation_Binary { @@ -369,7 +369,7 @@ class ArrayIndex : Operation_Binary { ArrayIndex { if (auto st = left ? left->type->to() : nullptr) type = st->elementType; } - toString{ return left->toString() + "[" + right->toString() + "]"; } + toString{ return left->toString() + "["_cs + right->toString() + "]"_cs; } } class Range : Operation_Binary { @@ -401,7 +401,7 @@ class DefaultExpression : Expression {} // That's why we use a hidden id field to distinguish them. class This : Expression { long id = nextId++; - toString { return "this"; } + toString { return "this"_cs; } private: static long nextId; } @@ -413,7 +413,7 @@ class Cast : Operation_Unary { /// type, and 'type' will only be updated later when type inferencing occurs precedence = DBPrint::Prec_Prefix; stringOp = "(cast)"; - toString{ return "(" + destType->toString() + ")" + expr->toString(); } + toString{ return "("_cs + destType->toString() + ")"_cs + expr->toString(); } validate{ BUG_CHECK(!destType->is(), "%1%: Cannot cast to unknown type", this); } } @@ -436,7 +436,7 @@ class MethodCallExpression : Expression { optional Vector typeArguments = new Vector; optional Vector arguments = new Vector; toString { - cstring str = method->toString() + "("; + std::string str = method->toString() + "("; if (!arguments->empty()) { str += arguments->at(0)->toString(); } @@ -480,7 +480,7 @@ class BaseListExpression : Expression { return components.at(size - 1)->is(); } toString { - cstring str = "{"; + std::string str = "{"; if (!components.empty()) { str += " " + components.at(0)->toString(); } @@ -535,7 +535,7 @@ class StructExpression : Expression { return components.at(size - 1)->is(); } toString { - cstring str = "{"; + std::string str = "{"; if (!components.empty()) { cstring exprStr = components.at(0)->expression->toString(); str += " " + components.at(0)->toString() + " = " + exprStr; diff --git a/ir/id.h b/ir/id.h index 9f66ceb9d1..c1d6ee578a 100644 --- a/ir/id.h +++ b/ir/id.h @@ -37,9 +37,9 @@ struct ID : Util::IHasSourceInfo { ID(Util::SourceInfo si, cstring n) : srcInfo(si), name(n), originalName(n) { if (n.isNullOrEmpty()) BUG("Identifier with no name"); } - ID(const char *n) : ID(Util::SourceInfo(), n) {} // NOLINT(runtime/explicit) - ID(cstring n) : ID(Util::SourceInfo(), n) {} // NOLINT(runtime/explicit) - ID(std::string n) : ID(Util::SourceInfo(), n) {} // NOLINT(runtime/explicit) + ID(const char *n) : ID(Util::SourceInfo(), cstring(n)) {} // NOLINT(runtime/explicit) + ID(cstring n) : ID(Util::SourceInfo(), n) {} // NOLINT(runtime/explicit) + ID(std::string n) : ID(Util::SourceInfo(), n) {} // NOLINT(runtime/explicit) ID(cstring n, cstring old) : ID(Util::SourceInfo(), n, old) {} void dbprint(std::ostream &out) const { out << name; diff --git a/ir/ir.cpp b/ir/ir.cpp index 93cab1f2f6..2322377438 100644 --- a/ir/ir.cpp +++ b/ir/ir.cpp @@ -41,19 +41,19 @@ limitations under the License. namespace IR { -const cstring ParserState::accept = "accept"; -const cstring ParserState::reject = "reject"; -const cstring ParserState::start = "start"; -const cstring ParserState::verify = "verify"; - -const cstring TableProperties::actionsPropertyName = "actions"; -const cstring TableProperties::keyPropertyName = "key"; -const cstring TableProperties::defaultActionPropertyName = "default_action"; -const cstring TableProperties::entriesPropertyName = "entries"; -const cstring TableProperties::sizePropertyName = "size"; -const cstring IApply::applyMethodName = "apply"; -const cstring P4Program::main = "main"; -const cstring Type_Error::error = "error"; +const cstring ParserState::accept = "accept"_cs; +const cstring ParserState::reject = "reject"_cs; +const cstring ParserState::start = "start"_cs; +const cstring ParserState::verify = "verify"_cs; + +const cstring TableProperties::actionsPropertyName = "actions"_cs; +const cstring TableProperties::keyPropertyName = "key"_cs; +const cstring TableProperties::defaultActionPropertyName = "default_action"_cs; +const cstring TableProperties::entriesPropertyName = "entries"_cs; +const cstring TableProperties::sizePropertyName = "size"_cs; +const cstring IApply::applyMethodName = "apply"_cs; +const cstring P4Program::main = "main"_cs; +const cstring Type_Error::error = "error"_cs; long IR::Declaration::nextId = 0; long IR::This::nextId = 0; diff --git a/ir/ir.def b/ir/ir.def index bc24cc504a..ee7cd96552 100644 --- a/ir/ir.def +++ b/ir/ir.def @@ -112,7 +112,7 @@ class P4Parser : Type_Declaration, INestedNamespace, ISimpleNamespace, IApply, I for (auto d : parserLocals) BUG_CHECK(!d->is(), "%1%: state in locals", d); } - toString { return cstring("parser ") + externalName(); } + toString { return "parser "_cs + externalName(); } } class P4Control : Type_Declaration, INestedNamespace, ISimpleNamespace, IApply, IContainer, IAnnotated { @@ -140,7 +140,7 @@ class P4Control : Type_Declaration, INestedNamespace, ISimpleNamespace, IApply, BUG("Name mismatch for %1%: %2% != %3%", this, name, type->name); controlLocals.check_null(); } - toString { return cstring("control ") + externalName(); } + toString { return "control "_cs + externalName(); } } /// A P4-16 action @@ -283,7 +283,7 @@ class Property : Declaration, IAnnotated { class TableProperties : ISimpleNamespace { optional inline IndexedVector properties; - toString{ return "TableProperties(" + Util::toString(properties.size()) + ")"; } + toString{ return "TableProperties("_cs + Util::toString(properties.size()) + ")"_cs; } Util::Enumerator* getDeclarations() const override { return properties.getDeclarations(); } Property getProperty(cstring name) const { @@ -427,14 +427,14 @@ abstract Statement : StatOrDecl { } class ExitStatement : Statement { - toString{ return "exit"; } + toString{ return "exit"_cs; } dbprint { out << "exit"; } } class ReturnStatement : Statement { NullOK Expression expression; - toString{ return cstring("return ") + - (expression != nullptr ? expression->toString() : cstring("")); } + toString{ return "return "_cs + + (expression != nullptr ? expression->toString() : ""_cs); } } class EmptyStatement : Statement { @@ -444,7 +444,7 @@ class EmptyStatement : Statement { class AssignmentStatement : Statement { Expression left; Expression right; - toString{ return left->toString() + " = " + right->toString(); } + toString{ return left->toString() + " = "_cs + right->toString(); } } class IfStatement : Statement { @@ -457,13 +457,13 @@ class IfStatement : Statement { } class BreakStatement : Statement { - toString{ return "break"; } + toString{ return "break"_cs; } dbprint { out << "break"; } visit_children; // in loop-visitor.cpp } class ContinueStatement : Statement { - toString{ return "continue"; } + toString{ return "continue"_cs; } dbprint { out << "continue"; } visit_children; // in loop-visitor.cpp } diff --git a/ir/irutils.cpp b/ir/irutils.cpp index a7f268ab1a..19fbddd5bd 100644 --- a/ir/irutils.cpp +++ b/ir/irutils.cpp @@ -11,6 +11,8 @@ namespace IR { +using namespace P4::literals; + /* ============================================================================================= * Types * ============================================================================================= */ @@ -61,7 +63,7 @@ const IR::Expression *getDefaultValue(const IR::Type *type, const Util::SourceIn return new IR::Member(srcInfo, new IR::TypeNameExpression(te->name), "NoError"); } if (type->is()) { - return new IR::StringLiteral(srcInfo, cstring("")); + return new IR::StringLiteral(srcInfo, ""_cs); } if (type->is()) { if (valueRequired) { diff --git a/ir/loop-visitor.cpp b/ir/loop-visitor.cpp index 261f578e02..79c49215ac 100644 --- a/ir/loop-visitor.cpp +++ b/ir/loop-visitor.cpp @@ -20,20 +20,20 @@ void IR::ForStatement::visit_children(THIS *self, Visitor &v) { v.visit(self->annotations, "annotations"); v.visit(self->init, "init"); if (auto *cfv = v.controlFlowVisitor()) { - ControlFlowVisitor::SaveGlobal outer(*cfv, "-BREAK-", "-CONTINUE-"); + ControlFlowVisitor::SaveGlobal outer(*cfv, "-BREAK-"_cs, "-CONTINUE-"_cs); ControlFlowVisitor *top = nullptr; while (true) { top = &cfv->flow_clone(); cfv->visit(self->condition, "condition", 1000); auto &inloop = cfv->flow_clone(); inloop.visit(self->body, "body"); - inloop.flow_merge_global_from("-CONTINUE-"); + inloop.flow_merge_global_from("-CONTINUE-"_cs); inloop.visit(self->updates, "updates"); inloop.flow_merge(*top); if (inloop == *top) break; cfv->flow_copy(inloop); } - cfv->flow_merge_global_from("-BREAK-"); + cfv->flow_merge_global_from("-BREAK-"_cs); } else { /* Since there is a variable number of init statements (0 or more), we * don't know what the child index of subsequent children will be. So we @@ -57,15 +57,15 @@ void IR::ForInStatement::visit_children(THIS *self, Visitor &v) { v.visit(self->decl, "decl", 0); v.visit(self->collection, "collection", 2); if (auto *cfv = v.controlFlowVisitor()) { - ControlFlowVisitor::SaveGlobal outer(*cfv, "-BREAK-", "-CONTINUE-"); + ControlFlowVisitor::SaveGlobal outer(*cfv, "-BREAK-"_cs, "-CONTINUE-"_cs); ControlFlowVisitor *top = nullptr; do { top = &cfv->flow_clone(); cfv->visit(self->ref, "ref", 1); cfv->visit(self->body, "body", 3); - cfv->flow_merge_global_from("-CONTINUE-"); + cfv->flow_merge_global_from("-CONTINUE-"_cs); } while (*cfv != *top); - cfv->flow_merge_global_from("-BREAK-"); + cfv->flow_merge_global_from("-BREAK-"_cs); } else { v.visit(self->ref, "ref", 1); v.visit(self->body, "body", 3); @@ -76,7 +76,7 @@ void IR::ForInStatement::visit_children(Visitor &v) const { visit_children(this, void IR::BreakStatement::visit_children(Visitor &v) const { if (auto *cfv = v.controlFlowVisitor()) { - cfv->flow_merge_global_to("-BREAK-"); + cfv->flow_merge_global_to("-BREAK-"_cs); cfv->setUnreachable(); } } @@ -86,7 +86,7 @@ void IR::BreakStatement::visit_children(Visitor &v) { void IR::ContinueStatement::visit_children(Visitor &v) const { if (auto *cfv = v.controlFlowVisitor()) { - cfv->flow_merge_global_to("-CONTINUE-"); + cfv->flow_merge_global_to("-CONTINUE-"_cs); cfv->setUnreachable(); } } diff --git a/ir/namemap.h b/ir/namemap.h index 7256000291..8463b8b1f7 100644 --- a/ir/namemap.h +++ b/ir/namemap.h @@ -46,7 +46,7 @@ class NameMap : public Node { auto obj_name(const U *obj) -> decltype(obj->name) { return obj->name; } - cstring obj_name(const void *) { return cstring(0); } + cstring obj_name(const void *) { return nullptr; } public: NameMap() = default; diff --git a/ir/node.cpp b/ir/node.cpp index 13498216f0..da7d521ce0 100644 --- a/ir/node.cpp +++ b/ir/node.cpp @@ -120,18 +120,18 @@ Util::JsonObject *IR::Node::sourceInfoJsonObj() const { // Added source_info for jsonObject when "--fromJSON" flag is used // which parameters are saved in srcInfo fileds(filename, line, column and srcBrief) auto json1 = new Util::JsonObject(); - json1->emplace("filename", srcInfo.filename); - json1->emplace("line", srcInfo.line); - json1->emplace("column", srcInfo.column); - json1->emplace("source_fragment", srcInfo.srcBrief); + json1->emplace("filename"_cs, srcInfo.filename); + json1->emplace("line"_cs, srcInfo.line); + json1->emplace("column"_cs, srcInfo.column); + json1->emplace("source_fragment"_cs, srcInfo.srcBrief); return json1; } } else { auto json = new Util::JsonObject(); - json->emplace("filename", fName); - json->emplace("line", lineNumber); - json->emplace("column", columnNumber); - json->emplace("source_fragment", si.toBriefSourceFragment().escapeJson()); + json->emplace("filename"_cs, fName); + json->emplace("line"_cs, lineNumber); + json->emplace("column"_cs, columnNumber); + json->emplace("source_fragment"_cs, si.toBriefSourceFragment().escapeJson()); return json; } } diff --git a/ir/node.h b/ir/node.h index 5c51bfebf9..93b1ebb1da 100644 --- a/ir/node.h +++ b/ir/node.h @@ -40,6 +40,8 @@ class JsonObject; namespace IR { +using namespace P4::literals; + class Node; class Annotation; // IWYU pragma: keep template @@ -138,8 +140,8 @@ class Node : public virtual INode { const Node *getNode() const final { return this; } Node *getNode() final { return this; } Util::SourceInfo getSourceInfo() const override { return srcInfo; } - cstring node_type_name() const override { return "Node"; } - static cstring static_type_name() { return "Node"; } + cstring node_type_name() const override { return "Node"_cs; } + static cstring static_type_name() { return "Node"_cs; } virtual int num_children() { return 0; } explicit Node(JSONLoader &json); cstring toString() const override { return node_type_name(); } diff --git a/ir/type.cpp b/ir/type.cpp index 6f85230930..f6ed7e4391 100644 --- a/ir/type.cpp +++ b/ir/type.cpp @@ -32,40 +32,40 @@ limitations under the License. namespace IR { -const cstring IR::Type_Stack::next = "next"; -const cstring IR::Type_Stack::last = "last"; -const cstring IR::Type_Stack::arraySize = "size"; -const cstring IR::Type_Stack::lastIndex = "lastIndex"; -const cstring IR::Type_Stack::push_front = "push_front"; -const cstring IR::Type_Stack::pop_front = "pop_front"; -const cstring IR::Type_Header::isValid = "isValid"; -const cstring IR::Type_Header::setValid = "setValid"; -const cstring IR::Type_Header::setInvalid = "setInvalid"; -const cstring IR::Type::minSizeInBits = "minSizeInBits"; -const cstring IR::Type::minSizeInBytes = "minSizeInBytes"; -const cstring IR::Type::maxSizeInBits = "maxSizeInBits"; -const cstring IR::Type::maxSizeInBytes = "maxSizeInBytes"; +const cstring IR::Type_Stack::next = "next"_cs; +const cstring IR::Type_Stack::last = "last"_cs; +const cstring IR::Type_Stack::arraySize = "size"_cs; +const cstring IR::Type_Stack::lastIndex = "lastIndex"_cs; +const cstring IR::Type_Stack::push_front = "push_front"_cs; +const cstring IR::Type_Stack::pop_front = "pop_front"_cs; +const cstring IR::Type_Header::isValid = "isValid"_cs; +const cstring IR::Type_Header::setValid = "setValid"_cs; +const cstring IR::Type_Header::setInvalid = "setInvalid"_cs; +const cstring IR::Type::minSizeInBits = "minSizeInBits"_cs; +const cstring IR::Type::minSizeInBytes = "minSizeInBytes"_cs; +const cstring IR::Type::maxSizeInBits = "maxSizeInBits"_cs; +const cstring IR::Type::maxSizeInBytes = "maxSizeInBytes"_cs; const IR::ID IR::Type_Table::hit = ID("hit"); const IR::ID IR::Type_Table::miss = ID("miss"); const IR::ID IR::Type_Table::action_run = ID("action_run"); -const cstring IR::Annotation::nameAnnotation = "name"; -const cstring IR::Annotation::tableOnlyAnnotation = "tableonly"; -const cstring IR::Annotation::defaultOnlyAnnotation = "defaultonly"; -const cstring IR::Annotation::atomicAnnotation = "atomic"; -const cstring IR::Annotation::hiddenAnnotation = "hidden"; -const cstring IR::Annotation::lengthAnnotation = "length"; -const cstring IR::Annotation::optionalAnnotation = "optional"; -const cstring IR::Annotation::pkginfoAnnotation = "pkginfo"; -const cstring IR::Annotation::deprecatedAnnotation = "deprecated"; -const cstring IR::Annotation::synchronousAnnotation = "synchronous"; -const cstring IR::Annotation::pureAnnotation = "pure"; -const cstring IR::Annotation::noSideEffectsAnnotation = "noSideEffects"; -const cstring IR::Annotation::noWarnAnnotation = "noWarn"; -const cstring IR::Annotation::matchAnnotation = "match"; -const cstring IR::Annotation::fieldListAnnotation = "field_list"; -const cstring IR::Annotation::debugLoggingAnnotation = "__debug"; +const cstring IR::Annotation::nameAnnotation = "name"_cs; +const cstring IR::Annotation::tableOnlyAnnotation = "tableonly"_cs; +const cstring IR::Annotation::defaultOnlyAnnotation = "defaultonly"_cs; +const cstring IR::Annotation::atomicAnnotation = "atomic"_cs; +const cstring IR::Annotation::hiddenAnnotation = "hidden"_cs; +const cstring IR::Annotation::lengthAnnotation = "length"_cs; +const cstring IR::Annotation::optionalAnnotation = "optional"_cs; +const cstring IR::Annotation::pkginfoAnnotation = "pkginfo"_cs; +const cstring IR::Annotation::deprecatedAnnotation = "deprecated"_cs; +const cstring IR::Annotation::synchronousAnnotation = "synchronous"_cs; +const cstring IR::Annotation::pureAnnotation = "pure"_cs; +const cstring IR::Annotation::noSideEffectsAnnotation = "noSideEffects"_cs; +const cstring IR::Annotation::noWarnAnnotation = "noWarn"_cs; +const cstring IR::Annotation::matchAnnotation = "match"_cs; +const cstring IR::Annotation::fieldListAnnotation = "field_list"_cs; +const cstring IR::Annotation::debugLoggingAnnotation = "__debug"_cs; long Type_Declaration::nextId = 0; long Type_InfInt::nextId = 0; diff --git a/ir/type.def b/ir/type.def index e06481cf67..e4a547fd0d 100644 --- a/ir/type.def +++ b/ir/type.def @@ -20,13 +20,13 @@ enum class Direction { inline cstring directionToString(IR::Direction direction) { switch (direction) { case IR::Direction::None: - return ""; + return ""_cs; case IR::Direction::In: - return "in"; + return "in"_cs; case IR::Direction::Out: - return "out"; + return "out"_cs; case IR::Direction::InOut: - return "inout"; + return "inout"_cs; default: BUG("Unhandled case"); } @@ -52,8 +52,9 @@ inline std::ostream& operator<<(std::ostream &out, IR::Direction d) { return out; } +// FIXME: should accept string_view inline bool operator>>(cstring s, IR::Direction &d) { - if (!s || s == "") d = IR::Direction::None; + if (!s || s == cstring::empty) d = IR::Direction::None; else if (s == "in") d = IR::Direction::In; else if (s == "out") d = IR::Direction::Out; else if (s == "inout") d = IR::Direction::InOut; @@ -74,10 +75,10 @@ class Type_Any : Type, ITypeVar { static long nextId; public: long declid = nextId++; - cstring getVarName() const override { return "int_" + Util::toString(declid); } + cstring getVarName() const override { return "int_"_cs + Util::toString(declid); } int getDeclId() const override { return declid; } dbprint { out << "ANYTYPE/" << declid; } - toString { return "ANYTYPE"; } + toString { return "ANYTYPE"_cs; } operator== { return declid == a.declid; } static Type_Any get(); static Type_Any get(const Util::SourceInfo &si); @@ -102,7 +103,7 @@ class Type_Any : Type, ITypeVar { class Type_Fragment : Type { Type type; dbprint { out << "FRAGMENT(" << type << ")"; } - toString { return "FRAGMENT(" + type->toString() + ")"; } + toString { return "FRAGMENT("_cs + type->toString() + ")"_cs; } const Type* getP4Type() const override { return nullptr; } } @@ -115,7 +116,7 @@ class Type_Fragment : Type { /// by type-checking. class Type_Type : Type { Type type; - toString { return "Type(" + type->toString() + ")"; } + toString { return "Type("_cs + type->toString() + ")"_cs; } dbprint { out << "Type(" << type << ")"; } const Type* getP4Type() const override { return type; } validate { BUG_CHECK(!type->is(), "%1%: nested Type_Type", type); } @@ -130,7 +131,7 @@ class Type_Boolean : Type_Base { static Type_Boolean get(); static Type_Boolean get(const Util::SourceInfo &si); int width_bits() const override { return 1; } - toString{ return "bool"; } + toString{ return "bool"_cs; } dbprint { out << "bool"; } } @@ -143,7 +144,7 @@ class Type_State : Type_Base { public: static Type_State get(); static Type_State get(const Util::SourceInfo &si); - toString{ return "state"; } + toString{ return "state"_cs; } dbprint { out << "state"; } } @@ -160,10 +161,10 @@ class Type_Bits : Type_Base { static Type_Bits get(const Util::SourceInfo &si, Expression expression, bool isSigned = false); static Type_Bits get(const Util::SourceInfo &si, int sz, bool isSigned = false); static Type_Bits get(int sz, bool isSigned = false); - cstring baseName() const { return isSigned ? "int" : "bit"; } + cstring baseName() const { return isSigned ? "int"_cs : "bit"_cs; } int width_bits() const override { return size; } - toString{ return baseName() + "<" + Util::toString(size) + ">"; } + toString{ return baseName() + "<"_cs + Util::toString(size) + ">"_cs; } dbprint { out << toString(); } } @@ -179,7 +180,7 @@ class Type_Varbits : Type_Base { static Type_Varbits get(const Util::SourceInfo &si, int size); static Type_Varbits get(int size); static Type_Varbits get(); - toString{ return cstring("varbit<") + Util::toString(size) + ">"; } + toString{ return "varbit<"_cs + Util::toString(size) + ">"_cs; } dbprint { out << "varbit<" << size << ">"; } } @@ -215,7 +216,7 @@ class ParameterList : ISimpleNamespace { IR::IDeclaration getDeclByName(cstring name) const override { return getParameter(name); } void push_back(const Parameter *p) { parameters.push_back(p); } toString { - cstring result = ""; + std::string result = ""; bool first = true; for (auto p : parameters) { if (!first) @@ -255,7 +256,7 @@ class Type_InfInt : Type, ITypeVar { cstring getVarName() const override { return "int_" + Util::toString(declid); } int getDeclId() const override { return declid; } dbprint { out << "int/" << declid; } - toString { return "int"; } + toString { return "int"_cs; } operator== { return declid == a.declid; } static Type_InfInt get(); static Type_InfInt get(const Util::SourceInfo &si); @@ -272,7 +273,7 @@ class Type_Dontcare : Type_Base { void *operator new(size_t size) { return ::operator new(size); } #end public: - toString{ return "_"; } + toString{ return "_"_cs; } static Type_Dontcare get(); static Type_Dontcare get(const Util::SourceInfo &si); dbprint { out << "_"; } @@ -284,7 +285,7 @@ class Type_Void : Type_Base { void *operator new(size_t size) { return ::operator new(size); } #end public: - toString{ return "void"; } + toString{ return "void"_cs; } static Type_Void get(); static Type_Void get(const Util::SourceInfo &si); dbprint { out << "void"; } @@ -296,7 +297,7 @@ class Type_MatchKind : Type_Base { void *operator new(size_t size) { return ::operator new(size); } #end public: - toString{ return "match_kind"; } + toString{ return "match_kind"_cs; } static Type_MatchKind get(); static Type_MatchKind get(const Util::SourceInfo &si); dbprint { out << "match_kind"; } @@ -314,8 +315,8 @@ class TypeParameters : ISimpleNamespace { validate{ parameters.check_null(); } toString { if (parameters.size() == 0) - return ""; - cstring result = "<"; + return ""_cs; + std::string result = "<"; bool first = true; for (auto p : parameters) { if (!first) @@ -385,7 +386,7 @@ abstract Type_StructLike : Type_Declaration, INestedNamespace, ISimpleNamespace, class Type_Struct : Type_StructLike { #nodbprint - toString{ return cstring("struct ") + externalName(); } + toString{ return "struct "_cs + externalName(); } } /// This is the type of a struct-valued expression whose @@ -397,7 +398,7 @@ class Type_UnknownStruct : Type_StructLike { class Type_HeaderUnion : Type_StructLike { #nodbprint - toString{ return cstring("header_union ") + externalName(); } + toString{ return "header_union "_cs + externalName(); } // this makes some assumptions on padding int width_bits() const override { int rv = 0; @@ -419,13 +420,13 @@ class Type_Header : Type_StructLike { static const cstring setInvalid; static const cstring isValid; #nodbprint - toString{ return cstring("header ") + externalName(); } + toString{ return "header "_cs + externalName(); } } class Type_Set : Type { Type elementType; dbprint{ Node::dbprint(out); out << "<" << elementType << ">"; } - toString { return cstring("set<") + elementType->toString() + ">"; } + toString { return "set<"_cs + elementType->toString() + ">"_cs; } const Type* getP4Type() const override { return nullptr; } int width_bits() const override { /// returning the width of the set elements, not the set itself, which doesn't @@ -454,6 +455,7 @@ abstract Type_BaseList : Type, Type_Indexed { } return rv; } cstring asString(const char* name) const { + // FIXME: simplify concatenation std::string result = name; result += "<"; bool first = true; @@ -492,8 +494,7 @@ class Type_P4List : Type { Type elementType; const Type* getP4Type() const override; toString{ - std::string result = "list<" + elementType->toString() + ">"; - return result; + return "list<"_cs + elementType->toString() + ">"_cs; } } @@ -515,7 +516,7 @@ class Type_Package : Type_ArchBlock, IContainer, ISimpleNamespace { ParameterList constructorParams; Type_Method getConstructorMethodType() const override; ParameterList getConstructorParameters() const override { return constructorParams; } - toString{ return cstring("package ") + externalName(); } + toString{ return "package "_cs + externalName(); } Util::Enumerator* getDeclarations() const override { return typeParameters->getDeclarations()->concat(constructorParams->getDeclarations()); } IDeclaration getDeclByName(cstring name) const override { @@ -528,14 +529,14 @@ class Type_Parser : Type_ArchBlock, IApply { ParameterList applyParams; Type_Method getApplyMethodType() const override; ParameterList getApplyParameters() const override { return applyParams; } - toString { return cstring("parser ") + externalName(); } + toString { return "parser "_cs + externalName(); } } class Type_Control : Type_ArchBlock, IApply { ParameterList applyParams; Type_Method getApplyMethodType() const override; ParameterList getApplyParameters() const override { return applyParams; } - toString { return cstring("control ") + externalName(); } + toString { return "control "_cs + externalName(); } } /// A type referred by name @@ -554,8 +555,9 @@ class Type_Name : Type { class Type_Stack : Type_Indexed, Type { Type elementType; Expression size; - toString{ return elementType->toString() + "[" + - (sizeKnown() ? Util::toString(getSize()) : "?") + "]"; } + // FIXME: do not create all these intermediate cstring's + toString{ return elementType->toString() + "["_cs + + (sizeKnown() ? Util::toString(getSize()) : "?"_cs) + "]"_cs; } dbprint{ out << elementType << "[" << size << "]"; } bool sizeKnown() const; size_t getSize() const override; @@ -581,8 +583,8 @@ class Type_Specialized : Type { validate{ arguments->check_null(); } const Type* getP4Type() const override; toString{ - cstring result = baseType->toString() + "<"; - cstring sep = ""; + std::string result = baseType->toString() + "<"; + std::string sep = ""; for (auto t : *arguments) { result += sep + t->toString(); sep = ", "; @@ -609,7 +611,7 @@ class Type_SpecializedCanonical : Type { BUG_CHECK(substituted->is(), "substituted %1% is not generic", substituted); } const Type* getP4Type() const override; - toString{ return baseType->toString() + "<...>"; } + toString{ return baseType->toString() + "<...>"_cs; } } /// A declaration that consists of just an identifier, e.g., an enum member @@ -627,7 +629,7 @@ class Type_String : Type_Base { public: static Type_String get(); static Type_String get(const Util::SourceInfo &si); - toString{ return "string"; } + toString{ return "string"_cs; } } class Type_Enum : Type_Declaration, ISimpleNamespace, IAnnotated { @@ -696,7 +698,7 @@ abstract Type_MethodBase : Type, IMayBeGenericType, ISimpleNamespace { size_t minParameterCount() const; virtual TypeParameters getTypeParameters() const override { return typeParameters; } void dbprint(std::ostream& out) const override; - toString { return ""; } + toString { return ""_cs; } const IR::Type* getP4Type() const override { return nullptr; } Util::Enumerator* getDeclarations() const override { return typeParameters->getDeclarations()->concat(parameters->getDeclarations()); } @@ -734,7 +736,7 @@ class Type_MethodCall : Type { Vector arguments; validate{ typeArguments->check_null(); arguments->check_null(); } const Type* getP4Type() const override { return nullptr; } - toString { return ""; } + toString { return ""_cs; } } /// Actions look a lot like methods in many respects. diff --git a/ir/v1.cpp b/ir/v1.cpp index 394d018eb1..47a66782b2 100644 --- a/ir/v1.cpp +++ b/ir/v1.cpp @@ -47,7 +47,7 @@ cstring IR::NamedCond::unique_name() { static int unique_counter = 0; char buf[16]; snprintf(buf, sizeof(buf), "cond-%d", unique_counter++); - return buf; + return cstring(buf); } struct primitive_info_t { @@ -56,62 +56,64 @@ struct primitive_info_t { unsigned type_match_operands; // bitset -- 1 bit per operand }; +using namespace P4::literals; + static const std::map prim_info = { - {"add", {3, 3, 0x1, 0x7}}, - {"add_header", {1, 1, 0x1, 0x0}}, - {"add_to_field", {2, 2, 0x1, 0x3}}, - {"bit_and", {3, 3, 0x1, 0x7}}, - {"bit_andca", {3, 3, 0x1, 0x7}}, - {"bit_andcb", {3, 3, 0x1, 0x7}}, - {"bit_nand", {3, 3, 0x1, 0x7}}, - {"bit_nor", {3, 3, 0x1, 0x7}}, - {"bit_not", {2, 2, 0x1, 0x3}}, - {"bit_or", {3, 3, 0x1, 0x7}}, - {"bit_orca", {3, 3, 0x1, 0x7}}, - {"bit_orcb", {3, 3, 0x1, 0x7}}, - {"bit_xnor", {3, 3, 0x1, 0x7}}, - {"bit_xor", {3, 3, 0x1, 0x7}}, - {"bypass_egress", {0, 0, 0x0, 0x0}}, - {"clone_egress_pkt_to_egress", {1, 2, 0x0, 0x0}}, - {"clone_ingress_pkt_to_egress", {1, 2, 0x0, 0x0}}, - {"copy_header", {2, 2, 0x1, 0x3}}, - {"copy_to_cpu", {1, 1, 0x0, 0x0}}, - {"count", {2, 2, 0x1, 0x0}}, - {"drop", {0, 0, 0x0, 0x0}}, - {"emit", {1, 1, 0x0, 0x0}}, - {"execute_meter", {3, 4, 0x5, 0x0}}, - {"execute_stateful_alu", {1, 2, 0x0, 0x0}}, - {"execute_stateful_alu_from_hash", {1, 2, 0x0, 0x0}}, - {"execute_stateful_log", {1, 1, 0x0, 0x0}}, - {"exit", {0, 0, 0x0, 0x0}}, - {"extract", {1, 1, 0x1, 0x0}}, - {"funnel_shift_right", {4, 4, 0x1, 0x0}}, - {"generate_digest", {2, 2, 0x0, 0x0}}, - {"invalidate", {1, 1, 0x0, 0x0}}, - {"mark_for_drop", {0, 0, 0x0, 0x0}}, - {"max", {3, 3, 0x1, 0x7}}, - {"min", {3, 3, 0x1, 0x7}}, - {"modify_field", {2, 3, 0x1, 0x7}}, - {"modify_field_conditionally", {3, 3, 0x1, 0x5}}, - {"modify_field_from_rng", {2, 3, 0x1, 0x5}}, - {"modify_field_rng_uniform", {3, 3, 0x1, 0x5}}, - {"modify_field_with_hash_based_offset", {4, 4, 0x1, 0x0}}, - {"no_op", {0, 0, 0x0, 0x0}}, - {"pop", {1, 2, 0x1, 0x0}}, - {"push", {1, 2, 0x1, 0x0}}, - {"recirculate", {1, 1, 0x0, 0x0}}, - {"register_read", {3, 3, 0x1, 0x0}}, - {"register_write", {3, 3, 0x0, 0x0}}, - {"remove_header", {1, 1, 0x1, 0x0}}, - {"resubmit", {0, 1, 0x0, 0x0}}, - {"sample_e2e", {2, 3, 0x0, 0x0}}, - {"set_metadata", {2, 2, 0x1, 0x3}}, - {"shift_left", {3, 3, 0x1, 0x0}}, - {"shift_right", {3, 3, 0x1, 0x0}}, - {"subtract", {3, 3, 0x1, 0x7}}, - {"subtract_from_field", {2, 2, 0x1, 0x3}}, - {"truncate", {1, 1, 0x0, 0x0}}, - {"valid", {1, 1, 0x0, 0x0}}, + {"add"_cs, {3, 3, 0x1, 0x7}}, + {"add_header"_cs, {1, 1, 0x1, 0x0}}, + {"add_to_field"_cs, {2, 2, 0x1, 0x3}}, + {"bit_and"_cs, {3, 3, 0x1, 0x7}}, + {"bit_andca"_cs, {3, 3, 0x1, 0x7}}, + {"bit_andcb"_cs, {3, 3, 0x1, 0x7}}, + {"bit_nand"_cs, {3, 3, 0x1, 0x7}}, + {"bit_nor"_cs, {3, 3, 0x1, 0x7}}, + {"bit_not"_cs, {2, 2, 0x1, 0x3}}, + {"bit_or"_cs, {3, 3, 0x1, 0x7}}, + {"bit_orca"_cs, {3, 3, 0x1, 0x7}}, + {"bit_orcb"_cs, {3, 3, 0x1, 0x7}}, + {"bit_xnor"_cs, {3, 3, 0x1, 0x7}}, + {"bit_xor"_cs, {3, 3, 0x1, 0x7}}, + {"bypass_egress"_cs, {0, 0, 0x0, 0x0}}, + {"clone_egress_pkt_to_egress"_cs, {1, 2, 0x0, 0x0}}, + {"clone_ingress_pkt_to_egress"_cs, {1, 2, 0x0, 0x0}}, + {"copy_header"_cs, {2, 2, 0x1, 0x3}}, + {"copy_to_cpu"_cs, {1, 1, 0x0, 0x0}}, + {"count"_cs, {2, 2, 0x1, 0x0}}, + {"drop"_cs, {0, 0, 0x0, 0x0}}, + {"emit"_cs, {1, 1, 0x0, 0x0}}, + {"execute_meter"_cs, {3, 4, 0x5, 0x0}}, + {"execute_stateful_alu"_cs, {1, 2, 0x0, 0x0}}, + {"execute_stateful_alu_from_hash"_cs, {1, 2, 0x0, 0x0}}, + {"execute_stateful_log"_cs, {1, 1, 0x0, 0x0}}, + {"exit"_cs, {0, 0, 0x0, 0x0}}, + {"extract"_cs, {1, 1, 0x1, 0x0}}, + {"funnel_shift_right"_cs, {4, 4, 0x1, 0x0}}, + {"generate_digest"_cs, {2, 2, 0x0, 0x0}}, + {"invalidate"_cs, {1, 1, 0x0, 0x0}}, + {"mark_for_drop"_cs, {0, 0, 0x0, 0x0}}, + {"max"_cs, {3, 3, 0x1, 0x7}}, + {"min"_cs, {3, 3, 0x1, 0x7}}, + {"modify_field"_cs, {2, 3, 0x1, 0x7}}, + {"modify_field_conditionally"_cs, {3, 3, 0x1, 0x5}}, + {"modify_field_from_rng"_cs, {2, 3, 0x1, 0x5}}, + {"modify_field_rng_uniform"_cs, {3, 3, 0x1, 0x5}}, + {"modify_field_with_hash_based_offset"_cs, {4, 4, 0x1, 0x0}}, + {"no_op"_cs, {0, 0, 0x0, 0x0}}, + {"pop"_cs, {1, 2, 0x1, 0x0}}, + {"push"_cs, {1, 2, 0x1, 0x0}}, + {"recirculate"_cs, {1, 1, 0x0, 0x0}}, + {"register_read"_cs, {3, 3, 0x1, 0x0}}, + {"register_write"_cs, {3, 3, 0x0, 0x0}}, + {"remove_header"_cs, {1, 1, 0x1, 0x0}}, + {"resubmit"_cs, {0, 1, 0x0, 0x0}}, + {"sample_e2e"_cs, {2, 3, 0x0, 0x0}}, + {"set_metadata"_cs, {2, 2, 0x1, 0x3}}, + {"shift_left"_cs, {3, 3, 0x1, 0x0}}, + {"shift_right"_cs, {3, 3, 0x1, 0x0}}, + {"subtract"_cs, {3, 3, 0x1, 0x7}}, + {"subtract_from_field"_cs, {2, 2, 0x1, 0x3}}, + {"truncate"_cs, {1, 1, 0x0, 0x0}}, + {"valid"_cs, {1, 1, 0x0, 0x0}}, }; void IR::Primitive::typecheck() const { @@ -206,6 +208,6 @@ IR::V1Program::V1Program() { new IR::StructField("instance_type", IR::Type::Bits::get(32)), new IR::StructField("parser_status", IR::Type::Bits::get(8)), new IR::StructField("parser_error_location", IR::Type::Bits::get(8))}); - scope.add("standard_metadata_t", new IR::v1HeaderType(standard_metadata_t)); - scope.add("standard_metadata", new IR::Metadata("standard_metadata", standard_metadata_t)); + scope.add("standard_metadata_t"_cs, new IR::v1HeaderType(standard_metadata_t)); + scope.add("standard_metadata"_cs, new IR::Metadata("standard_metadata", standard_metadata_t)); } diff --git a/ir/v1.def b/ir/v1.def index ec3f380e79..4edff84727 100644 --- a/ir/v1.def +++ b/ir/v1.def @@ -43,37 +43,37 @@ inline bool operator>>(cstring s, IR::CounterType &ctr) { #end class Type_Block : Type_Base { - toString { return "block"; } + toString { return "block"_cs; } static Type_Block get(); dbprint { out << "block"; } } class Type_Counter : Type_Base { - toString { return "counter"; } + toString { return "counter"_cs; } static Type_Counter get(); dbprint { out << "counter"; } } class Type_Expression : Type_Base { - toString { return "expression"; } + toString { return "expression"_cs; } static Type_Expression get(); dbprint { out << "expression"; } } class Type_FieldListCalculation : Type_Base { - toString { return "field_list_calculation"; } + toString { return "field_list_calculation"_cs; } static Type_FieldListCalculation get(); dbprint { out << "field_list_calculation"; } } class Type_Meter : Type_Base { - toString { return "meter"; } + toString { return "meter"_cs; } static Type_Meter get(); dbprint { out << "meter"; } } class Type_Register : Type_Base { - toString { return "register"; } + toString { return "register"_cs; } static Type_Register get(); dbprint { out << "register"; } } class Type_AnyTable : Type_Base { - toString { return "table"; } + toString { return "table"_cs; } static Type_AnyTable get(); dbprint { out << "table"; } } @@ -368,9 +368,9 @@ class ActionFunction : IAnnotated { v.visit(annotations, "annotations"); } toString { - return cstring("action ") + name + " {\n" + + return "action "_cs + name + " {\n"_cs + cstring::join(action.begin(), action.end(), ";\n") + - " }"; } + " }"_cs; } } class ActionProfile : Attached { diff --git a/ir/visitor.cpp b/ir/visitor.cpp index c4af4c42eb..043fcf65be 100644 --- a/ir/visitor.cpp +++ b/ir/visitor.cpp @@ -789,10 +789,10 @@ cstring Visitor::demangle(const char *str) { int status; cstring rv; if (char *n = abi::__cxa_demangle(str, 0, 0, &status)) { - rv = n; + rv = cstring(n); free(n); } else { - rv = str; + rv = cstring(str); } return rv; } diff --git a/ir/visitor.h b/ir/visitor.h index 1321312cfa..512eba1670 100644 --- a/ir/visitor.h +++ b/ir/visitor.h @@ -221,7 +221,7 @@ class Visitor { if (!internalName) internalName = demangle(typeid(*this).name()); return internalName.c_str(); } - void setName(const char *name) { internalName = name; } + void setName(const char *name) { internalName = cstring(name); } void print_context() const; // for debugging; can be called from debugger // Context access/search functions. getContext returns the context diff --git a/lib/cstring.cpp b/lib/cstring.cpp index d58ae1bf39..99daa6ed41 100644 --- a/lib/cstring.cpp +++ b/lib/cstring.cpp @@ -16,6 +16,13 @@ limitations under the License. #include "cstring.h" +#if HAVE_LIBGC +#include +#define IF_HAVE_LIBGC(X) X +#else +#define IF_HAVE_LIBGC(X) +#endif /* HAVE_LIBGC */ + #include #include #include @@ -75,8 +82,8 @@ class table_entry { m_inplace_string[length] = '\0'; m_flags = table_entry_flags::inplace; } else { - // Make copy of string elseware - auto copy = new char[length + 1]; + // Make copy of string elsewhere + auto copy = new IF_HAVE_LIBGC((NoGC)) char[length + 1]; std::memcpy(copy, string, length); copy[length] = '\0'; m_string = copy; @@ -185,18 +192,18 @@ size_t cstring::cache_size(size_t &count) { return rv; } -cstring cstring::newline = cstring("\n"); -cstring cstring::empty = cstring(""); +cstring cstring::newline = cstring::literal("\n"); +cstring cstring::empty = cstring::literal(""); -bool cstring::startsWith(const cstring &prefix) const { - if (prefix.isNullOrEmpty()) return true; - return size() >= prefix.size() && memcmp(str, prefix.str, prefix.size()) == 0; +bool cstring::startsWith(std::string_view prefix) const { + if (prefix.empty()) return true; + return size() >= prefix.size() && memcmp(str, prefix.data(), prefix.size()) == 0; } -bool cstring::endsWith(const cstring &suffix) const { - if (suffix.isNullOrEmpty()) return true; +bool cstring::endsWith(std::string_view suffix) const { + if (suffix.empty()) return true; return size() >= suffix.size() && - memcmp(str + size() - suffix.size(), suffix.str, suffix.size()) == 0; + memcmp(str + size() - suffix.size(), suffix.data(), suffix.size()) == 0; } cstring cstring::before(const char *at) const { return substr(0, at - str); } @@ -231,8 +238,8 @@ cstring cstring::replace(cstring search, cstring replace) const { cstring cstring::indent(size_t amount) const { std::string spaces = ""; for (size_t i = 0; i < amount; i++) spaces += " "; - cstring spc = cstring("\n") + spaces; - return cstring(spaces) + replace("\n", spc); + cstring spc = newline + spaces; + return cstring(spaces) + replace(newline, spc); } // See https://stackoverflow.com/a/33799784/4538702 diff --git a/lib/cstring.h b/lib/cstring.h index 60d92d63ce..1a1a089aba 100644 --- a/lib/cstring.h +++ b/lib/cstring.h @@ -70,13 +70,20 @@ limitations under the License. * This is convenient, but in performance-sensitive code it's good to be aware * that mixing the two types of strings can trigger a lot of implicit copies. */ + +class cstring; + +namespace P4::literals { +inline cstring operator""_cs(const char *str, std::size_t len); +} + class cstring { const char *str = nullptr; public: cstring() = default; - // TODO (DanilLutsenko): Enable when initialization with 0 will be eliminated - // cstring(std::nullptr_t) {} // NOLINT(runtime/explicit) + + cstring(std::nullptr_t) {} // NOLINT(runtime/explicit) // Copy and assignment from other kinds of strings @@ -92,7 +99,7 @@ class cstring { // Owner of string is someone else, we do not know size of string. // Do not use if possible, this is linear time operation if string // not exists in table, because the underlying string must be copied. - cstring(const char *string) { // NOLINT(runtime/explicit) + explicit cstring(const char *string) { if (string != nullptr) { construct_from_shared(string, std::strlen(string)); } @@ -151,6 +158,8 @@ class cstring { // string is literal void construct_from_literal(const char *string, std::size_t length); + friend cstring P4::literals::operator""_cs(const char *str, std::size_t len); + public: /// @return a version of the string where all necessary characters /// are properly escaped to make this into a json string (without @@ -166,10 +175,12 @@ class cstring { const char *c_str() const { return str; } operator const char *() const { return str; } - std::string string() const { return std::string(str); } + std::string string() const { return str ? std::string(str) : std::string(""); } explicit operator std::string() const { return string(); } - std::string_view string_view() const { return std::string_view(str); } + std::string_view string_view() const { + return str ? std::string_view(str) : std::string_view(""); + } explicit operator std::string_view() const { return string_view(); } // Size tests. Constant time except for size(), which is linear time. @@ -211,6 +222,8 @@ class cstring { bool operator>(const char *a) const { return str ? !a || strcmp(str, a) > 0 : false; } bool operator>=(cstring a) const { return *this >= a.str; } bool operator>=(const char *a) const { return str ? !a || strcmp(str, a) >= 0 : !a; } + bool operator==(std::string_view a) const { return str ? a.compare(str) == 0 : a.empty(); } + bool operator!=(std::string_view a) const { return str ? a.compare(str) != 0 : !a.empty(); } bool operator==(const std::string &a) const { return *this == a.c_str(); } bool operator!=(const std::string &a) const { return *this != a.c_str(); } @@ -219,8 +232,8 @@ class cstring { bool operator>(const std::string &a) const { return *this > a.c_str(); } bool operator>=(const std::string &a) const { return *this >= a.c_str(); } - bool startsWith(const cstring &prefix) const; - bool endsWith(const cstring &suffix) const; + bool startsWith(std::string_view prefix) const; + bool endsWith(std::string_view suffix) const; // FIXME (DanilLutsenko): We really need mutations for immutable string? // Probably better do transformation in std::string-like containter and @@ -237,7 +250,7 @@ class cstring { cstring before(const char *at) const; cstring substr(size_t start) const { - return (start >= size()) ? "" : substr(start, size() - start); + return (start >= size()) ? cstring::literal("") : substr(start, size() - start); } cstring substr(size_t start, size_t length) const; cstring replace(char find, char replace) const; @@ -384,7 +397,11 @@ namespace P4::literals { /// A user-provided literal suffix to allow creation of cstring from literals: "foo"_cs. /// Note that the C++ standard mandates that all user-defined literal suffixes defined outside of /// the standard library must start with underscore. -inline cstring operator""_cs(const char *str, std::size_t len) { return cstring(str, len); } +inline cstring operator""_cs(const char *str, std::size_t len) { + cstring result; + result.construct_from_literal(str, len); + return result; +} } // namespace P4::literals namespace std { diff --git a/lib/error.h b/lib/error.h index 6fed143305..f5f82b2aae 100644 --- a/lib/error.h +++ b/lib/error.h @@ -176,7 +176,7 @@ template inline void diagnose(DiagnosticAction defaultAction, const char *diagnosticName, const char *format, const char *suffix, Args &&...args) { auto &context = BaseCompileContext::get(); - auto action = context.getDiagnosticAction(diagnosticName, defaultAction); + auto action = context.getDiagnosticAction(cstring(diagnosticName), defaultAction); context.errorReporter().diagnose(action, diagnosticName, format, suffix, std::forward(args)...); } diff --git a/lib/error_catalog.cpp b/lib/error_catalog.cpp index 5e0cb4c0ca..cc8e2f80e6 100644 --- a/lib/error_catalog.cpp +++ b/lib/error_catalog.cpp @@ -17,7 +17,10 @@ limitations under the License. #include "error_catalog.h" #include -#include + +#include "lib/cstring.h" + +using namespace P4::literals; // -------- Errors ------------- const int ErrorType::LEGACY_ERROR = 0; @@ -71,49 +74,49 @@ const int ErrorType::INFO_PROGRESS = 2143; // map from errorCode to ErrorSig std::map ErrorCatalog::errorCatalog = { // Errors - {ErrorType::LEGACY_ERROR, "legacy"}, - {ErrorType::ERR_UNKNOWN, "unknown"}, - {ErrorType::ERR_UNSUPPORTED, "unsupported"}, - {ErrorType::ERR_UNEXPECTED, "unexpected"}, - {ErrorType::ERR_EXPECTED, "expected"}, - {ErrorType::ERR_NOT_FOUND, "not-found"}, - {ErrorType::ERR_INVALID, "invalid"}, - {ErrorType::ERR_EXPRESSION, "expr"}, - {ErrorType::ERR_OVERLIMIT, "overlimit"}, - {ErrorType::ERR_INSUFFICIENT, "insufficient"}, - {ErrorType::ERR_UNINITIALIZED, "uninitialized"}, - {ErrorType::ERR_TYPE_ERROR, "type-error"}, - {ErrorType::ERR_UNSUPPORTED_ON_TARGET, "target-error"}, - {ErrorType::ERR_DUPLICATE, "duplicate"}, - {ErrorType::ERR_IO, "I/O error"}, - {ErrorType::ERR_MODEL, "Target model error"}, - {ErrorType::ERR_RESERVED, "reserved"}, + {ErrorType::LEGACY_ERROR, "legacy"_cs}, + {ErrorType::ERR_UNKNOWN, "unknown"_cs}, + {ErrorType::ERR_UNSUPPORTED, "unsupported"_cs}, + {ErrorType::ERR_UNEXPECTED, "unexpected"_cs}, + {ErrorType::ERR_EXPECTED, "expected"_cs}, + {ErrorType::ERR_NOT_FOUND, "not-found"_cs}, + {ErrorType::ERR_INVALID, "invalid"_cs}, + {ErrorType::ERR_EXPRESSION, "expr"_cs}, + {ErrorType::ERR_OVERLIMIT, "overlimit"_cs}, + {ErrorType::ERR_INSUFFICIENT, "insufficient"_cs}, + {ErrorType::ERR_UNINITIALIZED, "uninitialized"_cs}, + {ErrorType::ERR_TYPE_ERROR, "type-error"_cs}, + {ErrorType::ERR_UNSUPPORTED_ON_TARGET, "target-error"_cs}, + {ErrorType::ERR_DUPLICATE, "duplicate"_cs}, + {ErrorType::ERR_IO, "I/O error"_cs}, + {ErrorType::ERR_MODEL, "Target model error"_cs}, + {ErrorType::ERR_RESERVED, "reserved"_cs}, // Warnings - {ErrorType::LEGACY_WARNING, "legacy"}, - {ErrorType::WARN_FAILED, "failed"}, - {ErrorType::WARN_UNKNOWN, "unknown"}, - {ErrorType::WARN_INVALID, "invalid"}, - {ErrorType::WARN_UNSUPPORTED, "unsupported"}, - {ErrorType::WARN_DEPRECATED, "deprecated"}, - {ErrorType::WARN_UNINITIALIZED, "uninitialized"}, - {ErrorType::WARN_UNUSED, "unused"}, - {ErrorType::WARN_MISSING, "missing"}, - {ErrorType::WARN_ORDERING, "ordering"}, - {ErrorType::WARN_MISMATCH, "mismatch"}, - {ErrorType::WARN_OVERFLOW, "overflow"}, - {ErrorType::WARN_IGNORE_PROPERTY, "ignore-prop"}, - {ErrorType::WARN_TYPE_INFERENCE, "type-inference"}, - {ErrorType::WARN_PARSER_TRANSITION, "parser-transition"}, - {ErrorType::WARN_UNREACHABLE, "parser-transition"}, - {ErrorType::WARN_SHADOWING, "shadow"}, - {ErrorType::WARN_UNINITIALIZED_USE, "uninitialized_use"}, - {ErrorType::WARN_UNINITIALIZED_OUT_PARAM, "uninitialized_out_param"}, - {ErrorType::WARN_IGNORE, "ignore"}, - {ErrorType::WARN_INVALID_HEADER, "invalid_header"}, - {ErrorType::WARN_DUPLICATE_PRIORITIES, "duplicate_priorities"}, - {ErrorType::WARN_ENTRIES_OUT_OF_ORDER, "entries_out_of_priority_order"}, + {ErrorType::LEGACY_WARNING, "legacy"_cs}, + {ErrorType::WARN_FAILED, "failed"_cs}, + {ErrorType::WARN_UNKNOWN, "unknown"_cs}, + {ErrorType::WARN_INVALID, "invalid"_cs}, + {ErrorType::WARN_UNSUPPORTED, "unsupported"_cs}, + {ErrorType::WARN_DEPRECATED, "deprecated"_cs}, + {ErrorType::WARN_UNINITIALIZED, "uninitialized"_cs}, + {ErrorType::WARN_UNUSED, "unused"_cs}, + {ErrorType::WARN_MISSING, "missing"_cs}, + {ErrorType::WARN_ORDERING, "ordering"_cs}, + {ErrorType::WARN_MISMATCH, "mismatch"_cs}, + {ErrorType::WARN_OVERFLOW, "overflow"_cs}, + {ErrorType::WARN_IGNORE_PROPERTY, "ignore-prop"_cs}, + {ErrorType::WARN_TYPE_INFERENCE, "type-inference"_cs}, + {ErrorType::WARN_PARSER_TRANSITION, "parser-transition"_cs}, + {ErrorType::WARN_UNREACHABLE, "parser-transition"_cs}, + {ErrorType::WARN_SHADOWING, "shadow"_cs}, + {ErrorType::WARN_UNINITIALIZED_USE, "uninitialized_use"_cs}, + {ErrorType::WARN_UNINITIALIZED_OUT_PARAM, "uninitialized_out_param"_cs}, + {ErrorType::WARN_IGNORE, "ignore"_cs}, + {ErrorType::WARN_INVALID_HEADER, "invalid_header"_cs}, + {ErrorType::WARN_DUPLICATE_PRIORITIES, "duplicate_priorities"_cs}, + {ErrorType::WARN_ENTRIES_OUT_OF_ORDER, "entries_out_of_priority_order"_cs}, // Info messages - {ErrorType::INFO_INFERRED, "inferred"}, - {ErrorType::INFO_PROGRESS, "progress"}}; + {ErrorType::INFO_INFERRED, "inferred"_cs}, + {ErrorType::INFO_PROGRESS, "progress"_cs}}; diff --git a/lib/error_catalog.h b/lib/error_catalog.h index 122a0539fa..ce8eaa8493 100644 --- a/lib/error_catalog.h +++ b/lib/error_catalog.h @@ -32,6 +32,7 @@ class ErrorType { public: // -------- Errors ------------- // errors as initially defined with a format string + // FIXME: make these constexpr static const int LEGACY_ERROR; static const int ERR_UNKNOWN; // unknown construct (in context) static const int ERR_UNSUPPORTED; // unsupported construct @@ -123,17 +124,20 @@ class ErrorCatalog { /// retrieve the name for errorCode cstring getName(int errorCode) { + using namespace P4::literals; + if (errorCatalog.count(errorCode)) return errorCatalog.at(errorCode); - return "--unknown--"; + return "--unknown--"_cs; } /// return true if the given diagnostic can _only_ be an error; false otherwise - bool isError(cstring name) { + bool isError(std::string_view name) { + cstring lookup(name); // Some diagnostics might be both errors and warning/info // (e.g. "invalid" -> both ERR_INVALID and WARN_INVALID). bool error = false; for (const auto &pair : errorCatalog) { - if (pair.second == name) { + if (pair.second == lookup) { if (pair.first < ErrorType::LEGACY_ERROR || pair.first > ErrorType::ERR_MAX) return false; error = true; diff --git a/lib/error_reporter.h b/lib/error_reporter.h index 1affede912..8fe7151a12 100644 --- a/lib/error_reporter.h +++ b/lib/error_reporter.h @@ -78,9 +78,7 @@ class ErrorReporter { } /// retrieve the format from the error catalog - const char *get_error_name(int errorCode) { - return ErrorCatalog::getCatalog().getName(errorCode); - } + cstring get_error_name(int errorCode) { return ErrorCatalog::getCatalog().getName(errorCode); } public: ErrorReporter() @@ -112,7 +110,7 @@ class ErrorReporter { void diagnose(DiagnosticAction action, const int errorCode, const char *format, const char *suffix, const T *node, Args &&...args) { if (node && !error_reported(errorCode, node->getSourceInfo())) { - const char *name = get_error_name(errorCode); + cstring name = get_error_name(errorCode); auto da = getDiagnosticAction(name, action); if (name) diagnose(da, name, format, suffix, node, std::forward(args)...); @@ -130,7 +128,7 @@ class ErrorReporter { template void diagnose(DiagnosticAction action, const int errorCode, const char *format, const char *suffix, Args &&...args) { - const char *name = get_error_name(errorCode); + cstring name = get_error_name(errorCode); auto da = getDiagnosticAction(name, action); if (name) diagnose(da, name, format, suffix, std::forward(args)...); @@ -245,8 +243,8 @@ class ErrorReporter { } /// Set the action to take for the given diagnostic. - void setDiagnosticAction(cstring diagnostic, DiagnosticAction action) { - diagnosticActions[diagnostic] = action; + void setDiagnosticAction(std::string_view diagnostic, DiagnosticAction action) { + diagnosticActions[cstring(diagnostic)] = action; } /// @return the default diagnostic action for calls to `::warning()`. diff --git a/lib/json.cpp b/lib/json.cpp index 782f5aa7f0..7620ab07c1 100644 --- a/lib/json.cpp +++ b/lib/json.cpp @@ -163,9 +163,9 @@ JsonObject *JsonObject::emplace(cstring label, IJson *value) { auto j = get(label); if (j != nullptr) { cstring s = value->toString(); - throw std::logic_error(cstring("Attempt to add to json object a value " - "for a label which already exists ") + - label.c_str() + " " + s.c_str()); + throw std::logic_error(std::string("Attempt to add to json object a value " + "for a label which already exists ") + + label.string() + " " + s.string()); } ordered_map::emplace(label, value); return this; diff --git a/lib/json.h b/lib/json.h index 93a52994b5..5b0f53c873 100644 --- a/lib/json.h +++ b/lib/json.h @@ -103,7 +103,7 @@ class JsonValue final : public IJson { const Kind tag; const big_int value = 0; - const cstring str = nullptr; + const cstring str = ""_cs; DECLARE_TYPEINFO(JsonValue, IJson); }; diff --git a/lib/nullstream.cpp b/lib/nullstream.cpp index c3f6ee11b8..31a82ebd64 100644 --- a/lib/nullstream.cpp +++ b/lib/nullstream.cpp @@ -18,6 +18,7 @@ limitations under the License. #include // IWYU pragma: keep +// FIXME: this should accept string_view instead std::ostream *openFile(cstring name, bool nullOnError) { if (name.isNullOrEmpty()) { if (nullOnError) return new nullstream(); diff --git a/lib/options.cpp b/lib/options.cpp index 64273abca1..c6451eae75 100644 --- a/lib/options.cpp +++ b/lib/options.cpp @@ -27,15 +27,15 @@ void Util::Options::registerOption(const char *option, const char *argName, if (option[0] != '-') throw std::logic_error(std::string("Expected option to start with -: ") + option); auto o = new Option(); - o->option = option; + o->option = cstring(option); o->argName = argName; o->processor = processor; o->description = description; o->flags = flags; - auto opt = get(options, option); + auto opt = get(options, cstring(option)); if (opt != nullptr) throw std::logic_error(std::string("Option already registered: ") + option); options.emplace(option, o); - optionOrder.push_back(option); + optionOrder.push_back(cstring(option)); } // Process options; return list of remaining options. @@ -57,7 +57,7 @@ std::vector *Util::Options::process(int argc, char *const argv[]) strftime(build_date, 50, "%c", localtime(&now)); buildDate = cstring(build_date); for (int i = 1; i < argc; i++) { - cstring opt = argv[i]; + cstring opt = cstring(argv[i]); const char *arg = nullptr; const Option *option = nullptr; diff --git a/lib/options.h b/lib/options.h index 03ba0adcc4..6437b13943 100644 --- a/lib/options.h +++ b/lib/options.h @@ -82,7 +82,8 @@ class Options { const char *description, // option help message OptionFlags flags = OptionFlags::Default); // additional flags - explicit Options(cstring message) : binaryName(nullptr), message(message), compileCommand("") {} + explicit Options(std::string_view message) + : binaryName(nullptr), message(message), compileCommand("") {} public: /** diff --git a/lib/path.cpp b/lib/path.cpp index c7f01188fa..7bcfc206bf 100644 --- a/lib/path.cpp +++ b/lib/path.cpp @@ -54,7 +54,7 @@ cstring PathName::getExtension() const { const char *dot = filename.str.findlast('.'); if (dot == nullptr) return cstring::empty; - return dot + 1; + return cstring(dot + 1); } PathName PathName::getFolder() const { diff --git a/lib/path.h b/lib/path.h index 969726f3fe..9e28369236 100644 --- a/lib/path.h +++ b/lib/path.h @@ -25,7 +25,10 @@ limitations under the License. #include "cstring.h" namespace Util { +using namespace P4::literals; + // Represents a filename path, e.g., /usr/local/bin/file.exe +// FIXME: Can we replace with std::filesystem? class PathName final { private: static const char pathSeparators[2]; @@ -36,9 +39,9 @@ class PathName final { public: static inline cstring separator() { #ifdef _WIN32 - return "\\"; + return "\\"_cs; #else - return "/"; + return "/"_cs; #endif } diff --git a/lib/sourceCodeBuilder.h b/lib/sourceCodeBuilder.h index f5c9545d7c..10f770fc6d 100644 --- a/lib/sourceCodeBuilder.h +++ b/lib/sourceCodeBuilder.h @@ -53,6 +53,10 @@ class SourceCodeBuilder { } void append(cstring str) { append(str.c_str()); } + void appendLine(const char *str) { + append(str); + newline(); + } void appendLine(cstring str) { append(str); newline(); diff --git a/lib/source_file.cpp b/lib/source_file.cpp index e34e6a00fd..f23c877212 100644 --- a/lib/source_file.cpp +++ b/lib/source_file.cpp @@ -56,7 +56,7 @@ cstring SourceInfo::toString() const { ////////////////////////////////////////////////////////////////////////////////////////// InputSources::InputSources() : sealed(false) { - mapLine(nullptr, 1); // the first line read will be line 1 of stdin + mapLine("", 1); // the first line read will be line 1 of stdin contents.push_back(""); } @@ -137,7 +137,7 @@ void InputSources::appendText(const char *text) { cstring InputSources::getLine(unsigned lineNumber) const { if (lineNumber == 0) { - return ""; + return ""_cs; // BUG("Lines are numbered starting at 1"); // don't throw: this code may be called by exceptions // reporting on elements that have no source position @@ -145,7 +145,7 @@ cstring InputSources::getLine(unsigned lineNumber) const { return contents.at(lineNumber - 1); } -void InputSources::mapLine(cstring file, unsigned originalSourceLineNo) { +void InputSources::mapLine(std::string_view file, unsigned originalSourceLineNo) { if (sealed) BUG("Changing mapping to sealed InputSources"); unsigned lineno = getCurrentLineNumber(); line_file_map.emplace(lineno, SourceFileLine(file, originalSourceLineNo)); @@ -169,7 +169,7 @@ SourceFileLine InputSources::getSourceLine(unsigned line) const { // So we have to subtract one to get the real line number. const auto nominalLine = line - it->first + it->second.sourceLine; const auto realLine = nominalLine > 0 ? nominalLine - 1 : 0; - return SourceFileLine(it->second.fileName, realLine); + return SourceFileLine(it->second.fileName.string_view(), realLine); } unsigned InputSources::getCurrentLineNumber() const { return contents.size(); } @@ -204,7 +204,7 @@ cstring carets(cstring source, unsigned start, unsigned end) { } cstring InputSources::getSourceFragment(const SourceInfo &position, bool useMarker) const { - if (!position.isValid()) return ""; + if (!position.isValid()) return ""_cs; // If the position spans multiple lines, truncate to just the first line if (position.getEnd().getLineNumber() > position.getStart().getLineNumber()) @@ -213,7 +213,7 @@ cstring InputSources::getSourceFragment(const SourceInfo &position, bool useMark cstring result = getLine(position.getStart().getLineNumber()); // Normally result has a newline, but if not // then we have to add a newline - cstring toadd = ""; + cstring toadd = ""_cs; if (result.find('\n') == nullptr) toadd = cstring::newline; cstring marker = carets(result, position.getStart().getColumnNumber(), position.getEnd().getColumnNumber()); @@ -225,12 +225,12 @@ cstring InputSources::getSourceFragment(const SourceInfo &position, bool useMark } cstring InputSources::getBriefSourceFragment(const SourceInfo &position) const { - if (!position.isValid()) return ""; + if (!position.isValid()) return ""_cs; cstring result = getLine(position.getStart().getLineNumber()); unsigned int start = position.getStart().getColumnNumber(); unsigned int end; - cstring toadd = ""; + cstring toadd = ""_cs; // If the position spans multiple lines, truncate to just the first line if (position.getEnd().getLineNumber() > position.getStart().getLineNumber()) { @@ -239,7 +239,7 @@ cstring InputSources::getBriefSourceFragment(const SourceInfo &position) const { if (result.find('\n') != nullptr) { --end; } - toadd = " ..."; + toadd = " ..."_cs; } else { end = position.getEnd().getColumnNumber(); } @@ -247,7 +247,7 @@ cstring InputSources::getBriefSourceFragment(const SourceInfo &position) const { // Adding escape character in front of '"' character to properly store // quote marks as part of JSON properties, they must be escaped. if (result.find('"') != nullptr) { - cstring out = result.replace("\"", "\\\""); + cstring out = result.replace("\""_cs, "\\\""_cs); return out.substr(0, out.size() - 1); } @@ -265,17 +265,17 @@ cstring InputSources::toDebugString() const { /////////////////////////////////////////////////// cstring SourceInfo::toSourceFragment(bool useMarker) const { - if (!isValid()) return ""; + if (!isValid()) return ""_cs; return sources->getSourceFragment(*this, useMarker); } cstring SourceInfo::toBriefSourceFragment() const { - if (!isValid()) return ""; + if (!isValid()) return ""_cs; return sources->getBriefSourceFragment(*this); } cstring SourceInfo::toPositionString() const { - if (!isValid()) return ""; + if (!isValid()) return ""_cs; SourceFileLine position = sources->getSourceLine(start.getLineNumber()); return position.toString(); } @@ -288,7 +288,7 @@ cstring SourceInfo::toSourcePositionData(unsigned *outLineNumber, unsigned *outC if (outColumnNumber != nullptr) { *outColumnNumber = start.getColumnNumber(); } - return position.fileName.c_str(); + return position.fileName; } SourceFileLine SourceInfo::toPosition() const { diff --git a/lib/source_file.h b/lib/source_file.h index 8d26306b0d..198db41c13 100644 --- a/lib/source_file.h +++ b/lib/source_file.h @@ -37,6 +37,8 @@ class UtilSourceFile; } namespace Util { +using namespace P4::literals; + struct SourceFileLine; /** A character position within some InputSources: a pair of @@ -119,10 +121,10 @@ SourceInfo can also be "invalid" */ class SourceInfo final { public: - cstring filename = ""; + cstring filename = ""_cs; int line = -1; int column = -1; - cstring srcBrief = ""; + cstring srcBrief = ""_cs; SourceInfo(cstring filename, int line, int column, cstring srcBrief) { this->filename = filename; this->line = line; @@ -220,7 +222,7 @@ struct SourceFileLine { cstring fileName; unsigned sourceLine; - SourceFileLine(cstring file, unsigned line) : fileName(file), sourceLine(line) {} + SourceFileLine(std::string_view file, unsigned line) : fileName(file), sourceLine(line) {} cstring toString() const; }; @@ -282,7 +284,7 @@ class InputSources final { /** Map the next line in the file to the line with number 'originalSourceLine' from file 'file'. */ - void mapLine(cstring file, unsigned originalSourceLineNo); + void mapLine(std::string_view file, unsigned originalSourceLineNo); /** The following return a nice (multi-line, newline-terminated) diff --git a/midend/actionSynthesis.cpp b/midend/actionSynthesis.cpp index 502c40f995..1138988ccf 100644 --- a/midend/actionSynthesis.cpp +++ b/midend/actionSynthesis.cpp @@ -21,6 +21,8 @@ limitations under the License. namespace P4 { +using namespace literals; + const IR::Node *DoMoveActionsToTables::postorder(IR::MethodCallStatement *statement) { auto mi = MethodInstance::resolve(statement, refMap, typeMap); if (!mi->is()) return statement; @@ -66,7 +68,7 @@ const IR::Node *DoMoveActionsToTables::postorder(IR::MethodCallStatement *statem // List of table properties auto props = new IR::TableProperties({prop, defprop}); // Synthesize a new table - cstring tblName = IR::ID(refMap->newName(cstring("tbl_") + ac->action->name.name), nullptr); + cstring tblName = IR::ID(refMap->newName("tbl_"_cs + ac->action->name.name), nullptr); auto annos = new IR::Annotations(); annos->add(new IR::Annotation(IR::Annotation::hiddenAnnotation, {})); @@ -167,9 +169,9 @@ const IR::Node *DoSynthesizeActions::preorder(IR::BlockStatement *statement) { } static cstring createName(const Util::SourceInfo &si) { - if (!si.isValid()) return "act"; + if (!si.isValid()) return "act"_cs; auto pos = si.toPosition(); - if (pos.fileName.isNullOrEmpty() || pos.sourceLine == 0) return "act"; + if (pos.fileName.isNullOrEmpty() || pos.sourceLine == 0) return "act"_cs; std::string name; const char *p = pos.fileName.findlast('/'); p = p ? p + 1 : pos.fileName.c_str(); @@ -178,14 +180,14 @@ static cstring createName(const Util::SourceInfo &si) { if (isalnum(*p) || *p == '_') name += *p; ++p; } - if (name.empty()) return "act"; + if (name.empty()) return "act"_cs; if (isdigit(name.back())) name += 'l'; return name + std::to_string(pos.sourceLine); } const IR::Statement *DoSynthesizeActions::createAction(const IR::Statement *toAdd) { changes = true; - auto name = refMap->newName(createName(toAdd->srcInfo)); + cstring name = refMap->newName(createName(toAdd->srcInfo).string_view()); const IR::BlockStatement *body; if (toAdd->is()) { body = toAdd->to(); diff --git a/midend/def_use.cpp b/midend/def_use.cpp index b941a9ca2f..9ce1728d1b 100644 --- a/midend/def_use.cpp +++ b/midend/def_use.cpp @@ -20,6 +20,8 @@ limitations under the License. namespace P4 { +using namespace literals; + const ordered_set ComputeDefUse::empty = {}; void ComputeDefUse::flow_merge(Visitor &a_) { @@ -143,7 +145,8 @@ class ComputeDefUse::SetupJoinPoints : public ControlFlowVisitor::SetupJoinPoint IndentCtl::TempIndent indent; LOG6("SetupJoinPoints(P4Parser " << p->name << ")" << indent); LOG8(" " << Log::indent << Log::indent << *p << Log::unindent << Log::unindent); - if (auto start = p->states.getDeclaration("start")) visit(start, "start"); + if (auto start = p->states.getDeclaration("start"_cs)) + visit(start, "start"); return false; } bool preorder(const IR::P4Control *) override { return false; } @@ -317,7 +320,7 @@ bool ComputeDefUse::preorder(const IR::P4Parser *p) { if (a->direction == IR::Direction::In || a->direction == IR::Direction::InOut) def_info[a].defs.insert(getLoc(a)); state = NORMAL; - if (auto start = p->states.getDeclaration("start")) { + if (auto start = p->states.getDeclaration("start"_cs)) { visit(start, "start"); } else { BUG("No start state in %s", p); diff --git a/midend/eliminateTuples.cpp b/midend/eliminateTuples.cpp index 8c4ecb4b39..6a15239122 100644 --- a/midend/eliminateTuples.cpp +++ b/midend/eliminateTuples.cpp @@ -4,6 +4,8 @@ namespace P4 { +using namespace literals; + const IR::Type *ReplacementMap::convertType(const IR::Type *type) { auto it = replacement.find(type); if (it != replacement.end()) return it->second; @@ -31,7 +33,7 @@ const IR::Type *ReplacementMap::convertType(const IR::Type *type) { size_t index = 0; for (auto t : bl->components) { auto ftype = convertType(t); - auto fname = cstring("f") + cstring(std::to_string(index)); + auto fname = "f"_cs + Util::toString(index); auto field = new IR::StructField(IR::ID(fname), ftype->getP4Type()); fields.push_back(field); index++; @@ -92,7 +94,7 @@ const IR::Node *DoReplaceTuples::postorder(IR::ArrayIndex *expression) { if (type->is()) { auto cst = expression->right->to(); BUG_CHECK(cst, "%1%: Expected a constant", expression->right); - cstring field = cstring("f") + Util::toString(cst->asInt()); + cstring field = "f"_cs + Util::toString(cst->asInt()); auto src = expression->right->srcInfo; return new IR::Member(src, expression->left, IR::ID(src, field)); } diff --git a/midend/expr_uses.h b/midend/expr_uses.h index 9205683820..25908667a4 100644 --- a/midend/expr_uses.h +++ b/midend/expr_uses.h @@ -29,7 +29,7 @@ class exprUses : public Inspector { const char *search_tail = nullptr; // pointer into look_for for partial match bool result = false; bool preorder(const IR::Path *p) override { - if (look_for.startsWith(p->name)) { + if (look_for.startsWith(p->name.name.string_view())) { search_tail = look_for.c_str() + p->name.name.size(); if (*search_tail == 0 || *search_tail == '.' || *search_tail == '[') result = true; } @@ -44,7 +44,7 @@ class exprUses : public Inspector { void postorder(const IR::Member *m) override { if (result && search_tail && *search_tail) { if (*search_tail == '.') search_tail++; - if (cstring(search_tail).startsWith(m->member)) { + if (cstring(search_tail).startsWith(m->member.name.string_view())) { search_tail += m->member.name.size(); if (*search_tail == 0 || *search_tail == '.' || *search_tail == '[') return; } diff --git a/midend/flattenHeaders.cpp b/midend/flattenHeaders.cpp index 4f386182c4..e67fdda2fe 100644 --- a/midend/flattenHeaders.cpp +++ b/midend/flattenHeaders.cpp @@ -18,6 +18,7 @@ limitations under the License. #include "flattenHeaders.h" namespace P4 { +using namespace literals; void FindHeaderTypesToReplace::createReplacement(const IR::Type_Header *type, AnnotationSelectionPolicy *policy) { @@ -63,11 +64,11 @@ const IR::Node *ReplaceHeaders::postorder(IR::Type_Header *type) { const IR::Node *ReplaceHeaders::postorder(IR::Member *expression) { // Find out if this applies to one of the parameters that are being replaced. const IR::Expression *e = expression; - cstring prefix = ""; + std::string prefix; const IR::Type_Header *h = nullptr; while (auto mem = e->to()) { e = mem->expr; - prefix = cstring(".") + mem->member + prefix; + prefix = "." + mem->member + prefix; auto type = typeMap->getType(e, true); if ((h = type->to())) break; } diff --git a/midend/flattenInterfaceStructs.cpp b/midend/flattenInterfaceStructs.cpp index a6eae9641e..cd854ce3bf 100644 --- a/midend/flattenInterfaceStructs.cpp +++ b/midend/flattenInterfaceStructs.cpp @@ -17,6 +17,7 @@ limitations under the License. #include "flattenInterfaceStructs.h" namespace P4 { +using namespace literals; namespace { static const IR::Type_Struct *isNestedStruct(const P4::TypeMap *typeMap, const IR::Type *type) { @@ -70,10 +71,10 @@ const IR::Node *ReplaceStructs::postorder(IR::Type_Struct *type) { const IR::Node *ReplaceStructs::postorder(IR::Member *expression) { // Find out if this applies to one of the parameters that are being replaced. const IR::Expression *e = expression; - cstring prefix = ""; + std::string prefix; while (auto mem = e->to()) { e = mem->expr; - prefix = cstring(".") + mem->member + prefix; + prefix = "." + mem->member + prefix; } auto pe = e->to(); if (pe == nullptr) return expression; diff --git a/midend/flattenInterfaceStructs.h b/midend/flattenInterfaceStructs.h index dbe39a22a5..22aa15664b 100644 --- a/midend/flattenInterfaceStructs.h +++ b/midend/flattenInterfaceStructs.h @@ -19,6 +19,7 @@ limitations under the License. #include "frontends/p4/typeChecking/typeChecker.h" #include "ir/ir.h" +#include "lib/cstring.h" namespace P4 { @@ -67,7 +68,7 @@ struct StructTypeReplacement : public IHasDbPrint { StructTypeReplacement(const P4::TypeMap *typeMap, const IR::Type_StructLike *type, AnnotationSelectionPolicy *policy) { auto vec = new IR::IndexedVector(); - flatten(typeMap, "", type, type->annotations, vec, policy); + flatten(typeMap, cstring::empty, type, type->annotations, vec, policy); if (type->is()) { replacementType = new IR::Type_Struct(type->srcInfo, type->name, IR::Annotations::empty, *vec); @@ -123,7 +124,7 @@ struct StructTypeReplacement : public IHasDbPrint { } return; } - cstring fieldName = prefix.replace(".", "_") + cstring::to_cstring(fieldNameRemap.size()); + cstring fieldName = prefix.replace('.', '_') + std::to_string(fieldNameRemap.size()); fieldNameRemap.emplace(prefix, fieldName); fields->push_back(new IR::StructField(IR::ID(fieldName), annotations, type->getP4Type())); LOG3("Flatten: " << type << " | " << prefix); diff --git a/midend/global_copyprop.cpp b/midend/global_copyprop.cpp index 2d816f17ef..5c1a0f6679 100644 --- a/midend/global_copyprop.cpp +++ b/midend/global_copyprop.cpp @@ -26,8 +26,8 @@ static cstring lValueName(const IR::Expression *exp) { /// Test to see if names denote overlapping locations. bool names_overlap(cstring name1, cstring name2) { if (name1 == name2) return true; - if (name1.startsWith(name2) && strchr(".[", name1.get(name2.size()))) return true; - if (name2.startsWith(name1) && strchr(".[", name2.get(name1.size()))) return true; + if (name1.startsWith(name2.string_view()) && strchr(".[", name1.get(name2.size()))) return true; + if (name2.startsWith(name1.string_view()) && strchr(".[", name2.get(name1.size()))) return true; return false; } diff --git a/midend/interpreter.h b/midend/interpreter.h index 35755f32a0..669e25f675 100644 --- a/midend/interpreter.h +++ b/midend/interpreter.h @@ -212,8 +212,8 @@ class SymbolicException : public SymbolicError { class SymbolicStaticError : public SymbolicError { public: - const cstring msg; - SymbolicStaticError(const IR::Node *errorPosition, cstring message) + const std::string msg; + SymbolicStaticError(const IR::Node *errorPosition, std::string_view message) : SymbolicError(errorPosition), msg(message) {} SymbolicValue *clone() const override { return new SymbolicStaticError(errorPosition, msg); } void dbprint(std::ostream &out) const override { out << "Error: " << msg; } diff --git a/midend/local_copyprop.cpp b/midend/local_copyprop.cpp index 9bbe021d67..b6e97bf47a 100644 --- a/midend/local_copyprop.cpp +++ b/midend/local_copyprop.cpp @@ -26,6 +26,8 @@ limitations under the License. namespace P4 { +using namespace literals; + /* helper function to get the 'outermost' containing expression in an lvalue */ static const IR::Expression *lvalue_out(const IR::Expression *exp) { if (auto ai = exp->to()) return lvalue_out(ai->left); @@ -231,8 +233,8 @@ bool DoLocalCopyPropagation::operator==(const ControlFlowVisitor &a_) const { /// test to see if names denote overlapping locations bool DoLocalCopyPropagation::name_overlap(cstring name1, cstring name2) { if (name1 == name2) return true; - if (name1.startsWith(name2) && strchr(".[", name1.get(name2.size()))) return true; - if (name2.startsWith(name1) && strchr(".[", name2.get(name1.size()))) return true; + if (name1.startsWith(name2.string_view()) && strchr(".[", name1.get(name2.size()))) return true; + if (name2.startsWith(name1.string_view()) && strchr(".[", name2.get(name1.size()))) return true; return false; } @@ -256,7 +258,8 @@ void DoLocalCopyPropagation::forOverlapAvail(cstring name, if (it != available.end()) fn(it->first, &it->second); } for (auto it = available.upper_bound(name); it != available.end(); ++it) { - if (!it->first.startsWith(name) || !strchr(".[", it->first.get(name.size()))) break; + if (!it->first.startsWith(name.string_view()) || !strchr(".[", it->first.get(name.size()))) + break; fn(it->first, &it->second); } } @@ -463,12 +466,12 @@ IR::IfStatement *DoLocalCopyPropagation::postorder(IR::IfStatement *s) { IR::ForStatement *DoLocalCopyPropagation::preorder(IR::ForStatement *s) { visit(s->init, "init"); s->apply(LoopPrepass(*this), getContext()); - ControlFlowVisitor::SaveGlobal outer(*this, "-BREAK-", "-CONTINUE-"); + ControlFlowVisitor::SaveGlobal outer(*this, "-BREAK-"_cs, "-CONTINUE-"_cs); visit(s->condition, "condition"); visit(s->body, "body"); - flow_merge_global_from("-CONTINUE-"); + flow_merge_global_from("-CONTINUE-"_cs); visit(s->updates, "updates"); - flow_merge_global_from("-BREAK-"); + flow_merge_global_from("-BREAK-"_cs); prune(); return s; } @@ -477,11 +480,11 @@ IR::ForInStatement *DoLocalCopyPropagation::preorder(IR::ForInStatement *s) { visit(s->decl, "decl", 0); visit(s->collection, "collection", 2); s->apply(LoopPrepass(*this), getContext()); - ControlFlowVisitor::SaveGlobal outer(*this, "-BREAK-", "-CONTINUE-"); + ControlFlowVisitor::SaveGlobal outer(*this, "-BREAK-"_cs, "-CONTINUE-"_cs); visit(s->ref, "ref", 1); visit(s->body, "body", 3); - flow_merge_global_from("-CONTINUE-"); - flow_merge_global_from("-BREAK-"); + flow_merge_global_from("-CONTINUE-"_cs); + flow_merge_global_from("-BREAK-"_cs); prune(); return s; } diff --git a/midend/nestedStructs.cpp b/midend/nestedStructs.cpp index dffe405278..be38559252 100644 --- a/midend/nestedStructs.cpp +++ b/midend/nestedStructs.cpp @@ -4,6 +4,8 @@ namespace P4 { +using namespace literals; + bool ComplexValues::isNestedStruct(const IR::Type *type) { if (!type->is()) return false; auto st = type->to(); @@ -30,7 +32,7 @@ void ComplexValues::explode(cstring prefix, const IR::Type_Struct *type, FieldsM map->members.emplace(f->name.name, submap); explode(fname, ftype->to(), submap, result); } else { - cstring newName = refMap->newName(fname); + cstring newName = refMap->newName(fname.string_view()); auto comp = new FinalName(newName); map->members.emplace(f->name.name, comp); auto clone = new IR::Declaration_Variable(IR::ID(newName), ftype->getP4Type()); @@ -45,9 +47,10 @@ const IR::Node *RemoveNestedStructs::postorder(IR::Declaration_Variable *decl) { if (!values->isNestedStruct(type)) return decl; BUG_CHECK(decl->initializer == nullptr, "%1%: did not expect an initializer", decl); - BUG_CHECK(decl->annotations->size() == 0 || (decl->annotations->size() == 1 && - decl->annotations->getSingle("name") != nullptr), - "%1%: don't know how to handle variable annotations other than @name", decl); + BUG_CHECK( + decl->annotations->size() == 0 || + (decl->annotations->size() == 1 && decl->annotations->getSingle("name"_cs) != nullptr), + "%1%: don't know how to handle variable annotations other than @name", decl); auto map = new ComplexValues::FieldsMap(type); values->values.emplace(getOriginal(), map); if (findContext()) { diff --git a/midend/parserUnroll.h b/midend/parserUnroll.h index f2024aa2a3..5246c391e9 100644 --- a/midend/parserUnroll.h +++ b/midend/parserUnroll.h @@ -151,7 +151,7 @@ class ParserStructure { std::map callsIndexes; // map for curent calls of state insite current one void setParser(const IR::P4Parser *parser) { CHECK_NULL(parser); - callGraph = new StateCallGraph(parser->name); + callGraph = new StateCallGraph(parser->name.name.string_view()); this->parser = parser; start = nullptr; } @@ -268,7 +268,7 @@ class RewriteAllParsers : public Transform { IR::Type::Void::get(), new IR::PathExpression( new IR::Type_Method(IR::Type::Void::get(), new IR::ParameterList(parameters), - "*method"), + "*method"_cs), new IR::Path(IR::ID("verify"))), arguments))); auto *outOfBoundsState = new IR::ParserState( diff --git a/midend/removeExits.cpp b/midend/removeExits.cpp index a150d2d21b..c559ae36d0 100644 --- a/midend/removeExits.cpp +++ b/midend/removeExits.cpp @@ -100,7 +100,7 @@ const IR::Node *DoRemoveExits::preorder(IR::P4Control *control) { return control; } - cstring var = refMap->newName(variableName); + cstring var = refMap->newName(variableName.string_view()); returnVar = IR::ID(var, nullptr); visit(control->controlLocals, "controlLocals"); diff --git a/midend/removeExits.h b/midend/removeExits.h index e1b99f113b..e6d1e34971 100644 --- a/midend/removeExits.h +++ b/midend/removeExits.h @@ -39,7 +39,7 @@ class DoRemoveExits : public DoRemoveReturns { public: DoRemoveExits(ReferenceMap *refMap, TypeMap *typeMap) - : DoRemoveReturns(refMap, "hasExited"), typeMap(typeMap) { + : DoRemoveReturns(refMap, "hasExited"_cs), typeMap(typeMap) { visitDagOnce = false; CHECK_NULL(typeMap); setName("DoRemoveExits"); diff --git a/midend/simplifySelectList.cpp b/midend/simplifySelectList.cpp index 908de03d40..a7cf69474f 100644 --- a/midend/simplifySelectList.cpp +++ b/midend/simplifySelectList.cpp @@ -16,6 +16,8 @@ limitations under the License. #include "simplifySelectList.h" +#include "lib/cstring.h" + namespace P4 { void SubstituteStructures::explode(const IR::Expression *expression, const IR::Type *type, @@ -89,7 +91,7 @@ void UnnestSelectList::flatten(const IR::Expression *expression, unsigned *nesti const IR::Node *UnnestSelectList::preorder(IR::SelectExpression *expression) { IR::Vector vec; - nesting = ""; + nesting = cstring::empty; flatten(expression->select, &vec); if (nesting.findlast(']') == nesting.c_str()) // no nested lists found diff --git a/midend/simplifySelectList.h b/midend/simplifySelectList.h index 7361c54ef2..d32596f98d 100644 --- a/midend/simplifySelectList.h +++ b/midend/simplifySelectList.h @@ -64,6 +64,7 @@ transition select(a, b, c, d) { class UnnestSelectList : public Transform { // Represent the nesting of lists inside of a selectExpression. // E.g.: [__[__]_] for two nested lists. + // FIXME: Lots of terrible concatenations here, must be std::string cstring nesting; void flatten(const IR::Expression *expression, IR::Vector *output); diff --git a/test/gtest/constant_folding.cpp b/test/gtest/constant_folding.cpp index e839646e50..e722ce086d 100644 --- a/test/gtest/constant_folding.cpp +++ b/test/gtest/constant_folding.cpp @@ -100,13 +100,13 @@ TEST_F(P4CConstantFoldingValidation, no_filter) { ASSERT_TRUE(program); // my_hdr_stack_1_t.hdr should be a Constant - auto *sf_1 = getStructField(program, "my_hdr_stack_1_t", "hdr"); + auto *sf_1 = getStructField(program, "my_hdr_stack_1_t"_cs, "hdr"_cs); ASSERT_TRUE(sf_1); auto *ts_1 = sf_1->type->to(); ASSERT_TRUE(ts_1->size->is()); // my_hdr_stack_2_t.hdr should be a Constant - auto *sf_2 = getStructField(program, "my_hdr_stack_2_t", "hdr"); + auto *sf_2 = getStructField(program, "my_hdr_stack_2_t"_cs, "hdr"_cs); ASSERT_TRUE(sf_2); auto *ts_2 = sf_2->type->to(); ASSERT_TRUE(ts_2->size->is()); @@ -121,13 +121,13 @@ TEST_F(P4CConstantFoldingValidation, filter) { ASSERT_TRUE(program); // my_hdr_stack_1_t.hdr should be a Constant - auto *sf_1 = getStructField(program, "my_hdr_stack_1_t", "hdr"); + auto *sf_1 = getStructField(program, "my_hdr_stack_1_t"_cs, "hdr"_cs); ASSERT_TRUE(sf_1); auto *ts_1 = sf_1->type->to(); EXPECT_TRUE(ts_1->size->is()); // my_hdr_stack_2_t.hdr should be a Constant - auto *sf_2 = getStructField(program, "my_hdr_stack_2_t", "hdr"); + auto *sf_2 = getStructField(program, "my_hdr_stack_2_t"_cs, "hdr"_cs); ASSERT_TRUE(sf_2); auto *ts_2 = sf_2->type->to(); EXPECT_TRUE(ts_2->size->is()); diff --git a/test/gtest/cstring.cpp b/test/gtest/cstring.cpp index 54c7d5dd1f..0484dbd1e0 100644 --- a/test/gtest/cstring.cpp +++ b/test/gtest/cstring.cpp @@ -20,6 +20,8 @@ limitations under the License. namespace Test { +using namespace P4::literals; + TEST(cstring, construct) { cstring c(nullptr); EXPECT_TRUE(c.isNullOrEmpty()); @@ -37,7 +39,7 @@ TEST(cstring, construct) { EXPECT_TRUE(c.isNullOrEmpty()); EXPECT_TRUE(c.isNull()); - c = ""; + c = ""_cs; EXPECT_TRUE(c.isNullOrEmpty()); EXPECT_FALSE(c.isNull()); @@ -52,32 +54,32 @@ TEST(cstring, construct) { } TEST(cstring, toupper) { - cstring c = "simple tEst"; - cstring c1 = ""; + cstring c = "simple tEst"_cs; + cstring c1 = ""_cs; EXPECT_EQ(c.toUpper(), "SIMPLE TEST"); EXPECT_EQ(c1.toUpper(), ""); } TEST(cstring, capitalize) { - cstring c = "simple tEst"; - cstring c1 = ""; + cstring c = "simple tEst"_cs; + cstring c1 = ""_cs; EXPECT_EQ(c.capitalize(), "Simple tEst"); EXPECT_EQ(c1.capitalize(), ""); } TEST(cstring, tolower) { - cstring c = "SIMple tEsT"; - cstring c1 = ""; + cstring c = "SIMple tEsT"_cs; + cstring c1 = ""_cs; EXPECT_EQ(c.toLower(), "simple test"); EXPECT_EQ(c1.toLower(), ""); } TEST(cstring, compare) { - cstring c = "simple"; - cstring c1 = ""; + cstring c = "simple"_cs; + cstring c1 = ""_cs; EXPECT_EQ(c, "simple"); EXPECT_EQ(c, c); @@ -110,7 +112,7 @@ TEST(cstring, compare) { } TEST(cstring, find) { - cstring c = "simplest"; + cstring c = "simplest"_cs; EXPECT_EQ(c.find('s'), c.c_str()); EXPECT_EQ(c.find('z'), nullptr); EXPECT_NE(c.findlast('s'), c.c_str()); @@ -119,7 +121,7 @@ TEST(cstring, find) { } TEST(cstring, substr) { - cstring c = "simplest"; + cstring c = "simplest"_cs; EXPECT_EQ(c.substr(3), "plest"); EXPECT_EQ(c.substr(3, 2), "pl"); EXPECT_EQ(c.substr(10), ""); @@ -128,16 +130,15 @@ TEST(cstring, substr) { } TEST(cstring, replace) { - cstring c = "Original"; - EXPECT_EQ(c.replace("in", "out"), "Origoutal"); - EXPECT_EQ(c.replace("", "out"), c); - EXPECT_EQ(c.replace("i", "o"), "Orogonal"); - EXPECT_EQ(c.replace("i", ""), "Orgnal"); + cstring c = "Original"_cs; + EXPECT_EQ(c.replace("in"_cs, "out"_cs), "Origoutal"); + EXPECT_EQ(c.replace(""_cs, "out"_cs), c); + EXPECT_EQ(c.replace("i"_cs, "o"_cs), "Orogonal"); + EXPECT_EQ(c.replace("i"_cs, ""_cs), "Orgnal"); } TEST(cstring, literalSuffix) { - using namespace P4::literals; - cstring c = "test"; + cstring c("test"); EXPECT_EQ(c, "test"_cs); EXPECT_TRUE((std::is_same_v)); } diff --git a/test/gtest/equiv_test.cpp b/test/gtest/equiv_test.cpp index 0d1b74c306..abcbafc51a 100644 --- a/test/gtest/equiv_test.cpp +++ b/test/gtest/equiv_test.cpp @@ -17,8 +17,8 @@ limitations under the License. #include #include "ir/ir.h" -#include "ir/visitor.h" -#include "lib/exceptions.h" + +using namespace P4::literals; TEST(IR, Equiv) { auto *t = IR::Type::Bits::get(16); @@ -60,14 +60,14 @@ TEST(IR, Equiv) { auto *pr1 = new IR::V1Program; auto *pr2 = pr1->clone(); - pr1->add("a", a1); - pr1->add("b", b); - pr1->add("call", call1); - pr2->add("a", a2); - pr2->add("b", b); - pr2->add("call", call2); + pr1->add("a"_cs, a1); + pr1->add("b"_cs, b); + pr1->add("call"_cs, call1); + pr2->add("a"_cs, a2); + pr2->add("b"_cs, b); + pr2->add("call"_cs, call2); EXPECT_TRUE(pr1->equiv(*pr2)); - pr1->add("lista", list1); - pr2->add("listb", list1); + pr1->add("lista"_cs, list1); + pr2->add("listb"_cs, list1); EXPECT_FALSE(pr1->equiv(*pr2)); } diff --git a/test/gtest/expr_uses_test.cpp b/test/gtest/expr_uses_test.cpp index 276ced83a5..ece56884c4 100644 --- a/test/gtest/expr_uses_test.cpp +++ b/test/gtest/expr_uses_test.cpp @@ -19,8 +19,8 @@ limitations under the License. #include #include "ir/ir.h" -#include "ir/visitor.h" -#include "lib/exceptions.h" + +using namespace P4::literals; TEST(expr_uses, expr_uses) { auto obj1 = new IR::PathExpression("obj1"); @@ -33,16 +33,16 @@ TEST(expr_uses, expr_uses) { auto sub = new IR::Sub(obj1_f11, obj2_f1); auto add2 = new IR::Add(obj1_f1, obj1_f11); - EXPECT_TRUE(exprUses(add, "obj1")); - EXPECT_TRUE(exprUses(add, "obj2")); - EXPECT_TRUE(exprUses(add, "obj1.f1")); - EXPECT_TRUE(exprUses(add, "obj1.f1[0]")); - EXPECT_FALSE(exprUses(add, "obj1.f11")); - EXPECT_FALSE(exprUses(add, "obj1.f11[1]")); - EXPECT_FALSE(exprUses(add, "obj2.f1")); - EXPECT_TRUE(exprUses(add, "obj2.f11")); - EXPECT_TRUE(exprUses(sub, "obj1")); - EXPECT_TRUE(exprUses(sub, "obj2")); - EXPECT_TRUE(exprUses(add2, "obj1.f1")); - EXPECT_TRUE(exprUses(add2, "obj1.f11")); + EXPECT_TRUE(exprUses(add, "obj1"_cs)); + EXPECT_TRUE(exprUses(add, "obj2"_cs)); + EXPECT_TRUE(exprUses(add, "obj1.f1"_cs)); + EXPECT_TRUE(exprUses(add, "obj1.f1[0]"_cs)); + EXPECT_FALSE(exprUses(add, "obj1.f11"_cs)); + EXPECT_FALSE(exprUses(add, "obj1.f11[1]"_cs)); + EXPECT_FALSE(exprUses(add, "obj2.f1"_cs)); + EXPECT_TRUE(exprUses(add, "obj2.f11"_cs)); + EXPECT_TRUE(exprUses(sub, "obj1"_cs)); + EXPECT_TRUE(exprUses(sub, "obj2"_cs)); + EXPECT_TRUE(exprUses(add2, "obj1.f1"_cs)); + EXPECT_TRUE(exprUses(add2, "obj1.f11"_cs)); } diff --git a/test/gtest/format_test.cpp b/test/gtest/format_test.cpp index 9208b3c106..6c32863c15 100644 --- a/test/gtest/format_test.cpp +++ b/test/gtest/format_test.cpp @@ -37,8 +37,8 @@ TEST(Util, Format) { int a, b, c; cstring toString() const { - return cstring("(") + Util::toString(this->a) + "," + Util::toString(this->b) + "," + - Util::toString(this->c) + ")"; + return "("_cs + Util::toString(this->a) + ","_cs + Util::toString(this->b) + ","_cs + + Util::toString(this->c) + ")"_cs; } }; @@ -46,8 +46,8 @@ TEST(Util, Format) { message = context.errorReporter().format_message("Nice=%1%", nf); EXPECT_EQ("Nice=(1,2,3)\n", message); - cstring x = "x"; - cstring y = "y"; + cstring x = "x"_cs; + cstring y = "y"_cs; message = context.errorReporter().format_message("%1% %2%", x, y); EXPECT_EQ("x y\n", message); diff --git a/test/gtest/indexed_vector.cpp b/test/gtest/indexed_vector.cpp index 191720a382..7417c57ed5 100644 --- a/test/gtest/indexed_vector.cpp +++ b/test/gtest/indexed_vector.cpp @@ -23,15 +23,15 @@ TEST(IndexedVector, basics) { EXPECT_EQ(vec.size(), 1u); EXPECT_EQ(vec[0]->name.name, "foo"); - vec.push_back(testItem("bar")); + vec.push_back(testItem("bar"_cs)); EXPECT_FALSE(vec.empty()); EXPECT_EQ(vec.size(), 2u); EXPECT_EQ(vec[1]->name.name, "bar"); - cstring check = "foo"; - for (auto *dec : vec) { + cstring check = "foo"_cs; + for (const auto *dec : vec) { EXPECT_EQ(dec->name.name, check); - check = "bar"; + check = "bar"_cs; } vec.pop_back(); @@ -39,7 +39,7 @@ TEST(IndexedVector, basics) { EXPECT_EQ(vec.size(), 1u); EXPECT_EQ(vec[0]->name.name, "foo"); - vec.removeByName("foo"); + vec.removeByName("foo"_cs); EXPECT_TRUE(vec.empty()); EXPECT_EQ(vec.size(), 0u); } @@ -64,7 +64,7 @@ TEST(IndexedVector, move_ctor) { TestVector vec2(std::move(vec)); EXPECT_TRUE(vec.empty()); EXPECT_TRUE(vec2.empty()); - vec2.push_back(testItem("foo")); + vec2.push_back(testItem("foo"_cs)); EXPECT_TRUE(vec.empty()); EXPECT_FALSE(vec2.empty()); @@ -75,21 +75,21 @@ TEST(IndexedVector, move_ctor) { } TEST(IndexedVector, ilist_ctor) { - TestVector vec{testItem("foo"), testItem("bar")}; + TestVector vec{testItem("foo"_cs), testItem("bar"_cs)}; EXPECT_EQ(vec.size(), 2u); EXPECT_EQ(vec[0]->name.name, "foo"); EXPECT_EQ(vec[1]->name.name, "bar"); } TEST(IndexedVector, save_vector_ctor) { - TestVector vec(safe_vector{testItem("foo"), testItem("bar")}); + TestVector vec(safe_vector{testItem("foo"_cs), testItem("bar"_cs)}); EXPECT_EQ(vec.size(), 2u); EXPECT_EQ(vec[0]->name.name, "foo"); EXPECT_EQ(vec[1]->name.name, "bar"); } TEST(IndexedVector, Vector_ctor) { - TestVector vec(Vector{testItem("foo"), testItem("bar")}); + TestVector vec(Vector{testItem("foo"_cs), testItem("bar"_cs)}); EXPECT_EQ(vec.size(), 2u); EXPECT_EQ(vec[0]->name.name, "foo"); EXPECT_EQ(vec[1]->name.name, "bar"); diff --git a/test/gtest/json_test.cpp b/test/gtest/json_test.cpp index 0d4a5629b6..0f9e80a9f7 100644 --- a/test/gtest/json_test.cpp +++ b/test/gtest/json_test.cpp @@ -65,9 +65,9 @@ TEST(Util, Json) { auto obj = new JsonObject(); EXPECT_EQ("{\n}", obj->toString()); - obj->emplace("x", "x"); + obj->emplace("x"_cs, "x"); EXPECT_EQ("{\n \"x\" : \"x\"\n}", obj->toString()); - obj->emplace("y", arr); + obj->emplace("y"_cs, arr); EXPECT_EQ("{\n \"x\" : \"x\",\n \"y\" : [\n 5,\n \"5\",\n [true]\n ]\n}", obj->toString()); } diff --git a/test/gtest/midend_pass.cpp b/test/gtest/midend_pass.cpp index 800e854da0..ef13f3c0c5 100644 --- a/test/gtest/midend_pass.cpp +++ b/test/gtest/midend_pass.cpp @@ -136,7 +136,7 @@ MidEnd::MidEnd(CompilerOptions &options, std::ostream *outStream) { [this, evaluator]() { toplevel = evaluator->getToplevelBlock(); }, new P4::MidEndLast()}); if (options.listMidendPasses) { - listPasses(*outStream, "\n"); + listPasses(*outStream, cstring::newline); *outStream << std::endl; return; } diff --git a/test/gtest/p4runtime.cpp b/test/gtest/p4runtime.cpp index 0d706500cb..e562f1e59a 100644 --- a/test/gtest/p4runtime.cpp +++ b/test/gtest/p4runtime.cpp @@ -46,6 +46,8 @@ limitations under the License. namespace p4v1 = ::p4::v1; namespace p4configv1 = ::p4::config::v1; +using namespace P4::literals; + namespace Test { namespace { @@ -63,12 +65,12 @@ using P4::ControlPlaneAPI::findP4RuntimeValueSet; using google::protobuf::util::MessageDifferencer; -const cstring defaultArch = "v1model"; +const cstring defaultArch = "v1model"_cs; class ParseAnnotations : public P4::ParseAnnotations { public: ParseAnnotations() - : P4::ParseAnnotations("FrontendTest", true, {PARSE("my_anno", StringLiteral)}) {} + : P4::ParseAnnotations("FrontendTest", true, {PARSE("my_anno"_cs, StringLiteral)}) {} }; struct AnnotationParsingPolicy : P4::FrontEndPolicy { @@ -199,7 +201,7 @@ TEST_F(P4Runtime, IdAssignment) { { // Check that 'igTable' ended up in the P4Info output. - const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTable"); + const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTable"_cs); ASSERT_TRUE(igTable != nullptr); // Check that the id indicates the correct resource type. @@ -215,8 +217,9 @@ TEST_F(P4Runtime, IdAssignment) { // Check that 'igTableWithName' ended up in the P4Info output under that // name, which is determined by its @name annotation, and *not* under // 'igTableWithoutName'. - EXPECT_TRUE(findP4RuntimeTable(*test->p4Info, "ingress.igTableWithoutName") == nullptr); - const auto *igTableWithName = findP4RuntimeTable(*test->p4Info, "ingress.igTableWithName"); + EXPECT_TRUE(findP4RuntimeTable(*test->p4Info, "ingress.igTableWithoutName"_cs) == nullptr); + const auto *igTableWithName = + findP4RuntimeTable(*test->p4Info, "ingress.igTableWithName"_cs); ASSERT_TRUE(igTableWithName != nullptr); // Check that the id of 'igTableWithName' was computed based on its @@ -229,7 +232,7 @@ TEST_F(P4Runtime, IdAssignment) { // Check that 'igTableWithId' ended up in the P4Info output, and that // its id matches the one set by its @id annotation, with the required // 8-bit type prefix (which is 0x2 for tables). - const auto *igTableWithId = findP4RuntimeTable(*test->p4Info, "ingress.igTableWithId"); + const auto *igTableWithId = findP4RuntimeTable(*test->p4Info, "ingress.igTableWithId"_cs); ASSERT_TRUE(igTableWithId != nullptr); auto expectedId = 1234U | (unsigned(P4Ids::TABLE) << 24); EXPECT_EQ(expectedId, igTableWithId->preamble().id()); @@ -238,7 +241,7 @@ TEST_F(P4Runtime, IdAssignment) { { // Same as above, but with the largest possible id (0xffffff). const auto *igTableWithLargestId = - findP4RuntimeTable(*test->p4Info, "ingress.igTableWithLargestId"); + findP4RuntimeTable(*test->p4Info, "ingress.igTableWithLargestId"_cs); ASSERT_TRUE(igTableWithLargestId != nullptr); auto expectedId = 0xffffffU | (static_cast(P4Ids::TABLE) << 24); EXPECT_EQ(expectedId, igTableWithLargestId->preamble().id()); @@ -248,7 +251,7 @@ TEST_F(P4Runtime, IdAssignment) { // Check that 'igTableWithPrefixedId' ended up in the P4Info output, and // that its id matches the one set by its @id annotation. const auto *igTableWithPrefixedId = - findP4RuntimeTable(*test->p4Info, "ingress.igTableWithPrefixedId"); + findP4RuntimeTable(*test->p4Info, "ingress.igTableWithPrefixedId"_cs); ASSERT_TRUE(igTableWithPrefixedId != nullptr); auto expectedId = 0x02000133U; EXPECT_EQ(expectedId, igTableWithPrefixedId->preamble().id()); @@ -258,10 +261,10 @@ TEST_F(P4Runtime, IdAssignment) { // Check that 'igTableWithNameAndId' ended up in the P4Info output under // that name, and that its id matches the one set by its @id annotation // - in other words, that @id takes precedence over @name. - EXPECT_TRUE(findP4RuntimeTable(*test->p4Info, "ingress.igTableWithoutNameAndId") == + EXPECT_TRUE(findP4RuntimeTable(*test->p4Info, "ingress.igTableWithoutNameAndId"_cs) == nullptr); const auto *igTableWithNameAndId = - findP4RuntimeTable(*test->p4Info, "ingress.igTableWithNameAndId"); + findP4RuntimeTable(*test->p4Info, "ingress.igTableWithNameAndId"_cs); ASSERT_TRUE(igTableWithNameAndId != nullptr); auto expectedId = 5678U | (static_cast(P4Ids::TABLE) << 24); EXPECT_EQ(expectedId, igTableWithNameAndId->preamble().id()); @@ -271,10 +274,10 @@ TEST_F(P4Runtime, IdAssignment) { // Check that the two tables with conflicting ids are both present, and // that they didn't end up with the same id in the P4Info output. const auto *conflictingTableA = - findP4RuntimeTable(*test->p4Info, "ingress.conflictingTableA"); + findP4RuntimeTable(*test->p4Info, "ingress.conflictingTableA"_cs); ASSERT_TRUE(conflictingTableA != nullptr); const p4::config::v1::Table *conflictingTableB = - findP4RuntimeTable(*test->p4Info, "ingress.conflictingTableB"); + findP4RuntimeTable(*test->p4Info, "ingress.conflictingTableB"_cs); ASSERT_TRUE(conflictingTableB != nullptr); EXPECT_TRUE(conflictingTableA->preamble().id() == 0x02000134 || conflictingTableB->preamble().id() == 0x02000134); @@ -372,7 +375,7 @@ TEST_F(P4Runtime, FieldIdAssignment) { { // Check the ids for igTable's match fields. - const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTable"); + const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTable"_cs); ASSERT_TRUE(igTable != nullptr); const auto &mf1 = igTable->match_fields(0); const auto &mf2 = igTable->match_fields(1); @@ -382,7 +385,7 @@ TEST_F(P4Runtime, FieldIdAssignment) { { // Check the ids for action a's parameters. - const auto *aAction = findP4RuntimeAction(*test->p4Info, "ingress.a"); + const auto *aAction = findP4RuntimeAction(*test->p4Info, "ingress.a"_cs); ASSERT_TRUE(aAction != nullptr); const auto &ap1 = aAction->params(0); const auto &ap2 = aAction->params(1); @@ -393,7 +396,7 @@ TEST_F(P4Runtime, FieldIdAssignment) { { // Check the ids for the packet-in header fields. const auto *packetInHeader = - findP4RuntimeControllerPacketMetadata(*test->p4Info, "packet_in"); + findP4RuntimeControllerPacketMetadata(*test->p4Info, "packet_in"_cs); ASSERT_TRUE(packetInHeader != nullptr); const auto &m1 = packetInHeader->metadata(0); const auto &m2 = packetInHeader->metadata(1); @@ -404,7 +407,7 @@ TEST_F(P4Runtime, FieldIdAssignment) { { // Check the ids for igTableNoAnno's match fields. Without @id // annotations, the ids should be assigned sequentially, starting at 1. - const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTableNoAnno"); + const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTableNoAnno"_cs); ASSERT_TRUE(igTable != nullptr); const auto &mf1 = igTable->match_fields(0); const auto &mf2 = igTable->match_fields(1); @@ -416,14 +419,14 @@ TEST_F(P4Runtime, FieldIdAssignment) { // Check the ids for igTableLargeId's match fields. The compiler should // be able to handle all unsigned 32-bit integers greater than 0, // including 0xffffffff. - const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTableLargeId"); + const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTableLargeId"_cs); ASSERT_TRUE(igTable != nullptr); const auto &mf1 = igTable->match_fields(0); EXPECT_EQ(0xffffffff, mf1.id()); } { - const auto *vset = findP4RuntimeValueSet(*test->p4Info, "parse.pvs"); + const auto *vset = findP4RuntimeValueSet(*test->p4Info, "parse.pvs"_cs); ASSERT_TRUE(vset != nullptr); const auto &mf1 = vset->match(0); const auto &mf2 = vset->match(1); @@ -485,27 +488,27 @@ TEST_F(P4Runtime, IdAssignmentCounters) { // checks that myDirectCounter1 with the right ID prefix { - const auto *myTable1 = findP4RuntimeTable(*test->p4Info, "myTable1"); + const auto *myTable1 = findP4RuntimeTable(*test->p4Info, "myTable1"_cs); ASSERT_TRUE(myTable1 != nullptr); const auto *myDirectCounter1 = - findP4RuntimeDirectCounter(*test->p4Info, "myDirectCounter1"); + findP4RuntimeDirectCounter(*test->p4Info, "myDirectCounter1"_cs); ASSERT_TRUE(myDirectCounter1 != nullptr); EXPECT_EQ(unsigned(P4Ids::DIRECT_COUNTER), myDirectCounter1->preamble().id() >> 24); EXPECT_EQ(myDirectCounter1->preamble().id(), myTable1->direct_resource_ids(0)); } // checks that myDirectCounter2 with the right ID prefix { - const auto *myTable2 = findP4RuntimeTable(*test->p4Info, "myTable2"); + const auto *myTable2 = findP4RuntimeTable(*test->p4Info, "myTable2"_cs); ASSERT_TRUE(myTable2 != nullptr); const auto *myDirectCounter2 = - findP4RuntimeDirectCounter(*test->p4Info, "myDirectCounter2"); + findP4RuntimeDirectCounter(*test->p4Info, "myDirectCounter2"_cs); ASSERT_TRUE(myDirectCounter2 != nullptr); EXPECT_EQ(unsigned(P4Ids::DIRECT_COUNTER), myDirectCounter2->preamble().id() >> 24); EXPECT_EQ(myDirectCounter2->preamble().id(), myTable2->direct_resource_ids(0)); } // checks that myCounter with the right ID prefix { - const auto *myCounter = findP4RuntimeCounter(*test->p4Info, "myCounter"); + const auto *myCounter = findP4RuntimeCounter(*test->p4Info, "myCounter"_cs); ASSERT_TRUE(myCounter != nullptr); EXPECT_EQ(unsigned(P4Ids::COUNTER), myCounter->preamble().id() >> 24); } @@ -633,7 +636,7 @@ TEST_F(P4Runtime, P416MatchFields) { ASSERT_TRUE(test); EXPECT_EQ(0u, ::diagnosticCount()); - const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTable"); + const auto *igTable = findP4RuntimeTable(*test->p4Info, "ingress.igTable"_cs); ASSERT_TRUE(igTable != nullptr); EXPECT_EQ(39, igTable->match_fields_size()); @@ -746,7 +749,7 @@ TEST_F(P4Runtime, DISABLED_P414MatchFields) { ASSERT_TRUE(test); EXPECT_EQ(0U, ::diagnosticCount()); - const auto *igTable = findP4RuntimeTable(*test->p4Info, "igTable"); + const auto *igTable = findP4RuntimeTable(*test->p4Info, "igTable"_cs); ASSERT_TRUE(igTable != nullptr); EXPECT_EQ(18, igTable->match_fields_size()); @@ -825,7 +828,7 @@ TEST_F(P4Runtime, Digests) { // digest() where T is a header. { - const auto *digest = findP4RuntimeDigest(*test->p4Info, "Header"); + const auto *digest = findP4RuntimeDigest(*test->p4Info, "Header"_cs); ASSERT_TRUE(digest != nullptr); EXPECT_EQ(unsigned(P4Ids::DIGEST), digest->preamble().id() >> 24); ASSERT_TRUE(digest->type_spec().has_header()); @@ -835,7 +838,7 @@ TEST_F(P4Runtime, Digests) { // digest() where T is a struct. { - const auto *digest = findP4RuntimeDigest(*test->p4Info, "Metadata"); + const auto *digest = findP4RuntimeDigest(*test->p4Info, "Metadata"_cs); ASSERT_TRUE(digest != nullptr); EXPECT_EQ(unsigned(P4Ids::DIGEST), digest->preamble().id() >> 24); ASSERT_TRUE(digest->type_spec().has_struct_()); @@ -845,7 +848,7 @@ TEST_F(P4Runtime, Digests) { // digest() where T is a tuple. { - const auto *digest = findP4RuntimeDigest(*test->p4Info, "digest_0"); + const auto *digest = findP4RuntimeDigest(*test->p4Info, "digest_0"_cs); ASSERT_TRUE(digest != nullptr); EXPECT_EQ(unsigned(P4Ids::DIGEST), digest->preamble().id() >> 24); ASSERT_TRUE(digest->type_spec().has_tuple()); @@ -935,7 +938,7 @@ TEST_F(P4Runtime, PSADigests) { PSA_Switch(ip, PacketReplicationEngine(), ep, BufferingQueueingEngine()) main; )"), - CompilerOptions::FrontendVersion::P4_16, "psa"); + CompilerOptions::FrontendVersion::P4_16, "psa"_cs); ASSERT_TRUE(test); // 0 warnings @@ -947,7 +950,7 @@ TEST_F(P4Runtime, PSADigests) { // Digest where T is a header. { - const auto *digest = findP4RuntimeDigest(*test->p4Info, "MyIC.digest1"); + const auto *digest = findP4RuntimeDigest(*test->p4Info, "MyIC.digest1"_cs); ASSERT_TRUE(digest != nullptr); EXPECT_EQ(unsigned(P4Ids::DIGEST), digest->preamble().id() >> 24); ASSERT_TRUE(digest->type_spec().has_header()); @@ -957,7 +960,7 @@ TEST_F(P4Runtime, PSADigests) { // Digest where T is a struct. { - const auto *digest = findP4RuntimeDigest(*test->p4Info, "MyIC.digest2"); + const auto *digest = findP4RuntimeDigest(*test->p4Info, "MyIC.digest2"_cs); ASSERT_TRUE(digest != nullptr); EXPECT_EQ(unsigned(P4Ids::DIGEST), digest->preamble().id() >> 24); ASSERT_TRUE(digest->type_spec().has_struct_()); @@ -967,7 +970,7 @@ TEST_F(P4Runtime, PSADigests) { // Digest where T is a tuple. { - const auto *digest = findP4RuntimeDigest(*test->p4Info, "MyIC.digest3"); + const auto *digest = findP4RuntimeDigest(*test->p4Info, "MyIC.digest3"_cs); ASSERT_TRUE(digest != nullptr); EXPECT_EQ(unsigned(P4Ids::DIGEST), digest->preamble().id() >> 24); ASSERT_TRUE(digest->type_spec().has_tuple()); @@ -1034,13 +1037,13 @@ TEST_F(P4Runtime, StaticTableEntries) { ASSERT_EQ(6, updates.size()); { - const auto *table = findP4RuntimeTable(*test->p4Info, "ingress.t_exact_ternary"); + const auto *table = findP4RuntimeTable(*test->p4Info, "ingress.t_exact_ternary"_cs); ASSERT_TRUE(table != nullptr); EXPECT_TRUE(table->is_const_table()); unsigned int hfAId = 1; unsigned int hfBId = 2; unsigned int xId = 1; - const auto *action = findP4RuntimeAction(*test->p4Info, "ingress.a_with_control_params"); + const auto *action = findP4RuntimeAction(*test->p4Info, "ingress.a_with_control_params"_cs); ASSERT_TRUE(action != nullptr); int priority = 1000; @@ -1087,10 +1090,10 @@ TEST_F(P4Runtime, StaticTableEntries) { } { - const auto *table = findP4RuntimeTable(*test->p4Info, "ingress.t_exact_valid"); + const auto *table = findP4RuntimeTable(*test->p4Info, "ingress.t_exact_valid"_cs); ASSERT_TRUE(table != nullptr); EXPECT_TRUE(table->is_const_table()); - const auto *action = findP4RuntimeAction(*test->p4Info, "ingress.a_with_bool_param"); + const auto *action = findP4RuntimeAction(*test->p4Info, "ingress.a_with_bool_param"_cs); ASSERT_TRUE(action != nullptr); auto checkEntry = [&](const p4v1::Update &update, const std::string &exact_v, @@ -1158,10 +1161,10 @@ TEST_F(P4Runtime, IsConstTable) { ASSERT_TRUE(test); EXPECT_EQ(0U, ::diagnosticCount()); - const auto *tableConst = findP4RuntimeTable(*test->p4Info, "ingress.t_const"); + const auto *tableConst = findP4RuntimeTable(*test->p4Info, "ingress.t_const"_cs); ASSERT_TRUE(tableConst != nullptr); EXPECT_TRUE(tableConst->is_const_table()); - const auto *tableNonConst = findP4RuntimeTable(*test->p4Info, "ingress.t_non_const"); + const auto *tableNonConst = findP4RuntimeTable(*test->p4Info, "ingress.t_non_const"_cs); ASSERT_TRUE(tableNonConst != nullptr); EXPECT_FALSE(tableNonConst->is_const_table()); } @@ -1201,7 +1204,7 @@ TEST_F(P4Runtime, TableActionsAnnotations) { ASSERT_TRUE(test); EXPECT_EQ(0U, ::diagnosticCount()); - const auto *table = findP4RuntimeTable(*test->p4Info, "ingress.t"); + const auto *table = findP4RuntimeTable(*test->p4Info, "ingress.t"_cs); ASSERT_TRUE(table != nullptr); // finds action reference based on the action name @@ -1266,16 +1269,16 @@ TEST_F(P4Runtime, ValueSet) { ASSERT_TRUE(test); EXPECT_EQ(0U, ::diagnosticCount()); - const auto *vset = findP4RuntimeValueSet(*test->p4Info, "parse.pvs"); + const auto *vset = findP4RuntimeValueSet(*test->p4Info, "parse.pvs"_cs); ASSERT_TRUE(vset != nullptr); EXPECT_EQ(vset->preamble().id() >> 24, unsigned(P4Ids::VALUE_SET)); EXPECT_EQ(vset->size(), 16); ASSERT_EQ(vset->match_size(), 3); using MatchField = p4configv1::MatchField; - auto checkMatchField = [](const p4configv1::MatchField &mf, unsigned int id, cstring name, - const std::vector &annotations, int bitwidth, - std::optional matchType, + auto checkMatchField = [](const p4configv1::MatchField &mf, unsigned int id, + std::string_view name, const std::vector &annotations, + int bitwidth, std::optional matchType, std::optional otherMatchType) { EXPECT_EQ(mf.id(), id); EXPECT_EQ(mf.name(), name); @@ -1291,10 +1294,10 @@ TEST_F(P4Runtime, ValueSet) { EXPECT_EQ(mf.other_match_type(), *otherMatchType); } }; - checkMatchField(vset->match(0), 1, "f1", {"@my_anno(\"body\")"}, 8, MatchField::TERNARY, + checkMatchField(vset->match(0), 1, "f1", {"@my_anno(\"body\")"_cs}, 8, MatchField::TERNARY, std::nullopt); checkMatchField(vset->match(1), 2, "f2", {}, 8, MatchField::EXACT, std::nullopt); - checkMatchField(vset->match(2), 3, "f3", {}, 8, std::nullopt, cstring("custom")); + checkMatchField(vset->match(2), 3, "f3", {}, 8, std::nullopt, "custom"_cs); } TEST_F(P4Runtime, Register) { @@ -1328,7 +1331,7 @@ TEST_F(P4Runtime, Register) { EXPECT_EQ(0U, ::diagnosticCount()); { // type parameter is tuple - const auto *register_ = findP4RuntimeRegister(*test->p4Info, "ingress.my_register_1"); + const auto *register_ = findP4RuntimeRegister(*test->p4Info, "ingress.my_register_1"_cs); ASSERT_TRUE(register_ != nullptr); EXPECT_EQ(unsigned(P4Ids::REGISTER), register_->preamble().id() >> 24); const auto &annotations = register_->preamble().annotations(); @@ -1340,7 +1343,7 @@ TEST_F(P4Runtime, Register) { EXPECT_EQ(2, typeSpec.tuple().members_size()); } { // type parameter is header - const auto *register_ = findP4RuntimeRegister(*test->p4Info, "ingress.my_register_2"); + const auto *register_ = findP4RuntimeRegister(*test->p4Info, "ingress.my_register_2"_cs); ASSERT_TRUE(register_ != nullptr); EXPECT_EQ(unsigned(P4Ids::REGISTER), register_->preamble().id() >> 24); EXPECT_EQ(128, register_->size()); @@ -1392,7 +1395,7 @@ TEST_F(P4Runtime, Documentation) { EXPECT_EQ(0U, ::diagnosticCount()); { - const auto *table = findP4RuntimeTable(*test->p4Info, "ingress.t"); + const auto *table = findP4RuntimeTable(*test->p4Info, "ingress.t"_cs); ASSERT_TRUE(table != nullptr); const auto &tDocumentation = table->preamble().doc(); EXPECT_EQ(tDocumentation.brief(), ""); @@ -1408,7 +1411,7 @@ TEST_F(P4Runtime, Documentation) { } { - const auto *noop = findP4RuntimeAction(*test->p4Info, "ingress.noop"); + const auto *noop = findP4RuntimeAction(*test->p4Info, "ingress.noop"_cs); ASSERT_TRUE(noop != nullptr); const auto &aDocumentation = noop->preamble().doc(); EXPECT_EQ(aDocumentation.brief(), "This action does nothing duh!"); @@ -1416,7 +1419,7 @@ TEST_F(P4Runtime, Documentation) { } { - const auto *drop = findP4RuntimeAction(*test->p4Info, "ingress.drop"); + const auto *drop = findP4RuntimeAction(*test->p4Info, "ingress.drop"_cs); ASSERT_TRUE(drop != nullptr); EXPECT_FALSE(drop->preamble().has_doc()); } @@ -1652,7 +1655,7 @@ class P4RuntimeDataTypeSpec : public P4Runtime { PassManager passes( {new P4::ParseAnnotations("P4RuntimeDataTypeSpecTest", false, { - {"p4runtime_translation", + {"p4runtime_translation"_cs, &P4::ParseAnnotations::parseP4rtTranslationAnnotation}, }), new P4::ResolveReferences(&refMap), new P4::TypeInference(&refMap, &typeMap, false)}); @@ -1740,7 +1743,7 @@ TEST_F(P4RuntimeDataTypeSpec, Struct) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1766,7 +1769,7 @@ TEST_F(P4RuntimeDataTypeSpec, Header) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1792,7 +1795,7 @@ TEST_F(P4RuntimeDataTypeSpec, HeaderWithFlattening) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1821,7 +1824,7 @@ TEST_F(P4RuntimeDataTypeSpec, HeaderUnion) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1851,7 +1854,7 @@ TEST_F(P4RuntimeDataTypeSpec, HeaderStack) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1873,7 +1876,7 @@ TEST_F(P4RuntimeDataTypeSpec, HeaderUnionStack) { auto pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - auto type = findExternTypeParameterName(pgm, "my_extern_t"); + auto type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); auto typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1895,7 +1898,7 @@ TEST_F(P4RuntimeDataTypeSpec, Enum) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1918,7 +1921,7 @@ TEST_F(P4RuntimeDataTypeSpec, SerEnum) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1943,7 +1946,7 @@ TEST_F(P4RuntimeDataTypeSpec, Error) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1965,7 +1968,7 @@ TEST_F(P4RuntimeDataTypeSpec, StructWithTypedef) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -1975,7 +1978,7 @@ TEST_F(P4RuntimeDataTypeSpec, StructWithTypedef) { auto it = typeInfo.structs().find("my_struct"); ASSERT_TRUE(it != typeInfo.structs().end()); ASSERT_EQ(2, it->second.members_size()); - auto checkMember = [&](cstring name, int index) { + auto checkMember = [&](std::string_view name, int index) { EXPECT_EQ(name, it->second.members(index).name()); const auto &memberTypeSpec = it->second.members(index).type_spec(); ASSERT_TRUE(memberTypeSpec.has_bitstring()); @@ -1998,7 +2001,7 @@ TEST_F(P4RuntimeDataTypeSpec, NewType) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); const auto *typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); @@ -2009,7 +2012,7 @@ TEST_F(P4RuntimeDataTypeSpec, NewType) { ASSERT_TRUE(it != typeInfo.structs().end()); ASSERT_EQ(2, it->second.members_size()); - auto checkMember = [&](cstring memberName, int index, cstring newTypeName) { + auto checkMember = [&](std::string_view memberName, int index, std::string_view newTypeName) { EXPECT_EQ(memberName, it->second.members(index).name()); const auto &memberTypeSpec = it->second.members(index).type_spec(); ASSERT_TRUE(memberTypeSpec.has_new_type()); @@ -2073,7 +2076,7 @@ TEST_F(P4RuntimeDataTypeSpec, NewTypeIllegalTranslationAnnotations) { ASSERT_TRUE(pgm != nullptr); ASSERT_EQ(::errorCount(), 0U); // No syntax error. - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); EXPECT_EQ(1U, ::errorCount()); // But a type error. @@ -2098,7 +2101,7 @@ TEST_F(P4RuntimeDataTypeSpec, NewTypeValidTranslationAnnotations) { const auto *pgm = getProgram(program); ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); - const auto *type = findExternTypeParameterName(pgm, "my_extern_t"); + const auto *type = findExternTypeParameterName(pgm, "my_extern_t"_cs); ASSERT_TRUE(type != nullptr); P4::ControlPlaneAPI::TypeSpecConverter::convert(&refMap, &typeMap, type, &typeInfo); diff --git a/test/gtest/parser_unroll.cpp b/test/gtest/parser_unroll.cpp index d5c634818e..2c417572fe 100644 --- a/test/gtest/parser_unroll.cpp +++ b/test/gtest/parser_unroll.cpp @@ -66,7 +66,7 @@ const IR::P4Program *load_model(const char *curFile, CompilerOptions &options) { auto originalEnv = getenv("P4C_16_INCLUDE_PATH"); setenv("P4C_16_INCLUDE_PATH", includeDir.c_str(), 1); options.loopsUnrolling = true; - options.file = sourcePath; + options.file = cstring(sourcePath); options.file += "testdata/p4_16_samples/"; options.file += curFile; auto program = P4::parseP4File(options); diff --git a/test/gtest/path_test.cpp b/test/gtest/path_test.cpp index 1c887445e7..3c302db2e6 100644 --- a/test/gtest/path_test.cpp +++ b/test/gtest/path_test.cpp @@ -73,15 +73,15 @@ TEST(Util, PathName) { { PathName path = ""; EXPECT_TRUE(path.isNullOrEmpty()); - PathName grow = path.join("x"); + PathName grow = path.join("x"_cs); EXPECT_EQ("x", grow.toString()); EXPECT_FALSE(grow.isNullOrEmpty()); - grow = grow.join("y"); + grow = grow.join("y"_cs); EXPECT_EQ("x/y", grow.toString()); path = PathName("x/"); - grow = path.join("y"); + grow = path.join("y"_cs); EXPECT_EQ("x/y", grow.toString()); } } diff --git a/tools/ir-generator/generator.cpp b/tools/ir-generator/generator.cpp index d6fdb1f334..e2dc54c381 100644 --- a/tools/ir-generator/generator.cpp +++ b/tools/ir-generator/generator.cpp @@ -52,15 +52,15 @@ int main(int argc, char *argv[]) { usage(argv[0]); return 1; case 'o': - header = openFile(optarg, false); + header = openFile(cstring(optarg), false); if (header == nullptr) return 1; break; case 'i': - impl = openFile(optarg, false); + impl = openFile(cstring(optarg), false); if (impl == nullptr) return 1; break; case 't': - t = openFile(optarg, false); + t = openFile(cstring(optarg), false); if (t == nullptr) return 1; break; case 'P': diff --git a/tools/ir-generator/ir-generator-lex.l b/tools/ir-generator/ir-generator-lex.l index 7f5cc23a38..7643576018 100644 --- a/tools/ir-generator/ir-generator-lex.l +++ b/tools/ir-generator/ir-generator-lex.l @@ -50,19 +50,19 @@ static std::string comment_block; return EMITBLOCK; } .* { block_buffer += yytext; } -"#include".*[\n] { yylval.str = yytext; return INCLUDE; } +"#include".*[\n] { yylval.str = cstring(yytext); return INCLUDE; } "/*" { comment_block.clear(); comment_block += yytext; yy_push_state(COMMENT); } "*/" { yy_pop_state(); comment_block += yytext; - yylval.str = comment_block; + yylval.str = cstring(comment_block); return COMMENTBLOCK; } . { comment_block += yytext; } [\n] { comment_block += yytext; } -"//".* { yylval.str = yytext; return COMMENTBLOCK; } +"//".* { yylval.str = cstring(yytext); return COMMENTBLOCK; } "::" { return DBLCOL; } "abstract" { return ABSTRACT; } @@ -84,13 +84,13 @@ static std::string comment_block; "virtual" { return VIRTUAL; } "NullOK" { return NULLOK; } "#apply" { return APPLY; } -"#no"[a-zA-Z_]* { yylval.str = yytext+3; return NO; } -"#nooperator==" { yylval.str = yytext+3; return NO; } -"0" { yylval.str = yytext; return ZERO; } --?[0-9]+ { yylval.str = yytext; return INTEGER; } +"#no"[a-zA-Z_]* { yylval.str = cstring(yytext+3); return NO; } +"#nooperator==" { yylval.str = cstring(yytext+3); return NO; } +"0" { yylval.str = cstring(yytext); return ZERO; } +-?[0-9]+ { yylval.str = cstring(yytext); return INTEGER; } -[A-Za-z_][A-Za-z0-9_]* { yylval.str = yytext; return IDENTIFIER; } -\"(\\.|[^\\"])*\" { yylval.str = yytext; return STRING; } +[A-Za-z_][A-Za-z0-9_]* { yylval.str = cstring(yytext); return IDENTIFIER; } +\"(\\.|[^\\"])*\" { yylval.str = cstring(yytext); return STRING; } "{" { BEGIN(NORMAL); return *yytext; } "{" { block_buffer = yytext; @@ -104,7 +104,7 @@ static std::string comment_block; "}" { block_buffer += *yytext; if (--block_depth <= 0) { yy_pop_state(); - yylval.str = block_buffer; + yylval.str = cstring(block_buffer); yylloc = block_start + yylloc; return BLOCK; } } "{" { block_buffer += *yytext; ++block_depth; } diff --git a/tools/ir-generator/ir-generator.ypp b/tools/ir-generator/ir-generator.ypp index 4e62067948..eab98c240b 100644 --- a/tools/ir-generator/ir-generator.ypp +++ b/tools/ir-generator/ir-generator.ypp @@ -58,6 +58,7 @@ static IrNamespace *current_namespace = LookupScope().resolve(0); %union { YYSTYPE() {} int i; + // FIXME: decide if this is a good idea to store all tokens inside cstring cache cstring str; IrClass *irClass; IrElement *irElement; @@ -71,6 +72,7 @@ static IrNamespace *current_namespace = LookupScope().resolve(0); NodeKind kind; struct { bool impl; + // FIXME: decide if this is a good idea to store all code blocks inside cstring cache cstring block; } emit; } @@ -130,9 +132,10 @@ symbol_print(FILE* file, int type, YYSTYPE value) #include "ir-generator-lex.c" #pragma GCC diagnostic pop +// FIXME: should receive string_view static cstring canon_name(cstring name) { /* canonical method names for backwards compatibility */ - if (name == "visitchildren") return "visit_children"; + if (name == "visitchildren") return "visit_children"_cs; return name; } @@ -278,16 +281,16 @@ method methodName : IDENTIFIER - | OPERATOR '=' '=' { $$ = "operator=="; } - | OPERATOR '!' '=' { $$ = "operator!="; } - | OPERATOR '<' '=' { $$ = "operator<="; } - | OPERATOR '>' '=' { $$ = "operator>="; } - | OPERATOR '<' { $$ = "operator<"; } - | OPERATOR '<' '<' { $$ = "operator<<"; } - | OPERATOR '>' { $$ = "operator>"; } - | OPERATOR '>' '>' { $$ = "operator>>"; } - | OPERATOR '*' { $$ = "operator*"; } - | OPERATOR '-' '>' { $$ = "operator->"; } + | OPERATOR '=' '=' { $$ = "operator=="_cs; } + | OPERATOR '!' '=' { $$ = "operator!="_cs; } + | OPERATOR '<' '=' { $$ = "operator<="_cs; } + | OPERATOR '>' '=' { $$ = "operator>="_cs; } + | OPERATOR '<' { $$ = "operator<"_cs; } + | OPERATOR '<' '<' { $$ = "operator<<"_cs; } + | OPERATOR '>' { $$ = "operator>"_cs; } + | OPERATOR '>' '>' { $$ = "operator>>"_cs; } + | OPERATOR '*' { $$ = "operator*"_cs; } + | OPERATOR '-' '>' { $$ = "operator->"_cs; } ; optArgList : argList | ; @@ -311,10 +314,10 @@ optOverride yyerror("syntax error, expecting override or method body"); } body: BLOCK - | '=' ZERO ';' { $$ = "= 0;"; } - | '=' DEFAULT ';' { $$ = "= default;"; } - | '=' DELETE ';' { $$ = "= delete;"; } - | ';' { $$ = nullptr; } + | '=' ZERO ';' { $$ = "= 0;"_cs; } + | '=' DEFAULT ';' { $$ = "= default;"_cs; } + | '=' DELETE ';' { $$ = "= delete;"_cs; } + | ';' { $$ = {}; } ; irField @@ -338,10 +341,10 @@ modifier modifiers : { $$ = 0; } | modifiers modifier { $$ = $1 | $2; } -fieldName: IDENTIFIER | OPTIONAL { $$ = "optional"; } ; +fieldName: IDENTIFIER | OPTIONAL { $$ = "optional"_cs; } ; optInitializer - : /* empty */ { $$ = nullptr; } + : /* empty */ { $$ = {}; } | '=' expression { $$ = $2; } | '=' BLOCK { $$ = $2; } ; @@ -354,7 +357,7 @@ lookup_scope nonRefType : IDENTIFIER { $$ = new NamedType(@1, 0, $1); } | lookup_scope IDENTIFIER { $$ = new NamedType(@2, $1, $2); } - | lookup_scope OPTIONAL { $$ = new NamedType(@2, $1, "optional"); } + | lookup_scope OPTIONAL { $$ = new NamedType(@2, $1, "optional"_cs); } | nonRefType '<' type_args '>' { $$ = new TemplateInstantiation(@1+@4, $1, *$3); } | nonRefType '[' INTEGER ']' { $$ = new ArrayType(@1+@4, $1, atoi($3)); } ; diff --git a/tools/ir-generator/irclass.cpp b/tools/ir-generator/irclass.cpp index 191e840fa6..d3b8dd9027 100644 --- a/tools/ir-generator/irclass.cpp +++ b/tools/ir-generator/irclass.cpp @@ -21,40 +21,40 @@ limitations under the License. const char *IrClass::indent = " "; IrNamespace &IrNamespace::global() { - static IrNamespace irn(nullptr, nullptr); + static IrNamespace irn({}, {}); return irn; } -static const LookupScope utilScope(nullptr, "Util"); -static const NamedType srcInfoType(Util::SourceInfo(), &utilScope, "SourceInfo"); +static const LookupScope utilScope(nullptr, "Util"_cs); +static const NamedType srcInfoType(Util::SourceInfo(), &utilScope, "SourceInfo"_cs); IrField *IrField::srcInfoField() { - static IrField irf(Util::SourceInfo(), &srcInfoType, "srcInfo", nullptr, + static IrField irf(Util::SourceInfo(), &srcInfoType, "srcInfo"_cs, {}, IrField::Inline | IrField::Optional); return &irf; } IrClass *IrClass::nodeClass() { - static IrClass irc(NodeKind::Abstract, "Node", {IrField::srcInfoField()}); + static IrClass irc(NodeKind::Abstract, "Node"_cs, {IrField::srcInfoField()}); return &irc; } IrClass *IrClass::vectorClass() { - static IrClass irc(NodeKind::Template, "Vector"); + static IrClass irc(NodeKind::Template, "Vector"_cs); return &irc; } IrClass *IrClass::namemapClass() { - static IrClass irc(NodeKind::Template, "NameMap"); + static IrClass irc(NodeKind::Template, "NameMap"_cs); return &irc; } IrClass *IrClass::nodemapClass() { - static IrClass irc(NodeKind::Template, "NodeMap"); + static IrClass irc(NodeKind::Template, "NodeMap"_cs); return &irc; } IrClass *IrClass::ideclaration() { - static IrClass irc(NodeKind::Interface, "IDeclaration"); + static IrClass irc(NodeKind::Interface, "IDeclaration"_cs); return &irc; } IrClass *IrClass::indexedVectorClass() { - static IrClass irc(NodeKind::Template, "IndexedVector"); + static IrClass irc(NodeKind::Template, "IndexedVector"_cs); return &irc; } bool LineDirective::inhibit = false; @@ -134,6 +134,7 @@ void IrDefinitions::generate(std::ostream &t, std::ostream &out, std::ostream &i << std::endl << "namespace IR {\n" << "extern std::map unpacker_table;\n" + << "using namespace P4::literals;\n" << "}\n"; impl << "std::map IR::unpacker_table = {\n"; @@ -145,7 +146,7 @@ void IrDefinitions::generate(std::ostream &t, std::ostream &out, std::ostream &i first = false; else impl << ",\n"; - impl << "{\"" << cls->name << "\", NodeFactoryFn(&IR::"; + impl << "{\"" << cls->name << "\"_cs, NodeFactoryFn(&IR::"; if (cls->containedIn && cls->containedIn->name) impl << cls->containedIn->name << "::"; impl << cls->name << "::fromJSON)}"; } @@ -235,9 +236,9 @@ void IrDefinitions::generate(std::ostream &t, std::ostream &out, std::ostream &i << " Node = 2,\n"; unsigned nkId = 3; - auto *irNamespace = IrNamespace::get(nullptr, "IR"); + auto *irNamespace = IrNamespace::get(nullptr, "IR"_cs); for (auto *cls : *getClasses()) - t << " " << cls->qualified_name(irNamespace).replace("::", "_") << " = " << nkId++ + t << " " << cls->qualified_name(irNamespace).replace("::"_cs, "_"_cs) << " = " << nkId++ << ",\n"; // Add some specials: @@ -374,14 +375,14 @@ std::string IrClass::fullName() const { } cstring IrNamespace::qualified_name(const IrNamespace *in) const { - cstring rv = name ? name : "IR"; + cstring rv = name ? name : "IR"_cs; if (parent) { for (auto i = in; i; i = i->parent) { auto sym = i->lookupChild(name); if (sym && this != sym) break; if (parent == i) return rv; } - rv = parent->qualified_name(in) + "::" + rv; + rv = parent->qualified_name(in) + "::"_cs + rv; } return rv; } @@ -394,7 +395,7 @@ cstring IrClass::qualified_name(const IrNamespace *in) const { if (sym && this != sym) break; if (containedIn == i) return rv; } - rv = containedIn->qualified_name(in) + "::" + rv; + rv = containedIn->qualified_name(in) + "::"_cs + rv; } return rv; } @@ -439,10 +440,10 @@ void IrClass::generate_hdr(std::ostream &out) const { out << indent << "IRNODE" << (kind == NodeKind::Abstract ? "_ABSTRACT" : "") << "_SUBCLASS(" << name << ")" << std::endl; - auto *irNamespace = IrNamespace::get(nullptr, "IR"); + auto *irNamespace = IrNamespace::get(nullptr, "IR"_cs); if (kind != NodeKind::Nested) { out << indent << "DECLARE_TYPEINFO_WITH_TYPEID(" << name - << ", NodeKind::" << qualified_name(irNamespace).replace("::", "_"); + << ", NodeKind::" << qualified_name(irNamespace).replace("::"_cs, "_"_cs); if (!concreteParent) out << ", " << (kind != NodeKind::Interface ? "Node" : "INode"); for (const auto *p : parentClasses) out << ", " << p->qualified_name(containedIn); out << ");" << std::endl; @@ -494,9 +495,9 @@ int IrClass::generateConstructor(const ctor_args_t &arglist, const IrMethod *use if (arg.second == this) { body << end_parent; end_parent = ""; - } else if (parent) { + } else if (!parent.isNullOrEmpty()) { body << sep << parent; - parent = nullptr; + parent = ""_cs; sep = "("; end_parent = ")"; } @@ -651,10 +652,10 @@ void IrField::generate_impl(std::ostream &) const { void ConstFieldInitializer::generate_hdr(std::ostream &out) const { out << IrClass::indent; if (name == "precedence") - out << "int getPrecedence() const override { return "; + out << "int getPrecedence() const override { return " << initializer << "; }" << std::endl; else if (name == "stringOp") - out << "cstring getStringOp() const override { return "; + out << "cstring getStringOp() const override { return cstring(" << initializer << "); }" + << std::endl; else throw Util::CompilationError("Unexpected constant field %1%", this); - out << initializer << "; }" << std::endl; } diff --git a/tools/ir-generator/irclass.h b/tools/ir-generator/irclass.h index ddeb7ffc6d..214d04efa9 100644 --- a/tools/ir-generator/irclass.h +++ b/tools/ir-generator/irclass.h @@ -33,6 +33,8 @@ limitations under the License. class IrClass; class IrField; +using namespace P4::literals; + class IrNamespace { std::map classes; std::map children; @@ -190,7 +192,7 @@ class IrNo : public IrElement { IrNo(Util::SourceInfo info, cstring text) : IrElement(info), text(text) {} void generate_hdr(std::ostream &) const override {} void generate_impl(std::ostream &) const override {} - cstring toString() const override { return "#no" + text; } + cstring toString() const override { return "#no"_cs + text; } }; class IrApply : public IrElement { @@ -198,7 +200,7 @@ class IrApply : public IrElement { explicit IrApply(Util::SourceInfo info) : IrElement(info) {} void generate_hdr(std::ostream &out) const override; void generate_impl(std::ostream &out) const override; - cstring toString() const override { return "#apply"; } + cstring toString() const override { return "#apply"_cs; } }; enum class NodeKind { @@ -229,7 +231,7 @@ class CommentBlock : public IrElement { cstring toString() const override { // print only Doxygen comments if (body.startsWith("/**") || body.startsWith("///")) return body; - return ""; + return ""_cs; } void append(cstring comment) { body += "\n" + comment; } void generate_hdr(std::ostream &out) const override { out << toString() << std::endl; }; diff --git a/tools/ir-generator/methods.cpp b/tools/ir-generator/methods.cpp index 03a5c417c1..a75ad86b1a 100644 --- a/tools/ir-generator/methods.cpp +++ b/tools/ir-generator/methods.cpp @@ -34,7 +34,7 @@ enum flags { }; const ordered_map IrMethod::Generate = { - {"operator==", + {"operator=="_cs, {&NamedType::Bool(), {}, CONST + IN_IMPL + INCL_NESTED + OVERRIDE + CLASSREF, @@ -71,9 +71,9 @@ const ordered_map IrMethod::Generate = { buf << cl->indent << "}"; return buf.str(); }}}, - {"equiv", + {"equiv"_cs, {&NamedType::Bool(), - {new IrField(new ReferenceType(new NamedType(IrClass::nodeClass()), true), "a_")}, + {new IrField(new ReferenceType(new NamedType(IrClass::nodeClass()), true), "a_"_cs)}, EXTEND + CONST + IN_IMPL + OVERRIDE, [](IrClass *cl, Util::SourceInfo srcInfo, cstring body) -> cstring { std::stringstream buf; @@ -126,9 +126,9 @@ const ordered_map IrMethod::Generate = { buf << cl->indent << "}"; return buf.str(); }}}, - {"operator<<", + {"operator<<"_cs, {&ReferenceType::OstreamRef, - {new IrField(&ReferenceType::OstreamRef, "out")}, + {new IrField(&ReferenceType::OstreamRef, "out"_cs)}, EXTEND + IN_IMPL + NOT_DEFAULT + INCL_NESTED + CLASSREF + FRIEND, [](IrClass *cl, Util::SourceInfo srcInfo, cstring body) -> cstring { std::stringstream buf; @@ -137,9 +137,9 @@ const ordered_map IrMethod::Generate = { buf << LineDirective(true) << cl->indent << "return out; }"; return buf.str(); }}}, - {"visit_children", + {"visit_children"_cs, {&NamedType::Void(), - {new IrField(&ReferenceType::VisitorRef, "v")}, + {new IrField(&ReferenceType::VisitorRef, "v"_cs)}, IN_IMPL + OVERRIDE, [](IrClass *cl, Util::SourceInfo, cstring) -> cstring { bool needed = false; @@ -162,7 +162,7 @@ const ordered_map IrMethod::Generate = { buf << "}"; return needed ? buf.str() : cstring(); }}}, - {"validate", + {"validate"_cs, {&NamedType::Void(), {}, CONST + IN_IMPL + EXTEND + OVERRIDE, @@ -189,23 +189,23 @@ const ordered_map IrMethod::Generate = { buf << " }"; return needed ? buf.str() : cstring(); }}}, - {"node_type_name", + {"node_type_name"_cs, {&NamedType::Cstring(), {}, CONST + OVERRIDE, [](IrClass *cl, Util::SourceInfo, cstring) -> cstring { std::stringstream buf; - buf << "{ return \"" << cl->containedIn << cl->name << "\"; }"; + buf << "{ return \"" << cl->containedIn << cl->name << "\"_cs; }"; return buf.str(); }}}, - {"dbprint", + {"dbprint"_cs, {&NamedType::Void(), - {new IrField(&ReferenceType::OstreamRef, "out")}, + {new IrField(&ReferenceType::OstreamRef, "out"_cs)}, CONST + IN_IMPL + OVERRIDE + CONCRETE_ONLY, - [](IrClass *, Util::SourceInfo, cstring) -> cstring { return ""; }}}, - {"dump_fields", + [](IrClass *, Util::SourceInfo, cstring) -> cstring { return ""_cs; }}}, + {"dump_fields"_cs, {&NamedType::Void(), - {new IrField(&ReferenceType::OstreamRef, "out")}, + {new IrField(&ReferenceType::OstreamRef, "out"_cs)}, CONST + IN_IMPL + OVERRIDE, [](IrClass *cl, Util::SourceInfo, cstring) -> cstring { std::stringstream buf; @@ -227,9 +227,9 @@ const ordered_map IrMethod::Generate = { buf << "}"; return needed ? buf.str() : cstring(); }}}, - {"toJSON", + {"toJSON"_cs, {&NamedType::Void(), - {new IrField(new ReferenceType(&NamedType::JSONGenerator()), "json")}, + {new IrField(new ReferenceType(&NamedType::JSONGenerator()), "json"_cs)}, CONST + IN_IMPL + OVERRIDE + INCL_NESTED, [](IrClass *cl, Util::SourceInfo, cstring) -> cstring { std::stringstream buf; @@ -249,7 +249,7 @@ const ordered_map IrMethod::Generate = { }}}, {nullptr, {nullptr, - {new IrField(new ReferenceType(&NamedType::JSONLoader()), "json")}, + {new IrField(new ReferenceType(&NamedType::JSONLoader()), "json"_cs)}, IN_IMPL + CONSTRUCTOR + INCL_NESTED, [](IrClass *cl, Util::SourceInfo, cstring) -> cstring { std::stringstream buf; @@ -264,10 +264,10 @@ const ordered_map IrMethod::Generate = { buf << "}"; return buf.str(); }}}, - {"fromJSON", + {"fromJSON"_cs, {nullptr, { - new IrField(new ReferenceType(&NamedType::JSONLoader()), "json"), + new IrField(new ReferenceType(&NamedType::JSONLoader()), "json"_cs), }, FACTORY + IN_IMPL + CONCRETE_ONLY + INCL_NESTED, [](IrClass *cl, Util::SourceInfo, cstring) -> cstring { @@ -275,7 +275,7 @@ const ordered_map IrMethod::Generate = { buf << "{ return new " << cl->name << "(json); }"; return buf.str(); }}}, - {"toString", + {"toString"_cs, {&NamedType::Cstring(), {}, CONST + IN_IMPL + OVERRIDE + NOT_DEFAULT, @@ -314,19 +314,19 @@ void IrClass::generateMethods() { auto *m = new IrMethod(def.first, body); if (def.second.flags & FRIEND) m->isFriend = true; m->clss = this; - if (!(def.second.flags & CONSTRUCTOR) || !shouldSkip("method_constructor")) { + if (!(def.second.flags & CONSTRUCTOR) || !shouldSkip("method_constructor"_cs)) { elements.push_back(m); } } } } for (auto *parent = getParent(); parent; parent = parent->getParent()) { - auto eq_overload = new IrMethod("operator==", "{ return a == *this; }"); + auto eq_overload = new IrMethod("operator=="_cs, "{ return a == *this; }"_cs); eq_overload->clss = this; eq_overload->isOverride = true; eq_overload->rtype = &NamedType::Bool(); eq_overload->args.push_back( - new IrField(new ReferenceType(new NamedType(parent), true), "a")); + new IrField(new ReferenceType(new NamedType(parent), true), "a"_cs)); eq_overload->isConst = true; elements.push_back(eq_overload); } @@ -371,14 +371,14 @@ void IrClass::generateMethods() { } m->args = info.args; if (info.flags & CLASSREF) - m->args.push_back(new IrField(new ReferenceType(new NamedType(this), true), "a")); + m->args.push_back(new IrField(new ReferenceType(new NamedType(this), true), "a"_cs)); if (info.flags & IN_IMPL) m->inImpl = true; if (info.flags & CONST) m->isConst = true; if ((info.flags & OVERRIDE) && kind != NodeKind::Nested) m->isOverride = true; if (info.flags & FACTORY) m->isStatic = true; } if (ctor) elements.erase(find(elements, ctor)); - if (kind != NodeKind::Interface && !shouldSkip("constructor")) { + if (kind != NodeKind::Interface && !shouldSkip("constructor"_cs)) { ctor_args_t args; computeConstructorArguments(args); if (!user_defined_default_ctor || !args.empty()) { diff --git a/tools/ir-generator/type.cpp b/tools/ir-generator/type.cpp index 036ba9cee2..ec3fec9b38 100644 --- a/tools/ir-generator/type.cpp +++ b/tools/ir-generator/type.cpp @@ -71,63 +71,63 @@ const IrClass *NamedType::resolve(const IrNamespace *in) const { } NamedType &NamedType::Bool() { - static NamedType nt("bool"); + static NamedType nt("bool"_cs); return nt; } NamedType &NamedType::Int() { - static NamedType nt("int"); + static NamedType nt("int"_cs); return nt; } NamedType &NamedType::Void() { - static NamedType nt("void"); + static NamedType nt("void"_cs); return nt; } NamedType &NamedType::Cstring() { - static NamedType nt("cstring"); + static NamedType nt("cstring"_cs); return nt; } NamedType &NamedType::Ostream() { - static NamedType nt(new LookupScope("std"), "ostream"); + static NamedType nt(new LookupScope("std"_cs), "ostream"_cs); return nt; } NamedType &NamedType::Visitor() { - static NamedType nt("Visitor"); + static NamedType nt("Visitor"_cs); return nt; } NamedType &NamedType::Unordered_Set() { - static NamedType nt(new LookupScope("std"), "unordered_set"); + static NamedType nt(new LookupScope("std"_cs), "unordered_set"_cs); return nt; } NamedType &NamedType::JSONGenerator() { - static NamedType nt("JSONGenerator"); + static NamedType nt("JSONGenerator"_cs); return nt; } NamedType &NamedType::JSONLoader() { - static NamedType nt("JSONLoader"); + static NamedType nt("JSONLoader"_cs); return nt; } NamedType &NamedType::JSONObject() { - static NamedType nt("JSONObject"); + static NamedType nt("JSONObject"_cs); return nt; } NamedType &NamedType::SourceInfo() { - static NamedType nt(new LookupScope("Util"), "SourceInfo"); + static NamedType nt(new LookupScope("Util"_cs), "SourceInfo"_cs); return nt; } cstring NamedType::toString() const { if (resolved) return resolved->fullName(); - if (!lookup && name == "ID") return "IR::ID"; // hack -- ID is in namespace IR + if (!lookup && name == "ID") return "IR::ID"_cs; // hack -- ID is in namespace IR if (lookup) return lookup->toString() + name; if (foundin) return LookupScope(foundin).toString() + name; return name; @@ -137,7 +137,7 @@ cstring TemplateInstantiation::toString() const { std::string rv = base->toString().c_str(); rv += '<'; const char *sep = ""; - for (auto arg : args) { + for (const auto *arg : args) { rv += sep; if (arg->isResolved() && !base->isResolved()) rv += "const "; rv += arg->toString().c_str(); @@ -149,7 +149,7 @@ cstring TemplateInstantiation::toString() const { } cstring ReferenceType::toString() const { - cstring rv = base->toString(); + std::string rv = base->toString().c_str(); if (isConst) rv += " const"; rv += " &"; return rv; @@ -159,7 +159,7 @@ ReferenceType ReferenceType::OstreamRef(&NamedType::Ostream()), ReferenceType::V &NamedType::Visitor()); cstring PointerType::toString() const { - cstring rv = base->toString(); + std::string rv = base->toString().c_str(); if (isConst) rv += " const"; rv += " *"; return rv; @@ -168,7 +168,7 @@ cstring PointerType::toString() const { cstring ArrayType::declSuffix() const { char buf[16]; snprintf(buf, sizeof(buf), "[%d]", size); - return buf; + return cstring(buf); } const IrClass *FunctionType::resolve(const IrNamespace *ns) const { @@ -178,10 +178,10 @@ const IrClass *FunctionType::resolve(const IrNamespace *ns) const { } cstring FunctionType::toString() const { - cstring result = ret->toString(); + std::string result = ret->toString().c_str(); result += "("; const char *sep = ""; - for (auto arg : args) { + for (const auto *arg : args) { result += sep; if (arg->isResolved()) result += "const "; result += arg->toString().c_str(); diff --git a/tools/ir-generator/type.h b/tools/ir-generator/type.h index 7512040d73..58af07b429 100644 --- a/tools/ir-generator/type.h +++ b/tools/ir-generator/type.h @@ -25,6 +25,8 @@ limitations under the License. class IrClass; class IrNamespace; +using namespace P4::literals; + #define ALL_TYPES(M) \ M(NamedType) \ M(TemplateInstantiation) M(ReferenceType) M(PointerType) M(ArrayType) M(FunctionType) @@ -41,7 +43,7 @@ class Type : public Util::IHasSourceInfo { Util::SourceInfo getSourceInfo() const override { return srcInfo; } virtual const IrClass *resolve(const IrNamespace *) const = 0; virtual bool isResolved() const = 0; - virtual cstring declSuffix() const { return ""; } + virtual cstring declSuffix() const { return ""_cs; } virtual bool operator==(const Type &) const = 0; bool operator!=(const Type &t) const { return !operator==(t); } #define OP_EQUALS(T) \ @@ -62,8 +64,8 @@ struct LookupScope : public Util::IHasSourceInfo { Util::SourceInfo getSourceInfo() const override { return srcInfo; } cstring toString() const override { - if (global) return "IR::"; - return (in ? in->toString() + name : name) + "::"; + if (global) return "IR::"_cs; + return (in ? in->toString() + name : name) + "::"_cs; } IrNamespace *resolve(const IrNamespace *) const; bool operator==(const LookupScope &l) const { From 8d6bb9d83d00756c492b06ddb2ed8d0f913aabf5 Mon Sep 17 00:00:00 2001 From: Fabian Ruffy <5960321+fruffy@users.noreply.github.com> Date: Fri, 7 Jun 2024 15:37:23 +0200 Subject: [PATCH 3/5] Add P4Smith, a random program generator to the P4Tools framework (#4182) * Add Smith. * Cstrings. --- backends/p4tools/README.md | 11 +- backends/p4tools/common/lib/util.cpp | 41 +- backends/p4tools/common/lib/util.h | 11 +- backends/p4tools/common/p4ctool.h | 3 +- backends/p4tools/modules/smith/CMakeLists.txt | 84 ++ backends/p4tools/modules/smith/README.md | 79 ++ .../modules/smith/common/declarations.cpp | 749 ++++++++++ .../modules/smith/common/declarations.h | 86 ++ .../modules/smith/common/expressions.cpp | 1246 +++++++++++++++++ .../modules/smith/common/expressions.h | 119 ++ .../p4tools/modules/smith/common/generator.h | 20 + .../p4tools/modules/smith/common/parser.cpp | 271 ++++ .../p4tools/modules/smith/common/parser.h | 35 + .../modules/smith/common/probabilities.h | 328 +++++ .../p4tools/modules/smith/common/scope.cpp | 342 +++++ backends/p4tools/modules/smith/common/scope.h | 124 ++ .../modules/smith/common/statements.cpp | 391 ++++++ .../p4tools/modules/smith/common/statements.h | 44 + .../p4tools/modules/smith/common/table.cpp | 159 +++ backends/p4tools/modules/smith/common/table.h | 37 + .../p4tools/modules/smith/core/target.cpp | 15 + backends/p4tools/modules/smith/core/target.h | 42 + backends/p4tools/modules/smith/main.cpp | 45 + backends/p4tools/modules/smith/options.cpp | 45 + backends/p4tools/modules/smith/options.h | 25 + backends/p4tools/modules/smith/register.h.in | 13 + .../modules/smith/scripts/compilation-test.sh | 53 + backends/p4tools/modules/smith/smith.cpp | 93 ++ backends/p4tools/modules/smith/smith.h | 25 + .../modules/smith/targets/bmv2/CMakeLists.txt | 16 + .../modules/smith/targets/bmv2/psa.cpp | 442 ++++++ .../p4tools/modules/smith/targets/bmv2/psa.h | 61 + .../modules/smith/targets/bmv2/register.h | 16 + .../modules/smith/targets/bmv2/target.cpp | 18 + .../modules/smith/targets/bmv2/target.h | 16 + .../smith/targets/bmv2/test/P4Tests.cmake | 13 + .../modules/smith/targets/bmv2/v1model.cpp | 385 +++++ .../modules/smith/targets/bmv2/v1model.h | 61 + .../smith/targets/generic/CMakeLists.txt | 14 + .../modules/smith/targets/generic/register.h | 12 + .../modules/smith/targets/generic/target.cpp | 225 +++ .../modules/smith/targets/generic/target.h | 68 + .../smith/targets/generic/test/P4Tests.cmake | 10 + .../modules/smith/targets/nic/CMakeLists.txt | 14 + .../modules/smith/targets/nic/register.h | 12 + .../modules/smith/targets/nic/target.cpp | 318 +++++ .../modules/smith/targets/nic/target.h | 65 + .../smith/targets/nic/test/P4Tests.cmake | 10 + .../smith/targets/tofino/CMakeLists.txt | 14 + .../modules/smith/targets/tofino/register.h | 12 + .../modules/smith/targets/tofino/target.cpp | 619 ++++++++ .../modules/smith/targets/tofino/target.h | 67 + .../smith/targets/tofino/test/P4Tests.cmake | 7 + backends/p4tools/modules/smith/toolname.h | 12 + backends/p4tools/modules/smith/util/util.cpp | 61 + backends/p4tools/modules/smith/util/util.h | 25 + .../p4tools/modules/smith/util/wordlist.cpp | 703 ++++++++++ .../p4tools/modules/smith/util/wordlist.h | 32 + .../p4tools/modules/smith/version.h.cmake | 39 + backends/p4tools/modules/testgen/README.md | 6 + 60 files changed, 7897 insertions(+), 12 deletions(-) create mode 100644 backends/p4tools/modules/smith/CMakeLists.txt create mode 100644 backends/p4tools/modules/smith/README.md create mode 100644 backends/p4tools/modules/smith/common/declarations.cpp create mode 100644 backends/p4tools/modules/smith/common/declarations.h create mode 100644 backends/p4tools/modules/smith/common/expressions.cpp create mode 100644 backends/p4tools/modules/smith/common/expressions.h create mode 100644 backends/p4tools/modules/smith/common/generator.h create mode 100644 backends/p4tools/modules/smith/common/parser.cpp create mode 100644 backends/p4tools/modules/smith/common/parser.h create mode 100644 backends/p4tools/modules/smith/common/probabilities.h create mode 100644 backends/p4tools/modules/smith/common/scope.cpp create mode 100644 backends/p4tools/modules/smith/common/scope.h create mode 100644 backends/p4tools/modules/smith/common/statements.cpp create mode 100644 backends/p4tools/modules/smith/common/statements.h create mode 100644 backends/p4tools/modules/smith/common/table.cpp create mode 100644 backends/p4tools/modules/smith/common/table.h create mode 100644 backends/p4tools/modules/smith/core/target.cpp create mode 100644 backends/p4tools/modules/smith/core/target.h create mode 100644 backends/p4tools/modules/smith/main.cpp create mode 100644 backends/p4tools/modules/smith/options.cpp create mode 100644 backends/p4tools/modules/smith/options.h create mode 100644 backends/p4tools/modules/smith/register.h.in create mode 100755 backends/p4tools/modules/smith/scripts/compilation-test.sh create mode 100644 backends/p4tools/modules/smith/smith.cpp create mode 100644 backends/p4tools/modules/smith/smith.h create mode 100644 backends/p4tools/modules/smith/targets/bmv2/CMakeLists.txt create mode 100644 backends/p4tools/modules/smith/targets/bmv2/psa.cpp create mode 100644 backends/p4tools/modules/smith/targets/bmv2/psa.h create mode 100644 backends/p4tools/modules/smith/targets/bmv2/register.h create mode 100644 backends/p4tools/modules/smith/targets/bmv2/target.cpp create mode 100644 backends/p4tools/modules/smith/targets/bmv2/target.h create mode 100644 backends/p4tools/modules/smith/targets/bmv2/test/P4Tests.cmake create mode 100644 backends/p4tools/modules/smith/targets/bmv2/v1model.cpp create mode 100644 backends/p4tools/modules/smith/targets/bmv2/v1model.h create mode 100644 backends/p4tools/modules/smith/targets/generic/CMakeLists.txt create mode 100644 backends/p4tools/modules/smith/targets/generic/register.h create mode 100644 backends/p4tools/modules/smith/targets/generic/target.cpp create mode 100644 backends/p4tools/modules/smith/targets/generic/target.h create mode 100644 backends/p4tools/modules/smith/targets/generic/test/P4Tests.cmake create mode 100644 backends/p4tools/modules/smith/targets/nic/CMakeLists.txt create mode 100644 backends/p4tools/modules/smith/targets/nic/register.h create mode 100644 backends/p4tools/modules/smith/targets/nic/target.cpp create mode 100644 backends/p4tools/modules/smith/targets/nic/target.h create mode 100644 backends/p4tools/modules/smith/targets/nic/test/P4Tests.cmake create mode 100644 backends/p4tools/modules/smith/targets/tofino/CMakeLists.txt create mode 100644 backends/p4tools/modules/smith/targets/tofino/register.h create mode 100644 backends/p4tools/modules/smith/targets/tofino/target.cpp create mode 100644 backends/p4tools/modules/smith/targets/tofino/target.h create mode 100644 backends/p4tools/modules/smith/targets/tofino/test/P4Tests.cmake create mode 100644 backends/p4tools/modules/smith/toolname.h create mode 100644 backends/p4tools/modules/smith/util/util.cpp create mode 100644 backends/p4tools/modules/smith/util/util.h create mode 100644 backends/p4tools/modules/smith/util/wordlist.cpp create mode 100644 backends/p4tools/modules/smith/util/wordlist.h create mode 100644 backends/p4tools/modules/smith/version.h.cmake diff --git a/backends/p4tools/README.md b/backends/p4tools/README.md index 1dc194160c..dc5a5a3f15 100644 --- a/backends/p4tools/README.md +++ b/backends/p4tools/README.md @@ -6,13 +6,13 @@ p4tools ├─ cmake ── common P4Tools CMake modules. ├─ common ── common code for the various P4Tools modules. - │ └─ compiler ── transformation passes for P4 code. - │ └─ control_plane ── code concerning P4Tool's control plane semantics. - │ └─ core ── definitions for core parts of the P4Tools modules. + │ ├─ compiler ── transformation passes for P4 code. + │ ├─ control_plane ── code concerning P4Tool's control plane semantics. + │ ├─ core ── definitions for core parts of the P4Tools modules. │ └─ lib ── helper functions and utilities for P4Tools modules. └─ modules ── P4Tools extensions. + ├─ smith ── P4Smith: a random P4 program generator. └─ testgen ── P4Testgen: a test-case generator for P4 programs. - ``` ## P4Tools @@ -20,6 +20,8 @@ P4Tools is a collection of tools that make testing P4 targets and programs a lit - [P4Testgen](https://github.com/p4lang/p4c/tree/main/backends/p4tools/modules/testgen): An input-output test case generator for P4. +- [P4Smith](https://github.com/p4lang/p4c/tree/main/backends/p4tools/modules/smith): A random P4 program generator in the spirit of Csmith. + ## Building Please see the general installation instructions [here](https://github.com/p4lang/p4c#installing-p4c-from-source). P4Tools can be built using the following CMAKE configuration in the P4C repository. @@ -31,7 +33,6 @@ make ``` ## Dependencies -* [inja](https://github.com/pantor/inja) template engine for testcase generation. * [z3](https://github.com/Z3Prover/z3) SMT solver to compute path constraints. * Important: We currently only support Z3 versions 4.8.14 to 4.12.0. diff --git a/backends/p4tools/common/lib/util.cpp b/backends/p4tools/common/lib/util.cpp index c6b6a5df08..3155e917ee 100644 --- a/backends/p4tools/common/lib/util.cpp +++ b/backends/p4tools/common/lib/util.cpp @@ -4,8 +4,8 @@ #include #include #include +#include #include -#include #include #include @@ -64,7 +64,30 @@ uint64_t Utils::getRandInt(uint64_t max) { return dist(rng); } -big_int Utils::getRandBigInt(big_int max) { +int64_t Utils::getRandInt(int64_t min, int64_t max) { + boost::random::uniform_int_distribution distribution(min, max); + return distribution(rng); +} + +int64_t Utils::getRandInt(const std::vector &percent) { + int sum = std::accumulate(percent.begin(), percent.end(), 0); + + // Do not pick zero since that conflicts with zero percentage values. + auto randNum = getRandInt(1, sum); + int ret = 0; + + int64_t retSum = 0; + for (auto i : percent) { + retSum += i; + if (retSum >= randNum) { + break; + } + ret = ret + 1; + } + return ret; +} + +big_int Utils::getRandBigInt(const big_int &max) { if (!currentSeed) { return 0; } @@ -72,6 +95,14 @@ big_int Utils::getRandBigInt(big_int max) { return dist(rng); } +big_int Utils::getRandBigInt(const big_int &min, const big_int &max) { + if (!currentSeed) { + return 0; + } + boost::random::uniform_int_distribution dist(min, max); + return dist(rng); +} + const IR::Constant *Utils::getRandConstantForWidth(int bitWidth) { auto maxVal = IR::getMaxBvVal(bitWidth); auto randInt = Utils::getRandBigInt(maxVal); @@ -145,8 +176,10 @@ std::vector argumentsToTypeDeclarations( const IR::IDeclaration *findProgramDecl(const IR::IGeneralNamespace *ns, const IR::Path *path) { auto name = path->name.name; - auto *decl = ns->getDeclsByName(name)->singleOrDefault(); - if (decl != nullptr) return decl; + const auto *decl = ns->getDeclsByName(name)->singleOrDefault(); + if (decl != nullptr) { + return decl; + } BUG("Variable %1% not found in the available namespaces.", path); } diff --git a/backends/p4tools/common/lib/util.h b/backends/p4tools/common/lib/util.h index b007fb67cf..f7a8f032aa 100644 --- a/backends/p4tools/common/lib/util.h +++ b/backends/p4tools/common/lib/util.h @@ -70,9 +70,18 @@ class Utils { /// @returns a random integer in the range [0, @param max]. Always return 0 if no seed is set. static uint64_t getRandInt(uint64_t max); + /// @returns a random integer between min and max. + static int64_t getRandInt(int64_t min, int64_t max); + + /// @returns a random integer based on the percent vector. + static int64_t getRandInt(const std::vector &percent); + /// @returns a random big integer in the range [0, @param max]. Always return 0 if no seed is /// set. - static big_int getRandBigInt(big_int max); + static big_int getRandBigInt(const big_int &max); + + /// This is a big_int version of getRndInt. + static big_int getRandBigInt(const big_int &min, const big_int &max); /// @returns a IR::Constant with a random big integer that fits the specified bit width. /// The type will be an unsigned Type_Bits with @param bitWidth. diff --git a/backends/p4tools/common/p4ctool.h b/backends/p4tools/common/p4ctool.h index 3d67d7bb0b..e40bb718b0 100644 --- a/backends/p4tools/common/p4ctool.h +++ b/backends/p4tools/common/p4ctool.h @@ -38,12 +38,11 @@ class AbstractP4cTool { auto &toolOptions = Options::get(); auto compileContext = toolOptions.process(args); if (!compileContext) { - return 1; + return EXIT_FAILURE; } // Set up the compilation context. AutoCompileContext autoContext(*compileContext); - // If not explicitly disabled, print basic information to standard output. if (!toolOptions.disableInformationLogging) { enableInformationLogging(); diff --git a/backends/p4tools/modules/smith/CMakeLists.txt b/backends/p4tools/modules/smith/CMakeLists.txt new file mode 100644 index 0000000000..83411dbe96 --- /dev/null +++ b/backends/p4tools/modules/smith/CMakeLists.txt @@ -0,0 +1,84 @@ +# CMake file for P4Smith. + +include(common) + +project(smith) + +# Declare common P4Testgen variables. +set(P4SMITH_DIR ${P4C_BINARY_DIR}/smith) +set(P4SMITH_DRIVER "${CMAKE_CURRENT_BINARY_DIR}/p4smith") + +configure_file( + "${CMAKE_CURRENT_SOURCE_DIR}/version.h.cmake" "${CMAKE_CURRENT_BINARY_DIR}/version.h" @ONLY +) +# Source files for smith. +set(SMITH_SOURCES + core/target.cpp + common/declarations.cpp + common/expressions.cpp + common/parser.cpp + common/scope.cpp + common/statements.cpp + common/table.cpp + util/util.cpp + util/wordlist.cpp + options.cpp + smith.cpp +) + +set(SMITH_LIBS + PRIVATE p4tools-common +) + +file(GLOB tools_targets RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/targets + ${CMAKE_CURRENT_SOURCE_DIR}/targets/* +) + +foreach(ext ${tools_targets}) + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/targets/${ext}/CMakeLists.txt) + # Generate an option that makes it possible to disable this extension. + string(MAKE_C_IDENTIFIER ${ext} EXT_AS_IDENTIFIER) + string(TOUPPER ${EXT_AS_IDENTIFIER} EXT_AS_OPTION_NAME) + string(CONCAT ENABLE_EXT_OPTION "ENABLE_TOOLS_TARGET_" ${EXT_AS_OPTION_NAME}) + string(CONCAT EXT_HELP_TEXT "Build the " ${ext} " target") + option(${ENABLE_EXT_OPTION} ${EXT_HELP_TEXT} ON) + if(${ENABLE_EXT_OPTION}) + message("-- Enabling target ${ext}") + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/targets/${ext}) + set(include_statements_var + "${include_statements_var}#include \"backends/p4tools/modules/smith/targets/${ext}/register.h\"\n" + ) + set(smith_targets_var "${smith_targets_var} ${ext}RegisterSmithTarget();\n") + endif() + endif() +endforeach(ext) + +# Fill the template +configure_file(register.h.in register.h) + +add_library(smith ${SMITH_SOURCES}) +target_link_libraries(smith + ${SMITH_LIBS} + # For Abseil includes. + PRIVATE frontend +) + +add_dependencies(smith p4tools-common) + +add_p4tools_executable(p4smith main.cpp) + +target_link_libraries( + p4smith + PRIVATE smith + ${SMITH_LIBS} + PRIVATE ${P4C_LIBRARIES} + PRIVATE ${P4C_LIB_DEPS} +) + +add_custom_target( + linkp4smith # Add some convenience links for invoking p4smith. + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4smith + ${CMAKE_BINARY_DIR}/p4smith +) + +add_dependencies(p4smith linkp4smith) diff --git a/backends/p4tools/modules/smith/README.md b/backends/p4tools/modules/smith/README.md new file mode 100644 index 0000000000..8dfc4b047a --- /dev/null +++ b/backends/p4tools/modules/smith/README.md @@ -0,0 +1,79 @@ +[![Status](https://github.com/p4lang/p4c/actions/workflows/ci-p4tools.yml/badge.svg)](https://github.com/p4lang/p4c/actions/workflows/ci-p4tools.yml) + +# P4Smith + +## Table of Contents + +- [Installation](#installation) +- [Extensions](#extensions) +- [Usage](#usage) +- [Limitations](#limitations) +- [Further Reading](#further-reading) +- [Contributing](#contributing) +- [License](#license) + +P4Smith is an extensible random P4 program generator in the spirit of [CSmith](https://en.wikipedia.org/wiki/Csmith). P4Smith generates random, but valid P4 programs for various P4 targets, for example the [v1model.p4](https://github.com/p4lang/behavioral-model/blob/main/docs/simple_switch.md) architecture on [BMv2](https://github.com/p4lang/behavioral-model) or `tna.p4` running on Tofino 1. P4Smiths generates programs that are valid according to the latest version of the (P4 specification)[https://p4.org/p4-spec/docs/P4-16-working-spec.html] or the restrictions of the specific target. + +## Installation + +P4Smith depends on the P4Tools framework and is automatically installed with P4Tools. Please follow the instructions listed [here](https://github.com/p4lang/p4c/tree/main/backends/p4tools#building) to install P4Smith. The main binary `p4smith` can be found in the `build` folder after a successful installation. + +P4Smith is available as part of the [official P4C docker image](https://hub.docker.com/r/p4lang/p4c/). On Debian-based systems, it is also possible to install a P4Smith binary by following [these](https://github.com/p4lang/p4c#installing-packaged-versions-of-p4c) instructions. + +## Extensions +P4Smith extensions are instantiations of a particular combination of P4 architecture and the target that executes the P4 code. For example, the `v1model.p4` architecture can be executed on the behavioral model. P4Smith extension make use of the core P4Smith framework to generate programs. Several open-source extensions are available. + +### core.p4 using the test compiler p4test +[targets/generic](targets/generic) + +This random program generator generates random packages and tries to produce all valid P4 code according to the latest P4 specification. Programs should be compiled using [p4test](https://github.com/p4lang/p4c/tree/main/backends/p4est). + +### v1model.p4 and psa.p4 on BMv2 +[targets/bmv2](targets/bmv2) + +P4Smith supports generating P4 programs for the `v1model` and `psa` architecture on [BMv2](https://github.com/p4lang/behavioral-model). + +### pna.p4 on the DPDK SoftNIC +[targets/pna](targets/pna) + +The [DPDK-SoftNIC](https://github.com/p4lang/p4-dpdk-target) is a new target implemented using the [Data Plane Development Kit (DPDK)](https://www.dpdk.org/). The SoftNIC can be programmed using the P4 `pna.p4` architecture. + +### tna.p4 on Tofino 1 +[targets/ebpf](targets/ebpf) + +P4Smith can also generate programs for the `tna` architecture on Tofino 1. The programs are intended to be compiled on the proprietary Barefoot Tofino compiler. + +## Usage +To access the possible options for `p4smith` use `p4smith --help`. To generate a test for a particular target and P4 architecture, run the following command: + +```bash +./p4smith --target [TARGET] --arch [ARCH] prog.p4 +``` +Where `ARCH` specifies the P4 architecture (e.g., v1model.p4) and `TARGET` represents the targeted network device (e.g., BMv2). `prog.p4` is the name of the generated program. + +## Further Reading +P4Smith was originally titled Bludgeon and part of the Gauntlet compiler testing framework. Section 4 of the [paper](https://arxiv.org/abs/2006.01074) provides a high-level overview of the tool. + + +If you would like to cite this tool please use this citation format: +```latex +@inproceedings{ruffy-osdi2020, +author = {Ruffy, Fabian and Wang, Tao and Sivaraman, Anirudh}, +title = {Gauntlet: Finding Bugs in Compilers for Programmable Packet Processing}, +booktitle = {14th {USENIX} Symposium on Operating Systems Design and Implementation ({OSDI} 20)}, +year = {2020}, +publisher = {{USENIX} Association}, +month = nov, + abstract = { + Programmable packet-processing devices such as programmable switches and network interface cards are becoming mainstream. These devices are configured in a domain-specific language such as P4, using a compiler to translate packet-processing programs into instructions for different targets. As networks with programmable devices become widespread, it is critical that these compilers be dependable. This paper considers the problem of finding bugs in compilers for packet processing in the context of P4-16. We introduce domain-specific techniques to induce both abnormal termination of the compiler (crash bugs) and miscompilation (semantic bugs). We apply these techniques to (1) the opensource P4 compiler (P4C) infrastructure, which serves as a common base for different P4 back ends; (2) the P4 back end for the P4 reference software switch; and (3) the P4 back end for the Barefoot Tofino switch. Across the 3 platforms, over 8 months of bug finding, our tool Gauntlet detected 96 new and distinct bugs (62 crash and 34 semantic), which we confirmed with the respective compiler developers. 54 have been fixed (31 crash and 23 semantic); the remaining have been assigned to a developer. Our bug-finding efforts also led to 6 P4 specification changes. We have open sourced Gauntlet at p4gauntlet.github.io and it now runs within P4C’s continuous integration pipeline.} +} + +``` + +## Contributing + +Contributions to P4Smith in any form are welcome! Please follow the guidelines listed [here](https://github.com/p4lang/p4c/blob/main/CONTRIBUTING.md) to contribute. + +## License + +This project is licensed under the Apache License 2.0. See the [LICENSE](https://github.com/p4lang/p4c/blob/main/backends/p4tools/LICENSE) file for details. diff --git a/backends/p4tools/modules/smith/common/declarations.cpp b/backends/p4tools/modules/smith/common/declarations.cpp new file mode 100644 index 0000000000..2b9a1be956 --- /dev/null +++ b/backends/p4tools/modules/smith/common/declarations.cpp @@ -0,0 +1,749 @@ +#include "backends/p4tools/modules/smith/common/declarations.h" + +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/common/table.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/vector.h" +#include "lib/cstring.h" +#include "lib/exceptions.h" +#include "lib/source_file.h" + +namespace P4Tools::P4Smith { + +IR::StatOrDecl *DeclarationGenerator::generateRandomStatementOrDeclaration(bool is_in_func) { + std::vector percent = {PCT.STATEMENTORDECLARATION_VAR, + PCT.STATEMENTORDECLARATION_CONSTANT, + PCT.STATEMENTORDECLARATION_STATEMENT}; + auto val = Utils::getRandInt(percent); + if (val == 0) { + auto *stmt = target().declarationGenerator().genVariableDeclaration(); + if (stmt == nullptr) { + BUG("Declaration in statementOrDeclaration should not be nullptr!"); + } + return stmt; + } + if (val == 1) { + auto *stmt = target().declarationGenerator().genConstantDeclaration(); + if (stmt == nullptr) { + BUG("Declaration in statementOrDeclaration should not be nullptr!"); + } + return stmt; + } + auto genStmt = target().statementGenerator(); + auto *stmt = genStmt.genAssignmentOrMethodCallStatement(is_in_func); + if (stmt == nullptr) { + // it can happen that no statement can be generated + // for example in functions without writable values + // so declare a variable instead + return target().declarationGenerator().genVariableDeclaration(); + } + return stmt; +} + +IR::Annotations *DeclarationGenerator::genAnnotation() { + Util::SourceInfo si; + IR::Vector annotations; + IR::Vector exprs; + cstring name = IR::Annotation::nameAnnotation; + auto *strLiteral = new IR::StringLiteral(IR::Type_String::get(), getRandomString(6)); + + exprs.push_back(strLiteral); + + auto *annotation = new IR::Annotation(si, name, exprs, false); + annotations.push_back(annotation); + + return new IR::Annotations(annotations); +} + +IR::Declaration_Constant *DeclarationGenerator::genConstantDeclaration() { + cstring name = getRandomString(6); + TyperefProbs typePercent = { + PCT.CONSTANTDECLARATION_BASETYPE_BIT, PCT.CONSTANTDECLARATION_BASETYPE_SIGNED_BIT, + PCT.CONSTANTDECLARATION_BASETYPE_VARBIT, PCT.CONSTANTDECLARATION_BASETYPE_INT, + PCT.CONSTANTDECLARATION_BASETYPE_ERROR, PCT.CONSTANTDECLARATION_BASETYPE_BOOL, + PCT.CONSTANTDECLARATION_BASETYPE_STRING, PCT.CONSTANTDECLARATION_DERIVED_ENUM, + PCT.CONSTANTDECLARATION_DERIVED_HEADER, PCT.CONSTANTDECLARATION_DERIVED_HEADER_STACK, + PCT.CONSTANTDECLARATION_DERIVED_STRUCT, PCT.CONSTANTDECLARATION_DERIVED_HEADER_UNION, + PCT.CONSTANTDECLARATION_DERIVED_TUPLE, PCT.CONSTANTDECLARATION_TYPE_VOID, + PCT.CONSTANTDECLARATION_TYPE_MATCH_KIND, + }; + + const auto *tp = target().expressionGenerator().pickRndType(typePercent); + + IR::Declaration_Constant *ret = nullptr; + // constant declarations need to be compile-time known + P4Scope::req.compile_time_known = true; + + if (tp->is() || tp->is() || tp->is() || + tp->is()) { + auto *expr = target().expressionGenerator().genExpression(tp); + ret = new IR::Declaration_Constant(name, tp, expr); + } else { + BUG("Type %s not supported!", tp->node_type_name()); + } + P4Scope::req.compile_time_known = false; + + P4Scope::addToScope(ret); + + return ret; +} + +IR::P4Action *DeclarationGenerator::genActionDeclaration() { + cstring name = getRandomString(5); + IR::ParameterList *params = nullptr; + IR::BlockStatement *blk = nullptr; + P4Scope::startLocalScope(); + P4Scope::prop.in_action = true; + params = genParameterList(); + + blk = target().statementGenerator().genBlockStatement(false); + + auto *ret = new IR::P4Action(name, params, blk); + + P4Scope::prop.in_action = false; + P4Scope::endLocalScope(); + + P4Scope::addToScope(ret); + + return ret; +} + +IR::IndexedVector DeclarationGenerator::genLocalControlDecls() { + IR::IndexedVector localDecls; + + auto vars = Utils::getRandInt(DECL.MIN_VAR, DECL.MAX_VAR); + auto decls = Utils::getRandInt(DECL.MIN_INSTANCE, DECL.MAX_INSTANCE); + auto actions = Utils::getRandInt(DECL.MIN_ACTION, DECL.MAX_ACTION); + auto tables = Utils::getRandInt(DECL.MIN_TABLE, DECL.MAX_TABLE); + + // variableDeclarations + for (int i = 0; i <= vars; i++) { + auto *varDecl = genVariableDeclaration(); + localDecls.push_back(varDecl); + } + + // declaration_instance + for (int i = 0; i <= decls; i++) { + auto *declIns = genControlDeclarationInstance(); + + if (declIns == nullptr) { + continue; + } + localDecls.push_back(declIns); + } + + // actionDeclarations + for (int i = 0; i <= actions; i++) { + auto *actDecl = genActionDeclaration(); + localDecls.push_back(actDecl); + } + + for (int i = 0; i <= tables; i++) { + auto *tabDecl = target().tableGenerator().genTableDeclaration(); + localDecls.push_back(tabDecl); + } + return localDecls; + // instantiations +} + +IR::P4Control *DeclarationGenerator::genControlDeclaration() { + // start of new scope + P4Scope::startLocalScope(); + cstring name = getRandomString(7); + IR::ParameterList *params = genParameterList(); + auto *typeCtrl = new IR::Type_Control(name, params); + + IR::IndexedVector localDecls = genLocalControlDecls(); + // apply body + auto *applyBlock = target().statementGenerator().genBlockStatement(false); + + // end of scope + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4ctrl = new IR::P4Control(name, typeCtrl, localDecls, applyBlock); + P4Scope::addToScope(p4ctrl); + + return p4ctrl; +} + +IR::Declaration_Instance *DeclarationGenerator::genControlDeclarationInstance() { + auto p4Ctrls = P4Scope::getDecls(); + size_t size = p4Ctrls.size(); + + if (size == 0) { + // FIXME: Figure out a better way to handle this nullptr + return nullptr; + } + auto *args = new IR::Vector(); + const IR::P4Control *p4ctrl = p4Ctrls.at(Utils::getRandInt(0, size - 1)); + IR::Type *tp = new IR::Type_Name(p4ctrl->name); + auto *decl = new IR::Declaration_Instance(cstring(getRandomString(6)), tp, args); + P4Scope::addToScope(decl); + return decl; +} + +IR::Type *DeclarationGenerator::genDerivedTypeDeclaration() { return genHeaderTypeDeclaration(); } + +IR::IndexedVector DeclarationGenerator::genIdentifierList(size_t len) { + IR::IndexedVector declIds; + std::set declIdsName; + + for (size_t i = 0; i < len; i++) { + cstring name = getRandomString(2); + auto *declId = new IR::Declaration_ID(name); + + if (declIdsName.find(name) != declIdsName.end()) { + delete name; + delete declId; + continue; + } + + declIds.push_back(declId); + } + + return declIds; +} + +IR::IndexedVector DeclarationGenerator::genSpecifiedIdentifier(size_t len) { + IR::IndexedVector members; + std::set membersName; + + for (size_t i = 0; i < len; i++) { + cstring name = getRandomString(2); + IR::Expression *ex = P4Tools::P4Smith::ExpressionGenerator::genIntLiteral(); + + if (membersName.find(name) != membersName.end()) { + delete ex; + continue; + } + + auto *member = new IR::SerEnumMember(name, ex); + + members.push_back(member); + } + + return members; +} +IR::IndexedVector DeclarationGenerator::genSpecifiedIdentifierList(size_t len) { + IR::IndexedVector members; + std::set membersName; + + for (size_t i = 0; i < len; i++) { + cstring name = getRandomString(2); + IR::Expression *ex = target().expressionGenerator().genIntLiteral(); + + if (membersName.find(name) != membersName.end()) { + delete ex; + continue; + } + + auto *member = new IR::SerEnumMember(name, ex); + + members.push_back(member); + } + + return members; +} + +IR::Type_Enum *DeclarationGenerator::genEnumDeclaration(cstring name) { + auto declIds = genIdentifierList(3); + auto *ret = new IR::Type_Enum(name, declIds); + + P4Scope::addToScope(ret); + return ret; +} + +IR::Type_SerEnum *DeclarationGenerator::genSerEnumDeclaration(cstring name) { + auto members = genSpecifiedIdentifierList(3); + const auto *tp = ExpressionGenerator::genBitType(false); + + auto *ret = new IR::Type_SerEnum(name, tp, members); + + P4Scope::addToScope(ret); + return ret; +} + +IR::Type *DeclarationGenerator::genEnumTypeDeclaration(int type) { + cstring name = getRandomString(4); + if (type == 0) { + return genEnumDeclaration(name); + } + return genSerEnumDeclaration(name); +} + +IR::Method *DeclarationGenerator::genExternDeclaration() { + cstring name = getRandomString(7); + IR::Type_Method *tm = nullptr; + P4Scope::startLocalScope(); + IR::ParameterList *params = genParameterList(); + + // externs have the same type restrictions as functions + TyperefProbs typePercent = { + PCT.FUNCTIONDECLARATION_BASETYPE_BIT, PCT.FUNCTIONDECLARATION_BASETYPE_SIGNED_BIT, + PCT.FUNCTIONDECLARATION_BASETYPE_VARBIT, PCT.FUNCTIONDECLARATION_BASETYPE_INT, + PCT.FUNCTIONDECLARATION_BASETYPE_ERROR, PCT.FUNCTIONDECLARATION_BASETYPE_BOOL, + PCT.FUNCTIONDECLARATION_BASETYPE_STRING, PCT.FUNCTIONDECLARATION_DERIVED_ENUM, + PCT.FUNCTIONDECLARATION_DERIVED_HEADER, PCT.FUNCTIONDECLARATION_DERIVED_HEADER_STACK, + PCT.FUNCTIONDECLARATION_DERIVED_STRUCT, PCT.FUNCTIONDECLARATION_DERIVED_HEADER_UNION, + PCT.FUNCTIONDECLARATION_DERIVED_TUPLE, PCT.FUNCTIONDECLARATION_TYPE_VOID, + PCT.FUNCTIONDECLARATION_TYPE_MATCH_KIND, + }; + const auto *returnType = target().expressionGenerator().pickRndType(typePercent); + tm = new IR::Type_Method(returnType, params, name); + auto *ret = new IR::Method(name, tm); + P4Scope::endLocalScope(); + P4Scope::addToScope(ret); + return ret; +} + +IR::Function *DeclarationGenerator::genFunctionDeclaration() { + cstring name = getRandomString(7); + IR::Type_Method *tm = nullptr; + IR::BlockStatement *blk = nullptr; + P4Scope::startLocalScope(); + IR::ParameterList *params = genParameterList(); + + TyperefProbs typePercent = { + PCT.FUNCTIONDECLARATION_BASETYPE_BIT, PCT.FUNCTIONDECLARATION_BASETYPE_SIGNED_BIT, + PCT.FUNCTIONDECLARATION_BASETYPE_VARBIT, PCT.FUNCTIONDECLARATION_BASETYPE_INT, + PCT.FUNCTIONDECLARATION_BASETYPE_ERROR, PCT.FUNCTIONDECLARATION_BASETYPE_BOOL, + PCT.FUNCTIONDECLARATION_BASETYPE_STRING, PCT.FUNCTIONDECLARATION_DERIVED_ENUM, + PCT.FUNCTIONDECLARATION_DERIVED_HEADER, PCT.FUNCTIONDECLARATION_DERIVED_HEADER_STACK, + PCT.FUNCTIONDECLARATION_DERIVED_STRUCT, PCT.FUNCTIONDECLARATION_DERIVED_HEADER_UNION, + PCT.FUNCTIONDECLARATION_DERIVED_TUPLE, PCT.FUNCTIONDECLARATION_TYPE_VOID, + PCT.FUNCTIONDECLARATION_TYPE_MATCH_KIND, + }; + const auto *returnType = target().expressionGenerator().pickRndType(typePercent); + tm = new IR::Type_Method(returnType, params, name); + + P4Scope::prop.ret_type = returnType; + blk = target().statementGenerator().genBlockStatement(true); + P4Scope::prop.ret_type = nullptr; + + auto *ret = new IR::Function(name, tm, blk); + P4Scope::endLocalScope(); + P4Scope::addToScope(ret); + return ret; +} + +IR::Type_Header *DeclarationGenerator::genEthernetHeaderType() { + IR::IndexedVector fields; + auto *ethDst = new IR::StructField("dst_addr", IR::Type_Bits::get(48, false)); + auto *ethSrc = new IR::StructField("src_addr", IR::Type_Bits::get(48, false)); + auto *ethType = new IR::StructField("eth_type", IR::Type_Bits::get(16, false)); + + fields.push_back(ethDst); + fields.push_back(ethSrc); + fields.push_back(ethType); + + auto *ret = new IR::Type_Header(IR::ID(ETH_HEADER_T), fields); + P4Scope::addToScope(ret); + + return ret; +} + +IR::Type_Header *DeclarationGenerator::genHeaderTypeDeclaration() { + cstring name = getRandomString(6); + IR::IndexedVector fields; + TyperefProbs typePercent = { + PCT.HEADERTYPEDECLARATION_BASETYPE_BIT, PCT.HEADERTYPEDECLARATION_BASETYPE_SIGNED_BIT, + PCT.HEADERTYPEDECLARATION_BASETYPE_VARBIT, PCT.HEADERTYPEDECLARATION_BASETYPE_INT, + PCT.HEADERTYPEDECLARATION_BASETYPE_ERROR, PCT.HEADERTYPEDECLARATION_BASETYPE_BOOL, + PCT.HEADERTYPEDECLARATION_BASETYPE_STRING, PCT.HEADERTYPEDECLARATION_DERIVED_ENUM, + PCT.HEADERTYPEDECLARATION_DERIVED_HEADER, PCT.HEADERTYPEDECLARATION_DERIVED_HEADER_STACK, + PCT.HEADERTYPEDECLARATION_DERIVED_STRUCT, PCT.HEADERTYPEDECLARATION_DERIVED_HEADER_UNION, + PCT.HEADERTYPEDECLARATION_DERIVED_TUPLE, PCT.HEADERTYPEDECLARATION_TYPE_VOID, + PCT.HEADERTYPEDECLARATION_TYPE_MATCH_KIND, + }; + + size_t len = Utils::getRandInt(1, 5); + for (size_t i = 0; i < len; i++) { + cstring fieldName = getRandomString(4); + const auto *fieldTp = target().expressionGenerator().pickRndType(typePercent); + + if (const auto *structTp = fieldTp->to()) { + fieldTp = new IR::Type_Name(structTp->name); + } + auto *sf = new IR::StructField(fieldName, fieldTp); + fields.push_back(sf); + } + auto *ret = new IR::Type_Header(name, fields); + if (P4Scope::req.byte_align_headers) { + auto remainder = ret->width_bits() % 8; + if (remainder != 0) { + const auto *padBit = IR::Type_Bits::get(8 - remainder, false); + auto *padField = new IR::StructField("padding", padBit); + ret->fields.push_back(padField); + } + } + P4Scope::addToScope(ret); + + return ret; +} + +IR::Type_HeaderUnion *DeclarationGenerator::genHeaderUnionDeclaration() { + cstring name = getRandomString(6); + + IR::IndexedVector fields; + auto lTypes = P4Scope::getDecls(); + if (lTypes.size() < 2) { + BUG("Creating a header union assumes at least two headers!"); + } + // !sure if this correct... + size_t len = Utils::getRandInt(2, lTypes.size() - 2); + std::set visitedHeaders; + // we need to guarantee correct execution so try as long as we can + // this is a bit dicey... do !like it + int attempts = 0; + while (true) { + if (attempts >= 100) { + BUG("We should not need this many attempts!"); + } + attempts++; + cstring fieldName = getRandomString(4); + const auto *hdrTp = lTypes.at(Utils::getRandInt(0, lTypes.size() - 1)); + // check if we have already added this header + if (visitedHeaders.find(hdrTp->name) != visitedHeaders.end()) { + continue; + } + auto *tpName = new IR::Type_Name(hdrTp->name); + auto *sf = new IR::StructField(fieldName, tpName); + visitedHeaders.insert(hdrTp->name); + fields.push_back(sf); + if (fields.size() == len) { + break; + } + } + + auto *ret = new IR::Type_HeaderUnion(name, fields); + + P4Scope::addToScope(ret); + + return ret; +} + +IR::Type *DeclarationGenerator::genHeaderStackType() { + auto lTypes = P4Scope::getDecls(); + if (lTypes.empty()) { + BUG("Creating a header stacks assumes at least one declared header!"); + } + const auto *hdrTp = lTypes.at(Utils::getRandInt(0, lTypes.size() - 1)); + auto stackSize = Utils::getRandInt(1, MAX_HEADER_STACK_SIZE); + auto *hdrTypeName = new IR::Type_Name(hdrTp->name); + auto *ret = + new IR::Type_Stack(hdrTypeName, new IR::Constant(IR::Type_InfInt::get(), stackSize)); + + P4Scope::addToScope(ret); + + return ret; +} + +IR::Type_Struct *DeclarationGenerator::genStructTypeDeclaration() { + cstring name = getRandomString(6); + + IR::IndexedVector fields; + TyperefProbs typePercent = { + PCT.STRUCTTYPEDECLARATION_BASETYPE_BIT, PCT.STRUCTTYPEDECLARATION_BASETYPE_SIGNED_BIT, + PCT.STRUCTTYPEDECLARATION_BASETYPE_VARBIT, PCT.STRUCTTYPEDECLARATION_BASETYPE_INT, + PCT.STRUCTTYPEDECLARATION_BASETYPE_ERROR, PCT.STRUCTTYPEDECLARATION_BASETYPE_BOOL, + PCT.STRUCTTYPEDECLARATION_BASETYPE_STRING, PCT.STRUCTTYPEDECLARATION_DERIVED_ENUM, + PCT.STRUCTTYPEDECLARATION_DERIVED_HEADER, PCT.STRUCTTYPEDECLARATION_DERIVED_HEADER_STACK, + PCT.STRUCTTYPEDECLARATION_DERIVED_STRUCT, PCT.STRUCTTYPEDECLARATION_DERIVED_HEADER_UNION, + PCT.STRUCTTYPEDECLARATION_DERIVED_TUPLE, PCT.STRUCTTYPEDECLARATION_TYPE_VOID, + PCT.STRUCTTYPEDECLARATION_TYPE_MATCH_KIND, + }; + auto lTypes = P4Scope::getDecls(); + if (lTypes.empty()) { + return nullptr; + } + size_t len = Utils::getRandInt(1, 5); + + for (size_t i = 0; i < len; i++) { + const auto *fieldTp = target().expressionGenerator().pickRndType(typePercent); + cstring fieldName = getRandomString(4); + if (fieldTp->to() != nullptr) { + // Right now there is now way to initialize a header stack + // So we have to add the entire structure to the banned expressions + P4Scope::notInitializedStructs.insert(name); + } + auto *sf = new IR::StructField(fieldName, fieldTp); + fields.push_back(sf); + } + + auto *ret = new IR::Type_Struct(name, fields); + + P4Scope::addToScope(ret); + + return ret; +} + +IR::Type_Struct *DeclarationGenerator::genHeaderStruct() { + IR::IndexedVector fields; + + // Tao: hard code for ethernet_t eth_hdr; + auto *ethSf = new IR::StructField(ETH_HDR, new IR::Type_Name(ETH_HEADER_T)); + fields.push_back(ethSf); + + size_t len = Utils::getRandInt(1, 5); + // we can only generate very specific types for headers + // header, header stack, header union + std::vector percent = {PCT.STRUCTTYPEDECLARATION_HEADERS_HEADER, + PCT.STRUCTTYPEDECLARATION_HEADERS_STACK}; + for (size_t i = 0; i < len; i++) { + cstring fieldName = getRandomString(4); + IR::Type *tp = nullptr; + switch (Utils::getRandInt(percent)) { + case 0: { + // TODO(fruffy): We have to assume that this works + auto lTypes = P4Scope::getDecls(); + if (lTypes.empty()) { + BUG("structTypeDeclaration: No available header for Headers!"); + } + const auto *candidateType = lTypes.at(Utils::getRandInt(0, lTypes.size() - 1)); + tp = new IR::Type_Name(candidateType->name.name); + break; + } + case 1: { + tp = genHeaderStackType(); + // Right now there is now way to initialize a header stack + // So we have to add the entire structure to the banned expressions + P4Scope::notInitializedStructs.insert(cstring("Headers")); + } + } + fields.push_back(new IR::StructField(fieldName, tp)); + } + auto *ret = new IR::Type_Struct("Headers", fields); + + P4Scope::addToScope(ret); + + return ret; +} + +IR::Type_Declaration *DeclarationGenerator::genTypeDeclaration() { + std::vector percent = {PCT.TYPEDECLARATION_HEADER, PCT.TYPEDECLARATION_STRUCT, + PCT.TYPEDECLARATION_UNION}; + IR::Type_Declaration *decl = nullptr; + bool useDefaultDecl = false; + switch (Utils::getRandInt(percent)) { + case 0: { + useDefaultDecl = true; + break; + } + case 1: { + decl = genStructTypeDeclaration(); + break; + } + case 2: { + // header unions are disabled for now, need to fix assignments + auto hdrs = P4Scope::getDecls(); + // we can only generate a union if we have at least two headers + if (hdrs.size() > 1) { + decl = genHeaderUnionDeclaration(); + if (decl == nullptr) { + useDefaultDecl = true; + } + } else { + useDefaultDecl = true; + } + break; + } + } + if (useDefaultDecl) { + decl = genHeaderTypeDeclaration(); + } + + return decl; +} + +const IR::Type *DeclarationGenerator::genType() { + std::vector percent = {PCT.TYPEDEFDECLARATION_BASE, PCT.TYPEDEFDECLARATION_STRUCTLIKE, + PCT.TYPEDEFDECLARATION_STACK}; + + std::vector typeProbs = { + PCT.TYPEDEFDECLARATION_BASETYPE_BOOL, PCT.TYPEDEFDECLARATION_BASETYPE_ERROR, + PCT.TYPEDEFDECLARATION_BASETYPE_INT, PCT.TYPEDEFDECLARATION_BASETYPE_STRING, + PCT.TYPEDEFDECLARATION_BASETYPE_BIT, PCT.TYPEDEFDECLARATION_BASETYPE_SIGNED_BIT, + PCT.TYPEDEFDECLARATION_BASETYPE_VARBIT}; + const IR::Type *tp = nullptr; + switch (Utils::getRandInt(percent)) { + case 0: { + std::vector bTypes = {1}; // only bit<> + tp = P4Tools::P4Smith::ExpressionGenerator::pickRndBaseType(typeProbs); + break; + } + case 1: { + auto lTypes = P4Scope::getDecls(); + if (lTypes.empty()) { + return nullptr; + } + const auto *candidateType = lTypes.at(Utils::getRandInt(0, lTypes.size() - 1)); + tp = new IR::Type_Name(candidateType->name.name); + break; + } + case 2: { + // tp = headerStackType::gen(); + break; + } + } + return tp; +} + +IR::Type_Typedef *DeclarationGenerator::genTypeDef() { + cstring name = getRandomString(5); + auto *ret = new IR::Type_Typedef(name, genType()); + P4Scope::addToScope(ret); + return ret; +} + +IR::Type_Newtype *DeclarationGenerator::genNewtype() { + cstring name = getRandomString(5); + IR::Type *type = nullptr; + + auto *ret = new IR::Type_Newtype(name, type); + P4Scope::addToScope(ret); + return ret; +} + +IR::Type *DeclarationGenerator::genTypeDefOrNewType() { + // TODO(fruffy): we only have typedef now, no newtype + return genTypeDef(); +} + +IR::Declaration_Variable *DeclarationGenerator::genVariableDeclaration() { + cstring name = getRandomString(6); + + TyperefProbs typePercent = { + PCT.VARIABLEDECLARATION_BASETYPE_BIT, PCT.VARIABLEDECLARATION_BASETYPE_SIGNED_BIT, + PCT.VARIABLEDECLARATION_BASETYPE_VARBIT, PCT.VARIABLEDECLARATION_BASETYPE_INT, + PCT.VARIABLEDECLARATION_BASETYPE_ERROR, PCT.VARIABLEDECLARATION_BASETYPE_BOOL, + PCT.VARIABLEDECLARATION_BASETYPE_STRING, PCT.VARIABLEDECLARATION_DERIVED_ENUM, + PCT.VARIABLEDECLARATION_DERIVED_HEADER, PCT.VARIABLEDECLARATION_DERIVED_HEADER_STACK, + PCT.VARIABLEDECLARATION_DERIVED_STRUCT, PCT.VARIABLEDECLARATION_DERIVED_HEADER_UNION, + PCT.VARIABLEDECLARATION_DERIVED_TUPLE, PCT.VARIABLEDECLARATION_TYPE_VOID, + PCT.VARIABLEDECLARATION_TYPE_MATCH_KIND, + }; + + const IR::Type *tp = target().expressionGenerator().pickRndType(typePercent); + + IR::Declaration_Variable *ret = nullptr; + + if (tp->is() || tp->is() || tp->is() || + tp->is()) { + auto *expr = target().expressionGenerator().genExpression(tp); + ret = new IR::Declaration_Variable(name, tp, expr); + } else if (tp->is()) { + // header stacks do !have an initializer yet + ret = new IR::Declaration_Variable(name, tp); + } else { + BUG("Type %s not supported!", tp->node_type_name()); + } + + P4Scope::addToScope(ret); + + return ret; +} + +IR::Parameter *DeclarationGenerator::genTypedParameter(bool if_none_dir) { + cstring name = getRandomString(4); + const IR::Type *tp = nullptr; + IR::Direction dir; + TyperefProbs typePercent; + + if (if_none_dir) { + typePercent = { + PCT.PARAMETER_NONEDIR_BASETYPE_BIT, PCT.PARAMETER_NONEDIR_BASETYPE_SIGNED_BIT, + PCT.PARAMETER_NONEDIR_BASETYPE_VARBIT, PCT.PARAMETER_NONEDIR_BASETYPE_INT, + PCT.PARAMETER_NONEDIR_BASETYPE_ERROR, PCT.PARAMETER_NONEDIR_BASETYPE_BOOL, + PCT.PARAMETER_NONEDIR_BASETYPE_STRING, PCT.PARAMETER_NONEDIR_DERIVED_ENUM, + PCT.PARAMETER_NONEDIR_DERIVED_HEADER, PCT.PARAMETER_NONEDIR_DERIVED_HEADER_STACK, + PCT.PARAMETER_NONEDIR_DERIVED_STRUCT, PCT.PARAMETER_NONEDIR_DERIVED_HEADER_UNION, + PCT.PARAMETER_NONEDIR_DERIVED_TUPLE, PCT.PARAMETER_NONEDIR_TYPE_VOID, + PCT.PARAMETER_NONEDIR_TYPE_MATCH_KIND, + }; + dir = IR::Direction::None; + } else { + typePercent = { + PCT.PARAMETER_BASETYPE_BIT, PCT.PARAMETER_BASETYPE_SIGNED_BIT, + PCT.PARAMETER_BASETYPE_VARBIT, PCT.PARAMETER_BASETYPE_INT, + PCT.PARAMETER_BASETYPE_ERROR, PCT.PARAMETER_BASETYPE_BOOL, + PCT.PARAMETER_BASETYPE_STRING, PCT.PARAMETER_DERIVED_ENUM, + PCT.PARAMETER_DERIVED_HEADER, PCT.PARAMETER_DERIVED_HEADER_STACK, + PCT.PARAMETER_DERIVED_STRUCT, PCT.PARAMETER_DERIVED_HEADER_UNION, + PCT.PARAMETER_DERIVED_TUPLE, PCT.PARAMETER_TYPE_VOID, + PCT.PARAMETER_TYPE_MATCH_KIND, + }; + std::vector dirPercent = {PCT.PARAMETER_DIR_IN, PCT.PARAMETER_DIR_OUT, + PCT.PARAMETER_DIR_INOUT}; + switch (Utils::getRandInt(dirPercent)) { + case 0: + dir = IR::Direction::In; + break; + case 1: + dir = IR::Direction::Out; + break; + case 2: + dir = IR::Direction::InOut; + break; + default: + dir = IR::Direction::None; + } + } + tp = target().expressionGenerator().pickRndType(typePercent); + + return new IR::Parameter(name, dir, tp); +} + +IR::Parameter *DeclarationGenerator::genParameter(IR::Direction dir, cstring p_name, + cstring t_name) { + IR::Type *tp = new IR::Type_Name(new IR::Path(t_name)); + return new IR::Parameter(p_name, dir, tp); +} + +IR::ParameterList *DeclarationGenerator::genParameterList() { + IR::IndexedVector params; + size_t totalParams = Utils::getRandInt(0, 3); + size_t numDirParams = (totalParams != 0U) ? Utils::getRandInt(0, totalParams - 1) : 0; + size_t numDirectionlessParams = totalParams - numDirParams; + for (size_t i = 0; i < numDirParams; i++) { + IR::Parameter *param = genTypedParameter(false); + if (param == nullptr) { + BUG("param is null"); + } + params.push_back(param); + // add to the scope + P4Scope::addToScope(param); + // only add values that are not read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + for (size_t i = 0; i < numDirectionlessParams; i++) { + IR::Parameter *param = genTypedParameter(true); + + if (param == nullptr) { + BUG("param is null"); + } + params.push_back(param); + // add to the scope + P4Scope::addToScope(param); + P4Scope::addLval(param->type, param->name.name, true); + } + + return new IR::ParameterList(params); +} + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/common/declarations.h b/backends/p4tools/modules/smith/common/declarations.h new file mode 100644 index 0000000000..06000eb1da --- /dev/null +++ b/backends/p4tools/modules/smith/common/declarations.h @@ -0,0 +1,86 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_DECLARATIONS_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_DECLARATIONS_H_ + +#include + +#include "backends/p4tools/modules/smith/common/generator.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" +#include "lib/cstring.h" + +namespace P4Tools::P4Smith { + +class DeclarationGenerator : public Generator { + public: + explicit DeclarationGenerator(const SmithTarget &target) : Generator(target) {} + + virtual ~DeclarationGenerator() = default; + + virtual IR::StatOrDecl *generateRandomStatementOrDeclaration(bool is_in_func); + + virtual IR::Annotations *genAnnotation(); + + virtual IR::P4Action *genActionDeclaration(); + + virtual IR::Declaration_Constant *genConstantDeclaration(); + + virtual IR::IndexedVector genLocalControlDecls(); + + virtual IR::P4Control *genControlDeclaration(); + + virtual IR::Declaration_Instance *genControlDeclarationInstance(); + + virtual IR::Type *genDerivedTypeDeclaration(); + + virtual IR::IndexedVector genIdentifierList(size_t len); + + virtual IR::IndexedVector genSpecifiedIdentifier(size_t len); + + virtual IR::IndexedVector genSpecifiedIdentifierList(size_t len); + + virtual IR::Type_Enum *genEnumDeclaration(cstring name); + + virtual IR::Type_SerEnum *genSerEnumDeclaration(cstring name); + + virtual IR::Type *genEnumTypeDeclaration(int type); + + virtual IR::Method *genExternDeclaration(); + + virtual IR::Function *genFunctionDeclaration(); + + static IR::Type_Header *genEthernetHeaderType(); + + virtual IR::Type_Header *genHeaderTypeDeclaration(); + + virtual IR::Type_HeaderUnion *genHeaderUnionDeclaration(); + + static constexpr size_t MAX_HEADER_STACK_SIZE = 10; + + virtual IR::Type *genHeaderStackType(); + + virtual IR::Type_Struct *genStructTypeDeclaration(); + + virtual IR::Type_Struct *genHeaderStruct(); + + virtual IR::Type_Declaration *genTypeDeclaration(); + + virtual const IR::Type *genType(); + + virtual IR::Type_Typedef *genTypeDef(); + + virtual IR::Type_Newtype *genNewtype(); + + virtual IR::Type *genTypeDefOrNewType(); + + virtual IR::Declaration_Variable *genVariableDeclaration(); + + virtual IR::Parameter *genTypedParameter(bool if_none_dir); + + virtual IR::Parameter *genParameter(IR::Direction dir, cstring p_name, cstring t_name); + + virtual IR::ParameterList *genParameterList(); +}; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_DECLARATIONS_H_ */ diff --git a/backends/p4tools/modules/smith/common/expressions.cpp b/backends/p4tools/modules/smith/common/expressions.cpp new file mode 100644 index 0000000000..2805dfe57e --- /dev/null +++ b/backends/p4tools/modules/smith/common/expressions.cpp @@ -0,0 +1,1246 @@ +#include "backends/p4tools/modules/smith/common/expressions.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "ir/indexed_vector.h" +#include "ir/vector.h" +#include "lib/exceptions.h" + +namespace P4Tools::P4Smith { + +const IR::Type_Boolean *ExpressionGenerator::genBoolType() { return IR::Type_Boolean::get(); } + +const IR::Type_InfInt *ExpressionGenerator::genIntType() { return IR::Type_InfInt::get(); } + +const IR::Type *ExpressionGenerator::pickRndBaseType(const std::vector &type_probs) { + if (type_probs.size() != 7) { + BUG("pickRndBaseType: Type probabilities must be exact"); + } + const IR::Type *tb = nullptr; + switch (Utils::getRandInt(type_probs)) { + case 0: { + // bool + tb = genBoolType(); + break; + } + case 1: { + // error, this is not supported right now + break; + } + case 2: { + // int, this is not supported right now + tb = genIntType(); + break; + } + case 3: { + // string, this is not supported right now + break; + } + case 4: { + // bit<> + tb = genBitType(false); + break; + } + case 5: { + // int<> + tb = genBitType(true); + break; + } + case 6: { + // varbit<>, this is not supported right now + break; + } + } + return tb; +} + +const IR::Type *ExpressionGenerator::pickRndType(TyperefProbs type_probs) { + const std::vector &typeProbsVector = { + type_probs.p4_bit, type_probs.p4_signed_bit, type_probs.p4_varbit, + type_probs.p4_int, type_probs.p4_error, type_probs.p4_bool, + type_probs.p4_string, type_probs.p4_enum, type_probs.p4_header, + type_probs.p4_header_stack, type_probs.p4_struct, type_probs.p4_header_union, + type_probs.p4_tuple, type_probs.p4_void, type_probs.p4_match_kind}; + + const std::vector &basetypeProbs = { + type_probs.p4_bool, type_probs.p4_error, type_probs.p4_int, type_probs.p4_string, + type_probs.p4_bit, type_probs.p4_signed_bit, type_probs.p4_varbit}; + + if (typeProbsVector.size() != 15) { + BUG("pickRndType: Type probabilities must be exact"); + } + const IR::Type *tp = nullptr; + size_t idx = Utils::getRandInt(typeProbsVector); + switch (idx) { + case 0: { + // bit<> + tp = ExpressionGenerator::genBitType(false); + break; + } + case 1: { + // int<> + tp = ExpressionGenerator::genBitType(true); + break; + } + case 2: { + // varbit<>, this is not supported right now + break; + } + case 3: { + tp = ExpressionGenerator::genIntType(); + break; + } + case 4: { + // error, this is not supported right now + break; + } + case 5: { + // bool + tp = ExpressionGenerator::genBoolType(); + break; + } + case 6: { + // string, this is not supported right now + break; + } + case 7: { + // enum, this is not supported right now + break; + } + case 8: { + // header + auto lTypes = P4Scope::getDecls(); + if (lTypes.empty()) { + tp = pickRndBaseType(basetypeProbs); + break; + } + const auto *candidateType = lTypes.at(Utils::getRandInt(0, lTypes.size() - 1)); + auto typeName = candidateType->name.name; + // check if struct is forbidden + if (P4Scope::notInitializedStructs.count(typeName) == 0) { + tp = new IR::Type_Name(candidateType->name.name); + } else { + tp = pickRndBaseType(basetypeProbs); + } + break; + } + case 9: { + tp = target().declarationGenerator().genHeaderStackType(); + break; + } + case 10: { + // struct + auto lTypes = P4Scope::getDecls(); + if (lTypes.empty()) { + tp = pickRndBaseType(basetypeProbs); + break; + } + const auto *candidateType = lTypes.at(Utils::getRandInt(0, lTypes.size() - 1)); + auto typeName = candidateType->name.name; + // check if struct is forbidden + if (P4Scope::notInitializedStructs.count(typeName) == 0) { + tp = new IR::Type_Name(candidateType->name.name); + } else { + tp = pickRndBaseType(basetypeProbs); + } + break; + } + case 11: { + // header union, this is not supported right now + break; + } + case 12: { + // tuple, this is not supported right now + break; + } + case 13: { + // void + tp = IR::Type_Void::get(); + break; + } + case 14: { + // match kind, this is not supported right now + break; + } + } + if (tp == nullptr) { + BUG("pickRndType: Chosen type is Null!"); + } + + return tp; +} + +IR::BoolLiteral *ExpressionGenerator::genBoolLiteral() { + if (Utils::getRandInt(0, 1) != 0) { + return new IR::BoolLiteral(false); + } + return new IR::BoolLiteral(true); +} + +const IR::Type_Bits *ExpressionGenerator::genBitType(bool isSigned) { + auto size = Utils::getRandInt(0, sizeof(BIT_WIDTHS) / sizeof(int) - 1); + + return IR::Type_Bits::get(BIT_WIDTHS[size], isSigned); +} + +IR::Constant *ExpressionGenerator::genIntLiteral(size_t bit_width) { + big_int min = -((big_int(1) << bit_width - 1)); + if (P4Scope::req.not_negative) { + min = 0; + } + big_int max = ((big_int(1) << bit_width - 1) - 1); + big_int value = Utils::getRandBigInt(min, max); + while (true) { + if (P4Scope::req.not_zero && value == 0) { + value = Utils::getRandBigInt(min, max); + // retry until we generate a value that is !zero + continue; + } + break; + } + return new IR::Constant(value); +} +IR::Constant *ExpressionGenerator::genBitLiteral(const IR::Type *tb) { + big_int maxSize = (big_int(1U) << tb->width_bits()); + + big_int value; + if (P4Scope::req.not_zero) { + value = Utils::getRandBigInt(1, maxSize - 1); + } else { + value = Utils::getRandBigInt(0, maxSize - 1); + } + return new IR::Constant(tb, value); +} + +IR::Expression *ExpressionGenerator::genExpression(const IR::Type *tp) { + IR::Expression *expr = nullptr; + + // reset the expression depth + P4Scope::prop.depth = 0; + + if (const auto *tb = tp->to()) { + expr = constructBitExpr(tb); + } else if (tp->is()) { + expr = constructIntExpr(); + } else if (tp->is()) { + expr = constructBooleanExpr(); + } else if (const auto *tn = tp->to()) { + expr = constructStructExpr(tn); + } else { + BUG("Expression: Type %s not yet supported", tp->node_type_name()); + } + // reset the expression depth, just to be safe... + P4Scope::prop.depth = 0; + return expr; +} + +IR::MethodCallExpression *ExpressionGenerator::pickFunction( + IR::IndexedVector viable_functions, const IR::Type **ret_type) { + // TODO(fruffy): Make this more sophisticated + if (viable_functions.empty() || P4Scope::req.compile_time_known) { + return nullptr; + } + + size_t idx = Utils::getRandInt(0, viable_functions.size() - 1); + cstring funName; + const IR::ParameterList *params = nullptr; + if (const auto *p4Fun = viable_functions[idx]->to()) { + funName = p4Fun->name.name; + params = p4Fun->getParameters(); + *ret_type = p4Fun->type->returnType; + } else if (const auto *p4Extern = viable_functions[idx]->to()) { + funName = p4Extern->name.name; + params = p4Extern->getParameters(); + *ret_type = p4Extern->type->returnType; + } else { + BUG("Unknown callable: Type %s not yet supported", viable_functions[idx]->node_type_name()); + } + auto *expr = genFunctionCall(funName, *params); + // sometimes, functions may !be callable + // because we do !have the right return values + if ((expr == nullptr) || (ret_type == nullptr)) { + return nullptr; + } + return expr; +} + +IR::MethodCallExpression *ExpressionGenerator::genFunctionCall(cstring method_name, + IR::ParameterList params) { + auto *args = new IR::Vector(); + IR::IndexedVector decls; + + bool canCall = true; + + for (const auto *par : params) { + if (!checkInputArg(par)) { + canCall = false; + } else { + IR::Argument *arg = nullptr; + arg = new IR::Argument(genInputArg(par)); + args->push_back(arg); + } + } + if (canCall) { + auto *pathExpr = new IR::PathExpression(method_name); + return new IR::MethodCallExpression(pathExpr, args); + } + return nullptr; +} + +IR::ListExpression *ExpressionGenerator::genExpressionList(IR::Vector types, + bool only_lval) { + IR::Vector components; + for (const auto *tb : types) { + IR::Expression *expr = nullptr; + if (only_lval) { + cstring lvalName = P4Scope::pickLval(tb); + expr = new IR::PathExpression(lvalName); + } else { + expr = genExpression(tb); + } + components.push_back(expr); + } + return new IR::ListExpression(components); +} + +IR::Expression *ExpressionGenerator::constructUnaryExpr(const IR::Type_Bits *tb) { + IR::Expression *expr = nullptr; + + if (P4Scope::prop.depth > MAX_DEPTH) { + return genBitLiteral(tb); + } + P4Scope::prop.depth++; + + // we want to avoid negation when we require no negative values + int64_t negPct = PCT.EXPRESSION_BIT_UNARY_NEG; + if (P4Scope::req.not_negative) { + negPct = 0; + } + + std::vector percent = {negPct, PCT.EXPRESSION_BIT_UNARY_CMPL, + PCT.EXPRESSION_BIT_UNARY_CAST, + PCT.EXPRESSION_BIT_UNARY_FUNCTION}; + + switch (Utils::getRandInt(percent)) { + case 0: { + // pick a negation that matches the type + expr = new IR::Neg(tb, constructBitExpr(tb)); + } break; + case 1: { + // pick a complement that matches the type + // width must be known so we cast + expr = constructBitExpr(tb); + if (P4Scope::prop.width_unknown) { + expr = new IR::Cast(tb, expr); + P4Scope::prop.width_unknown = false; + } + expr = new IR::Cmpl(tb, expr); + } break; + case 2: { + // pick a cast to the type that matches the type + // new bit type can be random here + expr = new IR::Cast(tb, constructBitExpr(tb)); + } break; + case 3: { + auto p4Functions = P4Scope::getDecls(); + auto p4Externs = P4Scope::getDecls(); + + IR::IndexedVector viableFunctions; + for (const auto *fun : p4Functions) { + if (fun->type->returnType->to() != nullptr) { + viableFunctions.push_back(fun); + } + } + for (const auto *fun : p4Externs) { + if (fun->type->returnType->to() != nullptr) { + viableFunctions.push_back(fun); + } + } + const IR::Type *retType = nullptr; + expr = pickFunction(viableFunctions, &retType); + // can !find a suitable function, generate a default value + if (expr == nullptr) { + expr = genBitLiteral(tb); + break; + } + // if the return value does !match try to cast it + if (retType != tb) { + expr = new IR::Cast(tb, expr); + } + } break; + } + return expr; +} + +IR::Expression *ExpressionGenerator::createSaturationOperand(const IR::Type_Bits *tb) { + IR::Expression *expr = constructBitExpr(tb); + + int width = P4Scope::constraints.max_phv_container_width; + if (width != 0) { + if (tb->width_bits() > width) { + const auto *type = IR::Type_Bits::get(width, false); + expr = new IR::Cast(type, expr); + expr->type = type; + P4Scope::prop.width_unknown = false; + return expr; + } + } + + // width must be known so we cast + if (P4Scope::prop.width_unknown) { + expr = new IR::Cast(tb, expr); + P4Scope::prop.width_unknown = false; + } + + expr->type = tb; + return expr; +} + +IR::Expression *ExpressionGenerator::constructBinaryBitExpr(const IR::Type_Bits *tb) { + IR::Expression *expr = nullptr; + + if (P4Scope::prop.depth > MAX_DEPTH) { + return genBitLiteral(tb); + } + P4Scope::prop.depth++; + + auto pctSub = PCT.EXPRESSION_BIT_BINARY_SUB; + auto pctSubsat = PCT.EXPRESSION_BIT_BINARY_SUBSAT; + // we want to avoid subtraction when we require no negative values + if (P4Scope::req.not_negative) { + pctSub = 0; + pctSubsat = 0; + } + + std::vector percent = {PCT.EXPRESSION_BIT_BINARY_MUL, + PCT.EXPRESSION_BIT_BINARY_DIV, + PCT.EXPRESSION_BIT_BINARY_MOD, + PCT.EXPRESSION_BIT_BINARY_ADD, + pctSub, + PCT.EXPRESSION_BIT_BINARY_ADDSAT, + pctSubsat, + PCT.EXPRESSION_BIT_BINARY_LSHIFT, + PCT.EXPRESSION_BIT_BINARY_RSHIFT, + PCT.EXPRESSION_BIT_BINARY_BAND, + PCT.EXPRESSION_BIT_BINARY_BOR, + PCT.EXPRESSION_BIT_BINARY_BXOR, + PCT.EXPRESSION_BIT_BINARY_CONCAT}; + + switch (Utils::getRandInt(percent)) { + case 0: { + IR::Expression *left = constructBitExpr(tb); + IR::Expression *right = constructBitExpr(tb); + // pick a multiplication that matches the type + expr = new IR::Mul(tb, left, right); + } break; + case 1: { + // pick a division that matches the type + // TODO(fruffy): Make more sophisticated + // this requires only compile time known values + IR::Expression *left = genBitLiteral(tb); + P4Scope::req.not_zero = true; + IR::Expression *right = genBitLiteral(tb); + P4Scope::req.not_zero = false; + expr = new IR::Div(tb, left, right); + } break; + case 2: { + // pick a modulo that matches the type + // TODO(fruffy): Make more sophisticated + // this requires only compile time known values + IR::Expression *left = genBitLiteral(tb); + P4Scope::req.not_zero = true; + IR::Expression *right = genBitLiteral(tb); + P4Scope::req.not_zero = false; + expr = new IR::Mod(tb, left, right); + } break; + case 3: { + IR::Expression *left = constructBitExpr(tb); + IR::Expression *right = constructBitExpr(tb); + // pick an addition that matches the type + expr = new IR::Add(tb, left, right); + } break; + case 4: { + IR::Expression *left = constructBitExpr(tb); + IR::Expression *right = constructBitExpr(tb); + // pick a subtraction that matches the type + expr = new IR::Sub(tb, left, right); + } break; + case 5: { + IR::Expression *left = createSaturationOperand(tb); + IR::Expression *right = createSaturationOperand(tb); + // pick a saturating addition that matches the type + BUG_CHECK(left->type->width_bits() == right->type->width_bits(), + "Operator must have same left and right types: %s, %s", left->type, + right->type); + expr = new IR::AddSat(tb, left, right); + // If we ended up constraining the operand width, the expr might not be the correct + // type. + if (left->type != tb) { + expr = new IR::Cast(tb, expr); + } + } break; + case 6: { + IR::Expression *left = createSaturationOperand(tb); + IR::Expression *right = createSaturationOperand(tb); + // pick a saturating addition that matches the type + BUG_CHECK(left->type->width_bits() == right->type->width_bits(), + "Operator must have same left and right types: %s, %s", left->type, + right->type); + expr = new IR::SubSat(tb, left, right); + // If we ended up constraining the operand width, the expr might not be the correct + // type. + if (left->type != tb) { + expr = new IR::Cast(tb, expr); + } + } break; + case 7: { + // width must be known so we cast + IR::Expression *left = constructBitExpr(tb); + if (P4Scope::prop.width_unknown) { + left = new IR::Cast(tb, left); + P4Scope::prop.width_unknown = false; + } + // TODO(fruffy): Make this more sophisticated, + P4Scope::req.not_negative = true; + IR::Expression *right = constructBitExpr(tb); + P4Scope::req.not_negative = false; + // TODO(fruffy): Make this more sophisticated + // shifts are limited to 8 bits + if (P4Scope::constraints.const_lshift_count) { + right = genBitLiteral(IR::Type_Bits::get(P4Scope::req.shift_width, false)); + } else { + right = new IR::Cast(IR::Type_Bits::get(8, false), right); + } + // pick a left-shift that matches the type + expr = new IR::Shl(tb, left, right); + } break; + case 8: { + // width must be known so we cast + IR::Expression *left = constructBitExpr(tb); + if (P4Scope::prop.width_unknown) { + left = new IR::Cast(tb, left); + P4Scope::prop.width_unknown = false; + } + + // TODO(fruffy): Make this more sophisticated, + P4Scope::req.not_negative = true; + IR::Expression *right = constructBitExpr(tb); + P4Scope::req.not_negative = false; + // shifts are limited to 8 bits + right = new IR::Cast(IR::Type_Bits::get(8, false), right); + // pick a right-shift that matches the type + expr = new IR::Shr(tb, left, right); + } break; + case 9: { + IR::Expression *left = constructBitExpr(tb); + IR::Expression *right = constructBitExpr(tb); + // pick an binary And that matches the type + expr = new IR::BAnd(tb, left, right); + } break; + case 10: { + IR::Expression *left = constructBitExpr(tb); + IR::Expression *right = constructBitExpr(tb); + // pick a binary Or and that matches the type + expr = new IR::BOr(tb, left, right); + } break; + case 11: { + IR::Expression *left = constructBitExpr(tb); + IR::Expression *right = constructBitExpr(tb); + // pick an binary Xor that matches the type + expr = new IR::BXor(tb, left, right); + } break; + case 12: { + // pick an concatenation that matches the type + size_t typeWidth = tb->width_bits(); + size_t split = Utils::getRandInt(1, typeWidth - 1); + // TODO(fruffy): lazy fallback + if (split >= typeWidth) { + return genBitLiteral(tb); + } + const auto *tl = IR::Type_Bits::get(typeWidth - split, false); + const auto *tr = IR::Type_Bits::get(split, false); + // width must be known so we cast + // width must be known so we cast + IR::Expression *left = constructBitExpr(tl); + if (P4Scope::prop.width_unknown) { + left = new IR::Cast(tl, left); + P4Scope::prop.width_unknown = false; + } + IR::Expression *right = constructBitExpr(tr); + if (P4Scope::prop.width_unknown) { + right = new IR::Cast(tr, right); + P4Scope::prop.width_unknown = false; + } + expr = new IR::Concat(tb, left, right); + } break; + } + return expr; +} + +IR::Expression *ExpressionGenerator::constructTernaryBitExpr(const IR::Type_Bits *tb) { + IR::Expression *expr = nullptr; + + if (P4Scope::prop.depth > MAX_DEPTH) { + return genBitLiteral(tb); + } + P4Scope::prop.depth++; + + std::vector percent = {PCT.EXPRESSION_BIT_BINARY_SLICE, PCT.EXPRESSION_BIT_BINARY_MUX}; + + switch (Utils::getRandInt(percent)) { + case 0: { + // TODO(fruffy): Refine this... + // pick a slice that matches the type + auto typeWidth = tb->width_bits(); + // TODO(fruffy): this is some arbitrary value... + auto newTypeSize = Utils::getRandInt(1, 128) + typeWidth; + const auto *sliceType = IR::Type_Bits::get(newTypeSize, false); + auto *sliceExpr = constructBitExpr(sliceType); + if (P4Scope::prop.width_unknown) { + sliceExpr = new IR::Cast(sliceType, sliceExpr); + P4Scope::prop.width_unknown = false; + } + auto margin = newTypeSize - typeWidth; + auto high = Utils::getRandInt(0, margin - 1) + typeWidth; + auto low = high - typeWidth + 1; + expr = new IR::Slice(sliceExpr, high, low); + break; + } + case 1: { + // pick a mux that matches the type + IR::Expression *cond = constructBooleanExpr(); + IR::Expression *left = constructBitExpr(tb); + if (P4Scope::prop.width_unknown) { + left = new IR::Cast(tb, left); + P4Scope::prop.width_unknown = false; + } + IR::Expression *right = constructBitExpr(tb); + if (P4Scope::prop.width_unknown) { + right = new IR::Cast(tb, right); + P4Scope::prop.width_unknown = false; + } + expr = new IR::Mux(tb, cond, left, right); + } break; + } + return expr; +} + +IR::Expression *ExpressionGenerator::pickBitVar(const IR::Type_Bits *tb) { + cstring nodeName = tb->node_type_name(); + auto availBitTypes = P4Scope::lvalMap[nodeName].size(); + if (P4Scope::checkLval(tb)) { + cstring name = P4Scope::pickLval(tb); + return new IR::PathExpression(name); + } + if (availBitTypes > 0) { + // even if we do !find anything we can still cast other bits + auto *newTb = P4Scope::pickDeclaredBitType(); + cstring name = P4Scope::pickLval(newTb); + return new IR::Cast(tb, new IR::PathExpression(name)); + } + + // fallback, just generate a literal + return genBitLiteral(tb); +} + +IR::Expression *ExpressionGenerator::constructBitExpr(const IR::Type_Bits *tb) { + IR::Expression *expr = nullptr; + + std::vector percent = {PCT.EXPRESSION_BIT_VAR, PCT.EXPRESSION_BIT_INT_LITERAL, + PCT.EXPRESSION_BIT_BIT_LITERAL, PCT.EXPRESSION_BIT_UNARY, + PCT.EXPRESSION_BIT_BINARY, PCT.EXPRESSION_BIT_TERNARY}; + + switch (Utils::getRandInt(percent)) { + case 0: { + // pick a variable that matches the type + // do !pick, if the requirement is to be a compile time known value + // TODO(fruffy): This is lazy, we can easily check + if (P4Scope::req.compile_time_known) { + expr = genBitLiteral(tb); + } else { + expr = pickBitVar(tb); + } + } break; + case 1: { + // pick an int literal, if allowed + if (P4Scope::req.require_scalar) { + expr = genBitLiteral(tb); + } else { + expr = constructIntExpr(); + P4Scope::prop.width_unknown = true; + } + } break; + case 2: { + // pick a bit literal that matches the type + expr = genBitLiteral(tb); + } break; + case 3: { + // pick a unary expression that matches the type + expr = constructUnaryExpr(tb); + } break; + case 4: { + // pick a binary expression that matches the type + expr = constructBinaryBitExpr(tb); + } break; + case 5: { + // pick a ternary expression that matches the type + expr = constructTernaryBitExpr(tb); + } break; + } + return expr; +} + +IR::Expression *ExpressionGenerator::constructCmpExpr() { + IR::Expression *expr = nullptr; + + // gen some random type + // can be either bits, int, bool, or structlike + // for now it is just bits + auto newTypeSize = Utils::getRandInt(1, 128); + const auto *newType = IR::Type_Bits::get(newTypeSize, false); + IR::Expression *left = constructBitExpr(newType); + IR::Expression *right = constructBitExpr(newType); + + std::vector percent = {PCT.EXPRESSION_BOOLEAN_CMP_EQU, PCT.EXPRESSION_BOOLEAN_CMP_NEQ}; + + switch (Utils::getRandInt(percent)) { + case 0: { + expr = new IR::Equ(left, right); + // pick an equals that matches the type + } break; + case 1: { + expr = new IR::Neq(left, right); + // pick a not-equals that matches the type + } break; + } + return expr; +} + +IR::Expression *ExpressionGenerator::constructBooleanExpr() { + IR::Expression *expr = nullptr; + IR::Expression *left = nullptr; + IR::Expression *right = nullptr; + + std::vector percent = { + PCT.EXPRESSION_BOOLEAN_VAR, PCT.EXPRESSION_BOOLEAN_LITERAL, PCT.EXPRESSION_BOOLEAN_NOT, + PCT.EXPRESSION_BOOLEAN_LAND, PCT.EXPRESSION_BOOLEAN_LOR, PCT.EXPRESSION_BOOLEAN_CMP, + PCT.EXPRESSION_BOOLEAN_FUNCTION, PCT.EXPRESSION_BOOLEAN_BUILT_IN}; + + switch (Utils::getRandInt(percent)) { + case 0: { + const auto *tb = IR::Type_Boolean::get(); + // TODO(fruffy): This is lazy, we can easily check + if (P4Scope::req.compile_time_known) { + expr = genBoolLiteral(); + break; + } + if (P4Scope::checkLval(tb)) { + cstring name = P4Scope::pickLval(tb); + expr = new IR::TypeNameExpression(name); + } else { + expr = genBoolLiteral(); + } + } break; + case 1: { + // pick a boolean literal + expr = genBoolLiteral(); + } break; + case 2: { + // pick a Not expression + expr = new IR::LNot(constructBooleanExpr()); + } break; + case 3: { + // pick an And expression + left = constructBooleanExpr(); + right = constructBooleanExpr(); + expr = new IR::LAnd(left, right); + } break; + case 4: { + // pick an Or expression + left = constructBooleanExpr(); + right = constructBooleanExpr(); + expr = new IR::LOr(left, right); + } break; + case 5: { + // pick a comparison + expr = constructCmpExpr(); + } break; + case 6: { + auto p4Functions = P4Scope::getDecls(); + auto p4Externs = P4Scope::getDecls(); + + IR::IndexedVector viableFunctions; + for (const auto *fun : p4Functions) { + if (fun->type->returnType->to() != nullptr) { + viableFunctions.push_back(fun); + } + } + for (const auto *fun : p4Externs) { + if (fun->type->returnType->to() != nullptr) { + viableFunctions.push_back(fun); + } + } + const IR::Type *retType = nullptr; + expr = pickFunction(viableFunctions, &retType); + // can !find a suitable function, generate a default value + if (expr == nullptr) { + expr = genBoolLiteral(); + } + } break; + case 7: { + // get the expression + auto *tblSet = P4Scope::getCallableTables(); + + // just generate a literal if there are no tables left + if (tblSet->empty() || P4Scope::req.compile_time_known) { + expr = genBoolLiteral(); + break; + } + auto idx = Utils::getRandInt(0, tblSet->size() - 1); + auto tblIter = std::begin(*tblSet); + + std::advance(tblIter, idx); + const IR::P4Table *tbl = *tblIter; + expr = new IR::Member(new IR::MethodCallExpression( + new IR::Member(new IR::PathExpression(tbl->name), "apply")), + "hit"); + tblSet->erase(tblIter); + } + } + return expr; +} + +IR::Expression *ExpressionGenerator::constructUnaryIntExpr() { + IR::Expression *expr = nullptr; + + if (P4Scope::prop.depth > MAX_DEPTH) { + return genIntLiteral(); + } + const auto *tp = IR::Type_InfInt::get(); + P4Scope::prop.depth++; + + // we want to avoid negation when we require no negative values + int64_t negPct = PCT.EXPRESSION_INT_UNARY_NEG; + if (P4Scope::req.not_negative) { + negPct = 0; + } + + std::vector percent = {negPct, PCT.EXPRESSION_INT_UNARY_FUNCTION}; + + switch (Utils::getRandInt(percent)) { + case 0: { + // pick a negation that matches the type + expr = new IR::Neg(tp, constructIntExpr()); + } break; + case 1: { + auto p4Functions = P4Scope::getDecls(); + auto p4Externs = P4Scope::getDecls(); + + IR::IndexedVector viableFunctions; + for (const auto *fun : p4Functions) { + if (fun->type->returnType->to() != nullptr) { + viableFunctions.push_back(fun); + } + } + for (const auto *fun : p4Externs) { + if (fun->type->returnType->to() != nullptr) { + viableFunctions.push_back(fun); + } + } + const IR::Type *retType = nullptr; + expr = pickFunction(viableFunctions, &retType); + // can !find a suitable function, generate a default value + if (expr == nullptr) { + expr = genIntLiteral(); + break; + } + } break; + } + return expr; +} + +IR::Expression *ExpressionGenerator::constructBinaryIntExpr() { + IR::Expression *expr = nullptr; + if (P4Scope::prop.depth > MAX_DEPTH) { + return genIntLiteral(); + } + const auto *tp = IR::Type_InfInt::get(); + P4Scope::prop.depth++; + + auto pctSub = PCT.EXPRESSION_INT_BINARY_SUB; + // we want to avoid subtraction when we require no negative values + if (P4Scope::req.not_negative) { + pctSub = 0; + } + + std::vector percent = {PCT.EXPRESSION_INT_BINARY_MUL, + PCT.EXPRESSION_INT_BINARY_DIV, + PCT.EXPRESSION_INT_BINARY_MOD, + PCT.EXPRESSION_INT_BINARY_ADD, + pctSub, + PCT.EXPRESSION_INT_BINARY_LSHIFT, + PCT.EXPRESSION_INT_BINARY_RSHIFT, + PCT.EXPRESSION_INT_BINARY_BAND, + PCT.EXPRESSION_INT_BINARY_BOR, + PCT.EXPRESSION_INT_BINARY_BXOR}; + + switch (Utils::getRandInt(percent)) { + case 0: { + IR::Expression *left = constructIntExpr(); + IR::Expression *right = constructIntExpr(); + // pick a multiplication that matches the type + expr = new IR::Mul(tp, left, right); + } break; + case 1: { + // pick a division that matches the type + // TODO(fruffy): Make more sophisticated + P4Scope::req.not_negative = true; + IR::Expression *left = genIntLiteral(); + P4Scope::req.not_zero = true; + IR::Expression *right = genIntLiteral(); + P4Scope::req.not_zero = false; + P4Scope::req.not_negative = false; + expr = new IR::Div(tp, left, right); + } break; + case 2: { + // pick a modulo that matches the type + // TODO(fruffy): Make more sophisticated + P4Scope::req.not_negative = true; + IR::Expression *left = genIntLiteral(); + P4Scope::req.not_zero = true; + IR::Expression *right = genIntLiteral(); + P4Scope::req.not_zero = false; + P4Scope::req.not_negative = false; + expr = new IR::Mod(tp, left, right); + } break; + case 3: { + IR::Expression *left = constructIntExpr(); + IR::Expression *right = constructIntExpr(); + // pick an addition that matches the type + expr = new IR::Add(tp, left, right); + } break; + case 4: { + IR::Expression *left = constructIntExpr(); + IR::Expression *right = constructIntExpr(); + // pick a subtraction that matches the type + expr = new IR::Sub(tp, left, right); + } break; + case 5: { + // width must be known so we cast + IR::Expression *left = constructIntExpr(); + // TODO(fruffy): Make this more sophisticated, + P4Scope::req.not_negative = true; + IR::Expression *right = constructIntExpr(); + // shifts are limited to 8 bits + right = new IR::Cast(IR::Type_Bits::get(8, false), right); + P4Scope::req.not_negative = false; + expr = new IR::Shl(tp, left, right); + } break; + case 6: { + // width must be known so we cast + IR::Expression *left = constructIntExpr(); + // TODO(fruffy): Make this more sophisticated, + P4Scope::req.not_negative = true; + IR::Expression *right = constructIntExpr(); + // shifts are limited to 8 bits + right = new IR::Cast(IR::Type_Bits::get(8, false), right); + P4Scope::req.not_negative = false; + expr = new IR::Shr(tp, left, right); + } break; + case 7: { + IR::Expression *left = constructIntExpr(); + IR::Expression *right = constructIntExpr(); + // pick an binary And that matches the type + expr = new IR::BAnd(tp, left, right); + } break; + case 8: { + IR::Expression *left = constructIntExpr(); + IR::Expression *right = constructIntExpr(); + // pick a binary Or and that matches the type + expr = new IR::BOr(tp, left, right); + } break; + case 9: { + IR::Expression *left = constructIntExpr(); + IR::Expression *right = constructIntExpr(); + // pick an binary Xor that matches the type + expr = new IR::BXor(tp, left, right); + } break; + } + return expr; +} + +IR::Expression *ExpressionGenerator::pickIntVar() { + const auto *tp = IR::Type_InfInt::get(); + if (P4Scope::checkLval(tp)) { + cstring name = P4Scope::pickLval(tp); + return new IR::PathExpression(name); + } + + // fallback, just generate a literal + return genIntLiteral(); +} + +IR::Expression *ExpressionGenerator::constructIntExpr() { + IR::Expression *expr = nullptr; + + std::vector percent = {PCT.EXPRESSION_INT_VAR, PCT.EXPRESSION_INT_INT_LITERAL, + PCT.EXPRESSION_INT_UNARY, PCT.EXPRESSION_INT_BINARY}; + + switch (Utils::getRandInt(percent)) { + case 0: { + expr = pickIntVar(); + } break; + case 1: { + // pick an int literal that matches the type + expr = genIntLiteral(); + } break; + case 2: { + // pick a unary expression that matches the type + expr = constructUnaryIntExpr(); + } break; + case 3: { + // pick a binary expression that matches the type + expr = constructBinaryIntExpr(); + } break; + } + return expr; +} + +IR::ListExpression *ExpressionGenerator::genStructListExpr(const IR::Type_Name *tn) { + IR::Vector components; + cstring tnName = tn->path->name.name; + + if (const auto *td = P4Scope::getTypeByName(tnName)) { + if (const auto *tnType = td->to()) { + for (const auto *sf : tnType->fields) { + IR::Expression *expr = nullptr; + if (const auto *fieldTn = sf->type->to()) { + // can!use another type here yet + expr = genStructListExpr(fieldTn); + components.push_back(expr); + } else if (const auto *fieldTs = sf->type->to()) { + auto stackSize = fieldTs->getSize(); + const auto *stackType = fieldTs->elementType; + if (const auto *sTypeName = stackType->to()) { + for (size_t idx = 0; idx < stackSize; ++idx) { + expr = genStructListExpr(sTypeName); + components.push_back(expr); + } + + } else { + BUG("genStructListExpr: Stack Type %s unsupported", tnName); + } + } else { + expr = genExpression(sf->type); + components.push_back(expr); + } + } + } else { + BUG("genStructListExpr: Requested Type %s not a struct-like type", tnName); + } + } else { + BUG("genStructListExpr: Requested Type %s not found", tnName); + } + return new IR::ListExpression(components); +} + +IR::Expression *ExpressionGenerator::constructStructExpr(const IR::Type_Name *tn) { + IR::Expression *expr = nullptr; + std::vector percent = {PCT.EXPRESSION_STRUCT_VAR, PCT.EXPRESSION_STRUCT_LITERAL, + PCT.EXPRESSION_STRUCT_FUNCTION}; + + // because fallthrough is !very portable... + bool useDefaultExpr = false; + + switch (Utils::getRandInt(percent)) { + case 0: + // pick a type from the available list + // do !pick, if the requirement is to be a compile time known value + if (P4Scope::checkLval(tn) && !P4Scope::req.compile_time_known) { + cstring lval = P4Scope::pickLval(tn); + expr = new IR::TypeNameExpression(lval); + } else { + // if there is no suitable declaration we fall through + useDefaultExpr = true; + } + break; + case 1: { + // construct a list expression out of base-types + useDefaultExpr = true; + } break; + case 2: { + // run a function call + auto p4Functions = P4Scope::getDecls(); + auto p4Externs = P4Scope::getDecls(); + + IR::IndexedVector viableFunctions; + for (const auto *fun : p4Functions) { + if (fun->type->returnType == tn) { + viableFunctions.push_back(fun); + } + } + for (const auto *fun : p4Externs) { + if (fun->type->returnType == tn) { + viableFunctions.push_back(fun); + } + } + + const IR::Type *retType = nullptr; + expr = pickFunction(viableFunctions, &retType); + // can !find a suitable function, generate a default value + if (expr == nullptr) { + useDefaultExpr = true; + break; + } + } + } + if (useDefaultExpr) { + expr = genStructListExpr(tn); + } + return expr; +} + +IR::Expression *ExpressionGenerator::genInputArg(const IR::Parameter *param) { + if (param->direction == IR::Direction::In) { + // this can be any value + return genExpression(param->type); + } + if (param->direction == IR::Direction::None) { + // such args can only be compile-time constants + P4Scope::req.compile_time_known = true; + auto *expr = genExpression(param->type); + P4Scope::req.compile_time_known = false; + return expr; + } + // for inout and out the value must be writeable + return pickLvalOrSlice(param->type); +} + +bool ExpressionGenerator::checkInputArg(const IR::Parameter *param) { + if (param->direction == IR::Direction::In || param->direction == IR::Direction::None) { + return P4Scope::checkLval(param->type, false); + } + return P4Scope::checkLval(param->type, true); +} + +size_t split(const std::string &txt, std::vector &strs, char ch) { + size_t pos = txt.find(ch); + size_t initialPos = 0; + strs.clear(); + + // Decompose statement + while (pos != std::string::npos) { + strs.emplace_back(txt.substr(initialPos, pos - initialPos)); + initialPos = pos + 1; + + pos = txt.find(ch, initialPos); + } + + // Add the last one + strs.emplace_back(txt.substr(initialPos, std::min(pos, txt.size()) - initialPos + 1)); + + return strs.size(); +} + +IR::Expression *ExpressionGenerator::editHdrStack(cstring lval) { + // Check if there is a stack bracket inside the string. + // Also, if we can not have variables inside the header stack index, + // then just return the original expression. + // FIXME: terrible but at least works for now + if ((lval.find('[') == nullptr) || P4Scope::constraints.const_header_stack_index) { + return new IR::PathExpression(lval); + } + + std::vector splitStr; + int size = split(lval.c_str(), splitStr, '.'); + if (size < 1) { + BUG("Unexpected split size. %d", size); + } + auto sIter = std::begin(splitStr); + IR::Expression *expr = new IR::PathExpression(*sIter); + for (advance(sIter, 1); sIter != splitStr.end(); ++sIter) { + // if there is an index, convert it towards the proper expression + auto subStr = *sIter; + const auto *hdrBrkt = subStr.find('['); + if (hdrBrkt != nullptr) { + auto stackStr = subStr.substr(static_cast(hdrBrkt - subStr + 1)); + const auto *stackSzEnd = stackStr.find(']'); + if (stackSzEnd == nullptr) { + BUG("There should be a closing bracket."); + } + int stackSz = std::stoi(stackStr.before(stackSzEnd).c_str()); + expr = new IR::Member(expr, subStr.before(hdrBrkt)); + auto *tb = IR::Type_Bits::get(3, false); + IR::Expression *idx = genExpression(tb); + auto *args = new IR::Vector(); + args->push_back(new IR::Argument(idx)); + args->push_back(new IR::Argument(new IR::Constant(tb, stackSz))); + idx = new IR::MethodCallExpression(new IR::PathExpression("max"), args); + + expr = new IR::ArrayIndex(expr, idx); + } else { + expr = new IR::Member(expr, subStr); + } + } + return expr; +} + +IR::Expression *ExpressionGenerator::pickLvalOrSlice(const IR::Type *tp) { + cstring lvalStr = P4Scope::pickLval(tp, true); + IR::Expression *expr = editHdrStack(lvalStr); + + if (const auto *tb = tp->to()) { + std::vector percent = {PCT.SCOPE_LVAL_PATH, PCT.SCOPE_LVAL_SLICE}; + switch (Utils::getRandInt(percent)) { + case 0: { + break; + } + case 1: { + auto keyTypesOpt = + P4Scope::getWriteableLvalForTypeKey(IR::Type_Bits::static_type_name()); + if (!keyTypesOpt) { + break; + } + auto keyTypes = keyTypesOpt.value(); + size_t targetWidth = tb->width_bits(); + + std::vector> candidates; + + for (const auto &bitBucket : keyTypes) { + size_t keySize = bitBucket.first; + if (keySize > targetWidth) { + for (cstring lval : keyTypes[keySize]) { + candidates.emplace_back(keySize, lval); + } + } + } + if (candidates.empty()) { + break; + } + size_t idx = Utils::getRandInt(0, candidates.size() - 1); + auto lval = std::begin(candidates); + // "advance" the iterator idx times + std::advance(lval, idx); + size_t candidateSize = lval->first; + auto *sliceExpr = new IR::PathExpression(lval->second); + size_t low = Utils::getRandInt(0, candidateSize - targetWidth); + size_t high = low + targetWidth - 1; + expr = new IR::Slice(sliceExpr, high, low); + } break; + } + } + return expr; +} + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/common/expressions.h b/backends/p4tools/modules/smith/common/expressions.h new file mode 100644 index 0000000000..c6104b1fca --- /dev/null +++ b/backends/p4tools/modules/smith/common/expressions.h @@ -0,0 +1,119 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_EXPRESSIONS_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_EXPRESSIONS_H_ + +#include +#include +#include + +#include "backends/p4tools/modules/smith/common/generator.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" +#include "ir/vector.h" +#include "lib/cstring.h" + +namespace P4Tools::P4Smith { + +using TyperefProbs = struct TyperefProbs { + int64_t p4_bit; + int64_t p4_signed_bit; + int64_t p4_varbit; + int64_t p4_int; + int64_t p4_error; + int64_t p4_bool; + int64_t p4_string; + // derived types + int64_t p4_enum; + int64_t p4_header; + int64_t p4_header_stack; + int64_t p4_struct; + int64_t p4_header_union; + int64_t p4_tuple; + int64_t p4_void; + int64_t p4_match_kind; +}; + +class ExpressionGenerator : public Generator { + public: + virtual ~ExpressionGenerator() = default; + explicit ExpressionGenerator(const SmithTarget &target) : Generator(target) {} + + static constexpr size_t MAX_DEPTH = 3; + + static constexpr int BIT_WIDTHS[6] = {4, 8, 16, 32, 64, 128}; + + static const IR::Type_Boolean *genBoolType(); + + static const IR::Type_InfInt *genIntType(); + + // isSigned, true -> int<>, false -> bit<> + static const IR::Type_Bits *genBitType(bool isSigned); + + static const IR::Type *pickRndBaseType(const std::vector &type_probs); + + virtual const IR::Type *pickRndType(TyperefProbs type_probs); + + static IR::BoolLiteral *genBoolLiteral(); + + static IR::Constant *genIntLiteral(size_t bit_width = INTEGER_WIDTH); + + static IR::Constant *genBitLiteral(const IR::Type *tb); + + private: + IR::Expression *constructUnaryExpr(const IR::Type_Bits *tb); + + IR::Expression *createSaturationOperand(const IR::Type_Bits *tb); + + IR::Expression *constructBinaryBitExpr(const IR::Type_Bits *tb); + + IR::Expression *constructTernaryBitExpr(const IR::Type_Bits *tb); + + public: + virtual IR::Expression *pickBitVar(const IR::Type_Bits *tb); + + virtual IR::Expression *constructBitExpr(const IR::Type_Bits *tb); + + private: + IR::Expression *constructCmpExpr(); + + public: + virtual IR::Expression *constructBooleanExpr(); + + private: + IR::Expression *constructUnaryIntExpr(); + + IR::Expression *constructBinaryIntExpr(); + + static IR::Expression *pickIntVar(); + + public: + IR::Expression *constructIntExpr(); + + private: + IR::ListExpression *genStructListExpr(const IR::Type_Name *tn); + + IR::Expression *editHdrStack(cstring lval); + + public: + virtual IR::Expression *constructStructExpr(const IR::Type_Name *tn); + + virtual IR::MethodCallExpression *genFunctionCall(cstring method_name, + IR::ParameterList params); + + virtual IR::MethodCallExpression *pickFunction( + IR::IndexedVector viable_functions, const IR::Type **ret_type); + + virtual IR::Expression *genExpression(const IR::Type *tp); + + virtual IR::ListExpression *genExpressionList(IR::Vector types, bool only_lval); + + virtual IR::Expression *genInputArg(const IR::Parameter *param); + + virtual IR::Expression *pickLvalOrSlice(const IR::Type *tp); + + virtual bool checkInputArg(const IR::Parameter *param); +}; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_EXPRESSIONS_H_ */ diff --git a/backends/p4tools/modules/smith/common/generator.h b/backends/p4tools/modules/smith/common/generator.h new file mode 100644 index 0000000000..37abd6ff11 --- /dev/null +++ b/backends/p4tools/modules/smith/common/generator.h @@ -0,0 +1,20 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_GENERATOR_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_GENERATOR_H_ + +#include + +namespace P4Tools::P4Smith { + +class SmithTarget; + +class Generator { + std::reference_wrapper _target; + + public: + explicit Generator(const SmithTarget &target) : _target(target) {} + + const SmithTarget &target() { return _target; } +}; +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_GENERATOR_H_ */ diff --git a/backends/p4tools/modules/smith/common/parser.cpp b/backends/p4tools/modules/smith/common/parser.cpp new file mode 100644 index 0000000000..4e140b6985 --- /dev/null +++ b/backends/p4tools/modules/smith/common/parser.cpp @@ -0,0 +1,271 @@ +#include "backends/p4tools/modules/smith/common/parser.h" + +#include +#include +#include +#include + +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/vector.h" +#include "lib/big_int_util.h" +#include "lib/cstring.h" +#include "lib/exceptions.h" + +namespace P4Tools::P4Smith { + +IR::MethodCallStatement *ParserGenerator::genHdrExtract(IR::Member *pkt_call, IR::Expression *mem) { + auto *args = new IR::Vector(); + auto *arg = new IR::Argument(mem); + + args->push_back(arg); + auto *mce = new IR::MethodCallExpression(pkt_call, args); + return new IR::MethodCallStatement(mce); +} + +void ParserGenerator::genHdrUnionExtract(IR::IndexedVector &components, + const IR::Type_HeaderUnion *hdru, IR::ArrayIndex *arr_ind, + IR::Member *pkt_call) { + const auto *sf = hdru->fields.at(0); + // for (auto sf : hdru->fields) { + // auto mem = new IR::Member(arr_ind, + // sf->type->to()->path->name); + auto *mem = new IR::Member(arr_ind, sf->name); + + components.push_back(genHdrExtract(pkt_call, mem)); + // } +} + +IR::ParserState *ParserGenerator::genStartState() { + IR::IndexedVector components; + IR::Expression *transition = new IR::PathExpression("parse_hdrs"); + auto *ret = new IR::ParserState("start", components, transition); + + P4Scope::addToScope(ret); + return ret; +} + +IR::ParserState *ParserGenerator::genHdrStates() { + IR::Expression *transition = nullptr; + IR::IndexedVector components; + std::vector hdrFieldsNames; + std::map hdrFieldsTypes; + + const auto *sysHdrType = P4Scope::getTypeByName(SYS_HDR_NAME); + const auto *sysHdr = sysHdrType->to(); + if (sysHdr == nullptr) { + BUG("Unexpected system header %s", sysHdrType->static_type_name()); + } + for (const auto *sf : sysHdr->fields) { + hdrFieldsNames.push_back(sf->name.name); + hdrFieldsTypes.emplace(sf->name.name, sf->type); + } + + auto *pktCall = new IR::Member(new IR::PathExpression("pkt"), "extract"); + for (auto sfName : hdrFieldsNames) { + const auto *sfType = hdrFieldsTypes[sfName]; + if (const auto *sfTpS = sfType->to()) { + auto *mem = new IR::Member(new IR::PathExpression("hdr"), sfName); + size_t size = sfTpS->getSize(); + const auto *eleTpName = sfTpS->elementType; + const auto *eleTp = + P4Scope::getTypeByName(eleTpName->to()->path->name.name); + if (eleTp->is()) { + for (size_t j = 0; j < size; j++) { + auto *nextMem = new IR::Member(mem, "next"); + components.push_back(genHdrExtract(pktCall, nextMem)); + } + } else if (const auto *hdruTp = eleTp->to()) { + for (size_t j = 0; j < size; j++) { + auto *arrInd = + new IR::ArrayIndex(mem, new IR::Constant(IR::Type_InfInt::get(), j)); + genHdrUnionExtract(components, hdruTp, arrInd, pktCall); + } + } else { + BUG("wtf here %s", sfType->node_type_name()); + } + } else if (sfType->is()) { + auto *mem = new IR::Member(new IR::PathExpression("hdr"), sfName); + const auto *hdrFieldTp = + P4Scope::getTypeByName(sfType->to()->path->name.name); + if (hdrFieldTp->is()) { + const auto *hdruTp = hdrFieldTp->to(); + const auto *sf = hdruTp->fields.at(0); + auto *hdrMem = new IR::Member(mem, sf->name); + components.push_back(genHdrExtract(pktCall, hdrMem)); + } else { + components.push_back(genHdrExtract(pktCall, mem)); + } + } else { + BUG("wtf here %s", sfType->node_type_name()); + } + } + + // transition part + // transition = new IR::PathExpression(new IR::Path(IR::ID("state_0"))); + /* cstring next_state = getRandomString(6); + genState(next_state); + transition = new IR::PathExpression(next_state);*/ + + transition = new IR::PathExpression("accept"); + + auto *ret = new IR::ParserState("parse_hdrs", components, transition); + P4Scope::addToScope(ret); + return ret; +} + +IR::ListExpression *ParserGenerator::buildMatchExpr(IR::Vector types) { + IR::Vector components; + for (const auto *tb : types) { + IR::Expression *expr = nullptr; + switch (Utils::getRandInt(0, 2)) { + case 0: { + // TODO(fruffy): Figure out allowed expressions + // if (P4Scope::checkLval(tb)) { + // cstring lval_name = P4Scope::pickLval(tb); + // expr = new IR::PathExpression(lval_name); + // } else { + // expr = target().expressionGenerator().genBitLiteral(tb); + // } + expr = target().expressionGenerator().genBitLiteral(tb); + break; + } + case 1: { + // Range + big_int maxRange = big_int(1U) << tb->width_bits(); + // FIXME: disable large ranges for now + maxRange = min(big_int(1U) << 32, maxRange); + big_int lower = Utils::getRandBigInt(0, maxRange - 1); + big_int higher = Utils::getRandBigInt(lower, maxRange - 1); + auto *lowerExpr = new IR::Constant(lower); + auto *higherExpr = new IR::Constant(higher); + expr = new IR::Range(tb, lowerExpr, higherExpr); + break; + } + case 2: { + // Mask + auto *left = target().expressionGenerator().genBitLiteral(tb); + auto *right = target().expressionGenerator().genBitLiteral(tb); + expr = new IR::Mask(tb, left, right); + break; + } + } + components.push_back(expr); + } + return new IR::ListExpression(components); +} + +void ParserGenerator::genState(cstring name) { + IR::IndexedVector components; + + P4Scope::startLocalScope(); + + // variable decls + for (int i = 0; i < 5; i++) { + auto *varDecl = target().declarationGenerator().genVariableDeclaration(); + components.push_back(varDecl); + } + // statements + for (int i = 0; i < 5; i++) { + auto *ass = target().statementGenerator().genAssignmentStatement(); + if (ass != nullptr) { + components.push_back(ass); + } + break; + } + + // expression + IR::Expression *transition = nullptr; + + std::vector percent = {PCT.P4STATE_TRANSITION_ACCEPT, PCT.P4STATE_TRANSITION_REJECT, + PCT.P4STATE_TRANSITION_STATE, PCT.P4STATE_TRANSITION_SELECT}; + + P4Scope::endLocalScope(); + switch (Utils::getRandInt(percent)) { + case 0: { + transition = new IR::PathExpression("accept"); + break; + } + case 1: { + transition = new IR::PathExpression("reject"); + break; + } + case 2: { + cstring nextState = getRandomString(6); + genState(nextState); + transition = new IR::PathExpression(nextState); + break; + } + case 3: { + IR::Vector exprs; + IR::Vector cases; + size_t numTransitions = Utils::getRandInt(1, 3); + size_t keySetLen = Utils::getRandInt(1, 4); + + IR::Vector types; + for (size_t i = 0; i <= keySetLen; i++) { + auto *tb = ExpressionGenerator::genBitType(false); + types.push_back(tb); + } + + for (size_t i = 0; i < numTransitions; i++) { + IR::Expression *matchSet = nullptr; + // TODO(fruffy): Do !always have a default + if (i == (numTransitions - 1)) { + P4Scope::req.compile_time_known = true; + matchSet = buildMatchExpr(types); + P4Scope::req.compile_time_known = false; + } else { + matchSet = new IR::DefaultExpression(); + } + switch (Utils::getRandInt(0, 2)) { + case 0: { + cases.push_back( + new IR::SelectCase(matchSet, new IR::PathExpression("accept"))); + break; + } + case 1: { + cases.push_back( + new IR::SelectCase(matchSet, new IR::PathExpression("reject"))); + break; + } + case 2: { + cstring nextState = getRandomString(6); + genState(nextState); + auto *swCase = + new IR::SelectCase(matchSet, new IR::PathExpression(nextState)); + cases.push_back(swCase); + break; + } + } + } + P4Scope::req.require_scalar = true; + IR::ListExpression *keySet = + target().expressionGenerator().genExpressionList(types, false); + P4Scope::req.require_scalar = false; + transition = new IR::SelectExpression(keySet, cases); + break; + } + } + + // add to scope + auto *ret = new IR::ParserState(name, components, transition); + P4Scope::addToScope(ret); + state_list.push_back(ret); +} + +void ParserGenerator::buildParserTree() { + state_list.push_back(ParserGenerator::genStartState()); + state_list.push_back(ParserGenerator::genHdrStates()); +} + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/common/parser.h b/backends/p4tools/modules/smith/common/parser.h new file mode 100644 index 0000000000..59da5007ce --- /dev/null +++ b/backends/p4tools/modules/smith/common/parser.h @@ -0,0 +1,35 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_PARSER_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_PARSER_H_ + +#include "backends/p4tools/modules/smith/common/generator.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" +#include "ir/vector.h" +#include "lib/cstring.h" + +namespace P4Tools::P4Smith { + +class ParserGenerator : public Generator { + private: + IR::IndexedVector state_list; + + public: + virtual ~ParserGenerator() = default; + explicit ParserGenerator(const SmithTarget &target) : Generator(target) {} + + virtual IR::MethodCallStatement *genHdrExtract(IR::Member *pkt_call, IR::Expression *mem); + virtual void genHdrUnionExtract(IR::IndexedVector &components, + const IR::Type_HeaderUnion *hdru, IR::ArrayIndex *arr_ind, + IR::Member *pkt_call); + virtual IR::ListExpression *buildMatchExpr(IR::Vector types); + virtual IR::ParserState *genStartState(); + virtual IR::ParserState *genHdrStates(); + virtual void genState(cstring name); + virtual void buildParserTree(); + + [[nodiscard]] IR::IndexedVector getStates() const { return state_list; } +}; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_PARSER_H_ */ diff --git a/backends/p4tools/modules/smith/common/probabilities.h b/backends/p4tools/modules/smith/common/probabilities.h new file mode 100644 index 0000000000..ac0b40a226 --- /dev/null +++ b/backends/p4tools/modules/smith/common/probabilities.h @@ -0,0 +1,328 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_PROBABILITIES_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_PROBABILITIES_H_ + +#include + +static struct Probabilities { + // assignment or method call + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_ASSIGN = 75; + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_CALL = 25; + // probabilities of assignment types + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_ASSIGN_BIT = 100; + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_ASSIGN_STRUCTLIKE = 0; + // probabilities of method calls + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_ACTION = 44; + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_FUNCTION = 45; + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_TABLE = 10; + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_CTRL = 5; + uint16_t ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_BUILT_IN = 1; + + // probabilities for statements + uint16_t STATEMENT_SWITCH = 5; + uint16_t STATEMENT_ASSIGNMENTORMETHODCALL = 85; + uint16_t STATEMENT_IF = 3; + uint16_t STATEMENT_RETURN = 2; + uint16_t STATEMENT_EXIT = 0; + uint16_t STATEMENT_BLOCK = 2; + + // probabilities to pick a slice when requesting an lval + uint16_t SCOPE_LVAL_PATH = 90; + uint16_t SCOPE_LVAL_SLICE = 10; + + // probabilities for statements or declarations + uint16_t STATEMENTORDECLARATION_VAR = 10; + uint16_t STATEMENTORDECLARATION_CONSTANT = 10; + uint16_t STATEMENTORDECLARATION_STATEMENT = 80; + + // probabilities for unary bit expressions + uint16_t EXPRESSION_BIT_UNARY_NEG = 20; + uint16_t EXPRESSION_BIT_UNARY_CMPL = 20; + uint16_t EXPRESSION_BIT_UNARY_CAST = 10; + uint16_t EXPRESSION_BIT_UNARY_FUNCTION = 50; + // probabilities for binary bit expressions + uint16_t EXPRESSION_BIT_BINARY_MUL = 5; + uint16_t EXPRESSION_BIT_BINARY_DIV = 5; + uint16_t EXPRESSION_BIT_BINARY_MOD = 5; + uint16_t EXPRESSION_BIT_BINARY_ADD = 10; + uint16_t EXPRESSION_BIT_BINARY_SUB = 10; + uint16_t EXPRESSION_BIT_BINARY_ADDSAT = 10; + uint16_t EXPRESSION_BIT_BINARY_SUBSAT = 10; + uint16_t EXPRESSION_BIT_BINARY_LSHIFT = 5; + uint16_t EXPRESSION_BIT_BINARY_RSHIFT = 5; + uint16_t EXPRESSION_BIT_BINARY_BAND = 10; + uint16_t EXPRESSION_BIT_BINARY_BOR = 10; + uint16_t EXPRESSION_BIT_BINARY_BXOR = 10; + uint16_t EXPRESSION_BIT_BINARY_CONCAT = 5; + // probabilities for ternary bit expressions + uint16_t EXPRESSION_BIT_BINARY_SLICE = 50; + uint16_t EXPRESSION_BIT_BINARY_MUX = 50; + // probabilities for bit expressions + uint16_t EXPRESSION_BIT_VAR = 20; + uint16_t EXPRESSION_BIT_INT_LITERAL = 5; + uint16_t EXPRESSION_BIT_BIT_LITERAL = 25; + uint16_t EXPRESSION_BIT_UNARY = 10; + uint16_t EXPRESSION_BIT_BINARY = 20; + uint16_t EXPRESSION_BIT_TERNARY = 10; + + // probabilities for unary int expressions + uint16_t EXPRESSION_INT_UNARY_NEG = 20; + uint16_t EXPRESSION_INT_UNARY_CMPL = 20; + uint16_t EXPRESSION_INT_UNARY_FUNCTION = 50; + // probabilities for binary int expressions + uint16_t EXPRESSION_INT_BINARY_MUL = 5; + uint16_t EXPRESSION_INT_BINARY_DIV = 5; + uint16_t EXPRESSION_INT_BINARY_MOD = 5; + uint16_t EXPRESSION_INT_BINARY_ADD = 10; + uint16_t EXPRESSION_INT_BINARY_SUB = 10; + uint16_t EXPRESSION_INT_BINARY_LSHIFT = 0; + uint16_t EXPRESSION_INT_BINARY_RSHIFT = 0; + uint16_t EXPRESSION_INT_BINARY_BAND = 10; + uint16_t EXPRESSION_INT_BINARY_BOR = 10; + uint16_t EXPRESSION_INT_BINARY_BXOR = 10; + // probabilities for ternary int expressions + uint16_t EXPRESSION_INT_BINARY_MUX = 50; + // probabilities for int expressions + uint16_t EXPRESSION_INT_VAR = 20; + uint16_t EXPRESSION_INT_INT_LITERAL = 5; + uint16_t EXPRESSION_INT_UNARY = 10; + uint16_t EXPRESSION_INT_BINARY = 20; + + // probabilities for boolean expressions + uint16_t EXPRESSION_BOOLEAN_VAR = 15; + uint16_t EXPRESSION_BOOLEAN_LITERAL = 20; + uint16_t EXPRESSION_BOOLEAN_NOT = 35; + uint16_t EXPRESSION_BOOLEAN_LAND = 5; + uint16_t EXPRESSION_BOOLEAN_LOR = 5; + uint16_t EXPRESSION_BOOLEAN_CMP = 10; + uint16_t EXPRESSION_BOOLEAN_FUNCTION = 5; + uint16_t EXPRESSION_BOOLEAN_BUILT_IN = 5; + // probabilities for comparisons + uint16_t EXPRESSION_BOOLEAN_CMP_EQU = 50; + uint16_t EXPRESSION_BOOLEAN_CMP_NEQ = 50; + + // probabilities for structlike expressions + uint16_t EXPRESSION_STRUCT_VAR = 50; + uint16_t EXPRESSION_STRUCT_LITERAL = 30; + uint16_t EXPRESSION_STRUCT_FUNCTION = 20; + + // probabilities for state transitions in the parser + uint16_t P4STATE_TRANSITION_ACCEPT = 50; + uint16_t P4STATE_TRANSITION_REJECT = 10; + uint16_t P4STATE_TRANSITION_STATE = 30; + uint16_t P4STATE_TRANSITION_SELECT = 10; + + uint16_t BASETYPE_BIT = 50; + uint16_t BASETYPE_SIGNED_BIT = 0; + uint16_t BASETYPE_VARBIT = 0; + uint16_t BASETYPE_INT = 10; + uint16_t BASETYPE_ERROR = 0; + uint16_t BASETYPE_BOOL = 10; + uint16_t BASETYPE_STRING = 0; + uint16_t DERIVED_ENUM = 0; + uint16_t DERIVED_HEADER = 5; + uint16_t DERIVED_HEADER_STACK = 2; + uint16_t DERIVED_STRUCT = 5; + uint16_t DERIVED_HEADER_UNION = 0; + uint16_t DERIVED_TUPLE = 0; + uint16_t TYPE_VOID = 0; + uint16_t TYPE_MATCH_KIND = 0; + + // probabilities for the types of constant declarations + uint16_t CONSTANTDECLARATION_TYPE_BASE = 80; + uint16_t CONSTANTDECLARATION_TYPE_STRUCT = 0; + // probabilities for the base types in constant declarations + uint16_t CONSTANTDECLARATION_BASETYPE_BIT = BASETYPE_BIT; + uint16_t CONSTANTDECLARATION_BASETYPE_SIGNED_BIT = BASETYPE_SIGNED_BIT; + uint16_t CONSTANTDECLARATION_BASETYPE_VARBIT = BASETYPE_VARBIT; + uint16_t CONSTANTDECLARATION_BASETYPE_INT = BASETYPE_INT; + uint16_t CONSTANTDECLARATION_BASETYPE_ERROR = BASETYPE_ERROR; + uint16_t CONSTANTDECLARATION_BASETYPE_BOOL = BASETYPE_BOOL; + uint16_t CONSTANTDECLARATION_BASETYPE_STRING = BASETYPE_STRING; + uint16_t CONSTANTDECLARATION_DERIVED_ENUM = DERIVED_ENUM; + uint16_t CONSTANTDECLARATION_DERIVED_HEADER = DERIVED_HEADER; + uint16_t CONSTANTDECLARATION_DERIVED_HEADER_STACK = 0; + uint16_t CONSTANTDECLARATION_DERIVED_STRUCT = DERIVED_STRUCT; + uint16_t CONSTANTDECLARATION_DERIVED_HEADER_UNION = DERIVED_HEADER_UNION; + uint16_t CONSTANTDECLARATION_DERIVED_TUPLE = DERIVED_TUPLE; + uint16_t CONSTANTDECLARATION_TYPE_VOID = TYPE_VOID; + uint16_t CONSTANTDECLARATION_TYPE_MATCH_KIND = TYPE_MATCH_KIND; + + // probabilities for the function return types + uint16_t FUNCTIONDECLARATION_TYPE_BASE = 90; + uint16_t FUNCTIONDECLARATION_TYPE_STRUCT = 9; + // probabilities for the base types in function declarations + uint16_t FUNCTIONDECLARATION_BASETYPE_BIT = BASETYPE_BIT; + uint16_t FUNCTIONDECLARATION_BASETYPE_SIGNED_BIT = BASETYPE_SIGNED_BIT; + uint16_t FUNCTIONDECLARATION_BASETYPE_VARBIT = BASETYPE_VARBIT; + uint16_t FUNCTIONDECLARATION_BASETYPE_INT = 0; + uint16_t FUNCTIONDECLARATION_BASETYPE_ERROR = BASETYPE_ERROR; + uint16_t FUNCTIONDECLARATION_BASETYPE_BOOL = BASETYPE_BOOL; + uint16_t FUNCTIONDECLARATION_BASETYPE_STRING = BASETYPE_STRING; + uint16_t FUNCTIONDECLARATION_DERIVED_ENUM = DERIVED_ENUM; + uint16_t FUNCTIONDECLARATION_DERIVED_HEADER = DERIVED_HEADER; + // there is no support yet for header stack initialization + uint16_t FUNCTIONDECLARATION_DERIVED_HEADER_STACK = 0; + uint16_t FUNCTIONDECLARATION_DERIVED_STRUCT = DERIVED_STRUCT; + uint16_t FUNCTIONDECLARATION_DERIVED_HEADER_UNION = DERIVED_HEADER_UNION; + uint16_t FUNCTIONDECLARATION_DERIVED_TUPLE = DERIVED_TUPLE; + uint16_t FUNCTIONDECLARATION_TYPE_VOID = 1; + uint16_t FUNCTIONDECLARATION_TYPE_MATCH_KIND = TYPE_MATCH_KIND; + + // probabilities for types in header structures + uint16_t HEADERTYPEDECLARATION_FIELD_BASE = 100; + uint16_t HEADERTYPEDECLARATION_FIELD_STRUCT = 0; + // probabilities for the base types in header type declarations + uint16_t HEADERTYPEDECLARATION_BASETYPE_BIT = BASETYPE_BIT; + uint16_t HEADERTYPEDECLARATION_BASETYPE_SIGNED_BIT = BASETYPE_SIGNED_BIT; + uint16_t HEADERTYPEDECLARATION_BASETYPE_VARBIT = BASETYPE_VARBIT; + uint16_t HEADERTYPEDECLARATION_BASETYPE_INT = 0; + uint16_t HEADERTYPEDECLARATION_BASETYPE_ERROR = BASETYPE_ERROR; + uint16_t HEADERTYPEDECLARATION_BASETYPE_BOOL = 0; + uint16_t HEADERTYPEDECLARATION_BASETYPE_STRING = BASETYPE_STRING; + uint16_t HEADERTYPEDECLARATION_DERIVED_ENUM = DERIVED_ENUM; + uint16_t HEADERTYPEDECLARATION_DERIVED_HEADER = 0; + uint16_t HEADERTYPEDECLARATION_DERIVED_HEADER_STACK = 0; + // FIXME: Headers should be able to have structs? + uint16_t HEADERTYPEDECLARATION_DERIVED_STRUCT = 0; + uint16_t HEADERTYPEDECLARATION_DERIVED_HEADER_UNION = 0; + uint16_t HEADERTYPEDECLARATION_DERIVED_TUPLE = 0; + uint16_t HEADERTYPEDECLARATION_TYPE_VOID = 0; + uint16_t HEADERTYPEDECLARATION_TYPE_MATCH_KIND = 0; + + // probabilities for the parameter direction + uint16_t PARAMETER_DIR_IN = 33; + uint16_t PARAMETER_DIR_OUT = 33; + uint16_t PARAMETER_DIR_INOUT = 33; + // probabilities for the base types in parameter declarations + uint16_t PARAMETER_BASETYPE_BIT = BASETYPE_BIT; + uint16_t PARAMETER_BASETYPE_SIGNED_BIT = BASETYPE_SIGNED_BIT; + uint16_t PARAMETER_BASETYPE_VARBIT = BASETYPE_VARBIT; + uint16_t PARAMETER_BASETYPE_INT = 0; + uint16_t PARAMETER_BASETYPE_ERROR = BASETYPE_ERROR; + uint16_t PARAMETER_BASETYPE_BOOL = 0; + uint16_t PARAMETER_BASETYPE_STRING = BASETYPE_STRING; + uint16_t PARAMETER_DERIVED_ENUM = DERIVED_ENUM; + uint16_t PARAMETER_DERIVED_HEADER = DERIVED_HEADER; + uint16_t PARAMETER_DERIVED_HEADER_STACK = 0; + uint16_t PARAMETER_DERIVED_STRUCT = DERIVED_STRUCT; + uint16_t PARAMETER_DERIVED_HEADER_UNION = DERIVED_HEADER_UNION; + uint16_t PARAMETER_DERIVED_TUPLE = DERIVED_TUPLE; + uint16_t PARAMETER_TYPE_VOID = TYPE_VOID; + uint16_t PARAMETER_TYPE_MATCH_KIND = TYPE_MATCH_KIND; + // probabilities for the directionless base types in parameter declarations + // the value is coming from the control, back ends can adjust these probs + uint16_t PARAMETER_NONEDIR_BASETYPE_BIT = PARAMETER_BASETYPE_BIT; + uint16_t PARAMETER_NONEDIR_BASETYPE_SIGNED_BIT = PARAMETER_BASETYPE_SIGNED_BIT; + uint16_t PARAMETER_NONEDIR_BASETYPE_VARBIT = PARAMETER_BASETYPE_VARBIT; + uint16_t PARAMETER_NONEDIR_BASETYPE_INT = PARAMETER_BASETYPE_INT; + uint16_t PARAMETER_NONEDIR_BASETYPE_ERROR = PARAMETER_BASETYPE_ERROR; + uint16_t PARAMETER_NONEDIR_BASETYPE_BOOL = PARAMETER_BASETYPE_BOOL; + uint16_t PARAMETER_NONEDIR_BASETYPE_STRING = PARAMETER_BASETYPE_STRING; + uint16_t PARAMETER_NONEDIR_DERIVED_ENUM = PARAMETER_DERIVED_ENUM; + uint16_t PARAMETER_NONEDIR_DERIVED_HEADER = PARAMETER_DERIVED_HEADER; + uint16_t PARAMETER_NONEDIR_DERIVED_HEADER_STACK = PARAMETER_DERIVED_HEADER_STACK; + uint16_t PARAMETER_NONEDIR_DERIVED_HEADER_UNION = DERIVED_HEADER_UNION; + uint16_t PARAMETER_NONEDIR_DERIVED_STRUCT = DERIVED_STRUCT; + uint16_t PARAMETER_NONEDIR_DERIVED_TUPLE = DERIVED_TUPLE; + uint16_t PARAMETER_NONEDIR_TYPE_VOID = TYPE_VOID; + uint16_t PARAMETER_NONEDIR_TYPE_MATCH_KIND = TYPE_MATCH_KIND; + + // probabilities for types in struct structures + uint16_t STRUCTTYPEDECLARATION_FIELD_BASE = 75; + uint16_t STRUCTTYPEDECLARATION_FIELD_STRUCT = 25; + uint16_t STRUCTTYPEDECLARATION_FIELD_STACK = 0; + // probabilities for the headers struct type + uint16_t STRUCTTYPEDECLARATION_HEADERS_HEADER = 90; + uint16_t STRUCTTYPEDECLARATION_HEADERS_STACK = 10; + // probabilities for the base types in struct type declarations + uint16_t STRUCTTYPEDECLARATION_BASETYPE_BIT = BASETYPE_BIT; + uint16_t STRUCTTYPEDECLARATION_BASETYPE_SIGNED_BIT = BASETYPE_SIGNED_BIT; + uint16_t STRUCTTYPEDECLARATION_BASETYPE_VARBIT = BASETYPE_VARBIT; + uint16_t STRUCTTYPEDECLARATION_BASETYPE_INT = 0; + uint16_t STRUCTTYPEDECLARATION_BASETYPE_ERROR = BASETYPE_ERROR; + uint16_t STRUCTTYPEDECLARATION_BASETYPE_BOOL = BASETYPE_BOOL; + uint16_t STRUCTTYPEDECLARATION_BASETYPE_STRING = BASETYPE_STRING; + uint16_t STRUCTTYPEDECLARATION_DERIVED_ENUM = DERIVED_ENUM; + uint16_t STRUCTTYPEDECLARATION_DERIVED_HEADER = DERIVED_HEADER; + uint16_t STRUCTTYPEDECLARATION_DERIVED_HEADER_STACK = DERIVED_HEADER_STACK; + uint16_t STRUCTTYPEDECLARATION_DERIVED_STRUCT = DERIVED_STRUCT; + uint16_t STRUCTTYPEDECLARATION_DERIVED_HEADER_UNION = DERIVED_HEADER_UNION; + uint16_t STRUCTTYPEDECLARATION_DERIVED_TUPLE = DERIVED_TUPLE; + uint16_t STRUCTTYPEDECLARATION_TYPE_VOID = 0; + uint16_t STRUCTTYPEDECLARATION_TYPE_MATCH_KIND = 0; + // probabilities for types in struct structures + uint16_t TYPEDECLARATION_HEADER = 75; + uint16_t TYPEDECLARATION_STRUCT = 25; + uint16_t TYPEDECLARATION_UNION = 0; + + // probabilities for types in struct structures + uint16_t TYPEDEFDECLARATION_BASE = 75; + uint16_t TYPEDEFDECLARATION_STRUCTLIKE = 25; + uint16_t TYPEDEFDECLARATION_STACK = 0; + // probabilities for the base types in typedef declarations + uint16_t TYPEDEFDECLARATION_BASETYPE_BIT = BASETYPE_BIT; + uint16_t TYPEDEFDECLARATION_BASETYPE_SIGNED_BIT = BASETYPE_SIGNED_BIT; + uint16_t TYPEDEFDECLARATION_BASETYPE_VARBIT = BASETYPE_VARBIT; + uint16_t TYPEDEFDECLARATION_BASETYPE_INT = 0; + uint16_t TYPEDEFDECLARATION_BASETYPE_ERROR = BASETYPE_ERROR; + uint16_t TYPEDEFDECLARATION_BASETYPE_BOOL = 0; + uint16_t TYPEDEFDECLARATION_BASETYPE_STRING = BASETYPE_STRING; + uint16_t TYPEDEFDECLARATION_DERIVED_ENUM = DERIVED_ENUM; + uint16_t TYPEDEFDECLARATION_DERIVED_HEADER = DERIVED_HEADER; + uint16_t TYPEDEFDECLARATION_DERIVED_HEADER_STACK = DERIVED_HEADER_STACK; + uint16_t TYPEDEFDECLARATION_STRUCT = DERIVED_STRUCT; + uint16_t TYPEDEFDECLARATION_HEADER_UNION = DERIVED_HEADER_UNION; + uint16_t TYPEDEFDECLARATION_TUPLE = DERIVED_TUPLE; + uint16_t TYPEDEFDECLARATION_TYPE_VOID = TYPE_VOID; + uint16_t TYPEDEFDECLARATION_TYPE_MATCH_KIND = TYPE_MATCH_KIND; + + // probabilities for the types of constant declarations + uint16_t VARIABLEDECLARATION_TYPE_BASE = 80; + uint16_t VARIABLEDECLARATION_TYPE_STRUCT = 15; + uint16_t VARIABLEDECLARATION_TYPE_STACK = 5; + // probabilities for the base types in variable declarations + uint16_t VARIABLEDECLARATION_BASETYPE_BIT = BASETYPE_BIT; + uint16_t VARIABLEDECLARATION_BASETYPE_SIGNED_BIT = BASETYPE_SIGNED_BIT; + uint16_t VARIABLEDECLARATION_BASETYPE_VARBIT = BASETYPE_VARBIT; + uint16_t VARIABLEDECLARATION_BASETYPE_INT = 0; + uint16_t VARIABLEDECLARATION_BASETYPE_ERROR = BASETYPE_ERROR; + uint16_t VARIABLEDECLARATION_BASETYPE_BOOL = BASETYPE_BOOL; + uint16_t VARIABLEDECLARATION_BASETYPE_STRING = BASETYPE_STRING; + uint16_t VARIABLEDECLARATION_DERIVED_ENUM = DERIVED_ENUM; + uint16_t VARIABLEDECLARATION_DERIVED_HEADER = DERIVED_HEADER; + uint16_t VARIABLEDECLARATION_DERIVED_HEADER_STACK = DERIVED_HEADER_STACK; + uint16_t VARIABLEDECLARATION_DERIVED_STRUCT = DERIVED_STRUCT; + uint16_t VARIABLEDECLARATION_DERIVED_HEADER_UNION = DERIVED_HEADER_UNION; + uint16_t VARIABLEDECLARATION_DERIVED_TUPLE = DERIVED_TUPLE; + uint16_t VARIABLEDECLARATION_TYPE_VOID = TYPE_VOID; + uint16_t VARIABLEDECLARATION_TYPE_MATCH_KIND = TYPE_MATCH_KIND; +} PCT; + +static struct Declarations { + // minimum and maximum number of type declarations + uint16_t MIN_TYPE = 1; + uint16_t MAX_TYPE = 8; + + // minimum and maximum number of statements in a block statement + uint16_t BLOCKSTATEMENT_MIN_STAT = 3; + uint16_t BLOCKSTATEMENT_MAX_STAT = 10; + + // minimum and maximum number of callable declarations + uint16_t MIN_CALLABLES = 0; + uint16_t MAX_CALLABLES = 4; + + // minimum and maximum variable declarations + uint16_t MIN_VAR = 0; + uint16_t MAX_VAR = 5; + + uint16_t MIN_INSTANCE = 0; + uint16_t MAX_INSTANCE = 2; + + uint16_t MIN_ACTION = 0; + uint16_t MAX_ACTION = 2; + + uint16_t MIN_TABLE = 0; + uint16_t MAX_TABLE = 3; +} DECL; + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_PROBABILITIES_H_ */ diff --git a/backends/p4tools/modules/smith/common/scope.cpp b/backends/p4tools/modules/smith/common/scope.cpp new file mode 100644 index 0000000000..b5c38cd8b8 --- /dev/null +++ b/backends/p4tools/modules/smith/common/scope.cpp @@ -0,0 +1,342 @@ +#include "backends/p4tools/modules/smith/common/scope.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/logging.h" +#include "backends/p4tools/common/lib/util.h" +#include "ir/node.h" +#include "ir/vector.h" +#include "lib/cstring.h" +#include "lib/exceptions.h" + +namespace P4Tools::P4Smith { + +std::vector *> P4Scope::scope; +std::set P4Scope::usedNames; +std::map>> P4Scope::lvalMap; +std::map>> P4Scope::lvalMapRw; +std::set P4Scope::callableTables; + +// TODO(fruffy): This should be set by the back end +std::set P4Scope::notInitializedStructs; +Properties P4Scope::prop; +Requirements P4Scope::req; +Constraints P4Scope::constraints; +void P4Scope::addToScope(const IR::Node *node) { + auto *lScope = P4Scope::scope.back(); + lScope->push_back(node); + + if (const auto *dv = node->to()) { + addLval(dv->type, dv->name.name); + } else if (const auto *dc = node->to()) { + addLval(dc->type, dc->name.name, true); + } +} + +void P4Scope::startLocalScope() { + auto *localScope = new IR::Vector(); + scope.push_back(localScope); +} + +void P4Scope::endLocalScope() { + IR::Vector *localScope = scope.back(); + + for (const auto *node : *localScope) { + if (const auto *decl = node->to()) { + deleteLval(decl->type, decl->name.name); + } else if (const auto *dc = node->to()) { + deleteLval(dc->type, dc->name.name); + } else if (const auto *param = node->to()) { + deleteLval(param->type, param->name.name); + } else if (const auto *tbl = node->to()) { + callableTables.erase(tbl); + } + } + + delete localScope; + scope.pop_back(); +} + +void addCompoundLvals(const IR::Type_StructLike *sl_type, cstring sl_name, bool read_only) { + for (const auto *field : sl_type->fields) { + std::stringstream ss; + ss.str(""); + ss << sl_name << "." << field->name.name; + cstring fieldName(ss.str()); + P4Scope::addLval(field->type, fieldName, read_only); + } +} + +void deleteCompoundLvals(const IR::Type_StructLike *sl_type, cstring sl_name) { + for (const auto *field : sl_type->fields) { + std::stringstream ss; + ss.str(""); + ss << sl_name << "." << field->name.name; + cstring fieldName(ss.str()); + P4Scope::deleteLval(field->type, fieldName); + } +} + +void P4Scope::deleteLval(const IR::Type *tp, cstring name) { + cstring typeKey; + int bitBucket = 0; + + if (const auto *tb = tp->to()) { + typeKey = IR::Type_Bits::static_type_name(); + bitBucket = tb->width_bits(); + } else if (const auto *tb = tp->to()) { + typeKey = IR::Type_Boolean::static_type_name(); + bitBucket = tb->width_bits(); + } else if (tp->is()) { + typeKey = IR::Type_InfInt::static_type_name(); + bitBucket = 1; + } else if (const auto *ts = tp->to()) { + size_t stackSize = ts->getSize(); + typeKey = IR::Type_Stack::static_type_name(); + bitBucket = 1; + if (const auto *tnType = ts->elementType->to()) { + std::stringstream ss; + ss.str(""); + ss << name << "[" << (stackSize - 1) << "]"; + cstring stackName(ss.str()); + deleteLval(tnType, stackName); + } else { + BUG("Type_Name %s not yet supported", ts->elementType->node_type_name()); + } + } else if (const auto *tn = tp->to()) { + auto tnName = tn->path->name.name; + if (tnName == "packet_in") { + return; + } + if (const auto *td = getTypeByName(tnName)) { + if (const auto *tnType = td->to()) { + typeKey = tnName; + // width_bits should work here, do !know why not... + // bit_bucket = P4Scope::compound_type[tn_name]->width_bits(); + bitBucket = 1; + deleteCompoundLvals(tnType, name); + } else { + BUG("Type_Name %s !found!", td->node_type_name()); + } + } else { + printInfo("Type %s does not exist!\n", tnName.c_str()); + return; + } + } else { + BUG("Type %s not yet supported", tp->node_type_name()); + } + lvalMap[typeKey][bitBucket].erase(name); + + // delete values in the normal map + if (lvalMap[typeKey][bitBucket].empty()) { + lvalMap[typeKey].erase(bitBucket); + } + + // delete values in the rw map + if (lvalMapRw.count(typeKey) != 0) { + if (lvalMapRw[typeKey].count(bitBucket) != 0) { + lvalMapRw[typeKey][bitBucket].erase(name); + if (lvalMapRw[typeKey][bitBucket].empty()) { + lvalMapRw[typeKey].erase(bitBucket); + } + } + } + // delete empty type entries + if (lvalMap[typeKey].empty()) { + lvalMap.erase(typeKey); + } + if (lvalMapRw[typeKey].empty()) { + lvalMapRw.erase(typeKey); + } +} + +void P4Scope::addLval(const IR::Type *tp, cstring name, bool read_only) { + cstring typeKey; + int bitBucket = 0; + + if (const auto *tb = tp->to()) { + typeKey = IR::Type_Bits::static_type_name(); + bitBucket = tb->width_bits(); + } else if (const auto *tb = tp->to()) { + typeKey = IR::Type_Boolean::static_type_name(); + bitBucket = tb->width_bits(); + } else if (tp->is()) { + typeKey = IR::Type_InfInt::static_type_name(); + bitBucket = 1; + } else if (const auto *ts = tp->to()) { + size_t stackSize = ts->getSize(); + typeKey = IR::Type_Stack::static_type_name(); + bitBucket = 1; + if (const auto *tnType = ts->elementType->to()) { + std::stringstream ss; + ss.str(""); + ss << name << "[" << (stackSize - 1) << "]"; + cstring stackName(ss.str()); + addLval(tnType, stackName, read_only); + } else { + BUG("Type_Name %s not yet supported", ts->elementType->node_type_name()); + } + } else if (const auto *tn = tp->to()) { + auto tnName = tn->path->name.name; + // FIXME: this could be better + if (tnName == "packet_in") { + return; + } + if (const auto *td = getTypeByName(tnName)) { + if (const auto *tnType = td->to()) { + // width_bits should work here, do !know why not... + typeKey = tnName; + // does !work for some reason... + // bit_bucket = P4Scope::compound_type[tn_name]->width_bits(); + bitBucket = 1; + addCompoundLvals(tnType, name, read_only); + } else { + BUG("Type_Name %s not yet supported", td->node_type_name()); + } + } else { + BUG("Type %s does not exist", tnName); + } + } else { + BUG("Type %s not yet supported", tp->node_type_name()); + } + if (!read_only) { + lvalMapRw[typeKey][bitBucket].insert(name); + } + lvalMap[typeKey][bitBucket].insert(name); +} + +std::set P4Scope::getCandidateLvals(const IR::Type *tp, bool must_write) { + cstring typeKey; + int bitBucket = 0; + + if (const auto *tb = tp->to()) { + typeKey = IR::Type_Bits::static_type_name(); + bitBucket = tb->width_bits(); + } else if (const auto *tb = tp->to()) { + typeKey = IR::Type_Boolean::static_type_name(); + bitBucket = tb->width_bits(); + } else if (tp->is()) { + typeKey = IR::Type_InfInt::static_type_name(); + bitBucket = 1; + } else if (const auto *ts = tp->to()) { + typeKey = ts->name.name; + bitBucket = 1; + } else if (const auto *tn = tp->to()) { + auto tnName = tn->path->name.name; + if (getTypeByName(tnName) != nullptr) { + typeKey = tnName; + // bit_bucket = td->width_bits(); + bitBucket = 1; + } else { + BUG("Type_name refers to unknown type %s", tnName); + } + } else { + BUG("Type %s not yet supported", tp->node_type_name()); + } + + std::map>> lookupMap; + + if (must_write) { + lookupMap = lvalMapRw; + } else { + lookupMap = lvalMap; + } + + if (lookupMap.count(typeKey) == 0) { + return {}; + } + auto keyTypes = lookupMap[typeKey]; + if (keyTypes.count(bitBucket) == 0) { + return {}; + } + + return keyTypes[bitBucket]; +} + +std::optional>> P4Scope::getWriteableLvalForTypeKey( + cstring typeKey) { + if (lvalMapRw.find(typeKey) == lvalMapRw.end()) { + return std::nullopt; + } + return lvalMapRw.at(typeKey); +} +bool P4Scope::hasWriteableLval(cstring typeKey) { + return lvalMapRw.find(typeKey) != lvalMapRw.end(); +} + +bool P4Scope::checkLval(const IR::Type *tp, bool must_write) { + std::set candidates = getCandidateLvals(tp, must_write); + return !candidates.empty(); +} + +cstring P4Scope::pickLval(const IR::Type *tp, bool must_write) { + std::set candidates = getCandidateLvals(tp, must_write); + + if (candidates.empty()) { + BUG("Invalid Type Query, %s not found", tp->toString()); + } + size_t idx = Utils::getRandInt(0, candidates.size() - 1); + auto lval = std::begin(candidates); + // "advance" the iterator idx times + std::advance(lval, idx); + + return *lval; +} + +const IR::Type_Bits *P4Scope::pickDeclaredBitType(bool must_write) { + std::map>> lookupMap; + + if (must_write) { + lookupMap = lvalMapRw; + } else { + lookupMap = lvalMap; + } + + cstring bitKey = IR::Type_Bits::static_type_name(); + if (lookupMap.count(bitKey) == 0) { + return nullptr; + } + auto keyTypes = lookupMap[bitKey]; + size_t idx = Utils::getRandInt(0, keyTypes.size() - 1); + int bitWidth = next(keyTypes.begin(), idx)->first; + return IR::Type_Bits::get(bitWidth, false); +} + +std::vector P4Scope::getFilteredDecls(std::set filter) { + std::vector ret; + for (auto *subScope : scope) { + for (const auto *node : *subScope) { + cstring name = node->node_type_name(); + if (filter.find(name) == filter.end()) { + if (const auto *decl = node->to()) { + ret.push_back(decl); + } + } + } + } + return ret; +} + +std::set *P4Scope::getCallableTables() { return &callableTables; } + +const IR::Type_Declaration *P4Scope::getTypeByName(cstring name) { + for (auto *subScope : scope) { + for (const auto *node : *subScope) { + if (const auto *decl = node->to()) { + if (decl->name.name == name) { + return decl; + } + } + } + } + return nullptr; +} +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/common/scope.h b/backends/p4tools/modules/smith/common/scope.h new file mode 100644 index 0000000000..d0e6c5e7a8 --- /dev/null +++ b/backends/p4tools/modules/smith/common/scope.h @@ -0,0 +1,124 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_SCOPE_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_SCOPE_H_ + +#include +#include +#include +#include +#include + +#include "ir/ir.h" +#include "ir/node.h" +#include "ir/vector.h" +#include "lib/cstring.h" + +namespace P4Tools::P4Smith { + +struct Requirements { + bool require_scalar{false}; + bool compile_time_known{false}; + bool no_methodcalls{false}; + bool not_zero{false}; + bool not_negative{false}; + bool byte_align_headers{false}; + int shift_width{8}; + Requirements() + + = default; +}; + +struct Constraints { + bool const_header_stack_index{false}; + bool const_lshift_count{false}; + bool single_stage_actions{false}; + int max_phv_container_width{0}; + Constraints() + + = default; +}; + +struct Properties { + bool width_unknown{false}; + bool has_methodcall{false}; + bool in_action{false}; + size_t depth = 0; + // This means we are in a block that returns. + // We need to return an expression with the specified type. + const IR::Type *ret_type = nullptr; + Properties() = default; +}; + +class P4Scope { + public: + /// This is a list of subscopes. + static std::vector *> scope; + + /// Maintain a set of names we have already used to avoid duplicates. + static std::set usedNames; + + /// This is a map of usable lvalues we store to be used for references. + static std::map>> lvalMap; + + /// A subset of the lval map that includes rw values. + static std::map>> lvalMapRw; + + /// TODO: Maybe we can just remove tables from the declarations list? + /// This is back-end specific. + static std::set callableTables; + + /// Structs that should not be initialized because they are incomplete. + static std::set notInitializedStructs; + + /// Properties that define the current state of the program. + /// For example, when should a return expression must be returned in a block. + static Properties prop; + + /// Back-end or node-specific restrictions. + static Requirements req; + + /// This defines all constraints specific to various targets or back-ends. + static Constraints constraints; + + P4Scope() = default; + + ~P4Scope() = default; + + static void addToScope(const IR::Node *n); + static void startLocalScope(); + static void endLocalScope(); + + static void addLval(const IR::Type *tp, cstring name, bool read_only = false); + static bool checkLval(const IR::Type *tp, bool must_write = false); + static cstring pickLval(const IR::Type *tp, bool must_write = false); + static void deleteLval(const IR::Type *tp, cstring name); + static std::set getCandidateLvals(const IR::Type *tp, bool must_write = true); + static bool hasWriteableLval(cstring typeKey); + static std::optional>> getWriteableLvalForTypeKey( + cstring typeKey); + + static const IR::Type_Bits *pickDeclaredBitType(bool must_write = false); + + static const IR::Type_Declaration *getTypeByName(cstring name); + + // template to get all declarations + // C++ is so shit... templates must be inlined to be generally usable. + template + static std::vector getDecls() { + std::vector ret; + + for (auto *subScope : scope) { + for (const auto *node : *subScope) { + if (const T *tmpObj = node->to()) { + ret.push_back(tmpObj); + } + } + } + return ret; + } + + static std::vector getFilteredDecls(std::set filter); + static std::set *getCallableTables(); +}; +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_SCOPE_H_ */ diff --git a/backends/p4tools/modules/smith/common/statements.cpp b/backends/p4tools/modules/smith/common/statements.cpp new file mode 100644 index 0000000000..2b54ba482a --- /dev/null +++ b/backends/p4tools/modules/smith/common/statements.cpp @@ -0,0 +1,391 @@ +#include "backends/p4tools/modules/smith/common/statements.h" + +#include +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/ir-generated.h" +#include "ir/vector.h" +#include "lib/cstring.h" +#include "lib/exceptions.h" +#include "lib/log.h" + +namespace P4Tools::P4Smith { + +IR::Statement *StatementGenerator::genStatement(bool is_in_func) { + // functions can!have exit statements so set their probability to zero + int64_t pctExit = PCT.STATEMENT_EXIT; + if (is_in_func) { + pctExit = 0; + } + std::vector percent = {PCT.STATEMENT_SWITCH, + PCT.STATEMENT_ASSIGNMENTORMETHODCALL, + PCT.STATEMENT_IF, + PCT.STATEMENT_RETURN, + pctExit, + PCT.STATEMENT_BLOCK}; + IR::Statement *stmt = nullptr; + bool useDefaultStmt = false; + + switch (Utils::getRandInt(percent)) { + case 0: { + stmt = genSwitchStatement(); + if (stmt == nullptr) { + useDefaultStmt = true; + } + break; + } + case 1: { + useDefaultStmt = true; + break; + } + case 2: { + stmt = genConditionalStatement(is_in_func); + break; + } + case 3: { + stmt = genReturnStatement(P4Scope::prop.ret_type); + break; + } + case 4: { + stmt = genExitStatement(); + break; + } + case 5: { + stmt = genBlockStatement(is_in_func); + break; + } + } + if (useDefaultStmt) { + stmt = genAssignmentOrMethodCallStatement(is_in_func); + } + return stmt; +} + +IR::IndexedVector StatementGenerator::genBlockStatementHelper(bool is_in_func) { + // Randomize the total number of statements. + int maxStatements = + Utils::getRandInt(DECL.BLOCKSTATEMENT_MIN_STAT, DECL.BLOCKSTATEMENT_MAX_STAT); + IR::IndexedVector statOrDecls; + + // Put tab_name .apply() after some initializations. + for (int numStat = 0; numStat <= maxStatements; numStat++) { + IR::StatOrDecl *stmt = + target().declarationGenerator().generateRandomStatementOrDeclaration(is_in_func); + if (stmt == nullptr) { + BUG("Statement in BlockStatement should not be nullptr!"); + } + statOrDecls.push_back(stmt); + } + return statOrDecls; +} + +IR::BlockStatement *StatementGenerator::genBlockStatement(bool is_in_func) { + P4Scope::startLocalScope(); + + auto statOrDecls = genBlockStatementHelper(is_in_func); + + if (is_in_func && (P4Scope::prop.ret_type->to() == nullptr)) { + auto *retStat = genReturnStatement(P4Scope::prop.ret_type); + statOrDecls.push_back(retStat); + } + P4Scope::endLocalScope(); + + return new IR::BlockStatement(statOrDecls); +} + +IR::IfStatement *StatementGenerator::genConditionalStatement(bool is_in_func) { + IR::Expression *cond = nullptr; + IR::Statement *ifTrue = nullptr; + IR::Statement *ifFalse = nullptr; + + cond = target().expressionGenerator().genExpression(IR::Type_Boolean::get()); + if (cond == nullptr) { + BUG("cond in IfStatement should !be nullptr!"); + } + ifTrue = genStatement(is_in_func); + if (ifTrue == nullptr) { + // could !generate a statement + // this happens when there is now way to generate an assignment + ifTrue = new IR::EmptyStatement(); + } + ifFalse = genStatement(is_in_func); + if (ifFalse == nullptr) { + // could !generate a statement + // this happens when there is now way to generate an assignment + ifFalse = new IR::EmptyStatement(); + } + return new IR::IfStatement(cond, ifTrue, ifFalse); +} + +void StatementGenerator::removeLval(const IR::Expression *left, const IR::Type *type) { + cstring lvalStr = nullptr; + if (const auto *path = left->to()) { + lvalStr = path->path->name.name; + } else if (const auto *mem = left->to()) { + lvalStr = mem->member.name; + } else if (const auto *slice = left->to()) { + lvalStr = slice->e0->to()->path->name.name; + } else if (const auto *arrIdx = left->to()) { + lvalStr = arrIdx->left->to()->path->name.name; + } + + P4Scope::deleteLval(type, lvalStr); +} + +IR::Statement *StatementGenerator::genAssignmentStatement() { + IR::AssignmentStatement *assignstat = nullptr; + IR::Expression *left = nullptr; + IR::Expression *right = nullptr; + + std::vector percent = {PCT.ASSIGNMENTORMETHODCALLSTATEMENT_ASSIGN_BIT, + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_ASSIGN_STRUCTLIKE}; + + switch (Utils::getRandInt(percent)) { + case 0: { + const auto *bitType = P4Scope::pickDeclaredBitType(true); + // Ideally this should have a fallback option + if (bitType == nullptr) { + LOG3("Could not find writable bit lval for assignment!\n"); + // TODO(fruffy): Find a more meaningful assignment statement + return nullptr; + } + left = target().expressionGenerator().pickLvalOrSlice(bitType); + if (P4Scope::constraints.single_stage_actions) { + removeLval(left, bitType); + } + right = target().expressionGenerator().genExpression(bitType); + return new IR::AssignmentStatement(left, right); + } + case 1: + // TODO(fruffy): Compound types + break; + } + + return assignstat; +} + +IR::Statement *StatementGenerator::genMethodCallExpression(const IR::PathExpression *methodName, + const IR::ParameterList ¶ms) { + auto *args = new IR::Vector(); + IR::IndexedVector decls; + + // all this boilerplate should be somewhere else... + P4Scope::startLocalScope(); + + for (const auto *par : params) { + IR::Argument *arg = nullptr; + // TODO(fruffy): Fix the direction none issue here. + if (!target().expressionGenerator().checkInputArg(par) && + par->direction != IR::Direction::None) { + auto name = cstring(getRandomString(6)); + auto *expr = target().expressionGenerator().genExpression(par->type); + // all this boilerplate should be somewhere else... + auto *decl = new IR::Declaration_Variable(name, par->type, expr); + P4Scope::addToScope(decl); + decls.push_back(decl); + } + arg = new IR::Argument(target().expressionGenerator().genInputArg(par)); + args->push_back(arg); + } + auto *mce = new IR::MethodCallExpression(methodName, args); + auto *mcs = new IR::MethodCallStatement(mce); + P4Scope::endLocalScope(); + if (decls.empty()) { + return mcs; + } + auto *blkStmt = new IR::BlockStatement(decls); + blkStmt->push_back(mcs); + return blkStmt; +} + +IR::Statement *StatementGenerator::genMethodCallStatement(bool is_in_func) { + IR::MethodCallExpression *mce = nullptr; + + // functions cannot call actions or tables so set their chance to zero + int16_t tmpActionPct = PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_ACTION; + int16_t tmpTblPct = PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_TABLE; + int16_t tmpCtrlPct = PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_CTRL; + if (is_in_func) { + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_ACTION = 0; + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_TABLE = 0; + } + if (P4Scope::prop.in_action) { + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_CTRL = 0; + } + std::vector percent = {PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_ACTION, + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_FUNCTION, + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_TABLE, + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_CTRL, + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_BUILT_IN}; + + switch (Utils::getRandInt(percent)) { + case 0: { + auto actions = P4Scope::getDecls(); + if (actions.empty()) { + break; + } + size_t idx = Utils::getRandInt(0, actions.size() - 1); + const auto *p4Fun = actions.at(idx); + auto params = p4Fun->getParameters()->parameters; + auto *methodName = new IR::PathExpression(p4Fun->name); + return genMethodCallExpression(methodName, params); + } + case 1: { + auto funcs = P4Scope::getDecls(); + if (funcs.empty()) { + break; + } + size_t idx = Utils::getRandInt(0, funcs.size() - 1); + const auto *p4Fun = funcs.at(idx); + auto params = p4Fun->getParameters()->parameters; + auto *methodName = new IR::PathExpression(p4Fun->name); + return genMethodCallExpression(methodName, params); + } + case 2: { + auto *tblSet = P4Scope::getCallableTables(); + if (tblSet->empty()) { + break; + } + auto idx = Utils::getRandInt(0, tblSet->size() - 1); + auto tblIter = std::begin(*tblSet); + std::advance(tblIter, idx); + const IR::P4Table *tbl = *tblIter; + auto *mem = new IR::Member(new IR::PathExpression(tbl->name), "apply"); + mce = new IR::MethodCallExpression(mem); + tblSet->erase(tblIter); + break; + } + case 3: { + auto decls = P4Scope::getDecls(); + if (decls.empty()) { + break; + } + auto idx = Utils::getRandInt(0, decls.size() - 1); + auto declIter = std::begin(decls); + std::advance(declIter, idx); + const IR::Declaration_Instance *declInstance = *declIter; + // avoid member here + std::stringstream tmpMethodStr; + tmpMethodStr << declInstance->name << ".apply"; + cstring tmpMethodCstr(tmpMethodStr.str()); + auto *methodName = new IR::PathExpression(tmpMethodCstr); + const auto *typeName = declInstance->type->to(); + + const auto *resolvedType = P4Scope::getTypeByName(typeName->path->name); + if (resolvedType == nullptr) { + BUG("Type Name %s not found", typeName->path->name); + } + if (const auto *ctrl = resolvedType->to()) { + auto params = ctrl->getApplyParameters()->parameters; + return genMethodCallExpression(methodName, params); + } + BUG("Declaration Instance type %s not yet supported", + declInstance->type->node_type_name()); + } + case 4: { + auto hdrs = P4Scope::getDecls(); + if (hdrs.empty()) { + break; + } + std::set hdrLvals; + for (const auto *hdr : hdrs) { + auto availableLvals = P4Scope::getCandidateLvals(hdr, true); + hdrLvals.insert(availableLvals.begin(), availableLvals.end()); + } + if (hdrLvals.empty()) { + break; + } + auto idx = Utils::getRandInt(0, hdrLvals.size() - 1); + auto hdrLvalIter = std::begin(hdrLvals); + std::advance(hdrLvalIter, idx); + cstring hdrLval = *hdrLvalIter; + const IR::Expression *member = nullptr; + if (Utils::getRandInt(0, 1) != 0) { + member = new IR::Member(new IR::PathExpression(hdrLval), "setValid"); + } else { + member = new IR::Member(new IR::PathExpression(hdrLval), "setInvalid"); + } + mce = new IR::MethodCallExpression(member); + break; + } + } + // restore previous probabilities + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_ACTION = tmpActionPct; + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_TABLE = tmpTblPct; + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_CTRL = tmpCtrlPct; + if (mce != nullptr) { + return new IR::MethodCallStatement(mce); + } + // unable to return a methodcall, return an assignment instead + return genAssignmentStatement(); +} + +IR::Statement *StatementGenerator::genAssignmentOrMethodCallStatement(bool is_in_func) { + std::vector percent = {PCT.ASSIGNMENTORMETHODCALLSTATEMENT_ASSIGN, + PCT.ASSIGNMENTORMETHODCALLSTATEMENT_METHOD_CALL}; + auto val = Utils::getRandInt(percent); + if (val == 0) { + return genAssignmentStatement(); + } + return genMethodCallStatement(is_in_func); +} + +IR::ExitStatement *StatementGenerator::genExitStatement() { return new IR::ExitStatement(); } + +IR::SwitchStatement *StatementGenerator::genSwitchStatement() { + // get the expression + auto *tblSet = P4Scope::getCallableTables(); + + // return nullptr if there are no tables left + if (tblSet->empty()) { + return nullptr; + } + auto idx = Utils::getRandInt(0, tblSet->size() - 1); + auto tblIter = std::begin(*tblSet); + + std::advance(tblIter, idx); + const IR::P4Table *tbl = *tblIter; + auto *expr = new IR::Member( + new IR::MethodCallExpression(new IR::Member(new IR::PathExpression(tbl->name), "apply")), + "action_run"); + tblSet->erase(tblIter); + + // get the switch cases + IR::Vector switchCases; + for (const auto *tabProperty : tbl->properties->properties) { + if (tabProperty->name.name == IR::TableProperties::actionsPropertyName) { + const auto *property = tabProperty->value->to(); + for (const auto *action : property->actionList) { + cstring actName = action->getName(); + auto *blkStat = genBlockStatement(false); + auto *switchCase = new IR::SwitchCase(new IR::PathExpression(actName), blkStat); + switchCases.push_back(switchCase); + } + } + } + + return new IR::SwitchStatement(expr, switchCases); +} + +IR::ReturnStatement *StatementGenerator::genReturnStatement(const IR::Type *tp) { + IR::Expression *expr = nullptr; + + // Type_Void is also empty + if ((tp != nullptr) && (tp->to() == nullptr)) { + expr = target().expressionGenerator().genExpression(tp); + } + return new IR::ReturnStatement(expr); +} + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/common/statements.h b/backends/p4tools/modules/smith/common/statements.h new file mode 100644 index 0000000000..2f2f7588eb --- /dev/null +++ b/backends/p4tools/modules/smith/common/statements.h @@ -0,0 +1,44 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_STATEMENTS_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_STATEMENTS_H_ + +#include "backends/p4tools/modules/smith/common/generator.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" + +namespace P4Tools::P4Smith { + +class StatementGenerator : public Generator { + public: + explicit StatementGenerator(const SmithTarget &target) : Generator(target) {} + + virtual ~StatementGenerator() = default; + + virtual IR::Statement *genStatement(bool is_in_func); + + IR::IndexedVector genBlockStatementHelper(bool is_in_func); + + virtual IR::BlockStatement *genBlockStatement(bool is_in_func); + + virtual IR::IfStatement *genConditionalStatement(bool is_in_func); + + static void removeLval(const IR::Expression *left, const IR::Type *type); + + virtual IR::Statement *genAssignmentStatement(); + + virtual IR::Statement *genMethodCallExpression(const IR::PathExpression *methodName, + const IR::ParameterList ¶ms); + + virtual IR::Statement *genMethodCallStatement(bool is_in_func); + + virtual IR::Statement *genAssignmentOrMethodCallStatement(bool is_in_func); + + virtual IR::ExitStatement *genExitStatement(); + + virtual IR::SwitchStatement *genSwitchStatement(); + + IR::ReturnStatement *genReturnStatement(const IR::Type *tp = nullptr); +}; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_STATEMENTS_H_ */ diff --git a/backends/p4tools/modules/smith/common/table.cpp b/backends/p4tools/modules/smith/common/table.cpp new file mode 100644 index 0000000000..c8aa637087 --- /dev/null +++ b/backends/p4tools/modules/smith/common/table.cpp @@ -0,0 +1,159 @@ +#include "backends/p4tools/modules/smith/common/table.h" + +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/logging.h" +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/vector.h" +#include "lib/cstring.h" +#include "lib/exceptions.h" + +namespace P4Tools::P4Smith { + +IR::P4Table *TableGenerator::genTableDeclaration() { + IR::TableProperties *tbProperties = genTablePropertyList(); + cstring name = getRandomString(6); + auto *ret = new IR::P4Table(name, tbProperties); + P4Scope::addToScope(ret); + P4Scope::callableTables.emplace(ret); + return ret; +} + +IR::TableProperties *TableGenerator::genTablePropertyList() { + IR::IndexedVector tabProperties; + + tabProperties.push_back(genKeyProperty()); + tabProperties.push_back(genActionListProperty()); + + return new IR::TableProperties(tabProperties); +} + +IR::Key *TableGenerator::genKeyElementList(size_t len) { + IR::Vector keys; + + for (size_t i = 0; i < len; i++) { + // TODO(fruffy): More types than just exact + IR::KeyElement *key = genKeyElement("exact"); + if (key == nullptr) { + continue; + } + // @name + // Tao: actually, this may never happen + const auto *keyAnno = key->annotations->annotations.at(0); + const auto *annotExpr = keyAnno->expr.at(0); + cstring keyAnnotatName; + if (annotExpr->is()) { + const auto *strExpr = annotExpr->to(); + keyAnnotatName = strExpr->value; + } else { + BUG("must be a string literal"); + } + + keys.push_back(key); + } + + return new IR::Key(keys); +} + +IR::KeyElement *TableGenerator::genKeyElement(IR::ID match_kind) { + auto *match = new IR::PathExpression(std::move(match_kind)); + auto *annotations = target().declarationGenerator().genAnnotation(); + auto *bitType = P4Scope::pickDeclaredBitType(false); + + // Ideally this should have a fallback option + if (bitType == nullptr) { + printInfo("Could not find key lval for key matches\n"); + return nullptr; + } + // this expression can!be an infinite precision integer + P4Scope::req.require_scalar = true; + auto *expr = target().expressionGenerator().genExpression(bitType); + P4Scope::req.require_scalar = false; + auto *key = new IR::KeyElement(annotations, expr, match); + + return key; +} + +IR::Property *TableGenerator::genKeyProperty() { + cstring name = IR::TableProperties::keyPropertyName; + auto *keys = genKeyElementList(Utils::getRandInt(0, 3)); + + // isConstant --> false + return new IR::Property(name, keys, false); +} + +IR::MethodCallExpression *TableGenerator::genTableActionCall(cstring method_name, + const IR::ParameterList ¶ms) { + auto *args = new IR::Vector(); + IR::IndexedVector decls; + + for (const auto *par : params) { + if (!target().expressionGenerator().checkInputArg(par)) { + return nullptr; + } + if (par->direction == IR::Direction::None) { + // do nothing; in tables directionless parameters are + // set by the control plane + continue; + } + IR::Argument *arg = nullptr; + if (par->direction == IR::Direction::In) { + // the generated expression needs to be compile-time known + P4Scope::req.compile_time_known = true; + arg = new IR::Argument(target().expressionGenerator().genExpression(par->type)); + P4Scope::req.compile_time_known = false; + } else { + arg = new IR::Argument(target().expressionGenerator().pickLvalOrSlice(par->type)); + } + args->push_back(arg); + } + auto *pathExpr = new IR::PathExpression(method_name); + return new IR::MethodCallExpression(pathExpr, args); +} + +IR::ActionList *TableGenerator::genActionList(size_t len) { + IR::IndexedVector actList; + auto p4Actions = P4Scope::getDecls(); + std::set actNames; + + if (p4Actions.empty()) { + return new IR::ActionList(actList); + } + for (size_t i = 0; i < len; i++) { + size_t idx = Utils::getRandInt(0, p4Actions.size() - 1); + const auto *p4Act = p4Actions[idx]; + cstring actName = p4Act->name.name; + + if (actNames.find(actName) != actNames.end()) { + continue; + } + actNames.insert(actName); + + const auto *params = p4Act->parameters; + + IR::MethodCallExpression *mce = genTableActionCall(actName, *params); + if (mce != nullptr) { + auto *actlistEle = new IR::ActionListElement(mce); + actList.push_back(actlistEle); + } + } + return new IR::ActionList(actList); +} + +IR::Property *TableGenerator::genActionListProperty() { + cstring name = IR::TableProperties::actionsPropertyName; + auto *acts = genActionList(Utils::getRandInt(0, 3)); + + return new IR::Property(name, acts, false); +} + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/common/table.h b/backends/p4tools/modules/smith/common/table.h new file mode 100644 index 0000000000..1edcde3332 --- /dev/null +++ b/backends/p4tools/modules/smith/common/table.h @@ -0,0 +1,37 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_TABLE_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_TABLE_H_ +#include + +#include "backends/p4tools/modules/smith/common/generator.h" +#include "ir/ir.h" +#include "lib/cstring.h" + +namespace P4Tools::P4Smith { + +class TableGenerator : public Generator { + public: + explicit TableGenerator(const SmithTarget &target) : Generator(target) {} + + virtual ~TableGenerator() = default; + + virtual IR::P4Table *genTableDeclaration(); + + virtual IR::TableProperties *genTablePropertyList(); + + virtual IR::KeyElement *genKeyElement(IR::ID match_kind); + + virtual IR::Key *genKeyElementList(size_t len); + + virtual IR::Property *genKeyProperty(); + + virtual IR::MethodCallExpression *genTableActionCall(cstring method_name, + const IR::ParameterList ¶ms); + + virtual IR::ActionList *genActionList(size_t len); + + IR::Property *genActionListProperty(); +}; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_COMMON_TABLE_H_ */ diff --git a/backends/p4tools/modules/smith/core/target.cpp b/backends/p4tools/modules/smith/core/target.cpp new file mode 100644 index 0000000000..9aeee340c7 --- /dev/null +++ b/backends/p4tools/modules/smith/core/target.cpp @@ -0,0 +1,15 @@ +#include "backends/p4tools/modules/smith/core/target.h" + +#include + +#include "backends/p4tools/common/compiler/compiler_target.h" +#include "backends/p4tools/common/core/target.h" + +namespace P4Tools::P4Smith { + +SmithTarget::SmithTarget(const std::string &deviceName, const std::string &archName) + : P4Tools::CompilerTarget("smith", deviceName, archName) {} + +const SmithTarget &SmithTarget::get() { return P4Tools::Target::get("smith"); } + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/core/target.h b/backends/p4tools/modules/smith/core/target.h new file mode 100644 index 0000000000..4131f59dea --- /dev/null +++ b/backends/p4tools/modules/smith/core/target.h @@ -0,0 +1,42 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_CORE_TARGET_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_CORE_TARGET_H_ + +#include +#include + +#include "backends/p4tools/common/compiler/compiler_target.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/common/table.h" +#include "ir/ir.h" + +namespace P4Tools::P4Smith { + +class SmithTarget : public CompilerTarget { + public: + /// @returns the singleton instance for the current target. + static const SmithTarget &get(); + + /// Write the necessary #include directives and other helpful constructs to the specified + /// stream. + [[nodiscard]] virtual int writeTargetPreamble(std::ostream *ostream) const = 0; + + [[nodiscard]] virtual const IR::P4Program *generateP4Program() const = 0; + + [[nodiscard]] virtual DeclarationGenerator &declarationGenerator() const = 0; + [[nodiscard]] virtual ExpressionGenerator &expressionGenerator() const = 0; + [[nodiscard]] virtual StatementGenerator &statementGenerator() const = 0; + [[nodiscard]] virtual ParserGenerator &parserGenerator() const = 0; + [[nodiscard]] virtual TableGenerator &tableGenerator() const = 0; + + protected: + explicit SmithTarget(const std::string &deviceName, const std::string &archName); + + private: +}; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_CORE_TARGET_H_ */ diff --git a/backends/p4tools/modules/smith/main.cpp b/backends/p4tools/modules/smith/main.cpp new file mode 100644 index 0000000000..ca1f798313 --- /dev/null +++ b/backends/p4tools/modules/smith/main.cpp @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/logging.h" +#include "backends/p4tools/modules/smith/smith.h" +#include "lib/crash.h" +#include "lib/exceptions.h" +#include "lib/timer.h" + +int main(int argc, char **argv) { + setup_signals(); + + std::vector args; + args.reserve(argc); + for (int i = 0; i < argc; ++i) { + args.push_back(argv[i]); + } + + int result = EXIT_SUCCESS; + try { + Util::ScopedTimer timer("P4Smith Main"); + result = P4Tools::P4Smith::Smith().main(args); + } catch (const Util::CompilerBug &e) { + std::cerr << "Internal error: " << e.what() << '\n'; + std::cerr << "Please submit a bug report with your code." << '\n'; + result = EXIT_FAILURE; + } catch (const Util::CompilerUnimplemented &e) { + std::cerr << e.what() << '\n'; + result = EXIT_FAILURE; + } catch (const Util::CompilationError &e) { + std::cerr << e.what() << '\n'; + result = EXIT_FAILURE; + } catch (const std::exception &e) { + std::cerr << "Internal error: " << e.what() << '\n'; + std::cerr << "Please submit a bug report with your code." << '\n'; + result = EXIT_FAILURE; + } catch (...) { + std::cerr << "Internal error. Please submit a bug report with your code." << '\n'; + result = EXIT_FAILURE; + } + P4Tools::printPerformanceReport(); + return result; +} diff --git a/backends/p4tools/modules/smith/options.cpp b/backends/p4tools/modules/smith/options.cpp new file mode 100644 index 0000000000..c3f7ab35f5 --- /dev/null +++ b/backends/p4tools/modules/smith/options.cpp @@ -0,0 +1,45 @@ +#include "backends/p4tools/modules/smith/options.h" + +#include +#include +#include + +#include "backends/p4tools/common/options.h" +#include "backends/p4tools/modules/smith/toolname.h" +#include "lib/compile_context.h" +#include "lib/error.h" +#include "lib/exceptions.h" + +namespace P4Tools { + +SmithOptions &SmithOptions::get() { + static SmithOptions INSTANCE; + return INSTANCE; +} + +const char *SmithOptions::getIncludePath() { + P4C_UNIMPLEMENTED("getIncludePath is not implemented for P4Smith."); +} + +void SmithOptions::processArgs(const std::vector &args) { + // Convert to the standard (argc, argv) pair. + int argc = 0; + char **argv = nullptr; + std::tie(argc, argv) = convertArgs(args); + + // Establish a dummy compilation context so that we can use ::error to report errors while + // processing command-line options. + class DummyCompileContext : public BaseCompileContext { + } dummyContext; + AutoCompileContext autoDummyContext(&dummyContext); + + // Delegate to the hook. + auto *remainingArgs = P4Tools::AbstractP4cToolOptions::process(argc, argv); + if ((remainingArgs == nullptr) || ::errorCount() > 0) { + return; + } +} + +SmithOptions::SmithOptions() : AbstractP4cToolOptions(P4Smith::TOOL_NAME, "P4Smith options.") {} + +} // namespace P4Tools diff --git a/backends/p4tools/modules/smith/options.h b/backends/p4tools/modules/smith/options.h new file mode 100644 index 0000000000..17a1b60e16 --- /dev/null +++ b/backends/p4tools/modules/smith/options.h @@ -0,0 +1,25 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_OPTIONS_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_OPTIONS_H_ +#include + +#include "backends/p4tools/common/options.h" + +namespace P4Tools { + +class SmithOptions : public AbstractP4cToolOptions { + public: + ~SmithOptions() override = default; + static SmithOptions &get(); + + const char *getIncludePath() override; + void processArgs(const std::vector &args); + + private: + SmithOptions(); +}; + +// using P4toZ3Context = P4CContextWithOptions; + +} // namespace P4Tools + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_OPTIONS_H_ */ diff --git a/backends/p4tools/modules/smith/register.h.in b/backends/p4tools/modules/smith/register.h.in new file mode 100644 index 0000000000..8ed1d5400f --- /dev/null +++ b/backends/p4tools/modules/smith/register.h.in @@ -0,0 +1,13 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_REGISTER_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_REGISTER_H_ + +@include_statements_var@ + +namespace P4Tools::P4Smith { + +inline void registerSmithTargets() { +@smith_targets_var@} + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_REGISTER_H_ */ diff --git a/backends/p4tools/modules/smith/scripts/compilation-test.sh b/backends/p4tools/modules/smith/scripts/compilation-test.sh new file mode 100755 index 0000000000..0f8718f70b --- /dev/null +++ b/backends/p4tools/modules/smith/scripts/compilation-test.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +set -e # Exit on error. + +if [ -z "$1" ]; then + echo "- Missing mandatory argument: NUM_ITERATIONS" + echo " - Usage: source compilation-test.sh " + return 1 +fi + +if [ -z "$2" ]; then + echo "- Missing mandatory argument: SMITH_BIN" + echo " - Usage: source compilation-test.sh " + return 1 +fi + +if [ -z "$3" ]; then + echo "- Missing mandatory argument: COMPILER_BIN" + echo " - Usage: source compilation-test.sh " + return 1 +fi + +if [ -z "$4" ]; then + echo "- Missing mandatory argument: TEST_DIR" + echo " - Usage: source compilation-test.sh " + return 1 +fi + +if [ -z "$5" ]; then + echo "- Missing mandatory argument: ARCH" + echo " - Usage: source compilation-test.sh " + return 1 +fi + +if [ -z "$6" ]; then + echo "- Missing mandatory argument: TARGET" + echo " - Usage: source compilation-test.sh " + return 1 +fi + +NUM_ITERATIONS=$1 +SMITH_BIN=$2 +COMPILER_BIN=$3 +TEST_DIR=$4 +ARCH=$5 +TARGET=$6 + +for i in $(seq 1 $NUM_ITERATIONS); do + echo "Generating program $i" + $SMITH_BIN --target $ARCH --arch $TARGET --seed $i $TEST_DIR/out.p4 + # TODO: Do not compile until we have stabilized. + # $COMPILER_BIN $TEST_DIR/out.p4 +done diff --git a/backends/p4tools/modules/smith/smith.cpp b/backends/p4tools/modules/smith/smith.cpp new file mode 100644 index 0000000000..87e6ab53d7 --- /dev/null +++ b/backends/p4tools/modules/smith/smith.cpp @@ -0,0 +1,93 @@ +#include "backends/p4tools/modules/smith/smith.h" + +#include +#include +#include +#include + +#include "backends/p4tools/common/compiler/compiler_result.h" +#include "backends/p4tools/common/lib/logging.h" +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "backends/p4tools/modules/smith/options.h" +#include "backends/p4tools/modules/smith/register.h" +#include "frontends/common/parser_options.h" +#include "frontends/p4/toP4/toP4.h" +#include "ir/ir.h" +#include "lib/compile_context.h" +#include "lib/cstring.h" +#include "lib/error.h" +#include "lib/nullstream.h" + +namespace P4Tools::P4Smith { + +void Smith::registerTarget() { registerSmithTargets(); } + +int Smith::main(const std::vector &args) { + // Register supported compiler targets. + registerTarget(); + + // Process command-line options. + auto &toolOptions = SmithOptions::get(); + auto compileContext = toolOptions.process(args); + if (!compileContext) { + return EXIT_FAILURE; + } + + // If not explicitly disabled, print basic information to standard output. + if (!toolOptions.disableInformationLogging) { + enableInformationLogging(); + } + + // Set up the compilation context. + AutoCompileContext autoContext(*compileContext); + // Instantiate a dummy program for now. In the future this can be a skeleton. + const IR::P4Program program; + return mainImpl(CompilerResult(program)); +} + +int Smith::mainImpl(const CompilerResult & /*result*/) { + registerSmithTargets(); + + auto outputFile = P4CContext::get().options().file; + + auto &smithOptions = P4Tools::SmithOptions::get(); + + // Use a default name if no specific output name is provided. + if (outputFile == nullptr) { + outputFile = cstring("out.p4"); + } + auto *ostream = openFile(outputFile, false); + if (ostream == nullptr) { + ::error("must have [file]"); + exit(EXIT_FAILURE); + } + if (smithOptions.seed.has_value()) { + printInfo("Using provided seed"); + } else { + printInfo("Generating seed..."); + // No seed provided, we generate our own. + std::random_device r; + smithOptions.seed = r(); + Utils::setRandomSeed(*smithOptions.seed); + } + // TODO(fruffy): Remove this. We are setting the seed in two frameworks. + printInfo("============ Program seed %1% =============\n", *smithOptions.seed); + const auto &smithTarget = SmithTarget::get(); + + auto result = smithTarget.writeTargetPreamble(ostream); + if (result != EXIT_SUCCESS) { + return result; + } + const auto *generatedProgram = smithTarget.generateP4Program(); + // Use ToP4 to write the P4 program to the specified stream. + P4::ToP4 top4(ostream, false); + generatedProgram->apply(top4); + ostream->flush(); + P4Scope::endLocalScope(); + + return EXIT_SUCCESS; +} + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/smith.h b/backends/p4tools/modules/smith/smith.h new file mode 100644 index 0000000000..1753049cfd --- /dev/null +++ b/backends/p4tools/modules/smith/smith.h @@ -0,0 +1,25 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_SMITH_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_SMITH_H_ + +#include + +#include "backends/p4tools/common/compiler/compiler_result.h" +#include "backends/p4tools/common/p4ctool.h" +#include "backends/p4tools/modules/smith/options.h" + +namespace P4Tools::P4Smith { + +class Smith : public AbstractP4cTool { + protected: + void registerTarget() override; + + int mainImpl(const CompilerResult &compilerResult) override; + + public: + virtual ~Smith() = default; + int main(const std::vector &args); +}; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_SMITH_H_ */ diff --git a/backends/p4tools/modules/smith/targets/bmv2/CMakeLists.txt b/backends/p4tools/modules/smith/targets/bmv2/CMakeLists.txt new file mode 100644 index 0000000000..024c9eef81 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/CMakeLists.txt @@ -0,0 +1,16 @@ +if(ENABLE_TESTING) + # Include the test subdirectory. + message("-- Adding p4smith bmv2 test suite") + include(test/P4Tests.cmake) +endif() + +# Source files for smith. +set( + SMITH_SOURCES + ${SMITH_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/psa.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/target.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/v1model.cpp + PARENT_SCOPE +) + diff --git a/backends/p4tools/modules/smith/targets/bmv2/psa.cpp b/backends/p4tools/modules/smith/targets/bmv2/psa.cpp new file mode 100644 index 0000000000..69adcbbc26 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/psa.cpp @@ -0,0 +1,442 @@ +#include "backends/p4tools/modules/smith/targets/bmv2/psa.h" + +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/targets/bmv2/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" +#include "ir/node.h" +#include "ir/vector.h" + +namespace P4Tools::P4Smith::BMv2 { + +using namespace P4::literals; + +/* ============================================================================================= + * Bmv2PsaSmithTarget implementation + * ============================================================================================= */ + +Bmv2PsaSmithTarget::Bmv2PsaSmithTarget() : AbstractBMv2SmithTarget("bmv2", "psa") {} + +void Bmv2PsaSmithTarget::make() { + static Bmv2PsaSmithTarget *INSTANCE = nullptr; + if (INSTANCE == nullptr) { + INSTANCE = new Bmv2PsaSmithTarget(); + } +} + +IR::P4Parser *Bmv2PsaSmithTarget::generateIngressParserBlock() const { + IR::IndexedVector parserLocals; + P4Scope::startLocalScope(); + + // generate type_parser !that this is labeled "p" + IR::IndexedVector params; + + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_in"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "hdr"_cs, SYS_HDR_NAME)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "user_meta"_cs, "metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "psa_ingress_parser_input_metadata_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "resubmit_meta"_cs, "empty_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "recirculate_meta"_cs, + "empty_t"_cs)); + auto *parList = new IR::ParameterList(params); + + auto *tpParser = new IR::Type_Parser("IngressParserImpl", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + // // generate decls + // for (int i = 0; i < 5; i++) { + // auto var_decl = variableDeclaration::gen(); + // parserLocals.push_back(var_decl); + // } + + // generate states + IR::IndexedVector states; + auto *startState = parserGenerator().genStartState(); + states.push_back(startState); + states.push_back(parserGenerator().genHdrStates()); + + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4parser = new IR::P4Parser("IngressParserImpl", tpParser, parserLocals, states); + P4Scope::addToScope(p4parser); + return p4parser; +} + +IR::P4Control *Bmv2PsaSmithTarget::generateIngressBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "user_meta"_cs, "metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "psa_ingress_input_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "ostd"_cs, + "psa_ingress_output_metadata_t"_cs)); + + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("ingress", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + IR::IndexedVector localDecls = declarationGenerator().genLocalControlDecls(); + // apply body + auto *applyBlock = statementGenerator().genBlockStatement(false); + // hardcode the output port to be zero + auto *outputPort = new IR::PathExpression("ostd.egress_port"); + // PSA requires explicit casts of the output port variable + // actually !sure why this is required... + auto *outPortCast = new IR::Cast(new IR::Type_Name("PortId_t"), new IR::Constant(0)); + auto *assign = new IR::AssignmentStatement(outputPort, outPortCast); + // some hack to insert the expression at the beginning + auto it = applyBlock->components.begin(); + applyBlock->components.insert(it, assign); + // also make sure the packet isn't dropped... + outputPort = new IR::PathExpression("ostd.drop"); + // PSA requires explicit casts of the output port variable + // actually !sure why this is required... + assign = new IR::AssignmentStatement(outputPort, new IR::BoolLiteral(false)); + // some hack to insert the expression at the beginning + it = applyBlock->components.begin(); + applyBlock->components.insert(it, assign); + // end of scope + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4ctrl = new IR::P4Control("ingress", typeCtrl, localDecls, applyBlock); + P4Scope::addToScope(p4ctrl); + return p4ctrl; +} + +IR::MethodCallStatement *genDeparserEmitCall() { + auto *call = new IR::PathExpression("pkt.emit"); + auto *args = new IR::Vector(); + + args->push_back(new IR::Argument(new IR::PathExpression("h"))); + + auto *mce = new IR::MethodCallExpression(call, args); + auto *mst = new IR::MethodCallStatement(mce); + return mst; +} + +IR::P4Control *Bmv2PsaSmithTarget::generateIngressDeparserBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_out"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "clone_i2e_meta"_cs, "empty_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "resubmit_meta"_cs, "empty_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "normal_meta"_cs, "empty_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "user_meta"_cs, "metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "psa_ingress_output_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("IngressDeparserImpl", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + blkStat->push_back(genDeparserEmitCall()); + + return new IR::P4Control("IngressDeparserImpl", typeCtrl, localDecls, blkStat); +} + +IR::P4Parser *Bmv2PsaSmithTarget::generateEgressParserBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_in"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "hdr"_cs, SYS_HDR_NAME)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "user_meta"_cs, "metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "psa_egress_parser_input_metadata_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "normal_meta"_cs, "empty_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "clone_i2e_meta"_cs, "empty_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "clone_e2e_meta"_cs, "empty_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeParser = new IR::Type_Parser("EgressParserImpl", parList); + IR::IndexedVector localDecls; + // TODO(fruffy): this hacky. FIX + // generate states + IR::IndexedVector states; + IR::IndexedVector components; + IR::Expression *transition = new IR::PathExpression("accept"); + auto *startState = new IR::ParserState("start", components, transition); + states.push_back(startState); + return new IR::P4Parser("EgressParserImpl", typeParser, localDecls, states); +} + +IR::P4Control *Bmv2PsaSmithTarget::generateEgressBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "user_meta"_cs, "metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "psa_egress_input_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "ostd"_cs, + "psa_egress_output_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("egress", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + + return new IR::P4Control("egress", typeCtrl, localDecls, blkStat); +} + +IR::P4Control *Bmv2PsaSmithTarget::generateEgressDeparserBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_out"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "clone_e2e_meta"_cs, "empty_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::Out, "recirculate_meta"_cs, + "empty_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "user_meta"_cs, "metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "psa_egress_output_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter( + IR::Direction::In, "edstd"_cs, "psa_egress_deparser_input_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("EgressDeparserImpl", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + blkStat->push_back(genDeparserEmitCall()); + + return new IR::P4Control("EgressDeparserImpl", typeCtrl, localDecls, blkStat); +} + +namespace { + +IR::Declaration_Instance *generateIngressPipeDeclaration() { + auto *args = new IR::Vector(); + + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("IngressParserImpl")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("ingress")))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("IngressDeparserImpl")))); + auto *packageName = new IR::Type_Name("IngressPipeline"); + return new IR::Declaration_Instance("ip", packageName, args); +} + +IR::Declaration_Instance *generateEgressPipeDeclaration() { + auto *args = new IR::Vector(); + + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("EgressParserImpl")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("egress")))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("EgressDeparserImpl")))); + auto *packageName = new IR::Type_Name("EgressPipeline"); + return new IR::Declaration_Instance("ep", packageName, args); +} + +IR::Declaration_Instance *generateMainPsaPackage() { + auto *args = new IR::Vector(); + args->push_back(new IR::Argument(new IR::TypeNameExpression("ip"))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("PacketReplicationEngine")))); + args->push_back(new IR::Argument(new IR::TypeNameExpression("ep"))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("BufferingQueueingEngine")))); + auto *packageName = new IR::Type_Name("PSA_Switch"); + return new IR::Declaration_Instance("main", packageName, args); +} + +IR::Type_Struct *generateUserMetadataType() { + // Do !emit meta fields for now, no need + IR::IndexedVector fields; + auto *ret = new IR::Type_Struct("metadata_t", fields); + P4Scope::addToScope(ret); + return ret; +} + +IR::Type_Struct *generateEmptyMetadataType() { + // Do !emit meta fields for now, no need + IR::IndexedVector fields; + auto *ret = new IR::Type_Struct("empty_t", fields); + P4Scope::addToScope(ret); + return ret; +} + +void generatePsaMetadata() { + IR::ID *name = nullptr; + IR::Type_Struct *ret = nullptr; + IR::IndexedVector fields; + + name = new IR::ID("psa_ingress_parser_input_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); + name = new IR::ID("psa_ingress_input_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); + name = new IR::ID("psa_ingress_output_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); + name = new IR::ID("psa_egress_input_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); + name = new IR::ID("psa_egress_output_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); +} + +void setBmv2PsaProbabilities() { + PCT.PARAMETER_NONEDIR_DERIVED_STRUCT = 0; + PCT.PARAMETER_NONEDIR_DERIVED_HEADER = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_BOOL = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_ERROR = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_STRING = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_VARBIT = 0; +} + +} // namespace + +int Bmv2PsaSmithTarget::writeTargetPreamble(std::ostream *ostream) const { + *ostream << "#include \n"; + *ostream << "#include \n\n"; + *ostream << "bit<3> max(in bit<3> val, in bit<3> bound) {\n"; + *ostream << " return val < bound ? val : bound;\n"; + *ostream << "}\n"; + return EXIT_SUCCESS; +} + +const IR::P4Program *Bmv2PsaSmithTarget::generateP4Program() const { + P4Scope::startLocalScope(); + + // insert banned structures + P4Scope::notInitializedStructs.insert("psa_ingress_parser_input_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("psa_ingress_input_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("psa_ingress_output_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("psa_egress_input_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("psa_egress_output_metadata_t"_cs); + // set psa-specific probabilities + setBmv2PsaProbabilities(); + // insert some dummy metadata + generatePsaMetadata(); + + // start to assemble the model + auto *objects = new IR::Vector(); + + objects->push_back(declarationGenerator().genEthernetHeaderType()); + + // generate some declarations + int typeDecls = Utils::getRandInt(DECL.MIN_TYPE, DECL.MAX_TYPE); + for (int i = 0; i < typeDecls; ++i) { + objects->push_back(declarationGenerator().genTypeDeclaration()); + } + + // generate struct Headers + objects->push_back(declarationGenerator().genHeaderStruct()); + // generate struct metadata_t + objects->push_back(generateUserMetadataType()); + // generate struct empty_t + objects->push_back(generateEmptyMetadataType()); + + // generate some callables + int callableDecls = Utils::getRandInt(DECL.MIN_CALLABLES, DECL.MAX_CALLABLES); + for (int i = 0; i < callableDecls; ++i) { + std::vector percent = {80, 15, 0, 5}; + switch (Utils::getRandInt(percent)) { + case 0: { + objects->push_back(declarationGenerator().genFunctionDeclaration()); + break; + } + case 1: { + objects->push_back(declarationGenerator().genActionDeclaration()); + break; + } + case 2: { + objects->push_back(declarationGenerator().genExternDeclaration()); + break; + } + case 3: { + objects->push_back(declarationGenerator().genControlDeclaration()); + break; + } + } + } + + // generate all the necessary pipelines for the package + objects->push_back(generateIngressParserBlock()); + objects->push_back(generateIngressBlock()); + objects->push_back(generateIngressDeparserBlock()); + objects->push_back(generateEgressParserBlock()); + objects->push_back(generateEgressBlock()); + objects->push_back(generateEgressDeparserBlock()); + + // finally assemble the package + objects->push_back(generateIngressPipeDeclaration()); + objects->push_back(generateEgressPipeDeclaration()); + objects->push_back(generateMainPsaPackage()); + + return new IR::P4Program(*objects); +} + +} // namespace P4Tools::P4Smith::BMv2 diff --git a/backends/p4tools/modules/smith/targets/bmv2/psa.h b/backends/p4tools/modules/smith/targets/bmv2/psa.h new file mode 100644 index 0000000000..a35d950abf --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/psa.h @@ -0,0 +1,61 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_PSA_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_PSA_H_ + +#include + +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/common/table.h" +#include "backends/p4tools/modules/smith/targets/bmv2/target.h" +#include "ir/ir.h" + +namespace P4Tools::P4Smith::BMv2 { + +class Bmv2PsaSmithTarget : public AbstractBMv2SmithTarget { + private: + DeclarationGenerator *_declarationGenerator = new DeclarationGenerator(*this); + ExpressionGenerator *_expressionGenerator = new ExpressionGenerator(*this); + StatementGenerator *_statementGenerator = new StatementGenerator(*this); + ParserGenerator *_parserGenerator = new ParserGenerator(*this); + TableGenerator *_tableGenerator = new TableGenerator(*this); + + [[nodiscard]] IR::P4Parser *generateIngressParserBlock() const; + [[nodiscard]] IR::P4Control *generateIngressBlock() const; + [[nodiscard]] IR::P4Control *generateIngressDeparserBlock() const; + [[nodiscard]] IR::P4Parser *generateEgressParserBlock() const; + [[nodiscard]] IR::P4Control *generateEgressBlock() const; + [[nodiscard]] IR::P4Control *generateEgressDeparserBlock() const; + + public: + /// Registers this target. + static void make(); + + [[nodiscard]] int writeTargetPreamble(std::ostream *ostream) const override; + + [[nodiscard]] const IR::P4Program *generateP4Program() const override; + + [[nodiscard]] DeclarationGenerator &declarationGenerator() const override { + return *_declarationGenerator; + } + + [[nodiscard]] ExpressionGenerator &expressionGenerator() const override { + return *_expressionGenerator; + } + + [[nodiscard]] StatementGenerator &statementGenerator() const override { + return *_statementGenerator; + } + + [[nodiscard]] ParserGenerator &parserGenerator() const override { return *_parserGenerator; } + + [[nodiscard]] TableGenerator &tableGenerator() const override { return *_tableGenerator; } + + private: + Bmv2PsaSmithTarget(); +}; + +} // namespace P4Tools::P4Smith::BMv2 + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_PSA_H_ */ diff --git a/backends/p4tools/modules/smith/targets/bmv2/register.h b/backends/p4tools/modules/smith/targets/bmv2/register.h new file mode 100644 index 0000000000..a39a1e3a82 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/register.h @@ -0,0 +1,16 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_REGISTER_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_REGISTER_H_ + +#include "backends/p4tools/modules/smith/targets/bmv2/psa.h" +#include "backends/p4tools/modules/smith/targets/bmv2/v1model.h" + +namespace P4Tools::P4Smith { + +inline void bmv2RegisterSmithTarget() { + BMv2::Bmv2V1modelSmithTarget::make(); + BMv2::Bmv2PsaSmithTarget::make(); +} + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_REGISTER_H_ */ diff --git a/backends/p4tools/modules/smith/targets/bmv2/target.cpp b/backends/p4tools/modules/smith/targets/bmv2/target.cpp new file mode 100644 index 0000000000..fb5e299651 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/target.cpp @@ -0,0 +1,18 @@ +#include "backends/p4tools/modules/smith/targets/bmv2/target.h" + +#include +#include + +#include "backends/p4tools/modules/smith/core/target.h" + +namespace P4Tools::P4Smith::BMv2 { + +/* ============================================================================================= + * AbstractBMv2SmithTarget implementation + * ============================================================================================= */ + +AbstractBMv2SmithTarget::AbstractBMv2SmithTarget(const std::string &deviceName, + const std::string &archName) + : SmithTarget(deviceName, archName) {} + +} // namespace P4Tools::P4Smith::BMv2 diff --git a/backends/p4tools/modules/smith/targets/bmv2/target.h b/backends/p4tools/modules/smith/targets/bmv2/target.h new file mode 100644 index 0000000000..d99673ab1a --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/target.h @@ -0,0 +1,16 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_TARGET_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_TARGET_H_ + +#include + +#include "backends/p4tools/modules/smith/core/target.h" + +namespace P4Tools::P4Smith::BMv2 { + +class AbstractBMv2SmithTarget : public SmithTarget { + protected: + explicit AbstractBMv2SmithTarget(const std::string &deviceName, const std::string &archName); +}; +} // namespace P4Tools::P4Smith::BMv2 + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_TARGET_H_ */ diff --git a/backends/p4tools/modules/smith/targets/bmv2/test/P4Tests.cmake b/backends/p4tools/modules/smith/targets/bmv2/test/P4Tests.cmake new file mode 100644 index 0000000000..a9b7ca4098 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/test/P4Tests.cmake @@ -0,0 +1,13 @@ +# This file defines how to execute Smith on P4 programs. +# General test utilities. +include(${P4TOOLS_SOURCE_DIR}/cmake/TestUtils.cmake) + +set(SMITH_BMV2_CMD ${smith_SOURCE_DIR}/scripts/compilation-test.sh) + +set(SMITH_BMV2_V1MODEL_ARGS 100 ${P4SMITH_DRIVER} ${CMAKE_BINARY_DIR}/p4c-bm2-ss ${CMAKE_BINARY_DIR} bmv2 v1model) + +add_test (NAME smith-compile-bmv2-v1model COMMAND ${SMITH_BMV2_CMD} ${SMITH_BMV2_V1MODEL_ARGS} WORKING_DIRECTORY ${P4C_BINARY_DIR}) + +set(SMITH_BMV2_PSA_ARGS 100 ${P4SMITH_DRIVER} ${CMAKE_BINARY_DIR}/p4c-bm2-psa ${CMAKE_BINARY_DIR} bmv2 psa) + +add_test (NAME smith-compile-bmv2-psa COMMAND ${SMITH_BMV2_CMD} ${SMITH_BMV2_PSA_ARGS} WORKING_DIRECTORY ${P4C_BINARY_DIR}) diff --git a/backends/p4tools/modules/smith/targets/bmv2/v1model.cpp b/backends/p4tools/modules/smith/targets/bmv2/v1model.cpp new file mode 100644 index 0000000000..5ecfbfa2b1 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/v1model.cpp @@ -0,0 +1,385 @@ +#include "backends/p4tools/modules/smith/targets/bmv2/v1model.h" + +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/targets/bmv2/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" +#include "ir/node.h" +#include "ir/vector.h" + +namespace P4Tools::P4Smith::BMv2 { + +using namespace P4::literals; + +/* ============================================================================================= + * Bmv2V1modelSmithTarget implementation + * ============================================================================================= */ + +Bmv2V1modelSmithTarget::Bmv2V1modelSmithTarget() : AbstractBMv2SmithTarget("bmv2", "v1model") {} + +void Bmv2V1modelSmithTarget::make() { + static Bmv2V1modelSmithTarget *INSTANCE = nullptr; + if (INSTANCE == nullptr) { + INSTANCE = new Bmv2V1modelSmithTarget(); + } +} + +IR::P4Parser *Bmv2V1modelSmithTarget::generateParserBlock() const { + IR::IndexedVector parserLocals; + + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_in"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "hdr"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "m"_cs, "Meta"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "sm"_cs, + "standard_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeParser = new IR::Type_Parser("p", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + // generate decls + /* for (int i = 0; i < 5; i++) { + auto var_decl = variableDeclaration::gen(); + parserLocals.push_back(var_decl); + }*/ + + // generate states + IR::IndexedVector states; + states.push_back(parserGenerator().genStartState()); + states.push_back(parserGenerator().genHdrStates()); + + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4parser = new IR::P4Parser("p", typeParser, parserLocals, states); + P4Scope::addToScope(p4parser); + return p4parser; +} + +IR::P4Control *Bmv2V1modelSmithTarget::generateIngressBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "m"_cs, "Meta"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "sm"_cs, + "standard_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("ingress", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + IR::IndexedVector localDecls = declarationGenerator().genLocalControlDecls(); + // apply body + auto *applyBlock = statementGenerator().genBlockStatement(false); + + // end of scope + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4ctrl = new IR::P4Control("ingress", typeCtrl, localDecls, applyBlock); + P4Scope::addToScope(p4ctrl); + return p4ctrl; +} + +IR::P4Control *Bmv2V1modelSmithTarget::generateVerifyBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "m"_cs, "Meta"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("vrfy", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + + return new IR::P4Control("vrfy", typeCtrl, localDecls, blkStat); +} + +IR::P4Control *Bmv2V1modelSmithTarget::generateUpdateBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "m"_cs, "Meta"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("update", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + + return new IR::P4Control("update", typeCtrl, localDecls, blkStat); +} + +IR::P4Control *Bmv2V1modelSmithTarget::generateEgressBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "m"_cs, "Meta"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "sm"_cs, + "standard_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("egress", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + + return new IR::P4Control("egress", typeCtrl, localDecls, blkStat); +} + +IR::MethodCallStatement *generateDeparserEmitCall() { + auto *call = new IR::PathExpression("pkt.emit"); + auto *args = new IR::Vector(); + + args->push_back(new IR::Argument(new IR::PathExpression("h"))); + + auto *mce = new IR::MethodCallExpression(call, args); + auto *mst = new IR::MethodCallStatement(mce); + return mst; +} + +IR::P4Control *Bmv2V1modelSmithTarget::generateDeparserBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_out"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "h"_cs, SYS_HDR_NAME)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("deparser"_cs, parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + blkStat->push_back(generateDeparserEmitCall()); + + return new IR::P4Control("deparser"_cs, typeCtrl, localDecls, blkStat); +} + +IR::Declaration_Instance *generateMainV1ModelPackage() { + auto *args = new IR::Vector(); + + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("p")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("vrfy")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("ingress")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("egress")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("update")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("deparser")))); + auto *packageName = new IR::Type_Name("V1Switch"); + return new IR::Declaration_Instance("main", packageName, args); +} + +IR::Type_Struct *generateMetadataStructure() { + // Do !emit meta fields for now, no need + // FIXME: Design a way to emit these that plays nicely with all targets + // auto sfl = new structFieldList(STRUCT, name->name); + // IR::IndexedVector< IR::StructField > fields = sfl->gen(Utils::getRandInt(1, + // 5)); + IR::IndexedVector fields; + + auto *ret = new IR::Type_Struct("Meta", fields); + + P4Scope::addToScope(ret); + + return ret; +} + +IR::IndexedVector generateStandardMetadataVector() { + IR::IndexedVector fields; + + // IR::ID *name; + // IR::Type *tp; + + /* + name = new IR::ID("ingress_port"); + tp = IR::Type_Bits::get(9, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("egress_spec"); + tp = IR::Type_Bits::get(9, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("egress_port"); + tp = IR::Type_Bits::get(9, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("instance_type"); + tp = IR::Type_Bits::get(32, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("packet_length"); + tp = IR::Type_Bits::get(32, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("enq_timestamp"); + tp = IR::Type_Bits::get(32, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("enq_qdepth"); + tp = IR::Type_Bits::get(19, false); + fields.push_back(new IR::StructField(*name, tp)); + // name = new IR::ID("dep_timedelta"); + // tp = IR::Type_Bits::get(32, false); + // fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("deq_qdepth"); + tp = IR::Type_Bits::get(19, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("ingress_global_timestamp"); + tp = IR::Type_Bits::get(48, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("egress_global_timestamp"); + tp = IR::Type_Bits::get(48, false); + fields.push_back(new IR::StructField(*name, tp)); + name = new IR::ID("egress_rid"); + tp = IR::Type_Bits::get(16, false); + fields.push_back(new IR::StructField(*name, tp)); + // Tao: error is omitted here + name = new IR::ID("priority"); + tp = IR::Type_Bits::get(3, false); + fields.push_back(new IR::StructField(*name, tp)); + */ + + return fields; +} + +IR::Type_Struct *generateStandardMetadataStructure() { + auto fields = generateStandardMetadataVector(); + + auto *ret = new IR::Type_Struct("standard_metadata_t", fields); + + P4Scope::addToScope(ret); + + return ret; +} + +void setProbabilitiesforBmv2V1model() { + PCT.PARAMETER_NONEDIR_DERIVED_STRUCT = 0; + PCT.PARAMETER_NONEDIR_DERIVED_HEADER = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_BOOL = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_ERROR = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_STRING = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_VARBIT = 0; + // V1Model does !support headers that are !multiples of 8 + PCT.STRUCTTYPEDECLARATION_BASETYPE_BOOL = 0; + // V1Model requires headers to be byte-aligned + P4Scope::req.byte_align_headers = true; +} + +int Bmv2V1modelSmithTarget::writeTargetPreamble(std::ostream *ostream) const { + *ostream << "#include \n"; + *ostream << "#include \n\n"; + *ostream << "bit<3> max(in bit<3> val, in bit<3> bound) {\n"; + *ostream << " return val < bound ? val : bound;\n"; + *ostream << "}\n"; + return EXIT_SUCCESS; +} + +const IR::P4Program *Bmv2V1modelSmithTarget::generateP4Program() const { + P4Scope::startLocalScope(); + + // insert banned structures + P4Scope::notInitializedStructs.insert("standard_metadata_t"_cs); + // Set bmv2-v1model-specific probabilities. + setProbabilitiesforBmv2V1model(); + + // start to assemble the model + auto *objects = new IR::Vector(); + + objects->push_back(declarationGenerator().genEthernetHeaderType()); + + // generate some declarations + int typeDecls = Utils::getRandInt(DECL.MIN_TYPE, DECL.MAX_TYPE); + for (int i = 0; i < typeDecls; ++i) { + objects->push_back(declarationGenerator().genTypeDeclaration()); + } + + // generate struct Headers + objects->push_back(declarationGenerator().genHeaderStruct()); + + // generate struct Meta + objects->push_back(generateMetadataStructure()); + // insert standard_metadata_t + generateStandardMetadataStructure(); + + // generate some callables + int callableDecls = Utils::getRandInt(DECL.MIN_CALLABLES, DECL.MAX_CALLABLES); + for (int i = 0; i < callableDecls; ++i) { + std::vector percent = {80, 15, 0, 5}; + switch (Utils::getRandInt(percent)) { + case 0: { + objects->push_back(declarationGenerator().genFunctionDeclaration()); + break; + } + case 1: { + objects->push_back(declarationGenerator().genActionDeclaration()); + break; + } + case 2: { + objects->push_back(declarationGenerator().genExternDeclaration()); + break; + } + case 3: { + objects->push_back(declarationGenerator().genControlDeclaration()); + break; + } + } + } + + // generate all the necessary pipelines for the package + objects->push_back(generateParserBlock()); + objects->push_back(generateIngressBlock()); + objects->push_back(generateVerifyBlock()); + objects->push_back(generateUpdateBlock()); + objects->push_back(generateEgressBlock()); + objects->push_back(generateDeparserBlock()); + + // finally assemble the package + objects->push_back(generateMainV1ModelPackage()); + + return new IR::P4Program(*objects); +} + +} // namespace P4Tools::P4Smith::BMv2 diff --git a/backends/p4tools/modules/smith/targets/bmv2/v1model.h b/backends/p4tools/modules/smith/targets/bmv2/v1model.h new file mode 100644 index 0000000000..4db53fd4c2 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/bmv2/v1model.h @@ -0,0 +1,61 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_V1MODEL_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_V1MODEL_H_ + +#include + +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/common/table.h" +#include "backends/p4tools/modules/smith/targets/bmv2/target.h" +#include "ir/ir.h" + +namespace P4Tools::P4Smith::BMv2 { + +class Bmv2V1modelSmithTarget : public AbstractBMv2SmithTarget { + private: + DeclarationGenerator *_declarationGenerator = new DeclarationGenerator(*this); + ExpressionGenerator *_expressionGenerator = new ExpressionGenerator(*this); + StatementGenerator *_statementGenerator = new StatementGenerator(*this); + ParserGenerator *_parserGenerator = new ParserGenerator(*this); + TableGenerator *_tableGenerator = new TableGenerator(*this); + + [[nodiscard]] IR::P4Parser *generateParserBlock() const; + [[nodiscard]] IR::P4Control *generateIngressBlock() const; + [[nodiscard]] IR::P4Control *generateUpdateBlock() const; + [[nodiscard]] IR::P4Control *generateVerifyBlock() const; + [[nodiscard]] IR::P4Control *generateEgressBlock() const; + [[nodiscard]] IR::P4Control *generateDeparserBlock() const; + + public: + /// Registers this target. + static void make(); + + [[nodiscard]] int writeTargetPreamble(std::ostream *ostream) const override; + + [[nodiscard]] const IR::P4Program *generateP4Program() const override; + + [[nodiscard]] DeclarationGenerator &declarationGenerator() const override { + return *_declarationGenerator; + } + + [[nodiscard]] ExpressionGenerator &expressionGenerator() const override { + return *_expressionGenerator; + } + + [[nodiscard]] StatementGenerator &statementGenerator() const override { + return *_statementGenerator; + } + + [[nodiscard]] ParserGenerator &parserGenerator() const override { return *_parserGenerator; } + + [[nodiscard]] TableGenerator &tableGenerator() const override { return *_tableGenerator; } + + private: + Bmv2V1modelSmithTarget(); +}; + +} // namespace P4Tools::P4Smith::BMv2 + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_BMV2_V1MODEL_H_ */ diff --git a/backends/p4tools/modules/smith/targets/generic/CMakeLists.txt b/backends/p4tools/modules/smith/targets/generic/CMakeLists.txt new file mode 100644 index 0000000000..61e5469efb --- /dev/null +++ b/backends/p4tools/modules/smith/targets/generic/CMakeLists.txt @@ -0,0 +1,14 @@ +if(ENABLE_TESTING) + # Include the test subdirectory. + message("-- Adding p4smith generic test suite") + include(test/P4Tests.cmake) +endif() + +# Source files for smith. +set( + SMITH_SOURCES + ${SMITH_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/target.cpp + PARENT_SCOPE +) + diff --git a/backends/p4tools/modules/smith/targets/generic/register.h b/backends/p4tools/modules/smith/targets/generic/register.h new file mode 100644 index 0000000000..71f562c9ee --- /dev/null +++ b/backends/p4tools/modules/smith/targets/generic/register.h @@ -0,0 +1,12 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_GENERIC_REGISTER_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_GENERIC_REGISTER_H_ + +#include "backends/p4tools/modules/smith/targets/generic/target.h" + +namespace P4Tools::P4Smith { + +inline void genericRegisterSmithTarget() { Generic::GenericCoreSmithTarget::make(); } + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_GENERIC_REGISTER_H_ */ diff --git a/backends/p4tools/modules/smith/targets/generic/target.cpp b/backends/p4tools/modules/smith/targets/generic/target.cpp new file mode 100644 index 0000000000..5a9303d5c5 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/generic/target.cpp @@ -0,0 +1,225 @@ +#include "backends/p4tools/modules/smith/targets/generic/target.h" + +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" +#include "ir/node.h" +#include "ir/vector.h" + +namespace P4Tools::P4Smith::Generic { + +using namespace P4::literals; + +/* ============================================================================================= + * AbstractGenericSmithTarget implementation + * ============================================================================================= */ + +AbstractGenericSmithTarget::AbstractGenericSmithTarget(const std::string &deviceName, + const std::string &archName) + : SmithTarget(deviceName, archName) {} + +/* ============================================================================================= + * GenericCoreSmithTarget implementation + * ============================================================================================= */ + +GenericCoreSmithTarget::GenericCoreSmithTarget() : AbstractGenericSmithTarget("generic", "core") {} + +void GenericCoreSmithTarget::make() { + static GenericCoreSmithTarget *INSTANCE = nullptr; + if (INSTANCE == nullptr) { + INSTANCE = new GenericCoreSmithTarget(); + } +} + +IR::P4Parser *GenericCoreSmithTarget::generateParserBlock() const { + IR::IndexedVector parserLocals; + + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_in"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "hdr"_cs, SYS_HDR_NAME)); + auto *parList = new IR::ParameterList(params); + auto *typeParser = new IR::Type_Parser("p", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + // generate decls + for (int i = 0; i < 5; i++) { + auto *varDecl = declarationGenerator().genVariableDeclaration(); + parserLocals.push_back(varDecl); + } + + // generate states + parserGenerator().buildParserTree(); + IR::IndexedVector states = parserGenerator().getStates(); + + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4parser = new IR::P4Parser("p", typeParser, parserLocals, states); + P4Scope::addToScope(p4parser); + return p4parser; +} + +IR::P4Control *GenericCoreSmithTarget::generateIngressBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("ingress", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + IR::IndexedVector localDecls = declarationGenerator().genLocalControlDecls(); + // apply body + auto *applyBlock = statementGenerator().genBlockStatement(false); + + // end of scope + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4ctrl = new IR::P4Control("ingress", typeCtrl, localDecls, applyBlock); + P4Scope::addToScope(p4ctrl); + return p4ctrl; +} + +IR::Declaration_Instance *GenericCoreSmithTarget::generateMainPackage() { + auto *args = new IR::Vector(); + + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("p")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("ingress")))); + auto *packageName = new IR::Type_Name("top"); + return new IR::Declaration_Instance("main", packageName, args); +} + +IR::Type_Parser *GenericCoreSmithTarget::generateParserBlockType() const { + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "b"_cs, "packet_in"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "hdr"_cs, SYS_HDR_NAME)); + auto *parList = new IR::ParameterList(params); + return new IR::Type_Parser("Parser", parList); +} + +IR::Type_Control *GenericCoreSmithTarget::generateIngressBlockType() const { + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "hdr"_cs, SYS_HDR_NAME)); + auto *parList = new IR::ParameterList(params); + return new IR::Type_Control("Ingress", parList); +} + +IR::Type_Package *GenericCoreSmithTarget::generatePackageType() const { + IR::IndexedVector params; + params.push_back(declarationGenerator().genParameter(IR::Direction::None, "p"_cs, "Parser"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "ig"_cs, "Ingress"_cs)); + auto *parList = new IR::ParameterList(params); + return new IR::Type_Package("top", parList); +} + +int GenericCoreSmithTarget::writeTargetPreamble(std::ostream *ostream) const { + *ostream << "#include \n"; + *ostream << "bit<3> max(in bit<3> val, in bit<3> bound) {\n"; + *ostream << " return val < bound ? val : bound;\n"; + *ostream << "}\n"; + return EXIT_SUCCESS; +} + +const IR::P4Program *GenericCoreSmithTarget::generateP4Program() const { + P4Scope::startLocalScope(); + + // start to assemble the model + auto *objects = new IR::Vector(); + + objects->push_back(declarationGenerator().genEthernetHeaderType()); + + // generate some declarations + int typeDecls = Utils::getRandInt(DECL.MIN_TYPE, DECL.MAX_TYPE); + for (int i = 0; i < typeDecls; ++i) { + objects->push_back(declarationGenerator().genTypeDeclaration()); + } + + // generate struct Headers + objects->push_back(declarationGenerator().genHeaderStruct()); + + // generate some callables + int callableDecls = Utils::getRandInt(DECL.MIN_CALLABLES, DECL.MAX_CALLABLES); + for (int i = 0; i < callableDecls; ++i) { + std::vector percent = {70, 15, 10, 5}; + switch (Utils::getRandInt(percent)) { + case 0: { + objects->push_back(declarationGenerator().genFunctionDeclaration()); + break; + } + case 1: { + objects->push_back(declarationGenerator().genActionDeclaration()); + break; + } + case 2: { + objects->push_back(declarationGenerator().genExternDeclaration()); + break; + } + case 3: { + objects->push_back(declarationGenerator().genControlDeclaration()); + break; + } + } + } + + // generate all the necessary pipelines for the package + objects->push_back(generateParserBlock()); + objects->push_back(generateIngressBlock()); + + // finally assemble the package + objects->push_back(generateParserBlockType()); + objects->push_back(generateIngressBlockType()); + objects->push_back(generatePackageType()); + objects->push_back(generateMainPackage()); + + return new IR::P4Program(*objects); +} + +} // namespace P4Tools::P4Smith::Generic diff --git a/backends/p4tools/modules/smith/targets/generic/target.h b/backends/p4tools/modules/smith/targets/generic/target.h new file mode 100644 index 0000000000..1a5bef9b69 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/generic/target.h @@ -0,0 +1,68 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_GENERIC_TARGET_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_GENERIC_TARGET_H_ + +#include +#include + +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/common/table.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "ir/ir.h" + +namespace P4Tools::P4Smith::Generic { + +class AbstractGenericSmithTarget : public SmithTarget { + protected: + explicit AbstractGenericSmithTarget(const std::string &deviceName, const std::string &archName); +}; + +class GenericCoreSmithTarget : public AbstractGenericSmithTarget { + private: + DeclarationGenerator *_declarationGenerator = new DeclarationGenerator(*this); + ExpressionGenerator *_expressionGenerator = new ExpressionGenerator(*this); + StatementGenerator *_statementGenerator = new StatementGenerator(*this); + ParserGenerator *_parserGenerator = new ParserGenerator(*this); + TableGenerator *_tableGenerator = new TableGenerator(*this); + + [[nodiscard]] IR::P4Parser *generateParserBlock() const; + [[nodiscard]] IR::P4Control *generateIngressBlock() const; + [[nodiscard]] static IR::Declaration_Instance *generateMainPackage(); + + [[nodiscard]] IR::Type_Parser *generateParserBlockType() const; + [[nodiscard]] IR::Type_Control *generateIngressBlockType() const; + [[nodiscard]] IR::Type_Package *generatePackageType() const; + + public: + /// Registers this target. + static void make(); + + [[nodiscard]] int writeTargetPreamble(std::ostream *ostream) const override; + + [[nodiscard]] const IR::P4Program *generateP4Program() const override; + + [[nodiscard]] DeclarationGenerator &declarationGenerator() const override { + return *_declarationGenerator; + } + + [[nodiscard]] ExpressionGenerator &expressionGenerator() const override { + return *_expressionGenerator; + } + + [[nodiscard]] StatementGenerator &statementGenerator() const override { + return *_statementGenerator; + } + + [[nodiscard]] ParserGenerator &parserGenerator() const override { return *_parserGenerator; } + + [[nodiscard]] TableGenerator &tableGenerator() const override { return *_tableGenerator; } + + private: + GenericCoreSmithTarget(); +}; + +} // namespace P4Tools::P4Smith::Generic + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_GENERIC_TARGET_H_ */ diff --git a/backends/p4tools/modules/smith/targets/generic/test/P4Tests.cmake b/backends/p4tools/modules/smith/targets/generic/test/P4Tests.cmake new file mode 100644 index 0000000000..cf3729ccd3 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/generic/test/P4Tests.cmake @@ -0,0 +1,10 @@ +# This file defines how to execute Smith on P4 programs. +# General test utilities. +include(${P4TOOLS_SOURCE_DIR}/cmake/TestUtils.cmake) + +set(SMITH_BMV2_CMD ${smith_SOURCE_DIR}/scripts/compilation-test.sh) + +set(SMITH_BMV2_ARGS 100 ${P4SMITH_DRIVER} ${CMAKE_BINARY_DIR}/p4test ${CMAKE_BINARY_DIR} generic core) + +add_test(NAME smith-compile-core COMMAND ${SMITH_BMV2_CMD} ${SMITH_BMV2_ARGS} WORKING_DIRECTORY ${P4C_BINARY_DIR}) + diff --git a/backends/p4tools/modules/smith/targets/nic/CMakeLists.txt b/backends/p4tools/modules/smith/targets/nic/CMakeLists.txt new file mode 100644 index 0000000000..cc538cea6f --- /dev/null +++ b/backends/p4tools/modules/smith/targets/nic/CMakeLists.txt @@ -0,0 +1,14 @@ +if(ENABLE_TESTING) + # Include the test subdirectory. + message("-- Adding p4smith nic test suite") + include(test/P4Tests.cmake) +endif() + +# Source files for smith. +set( + SMITH_SOURCES + ${SMITH_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/target.cpp + PARENT_SCOPE +) + diff --git a/backends/p4tools/modules/smith/targets/nic/register.h b/backends/p4tools/modules/smith/targets/nic/register.h new file mode 100644 index 0000000000..36c256a884 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/nic/register.h @@ -0,0 +1,12 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_NIC_REGISTER_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_NIC_REGISTER_H_ + +#include "backends/p4tools/modules/smith/targets/nic/target.h" + +namespace P4Tools::P4Smith { + +inline void nicRegisterSmithTarget() { Nic::DpdkPnaSmithTarget::make(); } + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_NIC_REGISTER_H_ */ diff --git a/backends/p4tools/modules/smith/targets/nic/target.cpp b/backends/p4tools/modules/smith/targets/nic/target.cpp new file mode 100644 index 0000000000..9da0b28d6a --- /dev/null +++ b/backends/p4tools/modules/smith/targets/nic/target.cpp @@ -0,0 +1,318 @@ +#include "backends/p4tools/modules/smith/targets/nic/target.h" + +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" +#include "ir/node.h" +#include "ir/vector.h" + +namespace P4Tools::P4Smith::Nic { + +using namespace P4::literals; + +/* ============================================================================================= + * AbstractNicSmithTarget implementation + * ============================================================================================= */ + +AbstractNicSmithTarget::AbstractNicSmithTarget(const std::string &deviceName, + const std::string &archName) + : SmithTarget(deviceName, archName) {} + +/* ============================================================================================= + * DpdkPnaSmithTarget implementation + * ============================================================================================= */ + +DpdkPnaSmithTarget::DpdkPnaSmithTarget() : AbstractNicSmithTarget("dpdk", "pna") {} + +void DpdkPnaSmithTarget::make() { + static DpdkPnaSmithTarget *INSTANCE = nullptr; + if (INSTANCE == nullptr) { + INSTANCE = new DpdkPnaSmithTarget(); + } +} + +IR::P4Parser *DpdkPnaSmithTarget::generateMainParserBlock() const { + IR::IndexedVector parserLocals; + P4Scope::startLocalScope(); + + // generate type_parser !that this is labeled "p" + IR::IndexedVector params; + + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_in"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "hdr"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "user_meta"_cs, + "main_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "pna_main_parser_input_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + + auto *tpParser = new IR::Type_Parser("MainParserImpl", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + // // generate decls + // for (int i = 0; i < 5; i++) { + // auto var_decl = variableDeclaration::gen(); + // parserLocals.push_back(var_decl); + // } + + // generate states + IR::IndexedVector states; + auto *startState = parserGenerator().genStartState(); + states.push_back(startState); + states.push_back(parserGenerator().genHdrStates()); + + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4parser = new IR::P4Parser("MainParserImpl", tpParser, parserLocals, states); + P4Scope::addToScope(p4parser); + return p4parser; +} + +IR::P4Control *DpdkPnaSmithTarget::generatePreControlBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "hdr"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "user_meta"_cs, + "main_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "pna_pre_input_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "ostd"_cs, + "pna_pre_output_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("PreControlImpl", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + + return new IR::P4Control("PreControlImpl", typeCtrl, localDecls, blkStat); +} + +IR::P4Control *DpdkPnaSmithTarget::generateMainControlBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "hdr"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "user_meta"_cs, + "main_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "istd"_cs, + "pna_main_input_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "ostd"_cs, + "pna_main_output_metadata_t"_cs)); + + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("MainControlImpl", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + IR::IndexedVector localDecls = declarationGenerator().genLocalControlDecls(); + // apply body + auto *applyBlock = statementGenerator().genBlockStatement(false); + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4ctrl = new IR::P4Control("MainControlImpl", typeCtrl, localDecls, applyBlock); + P4Scope::addToScope(p4ctrl); + return p4ctrl; +} + +IR::MethodCallStatement *generateDeparserEmitCall() { + auto *call = new IR::PathExpression("pkt.emit"); + auto *args = new IR::Vector(); + + args->push_back(new IR::Argument(new IR::PathExpression("hdr"))); + + auto *mce = new IR::MethodCallExpression(call, args); + auto *mst = new IR::MethodCallStatement(mce); + return mst; +} + +IR::P4Control *DpdkPnaSmithTarget::generateMainDeparserBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_out"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "hdr"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "user_meta"_cs, + "main_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "ostd"_cs, + "pna_main_output_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("MainDeparserImpl", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + blkStat->push_back(generateDeparserEmitCall()); + + return new IR::P4Control("MainDeparserImpl", typeCtrl, localDecls, blkStat); +} + +IR::Declaration_Instance *generateMainPackage() { + auto *args = new IR::Vector(); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("MainParserImpl")))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("PreControlImpl")))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("MainControlImpl")))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("MainDeparserImpl")))); + auto *packageName = new IR::Type_Name("PNA_NIC"); + return new IR::Declaration_Instance("main", packageName, args); +} + +IR::Type_Struct *generateUserMetadata() { + // Do not emit meta fields for now, no need + IR::IndexedVector fields; + auto *ret = new IR::Type_Struct("main_metadata_t", fields); + P4Scope::addToScope(ret); + return ret; +} + +void generateMainMetadata() { + IR::ID *name = nullptr; + IR::Type_Struct *ret = nullptr; + IR::IndexedVector fields; + + name = new IR::ID("pna_main_parser_input_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); + name = new IR::ID("pna_pre_input_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); + name = new IR::ID("pna_pre_output_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); + name = new IR::ID("pna_main_input_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); + name = new IR::ID("pna_main_output_metadata_t"); + ret = new IR::Type_Struct(*name, fields); + P4Scope::addToScope(ret); +} + +void setPnaDpdkProbabilities() { + PCT.PARAMETER_NONEDIR_DERIVED_STRUCT = 0; + PCT.PARAMETER_NONEDIR_DERIVED_HEADER = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_BOOL = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_ERROR = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_STRING = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_VARBIT = 0; +} + +int DpdkPnaSmithTarget::writeTargetPreamble(std::ostream *ostream) const { + *ostream << "#include \n"; + *ostream << "#include \n\n"; + *ostream << "bit<3> max(in bit<3> val, in bit<3> bound) {\n"; + *ostream << " return val < bound ? val : bound;\n"; + *ostream << "}\n"; + return EXIT_SUCCESS; +} + +const IR::P4Program *DpdkPnaSmithTarget::generateP4Program() const { + P4Scope::startLocalScope(); + // insert banned structures + P4Scope::notInitializedStructs.insert("psa_ingress_parser_input_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("psa_ingress_input_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("psa_ingress_output_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("psa_egress_input_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("psa_egress_output_metadata_t"_cs); + // set psa-specific probabilities + setPnaDpdkProbabilities(); + // insert some dummy metadata + generateMainMetadata(); + + // start to assemble the model + auto *objects = new IR::Vector(); + + objects->push_back(declarationGenerator().genEthernetHeaderType()); + + // generate some declarations + int typeDecls = Utils::getRandInt(DECL.MIN_TYPE, DECL.MAX_TYPE); + for (int i = 0; i < typeDecls; ++i) { + objects->push_back(declarationGenerator().genTypeDeclaration()); + } + + // generate struct Headers + objects->push_back(declarationGenerator().genHeaderStruct()); + // generate struct metadata_t + objects->push_back(generateUserMetadata()); + + // generate some callables + int callableDecls = Utils::getRandInt(DECL.MIN_CALLABLES, DECL.MAX_CALLABLES); + for (int i = 0; i < callableDecls; ++i) { + std::vector percent = {80, 15, 0, 5}; + switch (Utils::getRandInt(percent)) { + case 0: { + objects->push_back(declarationGenerator().genFunctionDeclaration()); + break; + } + case 1: { + objects->push_back(declarationGenerator().genActionDeclaration()); + break; + } + case 2: { + objects->push_back(declarationGenerator().genExternDeclaration()); + break; + } + case 3: { + objects->push_back(declarationGenerator().genControlDeclaration()); + break; + } + } + } + + // generate all the necessary pipelines for the package + objects->push_back(generateMainParserBlock()); + objects->push_back(generatePreControlBlock()); + objects->push_back(generateMainControlBlock()); + objects->push_back(generateMainDeparserBlock()); + + // finally assemble the package + objects->push_back(generateMainPackage()); + + return new IR::P4Program(*objects); +} + +} // namespace P4Tools::P4Smith::Nic diff --git a/backends/p4tools/modules/smith/targets/nic/target.h b/backends/p4tools/modules/smith/targets/nic/target.h new file mode 100644 index 0000000000..28542b8da2 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/nic/target.h @@ -0,0 +1,65 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_NIC_TARGET_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_NIC_TARGET_H_ + +#include +#include + +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/common/table.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "ir/ir.h" + +namespace P4Tools::P4Smith::Nic { + +class AbstractNicSmithTarget : public SmithTarget { + protected: + explicit AbstractNicSmithTarget(const std::string &deviceName, const std::string &archName); +}; + +class DpdkPnaSmithTarget : public AbstractNicSmithTarget { + private: + DeclarationGenerator *_declarationGenerator = new DeclarationGenerator(*this); + ExpressionGenerator *_expressionGenerator = new ExpressionGenerator(*this); + StatementGenerator *_statementGenerator = new StatementGenerator(*this); + ParserGenerator *_parserGenerator = new ParserGenerator(*this); + TableGenerator *_tableGenerator = new TableGenerator(*this); + + [[nodiscard]] IR::P4Parser *generateMainParserBlock() const; + [[nodiscard]] IR::P4Control *generatePreControlBlock() const; + [[nodiscard]] IR::P4Control *generateMainControlBlock() const; + [[nodiscard]] IR::P4Control *generateMainDeparserBlock() const; + + public: + /// Registers this target. + static void make(); + + [[nodiscard]] int writeTargetPreamble(std::ostream *ostream) const override; + + [[nodiscard]] const IR::P4Program *generateP4Program() const override; + + [[nodiscard]] DeclarationGenerator &declarationGenerator() const override { + return *_declarationGenerator; + } + + [[nodiscard]] ExpressionGenerator &expressionGenerator() const override { + return *_expressionGenerator; + } + + [[nodiscard]] StatementGenerator &statementGenerator() const override { + return *_statementGenerator; + } + + [[nodiscard]] ParserGenerator &parserGenerator() const override { return *_parserGenerator; } + + [[nodiscard]] TableGenerator &tableGenerator() const override { return *_tableGenerator; } + + private: + DpdkPnaSmithTarget(); +}; + +} // namespace P4Tools::P4Smith::Nic + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_NIC_TARGET_H_ */ diff --git a/backends/p4tools/modules/smith/targets/nic/test/P4Tests.cmake b/backends/p4tools/modules/smith/targets/nic/test/P4Tests.cmake new file mode 100644 index 0000000000..3e142b552c --- /dev/null +++ b/backends/p4tools/modules/smith/targets/nic/test/P4Tests.cmake @@ -0,0 +1,10 @@ +# This file defines how to execute Smith on P4 programs. +# General test utilities. +include(${P4TOOLS_SOURCE_DIR}/cmake/TestUtils.cmake) + +set(SMITH_BMV2_CMD ${smith_SOURCE_DIR}/scripts/compilation-test.sh) + +set(SMITH_BMV2_ARGS 100 ${P4SMITH_DRIVER} ${CMAKE_BINARY_DIR}/p4c-dpdk ${CMAKE_BINARY_DIR} dpdk pna) + +add_test (NAME smith-compile-dpdk COMMAND ${SMITH_BMV2_CMD} ${SMITH_BMV2_ARGS} WORKING_DIRECTORY ${P4C_BINARY_DIR}) + diff --git a/backends/p4tools/modules/smith/targets/tofino/CMakeLists.txt b/backends/p4tools/modules/smith/targets/tofino/CMakeLists.txt new file mode 100644 index 0000000000..cab87d5a52 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/tofino/CMakeLists.txt @@ -0,0 +1,14 @@ +if(ENABLE_TESTING) + # Include the test subdirectory. + message("-- Adding p4smith tofino test suite") + include(test/P4Tests.cmake) +endif() + +# Source files for smith. +set( + SMITH_SOURCES + ${SMITH_SOURCES} + ${CMAKE_CURRENT_SOURCE_DIR}/target.cpp + PARENT_SCOPE +) + diff --git a/backends/p4tools/modules/smith/targets/tofino/register.h b/backends/p4tools/modules/smith/targets/tofino/register.h new file mode 100644 index 0000000000..0c1ee00092 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/tofino/register.h @@ -0,0 +1,12 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_TOFINO_REGISTER_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_TOFINO_REGISTER_H_ + +#include "backends/p4tools/modules/smith/targets/tofino/target.h" + +namespace P4Tools::P4Smith { + +inline void tofinoRegisterSmithTarget() { Tofino::TofinoTnaSmithTarget::make(); } + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_TOFINO_REGISTER_H_ */ diff --git a/backends/p4tools/modules/smith/targets/tofino/target.cpp b/backends/p4tools/modules/smith/targets/tofino/target.cpp new file mode 100644 index 0000000000..074311d8c1 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/tofino/target.cpp @@ -0,0 +1,619 @@ +#include "backends/p4tools/modules/smith/targets/tofino/target.h" + +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/probabilities.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "backends/p4tools/modules/smith/util/util.h" +#include "ir/indexed_vector.h" +#include "ir/ir.h" +#include "ir/node.h" +#include "ir/vector.h" +#include "lib/cstring.h" + +namespace P4Tools::P4Smith::Tofino { + +using namespace P4::literals; + +/* ============================================================================================= + * AbstractTofinoSmithTarget implementation + * ============================================================================================= */ + +AbstractTofinoSmithTarget::AbstractTofinoSmithTarget(const std::string &deviceName, + const std::string &archName) + : SmithTarget(deviceName, archName) {} + +/* ============================================================================================= + * TofinoTnaSmithTarget implementation + * ============================================================================================= */ + +TofinoTnaSmithTarget::TofinoTnaSmithTarget() : AbstractTofinoSmithTarget("tofino", "tna") {} + +void TofinoTnaSmithTarget::make() { + static TofinoTnaSmithTarget *INSTANCE = nullptr; + if (INSTANCE == nullptr) { + INSTANCE = new TofinoTnaSmithTarget(); + } +} + +namespace { + +IR::Declaration_Instance *generatePackageDeclaration() { + auto *args = new IR::Vector(); + + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("SwitchIngressParser")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("ingress")))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("SwitchIngressDeparser")))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("SwitchEgressParser")))); + args->push_back( + new IR::Argument(new IR::MethodCallExpression(new IR::TypeNameExpression("SwitchEgress")))); + args->push_back(new IR::Argument( + new IR::MethodCallExpression(new IR::TypeNameExpression("SwitchEgressDeparser")))); + auto *packageName = new IR::Type_Name("Pipeline"); + return new IR::Declaration_Instance("pipe", packageName, args); +} + +IR::Declaration_Instance *generateMainPackage() { + auto *args = new IR::Vector(); + args->push_back(new IR::Argument(new IR::TypeNameExpression("pipe"))); + auto *packageName = new IR::Type_Name("Switch"); + return new IR::Declaration_Instance("main", packageName, args); +} + +IR::IndexedVector generateStructFields(std::vector &fields, + std::vector &bit_size, + size_t vec_size) { + IR::IndexedVector retFields; + + for (size_t i = 0; i < vec_size; i++) { + cstring name = fields.at(i); + retFields.push_back(new IR::StructField(name, IR::Type_Bits::get(bit_size.at(i), false))); + } + + return retFields; +} + +IR::IndexedVector generateIngressIntrinsicMetadata() { + std::vector fields = { + // "resubmit_flag", + }; + + std::vector bitSize = { + // 1, + }; + + return generateStructFields(fields, bitSize, fields.size()); +} + +IR::IndexedVector generateIngressIntrinsicMetadataForTrafficManager() { + std::vector fields = { + // "ucast_egress_port", + // "bypass_egress", + // "deflect_on_drop", + // "ingress_cos", + // "qid", + // "icos_for_copy_to_cpu", + // "copy_to_cpu", + // "packet_color", + // "disable_ucast_cutthru", + // "enable_mcast_cutthru", + // "mcast_grp_a", + // "mcast_grp_b", + // "level1_mcast_hash", + // "level2_mcast_hash", + // "level1_exclusion_id", + // "level2_exclusion_id", + // "rid", + }; + + std::vector bitSize = { + // 9, + // 1, + // 1, + // 3, + // 5, + // 3, + // 1, + // 2, + // 1, + // 1, + // 16, + // 16, + // 13, + // 13, + // 16, + // 9, + // 16, + }; + + return generateStructFields(fields, bitSize, fields.size()); +} + +IR::IndexedVector generateIngressIntrinsicMetadataFromParser() { + std::vector fields = { + // "parser_err", + }; + + std::vector bitSize = { + // 16, + }; + + return generateStructFields(fields, bitSize, fields.size()); +} + +IR::IndexedVector generateIngressIntrinsicMetadataForDeparser() { + std::vector fields = { + // "drop_ctl", + // "digest_type", + // "resubmit_type", + // "mirror_type", + }; + + std::vector bitSize = { + // 3, + // 3, + // 3, + // 3, + }; + + return generateStructFields(fields, bitSize, fields.size()); +} + +IR::IndexedVector generateEgressIntrisicMetadata() { + std::vector fields = { + // "egress_port", + }; + + std::vector bitSize = { + // 9, + }; + + return generateStructFields(fields, bitSize, fields.size()); +} + +IR::IndexedVector generateEgressIntrinsicMetadataFromParser() { + std::vector fields = { + // "parser_err", + }; + + std::vector bitSize = { + // 16, + }; + + return generateStructFields(fields, bitSize, fields.size()); +} + +IR::IndexedVector generateEgressIntrinsicMetadataForDeparser() { + std::vector fields = { + // "drop_ctl", + // "mirror_type", + // "coalesce_flush", + // "coalesce_length", + }; + + std::vector bitSize = { + // 3, + // 3, + // 1, + // 7, + }; + + return generateStructFields(fields, bitSize, fields.size()); +} + +IR::IndexedVector generateEgressIntrinsicMetadataForOutputPort() { + std::vector fields = { + // "force_tx_error", + }; + + std::vector bitSize = { + // 1, + }; + + return generateStructFields(fields, bitSize, fields.size()); +} + +void generateTnaMetadata() { + IR::ID *name = nullptr; + // IR::IndexedVector fields; + IR::Type_Struct *ret = nullptr; + + name = new IR::ID("ingress_intrinsic_metadata_t"); + ret = new IR::Type_Struct(*name, generateIngressIntrinsicMetadata()); + P4Scope::addToScope(ret); + name = new IR::ID("ingress_intrinsic_metadata_for_tm_t"); + ret = new IR::Type_Struct(*name, generateIngressIntrinsicMetadataForTrafficManager()); + P4Scope::addToScope(ret); + name = new IR::ID("ingress_intrinsic_metadata_from_parser_t"); + ret = new IR::Type_Struct(*name, generateIngressIntrinsicMetadataFromParser()); + P4Scope::addToScope(ret); + name = new IR::ID("ingress_intrinsic_metadata_for_deparser_t"); + ret = new IR::Type_Struct(*name, generateIngressIntrinsicMetadataForDeparser()); + P4Scope::addToScope(ret); + name = new IR::ID("egress_intrinsic_metadata_t"); + ret = new IR::Type_Struct(*name, generateEgressIntrisicMetadata()); + P4Scope::addToScope(ret); + name = new IR::ID("egress_intrinsic_metadata_from_parser_t"); + ret = new IR::Type_Struct(*name, generateEgressIntrinsicMetadataFromParser()); + P4Scope::addToScope(ret); + name = new IR::ID("egress_intrinsic_metadata_for_deparser_t"); + ret = new IR::Type_Struct(*name, generateEgressIntrinsicMetadataForDeparser()); + P4Scope::addToScope(ret); + name = new IR::ID("egress_intrinsic_metadata_for_output_port_t"); + ret = new IR::Type_Struct(*name, generateEgressIntrinsicMetadataForOutputPort()); + P4Scope::addToScope(ret); +} + +IR::Type_Struct *generateIngressMetadataT() { + // Do !emit meta fields for now, no need + IR::IndexedVector fields; + auto *ret = new IR::Type_Struct("ingress_metadata_t", fields); + P4Scope::addToScope(ret); + return ret; +} + +IR::Type_Struct *generateEgressMetadataT() { + // Do !emit meta fields for now, no need + IR::IndexedVector fields; + auto *ret = new IR::Type_Struct("egress_metadata_t", fields); + P4Scope::addToScope(ret); + return ret; +} + +void setTnaProbabilities() { + PCT.PARAMETER_NONEDIR_DERIVED_STRUCT = 0; + PCT.PARAMETER_NONEDIR_DERIVED_HEADER = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_BOOL = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_ERROR = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_STRING = 0; + PCT.PARAMETER_NONEDIR_BASETYPE_VARBIT = 0; + // TNA does not support headers that are not multiples of 8. + PCT.STRUCTTYPEDECLARATION_BASETYPE_BOOL = 0; + // TNA requires headers to be byte-aligned. + P4Scope::req.byte_align_headers = true; + // TNA requires constant header stack indices. + P4Scope::constraints.const_header_stack_index = true; + // TNA requires that the shift count in IR::SHL must be a constant. + P4Scope::constraints.const_lshift_count = true; + // TNA *currently* only supports single stage actions. + P4Scope::constraints.single_stage_actions = true; + // Saturating arithmetic operators mau not exceed maximum PHV container width. + P4Scope::constraints.max_phv_container_width = 32; +} + +IR::MethodCallStatement *generateDeparserEmitCall() { + auto *call = new IR::PathExpression("pkt.emit"); + auto *args = new IR::Vector(); + + args->push_back(new IR::Argument(new IR::PathExpression("h"))); + + auto *mce = new IR::MethodCallExpression(call, args); + auto *mst = new IR::MethodCallStatement(mce); + return mst; +} + +} // namespace + +IR::P4Parser *TofinoTnaSmithTarget::generateIngressParserBlock() const { + IR::IndexedVector parserLocals; + P4Scope::startLocalScope(); + + // Generate type_parser, note that this is labeled "p". + IR::IndexedVector params; + + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_in"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::Out, "hdr"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::Out, "ig_md"_cs, + "ingress_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::Out, "ig_intr_md"_cs, + "ingress_intrinsic_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + + auto *tpParser = new IR::Type_Parser("SwitchIngressParser", parList); + + // Add params to the parser scope. + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // we only add values that are not read-only, to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + // Generate variable declarations. + for (int i = 0; i < 5; i++) { + auto *varDecl = declarationGenerator().genVariableDeclaration(); + parserLocals.push_back(varDecl); + } + + // Generate reguster actions. + // These are currently disabled because + // they cause a compiler bug, which is currently + // being investigates + for (int i = 0; i < 0; i++) { + // Need to pass in parserLocals because we generate register declarations + // inside genDeclInstance. + // auto *reg = RegisterActionDeclaration::genDeclInstance(&parserLocals); + // parserLocals.push_back(reg); + } + + // Generate Parser states. + IR::IndexedVector states; + auto *startState = parserGenerator().genStartState(); + + // Insert custom parsing statements into the start state. + auto *pktPath = new IR::PathExpression("pkt"); + auto *pktExtract = new IR::Member(pktPath, "extract"); + auto *pktAdvance = new IR::Member(pktPath, "advance"); + auto *igIntrMd = new IR::PathExpression("ig_intr_md"); + auto *extractTofinoMd = parserGenerator().genHdrExtract(pktExtract, igIntrMd); + startState->components.push_back(extractTofinoMd); + auto *portMdSize = new IR::PathExpression("PORT_METADATA_SIZE"); + auto *advanceTofinoMd = parserGenerator().genHdrExtract(pktAdvance, portMdSize); + startState->components.push_back(advanceTofinoMd); + // Done with custom statements. + states.push_back(startState); + states.push_back(parserGenerator().genHdrStates()); + + P4Scope::endLocalScope(); + + // Add the parser to the whole scope. + auto *p4parser = new IR::P4Parser("SwitchIngressParser", tpParser, parserLocals, states); + P4Scope::addToScope(p4parser); + return p4parser; +} + +IR::P4Control *TofinoTnaSmithTarget::generateIngressBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "ig_md"_cs, + "ingress_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "ig_intr_md"_cs, + "ingress_intrinsic_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter( + IR::Direction::In, "ig_prsr_md"_cs, "ingress_intrinsic_metadata_from_parser_t"_cs)); + params.push_back(declarationGenerator().genParameter( + IR::Direction::InOut, "ig_dprsr_md"_cs, "ingress_intrinsic_metadata_for_deparser_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "ig_tm_md"_cs, + "ingress_intrinsic_metadata_for_tm_t"_cs)); + + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("ingress", parList); + + // add to the scope + for (const auto *param : parList->parameters) { + P4Scope::addToScope(param); + // add to the name_2_type + // only add values that are !read-only to the modifiable types + if (param->direction == IR::Direction::In) { + P4Scope::addLval(param->type, param->name.name, true); + } else { + P4Scope::addLval(param->type, param->name.name, false); + } + } + + IR::IndexedVector localDecls = declarationGenerator().genLocalControlDecls(); + // apply body + auto *applyBlock = statementGenerator().genBlockStatement(false); + // hardcode the output port to be zero + auto *outputPort = new IR::PathExpression("ig_tm_md.ucast_egress_port"); + auto *outputPortVal = new IR::Constant(IR::Type_InfInt::get(), 0); + auto *assign = new IR::AssignmentStatement(outputPort, outputPortVal); + // some hack to insert the expression at the beginning + auto it = applyBlock->components.begin(); + applyBlock->components.insert(it, assign); + // end of scope + P4Scope::endLocalScope(); + + // add to the whole scope + auto *p4ctrl = new IR::P4Control("ingress", typeCtrl, localDecls, applyBlock); + P4Scope::addToScope(p4ctrl); + return p4ctrl; +} + +IR::P4Control *TofinoTnaSmithTarget::generateIngressDeparserBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_out"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "ig_md"_cs, + "ingress_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter( + IR::Direction::In, "ig_dprsr_md"_cs, "ingress_intrinsic_metadata_for_deparser_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("SwitchIngressDeparser", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + blkStat->push_back(generateDeparserEmitCall()); + + return new IR::P4Control("SwitchIngressDeparser", typeCtrl, localDecls, blkStat); +} + +IR::P4Parser *TofinoTnaSmithTarget::generateEgressParserBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_in"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::Out, "h"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::Out, "eg_md"_cs, + "egress_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::Out, "eg_intr_md"_cs, + "egress_intrinsic_metadata_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeParser = new IR::Type_Parser("SwitchEgressParser", parList); + IR::IndexedVector localDecls; + // TODO(fruffy): this hacky. FIX + // generate states + IR::IndexedVector states; + IR::IndexedVector components; + IR::Expression *transition = new IR::PathExpression("accept"); + auto *startState = new IR::ParserState("start", components, transition); + // insert custom parsing statements into the start state + auto *pktPath = new IR::PathExpression("pkt"); + auto *pktExtract = new IR::Member(pktPath, "extract"); + auto *egIntrMd = new IR::PathExpression("eg_intr_md"); + auto *extractTofinoMd = parserGenerator().genHdrExtract(pktExtract, egIntrMd); + startState->components.push_back(extractTofinoMd); + states.push_back(startState); + return new IR::P4Parser("SwitchEgressParser", typeParser, localDecls, states); +} + +IR::P4Control *TofinoTnaSmithTarget::generateEgressDeparserBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::None, "pkt"_cs, "packet_out"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "eg_md"_cs, "egress_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter( + IR::Direction::In, "eg_intr_dprs_md"_cs, "egress_intrinsic_metadata_for_deparser_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("SwitchEgressDeparser"_cs, parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + blkStat->push_back(generateDeparserEmitCall()); + + return new IR::P4Control("SwitchEgressDeparser", typeCtrl, localDecls, blkStat); +} + +IR::P4Control *TofinoTnaSmithTarget::generateEgressBlock() const { + // start of new scope + P4Scope::startLocalScope(); + + IR::IndexedVector params; + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "h"_cs, SYS_HDR_NAME)); + params.push_back(declarationGenerator().genParameter(IR::Direction::InOut, "eg_md"_cs, + "egress_metadata_t"_cs)); + params.push_back(declarationGenerator().genParameter(IR::Direction::In, "eg_intr_md"_cs, + "egress_intrinsic_metadata_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::In, "eg_intr_md_from_prsr"_cs, + "egress_intrinsic_metadata_from_parser_t"_cs)); + params.push_back(declarationGenerator().genParameter( + IR::Direction::InOut, "eg_intr_dprs_md"_cs, "egress_intrinsic_metadata_for_deparser_t"_cs)); + params.push_back( + declarationGenerator().genParameter(IR::Direction::InOut, "eg_intr_oport_md"_cs, + "egress_intrinsic_metadata_for_output_port_t"_cs)); + auto *parList = new IR::ParameterList(params); + auto *typeCtrl = new IR::Type_Control("SwitchEgress", parList); + IR::IndexedVector localDecls; + auto *blkStat = new IR::BlockStatement(); + + return new IR::P4Control("SwitchEgress", typeCtrl, localDecls, blkStat); +} + +int TofinoTnaSmithTarget::writeTargetPreamble(std::ostream *ostream) const { + *ostream << "#include \n"; + *ostream << "#define __TARGET_TOFINO__ 1\n"; + *ostream << "#include \n\n"; + return EXIT_SUCCESS; +} + +const IR::P4Program *TofinoTnaSmithTarget::generateP4Program() const { + P4Scope::startLocalScope(); + + // insert banned structures + P4Scope::notInitializedStructs.insert("ingress_intrinsic_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("ingress_intrinsic_metadata_for_tm_t"_cs); + P4Scope::notInitializedStructs.insert("ingress_intrinsic_metadata_from_parser_t"_cs); + P4Scope::notInitializedStructs.insert("ingress_intrinsic_metadata_for_deparser_t"_cs); + P4Scope::notInitializedStructs.insert("egress_intrinsic_metadata_t"_cs); + P4Scope::notInitializedStructs.insert("egress_intrinsic_metadata_from_parser_t"_cs); + P4Scope::notInitializedStructs.insert("egress_intrinsic_metadata_for_deparser_t"_cs); + P4Scope::notInitializedStructs.insert("egress_intrinsic_metadata_for_output_port_t"_cs); + + // set tna-specific probabilities + setTnaProbabilities(); + + // start to assemble the model + auto *objects = new IR::Vector(); + + // insert tofino metadata + generateTnaMetadata(); + + objects->push_back(declarationGenerator().genEthernetHeaderType()); + + // generate some declarations + int typeDecls = Utils::getRandInt(DECL.MIN_TYPE, DECL.MAX_TYPE); + for (int i = 0; i < typeDecls; ++i) { + objects->push_back(declarationGenerator().genTypeDeclaration()); + } + + // generate struct Headers + objects->push_back(declarationGenerator().genHeaderStruct()); + // generate struct ingress_metadata_t + objects->push_back(generateIngressMetadataT()); + // generate struct egress_metadata_t + objects->push_back(generateEgressMetadataT()); + + // generate some callables + int callableDecls = Utils::getRandInt(DECL.MIN_CALLABLES, DECL.MAX_CALLABLES); + for (int i = 0; i < callableDecls; ++i) { + std::vector percent = {80, 15, 0, 5}; + switch (Utils::getRandInt(percent)) { + case 0: { + objects->push_back(declarationGenerator().genFunctionDeclaration()); + break; + } + case 1: { + objects->push_back(declarationGenerator().genActionDeclaration()); + break; + } + case 2: { + objects->push_back(declarationGenerator().genExternDeclaration()); + break; + } + case 3: { + objects->push_back(declarationGenerator().genControlDeclaration()); + break; + } + } + } + + // generate all the necessary pipelines for the package + objects->push_back(generateIngressParserBlock()); + objects->push_back(generateIngressBlock()); + objects->push_back(generateIngressDeparserBlock()); + objects->push_back(generateEgressParserBlock()); + objects->push_back(generateEgressBlock()); + objects->push_back(generateEgressDeparserBlock()); + + // finally assemble the package + objects->push_back(generatePackageDeclaration()); + objects->push_back(generateMainPackage()); + + return new IR::P4Program(*objects); +} +} // namespace P4Tools::P4Smith::Tofino diff --git a/backends/p4tools/modules/smith/targets/tofino/target.h b/backends/p4tools/modules/smith/targets/tofino/target.h new file mode 100644 index 0000000000..c7c488f109 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/tofino/target.h @@ -0,0 +1,67 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_TOFINO_TARGET_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_TOFINO_TARGET_H_ + +#include +#include + +#include "backends/p4tools/modules/smith/common/declarations.h" +#include "backends/p4tools/modules/smith/common/expressions.h" +#include "backends/p4tools/modules/smith/common/parser.h" +#include "backends/p4tools/modules/smith/common/statements.h" +#include "backends/p4tools/modules/smith/common/table.h" +#include "backends/p4tools/modules/smith/core/target.h" +#include "ir/ir.h" + +namespace P4Tools::P4Smith::Tofino { + +class AbstractTofinoSmithTarget : public SmithTarget { + protected: + explicit AbstractTofinoSmithTarget(const std::string &deviceName, const std::string &archName); +}; + +class TofinoTnaSmithTarget : public AbstractTofinoSmithTarget { + private: + DeclarationGenerator *_declarationGenerator = new DeclarationGenerator(*this); + ExpressionGenerator *_expressionGenerator = new ExpressionGenerator(*this); + StatementGenerator *_statementGenerator = new StatementGenerator(*this); + ParserGenerator *_parserGenerator = new ParserGenerator(*this); + TableGenerator *_tableGenerator = new TableGenerator(*this); + + [[nodiscard]] IR::P4Parser *generateIngressParserBlock() const; + [[nodiscard]] IR::P4Control *generateIngressBlock() const; + [[nodiscard]] IR::P4Control *generateIngressDeparserBlock() const; + [[nodiscard]] IR::P4Parser *generateEgressParserBlock() const; + [[nodiscard]] IR::P4Control *generateEgressBlock() const; + [[nodiscard]] IR::P4Control *generateEgressDeparserBlock() const; + + public: + /// Registers this target. + static void make(); + + [[nodiscard]] int writeTargetPreamble(std::ostream *ostream) const override; + + [[nodiscard]] const IR::P4Program *generateP4Program() const override; + + [[nodiscard]] DeclarationGenerator &declarationGenerator() const override { + return *_declarationGenerator; + } + + [[nodiscard]] ExpressionGenerator &expressionGenerator() const override { + return *_expressionGenerator; + } + + [[nodiscard]] StatementGenerator &statementGenerator() const override { + return *_statementGenerator; + } + + [[nodiscard]] ParserGenerator &parserGenerator() const override { return *_parserGenerator; } + + [[nodiscard]] TableGenerator &tableGenerator() const override { return *_tableGenerator; } + + private: + TofinoTnaSmithTarget(); +}; + +} // namespace P4Tools::P4Smith::Tofino + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TARGETS_TOFINO_TARGET_H_ */ diff --git a/backends/p4tools/modules/smith/targets/tofino/test/P4Tests.cmake b/backends/p4tools/modules/smith/targets/tofino/test/P4Tests.cmake new file mode 100644 index 0000000000..46260e1f55 --- /dev/null +++ b/backends/p4tools/modules/smith/targets/tofino/test/P4Tests.cmake @@ -0,0 +1,7 @@ +# This file defines how to execute Smith on P4 programs. +# General test utilities. +include(${P4TOOLS_SOURCE_DIR}/cmake/TestUtils.cmake) + +set(SMITH_BMV2_CMD ${smith_SOURCE_DIR}/scripts/compilation-test.sh) + + diff --git a/backends/p4tools/modules/smith/toolname.h b/backends/p4tools/modules/smith/toolname.h new file mode 100644 index 0000000000..88b7a126bf --- /dev/null +++ b/backends/p4tools/modules/smith/toolname.h @@ -0,0 +1,12 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_TOOLNAME_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_TOOLNAME_H_ + +#include + +namespace P4Tools::P4Smith { + +static inline constexpr std::string_view TOOL_NAME = "smith"; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_TOOLNAME_H_ */ diff --git a/backends/p4tools/modules/smith/util/util.cpp b/backends/p4tools/modules/smith/util/util.cpp new file mode 100644 index 0000000000..b035b399ca --- /dev/null +++ b/backends/p4tools/modules/smith/util/util.cpp @@ -0,0 +1,61 @@ +#include "backends/p4tools/modules/smith/util/util.h" + +#include +#include +#include +#include +#include +#include + +#include "backends/p4tools/common/lib/util.h" +#include "backends/p4tools/modules/smith/common/scope.h" +#include "backends/p4tools/modules/smith/util/wordlist.h" + +namespace P4Tools::P4Smith { + +std::string getRandomString(size_t len) { + static const std::vector P4_KEYWORDS = {"if", "void", "else", + "key", "actions", "true"}; + static const std::array ALPHANUMERIC_CHARACTERS = { + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz"}; + + std::string ret; + + while (true) { + std::stringstream ss; + // Try to get a name from the wordlist. + ss << Wordlist::getFromWordlist(); + size_t lenFromWordlist = ss.str().length(); + + if (lenFromWordlist == len) { + ret = ss.str(); + } else if (lenFromWordlist > len) { + // We got a bigger word from the wordlist, so we have to truncate it. + ret = ss.str().substr(0, len); + } else if (lenFromWordlist < len) { + // The word was too small so we append it. + // Note: This also covers the case that we ran + // out of the words from the wordlist. + for (size_t i = lenFromWordlist; i < len; i++) { + ss << ALPHANUMERIC_CHARACTERS.at( + Utils::getRandInt(0, sizeof(ALPHANUMERIC_CHARACTERS) - 2)); + } + ret = ss.str(); + } + + if (std::find(P4_KEYWORDS.begin(), P4_KEYWORDS.end(), ret) != P4_KEYWORDS.end()) { + continue; + } + + // The name is usable, break the loop. + if (P4Scope::usedNames.count(ret) == 0) { + break; + } + } + + P4Scope::usedNames.insert(ret); + return ret; +} + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/util/util.h b/backends/p4tools/modules/smith/util/util.h new file mode 100644 index 0000000000..ae8e7ce358 --- /dev/null +++ b/backends/p4tools/modules/smith/util/util.h @@ -0,0 +1,25 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_UTIL_UTIL_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_UTIL_UTIL_H_ + +#include + +#include "lib/cstring.h" + +namespace P4Tools::P4Smith { + +static constexpr int INTEGER_WIDTH(32); + +/// These are hardcoded initialization names. +static const cstring SYS_HDR_NAME("Headers"); +static const cstring ETH_HEADER_T("ethernet_t"); +static const cstring ETH_HDR("eth_hdr"); + +/// @returns a randomly generated string. +/// If we can, return a word from a 10,000 word wordlist, +/// if not, generate a random string and return it. +/// @param len : Ignored when choosing from the wordlist. +std::string getRandomString(size_t len); + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_UTIL_UTIL_H_ */ diff --git a/backends/p4tools/modules/smith/util/wordlist.cpp b/backends/p4tools/modules/smith/util/wordlist.cpp new file mode 100644 index 0000000000..43728f4233 --- /dev/null +++ b/backends/p4tools/modules/smith/util/wordlist.cpp @@ -0,0 +1,703 @@ +#include "backends/p4tools/modules/smith/util/wordlist.h" + +#include +#include + +namespace P4Tools::P4Smith { + +std::size_t Wordlist::counter = 0; + +const std::array Wordlist::WORDS = { + "about", "search", "other", "which", "their", "there", "contact", "business", + "online", "first", "would", "services", "these", "click", "service", "price", + "people", "state", "email", "health", "world", "products", "music", "should", + "product", "system", "policy", "number", "please", "support", "message", "after", + "software", "video", "where", "rights", "public", "books", "school", "through", + "links", "review", "years", "order", "privacy", "items", "company", "group", + "under", "general", "research", "january", "reviews", "program", "games", "could", + "great", "united", "hotel", "center", "store", "travel", "comments", "report", + "member", "details", "terms", "before", "hotels", "right", "because", "local", + "those", "using", "results", "office", "national", "design", "posted", "internet", + "address", "within", "states", "phone", "shipping", "reserved", "subject", "between", + "forum", "family", "based", "black", "check", "special", "prices", "website", + "index", "being", "women", "today", "south", "project", "pages", "version", + "section", "found", "sports", "house", "related", "security", "county", "american", + "photo", "members", "power", "while", "network", "computer", "systems", "three", + "total", "place", "download", "without", "access", "think", "north", "current", + "posts", "media", "control", "water", "history", "pictures", "personal", "since", + "guide", "board", "location", "change", "white", "small", "rating", "children", + "during", "return", "students", "shopping", "account", "times", "sites", "level", + "digital", "profile", "previous", "events", "hours", "image", "title", "another", + "shall", "property", "class", "still", "money", "quality", "every", "listing", + "content", "country", "private", "little", "visit", "tools", "reply", "customer", + "december", "compare", "movies", "include", "college", "value", "article", "provide", + "source", "author", "press", "learn", "around", "print", "course", "canada", + "process", "stock", "training", "credit", "point", "science", "advanced", "sales", + "english", "estate", "select", "windows", "photos", "thread", "category", "large", + "gallery", "table", "register", "however", "october", "november", "market", "library", + "really", "action", "start", "series", "model", "features", "industry", "human", + "provided", "required", "second", "movie", "forums", "march", "better", "yahoo", + "going", "medical", "friend", "server", "study", "staff", "articles", "feedback", + "again", "looking", "issues", "april", "never", "users", "complete", "street", + "topic", "comment", "things", "working", "against", "standard", "person", "below", + "mobile", "party", "payment", "login", "student", "programs", "offers", "legal", + "above", "recent", "stores", "problem", "memory", "social", "august", "quote", + "language", "story", "options", "rates", "create", "young", "america", "field", + "paper", "single", "example", "girls", "password", "latest", "question", "changes", + "night", "texas", "poker", "status", "browse", "issue", "range", "building", + "seller", "court", "february", "always", "result", "audio", "light", "write", + "offer", "groups", "given", "files", "event", "release", "analysis", "request", + "china", "making", "picture", "needs", "possible", "might", "month", "major", + "areas", "future", "space", "cards", "problems", "london", "meeting", "become", + "interest", "child", "enter", "share", "similar", "garden", "schools", "million", + "added", "listed", "learning", "energy", "delivery", "popular", "stories", "journal", + "reports", "welcome", "central", "images", "notice", "original", "radio", "until", + "color", "council", "includes", "track", "archive", "others", "format", "least", + "society", "months", "safety", "friends", "trade", "edition", "messages", "further", + "updated", "having", "provides", "david", "already", "green", "studies", "close", + "common", "drive", "specific", "several", "living", "called", "short", "display", + "limited", "powered", "means", "director", "daily", "beach", "natural", "whether", + "period", "planning", "database", "official", "weather", "average", "window", "france", + "region", "island", "record", "direct", "records", "district", "calendar", "costs", + "style", "front", "update", "parts", "early", "miles", "sound", "resource", + "present", "either", "document", "works", "material", "written", "federal", "hosting", + "rules", "final", "adult", "tickets", "thing", "centre", "cheap", "finance", + "minutes", "third", "gifts", "europe", "reading", "topics", "cover", "usually", + "together", "videos", "percent", "function", "getting", "global", "economic", "player", + "projects", "lyrics", "often", "submit", "germany", "amount", "watch", "included", + "though", "thanks", "deals", "various", "words", "linux", "james", "weight", + "heart", "received", "choose", "archives", "points", "magazine", "error", "camera", + "clear", "receive", "domain", "methods", "chapter", "makes", "policies", "beauty", + "manager", "india", "position", "taken", "listings", "models", "michael", "known", + "cases", "florida", "simple", "quick", "wireless", "license", "friday", "whole", + "annual", "later", "basic", "shows", "google", "church", "method", "purchase", + "active", "response", "practice", "hardware", "figure", "holiday", "enough", "designed", + "along", "among", "death", "writing", "speed", "brand", "discount", "higher", + "effects", "created", "remember", "yellow", "increase", "kingdom", "thought", "stuff", + "french", "storage", "japan", "doing", "loans", "shoes", "entry", "nature", + "orders", "africa", "summary", "growth", "notes", "agency", "monday", "european", + "activity", "although", "western", "income", "force", "overall", "river", "package", + "contents", "players", "engine", "album", "regional", "supplies", "started", "views", + "plans", "double", "build", "screen", "exchange", "types", "lines", "continue", + "across", "benefits", "needed", "season", "apply", "someone", "anything", "printer", + "believe", "effect", "asked", "sunday", "casino", "volume", "cross", "anyone", + "mortgage", "silver", "inside", "solution", "mature", "rather", "weeks", "addition", + "supply", "nothing", "certain", "running", "lower", "union", "jewelry", "clothing", + "names", "robert", "homepage", "skills", "islands", "advice", "career", "military", + "rental", "decision", "leave", "british", "teens", "woman", "sellers", "middle", + "cable", "taking", "values", "division", "coming", "tuesday", "object", "lesbian", + "machine", "length", "actually", "score", "client", "returns", "capital", "follow", + "sample", "shown", "saturday", "england", "culture", "flash", "george", "choice", + "starting", "thursday", "courses", "consumer", "airport", "foreign", "artist", "outside", + "levels", "channel", "letter", "phones", "ideas", "summer", "allow", "degree", + "contract", "button", "releases", "homes", "super", "matter", "custom", "virginia", + "almost", "located", "multiple", "asian", "editor", "cause", "focus", "featured", + "rooms", "female", "thomas", "primary", "cancer", "numbers", "reason", "browser", + "spring", "answer", "voice", "friendly", "schedule", "purpose", "feature", "comes", + "police", "everyone", "approach", "cameras", "brown", "physical", "medicine", "ratings", + "chicago", "forms", "glass", "happy", "smith", "wanted", "thank", "unique", + "survey", "prior", "sport", "ready", "animal", "sources", "mexico", "regular", + "secure", "simply", "evidence", "station", "round", "paypal", "favorite", "option", + "master", "valley", "recently", "probably", "rentals", "built", "blood", "improve", + "larger", "networks", "earth", "parents", "nokia", "impact", "transfer", "kitchen", + "strong", "carolina", "wedding", "hospital", "ground", "overview", "owners", "disease", + "italy", "perfect", "classic", "basis", "command", "cities", "william", "express", + "award", "distance", "peter", "ensure", "involved", "extra", "partners", "budget", + "rated", "guides", "success", "maximum", "existing", "quite", "selected", "amazon", + "patients", "warning", "horse", "forward", "flowers", "stars", "lists", "owner", + "retail", "animals", "useful", "directly", "housing", "takes", "bring", "catalog", + "searches", "trying", "mother", "traffic", "joined", "input", "strategy", "agent", + "valid", "modern", "senior", "ireland", "teaching", "grand", "testing", "trial", + "charge", "units", "instead", "canadian", "normal", "wrote", "ships", "entire", + "leading", "metal", "positive", "fitness", "chinese", "opinion", "football", "abstract", + "output", "funds", "greater", "likely", "develop", "artists", "guest", "seems", + "trust", "contains", "session", "multi", "republic", "vacation", "century", "academic", + "graphics", "indian", "expected", "grade", "dating", "pacific", "mountain", "filter", + "mailing", "vehicle", "longer", "consider", "northern", "behind", "panel", "floor", + "german", "buying", "match", "proposed", "default", "require", "outdoor", "morning", + "allows", "protein", "plant", "reported", "politics", "partner", "authors", "boards", + "faculty", "parties", "mission", "string", "sense", "modified", "released", "stage", + "internal", "goods", "unless", "richard", "detailed", "japanese", "approved", "target", + "except", "ability", "maybe", "moving", "brands", "places", "pretty", "spain", + "southern", "yourself", "winter", "battery", "youth", "pressure", "boston", "keywords", + "medium", "break", "purposes", "dance", "itself", "defined", "papers", "playing", + "awards", "studio", "reader", "virtual", "device", "answers", "remote", "external", + "apple", "offered", "theory", "enjoy", "remove", "surface", "minimum", "visual", + "variety", "teachers", "martin", "manual", "block", "subjects", "agents", "repair", + "civil", "steel", "songs", "fixed", "wrong", "hands", "finally", "updates", + "desktop", "classes", "paris", "sector", "capacity", "requires", "jersey", "fully", + "father", "electric", "quotes", "officer", "driver", "respect", "unknown", "worth", + "teacher", "workers", "georgia", "peace", "campus", "showing", "creative", "coast", + "benefit", "progress", "funding", "devices", "grant", "agree", "fiction", "watches", + "careers", "beyond", "families", "museum", "blogs", "accepted", "former", "complex", + "agencies", "parent", "spanish", "michigan", "columbia", "setting", "scale", "stand", + "economy", "highest", "helpful", "monthly", "critical", "frame", "musical", "angeles", + "employee", "chief", "gives", "bottom", "packages", "detail", "changed", "heard", + "begin", "colorado", "royal", "clean", "switch", "russian", "largest", "african", + "titles", "relevant", "justice", "connect", "bible", "basket", "applied", "weekly", + "demand", "suite", "vegas", "square", "chris", "advance", "auction", "allowed", + "correct", "charles", "nation", "selling", "piece", "sheet", "seven", "older", + "illinois", "elements", "species", "cells", "module", "resort", "facility", "random", + "pricing", "minister", "motion", "looks", "fashion", "visitors", "monitor", "trading", + "forest", "calls", "whose", "coverage", "couple", "giving", "chance", "vision", + "ending", "clients", "actions", "listen", "discuss", "accept", "naked", "clinical", + "sciences", "markets", "lowest", "highly", "appear", "lives", "currency", "leather", + "patient", "actual", "stone", "commerce", "perhaps", "persons", "tests", "village", + "accounts", "amateur", "factors", "coffee", "settings", "buyer", "cultural", "steve", + "easily", "poster", "closed", "holidays", "zealand", "balance", "graduate", "replies", + "initial", "label", "thinking", "scott", "canon", "league", "waste", "minute", + "provider", "optional", "sections", "chair", "fishing", "effort", "phase", "fields", + "fantasy", "letters", "motor", "context", "install", "shirt", "apparel", "crime", + "count", "breast", "johnson", "quickly", "dollars", "websites", "religion", "claim", + "driving", "surgery", "patch", "measures", "kansas", "chemical", "doctor", "reduce", + "brought", "himself", "enable", "exercise", "santa", "leader", "diamond", "israel", + "servers", "alone", "meetings", "seconds", "jones", "arizona", "keyword", "flight", + "congress", "username", "produced", "italian", "pocket", "saint", "freedom", "argument", + "creating", "drugs", "joint", "premium", "fresh", "attorney", "upgrade", "factor", + "growing", "stream", "hearing", "eastern", "auctions", "therapy", "entries", "dates", + "signed", "upper", "serious", "prime", "samsung", "limit", "began", "louis", + "steps", "errors", "shops", "efforts", "informed", "thoughts", "creek", "worked", + "quantity", "urban", "sorted", "myself", "tours", "platform", "labor", "admin", + "nursing", "defense", "machines", "heavy", "covered", "recovery", "merchant", "expert", + "protect", "solid", "became", "orange", "vehicles", "prevent", "theme", "campaign", + "marine", "guitar", "finding", "examples", "saying", "spirit", "claims", "motorola", + "affairs", "touch", "intended", "towards", "goals", "election", "suggest", "branch", + "charges", "serve", "reasons", "magic", "mount", "smart", "talking", "latin", + "avoid", "manage", "corner", "oregon", "element", "birth", "virus", "abuse", + "requests", "separate", "quarter", "tables", "define", "racing", "facts", "column", + "plants", "faith", "chain", "identify", "avenue", "missing", "domestic", "sitemap", + "moved", "houston", "reach", "mental", "viewed", "moment", "extended", "sequence", + "attack", "sorry", "centers", "opening", "damage", "reserve", "recipes", "gamma", + "plastic", "produce", "placed", "truth", "counter", "failure", "follows", "weekend", + "dollar", "ontario", "films", "bridge", "native", "williams", "movement", "printing", + "baseball", "owned", "approval", "draft", "chart", "played", "contacts", "jesus", + "readers", "clubs", "jackson", "equal", "matching", "offering", "shirts", "profit", + "leaders", "posters", "variable", "expect", "parking", "compared", "workshop", "russia", + "codes", "kinds", "seattle", "golden", "teams", "lighting", "senate", "forces", + "funny", "brother", "turned", "portable", "tried", "returned", "pattern", "named", + "theatre", "laser", "earlier", "sponsor", "warranty", "indiana", "harry", "objects", + "delete", "evening", "assembly", "nuclear", "taxes", "mouse", "signal", "criminal", + "issued", "brain", "sexual", "powerful", "dream", "obtained", "false", "flower", + "passed", "supplied", "falls", "opinions", "promote", "stated", "stats", "hawaii", + "appears", "carry", "decided", "covers", "hello", "designs", "maintain", "tourism", + "priority", "adults", "clips", "savings", "graphic", "payments", "binding", "brief", + "ended", "winning", "eight", "straight", "script", "served", "wants", "prepared", + "dining", "alert", "atlanta", "dakota", "queen", "credits", "clearly", "handle", + "sweet", "criteria", "pubmed", "diego", "truck", "behavior", "enlarge", "revenue", + "measure", "changing", "votes", "looked", "festival", "ocean", "flights", "experts", + "signs", "depth", "whatever", "logged", "laptop", "vintage", "train", "exactly", + "explore", "maryland", "concept", "nearly", "eligible", "checkout", "reality", "forgot", + "handling", "origin", "gaming", "feeds", "billion", "scotland", "faster", "dallas", + "bought", "nations", "route", "followed", "broken", "frank", "alaska", "battle", + "anime", "speak", "protocol", "query", "equity", "speech", "rural", "shared", + "sounds", "judge", "bytes", "forced", "fight", "height", "speaker", "filed", + "obtain", "offices", "designer", "remain", "managed", "failed", "marriage", "korea", + "banks", "secret", "kelly", "leads", "negative", "austin", "toronto", "theater", + "springs", "missouri", "andrew", "perform", "healthy", "assets", "injury", "joseph", + "ministry", "drivers", "lawyer", "figures", "married", "proposal", "sharing", "portal", + "waiting", "birthday", "gratis", "banking", "brian", "toward", "slightly", "assist", + "conduct", "lingerie", "calling", "serving", "profiles", "miami", "comics", "matters", + "houses", "postal", "controls", "breaking", "combined", "ultimate", "wales", "minor", + "finish", "noted", "reduced", "physics", "spent", "extreme", "samples", "davis", + "daniel", "reviewed", "forecast", "removed", "helps", "singles", "cycle", "amounts", + "contain", "accuracy", "sleep", "pharmacy", "brazil", "creation", "static", "scene", + "hunter", "crystal", "famous", "writer", "chairman", "violence", "oklahoma", "speakers", + "drink", "academy", "dynamic", "gender", "cleaning", "concerns", "vendor", "intel", + "officers", "referred", "supports", "regions", "junior", "rings", "meaning", "ladies", + "henry", "ticket", "guess", "agreed", "soccer", "import", "posting", "presence", + "instant", "viewing", "majority", "christ", "aspects", "austria", "ahead", "scheme", + "utility", "preview", "manner", "matrix", "devel", "despite", "strength", "turkey", + "proper", "degrees", "delta", "seeking", "inches", "phoenix", "shares", "daughter", + "standing", "comfort", "colors", "cisco", "ordering", "alpha", "appeal", "cruise", + "bonus", "bookmark", "specials", "disney", "adobe", "smoking", "becomes", "drives", + "alabama", "improved", "trees", "achieve", "dress", "dealer", "nearby", "carried", + "happen", "exposure", "gambling", "refer", "miller", "outdoors", "clothes", "caused", + "luxury", "babes", "frames", "indeed", "circuit", "layer", "printed", "removal", + "easier", "printers", "adding", "kentucky", "mostly", "taylor", "prints", "spend", + "factory", "interior", "revised", "optical", "relative", "amazing", "clock", "identity", + "suites", "feeling", "hidden", "victoria", "serial", "relief", "revision", "ratio", + "planet", "copies", "recipe", "permit", "seeing", "proof", "tennis", "bedroom", + "empty", "instance", "licensed", "orlando", "bureau", "maine", "ideal", "specs", + "recorded", "pieces", "finished", "parks", "dinner", "lawyers", "sydney", "stress", + "cream", "trends", "discover", "patterns", "boxes", "hills", "fourth", "advisor", + "aware", "wilson", "shape", "irish", "stations", "remains", "greatest", "firms", + "operator", "generic", "usage", "charts", "mixed", "census", "exist", "wheel", + "transit", "compact", "poetry", "lights", "tracking", "angel", "keeping", "attempt", + "matches", "width", "noise", "engines", "forget", "array", "accurate", "stephen", + "climate", "alcohol", "greek", "managing", "sister", "walking", "explain", "smaller", + "newest", "happened", "extent", "sharp", "lesbians", "export", "managers", "aircraft", + "modules", "sweden", "conflict", "versions", "employer", "occur", "knows", "describe", + "concern", "backup", "citizens", "heritage", "holding", "trouble", "spread", "coach", + "kevin", "expand", "audience", "assigned", "jordan", "affect", "virgin", "raised", + "directed", "dealers", "sporting", "helping", "affected", "totally", "plate", "expenses", + "indicate", "blonde", "anderson", "organic", "albums", "cheats", "guests", "hosted", + "diseases", "nevada", "thailand", "agenda", "anyway", "tracks", "advisory", "logic", + "template", "prince", "circle", "grants", "anywhere", "atlantic", "edward", "investor", + "leaving", "wildlife", "cooking", "speaking", "sponsors", "respond", "sizes", "plain", + "entered", "launch", "checking", "costa", "belgium", "guidance", "trail", "symbol", + "crafts", "highway", "buddy", "observed", "setup", "booking", "glossary", "fiscal", + "styles", "denver", "filled", "channels", "ericsson", "appendix", "notify", "blues", + "portion", "scope", "supplier", "cables", "cotton", "biology", "dental", "killed", + "border", "ancient", "debate", "starts", "causes", "arkansas", "leisure", "learned", + "notebook", "explorer", "historic", "attached", "opened", "husband", "disabled", "crazy", + "upcoming", "britain", "concert", "scores", "comedy", "adopted", "weblog", "linear", + "bears", "carrier", "edited", "constant", "mouth", "jewish", "meter", "linked", + "portland", "concepts", "reflect", "deliver", "wonder", "lessons", "fruit", "begins", + "reform", "alerts", "treated", "mysql", "relating", "assume", "alliance", "confirm", + "neither", "lewis", "howard", "offline", "leaves", "engineer", "replace", "checks", + "reached", "becoming", "safari", "sugar", "stick", "allen", "relation", "enabled", + "genre", "slide", "montana", "tested", "enhance", "exact", "bound", "adapter", + "formal", "hockey", "storm", "micro", "colleges", "laptops", "showed", "editors", + "threads", "supreme", "brothers", "presents", "dolls", "estimate", "cancel", "limits", + "weapons", "paint", "delay", "pilot", "outlet", "czech", "novel", "ultra", + "winner", "idaho", "episode", "potter", "plays", "bulletin", "modify", "oxford", + "truly", "epinions", "painting", "universe", "patent", "eating", "planned", "watching", + "lodge", "mirror", "sterling", "sessions", "kernel", "stocks", "buyers", "journals", + "jennifer", "antonio", "charged", "broad", "taiwan", "chosen", "greece", "swiss", + "sarah", "clark", "terminal", "nights", "behalf", "liquid", "nebraska", "salary", + "foods", "gourmet", "guard", "properly", "orleans", "saving", "empire", "resume", + "twenty", "newly", "raise", "prepare", "avatar", "illegal", "hundreds", "lincoln", + "helped", "premier", "tomorrow", "decide", "consent", "drama", "visiting", "downtown", + "keyboard", "contest", "bands", "suitable", "millions", "lunch", "audit", "chamber", + "guinea", "findings", "muscle", "clicking", "polls", "typical", "tower", "yours", + "chicken", "attend", "shower", "sending", "jason", "tonight", "holdem", "shell", + "province", "catholic", "governor", "seemed", "swimming", "spyware", "formula", "solar", + "catch", "pakistan", "reliable", "doubt", "finder", "unable", "periods", "tasks", + "attacks", "const", "doors", "symptoms", "resorts", "biggest", "memorial", "visitor", + "forth", "insert", "gateway", "alumni", "drawing", "ordered", "fighting", "happens", + "romance", "bruce", "split", "themes", "powers", "heaven", "pregnant", "twice", + "focused", "egypt", "bargain", "cellular", "norway", "vermont", "asking", "blocks", + "normally", "hunting", "diabetes", "shift", "bodies", "cutting", "simon", "writers", + "marks", "flexible", "loved", "mapping", "numerous", "birds", "indexed", "superior", + "saved", "paying", "cartoon", "shots", "moore", "granted", "choices", "carbon", + "spending", "magnetic", "registry", "crisis", "outlook", "massive", "denmark", "employed", + "bright", "treat", "header", "poverty", "formed", "piano", "sheets", "patrick", + "puerto", "displays", "plasma", "allowing", "earnings", "mystery", "journey", "delaware", + "bidding", "risks", "banner", "charter", "barbara", "counties", "ports", "dreams", + "blogger", "stands", "teach", "occurred", "rapid", "hairy", "reverse", "deposit", + "seminar", "latina", "wheels", "specify", "dutch", "formats", "depends", "boots", + "holds", "router", "concrete", "editing", "poland", "folder", "womens", "upload", + "pulse", "voting", "courts", "notices", "detroit", "metro", "toshiba", "strip", + "pearl", "accident", "resident", "possibly", "airline", "regard", "exists", "smooth", + "strike", "flashing", "narrow", "threat", "surveys", "sitting", "putting", "vietnam", + "trailer", "castle", "gardens", "missed", "malaysia", "antique", "labels", "willing", + "acting", "heads", "stored", "logos", "antiques", "density", "hundred", "strange", + "mention", "parallel", "honda", "amended", "operate", "bills", "bathroom", "stable", + "opera", "doctors", "lesson", "cinema", "asset", "drinking", "reaction", "blank", + "enhanced", "entitled", "severe", "generate", "deluxe", "humor", "monitors", "lived", + "duration", "pursuant", "fabric", "visits", "tight", "domains", "contrast", "flying", + "berlin", "siemens", "adoption", "meant", "capture", "pounds", "buffalo", "plane", + "desire", "camping", "meets", "welfare", "caught", "marked", "driven", "measured", + "medline", "bottle", "marshall", "massage", "rubber", "closing", "tampa", "thousand", + "legend", "grace", "susan", "adams", "python", "monster", "villa", "columns", + "hamilton", "cookies", "inner", "tutorial", "entity", "cruises", "holder", "portugal", + "lawrence", "roman", "duties", "valuable", "ethics", "forever", "dragon", "captain", + "imagine", "brings", "heating", "scripts", "stereo", "taste", "dealing", "commit", + "airlines", "liberal", "livecam", "trips", "sides", "turns", "cache", "jacket", + "oracle", "matthew", "lease", "aviation", "hobbies", "proud", "excess", "disaster", + "console", "commands", "giant", "achieved", "injuries", "shipped", "seats", "alarm", + "voltage", "anthony", "nintendo", "usual", "loading", "stamps", "appeared", "franklin", + "angle", "vinyl", "mining", "ongoing", "worst", "imaging", "betting", "liberty", + "wyoming", "convert", "analyst", "garage", "exciting", "thongs", "ringtone", "finland", + "morgan", "derived", "pleasure", "honor", "oriented", "eagle", "desktops", "pants", + "columbus", "nurse", "prayer", "quiet", "postage", "producer", "cheese", "comic", + "crown", "maker", "crack", "picks", "semester", "fetish", "applies", "casinos", + "smoke", "apache", "filters", "craft", "apart", "fellow", "blind", "lounge", + "coins", "gross", "strongly", "hilton", "proteins", "horror", "familiar", "capable", + "douglas", "debian", "epson", "elected", "carrying", "victory", "madison", "editions", + "mainly", "ethnic", "actor", "finds", "fifth", "citizen", "vertical", "prize", + "occurs", "absolute", "consists", "anytime", "soldiers", "guardian", "lecture", "layout", + "classics", "horses", "dirty", "wayne", "donate", "taught", "worker", "alive", + "temple", "prove", "wings", "breaks", "genetic", "waters", "promise", "prefer", + "ridge", "cabinet", "modem", "harris", "bringing", "evaluate", "tiffany", "tropical", + "collect", "toyota", "streets", "vector", "shaved", "turning", "buffer", "purple", + "larry", "mutual", "pipeline", "syntax", "prison", "skill", "chairs", "everyday", + "moves", "inquiry", "ethernet", "checked", "exhibit", "throw", "trend", "sierra", + "visible", "desert", "oldest", "rhode", "mercury", "steven", "handbook", "navigate", + "worse", "summit", "victims", "spaces", "burning", "escape", "coupons", "somewhat", + "receiver", "cialis", "boats", "glance", "scottish", "arcade", "richmond", "russell", + "tells", "obvious", "fiber", "graph", "covering", "platinum", "judgment", "bedrooms", + "talks", "filing", "foster", "modeling", "passing", "awarded", "trials", "tissue", + "clinton", "masters", "bonds", "alberta", "commons", "fraud", "spectrum", "arrival", + "pottery", "emphasis", "roger", "aspect", "awesome", "mexican", "counts", "priced", + "crash", "desired", "inter", "closer", "assumes", "heights", "shadow", "riding", + "firefox", "expense", "grove", "venture", "clinic", "korean", "healing", "princess", + "entering", "packet", "spray", "studios", "buttons", "funded", "thompson", "winners", + "extend", "roads", "dublin", "rolling", "memories", "nelson", "arrived", "creates", + "faces", "tourist", "mayor", "murder", "adequate", "senator", "yield", "grades", + "cartoons", "digest", "lodging", "hence", "entirely", "replaced", "radar", "rescue", + "losses", "combat", "reducing", "stopped", "lakes", "closely", "diary", "kings", + "shooting", "flags", "baker", "launched", "shock", "walls", "abroad", "ebony", + "drawn", "arthur", "visited", "walker", "suggests", "beast", "operated", "targets", + "overseas", "dodge", "counsel", "pizza", "invited", "yards", "gordon", "farmers", + "queries", "ukraine", "absence", "nearest", "cluster", "vendors", "whereas", "serves", + "woods", "surprise", "partial", "shoppers", "couples", "ranking", "jokes", "simpson", + "twiki", "sublime", "palace", "verify", "globe", "trusted", "copper", "dicke", + "kerry", "receipt", "supposed", "ordinary", "nobody", "ghost", "applying", "pride", + "knowing", "reporter", "keith", "champion", "cloudy", "linda", "chile", "plenty", + "sentence", "throat", "ignore", "maria", "uniform", "wealth", "vacuum", "dancing", + "brass", "writes", "plaza", "outcomes", "survival", "quest", "publish", "trans", + "jonathan", "whenever", "lifetime", "pioneer", "booty", "acrobat", "plates", "acres", + "venue", "athletic", "thermal", "essays", "vital", "telling", "fairly", "coastal", + "config", "charity", "excel", "modes", "campbell", "stupid", "harbor", "hungary", + "traveler", "segment", "realize", "enemy", "puzzle", "rising", "aluminum", "wells", + "wishlist", "opens", "insight", "secrets", "lucky", "latter", "thick", "trailers", + "repeat", "syndrome", "philips", "penalty", "glasses", "enables", "iraqi", "builder", + "vista", "jessica", "chips", "terry", "flood", "arena", "pupils", "stewart", + "outcome", "expanded", "casual", "grown", "polish", "lovely", "extras", "centres", + "jerry", "clause", "smile", "lands", "troops", "indoor", "bulgaria", "armed", + "broker", "charger", "believed", "cooling", "trucks", "divorce", "laura", "shopper", + "tokyo", "partly", "nikon", "candy", "pills", "tiger", "donald", "folks", + "sensor", "exposed", "telecom", "angels", "deputy", "sealed", "loaded", "scenes", + "boost", "spanking", "founded", "chronic", "icons", "moral", "catering", "finger", + "keeps", "pound", "locate", "trained", "roses", "bread", "tobacco", "wooden", + "motors", "tough", "roberts", "incident", "gonna", "dynamics", "decrease", "chest", + "pension", "billy", "revenues", "emerging", "worship", "craig", "herself", "churches", + "damages", "reserves", "solve", "shorts", "minority", "diverse", "johnny", "recorder", + "facing", "nancy", "tones", "passion", "sight", "defence", "patches", "refund", + "towns", "trembl", "divided", "emails", "cyprus", "insider", "seminars", "makers", + "hearts", "worry", "carter", "legacy", "pleased", "danger", "vitamin", "widely", + "phrase", "genuine", "raising", "paradise", "hybrid", "reads", "roles", "glory", + "bigger", "billing", "diesel", "versus", "combine", "exceed", "saudi", "fault", + "babies", "karen", "compiled", "romantic", "revealed", "albert", "examine", "jimmy", + "graham", "bristol", "margaret", "compaq", "slowly", "rugby", "portions", "infant", + "sectors", "samuel", "fluid", "grounds", "regards", "unlike", "equation", "baskets", + "wright", "barry", "proven", "cached", "warren", "studied", "reviewer", "involves", + "profits", "devil", "grass", "comply", "marie", "florist", "cherry", "deutsch", + "kenya", "webcam", "funeral", "nutten", "earrings", "enjoyed", "chapters", "charlie", + "quebec", "dennis", "francis", "sized", "manga", "noticed", "socket", "silent", + "literary", "signals", "theft", "swing", "symbols", "humans", "analog", "facial", + "choosing", "talent", "dated", "seeker", "wisdom", "shoot", "boundary", "packard", + "offset", "payday", "philip", "elite", "holders", "believes", "swedish", "poems", + "deadline", "robot", "witness", "collins", "equipped", "stages", "winds", "powder", + "broadway", "acquired", "assess", "stones", "entrance", "gnome", "roots", "losing", + "attempts", "gadgets", "noble", "glasgow", "impacts", "gospel", "shore", "loves", + "induced", "knight", "loose", "linking", "appeals", "earned", "illness", "islamic", + "pending", "parker", "lebanon", "kennedy", "teenage", "triple", "cooper", "vincent", + "secured", "unusual", "answered", "slots", "disorder", "routine", "toolbar", "rocks", + "titans", "wearing", "sought", "genes", "mounted", "habitat", "firewall", "median", + "scanner", "herein", "animated", "judicial", "integer", "bachelor", "attitude", "engaged", + "falling", "basics", "montreal", "carpet", "struct", "lenses", "binary", "genetics", + "attended", "dropped", "walter", "besides", "hosts", "moments", "atlas", "strings", + "feels", "torture", "deleted", "mitchell", "ralph", "warner", "embedded", "inkjet", + "wizard", "corps", "actors", "liver", "liable", "brochure", "morris", "petition", + "eminem", "recall", "antenna", "picked", "assumed", "belief", "killing", "bikini", + "memphis", "shoulder", "decor", "lookup", "texts", "harvard", "brokers", "diameter", + "ottawa", "podcast", "seasons", "refine", "bidder", "singer", "evans", "herald", + "literacy", "fails", "aging", "plugin", "diving", "invite", "alice", "latinas", + "suppose", "involve", "moderate", "terror", "younger", "thirty", "opposite", "rapidly", + "dealtime", "intro", "mercedes", "clerk", "mills", "outline", "tramadol", "holland", + "receives", "jeans", "fonts", "refers", "favor", "veterans", "sigma", "xhtml", + "occasion", "victim", "demands", "sleeping", "careful", "arrive", "sunset", "tracked", + "moreover", "minimal", "lottery", "framed", "aside", "licence", "michelle", "essay", + "dialogue", "camps", "declared", "aaron", "handheld", "trace", "disposal", "florists", + "packs", "switches", "romania", "consult", "greatly", "blogging", "cycling", "midnight", + "commonly", "inform", "turkish", "pentium", "quantum", "murray", "intent", "largely", + "pleasant", "announce", "spoke", "arrow", "sampling", "rough", "weird", "inspired", + "holes", "weddings", "blade", "suddenly", "oxygen", "cookie", "meals", "canyon", + "meters", "merely", "passes", "pointer", "stretch", "durham", "permits", "muslim", + "sleeve", "netscape", "cleaner", "cricket", "feeding", "stroke", "township", "rankings", + "robin", "robinson", "strap", "sharon", "crowd", "olympic", "remained", "entities", + "customs", "rainbow", "roulette", "decline", "gloves", "israeli", "medicare", "skiing", + "cloud", "valve", "hewlett", "explains", "proceed", "flickr", "feelings", "knife", + "jamaica", "shelf", "timing", "liked", "adopt", "denied", "fotos", "britney", + "freeware", "donation", "outer", "deaths", "rivers", "tales", "katrina", "islam", + "nodes", "thumbs", "seeds", "cited", "targeted", "skype", "realized", "twelve", + "founder", "decade", "gamecube", "dispute", "tired", "titten", "adverse", "excerpt", + "steam", "drinks", "voices", "acute", "climbing", "stood", "perfume", "carol", + "honest", "albany", "restore", "stack", "somebody", "curve", "creator", "amber", + "museums", "coding", "tracker", "passage", "trunk", "hiking", "pierre", "jelsoft", + "headset", "oakland", "colombia", "waves", "camel", "lamps", "suicide", "archived", + "arabia", "juice", "chase", "logical", "sauce", "extract", "panama", "payable", + "courtesy", "athens", "judges", "retired", "remarks", "detected", "decades", "walked", + "arising", "nissan", "bracelet", "juvenile", "afraid", "acoustic", "railway", "cassette", + "pointed", "causing", "mistake", "norton", "locked", "fusion", "mineral", "steering", + "beads", "fortune", "canvas", "parish", "claimed", "screens", "cemetery", "planner", + "croatia", "flows", "stadium", "fewer", "coupon", "nurses", "proxy", "lanka", + "edwards", "contests", "costume", "tagged", "berkeley", "voted", "killer", "bikes", + "gates", "adjusted", "bishop", "pulled", "shaped", "seasonal", "farmer", "counters", + "slave", "cultures", "norfolk", "coaching", "examined", "encoding", "heroes", "painted", + "lycos", "zdnet", "artwork", "cosmetic", "resulted", "portrait", "ethical", "carriers", + "mobility", "floral", "builders", "struggle", "schemes", "neutral", "fisher", "spears", + "bedding", "joining", "heading", "equally", "bearing", "combo", "seniors", "worlds", + "guilty", "haven", "tablet", "charm", "violent", "basin", "ranch", "crossing", + "cottage", "drunk", "crimes", "resolved", "mozilla", "toner", "latex", "branches", + "anymore", "delhi", "holdings", "alien", "locator", "broke", "nepal", "zimbabwe", + "browsing", "resolve", "melissa", "moscow", "thesis", "nylon", "discs", "rocky", + "bargains", "frequent", "nigeria", "ceiling", "pixels", "ensuring", "hispanic", "anybody", + "diamonds", "fleet", "untitled", "bunch", "totals", "marriott", "singing", "afford", + "starring", "referral", "optimal", "distinct", "turner", "sucking", "cents", "reuters", + "spoken", "omega", "stayed", "civic", "manuals", "watched", "saver", "thereof", + "grill", "redeem", "rogers", "grain", "regime", "wanna", "wishes", "depend", + "differ", "ranging", "monica", "repairs", "breath", "candle", "hanging", "colored", + "verified", "formerly", "situated", "seeks", "herbal", "loving", "strictly", "routing", + "stanley", "retailer", "vitamins", "elegant", "gains", "renewal", "opposed", "deemed", + "scoring", "brooklyn", "sisters", "critics", "spots", "hacker", "madrid", "margin", + "solely", "salon", "norman", "turbo", "headed", "voters", "madonna", "murphy", + "thinks", "thats", "soldier", "phillips", "aimed", "justin", "interval", "mirrors", + "tricks", "reset", "brush", "expansys", "panels", "repeated", "assault", "spare", + "kodak", "tongue", "bowling", "danish", "monkey", "filename", "skirt", "florence", + "invest", "honey", "analyzes", "drawings", "scenario", "lovers", "atomic", "approx", + "arabic", "gauge", "junction", "faced", "rachel", "solving", "weekends", "produces", + "chains", "kingston", "sixth", "engage", "deviant", "quoted", "adapters", "farms", + "imports", "cheat", "bronze", "sandy", "suspect", "macro", "sender", "crucial", + "adjacent", "tuition", "spouse", "exotic", "viewer", "signup", "threats", "puzzles", + "reaching", "damaged", "receptor", "laugh", "surgical", "destroy", "citation", "pitch", + "autos", "premises", "perry", "proved", "imperial", "dozen", "benjamin", "teeth", + "cloth", "studying", "stamp", "lotus", "salmon", "olympus", "cargo", "salem", + "starter", "upgrades", "likes", "butter", "pepper", "weapon", "luggage", "burden", + "tapes", "zones", "races", "stylish", "maple", "grocery", "offshore", "depot", + "kenneth", "blend", "harrison", "julie", "emission", "finest", "realty", "janet", + "apparent", "phpbb", "autumn", "probe", "toilet", "ranked", "jackets", "routes", + "packed", "excited", "outreach", "helen", "mounting", "recover", "lopez", "balanced", + "timely", "talked", "debug", "delayed", "chuck", "explicit", "villas", "ebook", + "exclude", "peeing", "brooks", "newton", "anxiety", "bingo", "whilst", "spatial", + "ceramic", "prompt", "precious", "minds", "annually", "scanners", "xanax", "fingers", + "sunny", "ebooks", "delivers", "necklace", "leeds", "cedar", "arranged", "theaters", + "advocacy", "raleigh", "threaded", "qualify", "blair", "hopes", "mason", "diagram", + "burns", "pumps", "footwear", "beijing", "peoples", "victor", "mario", "attach", + "licenses", "utils", "removing", "advised", "spider", "ranges", "pairs", "trails", + "hudson", "isolated", "calgary", "interim", "assisted", "divine", "approve", "chose", + "compound", "abortion", "dialog", "venues", "blast", "wellness", "calcium", "newport", + "indians", "shield", "harvest", "membrane", "prague", "previews", "locally", "pickup", + "mothers", "nascar", "iceland", "candles", "sailing", "sacred", "morocco", "chrome", + "tommy", "refused", "brake", "exterior", "greeting", "ecology", "oliver", "congo", + "botswana", "delays", "olive", "cyber", "verizon", "scored", "clone", "velocity", + "lambda", "relay", "composed", "tears", "oasis", "baseline", "angry", "silicon", + "compete", "lover", "belong", "honolulu", "beatles", "rolls", "thomson", "barnes", + "malta", "daddy", "ferry", "rabbit", "seating", "exports", "omaha", "electron", + "loads", "heather", "passport", "motel", "unions", "treasury", "warrant", "solaris", + "frozen", "occupied", "royalty", "scales", "rally", "observer", "sunshine", "strain", + "ceremony", "somehow", "arrested", "yamaha", "hebrew", "gained", "dying", "laundry", + "stuck", "solomon", "placing", "stops", "homework", "adjust", "assessed", "enabling", + "filling", "imposed", "silence", "focuses", "soviet", "treaty", "vocal", "trainer", + "organ", "stronger", "volumes", "advances", "lemon", "toxic", "darkness", "bizrate", + "vienna", "implied", "stanford", "packing", "statute", "rejected", "satisfy", "shelter", + "chapel", "gamespot", "layers", "guided", "bahamas", "powell", "mixture", "bench", + "rider", "radius", "logging", "hampton", "borders", "butts", "bobby", "sheep", + "railroad", "lectures", "wines", "nursery", "harder", "cheapest", "travesti", "stuart", + "salvador", "salad", "monroe", "tender", "paste", "clouds", "tanzania", "preserve", + "unsigned", "staying", "easter", "theories", "praise", "jeremy", "venice", "estonia", + "veteran", "streams", "landing", "signing", "executed", "katie", "showcase", "integral", + "relax", "namibia", "synopsis", "hardly", "prairie", "reunion", "composer", "sword", + "absent", "sells", "ecuador", "hoping", "accessed", "spirits", "coral", "pixel", + "float", "colin", "imported", "paths", "bubble", "acquire", "contrary", "tribune", + "vessel", "acids", "focusing", "viruses", "cheaper", "admitted", "dairy", "admit", + "fancy", "equality", "samoa", "stickers", "leasing", "lauren", "beliefs", "squad", + "analyze", "ashley", "scroll", "relate", "wages", "suffer", "forests", "invalid", + "concerts", "martial", "males", "retain", "execute", "tunnel", "genres", "cambodia", + "patents", "chaos", "wheat", "beaver", "updating", "readings", "kijiji", "confused", + "compiler", "eagles", "bases", "accused", "unity", "bride", "defines", "airports", + "begun", "brunette", "packets", "anchor", "socks", "parade", "trigger", "gathered", + "essex", "slovenia", "notified", "beaches", "folders", "dramatic", "surfaces", "terrible", + "routers", "pendant", "dresses", "baptist", "hiring", "clocks", "females", "wallace", + "reflects", "taxation", "fever", "cuisine", "surely", "myspace", "theorem", "stylus", + "drums", "arnold", "chicks", "cattle", "radical", "rover", "treasure", "reload", + "flame", "levitra", "tanks", "assuming", "monetary", "elderly", "floating", "bolivia", + "spell", "hottest", "stevens", "kuwait", "emily", "alleged", "compile", "webster", + "struck", "plymouth", "warnings", "bridal", "annex", "tribal", "curious", "freight", + "rebate", "meetup", "eclipse", "sudan", "shuttle", "stunning", "cycles", "affects", + "detect", "actively", "ampland", "fastest", "butler", "injured", "payroll", "cookbook", + "courier", "uploaded", "hints", "collapse", "americas", "unlikely", "techno", "beverage", + "tribute", "wired", "elvis", "immune", "latvia", "forestry", "barriers", "rarely", + "infected", "martha", "genesis", "barrier", "argue", "trains", "metals", "bicycle", + "letting", "arise", "celtic", "thereby", "jamie", "particle", "minerals", "advise", + "humidity", "bottles", "boxing", "bangkok", "hughes", "jeffrey", "chess", "operates", + "brisbane", "survive", "oscar", "menus", "reveal", "canal", "amino", "herbs", + "clinics", "manitoba", "missions", "watson", "lying", "costumes", "strict", "saddam", + "drill", "offense", "bryan", "protest", "hobby", "tries", "nickname", "inline", + "washing", "staffing", "trick", "enquiry", "closure", "timber", "intense", "playlist", + "showers", "ruling", "steady", "statutes", "myers", "drops", "wider", "plugins", + "enrolled", "sensors", "screw", "publicly", "hourly", "blame", "geneva", "freebsd", + "reseller", "handed", "suffered", "intake", "informal", "tucson", "heavily", "swingers", + "fifty", "headers", "mistakes", "uncle", "defining", "counting", "assure", "devoted", + "jacob", "sodium", "randy", "hormone", "timothy", "brick", "naval", "medieval", + "bridges", "captured", "thehun", "decent", "casting", "dayton", "shortly", "cameron", + "carlos", "donna", "andreas", "warrior", "diploma", "cabin", "innocent", "scanning", + "valium", "copying", "cordless", "patricia", "eddie", "uganda", "fired", "trivia", + "adidas", "perth", "grammar", "syria", "disagree", "klein", "harvey", "tires", + "hazard", "retro", "gregory", "episodes", "boolean", "circular", "anger", "mainland", + "suits", "chances", "interact", "bizarre", "glenn", "auckland", "olympics", "fruits", + "ribbon", "startup", "suzuki", "trinidad", "kissing", "handy", "exempt", "crops", + "reduces", "geometry", "slovakia", "guild", "gorgeous", "capitol", "dishes", "barbados", + "chrysler", "nervous", "refuse", "extends", "mcdonald", "replica", "plumbing", "brussels", + "tribe", "trades", "superb", "trinity", "handled", "legends", "floors", "exhaust", + "shanghai", "speaks", "burton", "davidson", "copied", "scotia", "farming", "gibson", + "roller", "batch", "organize", "alter", "nicole", "latino", "ghana", "edges", + "mixing", "handles", "skilled", "fitted", "harmony", "asthma", "twins", "triangle", + "amend", "oriental", "reward", "windsor", "zambia", "hydrogen", "webshots", "sprint", + "chick", "advocate", "inputs", "genome", "escorts", "thong", "medal", "coaches", + "vessels", "walks", "knives", "arrange", "artistic", "honors", "booth", "indie", + "unified", "bones", "breed", "detector", "ignored", "polar", "fallen", "precise", + "sussex", "msgid", "invoice", "gather", "backed", "alfred", "colonial", "carey", + "motels", "forming", "embassy", "danny", "rebecca", "slight", "proceeds", "indirect", + "amongst", "msgstr", "arrest", "adipex", "horizon", "deeply", "toolbox", "marina", + "prizes", "bosnia", "browsers", "patio", "surfing", "lloyd", "optics", "pursue", + "overcome", "attract", "brighton", "beans", "ellis", "disable", "snake", "succeed", + "leonard", "lending", "reminder", "searched", "plains", "raymond", "insights", "sullivan", + "midwest", "karaoke", "lonely", "hereby", "observe", "julia", "berry", "collar", + "racial", "bermuda", "amanda", "mobiles", "kelkoo", "exhibits", "terrace", "bacteria", + "replied", "seafood", "novels", "ought", "safely", "finite", "kidney", "fixes", + "sends", "durable", "mazda", "allied", "throws", "moisture", "roster", "symantec", + "spencer", "wichita", "nasdaq", "uruguay", "timer", "tablets", "tuning", "gotten", + "tyler", "futures", "verse", "highs", "wanting", "custody", "scratch", "launches", + "ellen", "rocket", "bullet", "towers", "racks", "nasty", "latitude", "tumor", + "deposits", "beverly", "mistress", "trustees", "watts", "duncan", "reprints", "bernard", + "forty", "tubes", "midlands", "priest", "floyd", "ronald", "analysts", "queue", + "trance", "locale", "nicholas", "bundle", "hammer", "invasion", "runner", "notion", + "skins", "mailed", "fujitsu", "spelling", "arctic", "exams", "rewards", "beneath", + "defend", "medicaid", "infrared", "seventh", "welsh", "belly", "quarters", "stolen", + "soonest", "haiti", "naturals", "lenders", "fitting", "fixtures", "bloggers", "agrees", + "surplus", "elder", "sonic", "cheers", "belarus", "zoning", "gravity", "thumb", + "guitars", "essence", "flooring", "ethiopia", "mighty", "athletes", "humanity", "holmes", + "scholars", "galaxy", "chester", "snapshot", "caring", "segments", "dominant", "twist", + "itunes", "stomach", "buried", "newbie", "minimize", "darwin", "ranks", "debut", + "bradley", "anatomy", "fraction", "defects", "milton", "marker", "clarity", "sandra", + "adelaide", "monaco", "settled", "folding", "emirates", "airfare", "vaccine", "belize", + "promised", "volvo", "penny", "robust", "bookings", "minolta", "porter", "jungle", + "ivory", "alpine", "andale", "fabulous", "remix", "alias", "newer", "spice", + "implies", "cooler", "maritime", "periodic", "overhead", "ascii", "prospect", "shipment", + "breeding", "donor", "tension", "trash", "shapes", "manor", "envelope", "diane", + "homeland", "excluded", "andrea", "breeds", "rapids", "disco", "bailey", "endif", + "emotions", "incoming", "lexmark", "cleaners", "eternal", "cashiers", "rotation", "eugene", + "metric", "minus", "bennett", "hotmail", "joshua", "armenia", "varied", "grande", + "closest", "actress", "assign", "tigers", "aurora", "slides", "milan", "premiere", + "lender", "villages", "shade", "chorus", "rhythm", "digit", "argued", "dietary", + "symphony", "clarke", "sudden", "marilyn", "lions", "findlaw", "pools", "lyric", + "claire", "speeds", "matched", "carroll", "rational", "fighters", "chambers", "warming", + "vocals", "fountain", "chubby", "grave", "burner", "finnish", "gentle", "deeper", + "muslims", "footage", "howto", "worthy", "reveals", "saints", "carries", "devon", + "helena", "saves", "regarded", "marion", "lobby", "egyptian", "tunisia", "outlined", + "headline", "treating", "punch", "gotta", "cowboy", "bahrain", "enormous", "karma", + "consist", "betty", "queens", "lucas", "tribes", "defeat", "clicks", "honduras", + "naughty", "hazards", "insured", "harper", "mardi", "tenant", "cabinets", "tattoo", + "shake", "algebra", "shadows", "holly", "silly", "mercy", "hartford", "freely", + "marcus", "sunrise", "wrapping", "weblogs", "timeline", "belongs", "readily", "fence", + "nudist", "infinite", "diana", "ensures", "lindsay", "legally", "shame", "civilian", + "fatal", "remedy", "realtors", "briefly", "genius", "fighter", "flesh", "retreat", + "adapted", "barely", "wherever", "estates", "democrat", "borough", "failing", "retained", + "pamela", "andrews", "marble", "jesse", "logitech", "surrey", "briefing", "belkin", + "highland", "modular", "brandon", "giants", "balloon", "winston", "solved", "hawaiian", + "gratuit", "consoles", "qatar", "magnet", "porsche", "cayman", "jaguar", "sheer", + "posing", "hopkins", "urgent", "infants", "gothic", "cylinder", "witch", "cohen", + "puppy", "kathy", "graphs", "surround", "revenge", "expires", "enemies", "finances", + "accepts", "enjoying", "patrol", "smell", "italiano", "carnival", "roughly", "sticker", + "promises", "divide", "cornell", "satin", "deserve", "mailto", "promo", "worried", + "tunes", "garbage", "combines", "bradford", "phrases", "chelsea", "boring", "reynolds", + "speeches", "reaches", "schema", "catalogs", "quizzes", "prefix", "lucia", "savannah", + "barrel", "typing", "nerve", "planets", "deficit", "boulder", "pointing", "renew", + "coupled", "myanmar", "metadata", "harold", "circuits", "floppy", "texture", "handbags", + "somerset", "incurred", "antigua", "thunder", "caution", "locks", "namely", "euros", + "pirates", "aerial", "rebel", "origins", "hired", "makeup", "textile", "nathan", + "tobago", "indexes", "hindu", "licking", "markers", "weights", "albania", "lasting", + "wicked", "kills", "roommate", "webcams", "pushed", "slope", "reggae", "failures", + "surname", "theology", "nails", "evident", "whats", "rides", "rehab", "saturn", + "allergy", "twisted", "merit", "enzyme", "zshops", "planes", "edmonton", "tackle", + "disks", "condo", "pokemon", "ambien", "retrieve", "vernon", "worldcat", "titanium", + "fairy", "builds", "shaft", "leslie", "casio", "deutsche", "postings", "kitty", + "drain", "monte", "fires", "algeria", "blessed", "cardiff", "cornwall", "favors", + "potato", "panic", "sticks", "leone", "excuse", "reforms", "basement", "onion", + "strand", "sandwich", "lawsuit", "cheque", "banners", "reject", "circles", "italic", + "beats", "merry", "scuba", "passive", "valued", "courage", "verde", "gazette", + "hitachi", "batman", "hearings", "coleman", "anaheim", "textbook", "dried", "luther", + "frontier", "settle", "stopping", "refugees", "knights", "palmer", "derby", "peaceful", + "altered", "pontiac", "doctrine", "scenic", "trainers", "sewing", "conclude", "munich", + "celebs", "propose", "lighter", "advisors", "pavilion", "tactics", "trusts", "talented", + "annie", "pillow", "derek", "shorter", "harley", "relying", "finals", "paraguay", + "steal", "parcel", "refined", "fifteen", "fears", "predict", "boutique", "acrylic", + "rolled", "tuner", "peterson", "shannon", "toddler", "flavor", "alike", "homeless", + "horrible", "hungry", "metallic", "blocked", "warriors", "cadillac", "malawi", "sagem", + "curtis", "parental", "strikes", "lesser", "marathon", "pressing", "gasoline", "dressed", + "scout", "belfast", "dealt", "niagara", "warcraft", "charms", "catalyst", "trader", + "bucks", "denial", "thrown", "prepaid", "raises", "electro", "badge", "wrist", + "analyzed", "heath", "ballot", "lexus", "varying", "remedies", "validity", "trustee", + "weighted", "angola", "performs", "plastics", "realm", "jenny", "helmet", "salaries", + "postcard", "elephant", "yemen", "tsunami", "scholar", "nickel", "buses", "expedia", + "geology", "coating", "wallet", "cleared", "smilies", "boating", "drainage", "shakira", + "corners", "broader", "rouge", "yeast", "clearing", "coated", "intend", "louise", + "kenny", "routines", "hitting", "yukon", "beings", "aquatic", "reliance", "habits", + "striking", "podcasts", "singh", "gilbert", "ferrari", "brook", "outputs", "ensemble", + "insulin", "assured", "biblical", "accent", "mysimon", "eleven", "wives", "ambient", + "utilize", "mileage", "prostate", "adaptor", "auburn", "unlock", "hyundai", "pledge", + "vampire", "angela", "relates", "nitrogen", "xerox", "merger", "softball", "firewire", + "nextel", "framing", "musician", "blocking", "rwanda", "sorts", "vsnet", "limiting", + "dispatch", "papua", "restored", "armor", "riders", "chargers", "remark", "dozens", + "varies", "rendered", "picking", "guards", "openings", "councils", "kruger", "pockets", + "granny", "viral", "inquire", "pipes", "laden", "aruba", "cottages", "realtor", + "merge", "edgar", "develops", "chassis", "dubai", "pushing", "fleece", "pierce", + "allan", "dressing", "sperm", "filme", "craps", "frost", "sally", "yacht", + "tracy", "prefers", "drilling", "breach", "whale", "tomatoes", "bedford", "mustang", + "clusters", "antibody", "momentum", "wiring", "pastor", "calvin", "shark", "phases", + "grateful", "emerald", "laughing", "grows", "cliff", "tract", "ballet", "abraham", + "bumper", "webpage", "garlic", "hostels", "shine", "senegal", "banned", "wendy", + "briefs", "diffs", "mumbai", "ozone", "radios", "tariff", "nvidia", "opponent", + "pasta", "muscles", "serum", "wrapped", "swift", "runtime", "inbox", "focal", + "distant", "decimal", "propecia", "samba", "hostel", "employ", "mongolia", "penguin", + "magical", "miracle", "manually", "reprint", "centered", "yearly", "wound", "belle", + "writings", "hamburg", "cindy", "fathers", "charging", "marvel", "lined", "petite", + "terrain", "strips", "gossip", "rangers", "rotary", "discrete", "beginner", "boxed", + "cubic", "sapphire", "kinase", "skirts", "crawford", "labeled", "marking", "serbia", + "sheriff", "griffin", "declined", "guyana", "spies", "neighbor", "elect", "highways", + "thinkpad", "intimate", "preston", "deadly", "bunny", "chevy", "rounds", "longest", + "tions", "dentists", "flyer", "dosage", "variance", "cameroon", "baking", "adaptive", + "computed", "needle", "baths", "brakes", "nirvana", "invision", "sticky", "destiny", + "generous", "madness", "emacs", "climb", "blowing", "heated", "jackie", "sparc", + "cardiac", "dover", "adrian", "vatican", "brutal", "learners", "token", "seekers", + "yields", "suited", "numeric", "skating", "kinda", "aberdeen", "emperor", "dylan", + "belts", "blacks", "educated", "rebates", "burke", "proudly", "inserted", "pulling", + "basename", "obesity", "curves", "suburban", "touring", "clara", "vertex", "tomato", + "andorra", "expired", "travels", "flush", "waiver", "hayes", "delight", "survivor", + "garcia", "cingular", "moses", "counted", "declare", "johns", "valves", "impaired", + "donors", "jewel", "teddy", "teaches", "ventures", "bufing", "stranger", "tragedy", + "julian", "dryer", "painful", "velvet", "tribunal", "ruled", "pensions", "prayers", + "funky", "nowhere", "joins", "wesley", "lately", "scary", "mattress", "mpegs", + "brunei", "likewise", "banana", "slovak", "cakes", "mixer", "remind", "sbjct", + "charming", "tooth", "annoying", "stays", "disclose", "affair", "drove", "washer", + "upset", "restrict", "springer", "beside", "mines", "rebound", "logan", "mentor", + "fought", "baghdad", "metres", "pencil", "freeze", "titled", "sphere", "ratios", + "concord", "endorsed", "walnut", "lance", "ladder", "italia", "liberia", "sherman", + "maximize", "hansen", "senators", "workout", "bleeding", "colon", "lanes", "purse", + "optimize", "stating", "caroline", "align", "bless", "engaging", "crest", "triumph", + "welding", "deferred", "alloy", "condos", "plots", "polished", "gently", "tulsa", + "locking", "casey", "draws", "fridge", "blanket", "bloom", "simpsons", "elliott", + "fraser", "justify", "blades", "loops", "surge", "trauma", "tahoe", "advert", + "possess", "flashers", "subaru", "vanilla", "picnic", "souls", "arrivals", "spank", + "hollow", "vault", "securely", "fioricet", "groove", "pursuit", "wires", "mails", + "backing", "sleeps", "blake", "travis", "endless", "figured", "orbit", "niger", + "bacon", "heater", "colony", "cannon", "circus", "promoted", "forbes", "moldova", + "paxil", "spine", "trout", "enclosed", "cooked", "thriller", "transmit", "apnic", + "fatty", "gerald", "pressed", "scanned", "hunger", "mariah", "joyce", "surgeon", + "cement", "planners", "disputes", "textiles", "missile", "intranet", "closes", "deborah", + "marco", "assists", "gabriel", "auditor", "aquarium", "violin", "prophet", "bracket", + "isaac", "oxide", "naples", "promptly", "modems", "harmful", "prozac", "sexually", + "dividend", "newark", "glucose", "phantom", "playback", "turtle", "warned", "neural", + "fossil", "hometown", "badly", "apollo", "persian", "handmade", "greene", "robots", + "grenada", "scoop", "earning", "mailman", "sanyo", "nested", "somalia", "movers", + "verbal", "blink", "carlo", "workflow", "novelty", "bryant", "tiles", "voyuer", + "switched", "tamil", "garmin", "fuzzy", "grams", "richards", "budgets", "toolkit", + "render", "carmen", "hardwood", "erotica", "temporal", "forge", "dense", "brave", + "awful", "airplane", "istanbul", "impose", "viewers", "asbestos", "meyer", "enters", + "savage", "willow", "resumes", "throwing", "existed", "wagon", "barbie", "knock", + "potatoes", "thorough", "peers", "roland", "optimum", "quilt", "creature", "mounts", + "syracuse", "refresh", "webcast", "michel", "subtle", "notre", "maldives", "stripes", + "firmware", "shepherd", "canberra", "cradle", "mambo", "flour", "sympathy", "choir", + "avoiding", "blond", "expects", "jumping", "fabrics", "polymer", "hygiene", "poultry", + "virtue", "burst", "surgeons", "bouquet", "promotes", "mandate", "wiley", "corpus", + "johnston", "fibre", "shades", "indices", "adware", "zoloft", "prisoner", "daisy", + "halifax", "ultram", "cursor", "earliest", "donated", "stuffed", "insects", "crude", + "morrison", "maiden", "examines", "viking", "myrtle", "bored", "cleanup", "bother", + "budapest", "knitting", "attacked", "bhutan", "mating", "compute", "redhead", "arrives", + "tractor", "allah", "unwrap", "fares", "resist", "hoped", "safer", "wagner", + "touched", "cologne", "wishing", "ranger", "smallest", "newman", "marsh", "ricky", + "scared", "theta", "monsters", "asylum", "lightbox", "robbie", "stake", "cocktail", + "outlets", "arbor", "poison"}; + +const char *P4Tools::P4Smith::Wordlist::getFromWordlist() { + if (counter < WORDLIST_LENGTH) { + counter++; + return WORDS.at(counter - 1); + } + return ""; +} + +} // namespace P4Tools::P4Smith diff --git a/backends/p4tools/modules/smith/util/wordlist.h b/backends/p4tools/modules/smith/util/wordlist.h new file mode 100644 index 0000000000..637cdb35cb --- /dev/null +++ b/backends/p4tools/modules/smith/util/wordlist.h @@ -0,0 +1,32 @@ +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_UTIL_WORDLIST_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_UTIL_WORDLIST_H_ +#include +#include + +#define WORDLIST_LENGTH 10000 + +namespace P4Tools::P4Smith { + +/// This class is a wrapper around an underlying array of words, which is currently being +/// used to aid random name generation. +class Wordlist { + public: + Wordlist() = default; + + ~Wordlist() = default; + + /// Pops and @returns the top-most(closest to the beginning of the array) non-popped + /// element from the array. + static const char *getFromWordlist(); + + private: + /// Stores the address of the next word to be popped of the words array + static std::size_t counter; + + /// The actual array storing the words. + static const std::array WORDS; +}; + +} // namespace P4Tools::P4Smith + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_UTIL_WORDLIST_H_ */ diff --git a/backends/p4tools/modules/smith/version.h.cmake b/backends/p4tools/modules/smith/version.h.cmake new file mode 100644 index 0000000000..3504ff6d49 --- /dev/null +++ b/backends/p4tools/modules/smith/version.h.cmake @@ -0,0 +1,39 @@ +/* +Copyright 2018-present Barefoot Networks, Inc. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may !use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#ifndef BACKENDS_P4TOOLS_MODULES_SMITH_VERSION_H_ +#define BACKENDS_P4TOOLS_MODULES_SMITH_VERSION_H_ + +/** + Set the compiler version at build time. + The build system defines P4C_VERSION as a full string as well as the + following components: P4C_VERSION_MAJOR, P4C_VERSION_MINOR, + P4C_VERSION_PATCH, P4C_VERSION_RC, and P4C_GIT_SHA. + + They can be used to construct a version string as follows: + #define VERSION_STRING "@P4C_VERSION@" + or + #define VERSION_STRING "@P4C_VERSION_MAJOR@.@P4C_VERSION_MINOR@.@P4C_VERSION_PATCH@@P4C_VERSION_RC@" + + Or, since this is backend specific, feel free to define other numbering + scheme. + + */ + +#define SMITH_VERSION_STRING "@P4C_VERSION@" + + +#endif /* BACKENDS_P4TOOLS_MODULES_SMITH_VERSION_H_ */ diff --git a/backends/p4tools/modules/testgen/README.md b/backends/p4tools/modules/testgen/README.md index 3bcb7fa7e6..6729e5fd45 100644 --- a/backends/p4tools/modules/testgen/README.md +++ b/backends/p4tools/modules/testgen/README.md @@ -34,6 +34,12 @@ P4Testgen depends on the P4Tools framework and is automatically installed with P P4Testgen is available as part of the [official P4C docker image](https://hub.docker.com/r/p4lang/p4c/). On Debian-based systems, it is also possible to install a P4Testgen binary by following [these](https://github.com/p4lang/p4c#installing-packaged-versions-of-p4c) instructions. +### Dependencies +In addition to [P4Tools'](../README.md#dependencies) own dependencies P4Testgen depends on the following external software: + * [inja](https://github.com/pantor/inja) template engine for testcase generation. + +These dependencies are automatically installed via CMakelist's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) module. + ## Extensions P4Testgen extensions are instantiations of a particular combination of P4 architecture and the target that executes the P4 code. For example, the `v1model.p4` architecture can be executed on the behavioral model. P4Testgen extension make use of the core P4Testgen framework to generate tests. Several open-source extensions are available. From 63595490f488963ce4c8074828c8314d5e03643c Mon Sep 17 00:00:00 2001 From: Nitish Kumar Date: Fri, 7 Jun 2024 20:41:50 +0530 Subject: [PATCH 4/5] Add a formatter binary skeleton as P4C back end (#4710) * init: p4 formatter Signed-off-by: Nitish * eliminate implicit char* -> cstring conversion in `P4fmtOptions` --------- Signed-off-by: Nitish --- CMakeLists.txt | 4 +++ backends/p4fmt/CMakeLists.txt | 14 ++++++++++ backends/p4fmt/README.md | 27 ++++++++++++++++++ backends/p4fmt/options.cpp | 17 ++++++++++++ backends/p4fmt/options.h | 29 +++++++++++++++++++ backends/p4fmt/p4fmt.cpp | 52 +++++++++++++++++++++++++++++++++++ 6 files changed, 143 insertions(+) create mode 100644 backends/p4fmt/CMakeLists.txt create mode 100644 backends/p4fmt/README.md create mode 100644 backends/p4fmt/options.cpp create mode 100644 backends/p4fmt/options.h create mode 100644 backends/p4fmt/p4fmt.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 02edc3d13a..cb848e2bab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -40,6 +40,7 @@ OPTION (ENABLE_EBPF "Build the EBPF backend (required for the full test suite)" OPTION (ENABLE_UBPF "Build the uBPF backend (required for the full test suite)" ON) OPTION (ENABLE_DPDK "Build the DPDK backend (required for the full test suite)" ON) OPTION (ENABLE_P4TC "Build the P4TC backend" ON) +OPTION (ENABLE_P4FMT "Build the P4FMT backend" ON) OPTION (ENABLE_P4TEST "Build the P4Test backend (required for the full test suite)" ON) OPTION (ENABLE_TEST_TOOLS "Build the P4Tools development platform" OFF) OPTION (ENABLE_P4C_GRAPHS "Build the p4c-graphs backend" ON) @@ -479,6 +480,9 @@ endif () if (ENABLE_TEST_TOOLS) add_subdirectory (backends/p4tools) endif () +if (ENABLE_P4FMT) + add_subdirectory (backends/p4fmt) +endif () if (ENABLE_UBPF) add_subdirectory (backends/ubpf) endif () diff --git a/backends/p4fmt/CMakeLists.txt b/backends/p4fmt/CMakeLists.txt new file mode 100644 index 0000000000..282c8b3549 --- /dev/null +++ b/backends/p4fmt/CMakeLists.txt @@ -0,0 +1,14 @@ +set(FMT_SRCS + p4fmt.cpp + options.cpp +) + +add_executable(p4fmt ${FMT_SRCS}) +target_link_libraries(p4fmt ${P4C_LIBRARIES} ${P4C_LIB_DEPS}) +add_dependencies(p4fmt frontend) + +add_custom_target(p4formatter + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4fmt ${P4C_BINARY_DIR}/p4fmt +) + +add_dependencies(p4c_driver p4formatter) diff --git a/backends/p4fmt/README.md b/backends/p4fmt/README.md new file mode 100644 index 0000000000..d4dc7da942 --- /dev/null +++ b/backends/p4fmt/README.md @@ -0,0 +1,27 @@ +# p4fmt (P4 Formatter) + +p4fmt is a WIP formatter for P4. It's in a highly experimental phase +and, not yet stable/reliable for general use. +Contributions and feedbacks from the community +would be highly appreciated. + +## Build +- Setup P4C correctly, from [here](https://github.com/p4lang/p4c#dependencies). + +- Follow the instructions here to [build](https://github.com/p4lang/p4c#installing-p4c-from-source). + +Later `p4fmt` executable can be found inside the `p4c/build/` dir, and can be invoked as `./build/p4fmt` from p4c's root dir. + +## Usage +- Takes an output file with a `-o` flag and writes to it. + + `./build/p4fmt -o ` + + - If an output file is not provided with `-o` flag, it just prints the output on the stdout. + + `./build/p4fmt ` + +Sample Usage: + + ./build/p4fmt/p4fmt sample.p4 + ./build/p4fmt/p4fmt sample.p4 -o out.p4 diff --git a/backends/p4fmt/options.cpp b/backends/p4fmt/options.cpp new file mode 100644 index 0000000000..5d250362be --- /dev/null +++ b/backends/p4fmt/options.cpp @@ -0,0 +1,17 @@ +#include "options.h" + +namespace P4Fmt { + +P4fmtOptions::P4fmtOptions() { + registerOption( + "-o", "outfile", + [this](const char *arg) { + outFile = cstring(arg); + return true; + }, + "Write formatted output to outfile"); +} + +const cstring &P4fmtOptions::outputFile() const { return outFile; } + +} // namespace P4Fmt diff --git a/backends/p4fmt/options.h b/backends/p4fmt/options.h new file mode 100644 index 0000000000..d6bd6e4a6f --- /dev/null +++ b/backends/p4fmt/options.h @@ -0,0 +1,29 @@ +#ifndef BACKENDS_P4FMT_OPTIONS_H_ +#define BACKENDS_P4FMT_OPTIONS_H_ + +#include "frontends/common/options.h" +#include "frontends/common/parser_options.h" + +namespace P4Fmt { + +class P4fmtOptions : public CompilerOptions { + public: + P4fmtOptions(); + virtual ~P4fmtOptions() = default; + P4fmtOptions(const P4fmtOptions &) = default; + P4fmtOptions(P4fmtOptions &&) = delete; + P4fmtOptions &operator=(const P4fmtOptions &) = default; + P4fmtOptions &operator=(P4fmtOptions &&) = delete; + + const cstring &outputFile() const; + + private: + /// File to output to. + cstring outFile = nullptr; +}; + +using P4FmtContext = P4CContextWithOptions; + +} // namespace P4Fmt + +#endif /* BACKENDS_P4FMT_OPTIONS_H_ */ diff --git a/backends/p4fmt/p4fmt.cpp b/backends/p4fmt/p4fmt.cpp new file mode 100644 index 0000000000..758d924a51 --- /dev/null +++ b/backends/p4fmt/p4fmt.cpp @@ -0,0 +1,52 @@ +#include + +#include "frontends/common/parseInput.h" +#include "frontends/common/parser_options.h" +#include "frontends/p4/toP4/toP4.h" +#include "ir/ir.h" +#include "lib/compile_context.h" +#include "lib/cstring.h" +#include "lib/error.h" +#include "lib/nullstream.h" +#include "options.h" +#include "test/gtest/helpers.h" + +int main(int argc, char *const argv[]) { + AutoCompileContext autoP4FmtContext(new P4Fmt::P4FmtContext); + auto &options = P4Fmt::P4FmtContext::get().options(); + + if (options.process(argc, argv) == nullptr) { + return EXIT_FAILURE; + } + + options.setInputFile(); + + std::ostream *out = nullptr; + + // Write to stdout in absence of an output file. + if (options.outputFile().isNullOrEmpty()) { + out = &std::cout; + } else { + out = openFile(options.outputFile(), false); + if (!(*out)) { + ::error(ErrorType::ERR_NOT_FOUND, "%2%: No such file or directory.", + options.outputFile()); + options.usage(); + return EXIT_FAILURE; + } + } + + const IR::P4Program *program = P4::parseP4File(options); + + if (program == nullptr && ::errorCount() != 0) { + return EXIT_FAILURE; + } + + auto top4 = P4::ToP4(out, false); + + *out << "\n############################## INITIAL ##############################\n"; + // Print the program before running front end passes. + program->apply(top4); + + return ::errorCount() > 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} From 7124b4ee2e046dea1fa0513aed0d6d8923fafd6a Mon Sep 17 00:00:00 2001 From: Anton Korobeynikov Date: Fri, 7 Jun 2024 18:16:43 -0700 Subject: [PATCH 5/5] Format-related string fixes and refactorings (#4704) * Use abseil StrFormat in SourceFile * Simplify source file: do not create cstrings for something transient * Switch to cord for source code builder * Switch to statically-checked format string printing. Uncovered and fixed few bugs here and there. * Switch from Utils::printf_format to abseil formatting. Overall cstring's are misused everywhere in this code. But this is a subject of different task. * Get rid of unsafe and error-prone printf_format * Add missed conversion behind #ifdef --- backends/ebpf/ebpfControl.cpp | 8 +- backends/ebpf/ebpfDeparser.cpp | 8 +- backends/ebpf/ebpfParser.cpp | 39 +++++----- backends/ebpf/ebpfTable.cpp | 38 +++++---- backends/ebpf/psa/ebpfPipeline.cpp | 45 +++++------ backends/ebpf/psa/ebpfPsaControl.cpp | 2 +- backends/ebpf/psa/ebpfPsaDeparser.cpp | 2 +- backends/ebpf/psa/ebpfPsaGen.h | 6 +- backends/ebpf/psa/ebpfPsaTable.cpp | 7 +- backends/ebpf/psa/externs/ebpfPsaCounter.cpp | 18 ++--- backends/ebpf/psa/externs/ebpfPsaDigest.cpp | 2 +- .../ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp | 4 +- backends/ebpf/psa/externs/ebpfPsaRegister.cpp | 11 ++- .../externs/ebpfPsaTableImplementation.cpp | 17 ++-- backends/ebpf/target.cpp | 9 ++- backends/tc/ebpfCodeGen.cpp | 77 +++++++++---------- frontends/p4/toP4/toP4.cpp | 4 +- ir/visitor.cpp | 2 +- lib/error_reporter.h | 2 + lib/sourceCodeBuilder.h | 37 +++++---- lib/source_file.cpp | 76 +++++++++--------- lib/source_file.h | 3 +- lib/stringify.cpp | 28 ------- lib/stringify.h | 4 - test/CMakeLists.txt | 1 - test/gtest/format_test.cpp | 3 - test/gtest/source_file_test.cpp | 4 +- test/gtest/stringify.cpp | 69 ----------------- 28 files changed, 208 insertions(+), 318 deletions(-) delete mode 100644 test/gtest/stringify.cpp diff --git a/backends/ebpf/ebpfControl.cpp b/backends/ebpf/ebpfControl.cpp index ad4563a8aa..8e4fdc3b85 100644 --- a/backends/ebpf/ebpfControl.cpp +++ b/backends/ebpf/ebpfControl.cpp @@ -143,7 +143,7 @@ bool ControlBodyTranslator::preorder(const IR::MethodCallExpression *expression) BUG_CHECK(expression->arguments->size() == 0, "%1%: unexpected arguments for action call", expression); cstring msg = - Util::printf_format("Control: explicit calling action %s()", ac->action->name.name); + absl::StrFormat("Control: explicit calling action %s()", ac->action->name.name); builder->target->emitTraceMessage(builder, msg.c_str()); visit(ac->action->body); return false; @@ -271,7 +271,7 @@ void ControlBodyTranslator::compileEmit(const IR::Vector *args) { // Increment header pointer builder->emitIndent(); - builder->appendFormat("%s += BYTES(%s);", program->headerStartVar.c_str(), width); + builder->appendFormat("%s += BYTES(%d);", program->headerStartVar.c_str(), width); builder->newline(); builder->blockEnd(true); @@ -304,7 +304,7 @@ void ControlBodyTranslator::processApply(const P4::ApplyMethod *method) { auto table = control->getTable(method->object->getName().name); BUG_CHECK(table != nullptr, "No table for %1%", method->expr); - msgStr = Util::printf_format("Control: applying %s", method->object->getName().name); + msgStr = absl::StrFormat("Control: applying %s", method->object->getName().name); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); @@ -393,7 +393,7 @@ void ControlBodyTranslator::processApply(const P4::ApplyMethod *method) { builder->blockEnd(true); builder->blockEnd(true); - msgStr = Util::printf_format("Control: %s applied", method->object->getName().name); + msgStr = absl::StrFormat("Control: %s applied", method->object->getName().name); builder->target->emitTraceMessage(builder, msgStr.c_str()); } diff --git a/backends/ebpf/ebpfDeparser.cpp b/backends/ebpf/ebpfDeparser.cpp index 41a8b3d424..64a53004b5 100644 --- a/backends/ebpf/ebpfDeparser.cpp +++ b/backends/ebpf/ebpfDeparser.cpp @@ -133,7 +133,7 @@ void DeparserHdrEmitTranslator::processMethod(const P4::ExternMethod *method) { "Header %1% size %2% is not a multiple of 8 bits.", expr, width); return; } - msgStr = Util::printf_format("Deparser: emitting header %s", expr->toString().c_str()); + msgStr = absl::StrFormat("Deparser: emitting header %s", expr->toString().c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); @@ -201,13 +201,13 @@ void DeparserHdrEmitTranslator::emitField(CodeBuilder *builder, cstring field, visit(hdrExpr); builder->appendFormat(".%s", field.c_str()); builder->endOfStatement(true); - msgStr = Util::printf_format("Deparser: emitting field %s=0x%%llx (%u bits)", field, - widthToEmit); + msgStr = absl::StrFormat("Deparser: emitting field %s=0x%%llx (%u bits)", field, + widthToEmit); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, "tmp"); builder->blockEnd(true); } } else { - msgStr = Util::printf_format("Deparser: emitting field %s (%u bits)", field, widthToEmit); + msgStr = absl::StrFormat("Deparser: emitting field %s (%u bits)", field, widthToEmit); builder->target->emitTraceMessage(builder, msgStr.c_str()); } diff --git a/backends/ebpf/ebpfParser.cpp b/backends/ebpf/ebpfParser.cpp index 26bdb52a18..377908b077 100644 --- a/backends/ebpf/ebpfParser.cpp +++ b/backends/ebpf/ebpfParser.cpp @@ -24,9 +24,9 @@ limitations under the License. namespace EBPF { void StateTranslationVisitor::compileLookahead(const IR::Expression *destination) { - cstring msgStr = Util::printf_format("Parser: lookahead for %s %s", - state->parser->typeMap->getType(destination)->toString(), - destination->toString()); + cstring msgStr = absl::StrFormat("Parser: lookahead for %s %s", + state->parser->typeMap->getType(destination)->toString(), + destination->toString()); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); @@ -49,8 +49,8 @@ void StateTranslationVisitor::compileAdvance(const P4::ExternMethod *extMethod) if (cnst) { cstring argStr = cstring::to_cstring(cnst->asUnsigned()); cstring offsetStr = - Util::printf_format("%s - (u8*)%s + BYTES(%s)", state->parser->program->headerStartVar, - state->parser->program->packetStartVar, argStr); + absl::StrFormat("%s - (u8*)%s + BYTES(%s)", state->parser->program->headerStartVar, + state->parser->program->packetStartVar, argStr); builder->target->emitTraceMessage(builder, "Parser (advance): check pkt_len=%%d < " "last_read_byte=%%d", @@ -115,8 +115,8 @@ void StateTranslationVisitor::compileVerify(const IR::MethodCallExpression *expr errorMember->member.name); builder->endOfStatement(true); - cstring msg = Util::printf_format("Verify: condition failed, parser_error=%%u (%s)", - errorMember->member.name); + cstring msg = absl::StrFormat("Verify: condition failed, parser_error=%%u (%s)", + errorMember->member.name); builder->target->emitTraceMessage(builder, msg.c_str(), 1, state->parser->program->errorVar.c_str()); @@ -156,10 +156,9 @@ bool StateTranslationVisitor::preorder(const IR::ParserState *parserState) { builder->spc(); builder->blockStart(); - cstring msgStr = - Util::printf_format("Parser: state %s (curr_offset=%%d)", parserState->name.name); - cstring offsetStr = Util::printf_format("%s - (u8*)%s", state->parser->program->headerStartVar, - state->parser->program->packetStartVar); + cstring msgStr = absl::StrFormat("Parser: state %s (curr_offset=%%d)", parserState->name.name); + cstring offsetStr = absl::StrFormat("%s - (u8*)%s", state->parser->program->headerStartVar, + state->parser->program->packetStartVar); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, offsetStr.c_str()); visit(parserState->components, "components"); @@ -283,7 +282,7 @@ void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, cstring msgStr; cstring fieldName = field->name.name; - msgStr = Util::printf_format("Parser: extracting field %s", fieldName); + msgStr = absl::StrFormat("Parser: extracting field %s", fieldName); builder->target->emitTraceMessage(builder, msgStr.c_str()); if (widthToExtract <= 64) { @@ -390,13 +389,13 @@ void StateTranslationVisitor::compileExtractField(const IR::Expression *expr, expr->to()->expr->to()->path->name.name)) { exprStr = exprStr.replace("."_cs, "->"_cs); } - cstring tmp = Util::printf_format("(unsigned long long) %s.%s", exprStr, fieldName); + cstring tmp = absl::StrFormat("(unsigned long long) %s.%s", exprStr, fieldName); - msgStr = Util::printf_format("Parser: extracted %s=0x%%llx (%u bits)", fieldName, - widthToExtract); + msgStr = + absl::StrFormat("Parser: extracted %s=0x%%llx (%u bits)", fieldName, widthToExtract); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, tmp.c_str()); } else { - msgStr = Util::printf_format("Parser: extracted %s (%u bits)", fieldName, widthToExtract); + msgStr = absl::StrFormat("Parser: extracted %s (%u bits)", fieldName, widthToExtract); builder->target->emitTraceMessage(builder, msgStr.c_str()); } } @@ -421,8 +420,8 @@ void StateTranslationVisitor::compileExtract(const IR::Expression *destination) auto program = state->parser->program; - cstring offsetStr = Util::printf_format("(%s - (u8*)%s) + BYTES(%s)", program->headerStartVar, - program->packetStartVar, cstring::to_cstring(width)); + cstring offsetStr = absl::StrFormat("(%s - (u8*)%s) + BYTES(%s)", program->headerStartVar, + program->packetStartVar, cstring::to_cstring(width)); builder->target->emitTraceMessage(builder, "Parser: check pkt_len=%d >= last_read_byte=%d", 2, program->lengthVar.c_str(), offsetStr.c_str()); @@ -465,7 +464,7 @@ void StateTranslationVisitor::compileExtract(const IR::Expression *destination) builder->newline(); builder->blockEnd(true); - msgStr = Util::printf_format("Parser: extracting header %s", destination->toString()); + msgStr = absl::StrFormat("Parser: extracting header %s", destination->toString()); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->newline(); @@ -495,7 +494,7 @@ void StateTranslationVisitor::compileExtract(const IR::Expression *destination) builder->appendFormat("%s += BYTES(%u);", program->headerStartVar.c_str(), width); builder->newline(); - msgStr = Util::printf_format("Parser: extracted %s", destination->toString()); + msgStr = absl::StrFormat("Parser: extracted %s", destination->toString()); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->newline(); diff --git a/backends/ebpf/ebpfTable.cpp b/backends/ebpf/ebpfTable.cpp index 2c0c866f4c..428781dafe 100644 --- a/backends/ebpf/ebpfTable.cpp +++ b/backends/ebpf/ebpfTable.cpp @@ -44,9 +44,7 @@ bool ActionTranslationVisitor::isActionParameter(const IR::PathExpression *expre cstring ActionTranslationVisitor::getParamInstanceName(const IR::Expression *expression) const { cstring actionName = EBPFObject::externalName(action); - auto paramStr = - Util::printf_format("%s->u.%s.%s", valueName, actionName, expression->toString()); - return paramStr; + return absl::StrFormat("%s->u.%s.%s", valueName, actionName, expression->toString()); } bool ActionTranslationVisitor::preorder(const IR::P4Action *act) { @@ -512,12 +510,12 @@ void EBPFTable::emitKey(CodeBuilder *builder, cstring keyName) { cstring msgStr, varStr; if (memcpy) { - msgStr = Util::printf_format("Control: key %s", c->expression->toString()); + msgStr = absl::StrFormat("Control: key %s", c->expression->toString()); builder->target->emitTraceMessage(builder, msgStr.c_str()); } else { - msgStr = Util::printf_format("Control: key %s=0x%%llx", c->expression->toString()); - varStr = Util::printf_format("(unsigned long long) %s.%s", keyName.c_str(), - fieldName.c_str()); + msgStr = absl::StrFormat("Control: key %s=0x%%llx", c->expression->toString()); + varStr = + absl::StrFormat("(unsigned long long) %s.%s", keyName.c_str(), fieldName.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, varStr.c_str()); } } @@ -538,21 +536,20 @@ void EBPFTable::emitAction(CodeBuilder *builder, cstring valueName, cstring acti builder->newline(); builder->increaseIndent(); - msgStr = Util::printf_format("Control: executing action %s", name); + msgStr = absl::StrFormat("Control: executing action %s", name); builder->target->emitTraceMessage(builder, msgStr.c_str()); for (auto param : *(action->parameters)) { auto etype = EBPFTypeFactory::instance->create(param->type); unsigned width = etype->as().widthInBits(); if (width <= 64) { - convStr = Util::printf_format("(unsigned long long) (%s->u.%s.%s)", valueName, name, - param->toString()); - msgStr = Util::printf_format("Control: param %s=0x%%llx (%d bits)", - param->toString(), width); + convStr = absl::StrFormat("(unsigned long long) (%s->u.%s.%s)", valueName, name, + param->toString()); + msgStr = absl::StrFormat("Control: param %s=0x%%llx (%d bits)", param->toString(), + width); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, convStr.c_str()); } else { - msgStr = - Util::printf_format("Control: param %s (%d bits)", param->toString(), width); + msgStr = absl::StrFormat("Control: param %s (%d bits)", param->toString(), width); builder->target->emitTraceMessage(builder, msgStr.c_str()); } } @@ -782,7 +779,7 @@ void EBPFTable::emitLookup(CodeBuilder *builder, cstring key, cstring value) { builder->emitIndent(); builder->appendFormat("for (int i = 0; i < sizeof(struct %s_mask) / 4; i++) ", keyTypeName); builder->blockStart(); - cstring str = Util::printf_format("*(((__u32 *) &%s) + i)", key); + cstring str = absl::StrFormat("*(((__u32 *) &%s) + i)", key); builder->target->emitTraceMessage( builder, "Control: [Ternary] Masking next 4 bytes of %llx with mask %llx", 2, str, "mask[i]"); @@ -806,8 +803,9 @@ void EBPFTable::emitLookup(CodeBuilder *builder, cstring key, cstring value) { builder->append("if (!tuple) "); builder->blockStart(); builder->target->emitTraceMessage( - builder, Util::printf_format("Control: Tuples map %s not found during ternary lookup. Bug?", - instanceName)); + builder, absl::StrFormat("Control: Tuples map %s not found during ternary lookup. Bug?", + instanceName) + .c_str()); builder->emitIndent(); builder->append("break;"); builder->newline(); @@ -861,7 +859,7 @@ cstring EBPFTable::p4ActionToActionIDName(const IR::P4Action *action) const { cstring actionName = EBPFObject::externalName(action); cstring tableInstance = dataMapName; - return Util::printf_format("%s_ACT_%s", tableInstance.toUpper(), actionName.toUpper()); + return absl::StrFormat("%s_ACT_%s", tableInstance.toUpper(), actionName.toUpper()); } /// As ternary has precedence over lpm, this function checks if any @@ -1145,7 +1143,7 @@ void EBPFValueSet::emitTypes(CodeBuilder *builder) { } else if (auto tuple = elemType->to()) { int i = 0; for (auto field : tuple->components) { - cstring name = Util::printf_format("field%d", i++); + cstring name = absl::StrFormat("field%d", i++); fieldEmitter(field, name); fieldNames.emplace_back(std::make_pair(name, field)); } @@ -1191,7 +1189,7 @@ void EBPFValueSet::emitKeyInitializer(CodeBuilder *builder, const IR::SelectExpr } cstring dst = - Util::printf_format("%s.%s", keyVarName.c_str(), fieldNames.at(i).first.c_str()); + absl::StrFormat("%s.%s", keyVarName.c_str(), fieldNames.at(i).first.c_str()); builder->appendFormat("__builtin_memcpy(&%s, &(", dst.c_str()); codeGen->visit(keyExpr); builder->appendFormat("[0]), sizeof(%s))", dst.c_str()); diff --git a/backends/ebpf/psa/ebpfPipeline.cpp b/backends/ebpf/psa/ebpfPipeline.cpp index f66546875b..fee84ee04f 100644 --- a/backends/ebpf/psa/ebpfPipeline.cpp +++ b/backends/ebpf/psa/ebpfPipeline.cpp @@ -255,11 +255,11 @@ void EBPFIngressPipeline::emit(CodeBuilder *builder) { emitMetadataFromCPUMAP(builder); builder->newline(); - msgStr = Util::printf_format( + msgStr = absl::StrFormat( "%s parser: parsing new packet, input_port=%%d, path=%%d, " "pkt_len=%%d", sectionName); - varStr = Util::printf_format("%s->packet_path", compilerGlobalMetadata); + varStr = absl::StrFormat("%s->packet_path", compilerGlobalMetadata); builder->target->emitTraceMessage(builder, msgStr.c_str(), 3, inputPortVar.c_str(), varStr, lengthVar.c_str()); @@ -274,20 +274,20 @@ void EBPFIngressPipeline::emit(CodeBuilder *builder) { builder->spc(); builder->blockStart(); emitPSAControlInputMetadata(builder); - msgStr = Util::printf_format("%s control: packet processing started", sectionName); + msgStr = absl::StrFormat("%s control: packet processing started", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); control->emit(builder); builder->blockEnd(true); - msgStr = Util::printf_format("%s control: packet processing finished", sectionName); + msgStr = absl::StrFormat("%s control: packet processing finished", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); // DEPARSER builder->emitIndent(); builder->blockStart(); - msgStr = Util::printf_format("%s deparser: packet deparsing started", sectionName); + msgStr = absl::StrFormat("%s deparser: packet deparsing started", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); deparser->emit(builder); - msgStr = Util::printf_format("%s deparser: packet deparsing finished", sectionName); + msgStr = absl::StrFormat("%s deparser: packet deparsing finished", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->blockEnd(true); @@ -425,11 +425,11 @@ void EBPFEgressPipeline::emit(CodeBuilder *builder) { emitPSAControlOutputMetadata(builder); emitPSAControlInputMetadata(builder); - msgStr = Util::printf_format( + msgStr = absl::StrFormat( "%s parser: parsing new packet, input_port=%%d, path=%%d, " "pkt_len=%%d", sectionName); - varStr = Util::printf_format("%s->packet_path", compilerGlobalMetadata); + varStr = absl::StrFormat("%s->packet_path", compilerGlobalMetadata); builder->target->emitTraceMessage(builder, msgStr.c_str(), 3, inputPortVar.c_str(), varStr, lengthVar.c_str()); @@ -449,20 +449,20 @@ void EBPFEgressPipeline::emit(CodeBuilder *builder) { builder->emitIndent(); builder->blockStart(); builder->newline(); - msgStr = Util::printf_format("%s control: packet processing started", sectionName); + msgStr = absl::StrFormat("%s control: packet processing started", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); control->emit(builder); builder->blockEnd(true); - msgStr = Util::printf_format("%s control: packet processing finished", sectionName); + msgStr = absl::StrFormat("%s control: packet processing finished", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); // DEPARSER builder->emitIndent(); builder->blockStart(); - msgStr = Util::printf_format("%s deparser: packet deparsing started", sectionName); + msgStr = absl::StrFormat("%s deparser: packet deparsing started", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); deparser->emit(builder); - msgStr = Util::printf_format("%s deparser: packet deparsing finished", sectionName); + msgStr = absl::StrFormat("%s deparser: packet deparsing finished", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->blockEnd(true); @@ -557,7 +557,7 @@ void TCIngressPipeline::emitTCWorkaroundUsingCPUMAP(CodeBuilder *builder) { /// - send to port void TCIngressPipeline::emitTrafficManager(CodeBuilder *builder) { cstring mcast_grp = - Util::printf_format("%s.multicast_group", control->outputStandardMetadata->name.name); + absl::StrFormat("%s.multicast_group", control->outputStandardMetadata->name.name); builder->emitIndent(); builder->appendFormat("if (%s != 0) ", mcast_grp.c_str()); builder->blockStart(); @@ -600,10 +600,9 @@ void TCIngressPipeline::emitTrafficManager(CodeBuilder *builder) { builder->endOfStatement(true); builder->blockEnd(true); - cstring eg_port = - Util::printf_format("%s.egress_port", control->outputStandardMetadata->name.name); + cstring eg_port = absl::StrFormat("%s.egress_port", control->outputStandardMetadata->name.name); cstring cos = - Util::printf_format("%s.class_of_service", control->outputStandardMetadata->name.name); + absl::StrFormat("%s.class_of_service", control->outputStandardMetadata->name.name); builder->target->emitTraceMessage( builder, "IngressTM: Sending packet out of port %d with priority %d", 2, eg_port, cos); builder->emitIndent(); @@ -655,15 +654,14 @@ void TCEgressPipeline::emitTrafficManager(CodeBuilder *builder) { builder->appendFormat("%s->packet_path = RECIRCULATE", compilerGlobalMetadata); builder->endOfStatement(true); builder->emitIndent(); - builder->appendFormat("return bpf_redirect(PSA_PORT_RECIRCULATE, BPF_F_INGRESS)", - contextVar.c_str()); + builder->appendFormat("return bpf_redirect(PSA_PORT_RECIRCULATE, BPF_F_INGRESS)"); builder->endOfStatement(true); builder->blockEnd(true); builder->newline(); // normal packet to port - varStr = Util::printf_format("%s->ifindex", contextVar); + varStr = absl::StrFormat("%s->ifindex", contextVar); builder->target->emitTraceMessage(builder, "EgressTM: output packet to port %d", 1, varStr.c_str()); builder->emitIndent(); @@ -699,8 +697,7 @@ void XDPIngressPipeline::emitGlobalMetadataInitializer(CodeBuilder *builder) { void XDPIngressPipeline::emitTrafficManager(CodeBuilder *builder) { // do not handle multicast; it has been handled earlier by PreDeparser. - cstring portVar = - Util::printf_format("%s.egress_port", control->outputStandardMetadata->name.name); + cstring portVar = absl::StrFormat("%s.egress_port", control->outputStandardMetadata->name.name); builder->target->emitTraceMessage(builder, "IngressTM: Sending packet out of port %u", 1, portVar); builder->emitIndent(); @@ -739,7 +736,7 @@ void XDPEgressPipeline::emitTrafficManager(CodeBuilder *builder) { builder->newline(); // normal packet to port - varStr = Util::printf_format("%s.egress_port", control->inputStandardMetadata->name.name); + varStr = absl::StrFormat("%s.egress_port", control->inputStandardMetadata->name.name); builder->target->emitTraceMessage(builder, "EgressTM: output packet to port %d", 1, varStr); builder->emitIndent(); builder->appendFormat("return %s;", this->forwardReturnCode()); @@ -785,11 +782,11 @@ void TCTrafficManagerForXDP::emit(CodeBuilder *builder) { emitReadXDP2TCMetadataFromHead(builder); } - msgStr = Util::printf_format("%s deparser: packet deparsing started", sectionName); + msgStr = absl::StrFormat("%s deparser: packet deparsing started", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); deparser->emit(builder); - msgStr = Util::printf_format("%s deparser: packet deparsing finished", sectionName); + msgStr = absl::StrFormat("%s deparser: packet deparsing finished", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); this->emitTrafficManager(builder); diff --git a/backends/ebpf/psa/ebpfPsaControl.cpp b/backends/ebpf/psa/ebpfPsaControl.cpp index 79411b12bc..00aa9c5577 100644 --- a/backends/ebpf/psa/ebpfPsaControl.cpp +++ b/backends/ebpf/psa/ebpfPsaControl.cpp @@ -48,7 +48,7 @@ bool ControlBodyTranslatorPSA::preorder(const IR::AssignmentStatement *a) { ext->originalExternType->name.name == "DirectMeter") { // It is just for trace message before meter execution cstring name = EBPFObject::externalName(ext->object); - auto msgStr = Util::printf_format("Executing meter: %s", name); + auto msgStr = absl::StrFormat("Executing meter: %s", name); builder->target->emitTraceMessage(builder, msgStr.c_str()); } } diff --git a/backends/ebpf/psa/ebpfPsaDeparser.cpp b/backends/ebpf/psa/ebpfPsaDeparser.cpp index 4c6821e667..c66fdb0ddb 100644 --- a/backends/ebpf/psa/ebpfPsaDeparser.cpp +++ b/backends/ebpf/psa/ebpfPsaDeparser.cpp @@ -263,7 +263,7 @@ void XDPIngressDeparserPSA::emitPreDeparser(CodeBuilder *builder) { builder->endOfStatement(true); builder->blockEnd(true); builder->emitIndent(); - builder->appendFormat("if (%s->drop) ", istd->name.name, istd->name.name); + builder->appendFormat("if (%s->drop) ", istd->name.name); builder->blockStart(); builder->target->emitTraceMessage(builder, "PreDeparser: dropping packet.."); builder->emitIndent(); diff --git a/backends/ebpf/psa/ebpfPsaGen.h b/backends/ebpf/psa/ebpfPsaGen.h index e3159000fe..5979227b8f 100644 --- a/backends/ebpf/psa/ebpfPsaGen.h +++ b/backends/ebpf/psa/ebpfPsaGen.h @@ -47,8 +47,8 @@ class EbpfCodeGenerator { class PSAEbpfGenerator : public EbpfCodeGenerator { public: - static const unsigned MaxClones = 64; - static const unsigned MaxCloneSessions = 1024; + static constexpr unsigned MaxClones = 64; + static constexpr unsigned MaxCloneSessions = 1024; EBPFPipeline *ingress; EBPFPipeline *egress; @@ -98,7 +98,7 @@ class PSAArchXDP : public PSAEbpfGenerator { EBPFPipeline *tcIngressForXDP; /// If the XDP mode is used, we need to have TC Egress pipeline to handle cloned packets. EBPFPipeline *tcEgressForXDP; - static const unsigned egressDevmapSize = 256; + static constexpr unsigned egressDevmapSize = 256; PSAArchXDP(const EbpfOptions &options, std::vector &ebpfTypes, EBPFPipeline *xdpIngress, EBPFPipeline *xdpEgress, EBPFPipeline *tcTrafficManager, diff --git a/backends/ebpf/psa/ebpfPsaTable.cpp b/backends/ebpf/psa/ebpfPsaTable.cpp index 2a53fa8824..4f66a0e40e 100644 --- a/backends/ebpf/psa/ebpfPsaTable.cpp +++ b/backends/ebpf/psa/ebpfPsaTable.cpp @@ -634,16 +634,15 @@ void EBPFTablePSA::emitMapUpdateTraceMsg(CodeBuilder *builder, cstring mapName, builder->emitIndent(); builder->appendFormat("if (%s) ", returnCode.c_str()); builder->blockStart(); - cstring msgStr = Util::printf_format("Map initializer: Error while map (%s) update, code: %s", - mapName, "%d"); + cstring msgStr = + absl::StrFormat("Map initializer: Error while map (%s) update, code: %s", mapName, "%d"); builder->target->emitTraceMessage(builder, msgStr, 1, returnCode.c_str()); builder->blockEnd(false); builder->append(" else "); builder->blockStart(); - msgStr = Util::printf_format("Map initializer: Map (%s) update succeed", mapName, - returnCode.c_str()); + msgStr = absl::StrFormat("Map initializer: Map (%s) update succeed", mapName); builder->target->emitTraceMessage(builder, msgStr); builder->blockEnd(true); } diff --git a/backends/ebpf/psa/externs/ebpfPsaCounter.cpp b/backends/ebpf/psa/externs/ebpfPsaCounter.cpp index 145c9459d1..b0b37351b3 100644 --- a/backends/ebpf/psa/externs/ebpfPsaCounter.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaCounter.cpp @@ -200,13 +200,13 @@ void EBPFCounterPSA::emitDirectMethodInvocation(CodeBuilder *builder, CHECK_NULL(pipeline); cstring msgStr = - Util::printf_format("Counter: updating %s, packets=1, bytes=%%u", instanceName.c_str()); - cstring varStr = Util::printf_format("%s", pipeline->lengthVar.c_str()); + absl::StrFormat("Counter: updating %s, packets=1, bytes=%%u", instanceName.c_str()); + cstring varStr = absl::StrFormat("%s", pipeline->lengthVar.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, varStr.c_str()); emitCounterUpdate(builder, target, ""_cs); - msgStr = Util::printf_format("Counter: %s updated", instanceName.c_str()); + msgStr = absl::StrFormat("Counter: %s updated", instanceName.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str()); } @@ -231,9 +231,9 @@ void EBPFCounterPSA::emitCount(CodeBuilder *builder, const IR::MethodCallExpress codeGen->visit(index); builder->endOfStatement(true); - msgStr = Util::printf_format("Counter: updating %s, id=%%u, packets=1, bytes=%%u", - instanceName.c_str()); - varStr = Util::printf_format("%s", program->lengthVar.c_str()); + msgStr = + absl::StrFormat("Counter: updating %s, id=%%u, packets=1, bytes=%%u", instanceName.c_str()); + varStr = absl::StrFormat("%s", program->lengthVar.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str(), 2, keyName.c_str(), varStr.c_str()); builder->emitIndent(); @@ -242,7 +242,7 @@ void EBPFCounterPSA::emitCount(CodeBuilder *builder, const IR::MethodCallExpress emitCounterUpdate(builder, valueName, keyName); - msgStr = Util::printf_format("Counter: %s updated", instanceName.c_str()); + msgStr = absl::StrFormat("Counter: %s updated", instanceName.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str()); } @@ -263,7 +263,7 @@ void EBPFCounterPSA::emitCounterUpdate(CodeBuilder *builder, const cstring targe program->lengthVar); builder->endOfStatement(true); - varStr = Util::printf_format("%sbytes", targetWAccess.c_str()); + varStr = absl::StrFormat("%sbytes", targetWAccess.c_str()); builder->target->emitTraceMessage(builder, "Counter: now bytes=%u", 1, varStr.c_str()); } if (type == CounterType::PACKETS || type == CounterType::PACKETS_AND_BYTES) { @@ -271,7 +271,7 @@ void EBPFCounterPSA::emitCounterUpdate(CodeBuilder *builder, const cstring targe builder->appendFormat("__sync_fetch_and_add(&(%spackets), 1)", targetWAccess.c_str()); builder->endOfStatement(true); - varStr = Util::printf_format("%spackets", targetWAccess.c_str()); + varStr = absl::StrFormat("%spackets", targetWAccess.c_str()); builder->target->emitTraceMessage(builder, "Counter: now packets=%u", 1, varStr.c_str()); } diff --git a/backends/ebpf/psa/externs/ebpfPsaDigest.cpp b/backends/ebpf/psa/externs/ebpfPsaDigest.cpp index 11f91cbc93..07d2888f07 100644 --- a/backends/ebpf/psa/externs/ebpfPsaDigest.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaDigest.cpp @@ -82,7 +82,7 @@ class EBPFDigestPSAValueVisitor : public CodeGenInspector { for (const auto *f : se->components) { auto type = typeMap->getType(f->expression); - cstring path = Util::printf_format("%s.%s", tmpVar, f->name.name); + cstring path = absl::StrFormat("%s.%s", tmpVar, f->name.name); codegen->emitAssignStatement(type, nullptr, path, f->expression); builder->newline(); } diff --git a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp index 653b6a4a8e..ef50b361ac 100644 --- a/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaHashAlgorithm.cpp @@ -296,11 +296,11 @@ void CRCChecksumAlgorithm::emitAddData(CodeBuilder *builder, const ArgumentsList } } - cstring varStr = Util::printf_format("(u64) %s", registerVar.c_str()); + cstring varStr = absl::StrFormat("(u64) %s", registerVar.c_str()); builder->target->emitTraceMessage(builder, "CRC: checksum state: %llx", 1, varStr.c_str()); cstring final_crc = - Util::printf_format("(u64) %s(%s)", finalizeMethod.c_str(), registerVar.c_str()); + absl::StrFormat("(u64) %s(%s)", finalizeMethod.c_str(), registerVar.c_str()); builder->target->emitTraceMessage(builder, "CRC: final checksum: %llx", 1, final_crc.c_str()); builder->blockEnd(true); diff --git a/backends/ebpf/psa/externs/ebpfPsaRegister.cpp b/backends/ebpf/psa/externs/ebpfPsaRegister.cpp index e065e05e27..697324146a 100644 --- a/backends/ebpf/psa/externs/ebpfPsaRegister.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaRegister.cpp @@ -135,8 +135,8 @@ void EBPFRegisterPSA::emitInitializer(CodeBuilder *builder) { builder->emitIndent(); builder->appendFormat("if (%s) ", ret.c_str()); builder->blockStart(); - cstring msgStr = Util::printf_format("Map initializer: Error while map (%s) update, code: %s", - instanceName, "%d"); + cstring msgStr = absl::StrFormat("Map initializer: Error while map (%s) update, code: %s", + instanceName, "%d"); builder->target->emitTraceMessage(builder, msgStr, 1, ret.c_str()); builder->blockEnd(true); @@ -160,7 +160,7 @@ void EBPFRegisterPSA::emitRegisterRead(CodeBuilder *builder, const P4::ExternMet this->valueType->declare(builder, valueName, true); builder->endOfStatement(true); - cstring msgStr = Util::printf_format("Register: reading %s", instanceName.c_str()); + cstring msgStr = absl::StrFormat("Register: reading %s", instanceName.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); @@ -215,7 +215,7 @@ void EBPFRegisterPSA::emitRegisterRead(CodeBuilder *builder, const P4::ExternMet void EBPFRegisterPSA::emitRegisterWrite(CodeBuilder *builder, const P4::ExternMethod *method, ControlBodyTranslatorPSA *translator) { - cstring msgStr = Util::printf_format("Register: writing %s", instanceName.c_str()); + cstring msgStr = absl::StrFormat("Register: writing %s", instanceName.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); @@ -230,8 +230,7 @@ void EBPFRegisterPSA::emitRegisterWrite(CodeBuilder *builder, const P4::ExternMe builder->emitIndent(); builder->appendFormat("if (%s) ", ret.c_str()); builder->blockStart(); - msgStr = - Util::printf_format("Register: Error while map (%s) update, code: %s", instanceName, "%d"); + msgStr = absl::StrFormat("Register: Error while map (%s) update, code: %s", instanceName, "%d"); builder->target->emitTraceMessage(builder, msgStr, 1, ret.c_str()); builder->blockEnd(true); diff --git a/backends/ebpf/psa/externs/ebpfPsaTableImplementation.cpp b/backends/ebpf/psa/externs/ebpfPsaTableImplementation.cpp index 1383e54638..ff906747f3 100644 --- a/backends/ebpf/psa/externs/ebpfPsaTableImplementation.cpp +++ b/backends/ebpf/psa/externs/ebpfPsaTableImplementation.cpp @@ -165,12 +165,11 @@ void EBPFActionProfilePSA::emitInstance(CodeBuilder *builder) { void EBPFActionProfilePSA::applyImplementation(CodeBuilder *builder, cstring tableValueName, cstring actionRunVariable) { - cstring msg = Util::printf_format("ActionProfile: applying %s", instanceName.c_str()); + cstring msg = absl::StrFormat("ActionProfile: applying %s", instanceName.c_str()); builder->target->emitTraceMessage(builder, msg.c_str()); cstring apValueName = program->refMap->newName("ap_value"); - cstring apKeyName = - Util::printf_format("%s->%s", tableValueName.c_str(), referenceName.c_str()); + cstring apKeyName = absl::StrFormat("%s->%s", tableValueName.c_str(), referenceName.c_str()); builder->target->emitTraceMessage(builder, "ActionProfile: entry id %u", 1, apKeyName.c_str()); @@ -200,7 +199,7 @@ void EBPFActionProfilePSA::applyImplementation(CodeBuilder *builder, cstring tab builder->endOfStatement(true); builder->blockEnd(true); - msg = Util::printf_format("ActionProfile: %s applied", instanceName.c_str()); + msg = absl::StrFormat("ActionProfile: %s applied", instanceName.c_str()); builder->target->emitTraceMessage(builder, msg.c_str()); } @@ -236,7 +235,7 @@ EBPFActionSelectorPSA::EBPFActionSelectorPSA(const EBPFProgram *program, CodeGen "value truncation, must be at least 1 bit", decl->arguments->at(2)->expression); } - outputHashMask = Util::printf_format("0x%llx", (1ull << outputHashWidth) - 1); + outputHashMask = absl::StrFormat("0x%llx", (1ull << outputHashWidth) - 1); // map names actionsMapName = instanceName + "_actions"; @@ -330,7 +329,7 @@ void EBPFActionSelectorPSA::applyImplementation(CodeBuilder *builder, cstring ta cstring actionRunVariable) { if (hashEngine == nullptr) return; - cstring msg = Util::printf_format("ActionSelector: applying %s", instanceName.c_str()); + cstring msg = absl::StrFormat("ActionSelector: applying %s", instanceName.c_str()); builder->target->emitTraceMessage(builder, msg.c_str()); // 1. Declare variables. @@ -518,7 +517,7 @@ void EBPFActionSelectorPSA::applyImplementation(CodeBuilder *builder, cstring ta } builder->blockEnd(true); - msg = Util::printf_format("ActionSelector: %s applied", instanceName.c_str()); + msg = absl::StrFormat("ActionSelector: %s applied", instanceName.c_str()); builder->target->emitTraceMessage(builder, msg.c_str()); } @@ -674,7 +673,7 @@ void EBPFActionSelectorPSA::emitCacheTypes(CodeBuilder *builder) { for (auto s : selectors) { auto type = program->typeMap->getType(s->expression); auto ebpfType = EBPFTypeFactory::instance->create(type); - cstring fieldName = Util::printf_format("field%u", fieldNumber++); + cstring fieldName = absl::StrFormat("field%u", fieldNumber++); builder->emitIndent(); ebpfType->declare(builder, fieldName, false); @@ -719,7 +718,7 @@ void EBPFActionSelectorPSA::emitCacheLookup(CodeBuilder *builder, cstring key, c for (auto s : selectors) { auto type = program->typeMap->getType(s->expression); auto ebpfType = EBPFTypeFactory::instance->create(type); - cstring fieldName = Util::printf_format("field%u", fieldNumber++); + cstring fieldName = absl::StrFormat("field%u", fieldNumber++); bool memcpy = false; auto scalar = ebpfType->to(); diff --git a/backends/ebpf/target.cpp b/backends/ebpf/target.cpp index a00b35f38c..78e78e1f90 100644 --- a/backends/ebpf/target.cpp +++ b/backends/ebpf/target.cpp @@ -67,8 +67,8 @@ void KernelSamplesTarget::emitTableDecl(Util::SourceCodeBuilder *builder, cstrin TableKind tableKind, cstring keyType, cstring valueType, unsigned size) const { cstring kind, flags; - cstring registerTable = "REGISTER_TABLE(%s, %s, %s, %s, %d)"_cs; - cstring registerTableWithFlags = "REGISTER_TABLE_FLAGS(%s, %s, %s, %s, %d, %s)"_cs; + static constexpr char registerTable[] = "REGISTER_TABLE(%s, %s, %s, %s, %d)"; + static constexpr char registerTableWithFlags[] = "REGISTER_TABLE_FLAGS(%s, %s, %s, %s, %d, %s)"; kind = getBPFMapType(tableKind); @@ -121,8 +121,9 @@ void KernelSamplesTarget::emitMapInMapDecl(Util::SourceCodeBuilder *builder, cst BUG("Unsupported type of outer map for map-in-map"); } - cstring registerOuterTable = "REGISTER_TABLE_OUTER(%s, %s_OF_MAPS, %s, %s, %d, %d, %s)"_cs; - cstring registerInnerTable = "REGISTER_TABLE_INNER(%s, %s, %s, %s, %d, %d, %d)"_cs; + static constexpr char registerOuterTable[] = + "REGISTER_TABLE_OUTER(%s, %s_OF_MAPS, %s, %s, %d, %d, %s)"; + static constexpr char registerInnerTable[] = "REGISTER_TABLE_INNER(%s, %s, %s, %s, %d, %d, %d)"; innerMapIndex++; diff --git a/backends/tc/ebpfCodeGen.cpp b/backends/tc/ebpfCodeGen.cpp index c6459cb15c..ae0a3118f5 100644 --- a/backends/tc/ebpfCodeGen.cpp +++ b/backends/tc/ebpfCodeGen.cpp @@ -315,11 +315,11 @@ void TCIngressPipelinePNA::emit(EBPF::CodeBuilder *builder) { builder->newline(); if (name == "tc-parse") { - msgStr = Util::printf_format( + msgStr = absl::StrFormat( "%s parser: parsing new packet, input_port=%%d, path=%%d, " "pkt_len=%%d", sectionName); - varStr = Util::printf_format("%s->packet_path", compilerGlobalMetadata); + varStr = absl::StrFormat("%s->packet_path", compilerGlobalMetadata); builder->target->emitTraceMessage(builder, msgStr.c_str(), 3, inputPortVar.c_str(), varStr, lengthVar.c_str()); @@ -336,21 +336,21 @@ void TCIngressPipelinePNA::emit(EBPF::CodeBuilder *builder) { if (name == "tc-ingress") { // CONTROL builder->blockStart(); - msgStr = Util::printf_format("%s control: packet processing started", sectionName); + msgStr = absl::StrFormat("%s control: packet processing started", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); ((EBPFControlPNA *)control)->emitExternDefinition(builder); control->emit(builder); builder->blockEnd(true); - msgStr = Util::printf_format("%s control: packet processing finished", sectionName); + msgStr = absl::StrFormat("%s control: packet processing finished", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); // DEPARSER builder->emitIndent(); builder->blockStart(); - msgStr = Util::printf_format("%s deparser: packet deparsing started", sectionName); + msgStr = absl::StrFormat("%s deparser: packet deparsing started", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); deparser->emit(builder); - msgStr = Util::printf_format("%s deparser: packet deparsing finished", sectionName); + msgStr = absl::StrFormat("%s deparser: packet deparsing finished", sectionName); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->blockEnd(true); } @@ -505,9 +505,9 @@ void TCIngressPipelinePNA::emitTrafficManager(EBPF::CodeBuilder *builder) { builder->endOfStatement(true); builder->blockEnd(true); - cstring eg_port = Util::printf_format("%s->egress_port", compilerGlobalMetadata); + cstring eg_port = absl::StrFormat("%s->egress_port", compilerGlobalMetadata); cstring cos = - Util::printf_format("%s.class_of_service", control->outputStandardMetadata->name.name); + absl::StrFormat("%s.class_of_service", control->outputStandardMetadata->name.name); builder->target->emitTraceMessage( builder, "IngressTM: Sending packet out of port %d with priority %d", 2, eg_port, cos); builder->emitIndent(); @@ -625,7 +625,7 @@ void PnaStateTranslationVisitor::compileExtractField(const IR::Expression *expr, } } - msgStr = Util::printf_format("Parser: extracting field %s", fieldName); + msgStr = absl::StrFormat("Parser: extracting field %s", fieldName); builder->target->emitTraceMessage(builder, msgStr.c_str()); if (widthToExtract <= 64) { @@ -741,13 +741,13 @@ void PnaStateTranslationVisitor::compileExtractField(const IR::Expression *expr, } } } - cstring tmp = Util::printf_format("(unsigned long long) %s.%s", exprStr, fieldName); + cstring tmp = absl::StrFormat("(unsigned long long) %s.%s", exprStr, fieldName); - msgStr = Util::printf_format("Parser: extracted %s=0x%%llx (%u bits)", fieldName, - widthToExtract); + msgStr = + absl::StrFormat("Parser: extracted %s=0x%%llx (%u bits)", fieldName, widthToExtract); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, tmp.c_str()); } else { - msgStr = Util::printf_format("Parser: extracted %s (%u bits)", fieldName, widthToExtract); + msgStr = absl::StrFormat("Parser: extracted %s (%u bits)", fieldName, widthToExtract); builder->target->emitTraceMessage(builder, msgStr.c_str()); } @@ -755,9 +755,9 @@ void PnaStateTranslationVisitor::compileExtractField(const IR::Expression *expr, } void PnaStateTranslationVisitor::compileLookahead(const IR::Expression *destination) { - cstring msgStr = Util::printf_format("Parser: lookahead for %s %s", - state->parser->typeMap->getType(destination)->toString(), - destination->toString()); + cstring msgStr = absl::StrFormat("Parser: lookahead for %s %s", + state->parser->typeMap->getType(destination)->toString(), + destination->toString()); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); @@ -916,7 +916,7 @@ void EBPFTablePNA::emitValueStructStructure(EBPF::CodeBuilder *builder) { cstring EBPFTablePNA::p4ActionToActionIDName(const IR::P4Action *action) const { cstring actionName = EBPFObject::externalName(action); cstring tableInstance = dataMapName; - return Util::printf_format("%s_ACT_%s", tableInstance.toUpper(), actionName.toUpper()); + return absl::StrFormat("%s_ACT_%s", tableInstance.toUpper(), actionName.toUpper()); } void EBPFTablePNA::emitActionArguments(EBPF::CodeBuilder *builder, const IR::P4Action *action, @@ -963,21 +963,20 @@ void EBPFTablePNA::emitAction(EBPF::CodeBuilder *builder, cstring valueName, builder->newline(); builder->increaseIndent(); - msgStr = Util::printf_format("Control: executing action %s", name); + msgStr = absl::StrFormat("Control: executing action %s", name); builder->target->emitTraceMessage(builder, msgStr.c_str()); for (auto param : *(action->parameters)) { auto etype = EBPF::EBPFTypeFactory::instance->create(param->type); unsigned width = etype->as().widthInBits(); if (width <= 64) { - convStr = Util::printf_format("(unsigned long long) (%s->u.%s.%s)", valueName, name, - param->toString()); - msgStr = Util::printf_format("Control: param %s=0x%%llx (%d bits)", - param->toString(), width); + convStr = absl::StrFormat("(unsigned long long) (%s->u.%s.%s)", valueName, name, + param->toString()); + msgStr = absl::StrFormat("Control: param %s=0x%%llx (%d bits)", param->toString(), + width); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, convStr.c_str()); } else { - msgStr = - Util::printf_format("Control: param %s (%d bits)", param->toString(), width); + msgStr = absl::StrFormat("Control: param %s (%d bits)", param->toString(), width); builder->target->emitTraceMessage(builder, msgStr.c_str()); } } @@ -1058,7 +1057,7 @@ void EBPFTablePNA::emitAction(EBPF::CodeBuilder *builder, cstring valueName, cstring noActionName = P4::P4CoreLibrary::instance().noAction.name; cstring tableInstance = dataMapName; cstring actionName = - Util::printf_format("%s_ACT_%s", tableInstance.toUpper(), noActionName.toUpper()); + absl::StrFormat("%s_ACT_%s", tableInstance.toUpper(), noActionName.toUpper()); builder->emitIndent(); builder->appendFormat("case %s: ", actionName); builder->newline(); @@ -1123,7 +1122,7 @@ void EBPFTablePNA::emitValueActionIDNames(EBPF::CodeBuilder *builder) { cstring noActionName = P4::P4CoreLibrary::instance().noAction.name; cstring tableInstance = dataMapName; cstring actionName = - Util::printf_format("%s_ACT_%s", tableInstance.toUpper(), noActionName.toUpper()); + absl::StrFormat("%s_ACT_%s", tableInstance.toUpper(), noActionName.toUpper()); unsigned int action_idx = tcIR->getActionId(noActionName); builder->emitIndent(); builder->appendFormat("#define %s %d", actionName, action_idx); @@ -1751,7 +1750,7 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) { auto table = control->getTable(method->object->getName().name); BUG_CHECK(table != nullptr, "No table for %1%", method->expr); - msgStr = Util::printf_format("Control: applying %s", method->object->getName().name); + msgStr = absl::StrFormat("Control: applying %s", method->object->getName().name); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); @@ -1851,12 +1850,12 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) { cstring msgStr, varStr; if (memcpy) { - msgStr = Util::printf_format("Control: key %s", c->expression->toString()); + msgStr = absl::StrFormat("Control: key %s", c->expression->toString()); builder->target->emitTraceMessage(builder, msgStr.c_str()); } else { - msgStr = Util::printf_format("Control: key %s=0x%%llx", c->expression->toString()); - varStr = Util::printf_format("(unsigned long long) %s.%s", keyname.c_str(), - fieldName.c_str()); + msgStr = absl::StrFormat("Control: key %s=0x%%llx", c->expression->toString()); + varStr = absl::StrFormat("(unsigned long long) %s.%s", keyname.c_str(), + fieldName.c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, varStr.c_str()); } } @@ -1914,7 +1913,7 @@ void ControlBodyTranslatorPNA::processApply(const P4::ApplyMethod *method) { toDereference.clear(); builder->blockEnd(true); - msgStr = Util::printf_format("Control: %s applied", method->object->getName().name); + msgStr = absl::StrFormat("Control: %s applied", method->object->getName().name); builder->target->emitTraceMessage(builder, msgStr.c_str()); } @@ -2003,9 +2002,9 @@ cstring ActionTranslationVisitorPNA::getParamInstanceName(const IR::Expression * if (isDefaultAction) { cstring actionName = action->name.originalName; - auto paramStr = Util::printf_format("p4tc_filter_fields.%s_%s_%s", - table->table->container->name.originalName, actionName, - expression->toString()); + auto paramStr = absl::StrFormat("p4tc_filter_fields.%s_%s_%s", + table->table->container->name.originalName, actionName, + expression->toString()); return paramStr; } else { return EBPF::ActionTranslationVisitor::getParamInstanceName(expression); @@ -2073,7 +2072,7 @@ void DeparserHdrEmitTranslatorPNA::processMethod(const P4::ExternMethod *method) builder->blockStart(); auto program = deparser->program; unsigned width = headerToEmit->width_bits(); - msgStr = Util::printf_format("Deparser: emitting header %s", expr->toString().c_str()); + msgStr = absl::StrFormat("Deparser: emitting header %s", expr->toString().c_str()); builder->target->emitTraceMessage(builder, msgStr.c_str()); builder->emitIndent(); @@ -2149,13 +2148,13 @@ void DeparserHdrEmitTranslatorPNA::emitField(EBPF::CodeBuilder *builder, cstring visit(hdrExpr); builder->appendFormat(".%s", field.c_str()); builder->endOfStatement(true); - msgStr = Util::printf_format("Deparser: emitting field %s=0x%%llx (%u bits)", field, - widthToEmit); + msgStr = absl::StrFormat("Deparser: emitting field %s=0x%%llx (%u bits)", field, + widthToEmit); builder->target->emitTraceMessage(builder, msgStr.c_str(), 1, "tmp"); builder->blockEnd(true); } } else { - msgStr = Util::printf_format("Deparser: emitting field %s (%u bits)", field, widthToEmit); + msgStr = absl::StrFormat("Deparser: emitting field %s (%u bits)", field, widthToEmit); builder->target->emitTraceMessage(builder, msgStr.c_str()); } diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index 96ddcdcb9a..fffd2702b1 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -1327,8 +1327,8 @@ bool ToP4::preorder(const IR::Annotations *a) { bool ToP4::preorder(const IR::Annotation *a) { builder.append("@"); builder.append(a->name); - char open = a->structured ? '[' : '('; - char close = a->structured ? ']' : ')'; + const char *open = a->structured ? "[" : "("; + const char *close = a->structured ? "]" : ")"; if (!a->expr.empty()) { builder.append(open); setVecSep(", "); diff --git a/ir/visitor.cpp b/ir/visitor.cpp index 043fcf65be..49a6a5b731 100644 --- a/ir/visitor.cpp +++ b/ir/visitor.cpp @@ -798,7 +798,7 @@ cstring Visitor::demangle(const char *str) { } #else #warning "No name demangling available; class names in logs will be mangled" -cstring Visitor::demangle(const char *str) { return str; } +cstring Visitor::demangle(const char *str) { return cstring(str); } #endif #if HAVE_LIBGC diff --git a/lib/error_reporter.h b/lib/error_reporter.h index 8fe7151a12..2dc61ac041 100644 --- a/lib/error_reporter.h +++ b/lib/error_reporter.h @@ -218,6 +218,8 @@ class ErrorReporter { Util::SourcePosition position = sources->getCurrentPosition(); position--; + // Unfortunately, we cannot go with statically checked format string + // here as it would require some changes to yyerror std::string message; if (!absl::FormatUntyped(&message, absl::UntypedFormatSpec(fmt), {absl::FormatArg(args)...})) { diff --git a/lib/sourceCodeBuilder.h b/lib/sourceCodeBuilder.h index 10f770fc6d..78d12adaef 100644 --- a/lib/sourceCodeBuilder.h +++ b/lib/sourceCodeBuilder.h @@ -19,8 +19,8 @@ limitations under the License. #include -#include - +#include "absl/strings/cord.h" +#include "absl/strings/str_format.h" #include "lib/cstring.h" #include "lib/exceptions.h" #include "lib/stringify.h" @@ -30,8 +30,7 @@ class SourceCodeBuilder { int indentLevel; // current indent level unsigned indentAmount; - std::stringstream buffer; - const std::string nl = "\n"; + absl::Cord buffer; bool endsInSpace; bool supressSemi = false; @@ -44,11 +43,11 @@ class SourceCodeBuilder { if (indentLevel < 0) BUG("Negative indent"); } void newline() { - buffer << nl; + buffer.Append("\n"); endsInSpace = true; } void spc() { - if (!endsInSpace) buffer << " "; + if (!endsInSpace) buffer.Append(" "); endsInSpace = true; } @@ -63,25 +62,25 @@ class SourceCodeBuilder { } void append(const std::string &str) { if (str.empty()) return; - endsInSpace = ::isspace(str.at(str.size() - 1)); - buffer << str; + endsInSpace = ::isspace(str.back()); + buffer.Append(str); } + [[deprecated("use string / char* version instead")]] void append(char c) { - endsInSpace = ::isspace(c); - buffer << c; + std::string str(1, c); + append(str); } void append(const char *str) { if (str == nullptr) BUG("Null argument to append"); if (strlen(str) == 0) return; endsInSpace = ::isspace(str[strlen(str) - 1]); - buffer << str; + buffer.Append(str); } - void appendFormat(const char *format, ...) { - va_list ap; - va_start(ap, format); - cstring str = Util::vprintf_format(format, ap); - va_end(ap); - append(str); + + template + void appendFormat(const absl::FormatSpec &format, Args &&...args) { + // FIXME: Sink directly to cord + append(absl::StrFormat(format, std::forward(args)...)); } void append(unsigned u) { appendFormat("%d", u); } void append(int u) { appendFormat("%d", u); } @@ -100,7 +99,7 @@ class SourceCodeBuilder { } void emitIndent() { - buffer << std::string(indentLevel, ' '); + buffer.Append(std::string(indentLevel, ' ')); if (indentLevel > 0) endsInSpace = true; } @@ -111,7 +110,7 @@ class SourceCodeBuilder { if (nl) newline(); } - std::string toString() const { return buffer.str(); } + std::string toString() const { return std::string(buffer); } void commentStart() { append("/* "); } void commentEnd() { append(" */"); } bool lastIsSpace() const { return endsInSpace; } diff --git a/lib/source_file.cpp b/lib/source_file.cpp index f23c877212..31723e8279 100644 --- a/lib/source_file.cpp +++ b/lib/source_file.cpp @@ -19,7 +19,11 @@ limitations under the License. #include #include -#include "exceptions.h" +#include "absl/strings/match.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/str_format.h" +#include "absl/strings/str_replace.h" +#include "lib/exceptions.h" #include "lib/log.h" #include "lib/stringify.h" @@ -35,7 +39,7 @@ SourcePosition::SourcePosition(unsigned lineNumber, unsigned columnNumber) } cstring SourcePosition::toString() const { - return Util::printf_format("%d:%d", lineNumber, columnNumber); + return absl::StrFormat("%d:%d", lineNumber, columnNumber); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -50,7 +54,8 @@ SourceInfo::SourceInfo(const InputSources *sources, SourcePosition start, Source } cstring SourceInfo::toString() const { - return Util::printf_format("(%s)-(%s)", start.toString(), end.toString()); + return absl::StrFormat("(%s)-(%s)", start.toString().string_view(), + end.toString().string_view()); } ////////////////////////////////////////////////////////////////////////////////////////// @@ -64,8 +69,7 @@ void InputSources::addComment(SourceInfo srcInfo, bool singleLine, cstring body) if (!singleLine) // Drop the "*/" body = body.exceptLast(2); - auto comment = new Comment(srcInfo, singleLine, body); - comments.push_back(comment); + comments.push_back(new Comment(srcInfo, singleLine, body)); } /// prevent further changes @@ -93,13 +97,13 @@ void InputSources::appendToLastLine(std::string_view text) { char c = text[i]; if (c == '\n') BUG("Text contains newlines"); } - contents.back() += toString(text); + contents.back() += text; } // Append a newline and start a new line void InputSources::appendNewline(std::string_view newline) { if (sealed) BUG("Appending to sealed InputSources"); - contents.back() += toString(newline); + contents.back() += newline; contents.push_back(""); // start a new line } @@ -135,9 +139,9 @@ void InputSources::appendText(const char *text) { } } -cstring InputSources::getLine(unsigned lineNumber) const { +std::string_view InputSources::getLine(unsigned lineNumber) const { if (lineNumber == 0) { - return ""_cs; + return ""; // BUG("Lines are numbered starting at 1"); // don't throw: this code may be called by exceptions // reporting on elements that have no source position @@ -185,13 +189,13 @@ cstring InputSources::getSourceFragment(const SourcePosition &position, bool use return getSourceFragment(info, useMarker); } -cstring carets(cstring source, unsigned start, unsigned end) { +static std::string carets(std::string_view source, unsigned start, unsigned end) { std::stringstream builder; if (start > source.size()) start = source.size(); - unsigned i; - for (i = 0; i < start; i++) { - char c = source.c_str()[i]; + unsigned i = 0; + for (; i < start; i++) { + char c = source[i]; if (c == ' ' || c == '\t') builder.put(c); else @@ -210,56 +214,54 @@ cstring InputSources::getSourceFragment(const SourceInfo &position, bool useMark if (position.getEnd().getLineNumber() > position.getStart().getLineNumber()) return getSourceFragment(position.getStart(), useMarker); - cstring result = getLine(position.getStart().getLineNumber()); - // Normally result has a newline, but if not - // then we have to add a newline - cstring toadd = ""_cs; - if (result.find('\n') == nullptr) toadd = cstring::newline; - cstring marker = - carets(result, position.getStart().getColumnNumber(), position.getEnd().getColumnNumber()); + std::string_view result = getLine(position.getStart().getLineNumber()); + unsigned int start = position.getStart().getColumnNumber(); + unsigned int end = position.getEnd().getColumnNumber(); + + // Normally result has a newline, but if not then we have to add a newline + bool addNewline = !absl::StrContains(result, "\n"); if (useMarker) { - return result + toadd + marker + cstring::newline; - } else { - return result + toadd + cstring::newline; + return absl::StrCat(result, addNewline ? "\n" : "", carets(result, start, end), "\n"); } + + return absl::StrCat(result, addNewline ? "\n" : "", "\n"); } cstring InputSources::getBriefSourceFragment(const SourceInfo &position) const { if (!position.isValid()) return ""_cs; - cstring result = getLine(position.getStart().getLineNumber()); + std::string_view result = getLine(position.getStart().getLineNumber()); unsigned int start = position.getStart().getColumnNumber(); - unsigned int end; - cstring toadd = ""_cs; + unsigned int end = position.getEnd().getColumnNumber(); + bool truncate = false; // If the position spans multiple lines, truncate to just the first line if (position.getEnd().getLineNumber() > position.getStart().getLineNumber()) { // go to the end of the first line end = result.size(); - if (result.find('\n') != nullptr) { + if (absl::StrContains(result, "\n")) { --end; } - toadd = " ..."_cs; - } else { - end = position.getEnd().getColumnNumber(); + truncate = true; } // Adding escape character in front of '"' character to properly store // quote marks as part of JSON properties, they must be escaped. - if (result.find('"') != nullptr) { - cstring out = result.replace("\""_cs, "\\\""_cs); + if (absl::StrContains(result, "\"")) { + auto out = absl::StrReplaceAll(result, {{"\"", "\\\""}}); return out.substr(0, out.size() - 1); } - return result.substr(start, end - start) + toadd; + return absl::StrCat(result.substr(start, end - start), truncate ? " ..." : ""); } cstring InputSources::toDebugString() const { std::stringstream builder; - for (auto line : contents) builder << line; + for (const auto &line : contents) builder << line; builder << "---------------" << std::endl; - for (auto lf : line_file_map) builder << lf.first << ": " << lf.second.toString() << std::endl; - return cstring(builder.str()); + for (const auto &lf : line_file_map) + builder << lf.first << ": " << lf.second.toString() << std::endl; + return builder.str(); } /////////////////////////////////////////////////// @@ -308,7 +310,7 @@ cstring SourceInfo::getLineNum() const { //////////////////////////////////////////////////////// cstring SourceFileLine::toString() const { - return Util::printf_format("%s(%d)", fileName.c_str(), sourceLine); + return absl::StrFormat("%s(%d)", fileName.string_view(), sourceLine); } } // namespace Util diff --git a/lib/source_file.h b/lib/source_file.h index 198db41c13..3abab5503c 100644 --- a/lib/source_file.h +++ b/lib/source_file.h @@ -22,6 +22,7 @@ limitations under the License. #define LIB_SOURCE_FILE_H_ #include +#include #include #include "cstring.h" @@ -267,7 +268,7 @@ class InputSources final { public: InputSources(); - cstring getLine(unsigned lineNumber) const; + std::string_view getLine(unsigned lineNumber) const; /// Original source line that produced the line with the specified number SourceFileLine getSourceLine(unsigned line) const; diff --git a/lib/stringify.cpp b/lib/stringify.cpp index cc113350c8..55a86eec8a 100644 --- a/lib/stringify.cpp +++ b/lib/stringify.cpp @@ -128,32 +128,4 @@ cstring toString(cstring value) { cstring toString(std::string_view value) { return cstring(value); } -cstring printf_format(const char *fmt_str, ...) { - if (fmt_str == nullptr) throw std::runtime_error("Null format string"); - va_list ap; - va_start(ap, fmt_str); - cstring formatted = vprintf_format(fmt_str, ap); - va_end(ap); - return formatted; -} - -// printf into a string -cstring vprintf_format(const char *fmt_str, va_list ap) { - static char buf[128]; - va_list ap_copy; - va_copy(ap_copy, ap); - if (fmt_str == nullptr) throw std::runtime_error("Null format string"); - - int size = vsnprintf(buf, sizeof(buf), fmt_str, ap); - if (size < 0) throw std::runtime_error("Error in vsnprintf"); - if (static_cast(size) >= sizeof(buf)) { - char *formatted = new char[size + 1]; - vsnprintf(formatted, size + 1, fmt_str, ap_copy); - va_end(ap_copy); - return cstring::own(formatted, size); - } - va_end(ap_copy); - return cstring(buf); -} - } // namespace Util diff --git a/lib/stringify.h b/lib/stringify.h index 51ffdcd03e..15cde6e449 100644 --- a/lib/stringify.h +++ b/lib/stringify.h @@ -95,10 +95,6 @@ cstring toString(std::string_view value); cstring toString(const big_int &value, unsigned width, bool sign, unsigned int base = 10); cstring toString(const void *value); -// printf into a string -cstring printf_format(const char *fmt_str, ...); -// vprintf into a string -cstring vprintf_format(const char *fmt_str, va_list ap); char DigitToChar(int digit); } // namespace Util diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1c3c24235b..5969155959 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -51,7 +51,6 @@ set (GTEST_UNITTEST_SOURCES gtest/source_file_test.cpp gtest/strength_reduction.cpp gtest/transforms.cpp - gtest/stringify.cpp gtest/rtti_test.cpp gtest/nethash.cpp gtest/visitor.cpp diff --git a/test/gtest/format_test.cpp b/test/gtest/format_test.cpp index 6c32863c15..0be5dab2a6 100644 --- a/test/gtest/format_test.cpp +++ b/test/gtest/format_test.cpp @@ -53,9 +53,6 @@ TEST(Util, Format) { message = context.errorReporter().format_message("%1% %2%", x, 5); EXPECT_EQ("x 5\n", message); - - message = Util::printf_format("Number=%d, String=%s", 5, "short"); - EXPECT_EQ("Number=5, String=short", message); } } // namespace Util diff --git a/test/gtest/source_file_test.cpp b/test/gtest/source_file_test.cpp index bea02b7e52..2c34b03b25 100644 --- a/test/gtest/source_file_test.cpp +++ b/test/gtest/source_file_test.cpp @@ -67,10 +67,10 @@ TEST(UtilSourceFile, InputSources) { EXPECT_EQ(3u, sources.lineCount()); - cstring fl = sources.getLine(1); + auto fl = sources.getLine(1); EXPECT_EQ("First line\n", fl); - cstring sl = sources.getLine(2); + auto sl = sources.getLine(2); EXPECT_EQ("Second line\n", sl); SourceFileLine original = sources.getSourceLine(3); diff --git a/test/gtest/stringify.cpp b/test/gtest/stringify.cpp deleted file mode 100644 index 3abc316baf..0000000000 --- a/test/gtest/stringify.cpp +++ /dev/null @@ -1,69 +0,0 @@ -/* -Copyright 2018-present VMware, Inc. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ -#include "lib/stringify.h" - -#include - -#include - -#include "lib/cstring.h" - -namespace Test { -cstring appendFormat(const char *format, ...) { - va_list ap; - va_start(ap, format); - cstring str = Util::vprintf_format(format, ap); - va_end(ap); - return str; -} - -TEST(stringify, vprintf_simple) { - cstring str = appendFormat("%s", "AAA"); - EXPECT_EQ(str, "AAA"); -} - -TEST(stringify, vprintf_overflow) { - std::string c(129, 'A'); - cstring test_str = c; - cstring str = appendFormat("%s", test_str); - EXPECT_EQ(str.c_str(), test_str.c_str()); - EXPECT_EQ(str.size(), test_str.size()); -} - -TEST(stringify, vprintf_empty) { - cstring str = appendFormat("%s", ""); - EXPECT_EQ(str, ""); -} - -TEST(stringify, printf_simple) { - cstring str = Util::printf_format("%s", "AAA"); - EXPECT_EQ(str, "AAA"); -} - -TEST(stringify, printf_overflow) { - std::string c(129, 'A'); - cstring test_str = c; - cstring str = Util::printf_format("%s", test_str); - EXPECT_EQ(str.c_str(), test_str.c_str()); - EXPECT_EQ(str.size(), test_str.size()); -} - -TEST(stringify, printf_empty) { - cstring str = Util::printf_format("%s", ""); - EXPECT_EQ(str, ""); -} - -} // namespace Test