diff --git a/backends/bmv2/pna_nic/midend.cpp b/backends/bmv2/pna_nic/midend.cpp index ac096f09843..adbb5f09c79 100644 --- a/backends/bmv2/pna_nic/midend.cpp +++ b/backends/bmv2/pna_nic/midend.cpp @@ -131,7 +131,7 @@ PnaNicMidEnd::PnaNicMidEnd(CompilerOptions &options, std::ostream *outStream) new P4::StrengthReduction(&typeMap), new P4::EliminateTuples(&refMap, &typeMap), new P4::SimplifyComparisons(&refMap, &typeMap), - new P4::CopyStructures(&refMap, &typeMap), + new P4::CopyStructures(&refMap, &typeMap, P4::CopyStructuresConfig()), new P4::NestedStructs(&refMap, &typeMap), new P4::SimplifySelectList(&refMap, &typeMap), new P4::RemoveSelectBooleans(&refMap, &typeMap), diff --git a/backends/bmv2/psa_switch/midend.cpp b/backends/bmv2/psa_switch/midend.cpp index 6a3a14bfb92..e8f1e462c49 100644 --- a/backends/bmv2/psa_switch/midend.cpp +++ b/backends/bmv2/psa_switch/midend.cpp @@ -131,7 +131,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions &options, std::ostream *outStre new P4::StrengthReduction(&typeMap), new P4::EliminateTuples(&refMap, &typeMap), new P4::SimplifyComparisons(&refMap, &typeMap), - new P4::CopyStructures(&refMap, &typeMap), + new P4::CopyStructures(&refMap, &typeMap, P4::CopyStructuresConfig()), new P4::NestedStructs(&refMap, &typeMap), new P4::SimplifySelectList(&refMap, &typeMap), new P4::RemoveSelectBooleans(&refMap, &typeMap), diff --git a/backends/bmv2/simple_switch/midend.cpp b/backends/bmv2/simple_switch/midend.cpp index ba04ca27794..51b0f47f572 100644 --- a/backends/bmv2/simple_switch/midend.cpp +++ b/backends/bmv2/simple_switch/midend.cpp @@ -100,7 +100,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions &options, std::ostream *o new P4::StrengthReduction(&typeMap), new P4::EliminateTuples(&refMap, &typeMap), new P4::SimplifyComparisons(&refMap, &typeMap), - new P4::CopyStructures(&refMap, &typeMap), + new P4::CopyStructures(&refMap, &typeMap, P4::CopyStructuresConfig()), new P4::NestedStructs(&refMap, &typeMap), new P4::SimplifySelectList(&refMap, &typeMap), new P4::RemoveSelectBooleans(&refMap, &typeMap), diff --git a/backends/dpdk/midend.cpp b/backends/dpdk/midend.cpp index 87d1f3d319b..e81ef9e78ed 100644 --- a/backends/dpdk/midend.cpp +++ b/backends/dpdk/midend.cpp @@ -195,7 +195,12 @@ DpdkMidEnd::DpdkMidEnd(CompilerOptions &options, std::ostream *outStream) { new P4::StrengthReduction(&typeMap), new P4::EliminateTuples(&refMap, &typeMap), new P4::SimplifyComparisons(&refMap, &typeMap), - new P4::CopyStructures(&refMap, &typeMap, false /* errorOnMethodCall */), + new P4::CopyStructures(&refMap, &typeMap, + P4::CopyStructuresConfig{ + /*errorOnMethodCall*/ false, + /*copyHeaders*/ false, + /*expandUnions*/ true, + }), new P4::NestedStructs(&refMap, &typeMap), new P4::SimplifySelectList(&refMap, &typeMap), new P4::RemoveSelectBooleans(&refMap, &typeMap), diff --git a/backends/p4test/midend.cpp b/backends/p4test/midend.cpp index 3cd139a1b1e..8fcbfa9cf34 100644 --- a/backends/p4test/midend.cpp +++ b/backends/p4test/midend.cpp @@ -103,7 +103,12 @@ MidEnd::MidEnd(CompilerOptions &options, std::ostream *outStream) { new P4::StrengthReduction(&typeMap), new P4::EliminateTuples(&refMap, &typeMap), new P4::SimplifyComparisons(&refMap, &typeMap), - new P4::CopyStructures(&refMap, &typeMap, false), + new P4::CopyStructures(&refMap, &typeMap, + P4::CopyStructuresConfig{ + /*errorOnMethodCall*/ false, + /*copyHeaders*/ false, + /*expandUnions*/ true, + }), new P4::NestedStructs(&refMap, &typeMap), new P4::StrengthReduction(&typeMap), new P4::SimplifySelectList(&refMap, &typeMap), diff --git a/backends/p4tools/common/compiler/midend.cpp b/backends/p4tools/common/compiler/midend.cpp index 5b42a3a6f30..e96935184c1 100644 --- a/backends/p4tools/common/compiler/midend.cpp +++ b/backends/p4tools/common/compiler/midend.cpp @@ -123,7 +123,13 @@ void MidEnd::addDefaultPasses() { new P4::SimplifyComparisons(&refMap, &typeMap), // Expand header and struct assignments into sequences of field assignments. new PassRepeated({ - new P4::CopyStructures(&refMap, &typeMap, false, true, nullptr), + new P4::CopyStructures(&refMap, &typeMap, + { + /*errorOnMethodCall*/ false, + /*copyHeaders*/ true, + /*expandUnions*/ false, + }, + nullptr), }), new P4::RemoveParserControlFlow(&typeMap), // Flatten nested list expressions. diff --git a/backends/ubpf/midend.cpp b/backends/ubpf/midend.cpp index d28974025d7..bd6cd6cefac 100644 --- a/backends/ubpf/midend.cpp +++ b/backends/ubpf/midend.cpp @@ -94,7 +94,7 @@ const IR::ToplevelBlock *MidEnd::run(EbpfOptions &options, const IR::P4Program * new P4::StrengthReduction(&typeMap), }), new P4::SimplifyComparisons(&refMap, &typeMap), - new P4::CopyStructures(&refMap, &typeMap), + new P4::CopyStructures(&refMap, &typeMap, P4::CopyStructuresConfig()), new P4::LocalCopyPropagation(&refMap, &typeMap), new P4::SimplifySelectList(&refMap, &typeMap), new P4::MoveDeclarations(), // more may have been introduced diff --git a/midend/copyStructures.cpp b/midend/copyStructures.cpp index a7f1faa12fc..706e43fd26c 100644 --- a/midend/copyStructures.cpp +++ b/midend/copyStructures.cpp @@ -73,13 +73,14 @@ const IR::Node *DoCopyStructures::postorder(IR::AssignmentStatement *statement) FIXME: this is not correct for header unions and should be fixed. The fix bellow, commented-out, causes problems elsewhere. https://github.com/p4lang/p4c/issues/3842 - if (ltype->is()) - return statement; */ + if (!_config.expandUnions && ltype->is()) { + return statement; + } // Do not copy structures for method calls. if (statement->right->is()) { - if (errorOnMethodCall) { + if (_config.errorOnMethodCall) { ::P4::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "%1%: functions or methods returning structures " "are not supported on this target", @@ -98,7 +99,7 @@ const IR::Node *DoCopyStructures::postorder(IR::AssignmentStatement *statement) retval->push_back( new IR::AssignmentStatement(statement->srcInfo, left, right->expression)); } - } else if (copyHeaders && ltype->is()) { + } else if (_config.copyHeaders && ltype->is()) { const auto *header = ltype->checkedTo(); // Build a "src.isValid()" call. const auto *isSrcValidCall = new IR::MethodCallExpression( diff --git a/midend/copyStructures.h b/midend/copyStructures.h index 5c2e92545b5..75504fc6437 100644 --- a/midend/copyStructures.h +++ b/midend/copyStructures.h @@ -22,6 +22,21 @@ limitations under the License. namespace P4 { +struct CopyStructuresConfig { + /// Specific targets may allow functions or methods to return structs. + /// Such methods will not be converted in this pass. Setting the + /// errorOnMethodCall flag will produce an error message if such a + /// method is encountered. + bool errorOnMethodCall = true; + + /// Do not only copy normal structures but also perform copy assignments for headers. + bool copyHeaders = false; + /// Also expand header union assignments. + /// TODO: This is only necessary because the copy structure pass does not correctly expand + /// header unions for some back ends. + bool expandUnions = true; +}; + /** * Convert assignments between structures to assignments between fields * @@ -53,19 +68,15 @@ namespace P4 { * */ class DoCopyStructures : public Transform { + /// The type map. TypeMap *typeMap; - /// Specific targets may allow functions or methods to return structs. - /// Such methods will not be converted in this pass. Setting the - /// errorOnMethodCall flag will produce an error message if such a - /// method is encountered. - bool errorOnMethodCall; - /// Do not only copy normal structures but also perform copy assignments for headers. - bool copyHeaders; + /// Configuration options. + CopyStructuresConfig _config; public: - explicit DoCopyStructures(TypeMap *typeMap, bool errorOnMethodCall, bool copyHeaders = false) - : typeMap(typeMap), errorOnMethodCall(errorOnMethodCall), copyHeaders(copyHeaders) { + explicit DoCopyStructures(TypeMap *typeMap, CopyStructuresConfig config) + : typeMap(typeMap), _config(config) { CHECK_NULL(typeMap); setName("DoCopyStructures"); } @@ -111,8 +122,8 @@ class RemoveAliases : public Transform { class CopyStructures : public PassRepeated { public: - explicit CopyStructures(ReferenceMap *refMap, TypeMap *typeMap, bool errorOnMethodCall = true, - bool copyHeaders = false, TypeChecking *typeChecking = nullptr) + explicit CopyStructures(ReferenceMap *refMap, TypeMap *typeMap, CopyStructuresConfig config, + TypeChecking *typeChecking = nullptr) : PassManager({}) { CHECK_NULL(refMap); CHECK_NULL(typeMap); @@ -123,7 +134,7 @@ class CopyStructures : public PassRepeated { passes.emplace_back(typeChecking); passes.emplace_back(new RemoveAliases(refMap, typeMap)); passes.emplace_back(typeChecking); - passes.emplace_back(new DoCopyStructures(typeMap, errorOnMethodCall, copyHeaders)); + passes.emplace_back(new DoCopyStructures(typeMap, config)); } }; diff --git a/test/gtest/midend_pass.cpp b/test/gtest/midend_pass.cpp index 667727b01b6..c8dad52565b 100644 --- a/test/gtest/midend_pass.cpp +++ b/test/gtest/midend_pass.cpp @@ -84,7 +84,7 @@ MidEnd::MidEnd(CompilerOptions &options, std::ostream *outStream) { new P4::StrengthReduction(&typeMap), new P4::EliminateTuples(&refMap, &typeMap), new P4::SimplifyComparisons(&refMap, &typeMap), - new P4::CopyStructures(&refMap, &typeMap), + new P4::CopyStructures(&refMap, &typeMap, P4::CopyStructuresConfig()), new P4::NestedStructs(&refMap, &typeMap), new P4::StrengthReduction(&typeMap), new P4::SimplifySelectList(&refMap, &typeMap),