test_performance.cl: use $RUN_KERNEL, not lli directly

// Test source code is from http://musicdsp.org/archive.php?classid=0#1 and
// modified to pass clang C compiler and changed TF to be local var in main
// to support ClampPointers pass.

// FormantsAM.cpp

// Thierry Rochebois' "Formantic Synthesis by Double Amplitude Modulation"

// Based on a tutorial by Thierry Rochebois.
// Comments by Paul Sernine.

// The spectral content of the signal is obtained by adding amplitude modulated formantic
// waveforms. The amplitude modulations spectraly shift the formantic waveforms.
// Continuous spectral shift, without losing the harmonic structure, is obtained
// by using crossfaded double carriers (multiple of the base frequency).
// To avoid  unwanted interference artifacts, phase relationships must be of the
// "cosine type".

// The output is a 44100Hz 16bit stereo PCM file.

// NOTE: for now looks like -O3 cripples safe exception load/store analysis
// TODO: get times from unclamped versions and compare to clamped ones and expect perf hit to be max 30%

// RUN: clang -target nvptx -S -c $TEST_SRC -O0 -emit-llvm -S -o $OUT_FILE.ll &&
// RUN: echo "Running and verifying 'Formantic Synthesis by Double Amplitude Modulation' case" &&
// RUN: opt -S -O3 $OUT_FILE.ll -o $OUT_FILE.O3.ll &&
// RUN: opt -debug -S -load $CLAMP_PLUGIN -clamp-pointers -allow-unsafe-exceptions $OUT_FILE.ll -o $OUT_FILE.clamped.ll &&
// RUN: opt -debug -S -load $CLAMP_PLUGIN -clamp-pointers -allow-unsafe-exceptions $OUT_FILE.O3.ll -o $OUT_FILE.O3.clamped.ll &&
// RUN: opt -S -O3 $OUT_FILE.clamped.ll -o $OUT_FILE.clamped.O3.ll &&
// RUN: echo "Running original.O0:" &&
// RUN: (BENCHMARK=1 $RUN_KERNEL $OUT_FILE.ll test_kernel 8 "(int,{0}):(int,1)") &&
// RUN: echo "Running original.O3:" &&
// RUN: (BENCHMARK=1 $RUN_KERNEL $OUT_FILE.O3.ll test_kernel 8 "(int,{0}):(int,1)") &&
// RUN: echo "Running clamped.O0:" &&
// RUN: (BENCHMARK=1 $RUN_KERNEL $OUT_FILE.clamped.ll test_kernel 8 "(int,{0}):(int,1)") &&
// RUN: echo "Running O3.clamped:" &&
// RUN: (BENCHMARK=1 $RUN_KERNEL $OUT_FILE.O3.clamped.ll test_kernel 8 "(int,{0}):(int,1)") &&
// RUN: echo "Running clamped.O3:" &&
// RUN: (BENCHMARK=1 $RUN_KERNEL $OUT_FILE.clamped.O3.ll)

typedef int int32_t;
typedef short int16_t;

float expf(float f);
float sinf(float f);
float cosf(float f);
float floorf(float f);
float powf(float a, float b);
float fmodf(float x, float y);

//Approximates cos(pi*x) for x in [-1,1].
float fast_cos(const float x)
{
  float x2 = x*x;
  return 1+x2*(-4+2*x2);
}

// Length of the table
#define L_TABLE (256+1) //The last entry of the table equals the first (to avoid a modulo)
// Maximal formant width
#define I_MAX 64

//Formantic function of width I (used to fill the table of formants)
float fonc_formant(float p,const float I)
{
  float a=0.5f;
  int32_t hmax=(int)(10*I)>L_TABLE/2?L_TABLE/2:(int32_t)(10*I);
  float phi=0.0f;
  for(int32_t h=1;h<hmax;h++)
    {
      phi+=3.14159265359f*p;
      float hann=0.5f+0.5f*fast_cos(h*(1.0f/hmax));
      float gaussienne=0.85f*expf(-h*h/(I*I));
      float jupe=0.15f;
      float harmonique=cosf(phi);
      a+=hann*(gaussienne+jupe)*harmonique;
    }
  return a;
}

//Initialisation of the table TF with the fonction fonc_formant.
void init_formant(float TF[])
{ float coef=2.0f/(L_TABLE-1);
  for(int32_t I=0;I<I_MAX;I++)
    for(int32_t P=0;P<L_TABLE;P++)
      TF[P+I*L_TABLE]=fonc_formant(-1+P*coef,(float)(I));
}

//This function emulates the function fonc_formant
// thanks to the table TF. A bilinear interpolation is
// performed
float formant(float p,float i, float TF[])
{
  i=i<0?0:i>I_MAX-2?I_MAX-2:i;    // width limitation
  float P=(L_TABLE-1)*(p+1)*0.5f; // phase normalisation
  int32_t P0=(int32_t)P;     float fP=P-P0;  // Integer and fractional
  int32_t I0=(int32_t)i;     float fI=i-I0;  // parts of the phase (p) and width (i).
  int32_t i00=P0+L_TABLE*I0;     int32_t i10=i00+L_TABLE;
  //bilinear interpolation.
  return (1-fI)*(TF[i00] + fP*(TF[i00+1]-TF[i00]))
    +    fI*(TF[i10] + fP*(TF[i10+1]-TF[i10]));
}

// Double carrier.
// h : position (float harmonic number)
// p : phase
float porteuse(const float h,const float p)
{
  float h0=floorf(h);  //integer and
  float hf=h-h0;      //decimal part of harmonic number.
  // modulos pour ramener p*h0 et p*(h0+1) dans [-1,1]
  float phi0=fmodf(p* h0   +1+1000,2.0f)-1.0f;
  float phi1=fmodf(p*(h0+1)+1+1000,2.0f)-1.0f;
  // two carriers.
  float Porteuse0=fast_cos(phi0);  float Porteuse1=fast_cos(phi1);
  // crossfade between the two carriers.
  return Porteuse0+hf*(Porteuse1-Porteuse0);
}

__kernel void test_kernel(__global int* out_val)
{
  //Formant table for various french vowels (you can add your own)
  float F1[]={  730,  200,  400,  250,  190,  350,  550,  550,  450};
  float A1[]={ 1.0f, 0.5f, 1.0f, 1.0f, 0.7f, 1.0f, 1.0f, 0.3f, 1.0f};
  float F2[]={ 1090, 2100,  900, 1700,  800, 1900, 1600,  850, 1100};
  float A2[]={ 2.0f, 0.5f, 0.7f, 0.7f,0.35f, 0.3f, 0.5f, 1.0f, 0.7f};
  float F3[]={ 2440, 3100, 2300, 2100, 2000, 2500, 2250, 1900, 1500};
  float A3[]={ 0.3f,0.15f, 0.2f, 0.4f, 0.1f, 0.3f, 0.7f, 0.2f, 0.2f};
  float F4[]={ 3400, 4700, 3000, 3300, 3400, 3700, 3200, 3000, 3000};
  float A4[]={ 0.2f, 0.1f, 0.2f, 0.3f, 0.1f, 0.1f, 0.3f, 0.2f, 0.3f};

  float f0,dp0,p0=0.0f;
  int32_t F=7; //number of the current formant preset
  float f1,f2,f3,f4,a1,a2,a3,a4;
  f1=f2=f3=f4=100.0f;a1=a2=a3=a4=0.0f;

  //Table of formants
  float TF[L_TABLE*I_MAX];

  init_formant(TF);

  for(int ns=0;ns<200*44100;ns++)
    {
      if(0==(ns%11025)){F++;F%=8;} //formant change
      f0=12*powf(2.0f,4-4*ns/(10*44100.0f)); //sweep
      f0*=(1.0f+0.01f*sinf(ns*0.0015f));        //vibrato
      dp0=f0*(1/22050.0f);
      float un_f0=1.0f/f0;
      p0+=dp0;  //phase increment
      p0-=2*(p0>1);
      { //smoothing of the commands.
        float r=0.001f;
        f1+=r*(F1[F]-f1);f2+=r*(F2[F]-f2);f3+=r*(F3[F]-f3);f4+=r*(F4[F]-f4);
        a1+=r*(A1[F]-a1);a2+=r*(A2[F]-a2);a3+=r*(A3[F]-a3);a4+=r*(A4[F]-a4);
      }

      //The f0/fn coefficients stand for a -3dB/oct spectral enveloppe
      float out=
        a1*(f0/f1)*formant(p0,100*un_f0,TF)*porteuse(f1*un_f0,p0)
        +0.7f*a2*(f0/f2)*formant(p0,120*un_f0,TF)*porteuse(f2*un_f0,p0)
        +     a3*(f0/f3)*formant(p0,150*un_f0,TF)*porteuse(f3*un_f0,p0)
        +     a4*(f0/f4)*formant(p0,300*un_f0,TF)*porteuse(f4*un_f0,p0);

      // write to volatile variable to test... (use puts to verify correctness)
      out_val[0] = (int16_t)(15000.0f*out);
    }
}

// Test source code is from http://musicdsp.org/archive.php?classid=0#1 and
// modified to pass clang C compiler and changed TF to be local var in main
// to support ClampPointers pass.

// FormantsAM.cpp

// Thierry Rochebois' "Formantic Synthesis by Double Amplitude Modulation"

// Based on a tutorial by Thierry Rochebois.
// Comments by Paul Sernine.

// The spectral content of the signal is obtained by adding amplitude modulated formantic
// waveforms. The amplitude modulations spectraly shift the formantic waveforms.
// Continuous spectral shift, without losing the harmonic structure, is obtained
// by using crossfaded double carriers (multiple of the base frequency).
// To avoid  unwanted interference artifacts, phase relationships must be of the
// "cosine type".

// The output is a 44100Hz 16bit stereo PCM file.

// NOTE: for now looks like -O3 cripples safe exception load/store analysis
// TODO: get times from unclamped versions and compare to clamped ones and expect perf hit to be max 30%

// RUN: clang -target nvptx -S -c $TEST_SRC -O0 -emit-llvm -S -o $OUT_FILE.ll &&
// RUN: echo "Running and verifying 'Formantic Synthesis by Double Amplitude Modulation' case" &&
// RUN: opt -S -O3 $OUT_FILE.ll -o $OUT_FILE.O3.ll &&
// RUN: opt -debug -S -load $CLAMP_PLUGIN -clamp-pointers -allow-unsafe-exceptions $OUT_FILE.ll -o $OUT_FILE.clamped.ll &&
// RUN: opt -debug -S -load $CLAMP_PLUGIN -clamp-pointers -allow-unsafe-exceptions $OUT_FILE.O3.ll -o $OUT_FILE.O3.clamped.ll &&
// RUN: opt -S -O3 $OUT_FILE.clamped.ll -o $OUT_FILE.clamped.O3.ll &&
// RUN: echo "Running original.O0:" &&
// RUN: time lli $OUT_FILE.ll &&
// RUN: echo "Running original.O3:" &&
// RUN: time lli $OUT_FILE.O3.ll &&
// RUN: echo "Running clamped.O0:" &&
// RUN: time lli $OUT_FILE.clamped.ll &&
// RUN: echo "Running O3.clamped:" &&
// RUN: time lli $OUT_FILE.O3.clamped.ll &&
// RUN: echo "Running clamped.O3:" &&
// RUN: time lli $OUT_FILE.clamped.O3.ll

typedef int int32_t;
typedef short int16_t;

float expf(float f);
float sinf(float f);
float cosf(float f);
float floorf(float f);
float powf(float a, float b);
float fmodf(float x, float y);

