Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
1975390
Initial changes for fp16 support
testhound Sep 21, 2021
98f9cd0
Merge branch 'master' into testhound/fp16-support
testhound Sep 21, 2021
8d30278
Add remaining fp16 operators except divide
testhound Oct 5, 2021
b51a32b
Merge branch 'master' into testhound/fp16-support
testhound Oct 6, 2021
7800f8d
Fix cuda simulation of fp16 operators
testhound Oct 6, 2021
9571f6e
Fix documentation underline error
testhound Oct 6, 2021
95727a4
Fix FROM_DTYPE for float16
testhound Oct 7, 2021
e6936e4
Fix failing ufunc testcase for fp16
testhound Oct 11, 2021
1c6a2bc
skip float16 arrays
testhound Oct 13, 2021
40751ce
Remove unnecessary operator handling, cpu target boxing/unboxing, ref…
testhound Oct 18, 2021
fd559ae
Simplify code generation for intrinsic fp16 mac, remove accidently co…
testhound Oct 18, 2021
caa6eeb
fp16 add/sub/mul/neg/absd oeprators: Add code to only run tests and l…
testhound Oct 28, 2021
186711b
Revert skip of unit test
testhound Oct 28, 2021
7f35c12
Skip fp16 unit tests if compute capability or toolkit version require…
testhound Oct 28, 2021
efee8a5
Pass fp16 arguments as int16 arguments to be consistent with nvcc
testhound Nov 10, 2021
164ae5b
Merge branch 'master' into testhound/fp16-support
testhound Nov 10, 2021
c3722ae
Move fp16 data model support to cuda model since there is no cpu supp…
testhound Nov 16, 2021
66e7d45
Initial support for casting from/to fp16 and other float/integer types
testhound Nov 24, 2021
2e4701d
Add lowering casts and tests case from/to fp16 to float32/float64/int…
testhound Nov 29, 2021
4feb427
Merge testhound/fp16-support with master Numba branch
testhound Nov 29, 2021
1821e0a
Split toolkit_and_compute_supported method into two separate methods …
testhound Nov 29, 2021
81eea70
Fix int to fp16 conversions, add more test cases, remove redundant ch…
testhound Dec 6, 2021
e8b66f3
Merge branch 'master' into testhound/fp16-support
testhound Dec 6, 2021
b462a87
Skip intrinsics tests when compiling for simulator
testhound Dec 6, 2021
99f74b8
Remove unnecessary test cases, add test cases for int literal to float16
testhound Dec 13, 2021
9f5d984
Merge branch 'master' into testhound/fp16-support
testhound Dec 13, 2021
fdca65c
Clarify comments and skip messages in test_intrinsics
gmarkall Dec 14, 2021
65686b5
Test casts of int and float literals to float16
gmarkall Dec 14, 2021
b6ae787
Formatting simplification in cudadecl.py
gmarkall Dec 14, 2021
5a1ae23
Simplify float16 lowering logic
gmarkall Dec 14, 2021
6689858
CUDA: Reorder FloatModel checks in ascending order
gmarkall Dec 14, 2021
750edaa
Use decorators to skip tests
gmarkall Dec 14, 2021
22e3286
Address PR #7460 feedback
gmarkall Dec 14, 2021
e734e9e
Add introduction to 16-bit FP intrinsics docs
gmarkall Dec 14, 2021
20c1d4f
Skip float16 casting test that uses arithmetic if CC < 5.3
gmarkall Dec 14, 2021
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
45 changes: 45 additions & 0 deletions docs/source/cuda-reference/kernel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,51 @@ precision parts of the CUDA Toolkit documentation.
``cbrt`` and ``cbrtf`` in the C api. Supports float32, and float64 arguments
only.

16-bit Floating Point Intrinsics
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Comment thread
stuartarchibald marked this conversation as resolved.
Resolved
.. function:: numba.cuda.fp16.hfma (a, b, c)

Perform the fused multiply-add operation ``(a * b) + c`` on 16-bit
floating point arguments in round to nearest mode. Maps to the ``fma.rn.f16``
PTX instruction.

Returns the fp16 result of the fused multiply-add.
Comment thread
gmarkall marked this conversation as resolved.
Resolved

