Skip to content

Commit 5e36ad2

Browse files
authored
Fix the worst Intel bugs (pyccel#2002)
This PR incorporate pyccel#1999 into the `devel` branch. pyccel#1999 included a workaround for an intel compiler bug. In the `devel` branch the intel branch wasn't working due to pyccel#2001 . This bug is not present in the `main` branch as there is a memory leak when returning arrays from functions (these arrays are never freed). The fix for this is non-standard and does not work with the Intel compiler. This is documented in pyccel#2001 however, for now, to prevent further Intel bugs being introduced without us noticing, the call to `free` is deactivated for the Intel compiler. This allows the tests to pass
1 parent 2ec91c4 commit 5e36ad2

File tree

6 files changed

+96
-107
lines changed

6 files changed

+96
-107
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ All notable changes to this project will be documented in this file.
108108
- \[INTERNALS\] Remove unused/unnecessary functions in `pyccel.parser.utilities` : `read_file`, `header_statement`, `accelerator_statement`, `get_module_name`, `view_tree`.
109109
- \[INTERNALS\] Remove unused functions `Errors.unset_target`, and `Errors.reset_target`.
110110

111-
## \[1.12.1\] - 2024-09-27
111+
## \[1.12.1\] - 2024-10-01
112112

113113
### Added
114114

pyccel/ast/builtins.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,7 @@ def __new__(cls, arg0, arg1=LiteralFloat(0)):
288288
return super().__new__(cls)
289289

290290
def __init__(self, arg0, arg1 = LiteralFloat(0)):
291-
self._is_cast = isinstance(arg0.dtype.primitive_type, PrimitiveComplexType) and \
292-
isinstance(arg1, Literal) and arg1.python_value == 0
291+
self._is_cast = isinstance(arg1, Literal) and arg1.python_value == 0
293292

294293
if self._is_cast:
295294
self._real_part = self._real_cast(arg0)

pyccel/codegen/pipeline.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ def handle_error(stage):
191191
# Get compiler object
192192
Compiler.acceptable_bin_paths = get_condaless_search_path(conda_warnings)
193193
src_compiler = Compiler(compiler, language, debug)
194-
wrapper_compiler = Compiler('GNU', 'c', debug)
194+
wrapper_compiler = Compiler(compiler, 'c', debug)
195195

196196
# Export the compiler information if requested
197197
if compiler_export_file:

pyccel/codegen/printing/fcode.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,8 +1547,11 @@ def _print_PythonFloat(self, expr):
15471547
def _print_PythonComplex(self, expr):
15481548
kind = self.print_kind(expr)
15491549
if expr.is_cast:
1550-
var = self._print(expr.internal_var)
1551-
code = f'cmplx({var}, kind = {kind})'
1550+
var = expr.internal_var
1551+
if isinstance(var.class_type.primitive_type, PrimitiveBooleanType):
1552+
var = PythonInt(var)
1553+
var_code = self._print(var)
1554+
code = f'cmplx({var_code}, kind = {kind})'
15521555
else:
15531556
real = self._print(expr.real)
15541557
imag = self._print(expr.imag)

pyccel/stdlib/cwrapper/cwrapper.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,10 @@ void get_strides_and_shape_from_numpy_array(PyObject* arr, int64_t shape[], int6
168168

169169
void capsule_cleanup(PyObject *capsule) {
170170
void *memory = PyCapsule_GetPointer(capsule, NULL);
171+
// TODO: Correct free method. See #2001
172+
#ifndef __INTEL_LLVM_COMPILER
171173
free(memory);
174+
#endif
172175
}
173176

174177
#ifdef _WIN32

tests/epyccel/recognised_functions/test_numpy_types.py

Lines changed: 85 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from test_numpy_funcs import (min_int, max_int, min_int8, max_int8,
88
min_int16, max_int16, min_int32, max_int32, max_int64, min_int64)
99
from test_numpy_funcs import max_float, min_float, max_float32, min_float32,max_float64, min_float64
10-
from test_numpy_funcs import matching_types
10+
from test_numpy_funcs import matching_types, RTOL, ATOL, RTOL32, ATOL32
1111

1212
from pyccel.decorators import template
1313
from pyccel import epyccel
@@ -190,13 +190,11 @@ def get_bool(a : 'T'):
190190
assert f_integer32_output == test_int32_output
191191
assert matching_types(f_integer32_output, test_int32_output)
192192

193-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
194-
if sys.platform != 'win32':
195-
f_integer64_output = epyccel_func(integer64)
196-
test_int64_output = get_bool(integer64)
193+
f_integer64_output = epyccel_func(integer64)
194+
test_int64_output = get_bool(integer64)
197195

198-
assert f_integer64_output == test_int64_output
199-
assert matching_types(f_integer64_output, test_int64_output)
196+
assert f_integer64_output == test_int64_output
197+
assert matching_types(f_integer64_output, test_int64_output)
200198

201199
f_fl_output = epyccel_func(fl)
202200
test_float_output = get_bool(fl)
@@ -312,31 +310,29 @@ def test_numpy_int_scalar(language, function_boundaries):
312310
assert f_integer32_output == test_int32_output
313311
assert matching_types(f_integer32_output, test_int32_output)
314312

315-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
316-
if sys.platform != 'win32':
317-
f_integer64_output = epyccel_func(integer64)
318-
test_int64_output = get_int(integer64)
313+
f_integer64_output = epyccel_func(integer64)
314+
test_int64_output = get_int(integer64)
319315

320-
assert f_integer64_output == test_int64_output
321-
assert matching_types(f_integer64_output, test_int64_output)
316+
assert f_integer64_output == test_int64_output
317+
assert matching_types(f_integer64_output, test_int64_output)
322318

323-
f_fl_output = epyccel_func(fl)
324-
test_float_output = get_int(fl)
319+
f_fl_output = epyccel_func(fl)
320+
test_float_output = get_int(fl)
325321

326-
assert f_fl_output == test_float_output
327-
assert matching_types(f_fl_output, test_float_output)
322+
assert f_fl_output == test_float_output
323+
assert matching_types(f_fl_output, test_float_output)
328324

329-
f_fl64_output = epyccel_func(fl64)
330-
test_float64_output = get_int(fl64)
325+
f_fl64_output = epyccel_func(fl64)
326+
test_float64_output = get_int(fl64)
331327

332-
assert f_fl64_output == test_float64_output
333-
assert matching_types(f_fl64_output, test_float64_output)
328+
assert f_fl64_output == test_float64_output
329+
assert matching_types(f_fl64_output, test_float64_output)
334330

335-
f_fl32_output = epyccel_func(fl32)
336-
test_float32_output = get_int(fl32)
331+
f_fl32_output = epyccel_func(fl32)
332+
test_float32_output = get_int(fl32)
337333

338-
assert f_fl32_output == test_float32_output
339-
assert matching_types(f_fl32_output, test_float32_output)
334+
assert f_fl32_output == test_float32_output
335+
assert matching_types(f_fl32_output, test_float32_output)
340336

341337
@template('T', ['bool[:]', 'int[:]', 'int8[:]', 'int16[:]', 'int32[:]', 'int64[:]', 'float[:]', 'float32[:]', 'float64[:]'])
342338
def get_int64_arr_1d(arr : 'T'):
@@ -399,12 +395,10 @@ def test_numpy_int_array_like_1d(language, function_boundaries):
399395
assert epyccel_func(integer16) == get_int(integer16)
400396
assert epyccel_func(integer) == get_int(integer)
401397
assert epyccel_func(integer32) == get_int(integer32)
402-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
403-
if sys.platform != 'win32':
404-
assert epyccel_func(integer64) == get_int(integer64)
405-
assert epyccel_func(fl) == get_int(fl)
406-
assert epyccel_func(fl64) == get_int(fl64)
407-
assert epyccel_func(fl32) == get_int(fl32)
398+
assert epyccel_func(integer64) == get_int(integer64)
399+
assert epyccel_func(fl) == get_int(fl)
400+
assert epyccel_func(fl64) == get_int(fl64)
401+
assert epyccel_func(fl32) == get_int(fl32)
408402

409403
@template('T', ['bool[:,:]', 'int[:,:]', 'int8[:,:]', 'int16[:,:]', 'int32[:,:]', 'int64[:,:]', 'float[:,:]', 'float32[:,:]', 'float64[:,:]'])
410404
def get_int64_arr_2d(arr : 'T'):
@@ -467,12 +461,10 @@ def test_numpy_int_array_like_2d(language, function_boundaries):
467461
assert epyccel_func(integer16) == get_int(integer16)
468462
assert epyccel_func(integer) == get_int(integer)
469463
assert epyccel_func(integer32) == get_int(integer32)
470-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
471-
if sys.platform != 'win32':
472-
assert epyccel_func(integer64) == get_int(integer64)
473-
assert epyccel_func(fl) == get_int(fl)
474-
assert epyccel_func(fl64) == get_int(fl64)
475-
assert epyccel_func(fl32) == get_int(fl32)
464+
assert epyccel_func(integer64) == get_int(integer64)
465+
assert epyccel_func(fl) == get_int(fl)
466+
assert epyccel_func(fl64) == get_int(fl64)
467+
assert epyccel_func(fl32) == get_int(fl32)
476468

477469
@template('T', ['bool', 'int', 'int8', 'int16', 'int32', 'int64', 'float', 'float32', 'float64'])
478470
def get_float(a : 'T'):
@@ -550,13 +542,11 @@ def test_numpy_float_scalar(language, get_float):
550542
assert f_integer32_output == test_int32_output
551543
assert matching_types(f_integer32_output, test_int32_output)
552544

553-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
554-
if sys.platform != 'win32':
555-
f_integer64_output = epyccel_func(integer64)
556-
test_int64_output = get_float(integer64)
545+
f_integer64_output = epyccel_func(integer64)
546+
test_int64_output = get_float(integer64)
557547

558-
assert f_integer64_output == test_int64_output
559-
assert matching_types(f_integer64_output, test_int64_output)
548+
assert f_integer64_output == test_int64_output
549+
assert matching_types(f_integer64_output, test_int64_output)
560550

561551
f_fl_output = epyccel_func(fl)
562552
test_float_output = get_float(fl)
@@ -616,11 +606,9 @@ def test_numpy_float_array_like_1d(language, get_float):
616606
assert epyccel_func(integer16) == get_float(integer16)
617607
assert epyccel_func(integer) == get_float(integer)
618608
assert epyccel_func(integer32) == get_float(integer32)
619-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
620-
if sys.platform != 'win32':
621-
assert epyccel_func(integer64) == get_float(integer64)
622-
assert epyccel_func(fl) == get_float(fl)
623-
assert epyccel_func(fl64) == get_float(fl64)
609+
assert epyccel_func(integer64) == get_float(integer64)
610+
assert epyccel_func(fl) == get_float(fl)
611+
assert epyccel_func(fl64) == get_float(fl64)
624612
assert epyccel_func(fl32) == get_float(fl32)
625613

626614
@template('T', ['bool[:,:]', 'int[:,:]', 'int8[:,:]', 'int16[:,:]', 'int32[:,:]', 'int64[:,:]', 'float[:,:]', 'float32[:,:]', 'float64[:,:]'])
@@ -662,11 +650,9 @@ def test_numpy_float_array_like_2d(language, get_float):
662650
assert epyccel_func(integer16) == get_float(integer16)
663651
assert epyccel_func(integer) == get_float(integer)
664652
assert epyccel_func(integer32) == get_float(integer32)
665-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
666-
if sys.platform != 'win32':
667-
assert epyccel_func(integer64) == get_float(integer64)
668-
assert epyccel_func(fl) == get_float(fl)
669-
assert epyccel_func(fl64) == get_float(fl64)
653+
assert epyccel_func(integer64) == get_float(integer64)
654+
assert epyccel_func(fl) == get_float(fl)
655+
assert epyccel_func(fl64) == get_float(fl64)
670656
assert epyccel_func(fl32) == get_float(fl32)
671657

672658
def test_numpy_double_scalar(language):
@@ -727,13 +713,11 @@ def get_double(a : 'T'):
727713
assert f_integer32_output == test_int32_output
728714
assert matching_types(f_integer32_output, test_int32_output)
729715

730-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
731-
if sys.platform != 'win32':
732-
f_integer64_output = epyccel_func(integer64)
733-
test_int64_output = get_double(integer64)
716+
f_integer64_output = epyccel_func(integer64)
717+
test_int64_output = get_double(integer64)
734718

735-
assert f_integer64_output == test_int64_output
736-
assert matching_types(f_integer64_output, test_int64_output)
719+
assert f_integer64_output == test_int64_output
720+
assert matching_types(f_integer64_output, test_int64_output)
737721

738722
f_fl_output = epyccel_func(fl)
739723
test_float_output = get_double(fl)
@@ -785,11 +769,9 @@ def get_double(arr : 'T'):
785769
assert epyccel_func(integer16) == get_double(integer16)
786770
assert epyccel_func(integer) == get_double(integer)
787771
assert epyccel_func(integer32) == get_double(integer32)
788-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
789-
if sys.platform != 'win32':
790-
assert epyccel_func(integer64) == get_double(integer64)
791-
assert epyccel_func(fl) == get_double(fl)
792-
assert epyccel_func(fl64) == get_double(fl64)
772+
assert epyccel_func(integer64) == get_double(integer64)
773+
assert epyccel_func(fl) == get_double(fl)
774+
assert epyccel_func(fl64) == get_double(fl64)
793775
assert epyccel_func(fl32) == get_double(fl32)
794776

795777
def test_numpy_double_array_like_2d(language):
@@ -823,11 +805,9 @@ def get_double(arr : 'T'):
823805
assert epyccel_func(integer16) == get_double(integer16)
824806
assert epyccel_func(integer) == get_double(integer)
825807
assert epyccel_func(integer32) == get_double(integer32)
826-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
827-
if sys.platform != 'win32':
828-
assert epyccel_func(integer64) == get_double(integer64)
829-
assert epyccel_func(fl) == get_double(fl)
830-
assert epyccel_func(fl64) == get_double(fl64)
808+
assert epyccel_func(integer64) == get_double(integer64)
809+
assert epyccel_func(fl) == get_double(fl)
810+
assert epyccel_func(fl64) == get_double(fl64)
831811
assert epyccel_func(fl32) == get_double(fl32)
832812

833813

@@ -906,13 +886,11 @@ def test_numpy_complex_scalar(language, get_complex):
906886
assert f_integer32_output == test_int32_output
907887
assert matching_types(f_integer32_output, test_int32_output)
908888

909-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
910-
if sys.platform != 'win32':
911-
f_integer64_output = epyccel_func(integer64)
912-
test_int64_output = get_complex(integer64)
889+
f_integer64_output = epyccel_func(integer64)
890+
test_int64_output = get_complex(integer64)
913891

914-
assert f_integer64_output == test_int64_output
915-
assert matching_types(f_integer64_output, test_int64_output)
892+
assert f_integer64_output == test_int64_output
893+
assert matching_types(f_integer64_output, test_int64_output)
916894

917895
f_fl_output = epyccel_func(fl)
918896
test_float_output = get_complex(fl)
@@ -986,24 +964,27 @@ def test_numpy_complex_array_like_1d(language, get_complex):
986964
integer32 = randint(min_int32, max_int32, size=size, dtype=np.int32)
987965
integer64 = randint(min_int64, max_int64, size=size, dtype=np.int64)
988966

989-
fl = uniform(min_float / 2, max_float / 2, size = size)
967+
# float32 is used as the maximum for all float types to avoid overflow errors
968+
fl = uniform(min_float32 / 2, max_float32 / 2, size = size)
990969
fl32 = uniform(min_float32 / 2, max_float32 / 2, size = size)
991970
fl32 = np.float32(fl32)
992-
fl64 = uniform(min_float64 / 2, max_float64 / 2, size = size)
971+
fl64 = uniform(min_float32 / 2, max_float32 / 2, size = size)
993972

994973
epyccel_func = epyccel(get_complex, language=language)
995974

996-
assert epyccel_func(bl) == get_complex(bl)
997-
assert epyccel_func(integer8) == get_complex(integer8)
998-
assert epyccel_func(integer16) == get_complex(integer16)
999-
assert epyccel_func(integer) == get_complex(integer)
1000-
assert epyccel_func(integer32) == get_complex(integer32)
1001-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
1002-
if sys.platform != 'win32':
1003-
assert epyccel_func(integer64) == get_complex(integer64)
1004-
assert epyccel_func(fl) == get_complex(fl)
1005-
assert epyccel_func(fl64) == get_complex(fl64)
1006-
assert epyccel_func(fl32) == get_complex(fl32)
975+
is_complex64 = get_complex(bl)[-1].dtype == np.complex64
976+
rtol = RTOL32 if is_complex64 else RTOL
977+
atol = ATOL32 if is_complex64 else ATOL
978+
979+
assert np.allclose(epyccel_func(bl), get_complex(bl), rtol=rtol, atol=atol)
980+
assert np.allclose(epyccel_func(integer8), get_complex(integer8), rtol=rtol, atol=atol)
981+
assert np.allclose(epyccel_func(integer16), get_complex(integer16), rtol=rtol, atol=atol)
982+
assert np.allclose(epyccel_func(integer), get_complex(integer), rtol=rtol, atol=atol)
983+
assert np.allclose(epyccel_func(integer32), get_complex(integer32), rtol=rtol, atol=atol)
984+
assert np.allclose(epyccel_func(integer64), get_complex(integer64), rtol=rtol, atol=atol)
985+
assert np.allclose(epyccel_func(fl), get_complex(fl), rtol=rtol, atol=atol)
986+
assert np.allclose(epyccel_func(fl64), get_complex(fl64), rtol=rtol, atol=atol)
987+
assert np.allclose(epyccel_func(fl32), get_complex(fl32), rtol=rtol, atol=atol)
1007988

1008989
@pytest.mark.parametrize( 'language', (
1009990
pytest.param("fortran", marks = [pytest.mark.fortran]),
@@ -1028,24 +1009,27 @@ def test_numpy_complex_array_like_2d(language, get_complex):
10281009
integer32 = randint(min_int32, max_int32, size=size, dtype=np.int32)
10291010
integer64 = randint(min_int64, max_int64, size=size, dtype=np.int64)
10301011

1031-
fl = uniform(min_float / 2, max_float / 2, size = size)
1012+
# float32 is used as the maximum for all float types to avoid overflow errors
1013+
fl = uniform(min_float32 / 2, max_float32 / 2, size = size)
10321014
fl32 = uniform(min_float32 / 2, max_float32 / 2, size = size)
10331015
fl32 = np.float32(fl32)
1034-
fl64 = uniform(min_float64 / 2, max_float64 / 2, size = size)
1016+
fl64 = uniform(min_float32 / 2, max_float32 / 2, size = size)
10351017

10361018
epyccel_func = epyccel(get_complex, language=language)
10371019

1038-
assert epyccel_func(bl) == get_complex(bl)
1039-
assert epyccel_func(integer8) == get_complex(integer8)
1040-
assert epyccel_func(integer16) == get_complex(integer16)
1041-
assert epyccel_func(integer) == get_complex(integer)
1042-
assert epyccel_func(integer32) == get_complex(integer32)
1043-
# the if block should be removed after resolving (https://github.com/pyccel/pyccel/issues/735).
1044-
if sys.platform != 'win32':
1045-
assert epyccel_func(integer64) == get_complex(integer64)
1046-
assert epyccel_func(fl) == get_complex(fl)
1047-
assert epyccel_func(fl64) == get_complex(fl64)
1048-
assert epyccel_func(fl32) == get_complex(fl32)
1020+
is_complex64 = get_complex(bl)[-1].dtype == np.complex64
1021+
rtol = RTOL32 if is_complex64 else RTOL
1022+
atol = ATOL32 if is_complex64 else ATOL
1023+
1024+
assert np.allclose(epyccel_func(bl), get_complex(bl), rtol=rtol, atol=atol)
1025+
assert np.allclose(epyccel_func(integer8), get_complex(integer8), rtol=rtol, atol=atol)
1026+
assert np.allclose(epyccel_func(integer16), get_complex(integer16), rtol=rtol, atol=atol)
1027+
assert np.allclose(epyccel_func(integer), get_complex(integer), rtol=rtol, atol=atol)
1028+
assert np.allclose(epyccel_func(integer32), get_complex(integer32), rtol=rtol, atol=atol)
1029+
assert np.allclose(epyccel_func(integer64), get_complex(integer64), rtol=rtol, atol=atol)
1030+
assert np.allclose(epyccel_func(fl), get_complex(fl), rtol=rtol, atol=atol)
1031+
assert np.allclose(epyccel_func(fl64), get_complex(fl64), rtol=rtol, atol=atol)
1032+
assert np.allclose(epyccel_func(fl32), get_complex(fl32), rtol=rtol, atol=atol)
10491033

10501034
def test_literal_complex64(language):
10511035
def get_complex64():

0 commit comments

Comments
 (0)