Skip to content

Commit 9358bef

Browse files
author
Diptorup Deb
authored
Merge pull request #818 from IntelPython/dpex_587
Updated Numba-dpex to use Numba 0.56.
2 parents 219ec1c + 2f1c304 commit 9358bef

20 files changed

+358
-90
lines changed

.github/workflows/conda-package.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,8 @@ jobs:
9797
strategy:
9898
matrix:
9999
python: ["3.8", "3.9"]
100-
numba: ["0.55"]
100+
numba: ["0.56"]
101+
dpnp: ["0.11"]
101102

102103
steps:
103104
- name: Download artifact
@@ -126,7 +127,7 @@ jobs:
126127
run: |
127128
CHANNELS="-c $GITHUB_WORKSPACE/channel $CHANNELS"
128129
conda list
129-
conda create -n numba_dpex_env $PACKAGE_NAME pytest dpcpp_linux-64 python=${{ matrix.python }} numba=${{ matrix.numba }} dpctl dpnp $CHANNELS
130+
conda create -n numba_dpex_env $PACKAGE_NAME pytest dpcpp_linux-64 python=${{ matrix.python }} numba=${{ matrix.numba }} dpctl dpnp=${{ matrix.dpnp }} $CHANNELS
130131
# Test installed packages
131132
conda list
132133
- name: Check DPNP

conda-recipe/meta.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@ requirements:
1818
- python
1919
- setuptools
2020
- cython
21-
- numba 0.54*|0.55*
21+
- numba 0.56*
2222
- dpctl >=0.13.0
23-
- dpnp >=0.10.1
23+
- dpnp >=0.11*
2424
- wheel
2525
run:
2626
- python
27-
- numba >=0.54
27+
- numba >=0.56*
2828
- dpctl >=0.13.0
2929
- spirv-tools
3030
- llvm-spirv 11.*
31-
- dpnp >=0.10.1
31+
- dpnp >=0.11*
3232
- packaging
3333

3434
test:

environment.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,9 @@ dependencies:
1111
- gxx_linux-64
1212
- dpcpp_linux-64
1313
- cython
14-
- numba 0.55*
14+
- numba >=0.56*
1515
- dpctl >=0.14*
16-
- dpnp >=0.10.2
16+
- dpnp >=0.11*
1717
- mkl >=2021.3.0 # for dpnp
1818
- spirv-tools
1919
- packaging

environment/coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies:
1111
- gxx_linux-64
1212
- dpcpp_linux-64
1313
- cython
14-
- numba 0.55*
14+
- numba 0.56*
1515
- dpctl >=0.14*
1616
- dpnp >=0.10.2
1717
- spirv-tools

environment/docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ dependencies:
1111
- gxx_linux-64
1212
- dpcpp_linux-64
1313
- cython
14-
- numba 0.55*
14+
- numba 0.56*
1515
- dpctl 0.14*
1616
- dpnp >=0.10.2
1717
- spirv-tools

numba_dpex/core/itanium_mangler.py

