[Libclc-dev] [PATCH 2/2] math: Add ldexp implementation

Aaron Watry awatry at gmail.com
Fri Mar 13 07:50:56 PDT 2015


On Thu, Mar 12, 2015 at 10:13 PM, Tom Stellard <tom at stellard.net> wrote:

> On Thu, Mar 12, 2015 at 08:48:13PM -0500, Aaron Watry wrote:
> > Signed-off-by: Aaron Watry <awatry at gmail.com>
> > ---
> >  generic/include/clc/clc.h                |   1 +
> >  generic/include/clc/math/binary_decl.inc |  18 ++++-
> >  generic/include/clc/math/gentype_tss.inc | 108
> +++++++++++++++++++++++++++++
> >  generic/include/clc/math/ldexp.h         |   9 +++
> >  generic/lib/SOURCES                      |   1 +
> >  generic/lib/clcmacro.h                   |  26 +++++++
> >  generic/lib/math/ldexp.cl                | 114
> +++++++++++++++++++++++++++++++
>
> I just sent out a patch implementing an optimized ldexp for R600/SI.
> I was able create the declarations and definitions without having to
> modify too many of the *.inc files or adding new macros to clcmacro.h
>
> I think we should try a similar approach for the generic version.
>
>
Fair enough.  We might as well piggy-back on what you did for the R600/SI
version.


