From 6ab10fcd9da58719f468ae4c7f4b94d71964911e Mon Sep 17 00:00:00 2001 From: 0x45f Date: Tue, 22 Aug 2023 03:20:54 +0000 Subject: [PATCH 1/5] Gen all Apis --- .../fluid/ir/dialect/op_generator/api_gen.py | 126 ++++++++++-------- .../paddle_dialect/ir/pd_manual_api.cc | 15 +-- .../dialect/paddle_dialect/ir/pd_manual_api.h | 7 +- 3 files changed, 72 insertions(+), 76 deletions(-) diff --git a/paddle/fluid/ir/dialect/op_generator/api_gen.py b/paddle/fluid/ir/dialect/op_generator/api_gen.py index 8432ebf2fade9..b9ece187beea5 100644 --- a/paddle/fluid/ir/dialect/op_generator/api_gen.py +++ b/paddle/fluid/ir/dialect/op_generator/api_gen.py @@ -64,7 +64,7 @@ {ret_type} {api_name}({args}){{ {in_combine} {compute_op} - {out_slice} + {out_split} {return_result} }} @@ -73,34 +73,15 @@ COMBINE_OP_TEMPLATE = """ auto {op_name} = APIBuilder::Instance().GetBuilder()->Build({in_name});""" -SLICE_OP_TEMPLATE = """ - auto {op_name} = APIBuilder::Instance().GetBuilder()->Build({in_name});""" +SPLIT_OP_TEMPLATE = """ + auto {op_name} = APIBuilder::Instance().GetBuilder()->Build({in_name});""" COMPUTE_OP_TEMPLATE = """ paddle::dialect::{op_class_name} {op_inst_name} = APIBuilder::Instance().GetBuilder()->Build({args});""" -API_LIST = [ - 'add_n', - 'mean', - 'sum', - 'divide', - 'full', - 'tanh_grad', - 'mean_grad', - 'concat', - 'add', - 'multiply', - 'elementwise_pow', - 'scale', - 'reshape', - 'expand', - 'tile', - 'add_grad', - 'divide_grad', - 'sum_grad', -] OP_RESULT = 'ir::OpResult' VECTOR_TYPE = 'ir::VectorType' +PD_MANUAL_OP_LIST = ['add_n'] def get_op_class_name(op_name): @@ -142,56 +123,70 @@ def _gen_api_inputs(self, op_info): ret.append(f'{self._type_map[type]} {name}') return ', '.join(ret) - def _gen_api_attrs(self, op_info, with_default): + def _gen_api_attrs(self, op_info, with_default, is_mutable_attr): name_list = op_info.attribute_name_list type_list = op_info.attribute_build_arg_type_list default_value_list = op_info.attribute_default_value_list + mutable_name_list = op_info.mutable_attribute_name_list assert len(name_list) == len(type_list) == len(default_value_list) - ret = [] + no_mutable_attr = [] + mutable_attr = [] for name, type, default_value in zip( name_list, type_list, default_value_list ): + if is_mutable_attr and name in mutable_name_list: + mutable_attr.append(f'{OP_RESULT} {name}') + continue if with_default and default_value is not None: if type in ['float', 'double']: default_value = default_value.strip('"') - ret.append( + no_mutable_attr.append( '{type} {name} = {default_value}'.format( type=type, name=name, default_value=default_value ) ) else: - ret.append(f'{type} {name}') - return ', '.join(ret) + no_mutable_attr.append(f'{type} {name}') + return ', '.join(mutable_attr + no_mutable_attr) - def _gen_api_args(self, op_info, with_default_attr): + def _gen_api_args(self, op_info, with_default_attr, is_mutable_attr): inputs = self._gen_api_inputs(op_info) - attrs = self._gen_api_attrs(op_info, with_default_attr) + attrs = self._gen_api_attrs(op_info, with_default_attr, is_mutable_attr) return (inputs + ', ' + attrs).strip(', ') def _gen_ret_type(self, op_info): type_list = op_info.output_type_list - assert len(type_list) >= 1 if len(type_list) > 1: return 'std::tuple<{}>'.format( ', '.join([self._type_map[type] for type in type_list]) ) elif len(type_list) == 1: return self._type_map[type_list[0]] + elif len(type_list) == 0: + return 'void' - def _gen_one_declare(self, op_info, op_name): + def _gen_one_declare(self, op_info, op_name, is_mutable_attr): return API_DECLARE_TEMPLATE.format( ret_type=self._gen_ret_type(op_info), api_name=op_name, - args=self._gen_api_args(op_info, True), + args=self._gen_api_args(op_info, True, is_mutable_attr), ) def _gen_h_file(self, op_info_items, namespaces, h_file_path): declare_str = '' for op_info in op_info_items: for op_name in op_info.op_phi_name: - if op_name not in API_LIST: + # NOTE:When infer_meta_func is None, the Build() function generated in pd_op + # is wrong, so temporarily skip the automatic generation of these APIs + if ( + op_info.infer_meta_func is None + and op_name not in PD_MANUAL_OP_LIST + ): continue - declare_str += self._gen_one_declare(op_info, op_name) + declare_str += self._gen_one_declare(op_info, op_name, False) + if len(op_info.mutable_attribute_name_list) > 0: + declare_str += self._gen_one_declare(op_info, op_name, True) + body = declare_str for namespace in reversed(namespaces): body = NAMESPACE_TEMPLATE.format(namespace=namespace, body=body) @@ -218,9 +213,13 @@ def _gen_in_combine(self, op_info): combine_op_list.append(None) return combine_op, combine_op_list - def _gen_compute_op_args(self, op_info, in_combine_op_list): + def _gen_compute_op_args( + self, op_info, in_combine_op_list, is_mutable_attr + ): input_name_list = op_info.input_name_list - attribute_name_list = op_info.attribute_name_list + all_attr_list = op_info.attribute_name_list + no_mutable_attr_list = op_info.non_mutable_attribute_name_list + mutable_attr_list = op_info.mutable_attribute_name_list assert len(input_name_list) == len(in_combine_op_list) ret = [] for input_name, combine_op in zip(input_name_list, in_combine_op_list): @@ -228,61 +227,69 @@ def _gen_compute_op_args(self, op_info, in_combine_op_list): ret.append(input_name) else: ret.append(f'{combine_op}.out()') - ret += list(attribute_name_list) + if is_mutable_attr: + ret += list(mutable_attr_list + no_mutable_attr_list) + else: + ret += list(all_attr_list) return ', '.join(ret) - def _gen_compute_op(self, op_info, op_name, in_combine_op_list): + def _gen_compute_op( + self, op_info, op_name, in_combine_op_list, is_mutable_attr + ): op_class_name = to_pascal_case(op_name) + 'Op' op_inst_name = op_name + '_op' return ( COMPUTE_OP_TEMPLATE.format( op_class_name=op_class_name, op_inst_name=op_inst_name, - args=self._gen_compute_op_args(op_info, in_combine_op_list), + args=self._gen_compute_op_args( + op_info, in_combine_op_list, is_mutable_attr + ), ), op_inst_name, ) - def _gen_out_slice_and_ret_list(self, op_info, op_inst_name): + def _gen_out_split_and_ret_list(self, op_info, op_inst_name): name_list = op_info.output_name_list type_list = op_info.output_type_list - slice_op_str = '' + split_op_str = '' ret_list = [] for i, (name, type) in enumerate(zip(name_list, type_list)): if VECTOR_TYPE in type: - slice_op_name = f'{name}_slice_op' - slice_op_str += SLICE_OP_TEMPLATE.format( - op_name=slice_op_name, in_name=f'{op_inst_name}.result({i})' + split_op_name = f'{name}_split_op' + split_op_str += SPLIT_OP_TEMPLATE.format( + op_name=split_op_name, in_name=f'{op_inst_name}.result({i})' ) - ret_list.append(f'{slice_op_name}.outputs()') + ret_list.append(f'{split_op_name}.outputs()') else: ret_list.append(f'{op_inst_name}.result({i})') - return slice_op_str, ret_list + return split_op_str, ret_list def _gen_return_result(self, ret_list): - assert len(ret_list) >= 1 if len(ret_list) > 1: return 'return std::make_tuple({});'.format(', '.join(ret_list)) - else: + elif len(ret_list) == 1: return f'return {ret_list[0]};' + elif len(ret_list) == 0: + return 'return;' - def _gen_one_impl(self, op_info, op_name): + def _gen_one_impl(self, op_info, op_name, is_mutable_attr): in_combine, in_combine_op_list = self._gen_in_combine(op_info) compute_op, op_inst_name = self._gen_compute_op( - op_info, op_name, in_combine_op_list + op_info, op_name, in_combine_op_list, is_mutable_attr ) - out_slice, ret_list = self._gen_out_slice_and_ret_list( + out_split, ret_list = self._gen_out_split_and_ret_list( op_info, op_inst_name ) ret = API_IMPL_TEMPLATE.format( ret_type=self._gen_ret_type(op_info), api_name=op_name, - args=self._gen_api_args(op_info, False), + args=self._gen_api_args(op_info, False, is_mutable_attr), in_combine=in_combine, compute_op=compute_op, - out_slice=out_slice, + out_split=out_split, return_result=self._gen_return_result(ret_list), ) @@ -293,9 +300,16 @@ def _gen_cpp_file(self, op_info_items, namespaces, cpp_file_path): impl_str = '' for op_info in op_info_items: for op_name in op_info.op_phi_name: - if op_name not in API_LIST: + # NOTE:When infer_meta_func is None, the Build() function generated in pd_op + # is wrong, so temporarily skip the automatic generation of these APIs + if ( + op_info.infer_meta_func is None + and op_name not in PD_MANUAL_OP_LIST + ): continue - impl_str += self._gen_one_impl(op_info, op_name) + impl_str += self._gen_one_impl(op_info, op_name, False) + if len(op_info.mutable_attribute_name_list) > 0: + impl_str += self._gen_one_impl(op_info, op_name, True) body = impl_str for namespace in reversed(namespaces): body = NAMESPACE_TEMPLATE.format(namespace=namespace, body=body) diff --git a/paddle/fluid/ir/dialect/paddle_dialect/ir/pd_manual_api.cc b/paddle/fluid/ir/dialect/paddle_dialect/ir/pd_manual_api.cc index 985e896d6e073..8866922e4aa34 100644 --- a/paddle/fluid/ir/dialect/paddle_dialect/ir/pd_manual_api.cc +++ b/paddle/fluid/ir/dialect/paddle_dialect/ir/pd_manual_api.cc @@ -18,18 +18,5 @@ #include "paddle/ir/core/builtin_op.h" namespace paddle { -namespace dialect { -std::vector concat_grad(std::vector x, - ir::OpResult out_grad, - ir::OpResult axis) { - auto combine_op = - APIBuilder::Instance().GetBuilder()->Build(x); - paddle::dialect::ConcatGradOp concat_grad_op = - APIBuilder::Instance().GetBuilder()->Build( - combine_op.out(), out_grad, axis); - auto split_op = APIBuilder::Instance().GetBuilder()->Build( - concat_grad_op.result(0)); - return split_op.outputs(); -} -} // namespace dialect +namespace dialect {} // namespace dialect } // namespace paddle diff --git a/paddle/fluid/ir/dialect/paddle_dialect/ir/pd_manual_api.h b/paddle/fluid/ir/dialect/paddle_dialect/ir/pd_manual_api.h index dff38ef565cb2..de86758dddba8 100644 --- a/paddle/fluid/ir/dialect/paddle_dialect/ir/pd_manual_api.h +++ b/paddle/fluid/ir/dialect/paddle_dialect/ir/pd_manual_api.h @@ -21,10 +21,5 @@ #include "paddle/phi/common/place.h" namespace paddle { -namespace dialect { - -std::vector concat_grad(std::vector x, - ir::OpResult out_grad, - ir::OpResult axis); -} // namespace dialect +namespace dialect {} // namespace dialect } // namespace paddle From 2b501541d321c9c6a55b820973222706a79e52f5 Mon Sep 17 00:00:00 2001 From: 0x45f Date: Tue, 22 Aug 2023 07:31:54 +0000 Subject: [PATCH 2/5] Gen python c apis --- .gitignore | 1 + .../ir/dialect/op_generator/python_c_gen.py | 344 ++++++++++++++++++ .../dialect/paddle_dialect/ir/CMakeLists.txt | 29 ++ paddle/fluid/pybind/eager_utils.cc | 22 +- paddle/fluid/pybind/eager_utils.h | 10 +- paddle/fluid/pybind/static_op_function.cc | 159 -------- paddle/fluid/pybind/static_op_function.h | 35 -- 7 files changed, 398 insertions(+), 202 deletions(-) create mode 100644 paddle/fluid/ir/dialect/op_generator/python_c_gen.py delete mode 100644 paddle/fluid/pybind/static_op_function.cc delete mode 100644 paddle/fluid/pybind/static_op_function.h diff --git a/.gitignore b/.gitignore index 478c7401241df..98a3d18b8a2a6 100644 --- a/.gitignore +++ b/.gitignore @@ -97,3 +97,4 @@ python/paddle/incubate/fleet/parameter_server/pslib/ps_pb2.py paddle/phi/kernels/fusion/cutlass/conv2d/generated/* python/paddle/fluid/incubate/fleet/parameter_server/pslib/ps_pb2.py paddle/fluid/ir_adaptor/translator/op_compat_info.cc +paddle/fluid/pybind/static_op_function.* diff --git a/paddle/fluid/ir/dialect/op_generator/python_c_gen.py b/paddle/fluid/ir/dialect/op_generator/python_c_gen.py new file mode 100644 index 0000000000000..f1109474ef454 --- /dev/null +++ b/paddle/fluid/ir/dialect/op_generator/python_c_gen.py @@ -0,0 +1,344 @@ +# 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. + +import argparse +import re + +from api_gen import ( + NAMESPACE_TEMPLATE, + OP_RESULT, + PD_MANUAL_OP_LIST, + VECTOR_TYPE, + CodeGen, +) + +H_FILE_TEMPLATE = """ + +#pragma once + +#include + +// Avoid a problem with copysign defined in pyconfig.h on Windows. +#ifdef copysign +#undef copysign +#endif + +{body} + +""" + +API_DECLARE_TEMPLATE = """ +PyObject *static_api_{name}(PyObject *self, PyObject *args, PyObject *kwargs); +""" + + +CPP_FILE_TEMPLATE = """ + +#include "paddle/fluid/pybind/static_op_function.h" +#include "paddle/fluid/ir/dialect/paddle_dialect/ir/pd_api.h" +#include "paddle/fluid/pybind/eager_utils.h" +#include "paddle/fluid/pybind/exception.h" +#include "paddle/fluid/pybind/op_function_common.h" +#include "paddle/phi/common/int_array.h" +#include "paddle/phi/core/enforce.h" + + +{body} + +""" + +NO_MUTABLE_ATTR_API_IMPL_TEMPLATE = """ +PyObject *static_api_{api_name}(PyObject *self, PyObject *args, PyObject *kwargs) {{ + try {{ + VLOG(6) << "Add {api_name} op into program"; + VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); + + // Get OpResult from args + {inputs} + + // Parse Attributes + {attrs} + + // Call ir static api + auto static_api_out = paddle::dialect::{api_name}({args}); + + return ToPyObject(static_api_out); + }} catch (...) {{ + ThrowExceptionToPython(std::current_exception()); + return nullptr; + }} +}} +""" + +INPUT_TEMPLATE = """ + PyObject *{name}_obj = PyTuple_GET_ITEM(args, {index}); + auto {name} = {cast_func}({name}_obj, "{api_name}", {index});""" + +NO_MUTABLE_ATTR_CAST_TEMPLATE = """ + PyObject *{name}_obj = PyTuple_GET_ITEM(args, {index}); + {type} {name} = {cast_func}({name}_obj, "{api_name}", {index});""" + +MUTABLE_ATTR_API_IMPL_TEMPLATE = """ +PyObject *static_api_{api_name}(PyObject *self, PyObject *args, PyObject *kwargs) {{ + try {{ + VLOG(6) << "Add {api_name} op into program"; + VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); + + // Get OpResult from args + {inputs} + + // Parse Attributes + {attrs_py_obj} + + // Check for mutable attrs + bool has_mutable_attr = false; + {check_mutable_attrs} + + if (has_mutable_attr){{ + {cast_attrs_with_mutable} + // Call ir static api + auto static_api_out = paddle::dialect::{api_name}({args_with_mutable_attrs}); + return ToPyObject(static_api_out); + }} else {{ + {cast_attrs_without_mutable} + // Call ir static api + auto static_api_out = paddle::dialect::{api_name}({args_without_mutable_attrs}); + return ToPyObject(static_api_out); + }} + }} catch (...) {{ + ThrowExceptionToPython(std::current_exception()); + return nullptr; + }} +}} +""" + +CHECK_MUTABLE_ATTR_TEMPLATE = """ + if (PyObject_CheckIROpResult({name}_obj)){{ + has_mutable_attr = true; + }}""" + +MUTABLE_ATTR_OBJ_TEMPLATE = """ + PyObject *{name}_obj = PyTuple_GET_ITEM(args, {index});""" + +MUTABLE_ATTR_CAST_TEMPLATE = """ + {type} {name} = {cast_func}({name}_obj, "{api_name}", {index});""" + + +TYPE_TO_FUNC_MAP = { + "bool": "CastPyArg2Boolean", + "int": "CastPyArg2Int", + "long": "CastPyArg2Long", + "int64_t": "CastPyArg2Long", + "float": "CastPyArg2Float", + "double": "CastPyArg2Double", + "std::string": "CastPyArg2String", + "std::vector": "CastPyArg2Booleans", + "std::vector": "CastPyArg2Ints", + "std::vector": "CastPyArg2Longs", + "std::vector": "CastPyArg2Longs", + "std::vector": "CastPyArg2Floats", + "std::vector": "CastPyArg2Float64s", + "std::vector": "CastPyArg2Strings", + "paddle::experimental::Scalar": "CastPyArg2Scalar", + "std::vector": "CastPyArg2ScalarArray", + "paddle::experimental::IntArray": "CastPyArg2IntArray", + "paddle::Place": "CastPyArg2Place", + "Place": "CastPyArg2Place", + "phi::DataType": "CastPyArg2DataType", +} + + +class PythonCCodeGen(CodeGen): + def __init__(self) -> None: + super().__init__() + + def _gen_one_declare(self, op_name): + return API_DECLARE_TEMPLATE.format(name=op_name) + + def _gen_h_file(self, op_info_items, namespaces, h_file_path): + declare_str = '' + for op_info in op_info_items: + for op_name in op_info.op_phi_name: + # NOTE:When infer_meta_func is None, the Build() function generated in pd_op + # is wrong, so temporarily skip the automatic generation of these APIs + if ( + op_info.infer_meta_func is None + and op_name not in PD_MANUAL_OP_LIST + ): + continue + declare_str += self._gen_one_declare(op_name) + + body = declare_str + for namespace in reversed(namespaces): + body = NAMESPACE_TEMPLATE.format(namespace=namespace, body=body) + with open(h_file_path, 'w') as f: + f.write(H_FILE_TEMPLATE.format(body=body)) + + def _gen_inputs(self, op_info, op_name): + name_list = op_info.input_name_list + type_list = op_info.input_type_list + assert len(name_list) == len(type_list) + ret = '' + for i, (name, type) in enumerate(zip(name_list, type_list)): + cast_func = ( + 'CastPyArg2VectorOfOpResult' + if VECTOR_TYPE in type + else 'CastPyArg2OpResult' + ) + ret += INPUT_TEMPLATE.format( + name=name, index=i, cast_func=cast_func, api_name=op_name + ) + return ret + + def _gen_attrs_without_mutable(self, op_info, op_name): + input_size = len(op_info.input_name_list) + name_list = op_info.attribute_name_list + type_list = op_info.attribute_build_arg_type_list + assert len(name_list) == len(type_list) + ret = '' + for i, (name, type) in enumerate(zip(name_list, type_list)): + type = type.replace('const ', '').replace('&', '') + cast_func = TYPE_TO_FUNC_MAP[type] + ret += NO_MUTABLE_ATTR_CAST_TEMPLATE.format( + name=name, + index=input_size + i, + type=type, + cast_func=cast_func, + api_name=op_name, + ) + return ret + + def _gen_attrs_py_obj_with_mutable(self, op_info): + input_size = len(op_info.input_name_list) + name_list = op_info.attribute_name_list + ret = '' + for i, name in enumerate(name_list): + ret += MUTABLE_ATTR_OBJ_TEMPLATE.format( + name=name, index=input_size + i + ) + return ret + + def _gen_check_mutable_attrs(self, op_info): + name_list = op_info.mutable_attribute_name_list + ret = '' + for name in name_list: + ret += CHECK_MUTABLE_ATTR_TEMPLATE.format(name=name) + return ret + + def _gen_cast_attrs(self, op_info, op_name, with_mutable): + input_size = len(op_info.input_name_list) + attr_name_list = op_info.attribute_name_list + attr_type_list = op_info.attribute_build_arg_type_list + mutable_attr_name_list = op_info.mutable_attribute_name_list + assert len(attr_name_list) == len(attr_type_list) + ret = '' + for i, (name, type) in enumerate(zip(attr_name_list, attr_type_list)): + type = type.replace('const ', '').replace('&', '') + cast_func = TYPE_TO_FUNC_MAP[type] + if with_mutable and name in mutable_attr_name_list: + type = OP_RESULT + cast_func = 'CastPyArg2OpResult' + ret += MUTABLE_ATTR_CAST_TEMPLATE.format( + type=type, + name=name, + cast_func=cast_func, + api_name=op_name, + index=input_size + i, + ) + return ret + + def _gen_one_impl(self, op_info, op_name): + input_name_list = op_info.input_name_list + attr_name_list = op_info.attribute_name_list + mutable_attr_name_list = op_info.mutable_attribute_name_list + no_mutable_attr_name_list = op_info.non_mutable_attribute_name_list + if len(mutable_attr_name_list) > 0: + ret = MUTABLE_ATTR_API_IMPL_TEMPLATE.format( + api_name=op_name, + inputs=self._gen_inputs(op_info, op_name), + attrs_py_obj=self._gen_attrs_py_obj_with_mutable(op_info), + check_mutable_attrs=self._gen_check_mutable_attrs(op_info), + cast_attrs_with_mutable=self._gen_cast_attrs( + op_info, op_name, True + ), + args_with_mutable_attrs=', '.join( + input_name_list + + mutable_attr_name_list + + no_mutable_attr_name_list + ), + cast_attrs_without_mutable=self._gen_cast_attrs( + op_info, op_name, False + ), + args_without_mutable_attrs=', '.join( + input_name_list + attr_name_list + ), + ) + else: + ret = NO_MUTABLE_ATTR_API_IMPL_TEMPLATE.format( + api_name=op_name, + inputs=self._gen_inputs(op_info, op_name), + attrs=self._gen_attrs_without_mutable(op_info, op_name), + args=', '.join(input_name_list + attr_name_list), + ) + ret = re.sub(r' +\n', '', ret) + return ret + + def _gen_cpp_file(self, op_info_items, namespaces, cpp_file_path): + impl_str = '' + for op_info in op_info_items: + for op_name in op_info.op_phi_name: + # NOTE:When infer_meta_func is None, the Build() function generated in pd_op + # is wrong, so temporarily skip the automatic generation of these APIs + if ( + op_info.infer_meta_func is None + and op_name not in PD_MANUAL_OP_LIST + ): + continue + impl_str += self._gen_one_impl(op_info, op_name) + body = impl_str + for namespace in reversed(namespaces): + body = NAMESPACE_TEMPLATE.format(namespace=namespace, body=body) + with open(cpp_file_path, 'w') as f: + f.write(CPP_FILE_TEMPLATE.format(body=body)) + + +def ParseArguments(): + parser = argparse.ArgumentParser( + description='Generate Dialect Python C Files By Yaml' + ) + parser.add_argument('--op_yaml_files', type=str) + parser.add_argument('--op_compat_yaml_file', type=str) + parser.add_argument('--namespaces', type=str) + parser.add_argument('--python_c_def_h_file', type=str) + parser.add_argument('--python_c_def_cc_file', type=str) + return parser.parse_args() + + +if __name__ == '__main__': + args = ParseArguments() + op_yaml_files = args.op_yaml_files.split(",") + op_compat_yaml_file = args.op_compat_yaml_file + if args.namespaces is not None: + namespaces = args.namespaces.split(",") + python_c_def_h_file = args.python_c_def_h_file + python_c_def_cc_file = args.python_c_def_cc_file + + code_gen = PythonCCodeGen() + code_gen.gen_h_and_cpp_file( + op_yaml_files, + op_compat_yaml_file, + namespaces, + python_c_def_h_file, + python_c_def_cc_file, + ) diff --git a/paddle/fluid/ir/dialect/paddle_dialect/ir/CMakeLists.txt b/paddle/fluid/ir/dialect/paddle_dialect/ir/CMakeLists.txt index ee84abd7f3270..247907e271078 100644 --- a/paddle/fluid/ir/dialect/paddle_dialect/ir/CMakeLists.txt +++ b/paddle/fluid/ir/dialect/paddle_dialect/ir/CMakeLists.txt @@ -71,6 +71,35 @@ add_custom_command( ${op_compat_yaml_file} VERBATIM) +set(python_c_gen_file + ${PADDLE_SOURCE_DIR}/paddle/fluid/ir/dialect/op_generator/python_c_gen.py) +set(python_c_header_file + ${PADDLE_SOURCE_DIR}/paddle/fluid/pybind/static_op_function.h) +set(python_c_source_file + ${PADDLE_SOURCE_DIR}/paddle/fluid/pybind/static_op_function.cc) +set(python_c_header_file_tmp ${python_c_header_file}.tmp) +set(python_c_source_file_tmp ${python_c_source_file}.tmp) + +add_custom_command( + OUTPUT ${python_c_header_file} ${python_c_source_file} + COMMAND + ${PYTHON_EXECUTABLE} ${python_c_gen_file} --op_yaml_files ${op_yaml_files} + --op_compat_yaml_file ${op_compat_yaml_file} --namespaces "paddle,pybind" + --python_c_def_h_file ${python_c_header_file_tmp} --python_c_def_cc_file + ${python_c_source_file_tmp} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${python_c_header_file_tmp} + ${python_c_header_file} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${python_c_source_file_tmp} + ${python_c_source_file} + COMMENT "copy_if_different ${python_c_header_file} ${python_c_source_file}" + DEPENDS ${python_c_gen_file} ${op_forward_yaml_file1} ${op_forward_yaml_file2} + ${op_backward_yaml_file1} ${op_backward_yaml_file2} + ${op_compat_yaml_file} + VERBATIM) + +add_custom_target(static_op_function_gen ALL DEPENDS ${python_c_header_file} + ${python_c_source_file}) + cc_library( pd_dialect_core SRCS pd_attribute.cc pd_type.cc diff --git a/paddle/fluid/pybind/eager_utils.cc b/paddle/fluid/pybind/eager_utils.cc index dcd2953acaba0..1245c7516c542 100644 --- a/paddle/fluid/pybind/eager_utils.cc +++ b/paddle/fluid/pybind/eager_utils.cc @@ -136,6 +136,10 @@ bool PyObject_CheckFloatOrConvertToFloat(PyObject** obj) { bool PyObject_CheckStr(PyObject* obj) { return PyUnicode_Check(obj); } +bool PyObject_CheckIROpResult(PyObject* obj) { + return PyObject_TypeCheck(obj, g_ir_opresult_pytype); +} + bool CastPyArg2AttrBoolean(PyObject* obj, ssize_t arg_pos) { if (obj == Py_None) { return false; // To be compatible with QA integration testing. Some @@ -884,6 +888,16 @@ PyObject* ToPyObject(const ir::OpResult& value) { return obj.ptr(); } +PyObject* ToPyObject(const std::vector& value) { + PyObject* result = PyList_New((Py_ssize_t)value.size()); + + for (size_t i = 0; i < value.size(); i++) { + PyList_SET_ITEM(result, static_cast(i), ToPyObject(value[i])); + } + + return result; +} + #ifdef PADDLE_WITH_DISTRIBUTE PyObject* ToPyObject(const phi::distributed::DistTensor* value) { auto obj = ::pybind11::cast(value, py::return_value_policy::reference); @@ -1453,8 +1467,8 @@ paddle::experimental::Scalar CastNumpy2Scalar(PyObject* obj, } } -ir::OpResult CastPyArg2OpResult(const std::string& op_type, - PyObject* obj, +ir::OpResult CastPyArg2OpResult(PyObject* obj, + const std::string& op_type, size_t arg_pos) { if (PyObject_TypeCheck(obj, g_ir_opresult_pytype)) { return ::pybind11::handle(obj).cast(); @@ -1468,8 +1482,8 @@ ir::OpResult CastPyArg2OpResult(const std::string& op_type, } } -std::vector CastPyArg2VectorOfOpResult(const std::string& op_type, - PyObject* obj, +std::vector CastPyArg2VectorOfOpResult(PyObject* obj, + const std::string& op_type, size_t arg_pos) { std::vector result_list; if (PyList_Check(obj)) { diff --git a/paddle/fluid/pybind/eager_utils.h b/paddle/fluid/pybind/eager_utils.h index fbf5da4e6c5d7..9dc8359d410fe 100644 --- a/paddle/fluid/pybind/eager_utils.h +++ b/paddle/fluid/pybind/eager_utils.h @@ -58,6 +58,7 @@ int TensorDtype2NumpyDtype(phi::DataType dtype); bool PyObject_CheckLongOrConvertToLong(PyObject** obj); bool PyObject_CheckFloatOrConvertToFloat(PyObject** obj); bool PyObject_CheckStr(PyObject* obj); +bool PyObject_CheckIROpResult(PyObject* obj); bool CastPyArg2AttrBoolean(PyObject* obj, ssize_t arg_pos); int CastPyArg2AttrInt(PyObject* obj, ssize_t arg_pos); int64_t CastPyArg2AttrLong(PyObject* obj, ssize_t arg_pos); @@ -76,11 +77,11 @@ std::vector CastPyArg2VectorOfInt(PyObject* obj, size_t arg_pos); std::vector CastPyArg2VectorOfInt64(PyObject* obj, size_t arg_pos); std::vector CastPyArg2VectorOfSize_t(PyObject* obj, size_t arg_pos); std::vector CastPyArg2VectorOfFloat(PyObject* obj, size_t arg_pos); -ir::OpResult CastPyArg2OpResult(const std::string& op_type, - PyObject* obj, +ir::OpResult CastPyArg2OpResult(PyObject* obj, + const std::string& op_type, size_t arg_pos); -std::vector CastPyArg2VectorOfOpResult(const std::string& op_type, - PyObject* obj, +std::vector CastPyArg2VectorOfOpResult(PyObject* obj, + const std::string& op_type, size_t arg_pos); std::vector> CastPyArg2VectorOfVectorOfSize_t( PyObject* obj, size_t arg_pos); @@ -135,6 +136,7 @@ PyObject* ToPyObject(const paddle::framework::Vocab& value); PyObject* ToPyObject(std::shared_ptr grad_node); PyObject* ToPyObject(const ir::OpResult& value); +PyObject* ToPyObject(const std::vector& value); class PyTensorHook : public egr::TensorHook { public: diff --git a/paddle/fluid/pybind/static_op_function.cc b/paddle/fluid/pybind/static_op_function.cc deleted file mode 100644 index 7923f0d569f6b..0000000000000 --- a/paddle/fluid/pybind/static_op_function.cc +++ /dev/null @@ -1,159 +0,0 @@ -// 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 "paddle/fluid/pybind/static_op_function.h" -#include "paddle/fluid/ir/dialect/paddle_dialect/ir/pd_api.h" -#include "paddle/fluid/pybind/eager_utils.h" -#include "paddle/fluid/pybind/exception.h" -#include "paddle/fluid/pybind/op_function_common.h" -#include "paddle/phi/common/int_array.h" -#include "paddle/phi/core/enforce.h" - -namespace paddle { -namespace pybind { -PyObject *static_api_add_n(PyObject *self, PyObject *args, PyObject *kwargs) { - try { - VLOG(6) << "Add add_n op into program"; - VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); - // Get OpResult from args - PyObject *x_obj = PyTuple_GET_ITEM(args, 0); - auto x = CastPyArg2VectorOfOpResult("add_n", x_obj, 0); - - // Parse Attributes if needed - - // Call ir static api - auto out = paddle::dialect::add_n(x); - return ToPyObject(out); - } catch (...) { - ThrowExceptionToPython(std::current_exception()); - return nullptr; - } -} -PyObject *static_api_mean(PyObject *self, PyObject *args, PyObject *kwargs) { - try { - VLOG(6) << "Add mean op into program"; - VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); - // Get OpResult from args - PyObject *x_obj = PyTuple_GET_ITEM(args, 0); - auto x = CastPyArg2OpResult("mean", x_obj, 0); - - // Parse Attributes if needed - PyObject *axis_obj = PyTuple_GET_ITEM(args, 1); - paddle::experimental::IntArray axis = - CastPyArg2IntArray(axis_obj, "mean", 1); - PyObject *keepdim_obj = PyTuple_GET_ITEM(args, 2); - bool keepdim = CastPyArg2Boolean(keepdim_obj, "mean", 2); - - // Call ir static api - auto out = paddle::dialect::mean(x, axis.GetData(), keepdim); - return ToPyObject(out); - } catch (...) { - ThrowExceptionToPython(std::current_exception()); - return nullptr; - } -} - -PyObject *static_api_sum(PyObject *self, PyObject *args, PyObject *kwargs) { - try { - VLOG(6) << "Add sum op into program"; - VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); - // Get OpResult from args - PyObject *x_obj = PyTuple_GET_ITEM(args, 0); - auto x = CastPyArg2OpResult("sum", x_obj, 0); - - // Parse Attributes if needed - PyObject *axis_obj = PyTuple_GET_ITEM(args, 1); - paddle::experimental::IntArray axis = - CastPyArg2IntArray(axis_obj, "sum", 1); - PyObject *dtype_obj = PyTuple_GET_ITEM(args, 2); - phi::DataType dtype = CastPyArg2DataType(dtype_obj, "sum", 2); - PyObject *keepdim_obj = PyTuple_GET_ITEM(args, 3); - bool keepdim = CastPyArg2Boolean(keepdim_obj, "sum", 3); - - // Call ir static api - auto out = paddle::dialect::sum(x, axis.GetData(), dtype, keepdim); - return ToPyObject(out); - } catch (...) { - ThrowExceptionToPython(std::current_exception()); - return nullptr; - } -} - -PyObject *static_api_divide(PyObject *self, PyObject *args, PyObject *kwargs) { - try { - VLOG(6) << "Add divide op into program"; - VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); - // Get OpResult from args - PyObject *x_obj = PyTuple_GET_ITEM(args, 0); - auto x = CastPyArg2OpResult("divide", x_obj, 0); - PyObject *y_obj = PyTuple_GET_ITEM(args, 1); - auto y = CastPyArg2OpResult("divide", y_obj, 1); - - // Call ir static api - auto out = paddle::dialect::divide(x, y); - return ToPyObject(out); - } catch (...) { - ThrowExceptionToPython(std::current_exception()); - return nullptr; - } -} - -PyObject *static_api_concat(PyObject *self, PyObject *args, PyObject *kwargs) { - try { - VLOG(6) << "Add concat op into program"; - VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); - // Get OpResult from args - PyObject *x_obj = PyTuple_GET_ITEM(args, 0); - auto x = CastPyArg2VectorOfOpResult("concat", x_obj, 0); - - PyObject *axis_obj = PyTuple_GET_ITEM(args, 1); - paddle::experimental::Scalar axis = CastPyArg2Scalar(axis_obj, "concat", 1); - - // Call ir static api - auto out = paddle::dialect::concat(x, axis.to()); - return ToPyObject(out); - } catch (...) { - ThrowExceptionToPython(std::current_exception()); - return nullptr; - } -} - -PyObject *static_api_full(PyObject *self, PyObject *args, PyObject *kwargs) { - try { - VLOG(6) << "Add full op into program"; - VLOG(8) << "args count: " << (PyTuple_Size(args) / 2); - - // Parse Attributes if needed - PyObject *shape_obj = PyTuple_GET_ITEM(args, 0); - paddle::experimental::IntArray shape = - CastPyArg2IntArray(shape_obj, "full", 0); - PyObject *value_obj = PyTuple_GET_ITEM(args, 1); - paddle::experimental::Scalar value = CastPyArg2Scalar(value_obj, "full", 1); - PyObject *dtype_obj = PyTuple_GET_ITEM(args, 2); - phi::DataType dtype = CastPyArg2DataTypeDirectly(dtype_obj, "full", 2); - PyObject *place_obj = PyTuple_GET_ITEM(args, 3); - paddle::Place place = CastPyArg2Place(place_obj, "full", 3); - - // Call ir static api - auto out = - paddle::dialect::full(shape.GetData(), value.to(), dtype, place); - return ToPyObject(out); - } catch (...) { - ThrowExceptionToPython(std::current_exception()); - return nullptr; - } -} - -} // namespace pybind -} // namespace paddle diff --git a/paddle/fluid/pybind/static_op_function.h b/paddle/fluid/pybind/static_op_function.h deleted file mode 100644 index 02d4777eeef05..0000000000000 --- a/paddle/fluid/pybind/static_op_function.h +++ /dev/null @@ -1,35 +0,0 @@ -// 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. - -#pragma once - -#include - -// Avoid a problem with copysign defined in pyconfig.h on Windows. -#ifdef copysign -#undef copysign -#endif - -namespace paddle { -namespace pybind { - -PyObject *static_api_add_n(PyObject *self, PyObject *args, PyObject *kwargs); -PyObject *static_api_mean(PyObject *self, PyObject *args, PyObject *kwargs); -PyObject *static_api_sum(PyObject *self, PyObject *args, PyObject *kwargs); -PyObject *static_api_divide(PyObject *self, PyObject *args, PyObject *kwargs); -PyObject *static_api_concat(PyObject *self, PyObject *args, PyObject *kwargs); -PyObject *static_api_full(PyObject *self, PyObject *args, PyObject *kwargs); - -} // namespace pybind -} // namespace paddle From 07d2372c2b91825cf67f9f0196ee107d3a3aafa8 Mon Sep 17 00:00:00 2001 From: 0x45f Date: Tue, 22 Aug 2023 08:00:46 +0000 Subject: [PATCH 3/5] Add empty file --- paddle/fluid/pybind/generate_file_structures.py | 1 + 1 file changed, 1 insertion(+) diff --git a/paddle/fluid/pybind/generate_file_structures.py b/paddle/fluid/pybind/generate_file_structures.py index 62968784ca8dd..966c512a31eb2 100644 --- a/paddle/fluid/pybind/generate_file_structures.py +++ b/paddle/fluid/pybind/generate_file_structures.py @@ -22,6 +22,7 @@ empty_files = [os.path.join(pybind_dir, "eager_legacy_op_function.cc")] empty_files.append(os.path.join(pybind_dir, "eager_op_function.cc")) + empty_files.append(os.path.join(pybind_dir, "static_op_function.cc")) for path in empty_files: if not os.path.exists(path): From c94653da24a40c10d9e08b5755ac2d0eaddbffc5 Mon Sep 17 00:00:00 2001 From: 0x45f Date: Wed, 23 Aug 2023 09:37:08 +0000 Subject: [PATCH 4/5] Fix cast data type --- paddle/fluid/ir/dialect/op_generator/python_c_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/paddle/fluid/ir/dialect/op_generator/python_c_gen.py b/paddle/fluid/ir/dialect/op_generator/python_c_gen.py index f1109474ef454..4510864baac5a 100644 --- a/paddle/fluid/ir/dialect/op_generator/python_c_gen.py +++ b/paddle/fluid/ir/dialect/op_generator/python_c_gen.py @@ -155,7 +155,7 @@ "paddle::experimental::IntArray": "CastPyArg2IntArray", "paddle::Place": "CastPyArg2Place", "Place": "CastPyArg2Place", - "phi::DataType": "CastPyArg2DataType", + "phi::DataType": "CastPyArg2DataTypeDirectly", } From 451de9e4de0db9a525953ecf78c1d32ba2378c02 Mon Sep 17 00:00:00 2001 From: 0x45f Date: Wed, 23 Aug 2023 12:45:29 +0000 Subject: [PATCH 5/5] Fix None dtype --- paddle/fluid/pybind/eager_utils.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/paddle/fluid/pybind/eager_utils.cc b/paddle/fluid/pybind/eager_utils.cc index 70ff183ebcc01..c1e7c2759c9a4 100644 --- a/paddle/fluid/pybind/eager_utils.cc +++ b/paddle/fluid/pybind/eager_utils.cc @@ -651,6 +651,10 @@ paddle::framework::proto::VarType::Type CastPyArg2ProtoType(PyObject* obj, paddle::DataType CastPyArg2DataTypeDirectly(PyObject* obj, const std::string& op_type, ssize_t arg_pos) { + if (obj == Py_None) { + return phi::DataType::UNDEFINED; + } + paddle::DataType dtype; if (PyObject_TypeCheck(obj, g_data_type_pytype)) { dtype = ::pybind11::handle(obj).cast();