Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
1cd16ff
Add support for fp16 operators: add, sub, mul, fma, abs and neg
testhound Feb 16, 2022
3efd4fe
Correctly name classes for unary operators
testhound Feb 16, 2022
6c69b2c
Add support for inplace binary operators
testhound Feb 17, 2022
5188b28
Merge branch 'main' into testhound/fp16-operators1
testhound Feb 17, 2022
5b721ad
Change to use AbstractTemplate
testhound Mar 3, 2022
87b8c2c
Use ConcreteTemplate for intrinsics and AbstractTemplate for operators
testhound Mar 4, 2022
6809886
Merge branch 'main' into testhound/fp16-operators1
testhound Mar 4, 2022
7b36527
User @register_global to register operator lowering functions, update…
testhound Apr 15, 2022
9269ff7
Merge branch 'main' into testhound/fp16-operators1
testhound Apr 15, 2022
227ca5b
Fix registration of 'abs', add test cases to verify fp16 operators ar…
testhound Apr 15, 2022
fac30e2
Handle different argument types correctly for binary operators
testhound May 12, 2022
db03e4d
Merge branch 'main' into testhound/fp16-operators1
testhound May 12, 2022
5898b6b
Allow safe promotions and safe conversions for fp16 operators
testhound Jun 6, 2022
527973c
Add fp16 mixed type test for binary operators
testhound Jun 7, 2022
f10a4e5
Merge branch 'main' into testhound/fp16-operators1
testhound Jul 5, 2022
882ea3d
Document need for AbstractTemplate and ConcreateTemplate
testhound Jul 8, 2022
0b244ea
Seed RNG and pass additional paramater to self.subTest:
testhound Jul 8, 2022
a7129d4
Merge branch 'main' into testhound/fp16-operators1
testhound Jul 8, 2022
e1783fa
Merge branch 'main' into testhound/fp16-operators1
testhound Jul 25, 2022
7a7ad7d
Update comment description to recommendation by @gmarkall
testhound Jul 26, 2022
b2bef05
Add new case for function resolution of fp16 unary and binary operators
testhound Jul 26, 2022
021503f
Merge branch 'main' into testhound/fp16-operators1
testhound Jul 28, 2022
f26d289
Skip test if nvvm is not available
testhound Jul 29, 2022
8932a70
Simplify test cases and remove redundant assignments, fix comments
testhound Aug 17, 2022
a19874d
Merge branch 'main' into testhound/fp16-operators1
testhound Aug 17, 2022
fbc183d
Merge comments for binary and comparison fp16 operators
testhound Aug 19, 2022
cfeb49c
Merge branch 'main' into testhound/fp16-operators1
testhound Aug 19, 2022
aa4835c
Merge branch 'main' into testhound/fp16-operators1
testhound Sep 1, 2022
dd8498e
Add back erroneously removed skip if compute compatability is less th…
testhound Sep 6, 2022
277cf08
Merge branch 'main' into testhound/fp16-operators1
testhound Sep 6, 2022
224bd48
Skip tests unless cc >= 5.3
testhound Sep 8, 2022
95670b0
Merge branch 'main' into testhound/fp16-operators1
testhound Sep 8, 2022
ce23094
Streamline code by assing assertEqual
testhound Sep 9, 2022
8a96ff7
Merge branch 'main' into testhound/fp16-operators1
testhound Sep 12, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 38 additions & 2 deletions numba/cuda/cudadecl.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import operator
from numba.core import types, errors
from numba.core.typing.npydecl import (parse_dtype, parse_shape,
register_number_classes)
Expand Down Expand Up @@ -346,6 +347,19 @@ class Cuda_fp16_unary(ConcreteTemplate):
return Cuda_fp16_unary


def _genfp16_unary_operator(l_key):
@register
Comment thread
gmarkall marked this conversation as resolved.
Resolved
class Cuda_fp16_unary(AbstractTemplate):
key = l_key

def generic(self, args, kws):
assert not kws
Comment thread
gmarkall marked this conversation as resolved.
Resolved
if len(args) == 1 and args[0] == types.float16:
return signature(types.float16, types.float16)

return Cuda_fp16_unary


def _genfp16_binary(l_key):
@register
class Cuda_fp16_binary(ConcreteTemplate):
Expand All @@ -355,11 +369,33 @@ class Cuda_fp16_binary(ConcreteTemplate):
return Cuda_fp16_binary


def _genfp16_binary_operator(l_key):
@register
Comment thread
gmarkall marked this conversation as resolved.
Resolved
class Cuda_fp16_binary(AbstractTemplate):
key = l_key

def generic(self, args, kws):
assert not kws
if len(args) == 2 and \
(args[0] == types.float16 or args[1] == types.float16):
return signature(types.float16, types.float16, types.float16)

return Cuda_fp16_binary


