// Copyright (c) 2024 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 "paddle/fluid/pir/utils/name_analysis.h" #include #include "paddle/fluid/pir/dialect/kernel/ir/kernel_op.h" #include "paddle/fluid/pir/dialect/operator/ir/pd_op.h" namespace pir { namespace utils { namespace name_analysis { Value GetOutputValueByName(const Program &program, const std::string &name) { auto &block = *program.block(); StrAttribute name_attr = StrAttribute::get(IrContext::Instance(), name); Value value; for (auto &op : block) { if (op.isa()) { if (op.attribute("output_name") == name_attr) { if (value) { PADDLE_THROW(common::errors::PreconditionNotMet( "More than one shadow output named with %s found.", name)); } value = op.operand_source(0); } } else if (op.isa() || op.isa() || op.isa()) { if (op.attribute("name") == name_attr) { if (value) { PADDLE_THROW(common::errors::PreconditionNotMet( "More than one feed/fetch named with %s found.", name)); } value = op.result(0); } } } return value; } Value GetValueByNameInPhiKernelProgram(const Program &program, const std::string &name) { auto &block = *program.block(); StrAttribute name_attr = StrAttribute::get(IrContext::Instance(), name); Value value; for (auto &op : block) { if (op.isa()) { if (op.attribute("output_name") == name_attr) { if (value) { PADDLE_THROW(common::errors::PreconditionNotMet( "More than one shadow output named with %s found.", name)); } value = op.operand_source(0); } } else if (op.isa()) { if (op.attribute("op_name").dyn_cast().AsString() == "pd_op.data") { if (op.attribute("name") == name_attr) { if (value) { PADDLE_THROW(common::errors::PreconditionNotMet( "More than one feed/fetch named with %s found.", name)); } value = op.result(0); } } } } return value; } Value GetParameterValueByName(const Program &program, const std::string &name) { auto &block = *program.block(); StrAttribute name_attr = StrAttribute::get(IrContext::Instance(), name); Value value; for (auto &op : block) { if (op.isa()) { if (op.attribute("parameter_name") == name_attr) { if (value) { PADDLE_THROW(common::errors::PreconditionNotMet( "More than one parameter named with %s found.", name)); } value = op.result(0); } } } return value; } std::unordered_map GetAllParameterValues( const Program &program) { auto &block = *program.block(); std::unordered_map values; for (auto &op : block) { if (op.isa()) { values [op.attribute("parameter_name").dyn_cast().AsString()] = op.result(0); } } return values; } void SetValueName(Value value, const std::string name) { Operation *define_op = value.defining_op(); if (define_op->isa()) { define_op->set_attribute("parameter_name", StrAttribute::get(IrContext::Instance(), name)); } else if (define_op->isa()) { define_op->set_attribute("name", StrAttribute::get(IrContext::Instance(), name)); } else if (auto block_arg = value.dyn_cast()) { PADDLE_THROW(common::errors::InvalidArgument( "Can Not set name for BlockArgument! ")); } else if (value.first_use()) { auto nextOp = value.first_use().owner(); if (nextOp->isa()) { nextOp->set_attribute("output_name", StrAttribute::get(IrContext::Instance(), name)); } else { PADDLE_THROW(common::errors::InvalidArgument( "Currently, we can only set name of Value which is " "shadowoutput ")); } } else { PADDLE_THROW(common::errors::InvalidArgument( "Currently, we can only set name of Value that " "is persistable")); } } std::map RenameValue(Value value, const std::string &new_name, Block *block) { std::map rename_mapping; VLOG(5) << "Starting to rename value to " << new_name; // Handle kwarg for (auto [name, kwarg] : block->kwargs()) { if (kwarg == value) { if (name == new_name) { break; } Value new_value; if (block->kwargs().count(new_name)) { new_value = block->kwargs().at(new_name); } else { new_value = block->AddKwarg(new_name, value.type()); } value.ReplaceAllUsesWith(new_value); block->EraseKwarg(name); value = new_value; VLOG(5) << "Value is kwarg, rename it from " << name << " to " << new_name; rename_mapping.insert({name, new_name}); break; } } // Handle inputs auto defining_op = value.defining_op(); if (defining_op) { // Handle DataOp if (defining_op->isa()) { auto name = defining_op->attribute("name").AsString(); if (name != new_name) { defining_op->set_attribute( "name", StrAttribute::get(IrContext::Instance(), new_name)); VLOG(5) << "Value is defined by DataOp, rename it from " << name << " to " << new_name; rename_mapping.insert({name, new_name}); } } // Handle ParameterOp if (defining_op->isa()) { auto name = defining_op->attribute("parameter_name").AsString(); if (name != new_name) { defining_op->set_attribute( "parameter_name", StrAttribute::get(IrContext::Instance(), new_name)); VLOG(5) << "Value is defined by ParameterOp, rename it from " << name << " to " << new_name; rename_mapping.insert({name, new_name}); } } // Handle ConstantTensorOp if (defining_op->isa()) { auto name = defining_op->attribute("tensor_name").AsString(); if (name != new_name) { defining_op->set_attribute( "tensor_name", StrAttribute::get(IrContext::Instance(), new_name)); VLOG(5) << "Value is defined by ConstantTensorOp, rename it from " << name << " to " << new_name; rename_mapping.insert({name, new_name}); } } } // Handle outputs for (auto iter = value.use_begin(); iter != value.use_end(); ++iter) { auto user_op = iter->owner(); if (user_op->isa()) { // Handle ShadowOutputOp auto name = user_op->attribute("output_name").AsString(); if (name == new_name) { continue; } user_op->set_attribute( "output_name", StrAttribute::get(IrContext::Instance(), new_name)); VLOG(5) << "Value is used by ShadowOutputOp, rename it from " << name << " to " << new_name; rename_mapping.insert({name, new_name}); } else if (user_op->isa()) { // Handle SetParameterOp auto name = user_op->attribute("parameter_name").AsString(); if (name == new_name) { continue; } user_op->set_attribute( "parameter_name", StrAttribute::get(IrContext::Instance(), new_name)); VLOG(5) << "Value is used by SetParameterOp, rename it from " << name << " to " << new_name; rename_mapping.insert({name, new_name}); } } return rename_mapping; } std::optional GetValueInputName(Value value) { std::optional name; if (auto block_arg = value.dyn_cast()) { if (block_arg.is_kwarg()) { name = block_arg.keyword(); } else { name = "arg_" + std::to_string(block_arg.index()); } } else if (auto param_op = value.defining_op()) { name = param_op.param_name(); } else if (auto data_op = value.defining_op()) { name = data_op.attribute("name").AsString(); } else if (auto constant_op = value.defining_op()) { name = constant_op.tensor_name(); } return name; } std::vector GetValueOutputNames(Value value) { std::vector names; for (auto iter = value.use_begin(); iter != value.use_end(); ++iter) { if (iter->owner()->isa()) { names.push_back( iter->owner()->attribute("output_name").AsString()); } else if (iter->owner()->isa()) { names.push_back( iter->owner()->attribute("parameter_name").AsString()); } } return names; } std::vector GetValueAllNames(Value value) { std::vector names; std::optional input_name = GetValueInputName(value); if (input_name.has_value()) { names.push_back(input_name.value()); } std::vector output_name = GetValueOutputNames(value); for (auto &name : output_name) { names.push_back(name); } return names; } std::optional TryGetValueFirstName(Value value) { std::optional name; auto names = GetValueAllNames(value); if (!names.empty()) { return names[0]; } return name; } std::string GetValueFirstName(Value value) { auto name = TryGetValueFirstName(value); PADDLE_ENFORCE(name.has_value(), common::errors::InvalidArgument( "Currently, we can only get name of Value from " "DataOp/ParameterOp/BlockArgument/ConstantTensorOp/" "SetParameterOp and ShadowOutputOp.")); return name.value(); } std::unordered_map GetAllNamedValues( const Program &program) { std::unordered_map named_values; std::vector all_values; all_values.insert(all_values.end(), program.block()->args().begin(), program.block()->args().end()); for (const auto &[k, v] : program.block()->kwargs()) { all_values.push_back(v); } for (auto op : program.block()->ops()) { for (auto var : op->results()) { all_values.push_back(var); } } for (auto &value : all_values) { std::optional name = TryGetValueFirstName(value); if (!name.has_value()) { continue; } named_values[name.value()] = value; } return named_values; } } // namespace name_analysis } // namespace utils } // namespace pir