.. function:: numba.cuda.fp16.hadd (a, b)

Perform the add operation ``a + b`` on 16-bit floating point arguments in
round to nearest mode. Maps to the ``add.f16`` PTX instruction.

Returns the 16-bit floating point result of the addition.

.. function:: numba.cuda.fp16.hsub (a, b)

Perform the subtract operation ``a - b`` on 16-bit floating point arguments in
round to nearest mode. Maps to the ``sub.f16`` PTX instruction.

Returns the 16-bit floating point result of the subtraction.

.. function:: numba.cuda.fp16.hmul (a, b)

Perform the multiply operation ``a * b`` on 16-bit floating point arguments in
round to nearest mode. Maps to the ``mul.f16`` PTX instruction.

Returns the 16-bit floating point result of the multiplication.

.. function:: numba.cuda.fp16.hneg (a)

Perform the negation operation ``-a`` on 1the 6-bit floating point argument.
Comment thread
gmarkall marked this conversation as resolved.
Resolved
Maps to the ``neg.f16`` PTX instruction.

Returns the 16-bit floating point result of the negation.

.. function:: numba.cuda.fp16.habs (a)

Perform the absolute value operation ``|a|`` on 1the 6-bit floating point argument.
Comment thread
gmarkall marked this conversation as resolved.
Resolved
Maps to the ``abs.f16`` PTX instruction.

Returns the 16-bit floating point result of the absolute value operation.

Control Flow Instructions
~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down
4 changes: 2 additions & 2 deletions numba/core/boxing.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def unbox_integer(typ, obj, c):

@box(types.Float)
def box_float(typ, val, c):
if typ == types.float32:
if typ == types.float32 or types == types.float16:
dbval = c.builder.fpext(val, c.pyapi.double)
else:
assert typ == types.float64
Expand All @@ -72,7 +72,7 @@ def unbox_float(typ, obj, c):
fobj = c.pyapi.number_float(obj)
dbval = c.pyapi.float_as_double(fobj)
c.pyapi.decref(fobj)
if typ == types.float32:
if typ == types.float32 or types == types.float16:
val = c.builder.fptrunc(dbval,
c.context.get_argument_type(typ))
else:
Expand Down
2 changes: 2 additions & 0 deletions numba/core/datamodel/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,8 @@ class FloatModel(PrimitiveModel):
def __init__(self, dmm, fe_type):
if fe_type == types.float32:
be_type = ir.FloatType()
elif fe_type == types.float16:
be_type = ir.HalfType()
elif fe_type == types.float64:
be_type = ir.DoubleType()
else:
Expand Down
2 changes: 2 additions & 0 deletions numba/core/itanium_mangler.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
'unsigned long long': 'y', # unsigned __int64
'__int128': 'n',
'unsigned __int128': 'o',
'float16' : 'Dh',

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.

Note to any other reviewers: correlates with https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling-builtin

'float': 'f',
'double': 'd',
'long double': 'e', # __float80
Expand All @@ -78,6 +79,7 @@
types.int32: 'int',
types.uint64: 'unsigned long long',
types.int64: 'long long',
types.float16: 'float16',
Comment thread
stuartarchibald marked this conversation as resolved.
Resolved
types.float32: 'float',
types.float64: 'double',
}
Expand Down
2 changes: 2 additions & 0 deletions numba/core/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@

float32 = Float('float32')
float64 = Float('float64')
float16 = Float('float16')

complex64 = Complex('complex64', float32)
complex128 = Complex('complex128', float64)
Expand Down Expand Up @@ -86,6 +87,7 @@
u4 = uint32
u8 = uint64

f2 = float16
f4 = float32
f8 = float64