//Approximates cos(pi*x) for x in [-1,1].
float fast_cos(const float x)
{
  float x2 = x*x;
  return 1+x2*(-4+2*x2);
}

// Length of the table
#define L_TABLE (256+1) //The last entry of the table equals the first (to avoid a modulo)
// Maximal formant width
#define I_MAX 64

//Formantic function of width I (used to fill the table of formants)
float fonc_formant(float p,const float I)
{
  float a=0.5f;
  int32_t hmax=(int)(10*I)>L_TABLE/2?L_TABLE/2:(int32_t)(10*I);
  float phi=0.0f;
  for(int32_t h=1;h<hmax;h++)
    {
      phi+=3.14159265359f*p;
      float hann=0.5f+0.5f*fast_cos(h*(1.0f/hmax));
      float gaussienne=0.85f*expf(-h*h/(I*I));
      float jupe=0.15f;
      float harmonique=cosf(phi);
      a+=hann*(gaussienne+jupe)*harmonique;
    }
  return a;
}

//Initialisation of the table TF with the fonction fonc_formant.
void init_formant(float TF[])
{ float coef=2.0f/(L_TABLE-1);
  for(int32_t I=0;I<I_MAX;I++)
    for(int32_t P=0;P<L_TABLE;P++)
      TF[P+I*L_TABLE]=fonc_formant(-1+P*coef,(float)(I));
}

//This function emulates the function fonc_formant
// thanks to the table TF. A bilinear interpolation is
// performed
float formant(float p,float i, float TF[])
{
  i=i<0?0:i>I_MAX-2?I_MAX-2:i;    // width limitation
  float P=(L_TABLE-1)*(p+1)*0.5f; // phase normalisation
  int32_t P0=(int32_t)P;     float fP=P-P0;  // Integer and fractional
  int32_t I0=(int32_t)i;     float fI=i-I0;  // parts of the phase (p) and width (i).
  int32_t i00=P0+L_TABLE*I0;     int32_t i10=i00+L_TABLE;
  //bilinear interpolation.
  return (1-fI)*(TF[i00] + fP*(TF[i00+1]-TF[i00]))
    +    fI*(TF[i10] + fP*(TF[i10+1]-TF[i10]));
}

// Double carrier.
// h : position (float harmonic number)
// p : phase
float porteuse(const float h,const float p)
{
  float h0=floorf(h);  //integer and
  float hf=h-h0;      //decimal part of harmonic number.
  // modulos pour ramener p*h0 et p*(h0+1) dans [-1,1]
  float phi0=fmodf(p* h0   +1+1000,2.0f)-1.0f;
  float phi1=fmodf(p*(h0+1)+1+1000,2.0f)-1.0f;
  // two carriers.
  float Porteuse0=fast_cos(phi0);  float Porteuse1=fast_cos(phi1);
  // crossfade between the two carriers.
  return Porteuse0+hf*(Porteuse1-Porteuse0);
}

__kernel void test_kernel(__global int16_t* out_val)
{
  //Formant table for various french vowels (you can add your own)
  float F1[]={  730,  200,  400,  250,  190,  350,  550,  550,  450};
  float A1[]={ 1.0f, 0.5f, 1.0f, 1.0f, 0.7f, 1.0f, 1.0f, 0.3f, 1.0f};
  float F2[]={ 1090, 2100,  900, 1700,  800, 1900, 1600,  850, 1100};
  float A2[]={ 2.0f, 0.5f, 0.7f, 0.7f,0.35f, 0.3f, 0.5f, 1.0f, 0.7f};
  float F3[]={ 2440, 3100, 2300, 2100, 2000, 2500, 2250, 1900, 1500};
  float A3[]={ 0.3f,0.15f, 0.2f, 0.4f, 0.1f, 0.3f, 0.7f, 0.2f, 0.2f};
  float F4[]={ 3400, 4700, 3000, 3300, 3400, 3700, 3200, 3000, 3000};
  float A4[]={ 0.2f, 0.1f, 0.2f, 0.3f, 0.1f, 0.1f, 0.3f, 0.2f, 0.3f};

  float f0,dp0,p0=0.0f;
  int32_t F=7; //number of the current formant preset
  float f1,f2,f3,f4,a1,a2,a3,a4;
  f1=f2=f3=f4=100.0f;a1=a2=a3=a4=0.0f;

  //Table of formants
  float TF[L_TABLE*I_MAX];

  init_formant(TF);

  for(int ns=0;ns<200*44100;ns++)
    {
      if(0==(ns%11025)){F++;F%=8;} //formant change
      f0=12*powf(2.0f,4-4*ns/(10*44100.0f)); //sweep
      f0*=(1.0f+0.01f*sinf(ns*0.0015f));        //vibrato
      dp0=f0*(1/22050.0f);
      float un_f0=1.0f/f0;
      p0+=dp0;  //phase increment
      p0-=2*(p0>1);
      { //smoothing of the commands.
        float r=0.001f;
        f1+=r*(F1[F]-f1);f2+=r*(F2[F]-f2);f3+=r*(F3[F]-f3);f4+=r*(F4[F]-f4);
        a1+=r*(A1[F]-a1);a2+=r*(A2[F]-a2);a3+=r*(A3[F]-a3);a4+=r*(A4[F]-a4);
      }

      //The f0/fn coefficients stand for a -3dB/oct spectral enveloppe
      float out=
        a1*(f0/f1)*formant(p0,100*un_f0,TF)*porteuse(f1*un_f0,p0)
        +0.7f*a2*(f0/f2)*formant(p0,120*un_f0,TF)*porteuse(f2*un_f0,p0)
        +     a3*(f0/f3)*formant(p0,150*un_f0,TF)*porteuse(f3*un_f0,p0)
        +     a4*(f0/f4)*formant(p0,300*un_f0,TF)*porteuse(f4*un_f0,p0);

      // write to volatile variable to test... (use puts to verify correctness)
      out_val[0] = (int16_t)(15000.0f*out);
    }
}


pow: Use denormal path only

pow: Use denormal path only

It's OK to either flush to 0 or return denormal result if the device
does not support denormals. See sec 7.2 and 7.5.3 of OCL specs
Fixes CTS on carrizo and turks.
Signed-off-by: Jan Vesely <jan.vesely@rutgers.edu>
Reviewer: Aaron Watry <awatry@gmail.com>

git-svn-id: e7f1ab7c2a259259587475a3e7520e757882f167@330205 91177308-0d34-0410-b5e6-96231b3b80d8

/*
 * 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 "config.h"
#include "math.h"
#include "tables.h"
#include "../clcmacro.h"

/*
 compute pow using log and exp
 x^y = exp(y * log(x))

 we take care not to lose precision in the intermediate steps

 When computing log, calculate it in splits,

 r = f * (p_invead + p_inv_tail)
 r = rh + rt

 calculate log polynomial using r, in end addition, do
 poly = poly + ((rh-r) + rt)

 lth = -r
 ltt = ((xexp * log2_t) - poly) + logT
 lt = lth + ltt

 lh = (xexp * log2_h) + logH
 l = lh + lt

 Calculate final log answer as gh and gt,
 gh = l & higher-half bits
 gt = (((ltt - (lt - lth)) + ((lh - l) + lt)) + (l - gh))

 yh = y & higher-half bits
 yt = y - yh

 Before entering computation of exp,
 vs = ((yt*gt + yt*gh) + yh*gt)
 v = vs + yh*gh
 vt = ((yh*gh - v) + vs)

 In calculation of exp, add vt to r that is used for poly
 At the end of exp, do
 ((((expT * poly) + expT) + expH*poly) + expH)
*/

