Skip to content

Commit 72a3167

Browse files
authored
Merge pull request #1443 from IntelPython/improve/function_arg_mangling
Add the mangled_args property to kernel_api types.
2 parents 675cb79 + 71cc99f commit 72a3167

File tree

10 files changed

+100
-25
lines changed

10 files changed

+100
-25
lines changed

numba_dpex/core/debuginfo.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# SPDX-FileCopyrightText: 2020 - 2024 Intel Corporation
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
"""Implements a custom debug metadata generator class for numba-dpex kernels.
6+
"""
7+
8+
from numba.core import debuginfo
9+
10+
11+
class DIBuilder(debuginfo.DIBuilder):
12+
"""Overrides Numba's default DIBuilder with numba-dpex-specific customizations."""
13+
14+
# pylint: disable=too-many-arguments
15+
def mark_subprogram(self, function, qualname, argnames, argtypes, line):
16+
"""Sets DW_AT_name and DW_AT_linkagename tags for a kernel decorated function.
17+
18+
Numba generates a unique name for every function it compiles, but in
19+
upstream Numba the unique name is not used as the "qualified" name of
20+
the function. The behavior leads to a bug discovered in Numba-dpex when
21+
a compiled function uses closure variables.
22+
Refer (https://github.com/IntelPython/numba-dpex/issues/898).
23+
To resolve the issue numba-dpex uses the unique_name as the qualified
24+
name. Refer to
25+
:class:`numba_dpex.core.passes.passes.QualNameDisambiguationLowering`.
26+
However, doing so breaks setting GDB breakpoints based on function
27+
name as the function name is no longer what is in the source, but what
28+
is the unique name generated by Numba. To fix it, numba-dpex uses a
29+
modified DISubprogram metadata generator. The name (DW_AT_name) tag is
30+
set to the base function name, discarding the unique qualifier and
31+
linkagename is set to an empty string.
32+
"""
33+
name = qualname[0 : qualname.find("$")] # noqa: E203
34+
argmap = dict(zip(argnames, argtypes))
35+
36+
di_subp = self._add_subprogram(
37+
name=name,
38+
linkagename="",
39+
line=line,
40+
function=function,
41+
argmap=argmap,
42+
)
43+
function.set_metadata("dbg", di_subp)

numba_dpex/core/types/kernel_api/atomic_ref.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,3 +80,13 @@ def cast_python_value(self, args):
8080
AtomicRefType throws a NotImplementedError.
8181
"""
8282
raise NotImplementedError
83+
84+
@property
85+
def mangling_args(self):
86+
args = [
87+
self.dtype,
88+
self.memory_order,
89+
self.memory_scope,
90+
self.address_space,
91+
]
92+
return self.__class__.__name__, args

numba_dpex/core/types/kernel_api/index_space_ids.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ def key(self):
3131
def cast_python_value(self, args):
3232
raise NotImplementedError
3333

34+
@property
35+
def mangling_args(self):
36+
args = [self.ndim]
37+
return self.__class__.__name__, args
38+
3439

3540
class ItemType(types.Type):
3641
"""Numba-dpex type corresponding to :class:`numba_dpex.kernel_api.Item`"""
@@ -53,6 +58,11 @@ def key(self):
5358
"""Numba type specific overload"""
5459
return self._ndim
5560

61+
@property
62+
def mangling_args(self):
63+
args = [self.ndim]
64+
return self.__class__.__name__, args
65+
5666
def cast_python_value(self, args):
5767
raise NotImplementedError
5868

@@ -78,5 +88,10 @@ def key(self):
7888
"""Numba type specific overload"""
7989
return self._ndim
8090

91+
@property
92+
def mangling_args(self):
93+
args = [self.ndim]
94+
return self.__class__.__name__, args
95+
8196
def cast_python_value(self, args):
8297
raise NotImplementedError

numba_dpex/core/types/kernel_api/ranges.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ def ndim(self):
2828
def key(self):
2929
return self._ndim
3030

31+
@property
32+
def mangling_args(self):
33+
args = [self.ndim]
34+
return self.__class__.__name__, args
35+
3136

3237
class NdRangeType(types.Type):
3338
"""Numba-dpex type corresponding to
@@ -49,3 +54,8 @@ def ndim(self):
4954
@property
5055
def key(self):
5156
return self._ndim
57+
58+
@property
59+
def mangling_args(self):
60+
args = [self.ndim]
61+
return self.__class__.__name__, args

