Skip to content

Commit

Permalink
PythonCall: Support arr of simple types as ret type
Browse files Browse the repository at this point in the history
  • Loading branch information
Shaikh-Ubaid committed Jun 23, 2023
1 parent 9af095f commit 36c6ff7
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 12 deletions.
3 changes: 0 additions & 3 deletions src/libasr/codegen/asr_to_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,16 +30,13 @@ class ASRToCVisitor : public BaseCCPPVisitor<ASRToCVisitor>
{
public:

std::string array_types_decls;

std::unique_ptr<CUtils::CUtilFunctions> c_utils_functions;

int counter;

ASRToCVisitor(diag::Diagnostics &diag, CompilerOptions &co,
int64_t default_lower_bound)
: BaseCCPPVisitor(diag, co.platform, co, false, false, true, default_lower_bound),
array_types_decls(std::string("")),
c_utils_functions{std::make_unique<CUtils::CUtilFunctions>()},
counter{0} {
}
Expand Down
32 changes: 23 additions & 9 deletions src/libasr/codegen/asr_to_c_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class BaseCCPPVisitor : public ASR::BaseVisitor<Struct>
std::map<uint64_t, std::string> const_var_names;
std::map<int32_t, std::string> gotoid2name;
std::map<std::string, std::string> emit_headers;
std::string array_types_decls;

// Output configuration:
// Use std::string or char*
Expand Down Expand Up @@ -146,7 +147,7 @@ class BaseCCPPVisitor : public ASR::BaseVisitor<Struct>
BaseCCPPVisitor(diag::Diagnostics &diag, Platform &platform,
CompilerOptions &_compiler_options, bool gen_stdstring, bool gen_stdcomplex, bool is_c,
int64_t default_lower_bound) : diag{diag},
platform{platform}, compiler_options{_compiler_options},
platform{platform}, compiler_options{_compiler_options}, array_types_decls{std::string("")},
gen_stdstring{gen_stdstring}, gen_stdcomplex{gen_stdcomplex},
is_c{is_c}, global_scope{nullptr}, lower_bound{default_lower_bound},
template_number{0}, c_ds_api{std::make_unique<CCPPDSUtils>(is_c, platform)},
Expand Down Expand Up @@ -538,17 +539,30 @@ R"(#include <stdio.h>
if (!x.m_return_var) return "";
ASR::Variable_t* r_v = ASRUtils::EXPR2VAR(x.m_return_var);
std::string indent = "\n ";
std::string py_val_cnvrt = CUtils::get_py_obj_return_type_conv_func_from_ttype_t(r_v->m_type) + "(pValue)";
std::string ret_var_decl = indent + CUtils::get_c_type_from_ttype_t(r_v->m_type) + " " + std::string(r_v->m_name) + ";";
std::string ret_assign = indent + std::string(r_v->m_name) + " = " + py_val_cnvrt + ";";
std::string ret_stmt = indent + "return " + std::string(r_v->m_name) + ";";
std::string clear_pValue = indent + "Py_DECREF(pValue);";
std::string copy_result = "";
std::string py_val_cnvrt, ret_var_decl, copy_result;
if (ASRUtils::is_aggregate_type(r_v->m_type)) {
if (ASRUtils::is_character(*r_v->m_type)) {
copy_result = indent + std::string(r_v->m_name) + " = _lfortran_str_copy(" + std::string(r_v->m_name) + ", 1, 0);";
if (ASRUtils::is_array(r_v->m_type)) {
ASR::ttype_t* array_type_asr = ASRUtils::type_get_past_array(r_v->m_type);
std::string array_type_name = CUtils::get_c_type_from_ttype_t(array_type_asr);
std::string array_encoded_type_name = ASRUtils::get_type_code(array_type_asr, true, false);
std::string return_type = c_ds_api->get_array_type(array_type_name, array_encoded_type_name, array_types_decls, true);
py_val_cnvrt = bind_py_utils_functions->get_conv_py_arr_to_c(return_type, array_type_name,
array_encoded_type_name) + "(pValue)";
ret_var_decl = indent + return_type + " _lpython_return_variable;";
} else {
if (ASRUtils::is_character(*r_v->m_type)) {
py_val_cnvrt = CUtils::get_py_obj_return_type_conv_func_from_ttype_t(r_v->m_type) + "(pValue)";
ret_var_decl = indent + CUtils::get_c_type_from_ttype_t(r_v->m_type) + " _lpython_return_variable;";
copy_result = indent + "_lpython_return_variable = _lfortran_str_copy(" + std::string(r_v->m_name) + ", 1, 0);";
}
}
} else {
py_val_cnvrt = CUtils::get_py_obj_return_type_conv_func_from_ttype_t(r_v->m_type) + "(pValue)";
ret_var_decl = indent + CUtils::get_c_type_from_ttype_t(r_v->m_type) + " _lpython_return_variable;";
}
std::string ret_assign = indent + std::string(r_v->m_name) + " = " + py_val_cnvrt + ";";
std::string ret_stmt = indent + "return _lpython_return_variable;";
std::string clear_pValue = indent + "Py_DECREF(pValue);";
return ret_var_decl + ret_assign + copy_result + clear_pValue + ret_stmt + "\n";
}

Expand Down
51 changes: 51 additions & 0 deletions src/libasr/codegen/c_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,46 @@ namespace CUtils {
conv_dims_to_1D_arr();
return util2func["conv_dims_to_1D_arr"];
}

void conv_py_arr_to_c(std::string return_type,
std::string element_type, std::string encoded_type) {
if( util2func.find("conv_py_arr_to_c_" + encoded_type) != util2func.end() ) {
return;
}
std::string indent(indentation_level * indentation_spaces, ' ');
std::string tab(indentation_spaces, ' ');
util2func["conv_py_arr_to_c_" + encoded_type] = global_scope->get_unique_name("conv_py_arr_to_c_" + encoded_type);
std::string conv_py_arr_to_c_func = util2func["conv_py_arr_to_c_" + encoded_type];
std::string signature = "static inline " + return_type + " " + conv_py_arr_to_c_func + "(PyObject* pValue)";
util_func_decls += indent + signature + ";\n";
std::string body = indent + signature + " {\n";
body += indent + tab + "if (!PyArray_Check(pValue)) {\n";
body += indent + tab + tab + R"(fprintf(stderr, "Return value is not an array\n");)" + "\n";
body += indent + tab + "}\n";
body += indent + tab + "PyArrayObject *np_arr = (PyArrayObject *)pValue;\n";
body += indent + tab + return_type + " ret_var = (" + return_type + ") malloc(sizeof(struct " + encoded_type + "));\n";
body += indent + tab + "ret_var->n_dims = PyArray_NDIM(np_arr);\n";
body += indent + tab + "long* m_dims = PyArray_SHAPE(np_arr);\n";
body += indent + tab + "for (long i = 0; i < ret_var->n_dims; i++) {\n";
body += indent + tab + tab + "ret_var->dims[i].length = m_dims[i];\n";
body += indent + tab + tab + "ret_var->dims[i].lower_bound = 0;\n";
body += indent + tab + "}\n";
body += indent + tab + "long arr_size = PyArray_SIZE(np_arr);\n";
body += indent + tab + element_type + "* data = (" + element_type + "*) PyArray_DATA(np_arr);\n";
body += indent + tab + "ret_var->data = (" + element_type + "*) malloc(arr_size * sizeof(" + element_type + "));\n";
body += indent + tab + "for (long i = 0; i < arr_size; i++) {\n";
body += indent + tab + tab + "ret_var->data[i] = data[i];\n";
body += indent + tab + "}\n";
body += indent + tab + "return ret_var;\n";
body += indent + "}\n\n";
util_funcs += body;
}

std::string get_conv_py_arr_to_c(std::string return_type,
std::string element_type, std::string encoded_type) {
conv_py_arr_to_c(return_type, element_type, encoded_type);
return util2func["conv_py_arr_to_c_" + encoded_type];
}
};

static inline std::string get_tuple_type_code(ASR::Tuple_t *tup) {
Expand Down Expand Up @@ -487,6 +527,17 @@ namespace CUtils {
int kind = ASRUtils::extract_kind_from_ttype_t(t);
std::string type_src = "";
switch( t->type ) {
case ASR::ttypeType::Array: {
ASR::ttype_t* arr_type = ASR::down_cast<ASR::Array_t>(t)->m_type;
if (arr_type->type == ASR::ttypeType::Integer) {
type_src = ""; // we convert the array while copying it
} else if (arr_type->type == ASR::ttypeType::Real) {
type_src = ""; // we convert the array while copying it
} else {
throw CodeGenError("get_py_obj_return_type_conv_func_from_ttype_t: Unsupported array type for return variable");
}
break;
}
case ASR::ttypeType::Integer: {
switch (kind)
{
Expand Down

0 comments on commit 36c6ff7

Please sign in to comment.