// 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. #pragma once #include #include "paddle/ap/include/adt/adt.h" #include "paddle/ap/include/code_module/func_declare.h" #include "paddle/ap/include/code_module/project.h" namespace ap::code_module { struct ApiWrapperProjectMaker { adt::Result Make(const std::vector& func_declares) { ADT_LET_CONST_REF(nested_files, MakeNestedFiles(func_declares)); ADT_LET_CONST_REF(compile_cmd, GetCompileCmd()); ADT_LET_CONST_REF(so_relative_path, GetSoRelativePath()); axpr::AttrMap others; return Project{nested_files, compile_cmd, so_relative_path, others}; } adt::Result> MakeNestedFiles( const std::vector& func_declares) { Directory directory; ADT_LET_CONST_REF(file_content, GenerateApiWrapperCFileContent(func_declares)); directory.dentry2file->Set("api_wrapper.c", FileContent{file_content}); return directory; } adt::Result GenerateApiWrapperCFileContent( const std::vector& func_declares) { std::ostringstream ss; ss << "#include " << std::endl << std::endl; for (const auto& func_declare : func_declares) { ADT_RETURN_IF_ERR(GenerateCCode4FuncDeclare(&ss, func_declare)); ss << std::endl; } return ss.str(); } adt::Result GenerateCCode4FuncDeclare( std::ostringstream* ss, const FuncDeclare& func_declare) { (*ss) << "void " << func_declare->func_id << "(void* ret, void* f, void** args) {" << std::endl; ADT_LET_CONST_REF(func_ptr_var, DeclareFuncPtrType(func_declare, "func")); (*ss) << " " << func_ptr_var << " = f" << ";\n"; ADT_LET_CONST_REF(func_call_str, GenerateFuncCall(func_declare, "func", "args")); if (IsVoidRet(func_declare)) { (*ss) << " " << func_call_str << ";\n"; } else { ADT_LET_CONST_REF(ret_type, GenCode4ArgType(func_declare->ret_type)); (*ss) << " *(" << ret_type << "*)ret = " << func_call_str << ";\n"; } (*ss) << "}\n" << std::endl; return adt::Ok{}; } bool IsVoidRet(const FuncDeclare& func_declare) { return func_declare->ret_type.Match( [&](const axpr::DataType& data_type) -> bool { return data_type.template Has>(); }, [&](const axpr::PointerType& pointer_type) -> bool { return false; }); } adt::Result GenerateFuncCall(const FuncDeclare& func_declare, const std::string& func_var_name, const std::string& args_var_name) { std::ostringstream ss; ss << func_var_name << "("; for (size_t i = 0; i < func_declare->arg_types->size(); ++i) { if (i > 0) { ss << ", "; } const auto& arg_type = func_declare->arg_types->at(i); ADT_LET_CONST_REF(arg_type_str, GenCode4ArgType(arg_type)); ss << "*(" << arg_type_str << "*)" << args_var_name << "[" << i << "]"; } ss << ")"; return ss.str(); } adt::Result DeclareFuncPtrType(const FuncDeclare& func_declare, const std::string& func_name) { std::ostringstream ss; ADT_LET_CONST_REF(ret_type, GenCode4ArgType(func_declare->ret_type)); ss << ret_type << "(*" << func_name << ")("; int i = 0; for (const auto& arg_type : *func_declare->arg_types) { if (i++ > 0) { ss << ", "; } ADT_LET_CONST_REF(arg_type_str, GenCode4ArgType(arg_type)); ss << arg_type_str; } ss << ")"; return ss.str(); } adt::Result GenCode4ArgType(const ArgType& arg_type) { return arg_type.Match( [&](const axpr::DataType& data_type) -> adt::Result { return GenCode4DataType(data_type); }, [&](const axpr::PointerType& pointer_type) -> adt::Result { return GenCode4PointerType(pointer_type); }); } adt::Result GenCode4DataType(const axpr::DataType& data_type) { using RetT = adt::Result; return data_type.Match( [&](axpr::CppDataType) -> RetT { return "bool"; }, [&](axpr::CppDataType) -> RetT { return "int8_t"; }, [&](axpr::CppDataType) -> RetT { return "uint8_t"; }, [&](axpr::CppDataType) -> RetT { return "int16_t"; }, [&](axpr::CppDataType) -> RetT { return "uint16_t"; }, [&](axpr::CppDataType) -> RetT { return "int32_t"; }, [&](axpr::CppDataType) -> RetT { return "uint32_t"; }, [&](axpr::CppDataType) -> RetT { return "int64_t"; }, [&](axpr::CppDataType) -> RetT { return "uint64_t"; }, [&](axpr::CppDataType) -> RetT { return "float"; }, [&](axpr::CppDataType) -> RetT { return "double"; }, [&](axpr::CppDataType) -> RetT { return adt::errors::TypeError{ "bfloat16 is not supported in SO function calls; use float or " "half " "(if available) as an alternative"}; }, [&](axpr::CppDataType) -> RetT { return adt::errors::TypeError{ "float8_e4m3fn is not supported in SO function calls; consider " "using " "higher-precision floating-point types"}; }, [&](axpr::CppDataType) -> RetT { return adt::errors::TypeError{ "float8_e5m2 is not supported in SO function calls; consider " "using " "higher-precision floating-point types"}; }, [&](axpr::CppDataType) -> RetT { return adt::errors::TypeError{ "float16 (half precision) is not supported in SO function calls; " "use " "float instead if possible"}; }, [&](axpr::CppDataType) -> RetT { return adt::errors::TypeError{ "complex64 is not supported in SO function calls; decompose into " "real and imaginary parts manually"}; }, [&](axpr::CppDataType) -> RetT { return adt::errors::TypeError{ "complex128 is not supported in SO function calls; handle " "complex " "arithmetic explicitly"}; }, [&](axpr::CppDataType) -> RetT { return adt::errors::TypeError{ "pstring is not supported in SO function calls; use const char* " "or " "void* with length metadata instead"}; }, [&](axpr::CppDataType) -> RetT { return "void"; }); } adt::Result GenCode4PointerType( const axpr::PointerType& pointer_type) { using RetT = adt::Result; return pointer_type.Match( [&](axpr::CppPointerType) -> RetT { return "bool*"; }, [&](axpr::CppPointerType) -> RetT { return "int8_t*"; }, [&](axpr::CppPointerType) -> RetT { return "uint8_t*"; }, [&](axpr::CppPointerType) -> RetT { return "int16_t*"; }, [&](axpr::CppPointerType) -> RetT { return "uint16_t*"; }, [&](axpr::CppPointerType) -> RetT { return "int32_t*"; }, [&](axpr::CppPointerType) -> RetT { return "uint32_t*"; }, [&](axpr::CppPointerType) -> RetT { return "int64_t*"; }, [&](axpr::CppPointerType) -> RetT { return "uint64_t*"; }, [&](axpr::CppPointerType) -> RetT { return "float*"; }, [&](axpr::CppPointerType) -> RetT { return "double*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "bool*"; }, [&](axpr::CppPointerType) -> RetT { return "int8_t*"; }, [&](axpr::CppPointerType) -> RetT { return "uint8_t*"; }, [&](axpr::CppPointerType) -> RetT { return "int16_t*"; }, [&](axpr::CppPointerType) -> RetT { return "uint16_t*"; }, [&](axpr::CppPointerType) -> RetT { return "int32_t*"; }, [&](axpr::CppPointerType) -> RetT { return "uint32_t*"; }, [&](axpr::CppPointerType) -> RetT { return "int64_t*"; }, [&](axpr::CppPointerType) -> RetT { return "uint64_t*"; }, [&](axpr::CppPointerType) -> RetT { return "float*"; }, [&](axpr::CppPointerType) -> RetT { return "double*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }, [&](axpr::CppPointerType) -> RetT { return "void*"; }); } adt::Result GetCompileCmd() { return "gcc -fPIC -shared api_wrapper.c -o api_wrapper.so"; } adt::Result GetSoRelativePath() { return "api_wrapper.so"; } }; } // namespace ap::code_module