numba_dpex/kernel_api_impl/spirv/target.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import dpnp
1212
from llvmlite import binding as ll
1313
from llvmlite import ir as llvmir
14-
from numba.core import cgutils, funcdesc
14+
from numba.core import cgutils
1515
from numba.core import types as nb_types
1616
from numba.core import typing
1717
from numba.core.base import BaseContext
@@ -21,8 +21,10 @@
2121
from numba.core.typing import cmathdecl, enumdecl
2222

2323
from numba_dpex.core.datamodel.models import _init_kernel_data_model_manager
24+
from numba_dpex.core.debuginfo import DIBuilder as DpexDIbuilder
2425
from numba_dpex.core.types import IntEnumLiteral
2526
from numba_dpex.core.typing import dpnpdecl
27+
from numba_dpex.core.utils import itanium_mangler
2628
from numba_dpex.kernel_api.flag_enum import FlagEnum
2729
from numba_dpex.kernel_api.memory_enums import AddressSpace as address_space
2830
from numba_dpex.kernel_api_impl.spirv import printimpl
@@ -134,6 +136,7 @@ class SPIRVTargetContext(BaseContext):
134136

135137
implement_powi_as_math_call = True
136138
allow_dynamic_globals = True
139+
DIBuilder = DpexDIbuilder
137140

