Skip to content

C: Support callbacks #2175

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

Merged
merged 4 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -694,7 +694,8 @@ RUN(NAME global_syms_04 LABELS cpython llvm c wasm wasm_x64)
RUN(NAME global_syms_05 LABELS cpython llvm c)
RUN(NAME global_syms_06 LABELS cpython llvm c)

RUN(NAME callback_01 LABELS cpython llvm)
RUN(NAME callback_01 LABELS cpython llvm c)
RUN(NAME callback_02 LABELS cpython llvm c)

# Intrinsic Functions
RUN(NAME intrinsics_01 LABELS cpython llvm NOFAST) # any
Expand Down
18 changes: 18 additions & 0 deletions integration_tests/callback_02.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from lpython import ccallback, i32, Callable

# test issue 2169

def foo(x : i32) -> i32:
return x**2

def bar(func : Callable[[i32], i32], arg : i32) -> i32:
return func(arg)

@ccallback
def entry_point() -> None:
z: i32 = 5
x: i32 = bar(foo, z)
assert z**2 == x


entry_point()
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 @@ -739,8 +739,8 @@ R"(
array_types_decls.insert(0, "struct dimension_descriptor\n"
"{\n int32_t lower_bound, length;\n};\n");
}

src = to_include + head + array_types_decls + unit_src +
forward_decl_functions += "\n\n";
src = to_include + head + array_types_decls + forward_decl_functions + unit_src +
ds_funcs_defined + util_funcs_defined;
if (!emit_headers.empty()) {
std::string to_includes_1 = "";
Expand Down
60 changes: 41 additions & 19 deletions src/libasr/codegen/asr_to_c_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@ class BaseCCPPVisitor : public ASR::BaseVisitor<Struct>
std::map<int32_t, std::string> gotoid2name;
std::map<std::string, std::string> emit_headers;
std::string array_types_decls;
std::string forward_decl_functions;

// Output configuration:
// Use std::string or char*
Expand Down Expand Up @@ -493,18 +494,18 @@ R"(#include <stdio.h>
}