_CLC_DEF _CLC_OVERLOAD float __clc_pow(float x, float y)
{

    int ix = as_int(x);
    int ax = ix & EXSIGNBIT_SP32;
    int xpos = ix == ax;

    int iy = as_int(y);
    int ay = iy & EXSIGNBIT_SP32;
    int ypos = iy == ay;

    /* Extra precise log calculation
     *  First handle case that x is close to 1
     */
    float r = 1.0f - as_float(ax);
    int near1 = fabs(r) < 0x1.0p-4f;
    float r2 = r*r;

    /* Coefficients are just 1/3, 1/4, 1/5 and 1/6 */
    float poly = mad(r,
                     mad(r,
                         mad(r,
                             mad(r, 0x1.24924ap-3f, 0x1.555556p-3f),
                             0x1.99999ap-3f),
                         0x1.000000p-2f),
                     0x1.555556p-2f);

    poly *= r2*r;

    float lth_near1 = -r2 * 0.5f;
    float ltt_near1 = -poly;
    float lt_near1 = lth_near1 + ltt_near1;
    float lh_near1 = -r;
    float l_near1 = lh_near1 + lt_near1;

    /* Computations for x not near 1 */
    int m = (int)(ax >> EXPSHIFTBITS_SP32) - EXPBIAS_SP32;
    float mf = (float)m;
    int ixs = as_int(as_float(ax | 0x3f800000) - 1.0f);
    float mfs = (float)((ixs >> EXPSHIFTBITS_SP32) - 253);
    int c = m == -127;
    int ixn = c ? ixs : ax;
    float mfn = c ? mfs : mf;

    int indx = (ixn & 0x007f0000) + ((ixn & 0x00008000) << 1);

    /* F - Y */
    float f = as_float(0x3f000000 | indx) - as_float(0x3f000000 | (ixn & MANTBITS_SP32));

    indx = indx >> 16;
    float2 tv = USE_TABLE(log_inv_tbl_ep, indx);
    float rh = f * tv.s0;
    float rt = f * tv.s1;
    r = rh + rt;

    poly = mad(r, mad(r, 0x1.0p-2f, 0x1.555556p-2f), 0x1.0p-1f) * (r*r);
    poly += (rh - r) + rt;

    const float LOG2_HEAD = 0x1.62e000p-1f;  /* 0.693115234 */
    const float LOG2_TAIL = 0x1.0bfbe8p-15f; /* 0.0000319461833 */
    tv = USE_TABLE(loge_tbl, indx);
    float lth = -r;
    float ltt = mad(mfn, LOG2_TAIL, -poly) + tv.s1;
    float lt = lth + ltt;
    float lh = mad(mfn, LOG2_HEAD, tv.s0);
    float l = lh + lt;

    /* Select near 1 or not */
    lth = near1 ? lth_near1 : lth;
    ltt = near1 ? ltt_near1 : ltt;
    lt = near1 ? lt_near1 : lt;
    lh = near1 ? lh_near1 : lh;
    l = near1 ? l_near1 : l;

    float gh = as_float(as_int(l) & 0xfffff000);
    float gt = ((ltt - (lt - lth)) + ((lh - l) + lt)) + (l - gh);

    float yh = as_float(iy & 0xfffff000);

    float yt = y - yh;

    float ylogx_s = mad(gt, yh, mad(gh, yt, yt*gt));
    float ylogx = mad(yh, gh, ylogx_s);
    float ylogx_t = mad(yh, gh, -ylogx) + ylogx_s;

    /* Extra precise exp of ylogx */
    const float R_64_BY_LOG2 = 0x1.715476p+6f; /* 64/log2 : 92.332482616893657 */
    int n = convert_int(ylogx * R_64_BY_LOG2);
    float nf = (float) n;

    int j = n & 0x3f;
    m = n >> 6;
    int m2 = m << EXPSHIFTBITS_SP32;

    const float R_LOG2_BY_64_LD = 0x1.620000p-7f;  /* log2/64 lead: 0.0108032227 */
    const float R_LOG2_BY_64_TL = 0x1.c85fdep-16f; /* log2/64 tail: 0.0000272020388 */
    r = mad(nf, -R_LOG2_BY_64_TL, mad(nf, -R_LOG2_BY_64_LD, ylogx)) + ylogx_t;

    /* Truncated Taylor series for e^r */
    poly = mad(mad(mad(r, 0x1.555556p-5f, 0x1.555556p-3f), r, 0x1.000000p-1f), r*r, r);

    tv = USE_TABLE(exp_tbl_ep, j);

    float expylogx = mad(tv.s0, poly, mad(tv.s1, poly, tv.s1)) + tv.s0;
    float sexpylogx = expylogx * as_float(0x1 << (m + 149));
    float texpylogx = as_float(as_int(expylogx) + m2);
    expylogx = m < -125 ? sexpylogx : texpylogx;

    /* Result is +-Inf if (ylogx + ylogx_t) > 128*log2 */
    expylogx = (ylogx > 0x1.62e430p+6f) | (ylogx == 0x1.62e430p+6f & ylogx_t > -0x1.05c610p-22f) ? as_float(PINFBITPATT_SP32) : expylogx;

    /* Result is 0 if ylogx < -149*log2 */
    expylogx = ylogx <  -0x1.9d1da0p+6f ? 0.0f : expylogx;

    /* Classify y:
     *   inty = 0 means not an integer.
     *   inty = 1 means odd integer.
     *   inty = 2 means even integer.
     */

    int yexp = (int)(ay >> EXPSHIFTBITS_SP32) - EXPBIAS_SP32 + 1;
    int mask = (1 << (24 - yexp)) - 1;
    int yodd = ((iy >> (24 - yexp)) & 0x1) != 0;
    int inty = yodd ? 1 : 2;
    inty = (iy & mask) != 0 ? 0 : inty;
    inty = yexp < 1 ? 0 : inty;
    inty = yexp > 24 ? 2 : inty;

    float signval = as_float((as_uint(expylogx) ^ SIGNBIT_SP32));
    expylogx = ((inty == 1) & !xpos) ? signval : expylogx;
    int ret = as_int(expylogx);

    /* Corner case handling */
    ret = (!xpos & (inty == 0)) ? QNANBITPATT_SP32 : ret;
    ret = ax < 0x3f800000 & iy == NINFBITPATT_SP32 ? PINFBITPATT_SP32 : ret;
    ret = ax > 0x3f800000 & iy == NINFBITPATT_SP32 ? 0 : ret;
    ret = ax < 0x3f800000 & iy == PINFBITPATT_SP32 ? 0 : ret;
    ret = ax > 0x3f800000 & iy == PINFBITPATT_SP32 ? PINFBITPATT_SP32 : ret;
    int xinf = xpos ? PINFBITPATT_SP32 : NINFBITPATT_SP32;
    ret = ((ax == 0) & !ypos & (inty == 1)) ? xinf : ret;
    ret = ((ax == 0) & !ypos & (inty != 1)) ? PINFBITPATT_SP32 : ret;
    int xzero = xpos ? 0 : 0x80000000;
    ret = ((ax == 0) & ypos & (inty == 1)) ? xzero : ret;
    ret = ((ax == 0) & ypos & (inty != 1)) ? 0 : ret;
    ret = ((ax == 0) & (iy == NINFBITPATT_SP32)) ? PINFBITPATT_SP32 : ret;
    ret = ((ix == 0xbf800000) & (ay == PINFBITPATT_SP32)) ? 0x3f800000 : ret;
    ret = ((ix == NINFBITPATT_SP32) & !ypos & (inty == 1)) ? 0x80000000 : ret;
    ret = ((ix == NINFBITPATT_SP32) & !ypos & (inty != 1)) ? 0 : ret;
    ret = ((ix == NINFBITPATT_SP32) & ypos & (inty == 1)) ? NINFBITPATT_SP32 : ret;
    ret = ((ix == NINFBITPATT_SP32) & ypos & (inty != 1)) ? PINFBITPATT_SP32 : ret;
    ret = ((ix == PINFBITPATT_SP32) & !ypos) ? 0 : ret;
    ret = ((ix == PINFBITPATT_SP32) & ypos) ? PINFBITPATT_SP32 : ret;
    ret = (ax > PINFBITPATT_SP32) ? ix : ret;
    ret = (ay > PINFBITPATT_SP32) ? iy : ret;
    ret = ay == 0 ? 0x3f800000 : ret;
    ret = ix == 0x3f800000 ? 0x3f800000 : ret;

    return as_float(ret);
}
_CLC_BINARY_VECTORIZE(_CLC_DEF _CLC_OVERLOAD, float, __clc_pow, float, float)

#ifdef cl_khr_fp64
_CLC_DEF _CLC_OVERLOAD double __clc_pow(double x, double y)
{
    const double real_log2_tail = 5.76999904754328540596e-08;
    const double real_log2_lead = 6.93147122859954833984e-01;

    long ux = as_long(x);
    long ax = ux & (~SIGNBIT_DP64);
    int xpos = ax == ux;

    long uy = as_long(y);
    long ay = uy & (~SIGNBIT_DP64);
    int ypos = ay == uy;

    // Extended precision log
    double v, vt;
    {
        int exp = (int)(ax >> 52) - 1023;
        int mask_exp_1023 = exp == -1023;
        double xexp = (double) exp;
        long mantissa = ax & 0x000FFFFFFFFFFFFFL;

        long temp_ux = as_long(as_double(0x3ff0000000000000L | mantissa) - 1.0);
        exp = ((temp_ux & 0x7FF0000000000000L) >> 52) - 2045;
        double xexp1 = (double) exp;
        long mantissa1 = temp_ux & 0x000FFFFFFFFFFFFFL;

        xexp = mask_exp_1023 ? xexp1 : xexp;
        mantissa = mask_exp_1023 ? mantissa1 : mantissa;

        long rax = (mantissa & 0x000ff00000000000) + ((mantissa & 0x0000080000000000) << 1);
        int index = rax >> 44;

        double F = as_double(rax | 0x3FE0000000000000L);
        double Y = as_double(mantissa | 0x3FE0000000000000L);
        double f = F - Y;
        double2 tv = USE_TABLE(log_f_inv_tbl, index);
        double log_h = tv.s0;
        double log_t = tv.s1;
        double f_inv = (log_h + log_t) * f;
        double r1 = as_double(as_long(f_inv) & 0xfffffffff8000000L);
        double r2 = fma(-F, r1, f) * (log_h + log_t);
        double r = r1 + r2;

        double poly = fma(r,
                          fma(r,
                              fma(r,
                                  fma(r, 1.0/7.0, 1.0/6.0),
                                  1.0/5.0),
                              1.0/4.0),
                          1.0/3.0);
        poly = poly * r * r * r;

        double hr1r1 = 0.5*r1*r1;
        double poly0h = r1 + hr1r1;
        double poly0t = r1 - poly0h + hr1r1;
        poly = fma(r1, r2, fma(0.5*r2, r2, poly)) + r2 + poly0t;

        tv = USE_TABLE(powlog_tbl, index);
        log_h = tv.s0;
        log_t = tv.s1;

        double resT_t = fma(xexp, real_log2_tail, + log_t) - poly;
        double resT = resT_t - poly0h;
        double resH = fma(xexp, real_log2_lead, log_h);
        double resT_h = poly0h;

        double H = resT + resH;
        double H_h = as_double(as_long(H) & 0xfffffffff8000000L);
        double T = (resH - H + resT) + (resT_t - (resT + resT_h)) + (H - H_h);
        H = H_h;

        double y_head = as_double(uy & 0xfffffffff8000000L);
        double y_tail = y - y_head;

        double temp = fma(y_tail, H, fma(y_head, T, y_tail*T));
        v = fma(y_head, H, temp);
        vt = fma(y_head, H, -v) + temp;
    }

    // Now calculate exp of (v,vt)

    double expv;
    {
        const double max_exp_arg = 709.782712893384;
        const double min_exp_arg = -745.1332191019411;
        const double sixtyfour_by_lnof2 = 92.33248261689366;
        const double lnof2_by_64_head = 0.010830424260348081;
        const double lnof2_by_64_tail = -4.359010638708991e-10;

        double temp = v * sixtyfour_by_lnof2;
        int n = (int)temp;
        double dn = (double)n;
        int j = n & 0x0000003f;
        int m = n >> 6;

        double2 tv = USE_TABLE(two_to_jby64_ep_tbl, j);
        double f1 = tv.s0;
        double f2 = tv.s1;
        double f = f1 + f2;

        double r1 = fma(dn, -lnof2_by_64_head, v);
        double r2 = dn * lnof2_by_64_tail;
        double r = (r1 + r2) + vt;

        double q = fma(r,
                       fma(r,
                           fma(r,
                               fma(r, 1.38889490863777199667e-03, 8.33336798434219616221e-03),
                               4.16666666662260795726e-02),
                           1.66666666665260878863e-01),
                       5.00000000000000008883e-01);
        q = fma(r*r, q, r);

        expv = fma(f, q, f2) + f1;
	      expv = ldexp(expv, m);

        expv = v > max_exp_arg ? as_double(0x7FF0000000000000L) : expv;
        expv = v < min_exp_arg ? 0.0 : expv;
    }

    // See whether y is an integer.
    // inty = 0 means not an integer.
    // inty = 1 means odd integer.
    // inty = 2 means even integer.

    int inty;
    {
        int yexp = (int)(ay >> EXPSHIFTBITS_DP64) - EXPBIAS_DP64 + 1;
        inty = yexp < 1 ? 0 : 2;
        inty = yexp > 53 ? 2 : inty;
        long mask = (1L << (53 - yexp)) - 1L;
        int inty1 = (((ay & ~mask) >> (53 - yexp)) & 1L) == 1L ? 1 : 2;
        inty1 = (ay & mask) != 0 ? 0 : inty1;
        inty = !(yexp < 1) & !(yexp > 53) ? inty1 : inty;
    }

    expv *= (inty == 1) & !xpos ? -1.0 : 1.0;

    long ret = as_long(expv);

    // Now all the edge cases
    ret = !xpos & (inty == 0) ? QNANBITPATT_DP64 : ret;
    ret = ax < 0x3ff0000000000000L & uy == NINFBITPATT_DP64 ? PINFBITPATT_DP64 : ret;
    ret = ax > 0x3ff0000000000000L & uy == NINFBITPATT_DP64 ? 0L : ret;
    ret = ax < 0x3ff0000000000000L & uy == PINFBITPATT_DP64 ? 0L : ret;
    ret = ax > 0x3ff0000000000000L & uy == PINFBITPATT_DP64 ? PINFBITPATT_DP64 : ret;
    long xinf = xpos ? PINFBITPATT_DP64 : NINFBITPATT_DP64;
    ret = ((ax == 0L) & !ypos & (inty == 1)) ? xinf : ret;
    ret = ((ax == 0L) & !ypos & (inty != 1)) ? PINFBITPATT_DP64 : ret;
    long xzero = xpos ? 0L : 0x8000000000000000L;
    ret = ((ax == 0L) & ypos & (inty == 1)) ? xzero : ret;
    ret = ((ax == 0L) & ypos & (inty != 1)) ? 0L : ret;
    ret = ((ax == 0L) & (uy == NINFBITPATT_DP64)) ? PINFBITPATT_DP64 : ret;
    ret = ((ux == 0xbff0000000000000L) & (ay == PINFBITPATT_DP64)) ? 0x3ff0000000000000L : ret;
    ret = ((ux == NINFBITPATT_DP64) & !ypos & (inty == 1)) ? 0x8000000000000000L : ret;
    ret = ((ux == NINFBITPATT_DP64) & !ypos & (inty != 1)) ? 0L : ret;
    ret = ((ux == NINFBITPATT_DP64) & ypos & (inty == 1)) ? NINFBITPATT_DP64 : ret;
    ret = ((ux == NINFBITPATT_DP64) & ypos & (inty != 1)) ? PINFBITPATT_DP64 : ret;
    ret = (ux == PINFBITPATT_DP64) & !ypos ? 0L : ret;
    ret = (ux == PINFBITPATT_DP64) & ypos ? PINFBITPATT_DP64 : ret;
    ret = ax > PINFBITPATT_DP64 ? ux : ret;
    ret = ay > PINFBITPATT_DP64 ? uy : ret;
    ret = ay == 0L ? 0x3ff0000000000000L : ret;
    ret = ux == 0x3ff0000000000000L ? 0x3ff0000000000000L : ret;

    return as_double(ret);
}
_CLC_BINARY_VECTORIZE(_CLC_DEF _CLC_OVERLOAD, double, __clc_pow, double, double)
#endif