Expand Down
5 changes: 5 additions & 0 deletions numba/core/typing/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,8 @@ class DivMod(ConcreteTemplate):
@infer_global(operator.pow)
class BinOpPower(ConcreteTemplate):
cases = list(integer_binop_cases)
cases += [signature(types.float16, types.float16, op)
for op in (types.int32, types.int64, types.uint64)]
# Ensure that float32 ** int doesn't go through DP computations
cases += [signature(types.float32, types.float32, op)
for op in (types.int32, types.int64, types.uint64)]
Expand All @@ -265,6 +267,8 @@ class BinOpPower(ConcreteTemplate):
@infer_global(operator.ipow)
class BinOpPower(ConcreteTemplate):
cases = list(integer_binop_cases)
cases += [signature(types.float16, types.float16, op)
for op in (types.int32, types.int64, types.uint64)]
# Ensure that float32 ** int doesn't go through DP computations
cases += [signature(types.float32, types.float32, op)
for op in (types.int32, types.int64, types.uint64)]
Expand Down Expand Up @@ -919,6 +923,7 @@ class Round(ConcreteTemplate):
cases = [
signature(types.intp, types.float32),
signature(types.int64, types.float64),
signature(types.float16, types.float16, types.intp),
signature(types.float32, types.float32, types.intp),
signature(types.float64, types.float64, types.intp),
]
Expand Down
5 changes: 4 additions & 1 deletion numba/cuda/compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import sys

import numpy as np

from numba import _dispatcher
from numba.core.typing.templates import AbstractTemplate, ConcreteTemplate
from numba.core import (types, typing, utils, funcdesc, serialize, config,
Expand Down Expand Up @@ -816,6 +815,10 @@ def _prepare_args(self, ty, val, stream, retr, kernelargs):
cval = getattr(ctypes, "c_%s" % ty)(val)
kernelargs.append(cval)

elif ty == types.float16:
cval = ctypes.c_uint16(np.float16(val).view(np.uint16))
kernelargs.append(cval)

elif ty == types.float64:
cval = ctypes.c_double(val)
kernelargs.append(cval)
Expand Down
63 changes: 63 additions & 0 deletions numba/cuda/cudadecl.py
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,14 @@ class Cuda_fma(ConcreteTemplate):
]


@register
class Cuda_hfma(ConcreteTemplate):
key = cuda.fp16.hfma
cases = [
signature(types.float16, types.float16, types.float16, types.float16)
]


@register
class Cuda_cbrt(ConcreteTemplate):

Expand Down Expand Up @@ -327,6 +335,35 @@ def generic(self, args, kws):
return signature(a, test, a, a)


def _genfp16_unary(l_key):
@register
class Cuda_fp16_unary(ConcreteTemplate):
key = l_key

cases = [
signature(types.float16, types.float16)
]
return Cuda_fp16_unary


def _genfp16_binary(l_key):
@register
class Cuda_fp16(ConcreteTemplate):
key = l_key

cases = [
signature(types.float16, types.float16, types.float16)
]
return Cuda_fp16


Cuda_hadd = _genfp16_binary(cuda.fp16.hadd)
Cuda_hsub = _genfp16_binary(cuda.fp16.hsub)
Cuda_hmul = _genfp16_binary(cuda.fp16.hmul)
Cuda_hneg = _genfp16_unary(cuda.fp16.hneg)
Cuda_habs = _genfp16_unary(cuda.fp16.habs)


# generate atomic operations
def _gen(l_key, supported_types):
@register
Expand Down Expand Up @@ -472,6 +509,29 @@ def resolve_compare_and_swap(self, mod):
return types.Function(Cuda_atomic_compare_and_swap)


@register_attr
class CudaFp16Template(AttributeTemplate):
key = types.Module(cuda.fp16)

def resolve_hadd(self, mod):
return types.Function(Cuda_hadd)

def resolve_hsub(self, mod):
return types.Function(Cuda_hsub)

def resolve_hmul(self, mod):
return types.Function(Cuda_hmul)

def resolve_hneg(self, mod):
return types.Function(Cuda_hneg)

def resolve_habs(self, mod):
return types.Function(Cuda_habs)

def resolve_hfma(self, mod):
return types.Function(Cuda_hfma)


@register_attr
class CudaModuleTemplate(AttributeTemplate):
key = types.Module(cuda)
Expand Down Expand Up @@ -575,6 +635,9 @@ def resolve_nanosleep(self, mod):
def resolve_atomic(self, mod):
return types.Module(cuda.atomic)

def resolve_fp16(self, mod):
return types.Module(cuda.fp16)

def resolve_const(self, mod):
return types.Module(cuda.const)

Expand Down
79 changes: 79 additions & 0 deletions numba/cuda/cudaimpl.py
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,85 @@ def ptx_popc(context, builder, sig, args):
def ptx_fma(context, builder, sig, args):
return builder.fma(*args)


