Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BindPython ABI #2796

Merged
merged 21 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
272889a
importing `cpython_bindings.py` when using `BindPython` ABI
Vipul-Cariappa Jul 29, 2024
51e3975
BindPython for no args - no return functions in LLVM backend
Vipul-Cariappa Aug 1, 2024
67853c7
BindPython support for args of int and float types
Vipul-Cariappa Aug 2, 2024
94fa4b6
refactored "from ... import ..." AST to ASR code
Vipul-Cariappa Aug 3, 2024
f256e43
BindPython support for args of str and bool types
Vipul-Cariappa Aug 3, 2024
57b0e80
BindPython support for return type of str, bool, integer & real types
Vipul-Cariappa Aug 3, 2024
ff32b75
refactored python_bind
Vipul-Cariappa Aug 3, 2024
42565b5
fix for CI
Vipul-Cariappa Aug 3, 2024
31f1225
fix for failing test
Vipul-Cariappa Aug 4, 2024
62ae095
add integration test for llvm backend
Vipul-Cariappa Aug 4, 2024
24f52fa
refactor: importing cpython_bindings separate out into function
Vipul-Cariappa Aug 4, 2024
3d1b50e
skip python_bind ASR pass when using C backend
Vipul-Cariappa Aug 5, 2024
a3bca79
changes according to code review
Vipul-Cariappa Aug 10, 2024
3cf7b22
generating CPython related function declarations in python_bind pass
Vipul-Cariappa Aug 11, 2024
432b184
fix for failing CI
Vipul-Cariappa Aug 11, 2024
dd6a76b
remove use of `PyRun_SimpleString` to set python path
Vipul-Cariappa Aug 11, 2024
8278e43
clean up unwanted comment
Vipul-Cariappa Aug 11, 2024
644a453
refactored `declare_functions` to asr_utils.cpp
Vipul-Cariappa Aug 11, 2024
e750a04
Update src/libasr/pass/python_bind.cpp
Vipul-Cariappa Aug 12, 2024
9ea5cdc
skipping python_bind ASR pass if `--enable-cpython` flag not used
Vipul-Cariappa Aug 12, 2024
839f6b9
fix related to previous commit
Vipul-Cariappa Aug 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -660,7 +660,7 @@ RUN(NAME bindc_05 LABELS llvm c
EXTRAFILES bindc_05b.c)
RUN(NAME bindc_06 LABELS llvm c
EXTRAFILES bindc_06b.c)
RUN(NAME bindpy_01 LABELS cpython c_py EXTRA_ARGS --enable-cpython NOFAST COPY_TO_BIN bindpy_01_module.py)
RUN(NAME bindpy_01 LABELS cpython llvm_py c_py EXTRA_ARGS --enable-cpython NOFAST COPY_TO_BIN bindpy_01_module.py)
RUN(NAME bindpy_02 LABELS cpython c_py EXTRA_ARGS --link-numpy COPY_TO_BIN bindpy_02_module.py)
RUN(NAME bindpy_03 LABELS cpython c_py EXTRA_ARGS --link-numpy NOFAST COPY_TO_BIN bindpy_03_module.py)
RUN(NAME bindpy_04 LABELS cpython c_py EXTRA_ARGS --link-numpy NOFAST COPY_TO_BIN bindpy_04_module.py)
Expand Down
6 changes: 3 additions & 3 deletions integration_tests/bindpy_05.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ def PyObject_CallObject(a: CPtr, b: CPtr) -> CPtr:
pass

@ccall(header="Python.h")
def PyLong_AsLongLong(a: CPtr) -> i32:
def PyLong_AsLongLong(a: CPtr) -> i64:
pass

def my_f():
Expand All @@ -62,9 +62,9 @@ def my_f():
_Py_DecRef(pArgs)
assert bool(pValue), "Call to my_f failed\n"