/*
 * 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 "config.h"
#include "math.h"
#include "tables.h"
#include "../clcmacro.h"

/*
 compute pow using log and exp
 x^y = exp(y * log(x))

 we take care not to lose precision in the intermediate steps

 When computing log, calculate it in splits,

 r = f * (p_invead + p_inv_tail)
 r = rh + rt

 calculate log polynomial using r, in end addition, do
 poly = poly + ((rh-r) + rt)

 lth = -r
 ltt = ((xexp * log2_t) - poly) + logT
 lt = lth + ltt

 lh = (xexp * log2_h) + logH
 l = lh + lt

 Calculate final log answer as gh and gt,
 gh = l & higher-half bits
 gt = (((ltt - (lt - lth)) + ((lh - l) + lt)) + (l - gh))

 yh = y & higher-half bits
 yt = y - yh

 Before entering computation of exp,
 vs = ((yt*gt + yt*gh) + yh*gt)
 v = vs + yh*gh
 vt = ((yh*gh - v) + vs)

 In calculation of exp, add vt to r that is used for poly
 At the end of exp, do
 ((((expT * poly) + expT) + expH*poly) + expH)
*/

_CLC_DEF _CLC_OVERLOAD float __clc_pow(float x, float y)
{

    int ix = as_int(x);
    int ax = ix & EXSIGNBIT_SP32;
    int xpos = ix == ax;

    int iy = as_int(y);
    int ay = iy & EXSIGNBIT_SP32;
    int ypos = iy == ay;

    /* Extra precise log calculation
     *  First handle case that x is close to 1
     */
    float r = 1.0f - as_float(ax);
    int near1 = fabs(r) < 0x1.0p-4f;
    float r2 = r*r;

    /* Coefficients are just 1/3, 1/4, 1/5 and 1/6 */
    float poly = mad(r,
                     mad(r,
                         mad(r,
                             mad(r, 0x1.24924ap-3f, 0x1.555556p-3f),
                             0x1.99999ap-3f),
                         0x1.000000p-2f),
                     0x1.555556p-2f);

    poly *= r2*r;

    float lth_near1 = -r2 * 0.5f;
    float ltt_near1 = -poly;
    float lt_near1 = lth_near1 + ltt_near1;
    float lh_near1 = -r;
    float l_near1 = lh_near1 + lt_near1;

    /* Computations for x not near 1 */
    int m = (int)(ax >> EXPSHIFTBITS_SP32) - EXPBIAS_SP32;
    float mf = (float)m;
    int ixs = as_int(as_float(ax | 0x3f800000) - 1.0f);
    float mfs = (float)((ixs >> EXPSHIFTBITS_SP32) - 253);
    int c = m == -127;
    int ixn = c ? ixs : ax;
    float mfn = c ? mfs : mf;

    int indx = (ixn & 0x007f0000) + ((ixn & 0x00008000) << 1);

    /* F - Y */
    float f = as_float(0x3f000000 | indx) - as_float(0x3f000000 | (ixn & MANTBITS_SP32));

    indx = indx >> 16;
    float2 tv = USE_TABLE(log_inv_tbl_ep, indx);
    float rh = f * tv.s0;
    float rt = f * tv.s1;
    r = rh + rt;

    poly = mad(r, mad(r, 0x1.0p-2f, 0x1.555556p-2f), 0x1.0p-1f) * (r*r);
    poly += (rh - r) + rt;

    const float LOG2_HEAD = 0x1.62e000p-1f;  /* 0.693115234 */
    const float LOG2_TAIL = 0x1.0bfbe8p-15f; /* 0.0000319461833 */
    tv = USE_TABLE(loge_tbl, indx);
    float lth = -r;
    float ltt = mad(mfn, LOG2_TAIL, -poly) + tv.s1;
    float lt = lth + ltt;
    float lh = mad(mfn, LOG2_HEAD, tv.s0);
    float l = lh + lt;

    /* Select near 1 or not */
    lth = near1 ? lth_near1 : lth;
    ltt = near1 ? ltt_near1 : ltt;
    lt = near1 ? lt_near1 : lt;
    lh = near1 ? lh_near1 : lh;
    l = near1 ? l_near1 : l;

    float gh = as_float(as_int(l) & 0xfffff000);
    float gt = ((ltt - (lt - lth)) + ((lh - l) + lt)) + (l - gh);

    float yh = as_float(iy & 0xfffff000);

    float yt = y - yh;

    float ylogx_s = mad(gt, yh, mad(gh, yt, yt*gt));
    float ylogx = mad(yh, gh, ylogx_s);
    float ylogx_t = mad(yh, gh, -ylogx) + ylogx_s;

    /* Extra precise exp of ylogx */
    const float R_64_BY_LOG2 = 0x1.715476p+6f; /* 64/log2 : 92.332482616893657 */
    int n = convert_int(ylogx * R_64_BY_LOG2);
    float nf = (float) n;

    int j = n & 0x3f;
    m = n >> 6;
    int m2 = m << EXPSHIFTBITS_SP32;

    const float R_LOG2_BY_64_LD = 0x1.620000p-7f;  /* log2/64 lead: 0.0108032227 */
    const float R_LOG2_BY_64_TL = 0x1.c85fdep-16f; /* log2/64 tail: 0.0000272020388 */
    r = mad(nf, -R_LOG2_BY_64_TL, mad(nf, -R_LOG2_BY_64_LD, ylogx)) + ylogx_t;

    /* Truncated Taylor series for e^r */
    poly = mad(mad(mad(r, 0x1.555556p-5f, 0x1.555556p-3f), r, 0x1.000000p-1f), r*r, r);

    tv = USE_TABLE(exp_tbl_ep, j);

    float expylogx = mad(tv.s0, poly, mad(tv.s1, poly, tv.s1)) + tv.s0;
    float sexpylogx;
    if (!__clc_fp32_subnormals_supported()) {
		int explg = ((as_uint(expylogx) & EXPBITS_SP32 >> 23) - 127);
		m = (23-(m + 149)) == 0 ? 1: m;
		uint mantissa =  ((as_uint(expylogx) & MANTBITS_SP32)|IMPBIT_SP32) >> (23-(m + 149));
		sexpylogx = as_float(mantissa);
    } else {
		sexpylogx = expylogx * as_float(0x1 << (m + 149));
    }

    float texpylogx = as_float(as_int(expylogx) + m2);
    expylogx = m < -125 ? sexpylogx : texpylogx;

    /* Result is +-Inf if (ylogx + ylogx_t) > 128*log2 */
    expylogx = (ylogx > 0x1.62e430p+6f) | (ylogx == 0x1.62e430p+6f & ylogx_t > -0x1.05c610p-22f) ? as_float(PINFBITPATT_SP32) : expylogx;

    /* Result is 0 if ylogx < -149*log2 */
    expylogx = ylogx <  -0x1.9d1da0p+6f ? 0.0f : expylogx;

    /* Classify y:
     *   inty = 0 means not an integer.
     *   inty = 1 means odd integer.
     *   inty = 2 means even integer.
     */

    int yexp = (int)(ay >> EXPSHIFTBITS_SP32) - EXPBIAS_SP32 + 1;
    int mask = (1 << (24 - yexp)) - 1;
    int yodd = ((iy >> (24 - yexp)) & 0x1) != 0;
    int inty = yodd ? 1 : 2;
    inty = (iy & mask) != 0 ? 0 : inty;
    inty = yexp < 1 ? 0 : inty;
    inty = yexp > 24 ? 2 : inty;

    float signval = as_float((as_uint(expylogx) ^ SIGNBIT_SP32));
    expylogx = ((inty == 1) & !xpos) ? signval : expylogx;
    int ret = as_int(expylogx);

    /* Corner case handling */
    ret = (!xpos & (inty == 0)) ? QNANBITPATT_SP32 : ret;
    ret = ax < 0x3f800000 & iy == NINFBITPATT_SP32 ? PINFBITPATT_SP32 : ret;
    ret = ax > 0x3f800000 & iy == NINFBITPATT_SP32 ? 0 : ret;
    ret = ax < 0x3f800000 & iy == PINFBITPATT_SP32 ? 0 : ret;
    ret = ax > 0x3f800000 & iy == PINFBITPATT_SP32 ? PINFBITPATT_SP32 : ret;
    int xinf = xpos ? PINFBITPATT_SP32 : NINFBITPATT_SP32;
    ret = ((ax == 0) & !ypos & (inty == 1)) ? xinf : ret;
    ret = ((ax == 0) & !ypos & (inty != 1)) ? PINFBITPATT_SP32 : ret;
    int xzero = xpos ? 0 : 0x80000000;
    ret = ((ax == 0) & ypos & (inty == 1)) ? xzero : ret;
    ret = ((ax == 0) & ypos & (inty != 1)) ? 0 : ret;
    ret = ((ax == 0) & (iy == NINFBITPATT_SP32)) ? PINFBITPATT_SP32 : ret;
    ret = ((ix == 0xbf800000) & (ay == PINFBITPATT_SP32)) ? 0x3f800000 : ret;
    ret = ((ix == NINFBITPATT_SP32) & !ypos & (inty == 1)) ? 0x80000000 : ret;
    ret = ((ix == NINFBITPATT_SP32) & !ypos & (inty != 1)) ? 0 : ret;
    ret = ((ix == NINFBITPATT_SP32) & ypos & (inty == 1)) ? NINFBITPATT_SP32 : ret;
    ret = ((ix == NINFBITPATT_SP32) & ypos & (inty != 1)) ? PINFBITPATT_SP32 : ret;
    ret = ((ix == PINFBITPATT_SP32) & !ypos) ? 0 : ret;
    ret = ((ix == PINFBITPATT_SP32) & ypos) ? PINFBITPATT_SP32 : ret;
    ret = (ax > PINFBITPATT_SP32) ? ix : ret;
    ret = (ay > PINFBITPATT_SP32) ? iy : ret;
    ret = ay == 0 ? 0x3f800000 : ret;
    ret = ix == 0x3f800000 ? 0x3f800000 : ret;

    return as_float(ret);
}
_CLC_BINARY_VECTORIZE(_CLC_DEF _CLC_OVERLOAD, float, __clc_pow, float, float)