138141
def __init__(self, typingctx, target=SPIRV_TARGET_NAME):
139142
super().__init__(typingctx, target)
@@ -188,7 +191,7 @@ def _generate_spir_kernel_wrapper(self, func, argtypes):
188191
wrapper_module = self._internal_codegen.create_empty_spirv_module(
189192
"dpex.kernel.wrapper"
190193
)
191-
wrappername = func.name.replace("dpex_fn", "dpex_kernel")
194+
wrappername = func.name + ("dpex_kernel")
192195
argtys = list(arginfo.argument_types)
193196
fnty = llvmir.FunctionType(
194197
llvmir.IntType(32),
@@ -319,12 +322,9 @@ def target_data(self):
319322

320323
def mangler(self, name, types, *, abi_tags=(), uid=None):
321324
"""
322-
Generates a name for a function by appending \"dpex_fn\" to the
323-
name of the function before calling Numba's default function name
324-
mangler."""
325-
return funcdesc.default_mangler(
326-
name + "dpex_fn", types, abi_tags=abi_tags, uid=uid
327-
)
325+
Generates a mangled function name using numba_dpex's itanium mangler.
326+
"""
327+
return itanium_mangler.mangle(name, types, abi_tags=abi_tags, uid=uid)
328328

329329
def prepare_spir_kernel(self, func, argtypes):
330330
"""Generates a wrapper function with \"spir_kernel\" calling conv that

numba_dpex/tests/debugging/test_backtraces.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,5 @@ def test_backtrace(app):
2525

2626
app.backtrace()
2727

28-
app.expect(
29-
r"#0.*__main__::func_sum.* at simple_dpex_func.py:12", with_eol=True
30-
)
31-
app.expect(r"#1.*__main__::kernel_sum", with_eol=True)
28+
app.expect(r"#0.*func_sum.* at simple_dpex_func.py:12", with_eol=True)
29+
app.expect(r"#1.*kernel_sum", with_eol=True)

numba_dpex/tests/debugging/test_breakpoints.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,6 @@ def test_device_func_breakpoint(
5656
SAT-4449
5757
"""
5858

59-
if api == "numba-ndpx-kernel" and breakpoint != "side-by-side.py:15":
60-
pytest.skip(
61-
"Breakpoint by function name not working for numba-dpex."
62-
) # TODO: https://github.com/IntelPython/numba-dpex/issues/1242
63-
6459
app.breakpoint(breakpoint, condition=condition)
6560
app.run(f"side-by-side.py --api={api}")
6661
app.expect_hit_breakpoint("side-by-side.py:15")

numba_dpex/tests/debugging/test_info.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def test_info_functions(app):
104104

105105
app.info_functions("data_parallel_sum")
106106

107-
app.child.expect(r"11:\s+[a-z 0-9\*]+__main__::data_parallel_sum")
107+
app.child.expect(r"11:\s+[a-z 0-9\*]+data_parallel_sum")
108108

109109

110110
@pytest.mark.parametrize(

numba_dpex/tests/debugging/test_stepping.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def test_next(app: gdb):
3131
)
3232
# checking that we did not step in
3333
app.next()
34-
app.expect(r"in _ZN8__main__21kernel_sum_", with_eol=True)
34+
app.expect(r"in _ZN8__main__14kernel_sum_", with_eol=True)
3535

3636

3737
def test_step(app: gdb):
@@ -44,7 +44,7 @@ def test_step(app: gdb):
4444
)
4545
app.set_scheduler_lock()
4646
app.step()
47-
app.expect(r"__main__::func_sum.* at simple_dpex_func.py:12", with_eol=True)
47+
app.expect(r"func_sum.* at simple_dpex_func.py:12", with_eol=True)
4848
app.expect(r"12\s+result = a_in_func \+ b_in_func", with_eol=True)
4949
app.step()
5050
app.expect(

numba_dpex/tests/test_debuginfo.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,8 @@ def data_parallel_sum(item, a, b, c):
126126
c[i] = func_sum(a[i], b[i])
127127

128128
ir_tags = [
129-
r'\!DISubprogram\(name: ".*func_sum\$?\d*"',
130-
r'\!DISubprogram\(name: ".*data_parallel_sum\$?\d*"',
129+
r'\!DISubprogram\(name: ".*func_sum*"',
130+
r'\!DISubprogram\(name: ".*data_parallel_sum*"',
131131
]
132132

133133
sig = (itemty, f32arrty, f32arrty, f32arrty)
@@ -156,8 +156,8 @@ def data_parallel_sum(item, a, b, c):
156156
c[i] = func_sum(a[i], b[i])
157157

158158
ir_tags = [
159-
r'\!DISubprogram\(name: ".*func_sum\$?\d*"',
160-
r'\!DISubprogram\(name: ".*data_parallel_sum\$\d*"',
159+
r'\!DISubprogram\(name: ".*func_sum*"',
160+
r'\!DISubprogram\(name: ".*data_parallel_sum"',
161161
]
162162

163163
sig = (itemty, f32arrty, f32arrty, f32arrty)
@@ -176,6 +176,8 @@ def data_parallel_sum(item, a, b, c):
176176

177177

178178
def test_debuginfo_DISubprogram_linkageName():
179+
"""Tests to check that the linkagename tag is not set by numba-dpex."""
180+
179181
def foo(item, a, b):
180182
i = item.get_id(0)
181183
b[i] = a[i]
@@ -190,7 +192,9 @@ def foo(item, a, b):
190192
kernel_ir = kcres.library.get_llvm_str()
191193

192194
for tag in ir_tags:
193-
assert make_check(kernel_ir, tag)
195+
# Ensure that linkagename (DW_AT_linkagename) tag is not present for
196+
# the DISubprogram attribute.
197+
assert not make_check(kernel_ir, tag)
194198

195199

196200
def test_debuginfo_DICompileUnit_language_and_producer():

0 commit comments

Comments
 (0)