Cuda_hadd = _genfp16_binary(cuda.fp16.hadd)
Cuda_add = _genfp16_binary_operator(operator.add)
Cuda_iadd = _genfp16_binary_operator(operator.iadd)
Cuda_hsub = _genfp16_binary(cuda.fp16.hsub)
Cuda_sub = _genfp16_binary_operator(operator.sub)
Cuda_isub = _genfp16_binary_operator(operator.isub)
Cuda_hmul = _genfp16_binary(cuda.fp16.hmul)
Cuda_hneg = _genfp16_unary(cuda.fp16.hneg)
Cuda_habs = _genfp16_unary(cuda.fp16.habs)
Cuda_mul = _genfp16_binary_operator(operator.mul)
Cuda_imul = _genfp16_binary_operator(operator.imul)
Cuda_hneg = _genfp16_unary_operator(cuda.fp16.hneg)
Cuda_neg = _genfp16_unary(operator.neg)
Cuda_habs = _genfp16_unary_operator(cuda.fp16.habs)
Cuda_abs = _genfp16_unary(operator.abs)


# generate atomic operations
Expand Down
16 changes: 16 additions & 0 deletions numba/cuda/cudaimpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,8 +489,14 @@ def ptx_fp16_binary(context, builder, sig, args):


lower_fp16_binary(stubs.fp16.hadd, 'add')
lower_fp16_binary(operator.add, 'add')
lower_fp16_binary(operator.iadd, 'add')
Comment thread
gmarkall marked this conversation as resolved.
Resolved
lower_fp16_binary(stubs.fp16.hsub, 'sub')
lower_fp16_binary(operator.sub, 'sub')
lower_fp16_binary(operator.isub, 'sub')
lower_fp16_binary(stubs.fp16.hmul, 'mul')
lower_fp16_binary(operator.mul, 'mul')
lower_fp16_binary(operator.imul, 'mul')


@lower(stubs.fp16.hneg, types.float16)
Expand All @@ -500,6 +506,11 @@ def ptx_fp16_hneg(context, builder, sig, args):
return builder.call(asm, args)


@lower(operator.neg, types.float16)
def operator_hneg(context, builder, sig, args):
return ptx_fp16_hneg(context, builder, sig, args)


@lower(stubs.fp16.habs, types.float16)
def ptx_fp16_habs(context, builder, sig, args):
if cuda.runtime.get_version() < (10, 2):
Expand All @@ -517,6 +528,11 @@ def ptx_fp16_habs(context, builder, sig, args):
return builder.call(asm, args)


@lower(abs, types.float16)
def operator_habs(context, builder, sig, args):
return ptx_fp16_habs(context, builder, sig, args)


@lower(stubs.fp16.hfma, types.float16, types.float16, types.float16)
def ptx_hfma(context, builder, sig, args):
argtys = [ir.IntType(16), ir.IntType(16), ir.IntType(16)]
Expand Down
57 changes: 56 additions & 1 deletion numba/cuda/tests/cudapy/test_operator.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,29 @@
import numpy as np
from numba.cuda.testing import unittest, CUDATestCase
from numba.cuda.testing import unittest, CUDATestCase, skip_unless_cc_53
from numba import cuda
import operator


def simple_fp16add(ary, a, b):
ary[0] = a + b


def simple_fp16sub(ary, a, b):
ary[0] = a - b


def simple_fp16mul(ary, a, b):
ary[0] = a * b


def simple_fp16neg(ary, a):
ary[0] = -a


def simple_fp16abs(ary, a):
ary[0] = abs(a)


class TestOperatorModule(CUDATestCase):
"""
Test if operator module is supported by the CUDA target.
Expand Down Expand Up @@ -36,6 +56,41 @@ def test_truediv(self):
def test_floordiv(self):
self.operator_template(operator.floordiv)

@skip_unless_cc_53
def test_fp16_binary(self):
functions = (simple_fp16add, simple_fp16sub, simple_fp16mul)
ops = (operator.add, operator.sub, operator.mul)

for fn, op in zip(functions, ops):
with self.subTest(op=op):
kernel = cuda.jit("void(f2[:], f2, f2)")(fn)

expected = np.zeros(1, dtype=np.float16)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment of expected is superfluous, as it is re-assigned on line 154.

Suggested change
expected = np.zeros(1, dtype=np.float16)

got = np.zeros(1, dtype=np.float16)
arg1 = np.random.random(1).astype(np.float16)
arg2 = np.random.random(1).astype(np.float16)

kernel[1, 1](got, arg1[0], arg2[0])
expected = op(arg1, arg2)
np.testing.assert_allclose(got[0], expected)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This compares the scalar first element of got with the array expected. It would be simpler and clearer to just compare the two arrays.

Suggested change
np.testing.assert_allclose(got[0], expected)
np.testing.assert_allclose(got, expected)


@skip_unless_cc_53
def test_fp16_unary(self):
functions = (simple_fp16neg, simple_fp16abs)
ops = (operator.neg, operator.abs)

for fn, op in zip(functions, ops):
with self.subTest(op=op):
kernel = cuda.jit("void(f2[:], f2)")(fn)

expected = np.zeros(1, dtype=np.float16)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Superfluous assignment:

Suggested change
expected = np.zeros(1, dtype=np.float16)

got = np.zeros(1, dtype=np.float16)
arg1 = np.random.random(1).astype(np.float16)

kernel[1, 1](got, arg1[0])
expected = op(arg1)
np.testing.assert_allclose(got[0], expected)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should compare arrays instead of a scalar and an array:

Suggested change
np.testing.assert_allclose(got[0], expected)
np.testing.assert_allclose(got, expected)



if __name__ == '__main__':
unittest.main()