#ifdef cl_khr_fp64
_CLC_DEF _CLC_OVERLOAD double __clc_pow(double x, double y)
{
    const double real_log2_tail = 5.76999904754328540596e-08;
    const double real_log2_lead = 6.93147122859954833984e-01;

    long ux = as_long(x);
    long ax = ux & (~SIGNBIT_DP64);
    int xpos = ax == ux;

    long uy = as_long(y);
    long ay = uy & (~SIGNBIT_DP64);
    int ypos = ay == uy;

    // Extended precision log
    double v, vt;
    {
        int exp = (int)(ax >> 52) - 1023;
        int mask_exp_1023 = exp == -1023;
        double xexp = (double) exp;
        long mantissa = ax & 0x000FFFFFFFFFFFFFL;

        long temp_ux = as_long(as_double(0x3ff0000000000000L | mantissa) - 1.0);
        exp = ((temp_ux & 0x7FF0000000000000L) >> 52) - 2045;
        double xexp1 = (double) exp;
        long mantissa1 = temp_ux & 0x000FFFFFFFFFFFFFL;

        xexp = mask_exp_1023 ? xexp1 : xexp;
        mantissa = mask_exp_1023 ? mantissa1 : mantissa;

        long rax = (mantissa & 0x000ff00000000000) + ((mantissa & 0x0000080000000000) << 1);
        int index = rax >> 44;

        double F = as_double(rax | 0x3FE0000000000000L);
        double Y = as_double(mantissa | 0x3FE0000000000000L);
        double f = F - Y;
        double2 tv = USE_TABLE(log_f_inv_tbl, index);
        double log_h = tv.s0;
        double log_t = tv.s1;
        double f_inv = (log_h + log_t) * f;
        double r1 = as_double(as_long(f_inv) & 0xfffffffff8000000L);
        double r2 = fma(-F, r1, f) * (log_h + log_t);
        double r = r1 + r2;

        double poly = fma(r,
                          fma(r,
                              fma(r,
                                  fma(r, 1.0/7.0, 1.0/6.0),
                                  1.0/5.0),
                              1.0/4.0),
                          1.0/3.0);
        poly = poly * r * r * r;

        double hr1r1 = 0.5*r1*r1;
        double poly0h = r1 + hr1r1;
        double poly0t = r1 - poly0h + hr1r1;
        poly = fma(r1, r2, fma(0.5*r2, r2, poly)) + r2 + poly0t;

        tv = USE_TABLE(powlog_tbl, index);
        log_h = tv.s0;
        log_t = tv.s1;

        double resT_t = fma(xexp, real_log2_tail, + log_t) - poly;
        double resT = resT_t - poly0h;
        double resH = fma(xexp, real_log2_lead, log_h);
        double resT_h = poly0h;

        double H = resT + resH;
        double H_h = as_double(as_long(H) & 0xfffffffff8000000L);
        double T = (resH - H + resT) + (resT_t - (resT + resT_h)) + (H - H_h);
        H = H_h;

        double y_head = as_double(uy & 0xfffffffff8000000L);
        double y_tail = y - y_head;

        double temp = fma(y_tail, H, fma(y_head, T, y_tail*T));
        v = fma(y_head, H, temp);
        vt = fma(y_head, H, -v) + temp;
    }

    // Now calculate exp of (v,vt)

    double expv;
    {
        const double max_exp_arg = 709.782712893384;
        const double min_exp_arg = -745.1332191019411;
        const double sixtyfour_by_lnof2 = 92.33248261689366;
        const double lnof2_by_64_head = 0.010830424260348081;
        const double lnof2_by_64_tail = -4.359010638708991e-10;

        double temp = v * sixtyfour_by_lnof2;
        int n = (int)temp;
        double dn = (double)n;
        int j = n & 0x0000003f;
        int m = n >> 6;

        double2 tv = USE_TABLE(two_to_jby64_ep_tbl, j);
        double f1 = tv.s0;
        double f2 = tv.s1;
        double f = f1 + f2;

        double r1 = fma(dn, -lnof2_by_64_head, v);
        double r2 = dn * lnof2_by_64_tail;
        double r = (r1 + r2) + vt;

        double q = fma(r,
                       fma(r,
                           fma(r,
                               fma(r, 1.38889490863777199667e-03, 8.33336798434219616221e-03),
                               4.16666666662260795726e-02),
                           1.66666666665260878863e-01),
                       5.00000000000000008883e-01);
        q = fma(r*r, q, r);

        expv = fma(f, q, f2) + f1;
	      expv = ldexp(expv, m);

        expv = v > max_exp_arg ? as_double(0x7FF0000000000000L) : expv;
        expv = v < min_exp_arg ? 0.0 : expv;
    }

    // See whether y is an integer.
    // inty = 0 means not an integer.
    // inty = 1 means odd integer.
    // inty = 2 means even integer.

    int inty;
    {
        int yexp = (int)(ay >> EXPSHIFTBITS_DP64) - EXPBIAS_DP64 + 1;
        inty = yexp < 1 ? 0 : 2;
        inty = yexp > 53 ? 2 : inty;
        long mask = (1L << (53 - yexp)) - 1L;
        int inty1 = (((ay & ~mask) >> (53 - yexp)) & 1L) == 1L ? 1 : 2;
        inty1 = (ay & mask) != 0 ? 0 : inty1;
        inty = !(yexp < 1) & !(yexp > 53) ? inty1 : inty;
    }

    expv *= (inty == 1) & !xpos ? -1.0 : 1.0;

    long ret = as_long(expv);

    // Now all the edge cases
    ret = !xpos & (inty == 0) ? QNANBITPATT_DP64 : ret;
    ret = ax < 0x3ff0000000000000L & uy == NINFBITPATT_DP64 ? PINFBITPATT_DP64 : ret;
    ret = ax > 0x3ff0000000000000L & uy == NINFBITPATT_DP64 ? 0L : ret;
    ret = ax < 0x3ff0000000000000L & uy == PINFBITPATT_DP64 ? 0L : ret;
    ret = ax > 0x3ff0000000000000L & uy == PINFBITPATT_DP64 ? PINFBITPATT_DP64 : ret;
    long xinf = xpos ? PINFBITPATT_DP64 : NINFBITPATT_DP64;
    ret = ((ax == 0L) & !ypos & (inty == 1)) ? xinf : ret;
    ret = ((ax == 0L) & !ypos & (inty != 1)) ? PINFBITPATT_DP64 : ret;
    long xzero = xpos ? 0L : 0x8000000000000000L;
    ret = ((ax == 0L) & ypos & (inty == 1)) ? xzero : ret;
    ret = ((ax == 0L) & ypos & (inty != 1)) ? 0L : ret;
    ret = ((ax == 0L) & (uy == NINFBITPATT_DP64)) ? PINFBITPATT_DP64 : ret;
    ret = ((ux == 0xbff0000000000000L) & (ay == PINFBITPATT_DP64)) ? 0x3ff0000000000000L : ret;
    ret = ((ux == NINFBITPATT_DP64) & !ypos & (inty == 1)) ? 0x8000000000000000L : ret;
    ret = ((ux == NINFBITPATT_DP64) & !ypos & (inty != 1)) ? 0L : ret;
    ret = ((ux == NINFBITPATT_DP64) & ypos & (inty == 1)) ? NINFBITPATT_DP64 : ret;
    ret = ((ux == NINFBITPATT_DP64) & ypos & (inty != 1)) ? PINFBITPATT_DP64 : ret;
    ret = (ux == PINFBITPATT_DP64) & !ypos ? 0L : ret;
    ret = (ux == PINFBITPATT_DP64) & ypos ? PINFBITPATT_DP64 : ret;
    ret = ax > PINFBITPATT_DP64 ? ux : ret;
    ret = ay > PINFBITPATT_DP64 ? uy : ret;
    ret = ay == 0L ? 0x3ff0000000000000L : ret;
    ret = ux == 0x3ff0000000000000L ? 0x3ff0000000000000L : ret;

    return as_double(ret);
}
_CLC_BINARY_VECTORIZE(_CLC_DEF _CLC_OVERLOAD, double, __clc_pow, double, double)
#endif


r1902: mod with-database

r1902: mod with-database

;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          functional.cl
;;;; Purpose:       Functional interface
;;;; Programmer:    Pierre R. Mai
;;;;
;;;; Copyright (c) 1999-2001 Pierre R. Mai
;;;;
;;;; $Id: functional.cl,v 1.4 2002/05/04 02:43:15 kevin Exp $
;;;;
;;;; This file is part of CLSQL.
;;;;
;;;; CLSQL is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License (version 2) as
;;;; published by the Free Software Foundation.
;;;;
;;;; CLSQL is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with CLSQL; if not, write to the Free Software Foundation, Inc.,
;;;; 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
;;;; *************************************************************************