> >  7 files changed, 274 insertions(+), 3 deletions(-)
> >  create mode 100644 generic/include/clc/math/gentype_tss.inc
> >  create mode 100644 generic/include/clc/math/ldexp.h
> >  create mode 100644 generic/lib/math/ldexp.cl
> >
> > diff --git a/generic/include/clc/clc.h b/generic/include/clc/clc.h
> > index 1c12cf3..ecabcf1 100644
> > --- a/generic/include/clc/clc.h
> > +++ b/generic/include/clc/clc.h
> > @@ -51,6 +51,7 @@
> >  #include <clc/math/fmin.h>
> >  #include <clc/math/fmod.h>
> >  #include <clc/math/hypot.h>
> > +#include <clc/math/ldexp.h>
> >  #include <clc/math/log.h>
> >  #include <clc/math/log10.h>
> >  #include <clc/math/log1p.h>
> > diff --git a/generic/include/clc/math/binary_decl.inc
> b/generic/include/clc/math/binary_decl.inc
> > index 70a7114..1805527 100644
> > --- a/generic/include/clc/math/binary_decl.inc
> > +++ b/generic/include/clc/math/binary_decl.inc
> > @@ -1,6 +1,18 @@
> > -_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_FUNCTION(__CLC_GENTYPE a,
> __CLC_GENTYPE b);
> > -_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_FUNCTION(__CLC_GENTYPE a,
> float b);
> > +#ifdef __CLC_INT_GENTYPE
> > +  #if !defined(__CLC_SCALAR)
> > +    _CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_FUNCTION(__CLC_GENTYPE
> a, __CLC_INT_GENTYPE b);
> > +  #endif
> > +    _CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_FUNCTION(__CLC_GENTYPE
> a, __CLC_SCALAR_INT_TYPE b);
> > +
> > +#else
> > +
> > +#if !defined(__CLC_SCALAR)
> > +  _CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_FUNCTION(__CLC_GENTYPE a,
> __CLC_GENTYPE b);
> > +#endif
> > +  _CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_FUNCTION(__CLC_GENTYPE a,
> float b);
> >
> >  #ifdef cl_khr_fp64
> > -_CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_FUNCTION(__CLC_GENTYPE a,
> double b);
> > +  _CLC_OVERLOAD _CLC_DECL __CLC_GENTYPE __CLC_FUNCTION(__CLC_GENTYPE a,
> double b);
> > +#endif
> > +
> >  #endif
> > diff --git a/generic/include/clc/math/gentype_tss.inc
> b/generic/include/clc/math/gentype_tss.inc
> > new file mode 100644
> > index 0000000..11ec9ff
> > --- /dev/null
> > +++ b/generic/include/clc/math/gentype_tss.inc
> > @@ -0,0 +1,108 @@
> > +/* Used to provide support for multi-arg functions where the argument
> types and/or sizes do NOT match
> > + *
> > + *  e.g. ldexp(float16,int), ldexp(float16,int16), ldexp(double8, int)
> > + *
> > + * In general, consumers of this include will probably have versions
> with a vector first argument, and then
> > + * vector/scalar 2nd argument which may have an entirely different base
> type.
> > + */
> > +
> > +#define __CLC_SCALAR_GENTYPE float
> > +#ifndef __CLC_SCALAR_INT_TYPE
> > +    #define __CLC_UNDEF_SCALAR_INT_TYPE
> > +    #define __CLC_SCALAR_INT_TYPE int
> > +#endif
> > +#define __CLC_FPSIZE 32
> > +
> > +#define __CLC_GENTYPE float
> > +#define __CLC_INT_GENTYPE int
> > +#define __CLC_SCALAR
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +#undef __CLC_SCALAR
> > +
> > +#define __CLC_GENTYPE float2
> > +#define __CLC_INT_GENTYPE int2
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE float3
> > +#define __CLC_INT_GENTYPE int3
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE float4
> > +#define __CLC_INT_GENTYPE int4
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE float8
> > +#define __CLC_INT_GENTYPE int8
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE float16
> > +#define __CLC_INT_GENTYPE int16
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#undef __CLC_FPSIZE
> > +#undef __CLC_SCALAR_GENTYPE
> > +
> > +#ifdef cl_khr_fp64
> > +#define __CLC_SCALAR_GENTYPE double
> > +#define __CLC_FPSIZE 64
> > +
> > +#define __CLC_SCALAR
> > +#define __CLC_GENTYPE double
> > +#define __CLC_INT_GENTYPE int
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_SCALAR
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE double2
> > +#define __CLC_INT_GENTYPE int2
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE double3
> > +#define __CLC_INT_GENTYPE int3
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE double4
> > +#define __CLC_INT_GENTYPE int4
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE double8
> > +#define __CLC_INT_GENTYPE int8
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#define __CLC_GENTYPE double16
> > +#define __CLC_INT_GENTYPE int16
> > +#include __CLC_BODY
> > +#undef __CLC_GENTYPE
> > +#undef __CLC_INT_GENTYPE
> > +
> > +#undef __CLC_FPSIZE
> > +#undef __CLC_SCALAR_GENTYPE
> > +#endif
> > +
> > +#ifdef __CLC_UNDEF_SCALAR_INT_TYPE
> > +    #undef __CLC_SCALAR_INT_TYPE
> > +    #undef __CLC_UNDEF_SCALAR_INT_TYPE
> > +#endif
> > +
> > +#undef __CLC_BODY
> > diff --git a/generic/include/clc/math/ldexp.h
> b/generic/include/clc/math/ldexp.h
> > new file mode 100644
> > index 0000000..2e3b502
> > --- /dev/null
> > +++ b/generic/include/clc/math/ldexp.h
> > @@ -0,0 +1,9 @@
> > +#define __CLC_BODY <clc/math/binary_decl.inc>
> > +#define __CLC_FUNCTION ldexp
> > +
> > +#include <clc/math/gentype_tss.inc>
> > +
> > +#undef __CLC_BODY
> > +#undef __CLC_FUNCTION
> > +
> > +#undef __CLC_ARG2_BASE_TYPE
> > \ No newline at end of file
> > diff --git a/generic/lib/SOURCES b/generic/lib/SOURCES
> > index 0110e15..be6865e 100644
> > --- a/generic/lib/SOURCES
> > +++ b/generic/lib/SOURCES
> > @@ -70,6 +70,7 @@ math/fmax.cl
> >  math/fmin.cl
> >  math/fmod.cl
> >  math/hypot.cl
> > +math/ldexp.cl
> >  math/log10.cl
> >  math/log1p.cl
> >  math/mad.cl
> > diff --git a/generic/lib/clcmacro.h b/generic/lib/clcmacro.h
> > index 346adf2..3f389e5 100644
> > --- a/generic/lib/clcmacro.h
> > +++ b/generic/lib/clcmacro.h
> > @@ -41,6 +41,28 @@
> >      return (RET_TYPE##16)(FUNCTION(x.lo, y.lo), FUNCTION(x.hi, y.hi)); \
> >    }
> >
> > +#define _CLC_BINARY_VECTORIZE_SCALAR_SECOND_ARG(DECLSPEC, RET_TYPE,
> FUNCTION, ARG1_TYPE, ARG2_TYPE) \
> > +  DECLSPEC RET_TYPE##2 FUNCTION(ARG1_TYPE##2 x, ARG2_TYPE y) { \
> > +    return (RET_TYPE##2)(FUNCTION(x.x, y), FUNCTION(x.y, y)); \
> > +  } \
> > +\
> > +  DECLSPEC RET_TYPE##3 FUNCTION(ARG1_TYPE##3 x, ARG2_TYPE y) { \
> > +    return (RET_TYPE##3)(FUNCTION(x.x, y), FUNCTION(x.y, y), \
> > +                         FUNCTION(x.z, y)); \
> > +  } \
> > +\
> > +  DECLSPEC RET_TYPE##4 FUNCTION(ARG1_TYPE##4 x, ARG2_TYPE y) { \
> > +    return (RET_TYPE##4)(FUNCTION(x.lo, y), FUNCTION(x.hi, y)); \
> > +  } \
> > +\
> > +  DECLSPEC RET_TYPE##8 FUNCTION(ARG1_TYPE##8 x, ARG2_TYPE y) { \
> > +    return (RET_TYPE##8)(FUNCTION(x.lo, y), FUNCTION(x.hi, y)); \
> > +  } \
> > +\
> > +  DECLSPEC RET_TYPE##16 FUNCTION(ARG1_TYPE##16 x, ARG2_TYPE y) { \
> > +    return (RET_TYPE##16)(FUNCTION(x.lo, y), FUNCTION(x.hi, y)); \
> > +  }
> > +
> >  #define _CLC_V_S_V_VECTORIZE(DECLSPEC, RET_TYPE, FUNCTION, ARG1_TYPE,
> ARG2_TYPE) \
> >    DECLSPEC RET_TYPE##2 FUNCTION(ARG1_TYPE x, ARG2_TYPE##2 y) { \
> >      return (RET_TYPE##2)(FUNCTION(x, y.lo), FUNCTION(x, y.hi)); \
> > @@ -115,6 +137,10 @@ _CLC_DEF _CLC_OVERLOAD RET_TYPE FUNCTION(ARG1_TYPE
> x, ARG2_TYPE y) { \
> >  } \
> >  _CLC_BINARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, RET_TYPE, FUNCTION,
> ARG1_TYPE, ARG2_TYPE)
> >
> > +#define _CLC_DEFINE_BINARY_BUILTIN_WITH_SCALAR_SECOND_ARG(RET_TYPE,
> FUNCTION, BUILTIN, ARG1_TYPE, ARG2_TYPE) \
> > +_CLC_DEFINE_BINARY_BUILTIN(RET_TYPE, FUNCTION, BUILTIN, ARG1_TYPE,
> ARG2_TYPE) \
> > +_CLC_BINARY_VECTORIZE_SCALAR_SECOND_ARG(_CLC_OVERLOAD _CLC_DEF,
> RET_TYPE, FUNCTION, ARG1_TYPE, ARG2_TYPE)
> > +
> >  #define _CLC_DEFINE_UNARY_BUILTIN(RET_TYPE, FUNCTION, BUILTIN,
> ARG1_TYPE) \
> >  _CLC_DEF _CLC_OVERLOAD RET_TYPE FUNCTION(ARG1_TYPE x) { \
> >    return BUILTIN(x); \
> > diff --git a/generic/lib/math/ldexp.cl b/generic/lib/math/ldexp.cl
> > new file mode 100644
> > index 0000000..b7c5a92
> > --- /dev/null
> > +++ b/generic/lib/math/ldexp.cl
> > @@ -0,0 +1,114 @@
> > +/*
> > + * Copyright (c) 2014 Advanced Micro Devices, Inc.
> > + *
> > + * Permission is hereby granted, free of charge, to any person
> obtaining a copy
> > + * of this software and associated documentation files (the
> "Software"), to deal
> > + * in the Software without restriction, including without limitation
> the rights
> > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or
> sell
> > + * copies of the Software, and to permit persons to whom the Software is
> > + * furnished to do so, subject to the following conditions:
> > + *
> > + * The above copyright notice and this permission notice shall be
> included in
> > + * all copies or substantial portions of the Software.
> > + *
> > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
> EXPRESS OR
> > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
> MERCHANTABILITY,
> > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
> SHALL THE
> > + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
> OTHER
> > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> ARISING FROM,
> > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
> DEALINGS IN
> > + * THE SOFTWARE.
> > + */
> > +
> > +#include <clc/clc.h>
> > +#include "../clcmacro.h"
> > +#include "math.h"
> > +
> > +_CLC_DEF _CLC_OVERLOAD float ldexp(float x, int n) {
>
> I think this is where we need to integrate with my subnormal helper
> patches to add denormal flushing.  I can give this a try if you want.
>
>
Go for it.  I did notice that your denormal patch always reports false for
16/32-bit float denormal support, so this will always fall into the same
code path regardless for float ldexp.  It's just doubles which have a call
into llvm to check if the hardware supports subnormals.

Bit of a question:  If the hardware supports subnormals, do we just not
need the subnormal support code?

I noticed in quite a few of the amd builtins that subnormal support is
explicitly tested for, but in the ldexp case, the code below is straight
from the AMD built-in (doesn't have a check for if the hardware supports
subnormals or not).  I guess it's possible that the ldexp implementation
was done in such a way that it didn't matter if the hardware supports
subnormals or not, and we're leaving missing out on possible performance by
always running the code as written when we have hardware with subnormal
support.

In summary, floating point isn't my strongest area, and without wikipedia,
wolfram, and other sites to explain some of these algorithms, I'd be
hopeless :)

--Aaron

-Tom
>
>
> > +     /* supports denormal values */
> > +     const int multiplier = 24;
> > +     float val_f;
> > +     uint val_ui;
> > +     uint sign;
> > +     int exponent;
> > +     val_ui = as_uint(x);
> > +     sign = val_ui & 0x80000000;
> > +     val_ui = val_ui & 0x7fffffff;/* remove the sign bit */
> > +     int val_x = val_ui;
> > +
> > +     exponent = val_ui >> 23; /* get the exponent */
> > +     int dexp = exponent;
> > +
> > +     /* denormal support */
> > +     int fbh = 127 - (as_uint((float)(as_float(val_ui | 0x3f800000) -
> 1.0f)) >> 23);
> > +     int dexponent = 25 - fbh;
> > +     uint dval_ui = (( (val_ui << fbh) & 0x007fffff) | (dexponent <<
> 23));
> > +     int ex = dexponent + n - multiplier;
> > +     dexponent = ex;
> > +     uint val = sign | (ex << 23) | (dval_ui & 0x007fffff);
> > +     int ex1 = dexponent + multiplier;
> > +     ex1 = -ex1 +25;
> > +     dval_ui = (((dval_ui & 0x007fffff )| 0x800000) >> ex1);
> > +     dval_ui = dexponent > 0 ? val :dval_ui;
> > +     dval_ui = dexponent > 254 ? 0x7f800000 :dval_ui;  /*overflow*/
> > +     dval_ui = dexponent < -multiplier ? 0 : dval_ui;  /*underflow*/
> > +     dval_ui = dval_ui | sign;
> > +     val_f = as_float(dval_ui);
> > +
> > +     exponent += n;
> > +
> > +     val = sign | (exponent << 23) | (val_ui & 0x007fffff);
> > +     ex1 = exponent + multiplier;
> > +     ex1 = -ex1 +25;
> > +     val_ui = (((val_ui & 0x007fffff )| 0x800000) >> ex1);
> > +     val_ui = exponent > 0 ? val :val_ui;
> > +     val_ui = exponent > 254 ? 0x7f800000 :val_ui;  /*overflow*/
> > +     val_ui = exponent < -multiplier ? 0 : val_ui;  /*underflow*/
> > +     val_ui = val_ui | sign;
> > +
> > +     val_ui = dexp == 0? dval_ui : val_ui;
> > +     val_f = as_float(val_ui);
> > +
> > +     val_f = isnan(x) | isinf(x) | val_x == 0 ? x : val_f;
> > +     return val_f;
> > +}
> > +_CLC_BINARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, float, ldexp, float, int)
> > +_CLC_BINARY_VECTORIZE_SCALAR_SECOND_ARG(_CLC_OVERLOAD _CLC_DEF, float,
> ldexp, float, int)
> > +
> > +#ifdef cl_khr_fp64
> > +
> > +#pragma OPENCL EXTENSION cl_khr_fp64 : enable
> > +
> > +_CLC_DEF _CLC_OVERLOAD double ldexp(double x, int n) {
> > +     long l = as_ulong(x);
> > +     int e = (l >> 52) & 0x7ff;
> > +     long s = l & 0x8000000000000000;
> > +
> > +     ulong ux = as_ulong(x * 0x1.0p+53);
> > +     int de = ((int)(ux >> 52) & 0x7ff) - 53;
> > +     int c = e == 0;
> > +     e = c ? de: e;
> > +
> > +     ux = c ? ux : l;
> > +
> > +     int v = e + n;
> > +     v = clamp(v, -0x7ff, 0x7ff);
> > +
> > +     ux &= ~EXPBITS_DP64;
> > +
> > +     double mr = as_double(ux | ((ulong)(v+53) << 52));
> > +     mr = mr * 0x1.0p-53;
> > +
> > +     mr = v > 0  ? as_double(ux | ((ulong)v << 52)) : mr;
> > +
> > +     mr = v == 0x7ff ? as_double(s | PINFBITPATT_DP64)  : mr;
> > +     mr = v < -53 ? as_double(s) : mr;
> > +
> > +     mr  = ((n == 0) | isinf(x) | (x == 0) ) ? x : mr;
> > +     return mr;
> > +}
> > +
> > +_CLC_BINARY_VECTORIZE(_CLC_OVERLOAD _CLC_DEF, double, ldexp, double,
> int)
> > +_CLC_BINARY_VECTORIZE_SCALAR_SECOND_ARG(_CLC_OVERLOAD _CLC_DEF, double,
> ldexp, double, int)
> > +
> > +#endif
> > --
> > 2.2.0
> >
> >
> > _______________________________________________
> > Libclc-dev mailing list
> > Libclc-dev at pcc.me.uk
> > http://www.pcc.me.uk/cgi-bin/mailman/listinfo/libclc-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/libclc-dev/attachments/20150313/8b25fed0/attachment.html>


More information about the Libclc-dev mailing list