Skip to content

Commit bd73514

Browse files
smazouz42EmilyBournebauom
committed
Fix import handling (#49)
This pull request fixes #48, by implementing a tiny wrapper for CUDA and a wrapper for non-CUDA functionalities only with external 'C'. **Commit Summary** - Implemented new header printer for CUDA. - Added CUDA wrapper assignment - Instead of wrapping all local headers, wrap only C functions with extern 'C' --------- Co-authored-by: EmilyBourne <[email protected]> Co-authored-by: bauom <[email protected]>
1 parent 02a2360 commit bd73514

File tree

7 files changed

+143
-14
lines changed

7 files changed

+143
-14
lines changed

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ Contributors
3131
* Farouk Ech-Charef
3232
* Mustapha Belbiad
3333
* Varadarajan Rengaraj
34+
* Said Mazouz

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ All notable changes to this project will be documented in this file.
55

66
### Added
77

8-
- #32 : add support for `nvcc` Compiler and `cuda` language as a possible option.
8+
- #32 : Add support for `nvcc` Compiler and `cuda` language as a possible option.
9+
- #48 : Fix incorrect handling of imports in `cuda`.
910

1011
## \[UNRELEASED\]
1112

pyccel/codegen/printing/cucode.py

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -52,23 +52,42 @@ def _print_Module(self, expr):
5252

5353
# Print imports last to be sure that all additional_imports have been collected
5454
imports = [Import(expr.name, Module(expr.name,(),())), *self._additional_imports.values()]
55-
c_headers_imports = ''
56-
local_imports = ''
57-
58-
for imp in imports:
59-
if imp.source in c_library_headers:
60-
c_headers_imports += self._print(imp)
61-
else:
62-
local_imports += self._print(imp)
63-
64-
imports = f'{c_headers_imports}\
65-
extern "C"{{\n\
66-
{local_imports}\
67-
}}'
55+
imports = ''.join(self._print(i) for i in imports)
6856

6957
code = f'{imports}\n\
7058
{global_variables}\n\
7159
{body}\n'
7260

7361
self.exit_scope()
7462
return code
63+
64+
def _print_ModuleHeader(self, expr):
65+
self.set_scope(expr.module.scope)
66+
self._in_header = True
67+
name = expr.module.name
68+
69+
funcs = ""
70+
cuda_headers = ""
71+
for f in expr.module.funcs:
72+
if not f.is_inline:
73+
if 'kernel' in f.decorators: # Checking for 'kernel' decorator
74+
cuda_headers += self.function_signature(f) + ';\n'
75+
else:
76+
funcs += self.function_signature(f) + ';\n'
77+
global_variables = ''.join('extern '+self._print(d) for d in expr.module.declarations if not d.variable.is_private)
78+
# Print imports last to be sure that all additional_imports have been collected
79+
imports = [*expr.module.imports, *self._additional_imports.values()]
80+
imports = ''.join(self._print(i) for i in imports)
81+
82+
self._in_header = False
83+
self.exit_scope()
84+
function_declaration = f'{cuda_headers}\n\
85+
extern "C"{{\n\
86+
{funcs}\
87+
}}\n'
88+
return '\n'.join((f"#ifndef {name.upper()}_H",
89+
f"#define {name.upper()}_H",
90+
global_variables,
91+
function_declaration,
92+
"#endif // {name.upper()}_H\n"))
93+

pyccel/codegen/python_wrapper.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from pyccel.codegen.printing.fcode import FCodePrinter
1414
from pyccel.codegen.wrapper.fortran_to_c_wrapper import FortranToCWrapper
1515
from pyccel.codegen.wrapper.c_to_python_wrapper import CToPythonWrapper
16+
from pyccel.codegen.wrapper.cuda_to_c_wrapper import CudaToCWrapper
1617
from pyccel.codegen.utilities import recompile_object
1718
from pyccel.codegen.utilities import copy_internal_library
1819
from pyccel.codegen.utilities import internal_libs
@@ -144,6 +145,9 @@ def create_shared_library(codegen,
144145
verbose=verbose)
145146
timings['Bind C wrapping'] = time.time() - start_bind_c_compiling
146147
c_ast = bind_c_mod
148+
elif language == 'cuda':
149+
wrapper = CudaToCWrapper()
150+
c_ast = wrapper.wrap(codegen.ast)
147151
else:
148152
c_ast = codegen.ast
149153

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# coding: utf-8
2+
#------------------------------------------------------------------------------------------#
3+
# This file is part of Pyccel which is released under MIT License. See the LICENSE file or #
4+
# go to https://github.com/pyccel/pyccel/blob/master/LICENSE for full license details. #
5+
#------------------------------------------------------------------------------------------#
6+
"""
7+
Module describing the code-wrapping class : CudaToPythonWrapper
8+
which creates an interface exposing Cuda code to C.
9+
"""
10+
11+
from pyccel.ast.bind_c import BindCModule
12+
from pyccel.errors.errors import Errors
13+
from pyccel.ast.bind_c import BindCVariable
14+
from .wrapper import Wrapper
15+
16+
errors = Errors()
17+
18+
class CudaToCWrapper(Wrapper):
19+
"""
20+
Class for creating a wrapper exposing Cuda code to C.
21+
22+
While CUDA is typically compatible with C by default.
23+
this wrapper becomes necessary in scenarios where specific adaptations
24+
or modifications are required to ensure seamless integration with C.
25+
"""
26+
27+
def _wrap_Module(self, expr):
28+
"""
29+
Create a Module which is compatible with C.
30+
31+
Create a Module which provides an interface between C and the
32+
Module described by expr.
33+
34+
Parameters
35+
----------
36+
expr : pyccel.ast.core.Module
37+
The module to be wrapped.
38+
39+
Returns
40+
-------
41+
pyccel.ast.core.BindCModule
42+
The C-compatible module.
43+
"""
44+
init_func = expr.init_func
45+
if expr.interfaces:
46+
errors.report("Interface wrapping is not yet supported for Cuda",
47+
severity='warning', symbol=expr)
48+
if expr.classes:
49+
errors.report("Class wrapping is not yet supported for Cuda",
50+
severity='warning', symbol=expr)
51+
52+
variables = [self._wrap(v) for v in expr.variables]
53+
54+
return BindCModule(expr.name, variables, expr.funcs,
55+
init_func=init_func,
56+
scope = expr.scope,
57+
original_module=expr)
58+
59+
def _wrap_Variable(self, expr):
60+
"""
61+
Create all objects necessary to expose a module variable to C.
62+
63+
Create and return the objects which must be printed in the wrapping
64+
module in order to expose the variable to C
65+
66+
Parameters
67+
----------
68+
expr : pyccel.ast.variables.Variable
69+
The module variable.
70+
71+
Returns
72+
-------
73+
pyccel.ast.core.BindCVariable
74+
The C-compatible variable. which must be printed in
75+
the wrapping module to expose the variable.
76+
"""
77+
return expr.clone(expr.name, new_class = BindCVariable)
78+
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# pylint: disable=missing-function-docstring, missing-module-docstring
2+
import numpy as np
3+
4+
g = np.float64(9.81)
5+
r0 = np.float32(1.0)
6+
rmin = 0.01
7+
rmax = 1.0
8+
9+
skip_centre = True
10+
11+
method = 3
12+
13+
tiny = np.int32(4)

tests/epyccel/test_epyccel_modules.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,16 @@ def test_awkward_names(language):
200200
assert mod.function() == modnew.function()
201201
assert mod.pure() == modnew.pure()
202202
assert mod.allocate(1) == modnew.allocate(1)
203+
204+
def test_cuda_module(language_with_cuda):
205+
import modules.cuda_module as mod
206+
207+
modnew = epyccel(mod, language=language_with_cuda)
208+
209+
atts = ('g', 'r0', 'rmin', 'rmax', 'skip_centre',
210+
'method', 'tiny')
211+
for att in atts:
212+
mod_att = getattr(mod, att)
213+
modnew_att = getattr(modnew, att)
214+
assert mod_att == modnew_att
215+
assert type(mod_att) is type(modnew_att)

0 commit comments

Comments
 (0)