(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
(in-package :clsql-sys)

;;;; This file implements the more advanced functions of the
;;;; functional SQL interface, which are just nicer layers above the
;;;; basic SQL interface.

(defun insert-records
    (&key into attributes values av-pairs query (database *default-database*))
  "Insert records into the given table according to the given options."
  (cond
    ((and av-pairs (or attributes values))
     (error "Supply either av-pairs or values (and possibly attributes) to call of insert-records."))
    ((and (or av-pairs values) query)
     (error
      "Supply either query or values/av-pairs to call of insert-records."))
    ((and attributes (not query)
          (or (not (listp values)) (/= (length attributes) (length values))))
     (error "You must supply a matching values list when using attributes in call of insert-records."))
    (query
     (execute-command
      (format nil "insert into ~A ~@[(~{~A~^,~}) ~]~A" into attributes query)
      :database database))
    (t
     (execute-command
      (multiple-value-bind (attributes values)
          (if av-pairs
              (values (mapcar #'first av-pairs) (mapcar #'second av-pairs))
              (values attributes values))
	(format nil "insert into ~A ~@[(~{~A~^,~}) ~]values (~{'~A'~^,~})"
		into attributes values))
      :database database))))

(defun delete-records (&key from where (database *default-database*))
  "Delete the indicated records from the given database."
  (execute-command (format nil "delete from ~A ~@[where ~A ~]" from where)
                   :database database))

(defun update-records (table &key attributes values av-pairs where (database *default-database*))
  "Update the specified records in the given database."
  (cond
    ((and av-pairs (or attributes values))
     (error "Supply either av-pairs or values (and possibly attributes) to call of update-records."))
    ((and attributes
          (or (not (listp values)) (/= (length attributes) (length values))))
     (error "You must supply a matching values list when using attributes in call of update-records."))
    ((or (and attributes (not values)) (and values (not attributes)))
     (error "You must supply both values and attributes in call of update-records."))
    (t
     (execute-command
      (format nil "update ~A set ~:{~A = '~A'~:^, ~}~@[ where ~A~]"
              table
              (or av-pairs
                  (mapcar #'list attributes values))
              where)
      :database database))))

(defmacro with-database ((db-var connection-spec
				 &rest connect-args
				 &key (pool nil))
			 &body body)
  "Evaluate the body in an environment, where `db-var' is bound to the
database connection given by `connection-spec' and `connect-args'.
If pool is t the the connection will be taken from the general pool,
if pool is a conn-pool object the connection will be taken from this pool.
The connection is automatically closed or released to the pool
on exit from the body."
  `(let ((,db-var (connect ,connection-spec :pool ,pool ,@connect-args)))
     (unwind-protect
	 (progn
	   ,@body)
       (disconnect :database ,db-var :poool ,pool))))

;;;; -*- Mode: LISP; Syntax: ANSI-Common-Lisp; Base: 10 -*-
;;;; *************************************************************************
;;;; FILE IDENTIFICATION
;;;;
;;;; Name:          functional.cl
;;;; Purpose:       Functional interface
;;;; Programmer:    Pierre R. Mai
;;;;
;;;; Copyright (c) 1999-2001 Pierre R. Mai
;;;;
;;;; $Id: functional.cl,v 1.3 2002/05/03 20:50:18 marc.battyani Exp $
;;;;
;;;; This file is part of CLSQL.
;;;;
;;;; CLSQL is free software; you can redistribute it and/or modify
;;;; it under the terms of the GNU General Public License (version 2) as
;;;; published by the Free Software Foundation.
;;;;
;;;; CLSQL is distributed in the hope that it will be useful,
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;;;; GNU General Public License for more details.
;;;;
;;;; You should have received a copy of the GNU General Public License
;;;; along with CLSQL; if not, write to the Free Software Foundation, Inc.,
;;;; 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
;;;; *************************************************************************

(declaim (optimize (debug 3) (speed 3) (safety 1) (compilation-speed 0)))
(in-package :clsql-sys)

;;;; This file implements the more advanced functions of the
;;;; functional SQL interface, which are just nicer layers above the
;;;; basic SQL interface.

(defun insert-records
    (&key into attributes values av-pairs query (database *default-database*))
  "Insert records into the given table according to the given options."
  (cond
    ((and av-pairs (or attributes values))
     (error "Supply either av-pairs or values (and possibly attributes) to call of insert-records."))
    ((and (or av-pairs values) query)
     (error
      "Supply either query or values/av-pairs to call of insert-records."))
    ((and attributes (not query)
          (or (not (listp values)) (/= (length attributes) (length values))))
     (error "You must supply a matching values list when using attributes in call of insert-records."))
    (query
     (execute-command
      (format nil "insert into ~A ~@[(~{~A~^,~}) ~]~A" into attributes query)
      :database database))
    (t
     (execute-command
      (multiple-value-bind (attributes values)
          (if av-pairs
              (values (mapcar #'first av-pairs) (mapcar #'second av-pairs))
              (values attributes values))
	(format nil "insert into ~A ~@[(~{~A~^,~}) ~]values (~{'~A'~^,~})"
		into attributes values))
      :database database))))

(defun delete-records (&key from where (database *default-database*))
  "Delete the indicated records from the given database."
  (execute-command (format nil "delete from ~A ~@[where ~A ~]" from where)
                   :database database))

(defun update-records (table &key attributes values av-pairs where (database *default-database*))
  "Update the specified records in the given database."
  (cond
    ((and av-pairs (or attributes values))
     (error "Supply either av-pairs or values (and possibly attributes) to call of update-records."))
    ((and attributes
          (or (not (listp values)) (/= (length attributes) (length values))))
     (error "You must supply a matching values list when using attributes in call of update-records."))
    ((or (and attributes (not values)) (and values (not attributes)))
     (error "You must supply both values and attributes in call of update-records."))
    (t
     (execute-command
      (format nil "update ~A set ~:{~A = '~A'~:^, ~}~@[ where ~A~]"
              table
              (or av-pairs
                  (mapcar #'list attributes values))
              where)
      :database database))))

(defmacro with-database ((db-var connection-spec
				 &key (if-exists *connect-if-exists*)
				 (database-type *default-database-type*)
				 (pool nil))
			 &body body)
  "Evaluate the body in an environment, where `db-var' is bound to the
database connection given by `connection-spec' and `connect-args'.
If pool is t the the connection will be taken from the general pool,
if pool is a conn-pool object the connection will be taken from this pool.
The connection is automatically closed or released to the pool
on exit from the body."
  `(let ((,db-var (connect ,connection-spec :pool ,pool
			   :database-type ,database-type :if-exists ,if-exists)))
     (unwind-protect
	  (let ((,db-var ,db-var)) ,@body)
       (disconnect :database ,db-var))))


test case for __kernel_exec

test case for __kernel_exec

/* test case for OpenCL 1.1 Preprocessor Directives & Macros (section 6.9) */
__kernel_exec(1, float4) void compiler_preprocessor_macros()
{
#pragma OPENCL FP_CONTRACT ON
#pragma OPENCL FP_CONTRACT OFF
#pragma OPENCL FP_CONTRACT DEFAULT
  int i = __OPENCL_VERSION__;
  i = __CL_VERSION_1_0__;
  i = __CL_VERSION_1_1__;
  i = __ENDIAN_LITTLE__;
  i = __IMAGE_SUPPORT__;
  i = __FAST_RELAXED_MATH__;
}

/* test case for OpenCL 1.1 Preprocessor Directives & Macros (section 6.9) */
__kernel void compiler_preprocessor_macros()
{
#pragma OPENCL FP_CONTRACT ON
#pragma OPENCL FP_CONTRACT OFF
#pragma OPENCL FP_CONTRACT DEFAULT
  int i = __OPENCL_VERSION__;
  i = __CL_VERSION_1_0__;
  i = __CL_VERSION_1_1__;
  i = __ENDIAN_LITTLE__;
  i = __IMAGE_SUPPORT__;
  i = __FAST_RELAXED_MATH__;
}


BaseCL: Fixed entry-exit computation when inside the geometry.

/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2014-2015 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include "samplers.cl"
#include "transformations.cl"
#include "intersection/raytriangleintersection.cl"

__kernel void entryExitPointsKernel(float16 NDCToTextureMat
    , float16 worldToTextureMat
    , __global float const * __restrict vertices
    , __global int const * __restrict indices
    , int nIndices
    , write_only image2d_t entryPoints
    , write_only image2d_t exitPoints)
{
    int2 globalId = (int2)(get_global_id(0), get_global_id(1));
    if( any(globalId >= get_image_dim(entryPoints)) ) {
        return;
    }

	float2 normalizedScreenCoord = (float2)(get_global_id(0)+0.5f, get_global_id(1)+0.5f)/convert_float2(get_image_dim(entryPoints));

    // Compute near and far plane points along ray (device coordinates goes from [-1 -1 -1] to [1 1 1]
    float3 normalizedDeviceCoordNear = (float3)(2.0f*normalizedScreenCoord-1.0f, -1.f);
    float3 normalizedDeviceCoordFar = (float3)(2.0f*normalizedScreenCoord-1.0f, 1.f);
    // convert the ndc back to the volume texture coordinates
    float3 entry = (transformPointW(NDCToTextureMat, normalizedDeviceCoordNear));
    float3 exit = (transformPointW(NDCToTextureMat, normalizedDeviceCoordFar));
    float3 dir = exit-entry;
    float t = FLT_MAX;
    bool iSect = false;
    float t0 = FLT_MAX; float t1 = 0.f;
    for (int i = 0; i < nIndices-2; i +=1) {
        // Triangle strip
        int3 triangle = 3*(int3)(*indices, *(indices+1), *(indices+2));
        float3 v0 = (float3)(vertices[triangle.x], vertices[triangle.x+1], vertices[triangle.x+2]);
        float3 v1 = (float3)(vertices[triangle.y], vertices[triangle.y+1], vertices[triangle.y+2]);
        float3 v2 = (float3)(vertices[triangle.z], vertices[triangle.z+1], vertices[triangle.z+2]);
        float tt;
        iSect = rayTriangleIntersection(entry, dir, v0, v1, v2, &tt);
        if (iSect) {
            t0 = min(tt, t0);
            t1 = max(tt, t1);
        }
        indices+=1;
    }

	if(t1 != 0.f) {
		// We are inside the geometry if the
		// closest hit point is equal
		// to the farthest
		if (t0 == t1) {
			t0 = 0.f;
		}
        write_imagef(entryPoints, globalId,  (float4)(entry.xyz+t0*dir, 1.f));
		write_imagef(exitPoints, globalId,  (float4)(entry.xyz+t1*dir,1.f));
	} else {
		write_imagef(entryPoints, globalId,  (float4)(0.f));
		write_imagef(exitPoints, globalId,  (float4)(0.f));
	}
}

/*********************************************************************************
 *
 * Inviwo - Interactive Visualization Workshop
 *
 * Copyright (c) 2014-2015 Inviwo Foundation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 *********************************************************************************/

#include "samplers.cl"
#include "transformations.cl"
#include "intersection/raytriangleintersection.cl"

__kernel void entryExitPointsKernel(float16 NDCToTextureMat
    , float16 worldToTextureMat
    , __global float const * __restrict vertices
    , __global int const * __restrict indices
    , int nIndices
    , write_only image2d_t entryPoints
    , write_only image2d_t exitPoints)
{
    int2 globalId = (int2)(get_global_id(0), get_global_id(1));
    if( any(globalId >= get_image_dim(entryPoints)) ) {
        return;
    }

	float2 normalizedScreenCoord = (float2)(get_global_id(0)+0.5f, get_global_id(1)+0.5f)/convert_float2(get_image_dim(entryPoints));

    // Compute near and far plane points along ray (device coordinates goes from [-1 -1 -1] to [1 1 1]
    float3 normalizedDeviceCoordNear = (float3)(2.0f*normalizedScreenCoord-1.0f, -1.f);
    float3 normalizedDeviceCoordFar = (float3)(2.0f*normalizedScreenCoord-1.0f, 1.f);
    // convert the ndc back to the volume texture coordinates
    float3 entry = (transformPointW(NDCToTextureMat, normalizedDeviceCoordNear));
    float3 exit = (transformPointW(NDCToTextureMat, normalizedDeviceCoordFar));
    float3 dir = exit-entry;
    float t = FLT_MAX;
    bool iSect = false;
    float t0 = FLT_MAX; float t1 = 0.f;
    for (int i = 0; i < nIndices-2; i +=1) {
        // Triangle strip
        int3 triangle = 3*(int3)(*indices, *(indices+1), *(indices+2));
        float3 v0 = (float3)(vertices[triangle.x], vertices[triangle.x+1], vertices[triangle.x+2]);
        float3 v1 = (float3)(vertices[triangle.y], vertices[triangle.y+1], vertices[triangle.y+2]);
        float3 v2 = (float3)(vertices[triangle.z], vertices[triangle.z+1], vertices[triangle.z+2]);
        float tt;
        iSect = rayTriangleIntersection(entry, dir, v0, v1, v2, &tt);
        if (iSect) {
            t0 = min(tt, t0);
            t1 = max(tt, t1);
        }
        indices+=1;
    }

	if(t1 != 0.f) {
        write_imagef(entryPoints, globalId,  (float4)(entry.xyz+t0*dir, 1.f));
		write_imagef(exitPoints, globalId,  (float4)(entry.xyz+t1*dir,1.f));
	} else {
		write_imagef(entryPoints, globalId,  (float4)(0.f));
		write_imagef(exitPoints, globalId,  (float4)(0.f));
	}
}


sixtracklib/opencl: alternative fixes for the problems in the OpenCL tracking kernel functions

#ifndef SIXTRACKLIB_OPENCL_TRACK_PARTICLES_KERNEL_CL__
#define SIXTRACKLIB_OPENCL_TRACK_PARTICLES_KERNEL_CL__

#if defined( _GPUCODE )

void __kernel Track_remap_serialized_blocks_buffer(
     __global unsigned char* restrict  particles_data_buffer,
     __global unsigned char* restrict beam_elements_data_buffer,
     __global unsigned char* restrict elem_by_elem_data_buffer,
     __global long int*      restrict ptr_success_flag )
{
    size_t const global_id   = get_global_id( 0 );
    size_t const global_size = get_global_size( 0 );

    size_t const gid_to_remap_particles = 0;

    size_t const gid_to_remap_beam_elements = ( global_size > 1u )
        ? 1u : gid_to_remap_particles;

    size_t const gid_to_remap_elem_by_elem = ( global_size > 2u )
        ? 2u : gid_to_remap_beam_elements;

    long int  success_flag = 0;

    if( global_id <= gid_to_remap_elem_by_elem )
    {
        if( global_id == gid_to_remap_particles )
        {
            NS(Blocks) particles_buffer;
            NS(Blocks_preset)( &particles_buffer );

            if( 0 != NS(Blocks_unserialize)( &particles_buffer,
                        particles_data_buffer ) )
            {
                success_flag |= -1;
            }
        }

        if( ( success_flag == 0 ) &&
            ( global_id == gid_to_remap_beam_elements ) )
        {
            NS(Blocks) beam_elements;
            NS(Blocks_preset)( &beam_elements );

            if( 0 != NS(Blocks_unserialize)( &beam_elements,
                        beam_elements_data_buffer ) )
            {
                success_flag = -2;
            }
        }

        if( ( success_flag == 0 ) &&
            ( global_id == gid_to_remap_elem_by_elem ) )
        {
            __global unsigned long const* header =
                    ( __global unsigned long const* )elem_by_elem_data_buffer;

            if( ( header != 0 ) && ( header[ 0 ] != 0u ) )
            {
                NS(Blocks) elem_by_elem_buffer;
                NS(Blocks_preset)( &elem_by_elem_buffer );

                if( 0 != NS(Blocks_unserialize)(
                        &elem_by_elem_buffer, elem_by_elem_data_buffer ) )
                {
                    success_flag = -4;
                }
            }
        }

        if( ( success_flag != 0 ) && ( ptr_success_flag  != 0 ) )
        {
            *ptr_success_flag |= success_flag;
        }
    }

    return;
}

void __kernel Track_particles_kernel_opencl(
    unsigned long const num_of_turns,
    __global unsigned char* restrict particles_data_buffer,
    __global unsigned char* restrict beam_elements_data_buffer,
    __global unsigned char* restrict elem_by_elem_data_buffer,
    __global long int*      restrict ptr_success_flag )
{
    typedef __global unsigned long const* g_ulong_cptr_t;
    typedef __global NS(BlockInfo)*       g_info_ptr_t;
    typedef __global NS(Particles)*       g_particles_ptr_t;

    size_t const global_id   = get_global_id( 0 );
    size_t const global_size = get_global_size( 0 );

    NS(block_size_t) num_particle_blocks              = 0u;
    NS(block_size_t) num_beam_elements                = 0u;
    NS(block_size_t) num_elem_by_elem_blocks          = 0u;
    NS(block_size_t) num_elem_by_elem_blocks_per_turn = 0u;
    NS(block_size_t) num_required_elem_by_elem_blocks = 0u;
    NS(block_size_t) num_of_particles                 = 0u;

    NS(Blocks) particles_buffer;
    NS(Blocks) beam_elements;
    NS(Blocks) elem_by_elem_buffer;

    NS(Particles) particles;

    long int success_flag = 0;
    bool use_elem_by_elem_buffer = false;

    /* --------------------------------------------------------------------- */
    /* *****  SECTION FOR DEFUSING THE HEISENBUG *** */
    /* This printf section seems to defuse the Heisenbug on the AMDGPU
     * implementation available to the author -> YMMV */

    /*
    if( global_id == 0u )
    {
        g_particles_ptr_t particles_header =
            ( g_particles_ptr_t )particles_data_buffer;

        printf( "before unserialization: \r\n" );
        printf( "global_id     = %u\r\n", global_id );

        printf( "particles_header[ 0 ]   = %16x at %18x\r\n",
                 particles_header[ 0 ],
                 ( uintptr_t )( particles_data_buffer +  0 ) );

        printf( "particles_header[ 1 ]   = %16x at %18x\r\n",
                 particles_header[ 1 ],
                 ( uintptr_t )( particles_data_buffer +  8 ) );

        printf( "particles_header[ 2 ]   = %16x at %18x\r\n",
                 particles_header[ 2 ],
                ( uintptr_t )( particles_data_buffer + 16 ) );

        printf( "particles_header[ 3 ]   = %16x at %18x\r\n",
                 particles_header[ 3 ],
                ( uintptr_t )( particles_data_buffer + 32 ) );
    }

    barrier( CLK_GLOBAL_MEM_FENCE );
    */

    /* *****  END OF SECTION FOR DEFUSING THE HEISENBUG *** */
    /* --------------------------------------------------------------------- */

    NS(Blocks_preset)( &particles_buffer );

    if( 0 == NS(Blocks_unserialize_without_remapping)(
                &particles_buffer, particles_data_buffer ) )
    {
        num_particle_blocks = NS(Blocks_get_num_of_blocks)( &particles_buffer );

        if( num_particle_blocks == 1u )
        {
            g_particles_ptr_t ptr_particles  = 0;
            g_info_ptr_t  ptr_particles_info =
                NS(Blocks_get_block_infos_begin)( &particles_buffer );

            NS(BlockInfo) particles_info;

            if( ptr_particles_info != 0 )
            {
                particles_info = *ptr_particles_info;
            }
            else
            {
                NS(BlockInfo_preset)( &particles_info );
            }

            ptr_particles = NS(Blocks_get_particles)( &particles_info );

            if( ptr_particles != 0 )
            {
                particles = *ptr_particles;
            }
            else
            {
                NS(Particles_preset)( &particles );
            }

            num_of_particles = NS(Particles_get_num_particles)( &particles );
        }
    }

    if( num_of_particles == 0u )
    {
        NS(Blocks_preset)( &particles_buffer );
        NS(Particles_preset)( &particles );
        success_flag |= -1;
    }

    NS(Blocks_preset)( &beam_elements );

    if( 0 == NS(Blocks_unserialize_without_remapping)(
                &beam_elements, beam_elements_data_buffer ) )
    {
        num_beam_elements = NS(Blocks_get_num_of_blocks)( &beam_elements );
    }

    if( num_beam_elements == 0u )
    {
        NS(Blocks_preset)( &beam_elements );
        success_flag |= -2;
    }

    if( elem_by_elem_data_buffer != 0 )
    {
        g_ulong_cptr_t elem_by_elem_header =
            ( g_ulong_cptr_t )elem_by_elem_data_buffer;

        num_elem_by_elem_blocks_per_turn =
            num_beam_elements * num_particle_blocks;

        num_required_elem_by_elem_blocks =
            num_of_turns * num_elem_by_elem_blocks_per_turn;

        NS(Blocks_preset)( &elem_by_elem_buffer );

        if( 0 == NS(Blocks_unserialize_without_remapping)(
                    &elem_by_elem_buffer, elem_by_elem_data_buffer ) )
        {
            num_elem_by_elem_blocks =
                NS(Blocks_get_num_of_blocks)( &elem_by_elem_buffer );

            if( ( num_required_elem_by_elem_blocks > 0u ) &&
                ( num_elem_by_elem_blocks >=
                    num_required_elem_by_elem_blocks ) )
            {
                use_elem_by_elem_buffer = true;
            }
        }
        else if( elem_by_elem_header[ 0 ] != ( unsigned long )0u )
        {
            NS(Blocks_preset)( &elem_by_elem_buffer );
            success_flag |= -4;
        }
    }

    if( ( success_flag        == 0  ) && ( num_of_turns     != 0u ) &&
        ( num_beam_elements   != 0u ) && ( num_of_particles != 0u ) &&
        ( num_particle_blocks == 1u ) )
    {
        int ret = 0;
        unsigned long ii = 0u;

        if( global_id < num_of_particles )
        {
            if( !use_elem_by_elem_buffer )
            {
                for( ; ii < num_of_turns ; ++ii )
                {
                    ret |= NS(Track_beam_elements_particle)(
                            &particles, global_id, &beam_elements, 0 );
                }

                if( ret != 0 ) success_flag |= -8;
            }
            else
            {
                SIXTRL_GLOBAL_DEC NS(BlockInfo)* io_info_it =
                    NS(Blocks_get_block_infos_begin)( &elem_by_elem_buffer );

                for( ; ii < num_of_turns ; ++ii,
                        io_info_it = io_info_it + num_beam_elements )
                {
                    ret |= NS(Track_beam_elements_particle)(
                            &particles, global_id, &beam_elements, io_info_it );

                    if( io_info_it != 0 )
                    {
                        io_info_it = io_info_it +
                            num_elem_by_elem_blocks_per_turn;
                    }
                }

                if( ret != 0 ) success_flag |= -16;
            }
        }
    }
    else
    {
        success_flag |= -32;
    }

    if( ( success_flag != 0 ) && ( ptr_success_flag != 0 ) )
    {
        *ptr_success_flag |= success_flag;
    }

    return;
}

#endif /* defined( _GPUCODE ) */

#endif /* SIXTRACKLIB_OPENCL_TRACK_PARTICLES_KERNEL_CL__ */

/* end: sixtracklib/opencl/track_particles_kernel.cl */

#ifndef SIXTRACKLIB_OPENCL_TRACK_PARTICLES_KERNEL_CL__
#define SIXTRACKLIB_OPENCL_TRACK_PARTICLES_KERNEL_CL__

#if defined( _GPUCODE )

void __kernel Track_remap_serialized_blocks_buffer(
     __global unsigned char* restrict  particles_data_buffer,
     __global unsigned char* restrict beam_elements_data_buffer,
     __global unsigned char* restrict elem_by_elem_data_buffer,
     __global long int*      restrict ptr_success_flag )
{
    size_t const global_id   = get_global_id( 0 );
    size_t const global_size = get_global_size( 0 );

    size_t const gid_to_remap_particles = 0;

    size_t const gid_to_remap_beam_elements = ( global_size > 1u )
        ? 1u : gid_to_remap_particles;

    size_t const gid_to_remap_elem_by_elem = ( global_size > 2u )
        ? 2u : gid_to_remap_beam_elements;

    long int  success_flag = 0;

    if( global_id <= gid_to_remap_elem_by_elem )
    {
        if( global_id == gid_to_remap_particles )
        {
            NS(Blocks) particles_buffer;
            NS(Blocks_preset)( &particles_buffer );

            if( 0 != NS(Blocks_unserialize)( &particles_buffer,
                        particles_data_buffer ) )
            {
                success_flag |= -1;
            }
        }

        if( ( success_flag == 0 ) &&
            ( global_id == gid_to_remap_beam_elements ) )
        {
            NS(Blocks) beam_elements;
            NS(Blocks_preset)( &beam_elements );

            if( 0 != NS(Blocks_unserialize)( &beam_elements,
                        beam_elements_data_buffer ) )
            {
                success_flag = -2;
            }
        }

        if( ( success_flag == 0 ) &&
            ( global_id == gid_to_remap_elem_by_elem ) )
        {
            __global unsigned long const* header =
                    ( __global unsigned long const* )elem_by_elem_data_buffer;

            if( ( header != 0 ) && ( header[ 0 ] != 0u ) )
            {
                NS(Blocks) elem_by_elem_buffer;
                NS(Blocks_preset)( &elem_by_elem_buffer );

                if( 0 != NS(Blocks_unserialize)(
                        &elem_by_elem_buffer, elem_by_elem_data_buffer ) )
                {
                    success_flag = -4;
                }
            }
        }

        if( ( success_flag != 0 ) && ( ptr_success_flag  != 0 ) )
        {
            *ptr_success_flag |= success_flag;
        }
    }

    return;
}

void __kernel Track_particles_kernel_opencl(
    unsigned long const num_of_turns,
    __global unsigned char* restrict particles_data_buffer,
    __global unsigned char* restrict beam_elements_data_buffer,
    __global unsigned char* restrict elem_by_elem_data_buffer,
    __global long int*      restrict ptr_success_flag )
{
    typedef __global unsigned long const* g_ulong_cptr_t;
    typedef __global NS(BlockInfo)*       g_info_ptr_t;
    typedef __global NS(Particles)*       g_particles_ptr_t;

    size_t const global_id   = get_global_id( 0 );
    size_t const global_size = get_global_size( 0 );

    NS(block_size_t) num_particle_blocks              = 0u;
    NS(block_size_t) num_beam_elements                = 0u;
    NS(block_size_t) num_elem_by_elem_blocks          = 0u;
    NS(block_size_t) num_elem_by_elem_blocks_per_turn = 0u;
    NS(block_size_t) num_required_elem_by_elem_blocks = 0u;
    NS(block_size_t) num_of_particles                 = 0u;

    NS(Blocks) particles_buffer;
    NS(Blocks) beam_elements;
    NS(Blocks) elem_by_elem_buffer;

    NS(Particles) particles;

    long int success_flag = 0;
    bool use_elem_by_elem_buffer = false;

    /* --------------------------------------------------------------------- */
    /* *****  SECTION FOR DEFUSING THE HEISENBUG *** */
    /* This printf section seems to defuse the Heisenbug on the AMDGPU
     * implementation available to the author -> YMMV */

    /*
    if( global_id == 0u )
    {
        g_particles_ptr_t particles_header =
            ( g_particles_ptr_t )particles_data_buffer;

        printf( "before unserialization: \r\n" );
        printf( "global_id     = %u\r\n", global_id );

        printf( "particles_header[ 0 ]   = %16x at %18x\r\n",
                 particles_header[ 0 ],
                 ( uintptr_t )( particles_data_buffer +  0 ) );

        printf( "particles_header[ 1 ]   = %16x at %18x\r\n",
                 particles_header[ 1 ],
                 ( uintptr_t )( particles_data_buffer +  8 ) );

        printf( "particles_header[ 2 ]   = %16x at %18x\r\n",
                 particles_header[ 2 ],
                ( uintptr_t )( particles_data_buffer + 16 ) );

        printf( "particles_header[ 3 ]   = %16x at %18x\r\n",
                 particles_header[ 3 ],
                ( uintptr_t )( particles_data_buffer + 32 ) );
    }

    barrier( CLK_GLOBAL_MEM_FENCE );
    */

    /* *****  END OF SECTION FOR DEFUSING THE HEISENBUG *** */
    /* --------------------------------------------------------------------- */

    NS(Blocks_preset)( &particles_buffer );

    if( 0 == NS(Blocks_unserialize_without_remapping)(
                &particles_buffer, particles_data_buffer ) )
    {
        num_particle_blocks = NS(Blocks_get_num_of_blocks)( &particles_buffer );

        if( num_particle_blocks == 1u )
        {
            g_particles_ptr_t ptr_particles  = 0;
            g_info_ptr_t  ptr_particles_info =
                NS(Blocks_get_block_infos_begin)( &particles_buffer );

            NS(BlockInfo) particles_info;

            if( ptr_particles_info != 0 )
            {
                particles_info = *ptr_particles_info;
            }
            else
            {
                NS(BlockInfo_preset)( &particles_info );
            }

            ptr_particles = NS(Blocks_get_particles)( &particles_info );

            if( ptr_particles != 0 )
            {
                particles = *ptr_particles;
            }
            else
            {
                NS(Particles_preset)( &particles );
            }

            num_of_particles = NS(Particles_get_num_particles)( &particles );
        }
    }

    if( num_of_particles == 0u )
    {
        NS(Blocks_preset)( &particles_buffer );
        NS(Particles_preset)( &particles );
        success_flag |= -1;
    }

    NS(Blocks_preset)( &beam_elements );

    if( 0 == NS(Blocks_unserialize_without_remapping)(
                &beam_elements, beam_elements_data_buffer ) )
    {
        num_beam_elements = NS(Blocks_get_num_of_blocks)( &beam_elements );
    }

    if( num_beam_elements == 0u )
    {
        NS(Blocks_preset)( &beam_elements );
        success_flag |= -2;
    }

    if( elem_by_elem_data_buffer != 0 )
    {
        g_ulong_cptr_t elem_by_elem_header =
            ( g_ulong_cptr_t )elem_by_elem_data_buffer;

        num_elem_by_elem_blocks_per_turn =
            num_beam_elements * num_particle_blocks;

        num_required_elem_by_elem_blocks =
            num_of_turns * num_elem_by_elem_blocks_per_turn;

        NS(Blocks_preset)( &elem_by_elem_buffer );

        if( 0 == NS(Blocks_unserialize_without_remapping)(
                    &elem_by_elem_buffer, elem_by_elem_data_buffer ) )
        {
            num_elem_by_elem_blocks =
                NS(Blocks_get_num_of_blocks)( &elem_by_elem_buffer );

            if( ( num_required_elem_by_elem_blocks > 0u ) &&
                ( num_elem_by_elem_blocks >= num_required_elem_by_elem_blocks ) )
            {
                use_elem_by_elem_buffer = true;
            }
        }
        else if( elem_by_elem_header[ 0 ] != ( unsigned long )0u )
        {
            NS(Blocks_preset)( &elem_by_elem_buffer );
            success_flag |= -4;
        }
    }

    if( ( success_flag        == 0  ) && ( num_of_turns     != 0u ) &&
        ( num_beam_elements   != 0u ) && ( num_of_particles != 0u ) &&
        ( num_particle_blocks == 1u ) && ( global_id < num_of_particles ) )
    {
        int ret = 0;
        unsigned long ii = 0u;

        if( !use_elem_by_elem_buffer )
        {
            for( ; ii < num_of_turns ; ++ii )
            {
                ret |= NS(Track_beam_elements_particle)(
                        &particles, global_id, &beam_elements, 0 );
            }

            if( ret != 0 ) success_flag |= -8;
        }
        else
        {
            SIXTRL_GLOBAL_DEC NS(BlockInfo)* io_info_it =
                NS(Blocks_get_block_infos_begin)( &elem_by_elem_buffer );

            for( ; ii < num_of_turns ; ++ii,
                    io_info_it = io_info_it + num_beam_elements )
            {
                ret |= NS(Track_beam_elements_particle)(
                        &particles, global_id, &beam_elements, io_info_it );

                if( io_info_it != 0 )
                {
                    io_info_it = io_info_it + num_elem_by_elem_blocks_per_turn;
                }
            }

            if( ret != 0 ) success_flag |= -16;
        }
    }
    else
    {
        success_flag |= -32;
    }

    if( ( success_flag != 0 ) && ( ptr_success_flag != 0 ) )
    {
        *ptr_success_flag |= success_flag;
    }

    return;
}

#endif /* defined( _GPUCODE ) */

#endif /* SIXTRACKLIB_OPENCL_TRACK_PARTICLES_KERNEL_CL__ */

/* end: sixtracklib/opencl/track_particles_kernel.cl */


add explicit cast for half

add explicit cast for half

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (c) 2016-2017 Fabian David Tschopp, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#if defined(cl_khr_fp16)
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#endif

__kernel void prior_box(const int nthreads,
                        const float stepX,
                        const float stepY,
                        __global const float* _offsetsX,
                        __global const float* _offsetsY,
                        const int offsetsX_size,
                        __global const float* _widths,
                        __global const float* _heights,
                        const int widths_size,
                        __global Dtype* dst,
                        const int _layerHeight,
                        const int _layerWidth,
                        const int imgHeight,
                        const int imgWidth)
{
    for (int index = get_global_id(0); index < nthreads; index += get_global_size(0))
    {
        int w = index % _layerWidth;
        int h = index / _layerWidth;
        __global Dtype* outputPtr;

        outputPtr = dst + index * 4 * offsetsX_size * widths_size;

        float _boxWidth, _boxHeight;
        Dtype4 vec;
        for (int i = 0; i < widths_size; ++i)
        {
            _boxWidth = _widths[i];
            _boxHeight = _heights[i];
            for (int j = 0; j < offsetsX_size; ++j)
            {
                Dtype center_x = (w + _offsetsX[j]) * (Dtype)stepX;
                Dtype center_y = (h + _offsetsY[j]) * (Dtype)stepY;

                vec.x = (center_x - _boxWidth * 0.5f) / imgWidth;    // xmin
                vec.y = (center_y - _boxHeight * 0.5f) / imgHeight;  // ymin
                vec.z = (center_x + _boxWidth * 0.5f) / imgWidth;    // xmax
                vec.w = (center_y + _boxHeight * 0.5f) / imgHeight;  // ymax
                vstore4(vec, 0, outputPtr);

                outputPtr += 4;
            }
        }
    }
}

__kernel void set_variance(const int nthreads,
                           const int offset,
                           const int variance_size,
                           __global const float* variance,
                           __global Dtype* dst)
{
    for (int index = get_global_id(0); index < nthreads; index += get_global_size(0))
    {
        Dtype4 var_vec;

        if (variance_size == 1)
            var_vec = (Dtype4)(variance[0]);
        else
            var_vec = convert_T(vload4(0, variance));

        vstore4(var_vec, 0, dst + offset + index * 4);
    }
}

__kernel void clip(const int nthreads,
                   __global Dtype* dst)
{
    for (int index = get_global_id(0); index < nthreads; index += get_global_size(0))
    {
        Dtype4 vec = vload4(index, dst);
        vstore4(clamp(vec, (Dtype)0.0f, (Dtype)1.0f), index, dst);
    }
}

/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (c) 2016-2017 Fabian David Tschopp, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
//M*/

#if defined(cl_khr_fp16)
#pragma OPENCL EXTENSION cl_khr_fp16 : enable
#endif

__kernel void prior_box(const int nthreads,
                        const float stepX,
                        const float stepY,
                        __global const float* _offsetsX,
                        __global const float* _offsetsY,
                        const int offsetsX_size,
                        __global const float* _widths,
                        __global const float* _heights,
                        const int widths_size,
                        __global Dtype* dst,
                        const int _layerHeight,
                        const int _layerWidth,
                        const int imgHeight,
                        const int imgWidth)
{
    for (int index = get_global_id(0); index < nthreads; index += get_global_size(0))
    {
        int w = index % _layerWidth;
        int h = index / _layerWidth;
        __global Dtype* outputPtr;

        outputPtr = dst + index * 4 * offsetsX_size * widths_size;

        float _boxWidth, _boxHeight;
        Dtype4 vec;
        for (int i = 0; i < widths_size; ++i)
        {
            _boxWidth = _widths[i];
            _boxHeight = _heights[i];
            for (int j = 0; j < offsetsX_size; ++j)
            {
                Dtype center_x = (w + _offsetsX[j]) * (Dtype)stepX;
                Dtype center_y = (h + _offsetsY[j]) * (Dtype)stepY;

                vec.x = (center_x - _boxWidth * 0.5f) / imgWidth;    // xmin
                vec.y = (center_y - _boxHeight * 0.5f) / imgHeight;  // ymin
                vec.z = (center_x + _boxWidth * 0.5f) / imgWidth;    // xmax
                vec.w = (center_y + _boxHeight * 0.5f) / imgHeight;  // ymax
                vstore4(vec, 0, outputPtr);

                outputPtr += 4;
            }
        }
    }
}

__kernel void set_variance(const int nthreads,
                           const int offset,
                           const int variance_size,
                           __global const float* variance,
                           __global Dtype* dst)
{
    for (int index = get_global_id(0); index < nthreads; index += get_global_size(0))
    {
        Dtype4 var_vec;

        if (variance_size == 1)
            var_vec = (Dtype4)(variance[0]);
        else
            var_vec = convert_T(vload4(0, variance));

        vstore4(var_vec, 0, dst + offset + index * 4);
    }
}

__kernel void clip(const int nthreads,
                   __global Dtype* dst)
{
    for (int index = get_global_id(0); index < nthreads; index += get_global_size(0))
    {
        Dtype4 vec = vload4(index, dst);
        vstore4(clamp(vec, 0.0f, 1.0f), index, dst);
    }
}