Lines changed: 313 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,313 @@
1+
# SPDX-FileCopyrightText: 2020 - 2022 Intel Corporation
2+
#
3+
# SPDX-License-Identifier: Apache-2.0
4+
5+
"""
6+
Itanium CXX ABI Mangler
7+
8+
Reference: http://mentorembedded.github.io/cxx-abi/abi.html
9+
10+
The basics of the mangling scheme.
11+
12+
We are hijacking the CXX mangling scheme for our use. We map Python modules
13+
into CXX namespace. A `module1.submodule2.foo` is mapped to
14+
`module1::submodule2::foo`. For parameterized numba types, we treat them as
15+
templated types; for example, `array(int64, 1d, C)` becomes an
16+
`array<int64, 1, C>`.
17+
18+
All mangled names are prefixed with "_Z". It is followed by the name of the
19+
entity. A name contains one or more identifiers. Each identifier is encoded
20+
as "<num of char><name>". If the name is namespaced and, therefore,
21+
has multiple identifiers, the entire name is encoded as "N<name>E".
22+
23+
For functions, arguments types follow. There are condensed encodings for basic
24+
built-in types; e.g. "i" for int, "f" for float. For other types, the
25+
previously mentioned name encoding should be used.
26+
27+
For templated types, the template parameters are encoded immediately after the
28+
name. If it is namespaced, it should be within the 'N' 'E' marker. Template
29+
parameters are encoded in "I<params>E", where each parameter is encoded using
30+
the mentioned name encoding scheme. Template parameters can contain literal
31+
values like the '1' in the array type shown earlier. There is special encoding
32+
scheme for them to avoid leading digits.
33+
"""
34+
35+
36+
import re
37+
38+
from numba.core import types
39+
40+
41+
def mangle_type_or_value(typ):
42+
"""
43+
Mangle type parameter and arbitrary value.
44+
45+
This function extends Numba's `magle_type_or_value()` to
46+
support numba.types.CPointer type, e.g. an ``int *`` argument will be
47+
mangled to "Pi".
48+
Mangling of extended qualifiers is supported only
49+
for address space qualifiers. In which case, the mangling
50+
follows the rule defined in Section 5.1.5.1 of the ``Itanium ABI
51+
<https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangle.qualified-type>``_.
52+
For example, an ``int global *`` argument will be mangeled to "PU3AS1i".
53+
54+
Args:
55+
typ (numba.types, int, str) : Type to mangle
56+
57+
Returns:
58+
str: The mangled name of the type
59+
60+
"""
61+
if isinstance(typ, types.CPointer):
62+
rc = "P"
63+
if typ.addrspace is not None:
64+
rc += "U" + mangle_identifier("AS" + str(typ.addrspace))
65+
rc += mangle_type_or_value_numba(typ.dtype)
66+
return rc
67+
else:
68+
return mangle_type_or_value_numba(typ)
69+
70+
71+
def mangle_ext(ident, argtys, *, abi_tags=()):
72+
"""
73+
Mangle identifier with Numba type objects and abi-tags.
74+
"""
75+
kwargs = {}
76+
77+
# for support numba 0.54 and <=0.55.0dev0=*_469
78+
if abi_tags:
79+
kwargs["abi_tags"] = abi_tags
80+
81+
return PREFIX + mangle_identifier(ident, **kwargs) + mangle_args(argtys)
82+
83+
84+
# According the scheme, valid characters for mangled names are [a-zA-Z0-9_].
85+
# We borrow the '_' as the escape character to encode invalid char into
86+
# '_xx' where 'xx' is the hex codepoint.
87+
_re_invalid_char = re.compile(r"[^a-z0-9_]", re.I)
88+
89+
PREFIX = "_Z"
90+
91+
# C names to mangled type code
92+
C2CODE = {
93+
"void": "v",
94+
"wchar_t": "w",
95+
"bool": "b",
96+
"char": "c",
97+
"signed char": "a",
98+
"unsigned char": "h",
99+
"short": "s",
100+
"unsigned short": "t",
101+
"int": "i",
102+
"unsigned int": "j",
103+
"long": "l",
104+
"unsigned long": "m",
105+
"long long": "x", # __int64
106+
"unsigned long long": "y", # unsigned __int64
107+
"__int128": "n",
108+
"unsigned __int128": "o",
109+
"half": "Dh",
110+
"float": "f",
111+
"double": "d",
112+
"long double": "e", # __float80
113+
"__float128": "g",
114+
"ellipsis": "z",
115+
}
116+
117+
# Numba types to C names
118+
N2C = {
119+
types.void: "void",
120+
types.boolean: "bool",
121+
types.uint8: "unsigned char",
122+
types.int8: "signed char",
123+
types.uint16: "unsigned short",
124+
types.int16: "short",
125+
types.uint32: "unsigned int",
126+
types.int32: "int",
127+
types.uint64: "unsigned long long",
128+
types.int64: "long long",
129+
types.float16: "half",
130+
types.float32: "float",
131+
types.float64: "double",
132+
}
133+
134+
135+
def _escape_string(text):
136+
"""Escape the given string so that it only contains ASCII characters
137+
of [a-zA-Z0-9_$].
138+
139+
The dollar symbol ($) and other invalid characters are escaped into
140+
the string sequence of "$xx" where "xx" is the hex codepoint of the char.
141+
142+
Multibyte characters are encoded into utf8 and converted into the above
143+
hex format.
144+
"""
145+
146+
def repl(m):
147+
return "".join(("_%02x" % ch) for ch in m.group(0).encode("utf8"))
148+
149+
ret = re.sub(_re_invalid_char, repl, text)
150+
# Return str if we got a unicode (for py2)
151+
if not isinstance(ret, str):
152+
return ret.encode("ascii")
153+
return ret
154+
155+
156+
def _fix_lead_digit(text):
157+
"""
158+
Fix text with leading digit
159+
"""
160+
if text and text[0].isdigit():
161+
return "_" + text
162+
else:
163+
return text
164+
165+
166+
def _len_encoded(string):
167+
"""
168+
Prefix string with digit indicating the length.
169+
Add underscore if string is prefixed with digits.
170+
"""
171+
string = _fix_lead_digit(string)
172+
return "%u%s" % (len(string), string)
173+
174+
175+
def mangle_abi_tag(abi_tag: str) -> str:
176+
return "B" + _len_encoded(_escape_string(abi_tag))
177+
178+
179+
def mangle_identifier(ident, template_params="", *, abi_tags=(), uid=None):
180+
"""
181+
Mangle the identifier with optional template parameters and abi_tags.
182+
183+
Note:
184+
185+
This treats '.' as '::' in C++.
186+
"""
187+
# if uid is not None:
188+
# Add uid to abi-tags
189+
# abi_tags = (f"v{uid}", *abi_tags)
190+
parts = [_len_encoded(_escape_string(x)) for x in ident.split(".")]
191+
enc_abi_tags = list(map(mangle_abi_tag, abi_tags))
192+
extras = template_params + "".join(enc_abi_tags)
193+
if len(parts) > 1:
194+
return "N%s%sE" % ("".join(parts), extras)
195+
else:
196+
return "%s%s" % (parts[0], extras)
197+
198+
199+
def mangle_type_c(typ):
200+
"""
201+
Mangle C type name
202+
203+
Args
204+
----
205+
typ: str
206+
C type name
207+
"""
208+
if typ in C2CODE:
209+
return C2CODE[typ]
210+
else:
211+
return mangle_identifier(typ)
212+
213+
214+
def mangle_type_or_value_numba(typ):
215+
"""
216+
Mangle type parameter and arbitrary value.
217+
"""
218+
# Handle numba types
219+
if isinstance(typ, types.Type):
220+
if typ in N2C:
221+
return mangle_type_c(N2C[typ])
222+
else:
223+
return mangle_templated_ident(*typ.mangling_args)
224+
# Handle integer literal
225+
elif isinstance(typ, int):
226+
return "Li%dE" % typ
227+
# Handle str as identifier
228+
elif isinstance(typ, str):
229+
return mangle_identifier(typ)
230+
# Otherwise
231+
else:
232+
enc = _escape_string(str(typ))
233+
return _len_encoded(enc)
234+
235+
236+
# Alias
237+
mangle_type = mangle_type_or_value
238+
mangle_value = mangle_type_or_value
239+
240+
241+
def mangle_templated_ident(identifier, parameters):
242+
"""
243+
Mangle templated identifier.
244+
"""
245+
template_params = (
246+
"I%sE" % "".join(map(mangle_type_or_value, parameters))
247+
if parameters
248+
else ""
249+
)
250+
return mangle_identifier(identifier, template_params)
251+
252+
253+
def mangle_args_c(argtys):
254+
"""
255+
Mangle sequence of C type names
256+
"""
257+
return "".join([mangle_type_c(t) for t in argtys])
258+
259+
260+
def mangle_args(argtys):
261+
"""
262+
Mangle sequence of Numba type objects and arbitrary values.
263+
"""
264+
return "".join([mangle_type_or_value(t) for t in argtys])
265+
266+
267+
def mangle_c(ident, argtys):
268+
"""
269+
Mangle identifier with C type names
270+
"""
271+
return PREFIX + mangle_identifier(ident) + mangle_args_c(argtys)
272+
273+
274+
def mangle(ident, argtys, *, abi_tags=(), uid=None):
275+
"""
276+
Mangle identifier with Numba type objects and abi-tags.
277+
"""
278+
return "".join(
279+
[
280+
PREFIX,
281+
mangle_identifier(ident, abi_tags=abi_tags, uid=uid),
282+
mangle_args(argtys),
283+
]
284+
)
285+
286+
287+
def prepend_namespace(mangled, ns):
288+
"""
289+
Prepend namespace to mangled name.
290+
"""
291+
if not mangled.startswith(PREFIX):
292+
raise ValueError("input is not a mangled name")
293+
elif mangled.startswith(PREFIX + "N"):
294+
# nested
295+
remaining = mangled[3:]
296+
ret = PREFIX + "N" + mangle_identifier(ns) + remaining
297+
else:
298+
# non-nested
299+
remaining = mangled[2:]
300+
head, tail = _split_mangled_ident(remaining)
301+
ret = PREFIX + "N" + mangle_identifier(ns) + head + "E" + tail
302+
return ret
303+
304+
305+
def _split_mangled_ident(mangled):
306+
"""
307+
Returns `(head, tail)` where `head` is the `<len> + <name>` encoded
308+
identifier and `tail` is the remaining.
309+
"""
310+
ct = int(mangled)
311+
ctlen = len(str(ct))
312+
at = ctlen + ct
313+
return mangled[:at], mangled[at:]

numba_dpex/core/passes/passes.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,6 @@ def run_pass(self, state):
293293
# for support numba 0.54 and <=0.55.0dev0=*_469
294294
if hasattr(flags, "get_mangle_string"):
295295
kwargs["abi_tags"] = flags.get_mangle_string()
296-
297296
# Lowering
298297
fndesc = (
299298
funcdesc.PythonFunctionDescriptor.from_specialized_function(

0 commit comments

Comments
 (0)