Skip to content

Commit 5905252

Browse files
authored
Merge pull request #2211 from Shaikh-Ubaid/llvm_init_cpython_interop_example
LLVM: Initial CPython Interop example
2 parents 634177d + 2f174ec commit 5905252

File tree

7 files changed

+132
-15
lines changed

7 files changed

+132
-15
lines changed

.github/workflows/CI.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ jobs:
396396
shell: bash -e -l {0}
397397
run: |
398398
cd integration_tests
399-
./run_tests.py -b cpython c_py
400-
./run_tests.py -b cpython c_py -f
399+
./run_tests.py -b cpython c_py llvm_py
400+
./run_tests.py -b cpython c_py llvm_py -f
401401
402402
sympy:
403403
name: Run SymPy tests

integration_tests/CMakeLists.txt

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,14 @@ message("LPYTHON_RTLIB_DIR: ${LPYTHON_RTLIB_DIR}")
7676
message("LPYTHON_RTLIB_LIBRARY: ${LPYTHON_RTLIB_LIBRARY}")
7777

7878

79-
macro(RUN_UTIL RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXTRA_ARGS)
79+
macro(RUN_UTIL RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXTRA_ARGS RUN_COPY_TO_BIN)
8080
set(fail ${${RUN_FAIL}})
8181
set(name ${${RUN_NAME}})
8282
set(file_name ${${RUN_FILE_NAME}})
8383
set(labels ${${RUN_LABELS}})
8484
set(extra_files ${${RUN_EXTRAFILES}})
8585
set(extra_args ${${RUN_EXTRA_ARGS}})
86+
set(copy_to_bin ${${RUN_COPY_TO_BIN}})
8687