@lower(stubs.fp16.hadd, types.float16, types.float16)
def ptx_hadd(context, builder, sig, args):
hadd_fn_type = ir.FunctionType(ir.HalfType(),
[ir.HalfType(), ir.HalfType()])
hadd_inline_asm = "add.f16 $0,$1,$2;"
hadd_inline_constraints = "=h,h,h"
hadd_inline = ir.InlineAsm(hadd_fn_type, hadd_inline_asm,
hadd_inline_constraints)
arg1 = args[0]
arg2 = args[1]
return builder.call(hadd_inline, [arg1, arg2])
Comment thread
gmarkall marked this conversation as resolved.
Resolved


@lower(stubs.fp16.hsub, types.float16, types.float16)
Comment thread
gmarkall marked this conversation as resolved.
Resolved
def ptx_hsub(context, builder, sig, args):
hsub_fn_type = ir.FunctionType(ir.HalfType(),
[ir.HalfType(), ir.HalfType()])
hsub_inline_asm = "sub.f16 $0,$1,$2;"
hsub_inline_constraints = "=h,h,h"
hsub_inline = ir.InlineAsm(hsub_fn_type, hsub_inline_asm,
hsub_inline_constraints)
arg1 = args[0]
arg2 = args[1]
return builder.call(hsub_inline, [arg1, arg2])


@lower(stubs.fp16.hmul, types.float16, types.float16)
def ptx_hmul(context, builder, sig, args):
hmul_fn_type = ir.FunctionType(ir.HalfType(),
[ir.HalfType(), ir.HalfType()])
hmul_inline_asm = "mul.f16 $0,$1,$2;"
hmul_inline_constraints = "=h,h,h"
hmul_inline = ir.InlineAsm(hmul_fn_type, hmul_inline_asm,
hmul_inline_constraints)
arg1 = args[0]
arg2 = args[1]
return builder.call(hmul_inline, [arg1, arg2])


@lower(stubs.fp16.hfma, types.float16, types.float16, types.float16)
def ptx_hfma(context, builder, sig, args):
hfma_fn_type = ir.FunctionType(ir.HalfType(),
[ir.HalfType(),
ir.HalfType(),
ir.HalfType()])
hfma_inline_asm = "fma.rn.f16 $0,$1,$2,$3;"
hfma_inline_constraints = "=h,h,h,h"
hfma_inline = ir.InlineAsm(hfma_fn_type, hfma_inline_asm,
hfma_inline_constraints)
arg1 = args[0]
arg2 = args[1]
arg3 = args[2]
return builder.call(hfma_inline, [arg1, arg2, arg3])

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.

Suggested change
arg1 = args[0]
arg2 = args[1]
arg3 = args[2]
return builder.call(hfma_inline, [arg1, arg2, arg3])
return builder.call(hfma_inline, args)



@lower(stubs.fp16.hneg, types.float16)
Comment thread
gmarkall marked this conversation as resolved.
Resolved
def ptx_hneg(context, builder, sig, args):
hneg_fn_type = ir.FunctionType(ir.HalfType(),
[ir.HalfType()])
hneg_inline_asm = "neg.f16 $0,$1;"
hneg_inline_constraints = "=h,h"
hneg_inline = ir.InlineAsm(hneg_fn_type, hneg_inline_asm,
hneg_inline_constraints)
arg1 = args[0]
return builder.call(hneg_inline, [arg1])


@lower(stubs.fp16.habs, types.float16)
def ptx_habs(context, builder, sig, args):
habs_fn_type = ir.FunctionType(ir.HalfType(),
[ir.HalfType()])
habs_inline_asm = "abs.f16 $0,$1;"
habs_inline_constraints = "=h,h"
habs_inline = ir.InlineAsm(habs_fn_type, habs_inline_asm,
habs_inline_constraints)
arg1 = args[0]
return builder.call(habs_inline, [arg1])

# See:
# https://docs.nvidia.com/cuda/libdevice-users-guide/__nv_cbrt.html#__nv_cbrt
# https://docs.nvidia.com/cuda/libdevice-users-guide/__nv_cbrtf.html#__nv_cbrtf
Expand Down
Loading