// Copyright (c) 2023 PaddlePaddle Authors. All Rights Reserved. // // 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 #include "glog/logging.h" // NOTE(zhangbo9674): File pd_op.h is generated by op_gen.py, see details in // paddle/fluid/pir/dialect/CMakeLists.txt. #include "paddle/common/errors.h" #include "paddle/fluid/pir/dialect/operator/interface/op_yaml_info.h" #include "paddle/fluid/pir/dialect/operator/ir/op_dialect.h" #include "paddle/fluid/pir/dialect/operator/ir/op_type.h" #include "paddle/fluid/pir/dialect/operator/ir/pd_op.h" #include "paddle/fluid/pir/dialect/operator/utils/utils.h" #include "paddle/phi/core/enforce.h" #include "paddle/phi/kernels/elementwise_add_kernel.h" #include "paddle/pir/include/core/builtin_dialect.h" #include "paddle/pir/include/core/builtin_op.h" #include "paddle/pir/include/core/builtin_type.h" #include "paddle/pir/include/core/dialect.h" #include "paddle/pir/include/core/ir_context.h" #include "paddle/pir/include/core/op_base.h" #include "paddle/pir/include/core/operation.h" #include "paddle/pir/include/pass/pass.h" #include "paddle/pir/include/pass/pass_manager.h" #include "test/cpp/pir/tools/macros_utils.h" #ifndef _WIN32 class TestAnalysis1 {}; class TestAnalysis2 {}; IR_DECLARE_EXPLICIT_TEST_TYPE_ID(TestAnalysis1) IR_DEFINE_EXPLICIT_TYPE_ID(TestAnalysis1) IR_DECLARE_EXPLICIT_TEST_TYPE_ID(TestAnalysis2) IR_DEFINE_EXPLICIT_TYPE_ID(TestAnalysis2) TEST(pass_manager, PreservedAnalyses) { pir::detail::PreservedAnalyses pa; PADDLE_ENFORCE_EQ(pa.IsNone(), true, common::errors::InvalidArgument( "Preserved analyses not exist. Expected exist.")); PADDLE_ENFORCE_EQ(pa.IsPreserved(), false, common::errors::InvalidArgument( "Test Analysis is preserved. Expected not.")); pa.Preserve(); PADDLE_ENFORCE_EQ(pa.IsPreserved(), true, common::errors::InvalidArgument( "Test Analysis not preserved. Expected preserved.")); pa.Unpreserve(); PADDLE_ENFORCE_EQ(pa.IsPreserved(), false, common::errors::InvalidArgument( "Test Analysis is preserved. Expected not.")); PADDLE_ENFORCE_EQ(pa.IsPreserved(), false, common::errors::InvalidArgument( "Test Analysis is preserved. Expected not.")); pa.Preserve(); PADDLE_ENFORCE_EQ(pa.IsPreserved(), true, common::errors::InvalidArgument( "Test Analysis not preserved. Expected preserved.")); PADDLE_ENFORCE_EQ(pa.IsPreserved(), true, common::errors::InvalidArgument( "Test Analysis not preserved. Expected preserved.")); PADDLE_ENFORCE_EQ( pa.IsAll(), false, common::errors::InvalidArgument("Test Analysis is all. Expected not.")); pa.PreserveAll(); PADDLE_ENFORCE_EQ( pa.IsAll(), true, common::errors::InvalidArgument("Test Analysis not all. Expected all.")); PADDLE_ENFORCE_EQ( pa.IsNone(), false, common::errors::InvalidArgument("Test Analysis is none. Expected not.")); } #endif class AddOp : public pir::Op { public: using Op::Op; static const char *name() { return "test.add"; } static constexpr const char **attributes_name = nullptr; static constexpr uint32_t attributes_num = 0; void VerifySig(); static void Build(pir::Builder &builder, // NOLINT pir::OperationArgument &argument, // NOLINT pir::Value l_operand, pir::Value r_operand, pir::Type sum_type); }; void AddOp::VerifySig() { if (num_operands() != 2) { PADDLE_THROW( common::errors::Fatal("The size of inputs must be equal to 2.")); } if (num_results() != 1) { PADDLE_THROW( common::errors::Fatal("The size of outputs must be equal to 1.")); } } void AddOp::Build(pir::Builder &, pir::OperationArgument &argument, pir::Value l_operand, pir::Value r_operand, pir::Type sum_type) { argument.AddInput(l_operand); argument.AddInput(r_operand); argument.AddOutput(sum_type); } IR_DECLARE_EXPLICIT_TEST_TYPE_ID(AddOp) IR_DEFINE_EXPLICIT_TYPE_ID(AddOp) struct CountOpAnalysis { explicit CountOpAnalysis(pir::Operation *container_op) { PADDLE_ENFORCE_GT( container_op->num_regions(), 0, common::errors::InvalidArgument( "op must be a container with zero or multiple regions.")); LOG(INFO) << "In CountOpAnalysis, op is " << container_op->name() << "\n"; for (size_t i = 0; i < container_op->num_regions(); ++i) { auto ®ion = container_op->region(i); for (auto &block : region) { count += block.size(); } } LOG(INFO) << "-- count is " << count << "\n"; } int count = 0; }; IR_DECLARE_EXPLICIT_TEST_TYPE_ID(CountOpAnalysis) IR_DEFINE_EXPLICIT_TYPE_ID(CountOpAnalysis) struct NoOperationAnalysis { int scale = 0; }; IR_DECLARE_EXPLICIT_TEST_TYPE_ID(NoOperationAnalysis) IR_DEFINE_EXPLICIT_TYPE_ID(NoOperationAnalysis) class TestPass : public pir::Pass { public: TestPass() : pir::Pass("TestPass", 1) {} void Run(pir::Operation *op) override { auto count_op_analysis = analysis_manager().GetAnalysis(); pass_state()->preserved_analyses.Preserve(); PADDLE_ENFORCE_EQ( pass_state()->preserved_analyses.IsPreserved(), true, common::errors::InvalidArgument( "Count op analysis not preserved. Expected preserved.")); auto no_operation_analysis = analysis_manager().GetAnalysis(); pass_state()->preserved_analyses.Preserve(); PADDLE_ENFORCE_EQ( pass_state()->preserved_analyses.IsPreserved(), true, common::errors::InvalidArgument( "No operation analysis not preserved. Expected preserved.")); PADDLE_ENFORCE_EQ(count_op_analysis.count, 11UL, common::errors::InvalidArgument( "Count op analysis mismatch. Expected 11.")); no_operation_analysis.scale = 8; PADDLE_ENFORCE_EQ( no_operation_analysis.scale, 8UL, common::errors::InvalidArgument( "Scale of no operation analysis mismatch. Expected 8.")); auto module_op = op->dyn_cast(); PADDLE_ENFORCE_EQ( module_op.operation(), op, common::errors::InvalidArgument("module op operation mismatch.")); PADDLE_ENFORCE_EQ( module_op.name(), module_op->name(), common::errors::InvalidArgument("module op name mismatch.")); LOG(INFO) << "In " << pass_info().name << ": " << module_op->name() << std::endl; pass_state()->preserved_analyses.Unpreserve(); PADDLE_ENFORCE_EQ( pass_state()->preserved_analyses.IsPreserved(), false, common::errors::InvalidArgument( "Count op analysis is preserved. Expected not.")); pass_state()->preserved_analyses.Unpreserve(); PADDLE_ENFORCE_EQ( pass_state()->preserved_analyses.IsPreserved(), false, common::errors::InvalidArgument( "No operation analysis is preserved. Expected not.")); } bool CanApplyOn(pir::Operation *op) const override { return op->isa<::pir::ModuleOp>() && op->num_regions() > 0; } }; void BuildProgram(pir::Builder &builder) { // NOLINT paddle::dialect::FullOp full_input_op = builder.Build(std::vector{4, 3, 16, 16}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace()); paddle::dialect::FullOp full_filter_op = builder.Build(std::vector{64, 3, 3, 3}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace()); paddle::dialect::FullOp full_mean_op = builder.Build( std::vector{64}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace()); paddle::dialect::FullOp full_variance_op = builder.Build(std::vector{64}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace()); paddle::dialect::FullOp full_scale_op = builder.Build(std::vector{64}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace()); paddle::dialect::FullOp full_bias_op = builder.Build( std::vector{64}, 1.5, phi::DataType::FLOAT32, phi::CPUPlace()); paddle::dialect::Conv2dOp conv2d_op = builder.Build(full_input_op.out(), full_filter_op.out()); paddle::dialect::BatchNormOp batch_norm_op = builder.Build(conv2d_op.out(), full_mean_op.out(), full_variance_op.out(), full_scale_op.out(), full_bias_op.out(), true, 0.9, 1e-6, "NCHW", false, false); auto transpose1_op = builder.Build( batch_norm_op.out(), std::vector{0, 2, 3, 1}); auto transpose2_op = builder.Build( transpose1_op.out(), std::vector{0, 3, 1, 2}); builder.Build(transpose2_op.out(), "out", 0); } TEST(pass_manager, PassManager) { pir::IrContext *ctx = pir::IrContext::Instance(); ctx->GetOrRegisterDialect(); pir::Program program(ctx); pir::Builder builder = pir::Builder(ctx, program.block()); BuildProgram(builder); EXPECT_EQ(program.block()->size(), 11u); // (9) Test pass manager for program. pir::PassManager pm(ctx); pm.AddPass(std::make_unique()); // pm.EnableIRPrinting(); pm.EnableIRPrinting(std::make_unique( [](pir::Pass *pass, pir::Operation *op) { return pass->name() == "TestPass"; }, [](pir::Pass *pass, pir::Operation *op) { return pass->name() == "TestPass"; }, true, true)); // pm.EnablePassTiming(true); PADDLE_ENFORCE_EQ( pm.Run(&program), true, common::errors::InvalidArgument("Program not run. Expected run.")); }