8788
if (NOT name)
8889
message(FATAL_ERROR "Must specify the NAME argument")
@@ -105,6 +106,23 @@ macro(RUN_UTIL RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXT
105106
if (${fail})
106107
set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE)
107108
endif()
109+
elseif (KIND STREQUAL "llvm_py")
110+
add_custom_command(
111+
OUTPUT ${name}.o
112+
COMMAND ${LPYTHON} -c ${extra_args} ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py -o ${name}.o
113+
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${file_name}.py
114+
VERBATIM)
115+
add_executable(${name} ${name}.o ${extra_files})
116+
target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR} ${NUMPY_INCLUDE_DIR})
117+
set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C)
118+
target_link_libraries(${name} lpython_rtlib Python::Python)
119+
add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name})
120+
if (labels)
121+
set_tests_properties(${name} PROPERTIES LABELS "${labels}")
122+
endif()
123+
if (${fail})
124+
set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE)
125+
endif()
108126
elseif(KIND STREQUAL "llvm_sym")
109127
add_custom_command(
110128
OUTPUT ${name}.o
@@ -153,9 +171,6 @@ macro(RUN_UTIL RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXT
153171
target_include_directories(${name} PRIVATE ${CMAKE_SOURCE_DIR} ${NUMPY_INCLUDE_DIR})
154172
set_target_properties(${name} PROPERTIES LINKER_LANGUAGE C)
155173
target_link_libraries(${name} lpython_rtlib Python::Python)
156-
if (extra_files)
157-
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${extra_files} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
158-
endif()
159174
add_test(${name} ${CMAKE_CURRENT_BINARY_DIR}/${name})
160175
if (labels)
161176
set_tests_properties(${name} PROPERTIES LABELS "${labels}")
@@ -281,12 +296,17 @@ macro(RUN_UTIL RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXT
281296
set_tests_properties(${name} PROPERTIES WILL_FAIL TRUE)
282297
endif()
283298
endif()
299+
300+
if (copy_to_bin)
301+
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/${copy_to_bin} DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
302+
endif()
303+
284304
endif()
285305
endmacro(RUN_UTIL)
286306

287307
macro(RUN)
288308
set(options FAIL NOFAST ENABLE_CPYTHON LINK_NUMPY)
289-
set(oneValueArgs NAME IMPORT_PATH)
309+
set(oneValueArgs NAME IMPORT_PATH COPY_TO_BIN)
290310
set(multiValueArgs LABELS EXTRAFILES)
291311
cmake_parse_arguments(RUN "${options}" "${oneValueArgs}"
292312
"${multiValueArgs}" ${ARGN} )
@@ -309,14 +329,14 @@ macro(RUN)
309329
endif()
310330

311331
if (NOT FAST)
312-
RUN_UTIL(RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXTRA_ARGS)
332+
RUN_UTIL(RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXTRA_ARGS RUN_COPY_TO_BIN)
313333
endif()
314334

315335
if ((FAST) AND (NOT RUN_NOFAST))
316336
set(RUN_EXTRA_ARGS ${RUN_EXTRA_ARGS} --fast)
317337
set(RUN_NAME "${RUN_NAME}_FAST")
318338
list(REMOVE_ITEM RUN_LABELS cpython cpython_sym) # remove cpython, cpython_sym, from --fast test
319-
RUN_UTIL(RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXTRA_ARGS)
339+
RUN_UTIL(RUN_FAIL RUN_NAME RUN_FILE_NAME RUN_LABELS RUN_EXTRAFILES RUN_EXTRA_ARGS RUN_COPY_TO_BIN)
320340
endif()
321341
endmacro(RUN)
322342

@@ -575,10 +595,11 @@ RUN(NAME bindc_05 LABELS llvm c
575595
EXTRAFILES bindc_05b.c)
576596
RUN(NAME bindc_06 LABELS llvm c
577597
EXTRAFILES bindc_06b.c)
578-
RUN(NAME bindpy_01 LABELS cpython c_py ENABLE_CPYTHON NOFAST EXTRAFILES bindpy_01_module.py)
579-
RUN(NAME bindpy_02 LABELS cpython c_py LINK_NUMPY EXTRAFILES bindpy_02_module.py)
580-
RUN(NAME bindpy_03 LABELS cpython c_py LINK_NUMPY NOFAST EXTRAFILES bindpy_03_module.py)
581-
RUN(NAME bindpy_04 LABELS cpython c_py LINK_NUMPY NOFAST EXTRAFILES bindpy_04_module.py)
598+
RUN(NAME bindpy_01 LABELS cpython c_py ENABLE_CPYTHON NOFAST COPY_TO_BIN bindpy_01_module.py)
599+
RUN(NAME bindpy_02 LABELS cpython c_py LINK_NUMPY COPY_TO_BIN bindpy_02_module.py)
600+
RUN(NAME bindpy_03 LABELS cpython c_py LINK_NUMPY NOFAST COPY_TO_BIN bindpy_03_module.py)
601+
RUN(NAME bindpy_04 LABELS cpython c_py LINK_NUMPY NOFAST COPY_TO_BIN bindpy_04_module.py)
602+
RUN(NAME bindpy_05 LABELS llvm_py c_py ENABLE_CPYTHON COPY_TO_BIN bindpy_05_module.py)
582603
RUN(NAME test_generics_01 LABELS cpython llvm c NOFAST)
583604
RUN(NAME test_cmath LABELS cpython llvm c NOFAST)
584605
RUN(NAME test_complex_01 LABELS cpython llvm c wasm wasm_x64)

integration_tests/bindpy_05.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
from lpython import ccall, Pointer, i32, i64, empty_c_void_p, CPtr, pointer
2+
3+
@ccall(header="Python.h")
4+
def Py_Initialize():
5+
pass
6+
7+
@ccall(header="Python.h")
8+
def Py_DecodeLocale(s: str, p: CPtr) -> CPtr:
9+
pass
10+
11+
@ccall(header="Python.h")
12+
def PySys_SetArgv(n: i32, args: Pointer[CPtr]):
13+
pass
14+
15+
@ccall(header="Python.h")
16+
def Py_FinalizeEx() -> i32:
17+
pass
18+
19+
@ccall(header="Python.h")
20+
def PyUnicode_FromString(s: str) -> CPtr:
21+
pass
22+
23+
@ccall(header="Python.h")
24+
def PyImport_Import(name: CPtr) -> CPtr:
25+
pass
26+
27+
@ccall(header="Python.h")
28+
def _Py_DecRef(name: CPtr):
29+
pass
30+
31+
@ccall(header="Python.h")
32+
def PyObject_GetAttrString(m: CPtr, s: str) -> CPtr:
33+
pass
34+
35+
@ccall(header="Python.h")
36+
def PyTuple_New(n: i32) -> CPtr:
37+
pass
38+
39+
@ccall(header="Python.h")
40+
def PyObject_CallObject(a: CPtr, b: CPtr) -> CPtr:
41+
pass
42+
43+
@ccall(header="Python.h")
44+
def PyLong_AsLongLong(a: CPtr) -> i32:
45+
pass
46+
47+
def my_f():
48+
pName: CPtr; pModule: CPtr; pFunc: CPtr; pArgs: CPtr; pValue: CPtr
49+
50+
pName = PyUnicode_FromString("bindpy_05_module")
51+
assert bool(pName), "Failed to convert to unicode string bindpy_05_module\n"
52+
53+
pModule = PyImport_Import(pName)
54+
_Py_DecRef(pName)
55+
assert bool(pModule), "Failed to load python module bindpy_05_module\n"
56+
57+
pFunc = PyObject_GetAttrString(pModule, "my_f")
58+
assert bool(pFunc), "Cannot find function my_f\n"
59+
60+
pArgs = PyTuple_New(0)
61+
pValue = PyObject_CallObject(pFunc, pArgs)
62+
_Py_DecRef(pArgs)
63+
assert bool(pValue), "Call to my_f failed\n"
64+
65+
ans: i32 = PyLong_AsLongLong(pValue)
66+
print("Ans is", ans)
67+
assert ans == 5
68+
69+
70+
def main0():
71+
Py_Initialize()
72+
argv1: CPtr = Py_DecodeLocale("", empty_c_void_p())
73+
PySys_SetArgv(1, pointer(argv1, i64))
74+
75+
my_f()
76+
77+
assert(Py_FinalizeEx() >= 0), "BindPython: Unknown Error in FinalizeEx()\n"
78+
79+
main0()

integration_tests/bindpy_05_module.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
def my_f():
2+
print("hello from python")
3+
return 5

integration_tests/run_tests.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
# Initialization
88
DEFAULT_THREADS_TO_USE = 8 # default no of threads is 8
9-
SUPPORTED_BACKENDS = ['llvm', 'c', 'wasm', 'cpython', 'x86', 'wasm_x86', 'wasm_x64', 'c_py', 'c_sym', 'cpython_sym', 'llvm_sym']
9+
SUPPORTED_BACKENDS = ['llvm', 'c', 'wasm', 'cpython', 'x86', 'wasm_x86', 'wasm_x64', 'c_py', 'c_sym', 'cpython_sym', 'llvm_sym', 'llvm_py']
1010
BASE_DIR = os.path.dirname(os.path.realpath(__file__))
1111
LPYTHON_PATH = f"{BASE_DIR}/../src/bin"
1212

@@ -62,7 +62,7 @@ def main():
6262
DEFAULT_THREADS_TO_USE = args.no_of_threads or DEFAULT_THREADS_TO_USE
6363
fast_tests = "yes" if args.fast else "no"
6464
for backend in args.backends:
65-
python_libs_req = "yes" if backend in ["c_py", "c_sym", "llvm_sym"] else "no"
65+
python_libs_req = "yes" if backend in ["c_py", "c_sym", "llvm_sym", 'llvm_py'] else "no"
6666
test_backend(backend)
6767

6868

src/bin/lpython.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,6 +1226,16 @@ int link_executable(const std::vector<std::string> &infiles,
12261226
if (compiler_options.enable_symengine) {
12271227
cmd += " -L$CONDA_PREFIX/lib -Wl,-rpath -Wl,$CONDA_PREFIX/lib -lsymengine";
12281228
}
1229+
1230+
if (compiler_options.enable_cpython) {
1231+
std::string py_version = "3.10";
1232+
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"()";
1233+
if (compiler_options.link_numpy) {
1234+
py_flags += R"( -I$CONDA_PREFIX/lib/python)" + py_version + R"(/site-packages/numpy/core/include)";
1235+
}
1236+
cmd += " " + py_flags;
1237+
}
1238+
12291239
int err = system(cmd.c_str());
12301240
if (err) {
12311241
std::cout << "The command '" + cmd + "' failed." << std::endl;

src/lpython/semantics/python_intrinsic_eval.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,10 @@ struct IntrinsicNodeHandler {
244244

245245
} else if (ASRUtils::is_logical(*type)) {
246246
return (ASR::asr_t *)arg;
247+
} else if (ASR::is_a<ASR::CPtr_t>(*type)) {
248+
ASR::expr_t* c_null_ptr = ASRUtils::EXPR(ASR::make_PointerNullConstant_t(
249+
al, loc, ASRUtils::TYPE(ASR::make_CPtr_t(al, loc))));
250+
return ASR::make_CPtrCompare_t(al, loc, arg, ASR::cmpopType::NotEq, c_null_ptr, to_type, nullptr);
247251
} else {
248252
std::string stype = ASRUtils::type_to_str_python(type);
249253
throw SemanticError(

0 commit comments

Comments
 (0)