ans: i32 = PyLong_AsLongLong(pValue)
ans: i64 = PyLong_AsLongLong(pValue)
print("Ans is", ans)
assert ans == 5
assert ans == i64(5)


def main0():
Expand Down
14 changes: 8 additions & 6 deletions src/bin/lpython.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ int emit_c(const std::string &infile,
pass_manager.use_default_passes(true);
compiler_options.po.always_run = true;
compiler_options.po.run_fun = "f";
compiler_options.po.c_skip_bindpy_pass = true;

pass_manager.apply_passes(al, asr, compiler_options.po, diagnostics);

Expand Down Expand Up @@ -370,6 +371,7 @@ int emit_c_to_file(const std::string &infile, const std::string &outfile,

compiler_options.po.run_fun = "f";
compiler_options.po.always_run = true;
compiler_options.po.c_skip_bindpy_pass = true;

pass_manager.use_default_passes(true);
pass_manager.apply_passes(al, asr, compiler_options.po, diagnostics);
Expand Down Expand Up @@ -1130,7 +1132,7 @@ int compile_python_using_llvm(
LCompilers::LPython::DynamicLibrary cpython_lib;
LCompilers::LPython::DynamicLibrary symengine_lib;

if (compiler_options.enable_cpython) {
if (compiler_options.po.enable_cpython) {
LCompilers::LPython::open_cpython_library(cpython_lib);
}
if (compiler_options.enable_symengine) {
Expand All @@ -1149,7 +1151,7 @@ int compile_python_using_llvm(
e.execfn<void>("__module___main_____main__global_stmts");
}

if (compiler_options.enable_cpython) {
if (compiler_options.po.enable_cpython) {
LCompilers::LPython::close_cpython_library(cpython_lib);
}
if (compiler_options.enable_symengine) {
Expand Down Expand Up @@ -1533,7 +1535,7 @@ int link_executable(const std::vector<std::string> &infiles,
cmd += " -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lsymengine";
}

if (compiler_options.enable_cpython) {
if (compiler_options.po.enable_cpython) {
std::string py_version = "3.10";
std::string py_flags = R"(-I $CONDA_PREFIX/include/python)" + py_version + R"( -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lpython)" + py_version + R"()";
if (compiler_options.link_numpy) {
Expand Down Expand Up @@ -1592,7 +1594,7 @@ int link_executable(const std::vector<std::string> &infiles,
if (compiler_options.enable_symengine) {
cmd += " -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lsymengine";
}
if (compiler_options.enable_cpython) {
if (compiler_options.po.enable_cpython) {
std::string py_version = "3.10";
std::string py_flags = R"(-I $CONDA_PREFIX/include/python)" + py_version + R"( -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lpython)" + py_version + R"()";
if (compiler_options.link_numpy) {
Expand Down Expand Up @@ -1919,7 +1921,7 @@ int main(int argc, char *argv[])
app.add_flag("--dump-all-passes", compiler_options.po.dump_all_passes, "Apply all the passes and dump the ASR into a file");
app.add_flag("--dump-all-passes-fortran", compiler_options.po.dump_fortran, "Apply all passes and dump the ASR after each pass into fortran file");
app.add_flag("--cumulative", compiler_options.po.pass_cumulative, "Apply all the passes cumulatively till the given pass");
app.add_flag("--enable-cpython", compiler_options.enable_cpython, "Enable CPython runtime");
app.add_flag("--enable-cpython", compiler_options.po.enable_cpython, "Enable CPython runtime");
app.add_flag("--enable-symengine", compiler_options.enable_symengine, "Enable Symengine runtime");
app.add_flag("--link-numpy", compiler_options.link_numpy, "Enable NumPy runtime (implies --enable-cpython)");
app.add_flag("--separate-compilation", separate_compilation, "Generates unique names for all the symbols");
Expand Down Expand Up @@ -1981,7 +1983,7 @@ int main(int argc, char *argv[])
}

if (compiler_options.link_numpy) {
compiler_options.enable_cpython = true;
compiler_options.po.enable_cpython = true;
}

if (arg_version) {
Expand Down
1 change: 1 addition & 0 deletions src/libasr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ set(SRC
pass/for_all.cpp
pass/while_else.cpp
pass/global_stmts.cpp
pass/python_bind.cpp
pass/select_case.cpp
pass/init_expr.cpp
pass/implied_do_loops.cpp
Expand Down
91 changes: 91 additions & 0 deletions src/libasr/asr_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1707,6 +1707,97 @@ void append_error(diag::Diagnostics& diag, const std::string& msg,
//Initialize pointer to zero so that it can be initialized in first call to get_instance
ASRUtils::LabelGenerator* ASRUtils::LabelGenerator::label_generator = nullptr;

ASR::expr_t *type_enum_to_asr_expr(Allocator &al, enum TTYPE_T t, const Location &l, std::string n,
SymbolTable *current_scope, ASR::intentType intent) {
ASR::ttype_t *type = nullptr;

Str s;
s.from_str(al, n);

switch (t) {
case VOID:
return nullptr;
case I1:
type = ASRUtils::TYPE(ASR::make_Logical_t(al, l, 4));
break;
case I8:
type = ASRUtils::TYPE(ASR::make_Integer_t(al, l, 1));
break;
case I32:
type = ASRUtils::TYPE(ASR::make_Integer_t(al, l, 4));
break;
case I64:
type = ASRUtils::TYPE(ASR::make_Integer_t(al, l, 8));
break;
case U8:
type = ASRUtils::TYPE(ASR::make_UnsignedInteger_t(al, l, 1));
break;
case U32:
type = ASRUtils::TYPE(ASR::make_UnsignedInteger_t(al, l, 4));
break;
case U64:
type = ASRUtils::TYPE(ASR::make_UnsignedInteger_t(al, l, 8));
break;
case F32:
type = ASRUtils::TYPE(ASR::make_Real_t(al, l, 4));
break;
case F64:
type = ASRUtils::TYPE(ASR::make_Real_t(al, l, 8));
break;
case STR:
type = ASRUtils::TYPE(ASR::make_Character_t(al, l, 1, -2, nullptr));
break;
case PTR:
type = ASRUtils::TYPE(ASR::make_CPtr_t(al, l));
break;
case PTR_TO_PTR:
type = ASRUtils::TYPE(ASR::make_Pointer_t(al, l, ASRUtils::TYPE(ASR::make_CPtr_t(al, l))));
break;
}
LCOMPILERS_ASSERT(type);
ASR::symbol_t *v = ASR::down_cast<ASR::symbol_t>(ASR::make_Variable_t(al, l, current_scope, s.c_str(al), nullptr,
0, intent, nullptr, nullptr, ASR::storage_typeType::Default,
type, nullptr, ASR::abiType::BindC, ASR::Public,
ASR::presenceType::Required, true));
current_scope->add_symbol(n, v);
return ASRUtils::EXPR(ASR::make_Var_t(al, l, v));
}

void declare_function(Allocator &al, ASRFunc fn, const Location &l, SymbolTable *parent_scope,
std::string header_name) {
Str s;
char *c_header = nullptr;
if (header_name != "") {
s.from_str(al, header_name);
c_header = s.c_str(al);
}
s.from_str(al, fn.m_name);
Vec<ASR::expr_t*> args;
args.reserve(al, fn.args.size());
SymbolTable *current_scope = al.make_new<SymbolTable>(parent_scope);
int c = 0;
for (auto j: fn.args) {
args.push_back(al, type_enum_to_asr_expr(al, j, l, fn.m_name + std::to_string(++c), current_scope,
ASRUtils::intent_in));
}
ASR::expr_t *retval = type_enum_to_asr_expr(al, fn.retvar, l, "_lpython_return_variable", current_scope,
ASRUtils::intent_return_var);
char *fn_name = s.c_str(al);
ASR::asr_t *f = ASRUtils::make_Function_t_util(al, l, current_scope, fn_name, nullptr, 0, args.p, args.n,
nullptr, 0, retval, ASR::abiType::BindC, ASR::accessType::Public,
ASR::deftypeType::Interface, nullptr, false, false, false, false, false, nullptr, 0,
false, false, false, c_header);

parent_scope->add_symbol(fn.m_name, ASR::down_cast<ASR::symbol_t>(f));
}

void declare_functions(Allocator &al, std::vector<ASRFunc> fns, const Location &l, SymbolTable *parent_scope,
std::string header_name) {
for (auto i: fns) {
declare_function(al, i, l, parent_scope, header_name);
}
}

} // namespace ASRUtils


Expand Down
35 changes: 35 additions & 0 deletions src/libasr/asr_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -5415,6 +5415,41 @@ static inline bool is_argument_of_type_CPtr(ASR::expr_t *var) {
return is_argument;
}

enum TTYPE_T {
VOID,
I1,
I8,
STR,
I32,
I64,
U8,
U32,
U64,
F32,
F64,
PTR,
PTR_TO_PTR,
};

typedef struct {
std::string m_name;
std::vector<enum TTYPE_T> args;
enum TTYPE_T retvar;
} ASRFunc;

// Create a variable with name `n` and type `t` and add the symbol into `currect_scope`
// Returns the variable
ASR::expr_t *type_enum_to_asr_expr(Allocator &al, enum TTYPE_T t, const Location &l, std::string n,
SymbolTable *current_scope, ASR::intentType intent);

// created a BindC Interface function decleration in the `parent_scope`
void declare_function(Allocator &al, ASRFunc fn, const Location &l, SymbolTable *parent_scope,
std::string header_name="");

// created a BindC Interface functions decleration in the `parent_scope`
void declare_functions(Allocator &al, std::vector<ASRFunc> fns, const Location &l, SymbolTable *parent_scope,
std::string header_name="");

} // namespace ASRUtils

} // namespace LCompilers
Expand Down
4 changes: 2 additions & 2 deletions src/libasr/codegen/asr_to_c.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -820,7 +820,7 @@ R"(
}

std::string body;
if (compiler_options.enable_cpython) {
if (compiler_options.po.enable_cpython) {
headers.insert("Python.h");
body += R"(
Py_Initialize();
Expand Down Expand Up @@ -851,7 +851,7 @@ R"( // Initialise Numpy
body += src;
}

if (compiler_options.enable_cpython) {
if (compiler_options.po.enable_cpython) {
body += R"(
if (Py_FinalizeEx() < 0) {
fprintf(stderr,"BindPython: Unknown Error\n");
Expand Down
3 changes: 3 additions & 0 deletions src/libasr/pass/pass_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
#include <libasr/pass/replace_print_struct_type.h>
#include <libasr/pass/promote_allocatable_to_nonallocatable.h>
#include <libasr/pass/replace_function_call_in_declaration.h>
#include <libasr/pass/python_bind.h>
#include <libasr/codegen/asr_to_fortran.h>
#include <libasr/asr_verify.h>
#include <libasr/pickle.h>
Expand All @@ -79,6 +80,7 @@ namespace LCompilers {
{"do_loops", &pass_replace_do_loops},
{"while_else", &pass_while_else},
{"global_stmts", &pass_wrap_global_stmts},
{"python_bind", &pass_python_bind},
{"implied_do_loops", &pass_replace_implied_do_loops},
{"array_op", &pass_replace_array_op},
{"symbolic", &pass_replace_symbolic},
Expand Down Expand Up @@ -206,6 +208,7 @@ namespace LCompilers {
PassManager(): apply_default_passes{false},
c_skip_pass{false} {
_passes = {
"python_bind",
"nested_vars",
"global_stmts",
"transform_optional_argument_functions",
Expand Down
Loading
Loading