// Returns the declaration, no semi colon at the end
std::string get_function_declaration(const ASR::Function_t &x, bool &has_typevar) {
std::string get_function_declaration(const ASR::Function_t &x, bool &has_typevar, bool is_pointer=false) {
template_for_Kokkos.clear();
template_number = 0;
std::string sub, inl, static_attr;

// This helps to check if the function is generic.
// If it is generic we skip the codegen for that function.
has_typevar = false;
if (ASRUtils::get_FunctionType(x)->m_inline) {
if (ASRUtils::get_FunctionType(x)->m_inline && !is_pointer) {
inl = "inline __attribute__((always_inline)) ";
}
if( ASRUtils::get_FunctionType(x)->m_static ) {
if( ASRUtils::get_FunctionType(x)->m_static && !is_pointer) {
static_attr = "static ";
}
if (x.m_return_var) {
Expand All @@ -526,30 +527,47 @@ R"(#include <stdio.h>
f_type->m_deftype == ASR::deftypeType::Implementation) {
sym_name = "_xx_internal_" + sym_name + "_xx";
}
std::string func = static_attr + inl + sub + sym_name + "(";
std::string func = static_attr + inl + sub;
if (is_pointer) {
func += "(*" + sym_name + ")(";
} else {
func += sym_name + "(";
}
bracket_open++;
for (size_t i=0; i<x.n_args; i++) {
ASR::Variable_t *arg = ASRUtils::EXPR2VAR(x.m_args[i]);
LCOMPILERS_ASSERT(ASRUtils::is_arg_dummy(arg->m_intent));
if (ASR::is_a<ASR::TypeParameter_t>(*arg->m_type)) {
has_typevar = true;
bracket_open--;
return "";
}
if( is_c ) {
CDeclarationOptions c_decl_options;
c_decl_options.pre_initialise_derived_type = false;
func += self().convert_variable_decl(*arg, &c_decl_options);
ASR::symbol_t *sym = ASRUtils::symbol_get_past_external(
ASR::down_cast<ASR::Var_t>(x.m_args[i])->m_v);
if (ASR::is_a<ASR::Variable_t>(*sym)) {
ASR::Variable_t *arg = ASR::down_cast<ASR::Variable_t>(sym);
LCOMPILERS_ASSERT(ASRUtils::is_arg_dummy(arg->m_intent));
if( is_c ) {
CDeclarationOptions c_decl_options;
c_decl_options.pre_initialise_derived_type = false;
func += self().convert_variable_decl(*arg, &c_decl_options);
} else {
CPPDeclarationOptions cpp_decl_options;
cpp_decl_options.use_static = false;
cpp_decl_options.use_templates_for_arrays = true;
func += self().convert_variable_decl(*arg, &cpp_decl_options);
}
if (ASR::is_a<ASR::TypeParameter_t>(*arg->m_type)) {
has_typevar = true;
bracket_open--;
return "";
}
} else if (ASR::is_a<ASR::Function_t>(*sym)) {
ASR::Function_t *fun = ASR::down_cast<ASR::Function_t>(sym);
func += get_function_declaration(*fun, has_typevar, true);
} else {
CPPDeclarationOptions cpp_decl_options;
cpp_decl_options.use_static = false;
cpp_decl_options.use_templates_for_arrays = true;
func += self().convert_variable_decl(*arg, &cpp_decl_options);
throw CodeGenError("Unsupported function argument");
}
if (i < x.n_args-1) func += ", ";
}
func += ")";
bracket_open--;
if (f_type->m_abi == ASR::abiType::Source) {
forward_decl_functions += func + ";\n";
}
if( is_c || template_for_Kokkos.empty() ) {
return func;
}
Expand Down Expand Up @@ -1716,6 +1734,10 @@ PyMODINIT_FUNC PyInit_lpython_module_)" + fn_name + R"((void) {

void visit_Var(const ASR::Var_t &x) {
const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v);
if (ASR::is_a<ASR::Function_t>(*s)) {
src = ASRUtils::symbol_name(s);
return;
}
ASR::Variable_t* sv = ASR::down_cast<ASR::Variable_t>(s);
if( (sv->m_intent == ASRUtils::intent_in ||
sv->m_intent == ASRUtils::intent_inout) &&
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-c_interop1-e215531.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-c_interop1-e215531.stdout",
"stdout_hash": "31d7d540adfef1263741e1b9709e4a2a73c6208147d735906dbf233e",
"stdout_hash": "9d9dd1715b625024203f8b4de330a936a806c5e8031ae7b643c23e71",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
2 changes: 2 additions & 0 deletions tests/reference/c-c_interop1-e215531.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include <lfortran_intrinsics.h>




// Implementations
double f(double x);

Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-expr7-bb2692a.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-expr7-bb2692a.stdout",
"stdout_hash": "be3bac9bcf7f1fab11741c22151820f60793d5afc670486e9d0913aa",
"stdout_hash": "11026dff0f543f773698075edb3d690f8a475e8639124f1e1dcaef6a",
"stderr": "c-expr7-bb2692a.stderr",
"stderr_hash": "6e9790ac88db1a9ead8f64a91ba8a6605de67167037908a74b77be0c",
"returncode": 0
Expand Down
6 changes: 6 additions & 0 deletions tests/reference/c-expr7-bb2692a.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
#include <string.h>
#include <lfortran_intrinsics.h>

void test_pow();
int32_t test_pow_1(int32_t a, int32_t b);
void main0();
void __main____global_statements();



// Implementations
double __lpython_overloaded_0__pow(int32_t x, int32_t y)
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-expr_01-28f449f.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-expr_01-28f449f.stdout",
"stdout_hash": "21755da8aacbb21ee5a5229c8f47f7ba40c36d942af84f848e36bd5b",
"stdout_hash": "b9e6df09a73026d76ea9eefed3e2b211476b1ac55956ee8150a4a417",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
6 changes: 6 additions & 0 deletions tests/reference/c-expr_01-28f449f.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
#include <string.h>
#include <lfortran_intrinsics.h>

inline __attribute__((always_inline)) int32_t add(int32_t x, int32_t y);
inline __attribute__((always_inline)) int32_t and_op(int32_t x, int32_t y);
void main0();
void __main____global_statements();



// Implementations
inline __attribute__((always_inline)) int32_t add(int32_t x, int32_t y)
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-expr_11-c452314.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-expr_11-c452314.stdout",
"stdout_hash": "3566609825322587b3a725aa627c191e47e28835a78f182bb95546ab",
"stdout_hash": "828e55148962eac31cff8246dbf28003a81b9852481aa1e584128ecb",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
4 changes: 4 additions & 0 deletions tests/reference/c-expr_11-c452314.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include <string.h>
#include <lfortran_intrinsics.h>

void f();
void __main____global_statements();



// Implementations
void f()
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-expr_12-93c7780.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-expr_12-93c7780.stdout",
"stdout_hash": "094a6e7284485e456d1ff691266f3ab0400f2893e1e7670fb186cf6b",
"stdout_hash": "4ff750b49402a8f60ae61abdc16289388dfb3230995dda8b75fcd8cd",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
6 changes: 6 additions & 0 deletions tests/reference/c-expr_12-93c7780.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ struct i16
bool is_allocated;
};

void g(struct i16* *x, struct i16* y);
void check(struct i16* *ptr);
void f();
void __main____global_statements();



// Implementations
void g(struct i16* *x, struct i16* y)
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-func_static_01-fc146ec.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-func_static_01-fc146ec.stdout",
"stdout_hash": "ee924027aed46d89fab1ee33f7bb07aa925c27f272bb7e8766e9f63d",
"stdout_hash": "77431288e9f3af7e7f5d2a2859ade52772a79789337db403b3dc9943",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
5 changes: 5 additions & 0 deletions tests/reference/c-func_static_01-fc146ec.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@
#include <string.h>
#include <lfortran_intrinsics.h>

static int64_t fib(int64_t n);
void main0();
void __main____global_statements();



// Implementations
static int64_t fib(int64_t n)
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-import_order_01-3ebf3c3.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-import_order_01-3ebf3c3.stdout",
"stdout_hash": "63a56ec5425b877465861abc207045ed30f150f6ab78004a2243433d",
"stdout_hash": "f3e4798c2ffb4df885977927d38d89b0354c812264ae40b4e7103ced",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
3 changes: 3 additions & 0 deletions tests/reference/c-import_order_01-3ebf3c3.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
#include <string.h>
#include <lfortran_intrinsics.h>

int32_t f();



// Implementations
int32_t f()
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-loop1-3e341c7.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-loop1-3e341c7.stdout",
"stdout_hash": "63eae4287cec6a9ae5a1b3f5aacaddc08eb7edc0fa9ff7589c3ebc31",
"stdout_hash": "241f7395d191f7dd26195e71200be7e23a30969f2cca993137eb8b2d",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
7 changes: 7 additions & 0 deletions tests/reference/c-loop1-3e341c7.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@
#include <string.h>
#include <lfortran_intrinsics.h>

int32_t test_factorial_1(int32_t x);
int32_t test_factorial_2(int32_t x);
int64_t test_factorial_3(int32_t x);
void main0();
void __main____global_statements();



// Implementations
int32_t test_factorial_1(int32_t x)
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-loop4-eec10d3.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-loop4-eec10d3.stdout",
"stdout_hash": "dd37ec60eb4710dc87766a78d83b77dcb982672d291848eb82c45814",
"stdout_hash": "9c6c8fd97e7c24685ba75f6037f45993f3f739817b4fb6650cd9cab8",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
4 changes: 4 additions & 0 deletions tests/reference/c-loop4-eec10d3.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
#include <string.h>
#include <lfortran_intrinsics.h>

void test_for();
void __main____global_statements();



// Implementations
void test_for()
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-print_01-4d44628.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-print_01-4d44628.stdout",
"stdout_hash": "a42a087d40d750b53b9bc6ac7c8248c05b5adb253addd2c0a0d47550",
"stdout_hash": "eeedca2639797a26c43f22383f01cdd16382d27921d87a70687c44d9",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
4 changes: 4 additions & 0 deletions tests/reference/c-print_01-4d44628.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
#include <string.h>
#include <lfortran_intrinsics.h>

void f();
void __main____global_statements();



// Implementations
void f()
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-test_import_02-d2c54c4.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-test_import_02-d2c54c4.stdout",
"stdout_hash": "62cb9cf8e988af42d9375f49577532a91ab0c9bde8f9a9ce62c3f691",
"stdout_hash": "96649585d0a2f2f8e55f872b58bb924983457db3679b43525112a3ec",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
6 changes: 6 additions & 0 deletions tests/reference/c-test_import_02-d2c54c4.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
#include <string.h>
#include <lfortran_intrinsics.h>

int32_t add(int32_t x, int32_t y);
int32_t multiply(int32_t x, int32_t y);
void f();
void __main____global_statements();



// Implementations
const double μ = 1.45136923488338110e+00;
Expand Down
2 changes: 1 addition & 1 deletion tests/reference/c-test_issue_518-fbbd299.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"outfile": null,
"outfile_hash": null,
"stdout": "c-test_issue_518-fbbd299.stdout",
"stdout_hash": "f744351df831c8870f53e3a5eefbdf47df6716a1152b2f0bda2c2cfd",
"stdout_hash": "651a207e618ca25fb733b618072bd3586b652da51a824ddd03d681d1",
"stderr": null,
"stderr_hash": null,
"returncode": 0
Expand Down
6 changes: 6 additions & 0 deletions tests/reference/c-test_issue_518-fbbd299.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@
#include <string.h>
#include <lfortran_intrinsics.h>

int64_t fib(int64_t n);
void main0();
void _xx_lcompilers_changed_main_xx();
void __main____global_statements();



// Implementations
int64_t fib(int64_t n)
Expand Down
Loading