diff --git a/backends/p4tools/modules/testgen/core/program_info.cpp b/backends/p4tools/modules/testgen/core/program_info.cpp index 3175193dd2c..c6a19ecd181 100644 --- a/backends/p4tools/modules/testgen/core/program_info.cpp +++ b/backends/p4tools/modules/testgen/core/program_info.cpp @@ -83,8 +83,7 @@ void ProgramInfo::produceCopyInOutCall(const IR::Parameter *param, size_t paramI } const auto *archPath = new IR::PathExpression(paramType, new IR::Path(archRef)); const auto *paramRef = new IR::PathExpression(paramType, new IR::Path(param->name)); - const auto *paramDir = - new IR::StringLiteral(IR::Type_String::get(), directionToString(param->direction)); + const auto *paramDir = IR::getStringLiteral(directionToString(param->direction)); if (copyIns != nullptr) { // This mimicks the copy-in from the architecture environment. const auto *copyInCall = new IR::MethodCallStatement(Utils::generateInternalMethodCall( 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 d9b612d9e62..00eaffb1849 100644 --- a/backends/p4tools/modules/testgen/core/small_step/expr_stepper.cpp +++ b/backends/p4tools/modules/testgen/core/small_step/expr_stepper.cpp @@ -303,7 +303,7 @@ bool ExprStepper::preorder(const IR::PathExpression *pathExpression) { // If the path expression is a Type_MatchKind, convert it to a StringLiteral. if (pathExpression->type->is()) { state.replaceTopBody(Continuation::Return( - new IR::StringLiteral(IR::Type_MatchKind::get(), pathExpression->path->name))); + IR::getStringLiteral(pathExpression->path->name, IR::Type_MatchKind::get()))); result->emplace_back(state); return false; } 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 2f76e6f98e5..c2368cc8499 100644 --- a/backends/p4tools/modules/testgen/core/small_step/table_stepper.cpp +++ b/backends/p4tools/modules/testgen/core/small_step/table_stepper.cpp @@ -148,8 +148,7 @@ const IR::Expression *TableStepper::computeHit(TableMatchMap *matches) { const IR::StringLiteral *TableStepper::getTableActionString( const IR::MethodCallExpression *actionCall) { - cstring actionName = actionCall->method->toString(); - return new IR::StringLiteral(IR::Type_String::get(), actionName); + return IR::getStringLiteral(actionCall->method->toString()); } const IR::Expression *TableStepper::evalTableConstEntries() { diff --git a/backends/p4tools/modules/testgen/core/small_step/table_stepper.h b/backends/p4tools/modules/testgen/core/small_step/table_stepper.h index bf68f347178..19d05e256c0 100644 --- a/backends/p4tools/modules/testgen/core/small_step/table_stepper.h +++ b/backends/p4tools/modules/testgen/core/small_step/table_stepper.h @@ -73,7 +73,8 @@ class TableStepper { /// Sets the action taken by the given table. The arguments in the given MethodCallExpression /// are assumed to be symbolic values. - const IR::StringLiteral *getTableActionString(const IR::MethodCallExpression *actionCall); + static const IR::StringLiteral *getTableActionString( + const IR::MethodCallExpression *actionCall); /// A helper function to iteratively resolve table keys into symbolic values. /// This function returns false, if no key needs to be resolved. diff --git a/backends/p4tools/modules/testgen/targets/bmv2/program_info.cpp b/backends/p4tools/modules/testgen/targets/bmv2/program_info.cpp index eae3da95b67..927636c8523 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/program_info.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/program_info.cpp @@ -120,7 +120,7 @@ std::vector Bmv2V1ModelProgramInfo::processDeclaration( std::vector cmds; // Copy-in. const auto *copyInCall = new IR::MethodCallStatement(Utils::generateInternalMethodCall( - "copy_in", {new IR::StringLiteral(typeDecl->name)}, IR::Type_Void::get(), + "copy_in", {IR::getStringLiteral(typeDecl->name)}, IR::Type_Void::get(), new IR::ParameterList( {new IR::Parameter("blockRef", IR::Direction::In, IR::Type_Unknown::get())}))); cmds.emplace_back(copyInCall); @@ -128,7 +128,7 @@ std::vector Bmv2V1ModelProgramInfo::processDeclaration( cmds.emplace_back(typeDecl); // Copy-out. const auto *copyOutCall = new IR::MethodCallStatement(Utils::generateInternalMethodCall( - "copy_out", {new IR::StringLiteral(typeDecl->name)}, IR::Type_Void::get(), + "copy_out", {IR::getStringLiteral(typeDecl->name)}, IR::Type_Void::get(), new IR::ParameterList( {new IR::Parameter("blockRef", IR::Direction::In, IR::Type_Unknown::get())}))); cmds.emplace_back(copyOutCall); diff --git a/backends/p4tools/modules/testgen/targets/ebpf/program_info.cpp b/backends/p4tools/modules/testgen/targets/ebpf/program_info.cpp index e2687d95af0..45a35d07df6 100644 --- a/backends/p4tools/modules/testgen/targets/ebpf/program_info.cpp +++ b/backends/p4tools/modules/testgen/targets/ebpf/program_info.cpp @@ -85,7 +85,7 @@ std::vector EBPFProgramInfo::processDeclaration( // Copy-in. const auto *copyInCall = new IR::MethodCallStatement(Utils::generateInternalMethodCall( - "copy_in", {new IR::StringLiteral(typeDecl->name)}, IR::Type_Void::get(), + "copy_in", {IR::getStringLiteral(typeDecl->name)}, IR::Type_Void::get(), new IR::ParameterList( {new IR::Parameter("blockRef", IR::Direction::In, IR::Type_Unknown::get())}))); cmds.emplace_back(copyInCall); @@ -93,7 +93,7 @@ std::vector EBPFProgramInfo::processDeclaration( cmds.emplace_back(typeDecl); // Copy-out. const auto *copyOutCall = new IR::MethodCallStatement(Utils::generateInternalMethodCall( - "copy_out", {new IR::StringLiteral(typeDecl->name)}, IR::Type_Void::get(), + "copy_out", {IR::getStringLiteral(typeDecl->name)}, IR::Type_Void::get(), new IR::ParameterList( {new IR::Parameter("blockRef", IR::Direction::In, IR::Type_Unknown::get())}))); cmds.emplace_back(copyOutCall); 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 66c8ac2d382..cdc2c8bd9e1 100644 --- a/backends/p4tools/modules/testgen/targets/pna/dpdk/program_info.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/dpdk/program_info.cpp @@ -9,6 +9,7 @@ #include "backends/p4tools/common/lib/util.h" #include "ir/id.h" #include "ir/ir.h" +#include "ir/irutils.h" #include "lib/cstring.h" #include "lib/exceptions.h" @@ -69,7 +70,7 @@ std::vector PnaDpdkProgramInfo::processDeclaration( std::vector cmds; // Copy-in. const auto *copyInCall = new IR::MethodCallStatement(Utils::generateInternalMethodCall( - "copy_in", {new IR::StringLiteral(typeDecl->name)}, IR::Type_Void::get(), + "copy_in", {IR::getStringLiteral(typeDecl->name)}, IR::Type_Void::get(), new IR::ParameterList( {new IR::Parameter("blockRef", IR::Direction::In, IR::Type_Unknown::get())}))); cmds.emplace_back(copyInCall); @@ -77,7 +78,7 @@ std::vector PnaDpdkProgramInfo::processDeclaration( cmds.emplace_back(typeDecl); // Copy-out. const auto *copyOutCall = new IR::MethodCallStatement(Utils::generateInternalMethodCall( - "copy_out", {new IR::StringLiteral(typeDecl->name)}, IR::Type_Void::get(), + "copy_out", {IR::getStringLiteral(typeDecl->name)}, IR::Type_Void::get(), new IR::ParameterList( {new IR::Parameter("blockRef", IR::Direction::In, IR::Type_Unknown::get())}))); cmds.emplace_back(copyOutCall); diff --git a/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp b/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp index d3aa65a47b3..08f39568eaa 100644 --- a/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp +++ b/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp @@ -84,51 +84,49 @@ TEST_F(Z3SolverSatisfiabilityChecks, Strings) { const auto *fooVar = P4Tools::ToolsVariables::getSymbolicVariable(stringType, "foo"); const auto *barVar = P4Tools::ToolsVariables::getSymbolicVariable(stringType, "bar"); { - auto *expression = new IR::Equ(new IR::StringLiteral(stringType, "dead"), - new IR::StringLiteral(stringType, "dead")); + auto *expression = new IR::Equ(IR::getStringLiteral("dead"), IR::getStringLiteral("dead")); ConstraintVector inputExpression = {expression}; testCheckSat(inputExpression, true); } { - auto *expression = new IR::Equ(new IR::StringLiteral(stringType, "dead"), - new IR::StringLiteral(stringType, "beef")); + auto *expression = new IR::Equ(IR::getStringLiteral("dead"), IR::getStringLiteral("beef")); ConstraintVector inputExpression = {expression}; testCheckSat(inputExpression, false); } { - auto *expression = new IR::Equ(fooVar, new IR::StringLiteral(stringType, "dead")); + auto *expression = new IR::Equ(fooVar, IR::getStringLiteral("dead")); ConstraintVector inputExpression = {expression}; testCheckSat(inputExpression, true); } { - auto *expression = new IR::Equ(fooVar, new IR::StringLiteral(stringType, "dead")); - auto *constraint1 = new IR::Equ(fooVar, new IR::StringLiteral(stringType, "dead")); + auto *expression = new IR::Equ(fooVar, IR::getStringLiteral("dead")); + auto *constraint1 = new IR::Equ(fooVar, IR::getStringLiteral("dead")); ConstraintVector inputExpression = {expression, constraint1}; testCheckSat(inputExpression, true); } { auto *expression = new IR::Equ(fooVar, barVar); - auto *constraint1 = new IR::Equ(fooVar, new IR::StringLiteral(stringType, "dead")); + auto *constraint1 = new IR::Equ(fooVar, IR::getStringLiteral("dead")); ConstraintVector inputExpression = {expression, constraint1}; testCheckSat(inputExpression, true); } { auto *expression = new IR::Equ(fooVar, barVar); - auto *constraint1 = new IR::Equ(fooVar, new IR::StringLiteral(stringType, "dead")); - auto *constraint2 = new IR::Equ(barVar, new IR::StringLiteral(stringType, "dead")); + auto *constraint1 = new IR::Equ(fooVar, IR::getStringLiteral("dead")); + auto *constraint2 = new IR::Equ(barVar, IR::getStringLiteral("dead")); ConstraintVector inputExpression = {expression, constraint1, constraint2}; testCheckSat(inputExpression, true); } { - auto *expression = new IR::Equ(fooVar, new IR::StringLiteral(stringType, "dead")); - auto *constraint1 = new IR::Equ(fooVar, new IR::StringLiteral(stringType, "beef")); + auto *expression = new IR::Equ(fooVar, IR::getStringLiteral("dead")); + auto *constraint1 = new IR::Equ(fooVar, IR::getStringLiteral("beef")); ConstraintVector inputExpression = {expression, constraint1}; testCheckSat(inputExpression, false); } { auto *expression = new IR::Equ(fooVar, barVar); - auto *constraint1 = new IR::Equ(fooVar, new IR::StringLiteral(stringType, "dead")); - auto *constraint2 = new IR::Equ(barVar, new IR::StringLiteral(stringType, "beef")); + auto *constraint1 = new IR::Equ(fooVar, IR::getStringLiteral("dead")); + auto *constraint2 = new IR::Equ(barVar, IR::getStringLiteral("beef")); ConstraintVector inputExpression = {expression, constraint1, constraint2}; testCheckSat(inputExpression, false); } diff --git a/ir/irutils.cpp b/ir/irutils.cpp index e4913aaed7e..aea71296db3 100644 --- a/ir/irutils.cpp +++ b/ir/irutils.cpp @@ -72,6 +72,22 @@ const BoolLiteral *getBoolLiteral(bool value, const Util::SourceInfo &srcInfo) { return result; } +const IR::StringLiteral *getStringLiteral(cstring value, const IR::Type *type, + const Util::SourceInfo &srcInfo) { + if (type == nullptr) { + type = Type::String::get(); + } + // String literals are interned. + using key_t = std::pair; + static std::map STRINGS; + + auto *&result = STRINGS[{value, type}]; + if (result == nullptr) { + result = new IR::StringLiteral(srcInfo, type, value); + } + return result; +} + const IR::Constant *convertBoolLiteral(const IR::BoolLiteral *lit) { return IR::getConstant(IR::getBitType(1), lit->value ? 1 : 0, lit->getSourceInfo()); } diff --git a/ir/irutils.h b/ir/irutils.h index 9da6df6d475..82fa76f78f8 100644 --- a/ir/irutils.h +++ b/ir/irutils.h @@ -13,6 +13,7 @@ namespace IR { // Forward-declare some IR classes that are used in function declarations. class BoolLiteral; +class StringLiteral; class Constant; class Expression; class BaseListExpression; @@ -50,6 +51,10 @@ const Constant *getConstant(const Type *type, big_int v, const Util::SourceInfo /// @returns a bool literal. The value is cached. const BoolLiteral *getBoolLiteral(bool value, const Util::SourceInfo &srcInfo = {}); +/// @returns a string literal. If @param type is nullptr, Type_String is used. The value is cached. +const StringLiteral *getStringLiteral(cstring value, const Type *type = nullptr, + const Util::SourceInfo &srcInfo = {}); + /// @returns a constant with the maximum big_int value that can fit into this bit width. /// Implicitly converts boolean types to a bit vector of width one with value 1. const IR::Constant *getMaxValueConstant(const Type *t, const Util::SourceInfo &srcInfo = {});