Correct printf implementation

Correct printf implementation

/* OpenCL built-in library: printf()

   Copyright (c) 2013 Erik Schnetter <eschnetter@perimeterinstitute.ca>
                      Perimeter Institute for Theoretical Physics

   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.
*/

// Make the C99 printf visible again
#undef printf

#include <stdarg.h>

// We implement the OpenCL printf by calling the C99 printf. This is
// not very efficient, but is easy to implement.
int printf(const char* restrict fmt, ...);
int snprintf(char* restrict str, size_t size, const char* restrict fmt, ...);

// For debugging
// Use as: DEBUG_PRINTF((fmt, args...)) -- note double parentheses!
// #define DEBUG_PRINTF(args) (printf args)
#define DEBUG_PRINTF(args) ((void)0)

// Conversion flags
typedef struct {
  bool left;
  bool plus;
  bool space;
  bool alt;
  bool zero;
} flags_t;

// Helper routines to output integers

#define INT_CONV_char  "hh"
#define INT_CONV_short "h"
#define INT_CONV_int   ""
#define INT_CONV_long  "ll"     // C99 printf uses "ll" for int64_t

#define DEFINE_PRINT_INTS(WIDTH)                                        \
  void _cl_print_ints_##WIDTH(flags_t flags, int field_width, int precision, \
                              char conv, const void* vals, int n)       \
  {                                                                     \
    DEBUG_PRINTF(("[printf:ints:n=%df]\n", n));                         \
    char outfmt[1000];                                                  \
    snprintf(outfmt, sizeof outfmt,                                     \
             "%%%s%s%s%s%s%.0d%s%.0d" INT_CONV_##WIDTH "%c",            \
             flags.left ? "-" : "",                                     \
             flags.plus ? "+" : "",                                     \
             flags.space ? " " : "",                                    \
             flags.alt ? "#" : "",                                      \
             flags.zero ? "0" : "",                                     \
             field_width,                                               \
             precision != -1 ? "." : "",                                \
             precision != -1 ? precision : 0,                           \
             conv);                                                     \
    DEBUG_PRINTF(("[printf:ints:outfmt=%s]\n", outfmt));                \
    for (int d=0; d<n; ++d) {                                           \
      DEBUG_PRINTF(("[printf:ints:d=%d]\n", d));                        \
      if (d != 0) printf(",");                                          \
      printf(outfmt, ((const WIDTH*)vals)[d]);                          \
    }                                                                   \
    DEBUG_PRINTF(("[printf:ints:done]\n"));                             \
  }

DEFINE_PRINT_INTS(char)
DEFINE_PRINT_INTS(short)
DEFINE_PRINT_INTS(int)
#ifdef cles_khr_int64
DEFINE_PRINT_INTS(long)
#endif

#undef DEFINE_PRINT_INTS

// Helper routines to output floats

// Note: To simplify implementation, we print double values with %lf,
// although %f would suffice as well
#define FLOAT_CONV_half   "h"
#define FLOAT_CONV_float  ""
#define FLOAT_CONV_double "l"

#define DEFINE_PRINT_FLOATS(WIDTH)                                      \
  void _cl_print_floats_##WIDTH(flags_t flags, int field_width, int precision, \
                                char conv, const void* vals, int n)     \
  {                                                                     \
    DEBUG_PRINTF(("[printf:floats:n=%dd]\n", n));                       \
    char outfmt[1000];                                                  \
    snprintf(outfmt, sizeof outfmt,                                     \
             "%%%s%s%s%s%s%.0d%s%.0d" FLOAT_CONV_##WIDTH "%c",          \
             flags.left ? "-" : "",                                     \
             flags.plus ? "+" : "",                                     \
             flags.space ? " " : "",                                    \
             flags.alt ? "#" : "",                                      \
             flags.zero ? "0" : "",                                     \
             field_width,                                               \
             precision != -1 ? "." : "",                                \
             precision != -1 ? precision : 0,                           \
             conv);                                                     \
    DEBUG_PRINTF(("[printf:floats:outfmt=%s]\n", outfmt));              \
    for (int d=0; d<n; ++d) {                                           \
      DEBUG_PRINTF(("[printf:floats:d=%d]\n", d));                      \
      if (d != 0) printf(",");                                          \
      printf(outfmt, ((const WIDTH*)vals)[d]);                          \
    }                                                                   \
    DEBUG_PRINTF(("[printf:floats:done]\n"));                           \
  }

#ifdef cl_khr_fp16
DEFINE_PRINT_FLOATS(half)
#endif
DEFINE_PRINT_FLOATS(float)
#ifdef cl_khr_fp64
DEFINE_PRINT_FLOATS(double)
#endif

#undef DEFINE_PRINT_FLOATS

// The OpenCL printf routine.

// The implementation is straightforward:
// - walk through the format string
// - when a variable should be output, parse flags, field width,
//   precision, vector specifier, length, and conversion specifier
// - call a helper routine to perform the actual output
// - the helper routine is based on calling C99 printf, and constructs
//   a format string via snprintf
// - if there is an error during parsing, a "goto error" aborts the
//   routine, returning -1

int _cl_printf(const char* restrict format, ...)
{
  DEBUG_PRINTF(("[printf:format=%s]\n", format));
  va_list ap;
  va_start(ap, format);

  char ch = *format;
  while (ch) {
    if (ch == '%') {
      ch = *++format;

      if (ch == '%') {
        DEBUG_PRINTF(("[printf:%%]\n"));
        printf("%%");           // literal %
        ch = *++format;
      } else {
        DEBUG_PRINTF(("[printf:arg]\n"));
        // Flags
        flags_t flags;
        flags.left = false;
        flags.plus = false;
        flags.space = false;
        flags.alt = false;
        flags.zero = false;
        for (;;) {
          switch (ch) {
          case '-': if (flags.left) goto error; flags.left = true; break;
          case '+': if (flags.plus) goto error; flags.plus = true; break;
          case ' ': if (flags.space) goto error; flags.space = true; break;
          case '#': if (flags.alt) goto error; flags.alt = true; break;
          case '0': if (flags.zero) goto error; flags.zero = true; break;
          default: goto flags_done;
          }
          ch = *++format;
        }
      flags_done:;
        DEBUG_PRINTF(("[printf:flags:left=%d,plus=%d,space=%d,alt=%d,zero=%d]\n",
                      flags.left, flags.plus, flags.space, flags.alt, flags.zero));

        // Field width
        int field_width = 0;
        while (ch >= '0' && ch <= '9') {
          if (ch == '0' && field_width == 0) goto error;
          if (field_width > (INT_MAX - 9) / 10) goto error;
          field_width = 10 * field_width + (ch - '0');
          ch = *++format;
        }
        DEBUG_PRINTF(("[printf:width=%d]\n", field_width));

        // Precision
        int precision;
        if (ch == '.') {
          ch = *++format;
          precision = 0;
          while (ch >= '0' && ch <= '9') {
            if (precision > (INT_MAX - 9) / 10) goto error;
            precision = 10 * precision + (ch - '0');
            ch = *++format;
          }
        } else {
          precision = -1;
        }
        DEBUG_PRINTF(("[printf:precision=%d]\n", precision));

        // Vector specifier
        int vector_length = 0;
        if (ch == 'v') {
          ch = *++format;
          while (ch >= '0' && ch <= '9') {
            if (ch == '0' && vector_length == 0) goto error;
            if (vector_length > (INT_MAX - 9) / 10) goto error;
            vector_length = 10 * vector_length + (ch - '0');
            ch = *++format;
          }
          if (! (vector_length == 2 ||
                 vector_length == 3 ||
                 vector_length == 4 ||
                 vector_length == 8 ||
                 vector_length == 16)) goto error;

        }
        DEBUG_PRINTF(("[printf:vector_length=%d]\n", vector_length));

        // Length modifier
        int length = 0;           // default
        if (ch == 'h') {
          ch = *++format;
          if (ch == 'h') {
            ch = *++format;
            length = 1;           // "hh" -> char
          } else if (ch == 'l') {
            ch = *++format;
            length = 4;           // "hl" -> int
          } else {
            length = 2;           // "h" -> short
          }
        } else if (ch == 'l') {
          ch = *++format;
          length = 8;             // "l" -> long
        }
        if (vector_length > 0 && length == 0) goto error;
        if (vector_length == 0 && length == 4) goto error;
        if (vector_length == 0) vector_length = 1;
        DEBUG_PRINTF(("[printf:length=%d]\n", length));

        // Conversion specifier
        switch (ch) {

          // Output integers
        case 'd':
        case 'i':
        case 'o':
        case 'u':
        case 'x':
        case 'X':

#define CALL_PRINT_INTS(WIDTH, PROMOTED_WIDTH)                          \
          {                                                             \
            WIDTH##16 val;                                              \
            switch (vector_length) {                                    \
            default: __builtin_unreachable();                           \
            case 1: val.s0 = va_arg(ap, PROMOTED_WIDTH); break;         \
            case 2: val.s01 = va_arg(ap, WIDTH##2); break;              \
            case 3: val.s012 = va_arg(ap, WIDTH##3); break;             \
            case 4: val.s0123 = va_arg(ap, WIDTH##4); break;            \
            case 8: val.lo = va_arg(ap, WIDTH##8); break;               \
            case 16: val = va_arg(ap, WIDTH##16); break;                \
            }                                                           \
            _cl_print_ints_##WIDTH(flags, field_width, precision,       \
                                   ch, &val, vector_length);            \
          }

          DEBUG_PRINTF(("[printf:int:conversion=%c]\n", ch));
          switch (length) {
          default: __builtin_unreachable();
          case 1: CALL_PRINT_INTS(char, int); break;
          case 2: CALL_PRINT_INTS(short, int); break;
          case 0:
          case 4: CALL_PRINT_INTS(int, int); break;
#ifdef cles_khr_int64
          case 8: CALL_PRINT_INTS(long, long); break;
#endif
          }

#undef CALL_PRINT_INTS

          break;

          // Output floats
        case 'f':
        case 'F':
        case 'e':
        case 'E':
        case 'g':
        case 'G':
        case 'a':
        case 'A':

#define CALL_PRINT_FLOATS(WIDTH, PROMOTED_WIDTH)                        \
          {                                                             \
            WIDTH##16 val;                                              \
            switch (vector_length) {                                    \
            default: __builtin_unreachable();                           \
            case 1: val.s0 = va_arg(ap, PROMOTED_WIDTH); break;         \
            case 2: val.s01 = va_arg(ap, WIDTH##2); break;              \
            case 3: val.s012 = va_arg(ap, WIDTH##3); break;             \
            case 4: val.s0123 = va_arg(ap, WIDTH##4); break;            \
            case 8: val.lo = va_arg(ap, WIDTH##8); break;               \
            case 16: val = va_arg(ap, WIDTH##16); break;                \
            }                                                           \
            _cl_print_floats_##WIDTH(flags, field_width, precision,     \
                                     ch, &val, vector_length);          \
          }

          DEBUG_PRINTF(("[printf:float:conversion=%c]\n", ch));
          switch (length) {
          default: __builtin_unreachable();
#ifdef cl_khr_fp16
            // case 2: CALL_PRINT_FLOATS(half, double); break;
          case 2: goto error;   // not yet implemented
#endif
          case 0:
            // Note: width 0 cleverly falls through to float if double
            // is not supported
#ifdef cl_khr_fp64
          case 8: CALL_PRINT_FLOATS(double, double); break;
#endif
          case 4: CALL_PRINT_FLOATS(float, double); break;
          }

#undef CALL_PRINT_FLOATS

          break;

        case 'c': goto error;   // not yet implemented
        case 's': goto error;   // not yet implemented
        case 'p': goto error;   // not yet implemented

        default: goto error;
        }
        ch = *++format;

      } // not a literal %

    } else {
      DEBUG_PRINTF(("[printf:char]\n"));
      printf("%c", ch);
      ch = *++format;
    }
  }

  va_end(ap);
  DEBUG_PRINTF(("[printf:done]\n"));
  return 0;

 error:;
  va_end(ap);
  DEBUG_PRINTF(("[printf:error]\n"));
  return -1;
}

/* OpenCL built-in library: printf()

   Copyright (c) 2013 Erik Schnetter <eschnetter@perimeterinstitute.ca>
                      Perimeter Institute for Theoretical Physics

   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.
*/

// Make the C99 printf visible again
#undef printf

#include <stdarg.h>

// We implement the OpenCL printf by calling the C99 printf. This is
// not very efficient, but is easy to implement.
int printf(const char* restrict fmt, ...);
int snprintf(char* restrict str, size_t size, const char* restrict fmt, ...);

// For debugging
// Use as: DEBUG_PRINTF((fmt, args...)) -- note double parentheses!
// #define DEBUG_PRINTF(args) printf(args)
#define DEBUG_PRINTF(args) ((void)0)

// Conversion flags
typedef struct {
  bool left;
  bool plus;
  bool space;
  bool alt;
  bool zero;
} flags_t;

// Helper routines to output integers

#define INT_CONV_char  "hh"
#define INT_CONV_short "h"
#define INT_CONV_int   ""
#define INT_CONV_long  "ll"     // C99 printf uses "ll" for int64_t

#define DEFINE_PRINT_INTS(WIDTH)                                        \
  void _cl_print_ints_##WIDTH(flags_t flags, int field_width, int precision, \
                              char conv, const void* vals, int n)       \
  {                                                                     \
    DEBUG_PRINTF(("[printf:ints:n=%df]\n", n));                         \
    char outfmt[1000];                                                  \
    snprintf(outfmt, sizeof outfmt,                                     \
             "%%%s%s%s%s%s%.0d%s%.0d" INT_CONV_##WIDTH "%c",            \
             flags.left ? "-" : "",                                     \
             flags.plus ? "+" : "",                                     \
             flags.space ? " " : "",                                    \
             flags.alt ? "#" : "",                                      \
             flags.zero ? "0" : "",                                     \
             field_width,                                               \
             precision != -1 ? "." : "",                                \
             precision != -1 ? precision : 0,                           \
             conv);                                                     \
    DEBUG_PRINTF(("[printf:ints:outfmt=%s]\n", outfmt));                \
    for (int d=0; d<n; ++d) {                                           \
      DEBUG_PRINTF(("[printf:ints:d=%d]\n", d));                        \
      if (d != 0) printf(",");                                          \
      printf(outfmt, ((const WIDTH*)vals)[d]);                          \
    }                                                                   \
    DEBUG_PRINTF(("[printf:ints:done]\n"));                             \
  }

DEFINE_PRINT_INTS(char)
DEFINE_PRINT_INTS(short)
DEFINE_PRINT_INTS(int)
#ifdef cles_khr_int64
DEFINE_PRINT_INTS(long)
#endif

#undef DEFINE_PRINT_INTS

// Helper routines to output floats

// Note: To simplify implementation, we print double values with %lf,
// although %f would suffice as well
#define FLOAT_CONV_half   "h"
#define FLOAT_CONV_float  ""
#define FLOAT_CONV_double "l"

#define DEFINE_PRINT_FLOATS(WIDTH)                                      \
  void _cl_print_floats_##WIDTH(flags_t flags, int field_width, int precision, \
                                char conv, const void* vals, int n)     \
  {                                                                     \
    char outfmt[1000];                                                  \
    snprintf(outfmt, sizeof outfmt,                                     \
             "%%%s%s%s%s%s%.0d%s%.0d" FLOAT_CONV_##WIDTH "%c",          \
             flags.left ? "-" : "",                                     \
             flags.plus ? "+" : "",                                     \
             flags.space ? " " : "",                                    \
             flags.alt ? "#" : "",                                      \
             flags.zero ? "0" : "",                                     \
             field_width,                                               \
             precision != -1 ? "." : "",                                \
             precision != -1 ? precision : 0,                           \
             conv);                                                     \
    for (int d=0; d<n; ++d) {                                           \
      if (d != 0) printf(",");                                          \
      printf(outfmt, ((const WIDTH*)vals)[d]);                          \
    }                                                                   \
  }

#ifdef cl_khr_fp16
DEFINE_PRINT_FLOATS(half)
#endif
DEFINE_PRINT_FLOATS(float)
#ifdef cl_khr_fp64
DEFINE_PRINT_FLOATS(double)
#endif

#undef DEFINE_PRINT_FLOATS

// The OpenCL printf routine.

// The implementation is straightforward:
// - walk through the format string
// - when a variable should be output, parse flags, field width,
//   precision, vector specifier, length, and conversion specifier
// - call a helper routine to perform the actual output
// - the helper routine is based on calling C99 printf, and constructs
//   a format string via snprintf
// - if there is an error during parsing, a "goto error" aborts the
//   routine, returning -1

int _cl_printf(const char* restrict format, ...)
{
  DEBUG_PRINTF(("[printf:format=%s]\n", format));
  va_list ap;
  va_start(ap, format);

  char ch = *format;
  while (ch) {
    if (ch == '%') {
      ch = *++format;

      if (ch == '%') {
        DEBUG_PRINTF(("[printf:%%]\n"));
        printf("%%");           // literal %
        ch = *++format;
      } else {
        DEBUG_PRINTF(("[printf:arg]\n"));
        // Flags
        flags_t flags;
        flags.left = false;
        flags.plus = false;
        flags.space = false;
        flags.alt = false;
        flags.zero = false;
        for (;;) {
          switch (ch) {
          case '-': if (flags.left) goto error; flags.left = true; break;
          case '+': if (flags.plus) goto error; flags.plus = true; break;
          case ' ': if (flags.space) goto error; flags.space = true; break;
          case '#': if (flags.alt) goto error; flags.alt = true; break;
          case '0': if (flags.zero) goto error; flags.zero = true; break;
          default: goto flags_done;
          }
          ch = *++format;
        }
      flags_done:;
        DEBUG_PRINTF(("[printf:flags:left=%d,plus=%d,space=%d,alt=%d,zero=%d]\n",
                      flags.left, flags.plus, flags.space, flags.alt, flags.zero));

        // Field width
        int field_width = 0;
        while (ch >= '0' && ch <= '9') {
          if (ch == '0' && field_width == 0) goto error;
          if (field_width > (INT_MAX - 9) / 10) goto error;
          field_width = 10 * field_width + (ch - '0');
          ch = *++format;
        }
        DEBUG_PRINTF(("[printf:width=%d]\n", field_width));

        // Precision
        int precision;
        if (ch == '.') {
          ch = *++format;
          precision = 0;
          while (ch >= '0' && ch <= '9') {
            if (precision > (INT_MAX - 9) / 10) goto error;
            precision = 10 * precision + (ch - '0');
            ch = *++format;
          }
        } else {
          precision = -1;
        }
        DEBUG_PRINTF(("[printf:precision=%d]\n", precision));

        // Vector specifier
        int vector_length = 0;
        if (ch == 'v') {
          ch = *++format;
          while (ch >= '0' && ch <= '9') {
            if (ch == '0' && vector_length == 0) goto error;
            if (vector_length > (INT_MAX - 9) / 10) goto error;
            vector_length = 10 * vector_length + (ch - '0');
            ch = *++format;
          }
          if (! (vector_length == 2 ||
                 vector_length == 3 ||
                 vector_length == 4 ||
                 vector_length == 8 ||
                 vector_length == 16)) goto error;

        }
        DEBUG_PRINTF(("[printf:vector_length=%d]\n", vector_length));

        // Length modifier
        int length = 0;           // default
        if (ch == 'h') {
          ch = *++format;
          if (ch == 'h') {
            ch = *++format;
            length = 1;           // "hh" -> char
          } else if (ch == 'l') {
            ch = *++format;
            length = 4;           // "hl" -> int
          } else {
            length = 2;           // "h" -> short
          }
        } else if (ch == 'l') {
          ch = *++format;
          length = 8;             // "l" -> long
        }
        if (vector_length > 0 && length == 0) goto error;
        if (vector_length == 0 && length == 4) goto error;
        if (vector_length == 0) vector_length = 1;
        DEBUG_PRINTF(("[printf:length=%d]\n", length));

        // Conversion specifier
        switch (ch) {

          // Output integers
        case 'd':
        case 'i':
        case 'o':
        case 'u':
        case 'x':
        case 'X':

#define CALL_PRINT_INTS(WIDTH, PROMOTED_WIDTH)                          \
          {                                                             \
            WIDTH##16 val;                                              \
            switch (vector_length) {                                    \
            default: __builtin_unreachable();                           \
            case 1: val.s0 = va_arg(ap, PROMOTED_WIDTH); break;         \
            case 2: val.s01 = va_arg(ap, WIDTH##2); break;              \
            case 3: val.s012 = va_arg(ap, WIDTH##3); break;             \
            case 4: val.s0123 = va_arg(ap, WIDTH##4); break;            \
            case 8: val.lo = va_arg(ap, WIDTH##8); break;               \
            case 16: val = va_arg(ap, WIDTH##16); break;                \
            }                                                           \
            _cl_print_ints_##WIDTH(flags, field_width, precision,       \
                                   ch, &val, vector_length);            \
          }

          DEBUG_PRINTF(("[printf:int:conversion=%c]\n", ch));
          switch (length) {
          default: __builtin_unreachable();
          case 1: CALL_PRINT_INTS(char, int); break;
          case 2: CALL_PRINT_INTS(short, int); break;
          case 0:
          case 4: CALL_PRINT_INTS(int, int); break;
#ifdef cles_khr_int64
          case 8: CALL_PRINT_INTS(long, long); break;
#endif
          }

#undef CALL_PRINT_INTS

          break;

          // Output floats
        case 'f':
        case 'F':
        case 'e':
        case 'E':
        case 'g':
        case 'G':
        case 'a':
        case 'A':

#define CALL_PRINT_FLOATS(WIDTH, PROMOTED_WIDTH)                        \
          {                                                             \
            WIDTH##16 val;                                              \
            switch (vector_length) {                                    \
            default: __builtin_unreachable();                           \
            case 1: val.s0 = va_arg(ap, PROMOTED_WIDTH); break;         \
            case 2: val.s01 = va_arg(ap, WIDTH##2); break;              \
            case 3: val.s012 = va_arg(ap, WIDTH##3); break;             \
            case 4: val.s0123 = va_arg(ap, WIDTH##4); break;            \
            case 8: val.lo = va_arg(ap, WIDTH##8); break;               \
            case 16: val = va_arg(ap, WIDTH##16); break;                \
            }                                                           \
            _cl_print_floats_##WIDTH(flags, field_width, precision,     \
                                     ch, &val, vector_length);          \
          }

          DEBUG_PRINTF(("[printf:float:conversion=%c]\n", ch));
          switch (length) {
          default: __builtin_unreachable();
#ifdef cles_khr_fp16
          case 2: CALL_PRINT_FLOATS(half, double); break;
#endif
          case 0:
            // Note: width 0 cleverly falls through to float if double
            // is not supported
#ifdef cles_khr_fp64
          case 8: CALL_PRINT_FLOATS(double, double); break;
          case 4: CALL_PRINT_FLOATS(float, double); break;
#endif
              break;
          }

#undef CALL_PRINT_FLOATS

          break;

        case 'c': goto error;   // not yet implemented
        case 's': goto error;   // not yet implemented
        case 'p': goto error;   // not yet implemented

        default: goto error;
        }
        ch = *++format;

      } // not a literal %

    } else {
      DEBUG_PRINTF(("[printf:char]\n"));
      printf("%c", ch);
      ch = *++format;
    }
  }

  va_end(ap);
  DEBUG_PRINTF(("[printf:done]\n"));
  return 0;

 error:;
  va_end(ap);
  DEBUG_PRINTF(("[printf:error]\n"));
  return -1;
}


Correct hadd() implementation

Correct hadd() implementation

Correct hadd() implementation.
Re-enable hadd() for Clang 3.3, in the hope that it works now.

/* OpenCL built-in library: hadd()

   Copyright (c) 2011 Universidad Rey Juan Carlos

   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 "templates.h"

DEFINE_EXPR_G_GG(hadd,
                 (a >> (sgtype)1) + (b >> (sgtype)1) + (a & b & (sgtype)1))

/* OpenCL built-in library: hadd()

   Copyright (c) 2011 Universidad Rey Juan Carlos

   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 "templates.h"

#if (__clang_major__ == 3) && (__clang_minor__ <= 3)
// Clang 3.3 crashes when generating this. Probably due to the
// conversion (implicit conversion between vectors are not supported
// anyhow).
DEFINE_EXPR_G_GG(hadd,
                 (a >> (sgtype)1) + (b >> (sgtype)1) + (a & b & (gtype)1))
#endif


USE_CLRANDOM must be undefined!!!

USE_CLRANDOM must be undefined!!!

cl_random_prob is broken!!! produces the same random numbers for all cells.

git-svn-id: 602a26e73ae9f2a14e2bb95676f2e137fcc39919@3610 7c0444ca-5550-0410-9008-faecdbe78eb5

#include "LIF_params.h"
#include "cl_random.hcl"

#ifndef PV_USE_OPENCL
#  include <math.h>
#  define EXP expf
#  define CL_KERNEL
#  define CL_MEM_GLOBAL
#  define CL_MEM_LOCAL
#else  /* compiling with OpenCL */
#  define EXP exp
#  define CL_KERNEL       __kernel
#  define CL_MEM_GLOBAL   __global
#  define CL_MEM_LOCAL    __local
#  include "conversions.hcl"
#endif

#undef USE_CLRANDOM
#ifndef USE_CLRANDOM
#  include "../utils/pv_random.h"
#endif

//
// update the state of a retinal layer (spiking)
//
//    assume called with 1D kernel
//
CL_KERNEL
void LIF_update_state(
    const float time,
    const float dt,

    const int nx,
    const int ny,
    const int nf,
    const int nb,

    CL_MEM_GLOBAL LIF_params * params,
    CL_MEM_GLOBAL uint4 * rnd,
    CL_MEM_GLOBAL float * V,
    CL_MEM_GLOBAL float * Vth,
    CL_MEM_GLOBAL float * G_E,
    CL_MEM_GLOBAL float * G_I,
    CL_MEM_GLOBAL float * G_IB,
    CL_MEM_GLOBAL float * phiExc,
    CL_MEM_GLOBAL float * phiInh,
    CL_MEM_GLOBAL float * phiInhB,
    CL_MEM_GLOBAL float * R,
    CL_MEM_GLOBAL float * activity)
{
   int k;

   const float exp_tauE    = EXP(-dt/params->tauE);
   const float exp_tauI    = EXP(-dt/params->tauI);
   const float exp_tauIB   = EXP(-dt/params->tauIB);
   const float exp_tauVth  = EXP(-dt/params->tauVth);

   const float dt_sec = .001 * dt;   // convert to seconds
   const float exp_tauRate = EXP(-dt/params->tauRate);

#ifndef PV_USE_OPENCL

for (k = 0; k < nx*ny*nf; k++) {
#else
   k = get_global_id(0);
#endif

   int kex = kIndexExtended(k, nx, ny, nf, nb);

   //
   // kernel (nonheader part) begins here
   //

   // local param variables
   float tau, Vrest, VthRest, Vexc, Vinh, VinhB, deltaVth;

   const float GMAX = 10.0;

   // local variables
   float l_activ;

   uint4 l_rnd = rnd[k];

   float l_V   = V[k];
   float l_Vth = Vth[k];

   float l_G_E  = G_E[k];
   float l_G_I  = G_I[k];
   float l_G_IB = G_IB[k];

   float l_phiExc  = phiExc[k];
   float l_phiInh  = phiInh[k];
   float l_phiInhB = phiInhB[k];

   float l_R = R[k];

   // temporary arrays
   float tauInf, VmemInf;

   //
   // start of LIF2_update_exact_linear
   //

   // define local param variables
   //
   tau   = params->tau;
   Vexc  = params->Vexc;
   Vinh  = params->Vinh;
   VinhB = params->VinhB;
   Vrest = params->Vrest;

   VthRest  = params->VthRest;
   deltaVth = params->deltaVth;

   // add noise
   //

#ifdef USE_CLRANDOM
   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqE) {
      l_rnd = cl_random_get(l_rnd);
      l_phiExc = l_phiExc + params->noiseAmpE*cl_random_prob(l_rnd);
   }

   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqI) {
      l_rnd = cl_random_get(l_rnd);
      l_phiInh = l_phiInh + params->noiseAmpI*cl_random_prob(l_rnd);
   }

   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqIB) {
      l_rnd = cl_random_get(l_rnd);
      l_phiInhB = l_phiInhB + params->noiseAmpIB*cl_random_prob(l_rnd);
   }
#else
   if (pv_random_prob() < dt_sec*params->noiseFreqE) {
      l_phiExc = l_phiExc + params->noiseAmpE*pv_random_prob();
   }

   if (pv_random_prob() < dt_sec*params->noiseFreqI) {
      l_phiInh = l_phiInh + params->noiseAmpI*pv_random_prob();
   }

   if (pv_random_prob() < dt_sec*params->noiseFreqIB) {
      l_phiInhB = l_phiInhB + params->noiseAmpIB*pv_random_prob();
   }
#endif

   l_G_E  = l_phiExc  + l_G_E *exp_tauE;
   l_G_I  = l_phiInh  + l_G_I *exp_tauI;
   l_G_IB = l_phiInhB + l_G_IB*exp_tauIB;

   l_G_E  = (l_G_E  > GMAX) ? GMAX : l_G_E;
   l_G_I  = (l_G_I  > GMAX) ? GMAX : l_G_I;
   l_G_IB = (l_G_IB > GMAX) ? GMAX : l_G_IB;

   tauInf  = (dt/tau) * (1.0 + l_G_E + l_G_I + l_G_IB);
   VmemInf = (Vrest + l_G_E*Vexc + l_G_I*Vinh + l_G_IB*VinhB)
           / (1.0 + l_G_E + l_G_I + l_G_IB);

   l_V = VmemInf + (l_V - VmemInf)*EXP(-tauInf);

   //
   // start of LIF2_update_finish
   //

   l_Vth = VthRest + (l_Vth - VthRest)*exp_tauVth;

   //
   // start of update_f
   //

   bool fired_flag = (l_V > l_Vth);

   l_activ = fired_flag ? 1.0f             : 0.0f;
   l_V     = fired_flag ? Vrest            : l_V;
   l_Vth   = fired_flag ? l_Vth + deltaVth : l_Vth;
   l_G_IB  = fired_flag ? l_G_IB + 1.0f    : l_G_IB;

   // update average rate
   l_R = l_activ + l_R*exp_tauRate;

   //
   // These actions must be done outside of kernel
   //    1. set activity to 0 in boundary (if needed)
   //    2. update active indices
   //

   // store local variables back to global memory
   //
   rnd[k] = l_rnd;

   activity[kex] = l_activ;

   R[k] = l_R;

   V[k]   = l_V;
   Vth[k] = l_Vth;

   G_E[k]  = l_G_E;
   G_I[k]  = l_G_I;
   G_IB[k] = l_G_IB;

   phiExc[k]  = 0.0f;
   phiInh[k]  = 0.0f;
   phiInhB[k] = 0.0f;

#ifndef PV_USE_OPENCL
   } // loop over k
#endif

}

#include "LIF_params.h"
#include "cl_random.hcl"

#ifndef PV_USE_OPENCL
#  include <math.h>
#  define EXP expf
#  define CL_KERNEL
#  define CL_MEM_GLOBAL
#  define CL_MEM_LOCAL
#else  /* compiling with OpenCL */
#  define EXP exp
#  define CL_KERNEL       __kernel
#  define CL_MEM_GLOBAL   __global
#  define CL_MEM_LOCAL    __local
#  include "conversions.hcl"
#endif

#define USE_CLRANDOM
#ifndef USE_CLRANDOM
#  include "../utils/pv_random.h"
#endif

//
// update the state of a retinal layer (spiking)
//
//    assume called with 1D kernel
//
CL_KERNEL
void LIF_update_state(
    const float time,
    const float dt,

    const int nx,
    const int ny,
    const int nf,
    const int nb,

    CL_MEM_GLOBAL LIF_params * params,
    CL_MEM_GLOBAL uint4 * rnd,
    CL_MEM_GLOBAL float * V,
    CL_MEM_GLOBAL float * Vth,
    CL_MEM_GLOBAL float * G_E,
    CL_MEM_GLOBAL float * G_I,
    CL_MEM_GLOBAL float * G_IB,
    CL_MEM_GLOBAL float * phiExc,
    CL_MEM_GLOBAL float * phiInh,
    CL_MEM_GLOBAL float * phiInhB,
    CL_MEM_GLOBAL float * R,
    CL_MEM_GLOBAL float * activity)
{
   int k;

   const float exp_tauE    = EXP(-dt/params->tauE);
   const float exp_tauI    = EXP(-dt/params->tauI);
   const float exp_tauIB   = EXP(-dt/params->tauIB);
   const float exp_tauVth  = EXP(-dt/params->tauVth);

   const float dt_sec = .001 * dt;   // convert to seconds
   const float exp_tauRate = EXP(-dt/params->tauRate);

#ifndef PV_USE_OPENCL

for (k = 0; k < nx*ny*nf; k++) {
#else
   k = get_global_id(0);
#endif

   int kex = kIndexExtended(k, nx, ny, nf, nb);

   //
   // kernel (nonheader part) begins here
   //

   // local param variables
   float tau, Vrest, VthRest, Vexc, Vinh, VinhB, deltaVth;

   const float GMAX = 10.0;

   // local variables
   float l_activ;

   uint4 l_rnd = rnd[k];

   float l_V   = V[k];
   float l_Vth = Vth[k];

   float l_G_E  = G_E[k];
   float l_G_I  = G_I[k];
   float l_G_IB = G_IB[k];

   float l_phiExc  = phiExc[k];
   float l_phiInh  = phiInh[k];
   float l_phiInhB = phiInhB[k];

   float l_R = R[k];

   // temporary arrays
   float tauInf, VmemInf;

   //
   // start of LIF2_update_exact_linear
   //

   // define local param variables
   //
   tau   = params->tau;
   Vexc  = params->Vexc;
   Vinh  = params->Vinh;
   VinhB = params->VinhB;
   Vrest = params->Vrest;

   VthRest  = params->VthRest;
   deltaVth = params->deltaVth;

   // add noise
   //

#ifdef USE_CLRANDOM
   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqE) {
      l_rnd = cl_random_get(l_rnd);
      l_phiExc = l_phiExc + params->noiseAmpE*cl_random_prob(l_rnd);
   }

   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqI) {
      l_rnd = cl_random_get(l_rnd);
      l_phiInh = l_phiInh + params->noiseAmpI*cl_random_prob(l_rnd);
   }

   l_rnd = cl_random_get(l_rnd);
   if (cl_random_prob(l_rnd) < dt_sec*params->noiseFreqIB) {
      l_rnd = cl_random_get(l_rnd);
      l_phiInhB = l_phiInhB + params->noiseAmpIB*cl_random_prob(l_rnd);
   }
#else
   if (pv_random_prob() < dt_sec*params->noiseFreqE) {
      l_phiExc = l_phiExc + params->noiseAmpE*pv_random_prob();
   }

   if (pv_random_prob() < dt_sec*params->noiseFreqI) {
      l_phiInh = l_phiInh + params->noiseAmpI*pv_random_prob();
   }

   if (pv_random_prob() < dt_sec*params->noiseFreqIB) {
      l_phiInhB = l_phiInhB + params->noiseAmpIB*pv_random_prob();
   }
#endif

   l_G_E  = l_phiExc  + l_G_E *exp_tauE;
   l_G_I  = l_phiInh  + l_G_I *exp_tauI;
   l_G_IB = l_phiInhB + l_G_IB*exp_tauIB;

   l_G_E  = (l_G_E  > GMAX) ? GMAX : l_G_E;
   l_G_I  = (l_G_I  > GMAX) ? GMAX : l_G_I;
   l_G_IB = (l_G_IB > GMAX) ? GMAX : l_G_IB;

   tauInf  = (dt/tau) * (1.0 + l_G_E + l_G_I + l_G_IB);
   VmemInf = (Vrest + l_G_E*Vexc + l_G_I*Vinh + l_G_IB*VinhB)
           / (1.0 + l_G_E + l_G_I + l_G_IB);

   l_V = VmemInf + (l_V - VmemInf)*EXP(-tauInf);

   //
   // start of LIF2_update_finish
   //

   l_Vth = VthRest + (l_Vth - VthRest)*exp_tauVth;

   //
   // start of update_f
   //

   bool fired_flag = (l_V > l_Vth);

   l_activ = fired_flag ? 1.0f             : 0.0f;
   l_V     = fired_flag ? Vrest            : l_V;
   l_Vth   = fired_flag ? l_Vth + deltaVth : l_Vth;
   l_G_IB  = fired_flag ? l_G_IB + 1.0f    : l_G_IB;

   // update average rate
   l_R = l_activ + l_R*exp_tauRate;

   //
   // These actions must be done outside of kernel
   //    1. set activity to 0 in boundary (if needed)
   //    2. update active indices
   //

   // store local variables back to global memory
   //
   rnd[k] = l_rnd;

   activity[kex] = l_activ;

   R[k] = l_R;

   V[k]   = l_V;
   Vth[k] = l_Vth;

   G_E[k]  = l_G_E;
   G_I[k]  = l_G_I;
   G_IB[k] = l_G_IB;

   phiExc[k]  = 0.0f;
   phiInh[k]  = 0.0f;
   phiInhB[k] = 0.0f;

#ifndef PV_USE_OPENCL
   } // loop over k
#endif

}


Fix bug: Clear proc_list

Fix bug: Clear proc_list

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/CLBplustree/CLBplustree.git/'


WPacketBufferHandler is alomost finished


Fix some bugs for level >= 3 insertion/deletion


Adding lisp

Adding lisp

#!/usr/local/bin/clisp

(defun encrypt (password) (string password))

(write-line (encrypt "hello"))

error: pathspec 'Lisp/encrypt.cl' did not match any file(s) known to git


added median filter kernel

added median filter kernel

// median finding via wirths method
// http://www.gentoogeek.org/files/median/medians__1_d_8h.html#a3eb4543b5522a9ff6feba692cab5bc7a

// 2D

__kernel void median_2(__global ${DTYPE} * input,
						__global ${DTYPE} * output){

  int x = get_global_id(0);
  int y = get_global_id(1);

  int Nx = get_global_size(0);
  int Ny = get_global_size(1);

  ${DTYPE} a[${FSIZE_Y}*${FSIZE_X}];

  for (int m = 0; m < ${FSIZE_Y}; ++m) {
	for (int n = 0; n < ${FSIZE_X}; ++n) {

	  int x2 = x+n-(${FSIZE_X}/2);
	  int y2 = y+m-(${FSIZE_Y}/2);

	  bool inside = ((x2>=0)&&(x2<Nx)&&(y2>=0)&&(y2<Ny));

	  a[n+${FSIZE_X}*m] = inside?input[x2+y2*Nx]:${DTYPE}(${CVAL});

	}

  }

  // find median via Wirth

  int k = (${FSIZE_X}*${FSIZE_Y})/2;
  int n = (${FSIZE_X}*${FSIZE_Y});
  int i,j,l,m;

  ${DTYPE} val;

  l=0 ; m=n-1 ;
  while (l<m) {
  	val=a[k] ;
  	i=l ;
  	j=m ;
  	do {
  	  while (a[i]<val) i++ ;
  	  while (val<a[j]) j-- ;
  	  if (i<=j) {
  		${DTYPE} tmp = a[i];
  		a[i] = a[j];
  		a[j] = tmp;

  		i++ ; j-- ;
  	  }
  	} while (i<=j) ;
  	if (j<k) l=i ;
  	if (k<i) m=j ;

  }

  output[x+y*Nx] = a[k];

}

__kernel void median_3(__global ${DTYPE} * input,
						__global ${DTYPE} * output){

  int x = get_global_id(0);
  int y = get_global_id(1);
  int z = get_global_id(2);

  int Nx = get_global_size(0);
  int Ny = get_global_size(1);
  int Nz = get_global_size(2);

  ${DTYPE} a[${FSIZE_Z}*${FSIZE_Y}*${FSIZE_X}];

  for (int p = 0; p < ${FSIZE_Z}; ++p) {
	for (int m = 0; m < ${FSIZE_Y}; ++m) {
	  for (int n = 0; n < ${FSIZE_X}; ++n) {

	  int x2 = x+n-(${FSIZE_X}/2);
	  int y2 = y+m-(${FSIZE_Y}/2);
	  int z2 = z+p-(${FSIZE_Z}/2);

	  bool inside = ((x2>=0)&&(x2<Nx)&&(y2>=0)&&(y2<Ny)&&(z2>=0)&&(z2<Nz));

	  a[n+${FSIZE_X}*m+${FSIZE_X}*${FSIZE_Y}*p] = inside?input[x2+y2*Nx+z2*Nx*Ny]:${CVAL};
	  }
	}
  }

  // find median via Wirth

  int k = (${FSIZE_X}*${FSIZE_Y}*${FSIZE_Z})/2;
  int n = (${FSIZE_X}*${FSIZE_Y}*${FSIZE_Z});
  int i,j,l,m;

  ${DTYPE} val;

  l=0 ; m=n-1 ;
  while (l<m) {
  	val=a[k] ;
  	i=l ;
  	j=m ;
  	do {
  	  while (a[i]<val) i++ ;
  	  while (val<a[j]) j-- ;
  	  if (i<=j) {
  		${DTYPE} tmp = a[i];
  		a[i] = a[j];
  		a[j] = tmp;

  		i++ ; j-- ;
  	  }
  	} while (i<=j) ;
  	if (j<k) l=i ;
  	if (k<i) m=j ;
  }

  output[x+y*Nx+z*Nx*Ny] = a[k];

}

error: pathspec 'gputools/convolve/kernels/median_filter.cl' did not match any file(s) known to git


Fout in kernel nog

Fout in kernel nog

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/MichielPauwels/LCS.git/'


Create mayor.cl

Create mayor.cl

Universidad Mayor Sede Temuco. Email @mayor.cl (alumnos)

error: pathspec 'lib/domains/cl/mayor.cl' did not match any file(s) known to git


starting pyOpenCL library for particle (neutron,X-ray) scattering mostly for space-ships

int rand(int seed){
    //int const a = 16807; //ie 7**5
    //int const m = 2147483647; //ie 2**31-1
    return (long(seed* 16807))%2147483647;
    return seed;
}

static float noise3D(float x, float y, float z) {
    float ptr = 0.0f;
    return fract(sin(x*112.9898f + y*179.233f + z*237.212f) * 43758.5453f, &ptr);
}

__kernel void scatterFromPoint(
    __global float4* triangles, // triangles of scattering material; each float4 one vertex including thickness
    __global float4* materials, // material for each triangle
    __global float4* targets,   // positions and radius of spherical targets
    float*           count,     // count of particles which hit the target
    int ntris,
    int nbounce,
    float4 source,
){
    __local float4 LTRIS[32];

    const int iG = get_global_id (0);
    const int iL = get_local_id  (0);
    const int nL = get_local_size(0);

    float3 rd = randomDirection(iG);
    for (int i=0;i<nbounce;i++){

        for (int i0=0; i0<nAtoms; i0+= nL ){
            int i = i0 + iL;
            if(i>=nAtoms) break;

            LATOMS[iL] = atoms[i];
            barrier(CLK_LOCAL_MEM_FENCE);
            for (int j=0; j<nL; j++){
                fe += getCoulomb( LATOMS[j], pos );
            }
            barrier(CLK_LOCAL_MEM_FENCE);
        }
    }
}

error: pathspec 'python/pyScatter/cl/cl/Scatter.cl' did not match any file(s) known to git


clbpt_leafmirror


OpenCL implementation of RANLUX PRNG

OpenCL implementation of RANLUX PRNG

/******************************************************************************
 * @file     prngcl_ranlux.cl
 * @author   Vadim Demchik <vadimdi@yahoo.com>
 * @version  1.1
 *
 * @brief    [PRNGCL library]
 *           contains OpenCL implementation of RANLUX pseudo-random number generator
 *
 *
 * @section  CREDITS
 *
 *   Martin Luscher,
 *   "A portable high-quality random number generator for lattice field theory simulations",
 *   Computer Physics Communications, 79 (1994), 100--110.
 *
 *   F. James,
 *   "RANLUX: A Fortran implementation of the high-quality pseudorandom number generator of Luscher",
 *   Computer Physics Communications, 79 (1994), 111--114.
 *
 *
 * @section  LICENSE
 *
 * Copyright (c) 2013, Vadim Demchik
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 *    Redistributions of source code must retain the above copyright notice,
 *      this list of conditions and the following disclaimer.
 *
 *    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 HOLDER 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.
 *
 *****************************************************************************/

#ifndef PRNGCL_RANLUX_CL
#define PRNGCL_RANLUX_CL

#include "prngcl_common.cl"

#define RL_min    (1.0/16777216.0)
#define RL_max    (16777215.0/16777216.0)
#define RL_k      (5.9604644775390625E-8) // 1/2^24

#define RL_left   (RL_min+RL_k*RL_max)
#define RL_right  (RL_max+RL_k*RL_min)

#define RL_zero     0.0f
#define RL_icons    2147483563
#define RL_itwo24   16777216 // 1<<24
#define RL_twom24   0.000000059604644775390625f
#define RL_twom12   0.000244140625f
#define RL_twom24sq RL_twom24*RL_twom24

#ifndef RL_skip
#define RL_skip     223
#endif

#define RL_skip_24 (RL_skip / 24)
#if RL_skip == 97
#define RL_RANLUX2
#define RL_skip_4   0
#define RL_skip_1   0
#endif
#if RL_skip == 223
#define RL_RANLUX3
#define RL_skip_4   0
#define RL_skip_1   0
#endif
#if RL_skip == 389
#define RL_RANLUX4
#define RL_skip_4   0
#define RL_skip_1   0
#endif
#ifndef RL_skip_4
#define RL_skip_4  ((RL_skip - RL_skip_24 * 24) / 4)
#endif
#ifndef RL_skip_1
#define RL_skip_1  (RL_skip % 4)
#endif

//________________________________________________________________________________________________________ RANLUX PRNG
__attribute__((always_inline)) int4
rlseedint(int RL_jseed)
{
	int4 RL_output_int;
		int k = RL_jseed / 53668;
		RL_jseed = 40014 * (RL_jseed - k * 53668) - k * 12211;
		if (RL_jseed < 0) {RL_jseed = RL_jseed + RL_icons;}
		RL_output_int.x = RL_jseed;

		k = RL_jseed / 53668;
		RL_jseed = 40014 * (RL_jseed - k * 53668) - k * 12211;
		if (RL_jseed < 0) {RL_jseed = RL_jseed + RL_icons;}
		RL_output_int.y = RL_jseed;

		k = RL_jseed / 53668;
		RL_jseed = 40014 * (RL_jseed - k * 53668) - k * 12211;
		if (RL_jseed < 0) {RL_jseed = RL_jseed + RL_icons;}
		RL_output_int.z = RL_jseed;

		k = RL_jseed / 53668;
		RL_jseed = 40014 * (RL_jseed - k * 53668) - k * 12211;
		if (RL_jseed < 0) {RL_jseed = RL_jseed + RL_icons;}
		RL_output_int.w = RL_jseed;

    return RL_output_int;
}

__attribute__((always_inline)) float4
rlseedint2(int4 RL_temp)
{
	float4 RL_output_int;
	float4 RL_tmp = (float4) (RL_twom24,RL_twom24,RL_twom24,RL_twom24);
		RL_output_int.x = ((float) (RL_temp.x % RL_itwo24));
		RL_output_int.y = ((float) (RL_temp.y % RL_itwo24));
		RL_output_int.z = ((float) (RL_temp.z % RL_itwo24));
		RL_output_int.w = ((float) (RL_temp.w % RL_itwo24));
	RL_output_int = RL_output_int * RL_tmp;
    return RL_output_int;
}

__kernel void
ranlux_init(const __global uint * seeds, __global float4 * seedtable)
{
    int RL_jseed = (int) seeds[GID];
	int4		RL_temp1 = rlseedint(RL_jseed);
	seedtable[GID + 0 * GID_SIZE] = rlseedint2(RL_temp1);
				RL_temp1 = rlseedint(RL_temp1.w);
	seedtable[GID + 1 * GID_SIZE] = rlseedint2(RL_temp1);
				RL_temp1 = rlseedint(RL_temp1.w);
	seedtable[GID + 2 * GID_SIZE] = rlseedint2(RL_temp1);
				RL_temp1 = rlseedint(RL_temp1.w);
	seedtable[GID + 3 * GID_SIZE] = rlseedint2(RL_temp1);
				RL_temp1 = rlseedint(RL_temp1.w);
	seedtable[GID + 4 * GID_SIZE] = rlseedint2(RL_temp1);
				RL_temp1 = rlseedint(RL_temp1.w);
	float4		RL_temp2 = rlseedint2(RL_temp1);
	seedtable[GID + 5 * GID_SIZE] = RL_temp2;
	float4		RL_carin = (float4) (23.0f, 9.0f, 6.0f, 0.0f);
	if (RL_temp2.w == 0) {RL_carin.w = RL_twom24;}
	seedtable[GID + 6 * GID_SIZE] = RL_carin; // RL_i24, RL_j24, RL_in24, RL_carry
}

__attribute__((always_inline)) float4
rlproducefloat4(float4 * RL_seeds_i24, const float4 RL_seeds_j24, const float RL_seeds_j24P, float * RL_carry)
{
	float RL_c = *RL_carry;
	float4 RL_output_int = RL_seeds_j24 - (*RL_seeds_i24).wzyx;
	RL_output_int.x = RL_output_int.x - RL_c;
		if (RL_output_int.x < 0.0f) { RL_output_int.x = RL_output_int.x + 1.0f; RL_c = RL_twom24; } else { RL_c = 0.0f; }
	RL_output_int.y = RL_output_int.y - RL_c;
		if (RL_output_int.y < 0.0f) { RL_output_int.y = RL_output_int.y + 1.0f; RL_c = RL_twom24; } else { RL_c = 0.0f; }
	RL_output_int.z = RL_output_int.z - RL_c;
		if (RL_output_int.z < 0.0f) { RL_output_int.z = RL_output_int.z + 1.0f; RL_c = RL_twom24; } else { RL_c = 0.0f; }
	RL_output_int.w = RL_output_int.w - RL_c;
		if (RL_output_int.w < 0.0f) { RL_output_int.w = RL_output_int.w + 1.0f; RL_c = RL_twom24; } else { RL_c = 0.0f; }

	*RL_seeds_i24 = RL_output_int.wzyx;

    float4 RL_temporary = RL_seeds_j24.yzwx;
    RL_temporary.w = RL_seeds_j24P;

	float4 RL_output_int2 = select(RL_output_int, (RL_output_int + RL_twom24 * RL_temporary), RL_output_int < (float4) RL_twom12);
			RL_output_int = select(RL_output_int2, RL_twom24sq, RL_output_int2 == (float4) 0.0f);

	*RL_carry = RL_c;
	return RL_output_int;
}

__attribute__((always_inline)) void
rlproduceupd4(float4 * RL_seeds_i24, const float4 RL_seeds_j24, float * RL_carry)
{
	float RL_c = *RL_carry;
	float4 RL_output_int = RL_seeds_j24 - (*RL_seeds_i24).wzyx;
	RL_output_int.x = RL_output_int.x - RL_c;
		if (RL_output_int.x < 0.0f) { RL_output_int.x = RL_output_int.x + 1.0f; RL_c = RL_twom24; } else { RL_c = 0.0f; }
	RL_output_int.y = RL_output_int.y - RL_c;
		if (RL_output_int.y < 0.0f) { RL_output_int.y = RL_output_int.y + 1.0f; RL_c = RL_twom24; } else { RL_c = 0.0f; }
	RL_output_int.z = RL_output_int.z - RL_c;
		if (RL_output_int.z < 0.0f) { RL_output_int.z = RL_output_int.z + 1.0f; RL_c = RL_twom24; } else { RL_c = 0.0f; }
	RL_output_int.w = RL_output_int.w - RL_c;
		if (RL_output_int.w < 0.0f) { RL_output_int.w = RL_output_int.w + 1.0f; RL_c = RL_twom24; } else { RL_c = 0.0f; }

	*RL_seeds_i24 = RL_output_int.wzyx;
	*RL_carry = RL_c;
}

__attribute__((always_inline)) float4
rl_step(float4* RL_seed0,float4* RL_seed1,float4* RL_seed2,float4* RL_seed3,
        float4* RL_seed4,float4* RL_seed5,float4* RL_carin)
{
	float4 RL_seeds_j24, uni, RL_seed_temp, RL_seed_temp2;
 	float RL_carry = (*RL_carin).w;
		if ((*RL_carin).z >= 6.0f) {
			for (int t=0; t<RL_skip_24; t++) {
				RL_seeds_j24.xy = (*RL_seed2).yx;
				RL_seeds_j24.zw = (*RL_seed1).wz;
					rlproduceupd4(RL_seed5,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed1).yx;
				RL_seeds_j24.zw = (*RL_seed0).wz;
					rlproduceupd4(RL_seed4,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed0).yx;
				RL_seeds_j24.zw = (*RL_seed5).wz;
					rlproduceupd4(RL_seed3,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed5).yx;
				RL_seeds_j24.zw = (*RL_seed4).wz;
					rlproduceupd4(RL_seed2,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed4).yx;
				RL_seeds_j24.zw = (*RL_seed3).wz;
					rlproduceupd4(RL_seed1,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed3).yx;
				RL_seeds_j24.zw = (*RL_seed2).wz;
					rlproduceupd4(RL_seed0,RL_seeds_j24,&RL_carry);
			}
#if RL_skip_4 == 1
				RL_seeds_j24.xy = (*RL_seed2).yx;
				RL_seeds_j24.zw = (*RL_seed1).wz;
					rlproduceupd4(RL_seed5,RL_seeds_j24,&RL_carry);
                RL_seed_temp = (*RL_seed5);    // 5->4, 4->3, 3->2, 2->1, 1->0, 0->5
                (*RL_seed5) = (*RL_seed4);
                (*RL_seed4) = (*RL_seed3);
                (*RL_seed3) = (*RL_seed2);
                (*RL_seed2) = (*RL_seed1);
                (*RL_seed1) = (*RL_seed0);
                (*RL_seed0) = RL_seed_temp;
#elif RL_skip_4 == 2
				RL_seeds_j24.xy = (*RL_seed2).yx;
				RL_seeds_j24.zw = (*RL_seed1).wz;
					rlproduceupd4(RL_seed5,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed1).yx;
				RL_seeds_j24.zw = (*RL_seed0).wz;
					rlproduceupd4(RL_seed4,RL_seeds_j24,&RL_carry);
                RL_seed_temp = (*RL_seed5);    // 5->3, 4->2, 3->1, 2->0, 1->5, 0->4
                (*RL_seed5) = (*RL_seed3);
                (*RL_seed3) = (*RL_seed1);
                (*RL_seed1) = RL_seed_temp;
                RL_seed_temp = (*RL_seed2);
                (*RL_seed2) = (*RL_seed0);
                (*RL_seed0) = (*RL_seed4);
                (*RL_seed4) = RL_seed_temp;
#elif RL_skip_4 == 3
				RL_seeds_j24.xy = (*RL_seed2).yx;
				RL_seeds_j24.zw = (*RL_seed1).wz;
					rlproduceupd4(RL_seed5,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed1).yx;
				RL_seeds_j24.zw = (*RL_seed0).wz;
					rlproduceupd4(RL_seed4,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed0).yx;
				RL_seeds_j24.zw = (*RL_seed5).wz;
					rlproduceupd4(RL_seed3,RL_seeds_j24,&RL_carry);
                RL_seed_temp = (*RL_seed5);    // 5->2, 4->1, 3->0, 2->5, 1->4, 0->3
                (*RL_seed5) = (*RL_seed2);
                (*RL_seed2) = RL_seed_temp;
                RL_seed_temp = (*RL_seed4);
                (*RL_seed4) = (*RL_seed1);
                (*RL_seed1) = RL_seed_temp;
                RL_seed_temp = (*RL_seed3);
                (*RL_seed3) = (*RL_seed0);
                (*RL_seed0) = RL_seed_temp;
#elif RL_skip_4 == 4
				RL_seeds_j24.xy = (*RL_seed2).yx;
				RL_seeds_j24.zw = (*RL_seed1).wz;
					rlproduceupd4(RL_seed5,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed1).yx;
				RL_seeds_j24.zw = (*RL_seed0).wz;
					rlproduceupd4(RL_seed4,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed0).yx;
				RL_seeds_j24.zw = (*RL_seed5).wz;
					rlproduceupd4(RL_seed3,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed5).yx;
				RL_seeds_j24.zw = (*RL_seed4).wz;
					rlproduceupd4(RL_seed2,RL_seeds_j24,&RL_carry);
                RL_seed_temp = (*RL_seed5);    // 5->1, 4->0, 3->5, 2->4, 1->3, 0->2
                (*RL_seed5) = (*RL_seed1);
                (*RL_seed1) = (*RL_seed3);
                (*RL_seed3) = RL_seed_temp;
                RL_seed_temp = (*RL_seed4);
                (*RL_seed4) = (*RL_seed0);
                (*RL_seed0) = (*RL_seed2);
                (*RL_seed2) = RL_seed_temp;
#elif RL_skip_4 == 5
				RL_seeds_j24.xy = (*RL_seed2).yx;
				RL_seeds_j24.zw = (*RL_seed1).wz;
					rlproduceupd4(RL_seed5,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed1).yx;
				RL_seeds_j24.zw = (*RL_seed0).wz;
					rlproduceupd4(RL_seed4,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed0).yx;
				RL_seeds_j24.zw = (*RL_seed5).wz;
					rlproduceupd4(RL_seed3,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed5).yx;
				RL_seeds_j24.zw = (*RL_seed4).wz;
					rlproduceupd4(RL_seed2,RL_seeds_j24,&RL_carry);
				RL_seeds_j24.xy = (*RL_seed4).yx;
				RL_seeds_j24.zw = (*RL_seed3).wz;
					rlproduceupd4(RL_seed1,RL_seeds_j24,&RL_carry);
                RL_seed_temp = (*RL_seed5);    // 5->0, 4->5, 3->4, 2->3, 1->2, 0->1
                (*RL_seed5) = (*RL_seed0);
                (*RL_seed0) = (*RL_seed1);
                (*RL_seed1) = (*RL_seed2);
                (*RL_seed2) = (*RL_seed3);
                (*RL_seed3) = (*RL_seed4);
                (*RL_seed4) = RL_seed_temp;
#endif
#if RL_skip_1 == 1
                float RL_output_int = (*RL_seed2).y - (*RL_seed5).w;
                RL_output_int = RL_output_int - RL_carry;
                    if (RL_output_int < 0.0f) { RL_output_int = RL_output_int + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }
                (*RL_seed5).w = RL_output_int;

                RL_seed_temp = (*RL_seed5);
                (*RL_seed5).yzw = (*RL_seed5).xyz;
                (*RL_seed5).x = (*RL_seed4).w;
                (*RL_seed4).yzw = (*RL_seed4).xyz;
                (*RL_seed4).x = (*RL_seed3).w;
                (*RL_seed3).yzw = (*RL_seed3).xyz;
                (*RL_seed3).x = (*RL_seed2).w;
                (*RL_seed2).yzw = (*RL_seed2).xyz;
                (*RL_seed2).x = (*RL_seed1).w;
                (*RL_seed1).yzw = (*RL_seed1).xyz;
                (*RL_seed1).x = (*RL_seed0).w;
                (*RL_seed0).yzw = (*RL_seed0).xyz;
                (*RL_seed0).x = RL_seed_temp.w;
#elif RL_skip_1 == 2
                float4 RL_output_int;
                RL_output_int.xy = (*RL_seed2).yx - (*RL_seed5).wz;
                RL_output_int.x = RL_output_int.x - RL_carry;
                    if (RL_output_int.x < 0.0f) { RL_output_int.x = RL_output_int.x + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }
                RL_output_int.y = RL_output_int.y - RL_carry;
                    if (RL_output_int.y < 0.0f) { RL_output_int.y = RL_output_int.y + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }

                (*RL_seed5).zw = RL_output_int.yx;

                RL_seed_temp = (*RL_seed5);
                (*RL_seed5).zw = (*RL_seed5).xy;
                (*RL_seed5).xy = (*RL_seed4).zw;
                (*RL_seed4).zw = (*RL_seed4).xy;
                (*RL_seed4).xy = (*RL_seed3).zw;
                (*RL_seed3).zw = (*RL_seed3).xy;
                (*RL_seed3).xy = (*RL_seed2).zw;
                (*RL_seed2).zw = (*RL_seed2).xy;
                (*RL_seed2).xy = (*RL_seed1).zw;
                (*RL_seed1).zw = (*RL_seed1).xy;
                (*RL_seed1).xy = (*RL_seed0).zw;
                (*RL_seed0).zw = (*RL_seed0).xy;
                (*RL_seed0).xy = RL_seed_temp.zw;
#elif RL_skip_1 == 3
                float4 RL_output_int;
                RL_output_int.xy = (*RL_seed2).yx - (*RL_seed5).wz;
                RL_output_int.z = (*RL_seed1).w - (*RL_seed5).y;
                RL_output_int.x = RL_output_int.x - RL_carry;
                    if (RL_output_int.x < 0.0f) { RL_output_int.x = RL_output_int.x + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }
                RL_output_int.y = RL_output_int.y - RL_carry;
                    if (RL_output_int.y < 0.0f) { RL_output_int.y = RL_output_int.y + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }
                RL_output_int.z = RL_output_int.z - RL_carry;
                    if (RL_output_int.z < 0.0f) { RL_output_int.z = RL_output_int.z + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }

                (*RL_seed5).yzw = RL_output_int.zyx;

                RL_seed_temp = (*RL_seed5);
                (*RL_seed5).w = (*RL_seed5).x;
                (*RL_seed5).xyz = (*RL_seed4).yzw;
                (*RL_seed4).w = (*RL_seed4).x;
                (*RL_seed4).xyz = (*RL_seed3).yzw;
                (*RL_seed3).w = (*RL_seed3).x;
                (*RL_seed3).xyz = (*RL_seed2).yzw;
                (*RL_seed2).w = (*RL_seed2).x;
                (*RL_seed2).xyz = (*RL_seed1).yzw;
                (*RL_seed1).w = (*RL_seed1).x;
                (*RL_seed1).xyz = (*RL_seed0).yzw;
                (*RL_seed0).w = (*RL_seed0).x;
                (*RL_seed0).xyz = RL_seed_temp.yzw;
#endif
#ifdef RL_RANLUX2
                float RL_output_int = (*RL_seed2).y - (*RL_seed5).w;
                RL_output_int = RL_output_int - RL_carry;
                    if (RL_output_int < 0.0f) { RL_output_int = RL_output_int + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }
                (*RL_seed5).w = RL_output_int;

                RL_seed_temp = (*RL_seed5);
                (*RL_seed5).yzw = (*RL_seed5).xyz;
                (*RL_seed5).x = (*RL_seed4).w;
                (*RL_seed4).yzw = (*RL_seed4).xyz;
                (*RL_seed4).x = (*RL_seed3).w;
                (*RL_seed3).yzw = (*RL_seed3).xyz;
                (*RL_seed3).x = (*RL_seed2).w;
                (*RL_seed2).yzw = (*RL_seed2).xyz;
                (*RL_seed2).x = (*RL_seed1).w;
                (*RL_seed1).yzw = (*RL_seed1).xyz;
                (*RL_seed1).x = (*RL_seed0).w;
                (*RL_seed0).yzw = (*RL_seed0).xyz;
                (*RL_seed0).x = RL_seed_temp.w;
#endif
#ifdef RL_RANLUX3
                RL_seeds_j24.xy = (*RL_seed2).yx;
                RL_seeds_j24.zw = (*RL_seed1).wz;
                    rlproduceupd4(RL_seed5,RL_seeds_j24,&RL_carry);
                float4 RL_output_int;
                RL_output_int.xy = (*RL_seed1).yx - (*RL_seed4).wz;
                RL_output_int.z = (*RL_seed0).w - (*RL_seed4).y;
                RL_output_int.x = RL_output_int.x - RL_carry;
                    if (RL_output_int.x < 0.0f) { RL_output_int.x = RL_output_int.x + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }
                RL_output_int.y = RL_output_int.y - RL_carry;
                    if (RL_output_int.y < 0.0f) { RL_output_int.y = RL_output_int.y + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }
                RL_output_int.z = RL_output_int.z - RL_carry;
                    if (RL_output_int.z < 0.0f) { RL_output_int.z = RL_output_int.z + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }

                RL_seed_temp.xyz  = RL_output_int.zyx;
                RL_seed_temp.w    = (*RL_seed5).x;
                RL_seed_temp2.xyz = (*RL_seed5).yzw;
                RL_seed_temp2.w   = (*RL_seed0).x;

                (*RL_seed5).w   = (*RL_seed4).x;
                (*RL_seed5).xyz = (*RL_seed3).yzw;
                (*RL_seed4).w   = (*RL_seed3).x;
                (*RL_seed4).xyz = (*RL_seed2).yzw;
                (*RL_seed3).w   = (*RL_seed2).x;
                (*RL_seed3).xyz = (*RL_seed1).yzw;
                (*RL_seed2).w   = (*RL_seed1).x;
                (*RL_seed2).xyz = (*RL_seed0).yzw;
                (*RL_seed1)  = RL_seed_temp2;
                (*RL_seed0)  = RL_seed_temp;
#endif
#ifdef RL_RANLUX4
                RL_seeds_j24.xy = (*RL_seed2).yx;
                RL_seeds_j24.zw = (*RL_seed1).wz;
                    rlproduceupd4(RL_seed5,RL_seeds_j24,&RL_carry);
                float RL_output_int = (*RL_seed1).y - (*RL_seed4).w;
                RL_output_int = RL_output_int - RL_carry;
                    if (RL_output_int < 0.0f) { RL_output_int = RL_output_int + 1.0f; RL_carry = RL_twom24; } else { RL_carry = 0.0f; }

                RL_seed_temp  = (*RL_seed5);
                RL_seed_temp2.x = RL_output_int;

                (*RL_seed5).yzw = (*RL_seed4).xyz;
                (*RL_seed5).x   = (*RL_seed3).w;
                (*RL_seed4).yzw = (*RL_seed3).xyz;
                (*RL_seed4).x   = (*RL_seed2).w;
                (*RL_seed3).yzw = (*RL_seed2).xyz;
                (*RL_seed3).x   = (*RL_seed1).w;
                (*RL_seed2).yzw = (*RL_seed1).xyz;
                (*RL_seed2).x   = (*RL_seed0).w;
                (*RL_seed1).yzw = (*RL_seed0).xyz;
                (*RL_seed1).x   = RL_seed_temp.w;
                (*RL_seed0).yzw = RL_seed_temp.xyz;
                (*RL_seed0).x   = RL_seed_temp2.x;
#endif
            (*RL_carin).z = 0.0f;
		}
        if ((*RL_carin).z < 1.0f) {
			RL_seeds_j24.xy = (*RL_seed2).yx;
			RL_seeds_j24.zw = (*RL_seed1).wz;
				uni = rlproducefloat4(RL_seed5,RL_seeds_j24,(*RL_seed1).y,&RL_carry);
			(*RL_carin).z = 1.0f;
		} else if ((*RL_carin).z == 1.0f) {
			RL_seeds_j24.xy = (*RL_seed1).yx;
			RL_seeds_j24.zw = (*RL_seed0).wz;
				uni = rlproducefloat4(RL_seed4,RL_seeds_j24,(*RL_seed0).y,&RL_carry);
			(*RL_carin).z = 2.0f;
		} else if ((*RL_carin).z == 2.0f) {
			RL_seeds_j24.xy = (*RL_seed0).yx;
			RL_seeds_j24.zw = (*RL_seed5).wz;
				uni = rlproducefloat4(RL_seed3,RL_seeds_j24,(*RL_seed5).y,&RL_carry);
			(*RL_carin).z = 3.0f;
		} else if ((*RL_carin).z == 3.0f) {
			RL_seeds_j24.xy = (*RL_seed5).yx;
			RL_seeds_j24.zw = (*RL_seed4).wz;
				uni = rlproducefloat4(RL_seed2,RL_seeds_j24,(*RL_seed4).y,&RL_carry);
			(*RL_carin).z = 4.0f;
		} else if ((*RL_carin).z == 4.0f) {
			RL_seeds_j24.xy = (*RL_seed4).yx;
			RL_seeds_j24.zw = (*RL_seed3).wz;
				uni = rlproducefloat4(RL_seed1,RL_seeds_j24,(*RL_seed3).y,&RL_carry);
			(*RL_carin).z = 5.0f;
		} else if ((*RL_carin).z == 5.0f) {
			RL_seeds_j24.xy = (*RL_seed3).yx;
			RL_seeds_j24.zw = (*RL_seed2).wz;
				uni = rlproducefloat4(RL_seed0,RL_seeds_j24,(*RL_seed2).y,&RL_carry);
			(*RL_carin).z = 6.0f;
		}
	(*RL_carin).w = RL_carry;
    return uni;
}

#ifdef PRECISION_DOUBLE  // if double precision is defined
__attribute__((always_inline)) hgpu_double4
rl_step_double(float4* RL_seed0,float4* RL_seed1,float4* RL_seed2,float4* RL_seed3,
               float4* RL_seed4,float4* RL_seed5,float4* RL_carin)
{
    hgpu_double4 result;
    hgpu_double2 rnd_double;
    float4 rnd1,rnd2;
    bool flag = true;
    while (flag) {
        rnd1 = rl_step(RL_seed0,RL_seed1,RL_seed2,RL_seed3,RL_seed4,RL_seed5,RL_carin);
        rnd_double = hgpu_float4_to_double2(rnd1,RL_min,RL_max,RL_k);
        if ((rnd_double.x>=RL_left) && (rnd_double.x<RL_right) &&
            (rnd_double.y>=RL_left) && (rnd_double.y<RL_right)) flag = false;
    }
    result.x = rnd_double.x;
    result.y = rnd_double.y;

    flag = true;
    while (flag) {
        rnd2 = rl_step(RL_seed0,RL_seed1,RL_seed2,RL_seed3,RL_seed4,RL_seed5,RL_carin);
        rnd_double = hgpu_float4_to_double2(rnd2,RL_min,RL_max,RL_k);
        if ((rnd_double.x>=RL_left) && (rnd_double.x<RL_right) &&
            (rnd_double.y>=RL_left) && (rnd_double.y<RL_right)) flag = false;
    }
    result.z = rnd_double.x;
    result.w = rnd_double.y;

    return result;
}
#endif

__kernel void
ranlux(__global float4 * seedtable,__global hgpu_float4 * prns, const uint samples)
{
    uint giddst = GID;
		float4 RL_seed0 = seedtable[GID + 0 * GID_SIZE];
		float4 RL_seed1 = seedtable[GID + 1 * GID_SIZE];
		float4 RL_seed2 = seedtable[GID + 2 * GID_SIZE];
		float4 RL_seed3 = seedtable[GID + 3 * GID_SIZE];
		float4 RL_seed4 = seedtable[GID + 4 * GID_SIZE];
		float4 RL_seed5 = seedtable[GID + 5 * GID_SIZE];
		float4 RL_carin = seedtable[GID + 6 * GID_SIZE];    // RL_i24, RL_j24, RL_in24, RL_carry

	for (int i=0; i<samples; i++) {
#ifdef PRECISION_DOUBLE // if double precision is defined
        hgpu_double4 result = rl_step_double(&RL_seed0,&RL_seed1,&RL_seed2,&RL_seed3,&RL_seed4,&RL_seed5,&RL_carin);
        prns[giddst] = result;
#else
        float4 uni = rl_step(&RL_seed0,&RL_seed1,&RL_seed2,&RL_seed3,&RL_seed4,&RL_seed5,&RL_carin);
		prns[giddst] = uni;
#endif
		giddst += GID_SIZE;
	}

	seedtable[GID + 0 * GID_SIZE] = RL_seed0;
	seedtable[GID + 1 * GID_SIZE] = RL_seed1;
	seedtable[GID + 2 * GID_SIZE] = RL_seed2;
	seedtable[GID + 3 * GID_SIZE] = RL_seed3;
	seedtable[GID + 4 * GID_SIZE] = RL_seed4;
	seedtable[GID + 5 * GID_SIZE] = RL_seed5;
	seedtable[GID + 6 * GID_SIZE] = RL_carin;
}

#endif

error: pathspec 'randomcl/prngcl_ranlux.cl' did not match any file(s) known to git


Initial version.

Initial version.

git-svn-id: 602a26e73ae9f2a14e2bb95676f2e137fcc39919@3036 7c0444ca-5550-0410-9008-faecdbe78eb5

//#include <OpenCL/opencl.h>

#include <stdio.h>

//
// update the state of an LIF layer
//

//
//// 4. change if () guard so that it uses kx and ky

__kernel void update_state (
    __global float * V,
    __global float * G_E,
    __global float * G_I,
    __global float * G_IB,
    __global float * phi,
    __global float * activity,
    const uint nx,
    const uint ny,
    const uint nf,
    const uint nPad)
{
   float tauInf, VmemInf;
   float expExcite, expInhib, expInhibB;
   float dt, tau;
   float Vrest, Vexc, Vinh, VinhB;

   //ADD DT, HARD CODE IN VARIABLES, FIX stuff, implement and check by hand, and check boundaries

   const uint kx = get_global_id(0);
   const uint ky = get_global_id(1);
   const uint k  = kx + nx*ky;

   float one = 1.1f;

   VmemInf = 20.0f;
   //tauInf = 3.141f;

   //Hard Coded Variables
   tau = 20.0;
   Vrest = -70.0;
   Vexc = 0.0;
   Vinh = -75.0;
   VinhB = -90.0;

   dt = 1.0f;
   tau = 1.0f;
   Vrest = 2.0f;
   Vexc = 2.0f;
   Vinh = 2.0f;
   VinhB = 2.0f;

   expExcite = 1.0f;
   expInhib = 2.0f;
   expInhibB = 2.0f;

   if (kx < nx && ky < ny) {
      //printf ("%f %f %f\n", kx, ky, k);
      G_E[k]  = 1 + G_E[k] ;phiExc[k] + G_E[k]  * expExcite;
      G_I[k]  = phiInh[k]; //phiInh[k] + G_I[k]  * expInhib;
      G_IB[k] = phiInhB[k] + G_IB[k] * expInhibB;
      tauInf  = (dt / tau) * (1 + G_E[k] + G_I[k] + G_IB[k]);
      VmemInf = ( Vrest + G_E[k] * Vexc + G_I[k] * Vinh + G_IB[k] * VinhB )
                / (1.0 + G_E[k] + G_I[k] + G_IB[k]);
      V[k] = VmemInf + (V[k] - VmemInf) * exp(-tauInf);

      //printf("G_I[%d]=%f\n", k, G_I[k]);
      //printf("kx=%f\n", kx);
      //printf("nx=%f\n", nx);

//      V[k] = 8.0f;
   }
}

error: pathspec 'src/layers/kernels/LIF_update_state.cl' did not match any file(s) known to git


Fix merge/borrow/split

Fix merge/borrow/split


Initial version.

Initial version.

git-svn-id: 602a26e73ae9f2a14e2bb95676f2e137fcc39919@2827 7c0444ca-5550-0410-9008-faecdbe78eb5

//#include <OpenCL/opencl.h>

#ifdef DEBUG_PRINT
#  include <stdio.h>
#endif

#define pvdata_t float
#define PHI_EXC 0       // which phi buffer to use
#define PHI_INH 1       // which phi buffer to use
#define PHI_INHB 2
#define PI              3.1415926535897932

// refactory period for neurons (retina for now)
#define ABS_REFACTORY_PERIOD 3
#define REFACTORY_PERIOD     5

#define PV_RANDOM_MAX       0x7fffffff
#define PV_INV_RANDOM_MAX   (1.0 / (double) PV_RANDOM_MAX)

// problems including stdlib.h
double random();

static inline double pv_random_prob()
{
   return (double) random() * PV_INV_RANDOM_MAX;
}

static inline int featureIndex(int k, int nx, int ny, int nf)
{
   return k % nf;
}

static inline int kxPos(int k, int nx, int ny, int nf)
{
   return (k/nf) % nx;
}

static inline int kyPos(int k, int nx, int ny, int nf)
{
   return k / (nx*nf);
}

static inline int kIndex(int kx, int ky, int kf, int nx, int ny, int nf)
{
   return kf + (kx + (ky * nx)) * nf;
}

static inline int kIndexRestricted(int k_ex, int nx, int ny, int nf, int nb)
{
   int kx, ky, kf;

   const int nx_ex = nx + 2*nb;
   const int ny_ex = ny + 2*nb;

   kx = kxPos(k_ex, nx_ex, ny_ex, nf) - nb;
   if (kx < 0 || kx >= nx) return -1;

   ky = kyPos(k_ex, nx_ex, ny_ex, nf) - nb;
   if (ky < 0 || ky >= ny) return -1;

   kf = featureIndex(k_ex, nx_ex, ny_ex, nf);
   return kIndex(kx, ky, kf, nx, ny, nf);
}

inline uint k_index(uint nx, uint ny)
{
   return (get_global_id(0) + nx * get_global_id(1));
}

/**
 * Returns the extended index
 *  - assumes kernel called with extended thread space
 */
inline uint k_ex_index(uint nx, uint ny, uint nPad)
{
   return (get_global_id(0) + (nx+2*nPad) * get_global_id(1));
}

inline uint kx_index()
{
   return get_global_id(0);
}

inline uint ky_index()
{
   return get_global_id(1);
}

#undef SIMPLE_SPIKE
#ifdef SIMPLE_SPIKE
int spike(float time, float dt, float prev, float probBase, float probStim, float * probSpike)
{
   return 1;
}
#else
int spike(float time, float dt, float prev, float probBase, float probStim, float * probSpike)
{
//   fileread_params * params = (fileread_params *) clayer->params;
   float burstStatus = 1;
   float sinAmp = 1.0;

   // input parameters
   // TODO - how to get these into kernel
   //
   const float beginStim = 0.0f;
   const float endStim   = 9000000.0f;
   const float burstFreq = 40.0f;
   const float burstDuration = 7.5f;

   // see if neuron is in a refactory period
   //
   if ((time - prev) < ABS_REFACTORY_PERIOD) {
      return 0;
   }
   else {
      float delta = time - prev - ABS_REFACTORY_PERIOD;
      float refact = 1.0f - expf(-delta/REFACTORY_PERIOD);
      refact = (refact < 0) ? 0 : refact;
      probBase *= refact;
      probStim *= refact;
   }

   if (burstDuration <= 0 || burstFreq == 0) {
      sinAmp = cos( 2 * PI * time * burstFreq / 1000. );
   }
   else {
      burstStatus = fmodf(time, 1000. / burstFreq);
      burstStatus = burstStatus <= burstDuration;
   }

   burstStatus *= (int) ( (time >= beginStim) && (time < endStim) );
   *probSpike = probBase;

   if ((int)burstStatus) {
      *probSpike += probStim * sinAmp;  // negative prob is OK
    }
   return ( pv_random_prob() < *probSpike );
}
#endif

//
// update the state of a retinal layer (spiking)
//
// This will be called with grid layout in extended space (nx*2*nPad)*(ny*2*nPad)
//
__kernel void update_state (
    const float time,
    const float dt,
    const float probStim,
    const float probBase,

    const uint nx,
    const uint ny,
    const uint nf,
    const uint nPad,

    __global float * phi,
    __global float * activity,
    __global float * prevActivity)
{
   //
   // Make sure threads are within bounds.
   //
   if (kx_index() >= nx+2*nPad || ky_index() >= ny+2*nPad) {
      return;
   }

   float probSpike;
   const uint numNeurons = nx * ny * nf;

   __global pvdata_t * phiExc = & phi[PHI_EXC * numNeurons];
   __global pvdata_t * phiInh = & phi[PHI_INH * numNeurons];

   const uint kex = k_ex_index(nx, ny, nPad);
   const int k = kIndexRestricted(kex, nx, ny, nf, nPad);

   const float prevTime = prevActivity[kex];

   if (k >= 0) {
      //
      // interior region
      //
      const float l_V = phiExc[k] - phiInh[k];

      phiExc[k] = 0.0f;
      phiInh[k] = 0.0f;

      const float l_activity = spike(time, dt, prevTime, probBase, probStim*l_V, &probSpike);
      activity[kex] = l_activity;
      prevActivity[kex] = (l_activity > 0.0f) ? time : prevTime;

#ifdef DEBUG_PRINT
      if (k < 6) {
         printf("k==%d kex==%d kx==%d ky==%d l_V==%f\n", k, kex, kx_index(), ky_index(), l_V);
      }
#endif
   }
   else {
      //
      // border region (background activity only)
      //
      const float l_activity = spike(time, dt, prevTime, probBase, 0.0f, &probSpike);
      activity[kex] = l_activity;
      prevActivity[kex] = (l_activity > 0.0f) ? time : prevTime;
   }
}

error: pathspec 'src/layers/retina_updatestate.cl' did not match any file(s) known to git


cast vector before affectation (seen in nvidia examples)

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/mazhe/ClGaussianPyramid.git/'


Practice with writting my own macros, including the three rules to observe when writting a macro; practice the macro-writting macro

;; @file macros-advanced.cl
;;
;; @breif Advanced macro practices - defining your own macros
;;
;; Macro definition skeleton:
;; (defmacro name (parameter*)
;;   "Optional documentation string"
;;   body-form*)
;;
;; Note that backquote expression is most often used in the `body-form`
;;

; `primep` test a number for prime
(defun primep (n)
  "test a number for prime"
  (if (< n 2) (return-from primep))
  (do ((i 2 (1+ i)) (p t (not (zerop (mod n i)))))
      ((> i (sqrt n)) p)
    (when (not p) (return))))
; `next-prime` return the next prime bigger than the specified number
(defun next-prime (n)
  "return the next prime bigger than the speicified number"
  (do ((i (1+ n) (1+ i)))
      ((primep i) i)))
;
; The recommended procedures to writting a new macro are as follows:
; 1. Write a sample call to the macro and the code it should expand into
(do-primes (p 0 19)
  (format t "~d " p))
; Expected expanded codes
(do ((p (next-prime (- 0 1)) (next-prime p)))
    ((> p 19))
  (format t "~d " p))
; 2. Write code that generate the hardwritten expansion from the arguments in
; the sample call
(defmacro do-primes (var-and-range &rest body)
  (let ((var (first var-and-range))
        (start (second var-and-range))
        (end (third var-and-range)))
    `(do ((,var (next-prime (- ,start 1)) (next-prime ,var)))
         ((> ,var ,end))
      ,@body)))
; 2-1. More concise implementations with the 'parameter list destructuring' and
; '&body' synonym, it also emits more friendly messages on incorrent input.
(defmacro do-primes ((var start end) &body body)
  `(do ((,var (next-prime (- ,start 1)) (next-prime ,var)))
       ((> ,var ,end))
    ,@body))
; 2-2. Test the result of macro expansion with the `macroexpand-1` function
(macroexpand-1 '(do-primes (p 0 19) (format t "~d " p)))
; 3. Make sure the macro abstraction does not "leak"
(defmacro do-primes ((var start end) &body body)
  (let ((end-value-name (gensym)))
    `(do ((,var (next-prime (- ,start 1)) (next-prime ,var))
          (,end-value-name ,end))
         ((> ,var ,end-value-name))
      ,@body)))
; 3-1. Rules to observe to avoid common and possible leaks
;   a. include any subforms in the expansion in positions that will be evaluated
;      in the same order as the subforms appear in the macro call
;   b. make sure subforms are evaluated only once by creating a variable in the
;      expansion to hold the value of evaluating the argument form, and then
;      using that variable anywhere else the value is needed in the expansion
;   c. use `gensym` at macro expansion time to create variable names used in the
;      expansion
;
; Appendix I. Macro-writting macros, 'with-gensyms', to guranttee that rule c
; gets observed.
; Example usage of `with-gensyms`
(defmacro do-primes-a ((var start end) &body body)
  "do-primes implementation with macro-writting macro 'with-gensyms'"
  (with-gensyms (end-value-name)
    `(do ((,var (next-prime (- ,start 1)) (next-prime ,var))
          (,end-value-name ,end))
         ((> ,var ,end-value-name))
      ,@body)))
; Define the macro, note how comma is used to interpolate the value of the loop
; expression
(defmacro with-gensyms ((&rest names) &body body)
  `(let ,(loop for n in names collect `(,n (gensym)))
    ,@body)
)

error: pathspec 'macros-advanced.cl' did not match any file(s) known to git


Clean up code

Clean up code

/******************************************************************************
 * function: radix sort                                                       *
 * input:                                                                     *
 * output:                                                                    *
 ******************************************************************************/

 // Adapted from: https://github.com/Schw1ng/GPURadixSort

typedef struct radix_config {
  uint radices;  // number of radices
  uint blocks;   // number of blocks
  uint gpb;      // groups per block
  uint r_val;    // R
  uint tpg;      // threads per group
  uint epg;      // elements per group
  uint rpb;      // radices per block
  uint mask;     // bit mask
  uint l_val;    // L
  uint tpb;      // threads per block
  uint size;     // total elements
} configuration;

// If this is a prefix sum, can be optimize this, maybe, write a static
// version that assumes local size <= 1024?
inline void prefix_local(local uint* data, int len, int threads) {
  uint lid = get_local_id(0);
  int inc = 2;
  // reduce
  while (inc <= len) {
    int j = inc >> 1;
    for (int i = (j - 1) + (lid * inc); (i + inc) < len; i += threads * inc)
      data[i + j] = data[i] + data[i + j];
    inc = inc << 1;
    barrier(CLK_LOCAL_MEM_FENCE);
  }
  // downsweep
  data[len - 1] = 0;
  barrier(CLK_LOCAL_MEM_FENCE);
  while (inc >= 2) {
    int j = inc >> 1;
    for (int i = (j - 1) + (lid * inc); (i + j) <= len; i+= threads * inc) {
      uint tmp = data[i + j];
      data[i + j] = data[i] + data[i + j];
      data[i] = tmp;
    }
    inc = inc >> 1;
    barrier(CLK_LOCAL_MEM_FENCE);
  }
}

// The `global` thing here is just the memory placement, right?
inline void prefix_global(global uint* data, int len, int threads) {
  uint lid = get_local_id(0);
  int inc = 2;
  // reduce
  while (inc <= len) {
    int j = inc >> 1;
    for (int i = (j - 1) + (lid * inc); (i + inc) < len ; i += threads * inc)
      data[i + j] = data[i] + data[i + j];
    inc = inc << 1;
    barrier(CLK_LOCAL_MEM_FENCE);
  }
  // Downsweep
  data[len-1] = 0;
  barrier(CLK_LOCAL_MEM_FENCE);
  while (inc >= 2) {
    int j = inc >> 1;
    for (int i = (j - 1) + (lid * inc); (i + j) <= len; i += threads * inc) {
      uint tmp = data[i + j];
      data[i + j] = data[i] + data[i + j];
      data[i] = tmp;
    }
    inc = inc >> 1;
    barrier(CLK_LOCAL_MEM_FENCE);
  }
}

kernel void count(global uint* cell_in,
                  global volatile uint* counters,
                  configuration conf,
                  uint offset) {
  uint lid = get_local_id(0);
  uint grp = get_group_id(0);
  // Current thread group is based of the local id.
  uint thread_grp = lid / conf.r_val;
  // Startindex of the datablock that corresponds to the Threadblock.
  int active_block = grp * conf.gpb * conf.epg ;
  // Offset inside the block for the threadgroup of the current thread.
  int active_group = (lid / conf.r_val) * conf.epg;
  // Number of counters for each radix.
  uint groups = conf.blocks * conf.gpb;
  // Each Threadgroup has its own counter for each radix and is
  // calculating the offset based on current block / group.
  uint grp_offset = grp * conf.gpb;
  // Startindex for the current thread.
  uint start = active_block + active_group + lid % conf.r_val;
  //uint end = active_block + active_group + conf.epg;
  //end = (end > conf.size) ? conf.size : end;
  uint end = min(active_block + active_group + conf.epg, conf.size);
  for (;start < end; start += conf.tpg) {
    uint act_radix = (cell_in[start] >> offset) & conf.mask;
    // The following code ensures that the counters of each Threadgroup
    // are sequentially incremented.
    for (uint i = 0 ; i < conf.r_val; i++) {
      if (lid % conf.r_val == i) {
        uint start = (act_radix * groups) + grp_offset + thread_grp;
        // TODO: not a big fan of this, maybe use atomics?
        ++counters[start];
        //atomic_inc(&counters[start]);
      }
      barrier(CLK_LOCAL_MEM_FENCE);
    }
  }
}

kernel void sum(global uint* cell_in,
                global volatile uint* counters,
                global uint* prefixes,
                configuration conf,
                uint offset,
                local uint* counts) {
  uint lid = get_local_id(0);
  uint grp = get_group_id(0);
  uint groups = conf.blocks * conf.gpb;
  uint act_radix = conf.rpb * grp;
  for (uint i = 0; i < conf.rpb; i++) {
    // The Num_Groups counters of the radix are read from global memory to
    // shared memory. Jeder Thread liest die Counter basierend auf der localid aus
    int k = 0;
    uint boarder = ((act_radix + 1) * groups);
    // boarder = (boarder > conf.blocks * conf.gpb)
    //         ? conf.blocks * conf.gpb : boarder;
    for (uint j = (act_radix * groups) + lid; j < boarder; j+= conf.tpb) {
      counts[lid + conf.tpb * k] = counters[j];
      ++k;
    }
    barrier(CLK_LOCAL_MEM_FENCE);
    // Die einzelnen RadixCounter sind nun in dem counts local Memory
    prefix_local(counts, groups, conf.tpb);
    barrier(CLK_LOCAL_MEM_FENCE);
    // Gesamtprefix für den aktuellen radix berechnen
    if (lid == 1) {
      prefixes[act_radix]
        = counts[(groups) - 1] + counters[((act_radix + 1) * groups) - 1];
    }
    // Errechnete Prefixsumme zurück in den global memory schreiben
    barrier(CLK_LOCAL_MEM_FENCE);
    k = 0;
    for (uint j = (act_radix * groups) + lid; j < ((act_radix + 1) * groups);
         j += conf.tpb) {
      counters[j] = counts[lid + conf.tpb * k];
      ++k;
    }
    ++act_radix;
  }
}

kernel void reorder_keys(global uint* cell_in,
                         global uint* cell_out,
                         global uint* counters,
                         global uint* prefixes,
                         local uint* l_counters,
                         local uint* l_prefixes,
                         configuration conf,
                         uint offset) {
  uint lid = get_local_id(0);
  uint grp = get_group_id(0);
  uint thread_grp = lid / conf.r_val;
  uint act_radix = conf.rpb * grp;
  uint groups = conf.gpb * conf.blocks;
  int rc_offset = act_radix * groups;
  // erst abschließen der radix summierung
  for (uint i = 0 ; i < conf.rpb ; i++) {
    for (uint idx = lid; idx < groups; idx += conf.tpb) {
      // The Num_Groups counters of the radix are read from global memory
      // to shared memory. Jeder Thread liest die Counter basierend auf der
      // groupId aus
      l_counters[i * groups + idx] = counters[rc_offset + i * groups + idx];
    }
  }
  // Read radix prefixes to localMemory
  for (uint i = lid; i < conf.radices; i += conf.tpb) {
    l_prefixes[i] = prefixes[i];
  }
  // Präfixsumme über die RadixCounter bilden.
  barrier(CLK_LOCAL_MEM_FENCE);
  prefix_local(l_prefixes, conf.radices, conf.tpb);
  barrier(CLK_LOCAL_MEM_FENCE);
  // Die Präfixsumme des Radixe auf alle subcounter der radixes addieren
  for (uint i = 0; i < conf.rpb; i++) {
    for (uint j = lid; j < groups; j += conf.tpb) {
      l_counters[i * groups + j] += l_prefixes[act_radix + i];
    }
    // barrier(CLK_LOCAL_MEM_FENCE);
  }
  // Zurückschreiben der Radixe mit entsprechedem offset.
  for (uint i = 0; i < conf.rpb; i++) {
    for (uint idx = lid; idx < groups; idx += conf.tpb) {
      // The Num_Groups counters of the radix are read from global memory
      // to shared memory. Jeder Thread liest die Counter basierend auf
      // der groupId aus
      counters[rc_offset + i * groups + idx] = l_counters[i * groups + idx];
    }
  }
  barrier(CLK_LOCAL_MEM_FENCE);
  int active_block = grp * conf.gpb * conf.epg;
  int active_counter = grp * conf.gpb;
  int active_group = (lid / conf.r_val) * conf.epg;
  uint idx = active_block + active_group + lid % conf.r_val;
  //uint boundary = active_block + active_group + conf.epg;
  //boundary = (boundary < conf.size) ? boundary : conf.size;
  uint boundary = min(active_block + active_group + conf.epg, conf.size);
  for (; idx < boundary; idx += conf.tpg) {
    uint tmpRdx = (cell_in[idx] >> offset) & conf.mask;
    for (uint tmpIdx = 0; tmpIdx < conf.r_val; tmpIdx++) {
      if (lid % conf.r_val == tmpIdx) {
        uint idx = tmpRdx * groups + active_counter + thread_grp;
        cell_out[counters[idx]] = cell_in[idx];
        ++counters[idx];
      }
      barrier(CLK_LOCAL_MEM_FENCE);
    }
  }
}

kernel void reorder_values_by_keys(global uint* cell_in,
                                   global uint* cell_out,
                                   global ulong* valueIn,
                                   global ulong* valueOut,
                                   global uint* counters,
                                   global uint* prefixes,
                                   local uint* l_counters,
                                   local uint* l_prefixes,
                                   configuration conf,
                                   uint offset) {
  uint lid = get_local_id(0);
  uint grp = get_group_id(0);
  uint thread_grp = lid / conf.r_val;
  uint act_radix = conf.rpb * grp;
  uint groups = conf.gpb * conf.blocks;
  int rc_offset = act_radix * groups;
  // Finish the radix sum
  for (uint i = 0 ; i < conf.rpb ; i++) {
    for (uint blockidx = lid; blockidx < groups; blockidx += conf.tpb) {
      // The Num_Groups counters of the radix are read from global memory to
      // shared memory. Jeder Thread liest die Counter basierend auf der groupId
      // aus.
      l_counters[i * groups + blockidx]
        = counters[rc_offset + i * groups + blockidx];
    }
  }
  // Read radix prefixes to localMemory
  for (uint i = lid; i < conf.radices; i+= conf.tpb) {
    l_prefixes[i] = prefixes[i];
  }
  // build prefix sum over radix counters?
  // (seems to be the prefixes, not counters)
  barrier(CLK_LOCAL_MEM_FENCE);
  prefix_local(l_prefixes, conf.radices, conf.tpb);
  barrier(CLK_LOCAL_MEM_FENCE);
  // Add the sum of the radix to all subounter of the radixes
  for (uint i = 0; i < conf.rpb; i++) {
    for (uint j = lid; j < groups; j += conf.tpb) {
      l_counters[i * groups + j] += l_prefixes[act_radix + i];
    }
    // barrier(CLK_LOCAL_MEM_FENCE);
  }
  // Write back the radixes to their respectve offers
  for (uint i = 0; i < conf.rpb; i++) {
    for (uint blockidx = lid; blockidx < groups; blockidx += conf.tpb) {
      // The Num_Groups counters of the radix are read from global memory to
      // shared memory. Jeder Thread liest die Counter basierend auf der
      // groupId aus
      counters[rc_offset + i * groups + blockidx]
        = l_counters[i * groups + blockidx];
    }
  }
  barrier(CLK_LOCAL_MEM_FENCE);
  int active_block = grp * conf.gpb * conf.epg ;
  int active_counter = grp * conf.gpb  ;
  int active_group = (lid / conf.r_val) * conf.epg;
  uint idx = active_block + active_group +  lid % conf.r_val;
  //uint boundary = active_block + active_group + conf.epg;
  //boundary = (boundary < conf.size) ? boundary : conf.size;
  uint boundary = min(active_block + active_group + conf.epg, conf.size);
  for (; idx < boundary; idx += conf.tpg) {
    uint tmpRdx = (cell_in[idx] >> offset) & conf.mask;
    for (uint tmpIdx = 0; tmpIdx < conf.r_val; tmpIdx++) {
      if (lid % conf.r_val == tmpIdx) {
        uint tmp = tmpRdx * groups + active_counter + thread_grp;
        cell_out[counters[tmp]] = cell_in[idx];
        valueOut[counters[tmp]] = valueIn[idx];
        // TODO: is the increment ok, or should we use atomics?
        ++counters[tmp];
        //atomic_inc(&counters[tmp]);
      }
      barrier(CLK_LOCAL_MEM_FENCE);
    }
  }
}

error: pathspec 'include/radix.cl' did not match any file(s) known to git


3dconv

/** Convolution of src image by mask. Result is stored in dst image.

  */

// ARRAY convolution_window [window_size_x*window_size_y*window_size_z]
// SCALAR window_size_x
// SCALAR window_size_y
// SCALAR window_size_z

__kernel void vglCl3dConvolution(__read_only image3d_t img_input,
                          __write_only image3d_t img_output,
                          __constant float* convolution_window,
                          int window_size_x,
                          int window_size_y,
						  int window_size_z)
{
	int4 coords = (int4)(get_global_id(0), get_global_id(1), get_global_id(2), 0);
	const sampler_t smp = CLK_NORMALIZED_COORDS_FALSE | //Natural coordinates
                              CLK_ADDRESS_CLAMP_TO_EDGE |   //Clamp to next edge
                              CLK_FILTER_NEAREST;           //Don't interpolate
	float4 result= (0,0,0,0);

	int factorx = floor((float)window_size_x / 2.0f);
	int factory = floor((float)window_size_y / 2.0f);
	int factorz = floor((float)window_size_z / 2.0f);
	int conv_controller = 0;
	for(int i = -factorx; i <= factorx; i++)
	{
		for(int j = -factory; j <= factory; j++)
		{
			for (int k = -factorz; k <= factorz; k++)
			{
				float4 p = read_imagef(img_input, smp, (int4)(coords.x + i,coords.y + j, coords.z + k, 0));
				p.xyz *= convolution_window[conv_controller];
				result += p;
				conv_controller++;
			}
		}
	}
	write_imagef(img_output,coords,result);
}

error: pathspec 'src/CL/vglCl3dConvolution.cl' did not match any file(s) known to git


updating kernel

updating kernel

__kernel void invert(__read_only  image2d_t img_input,__write_only  image2d_t img_output)
{
	int2 coords = (int2)(get_global_id(0), get_global_id(1));
	const sampler_t smp = CLK_NORMALIZED_COORDS_FALSE | //Natural coordinates
						  CLK_ADDRESS_CLAMP | //Clamp to zeros
						  CLK_FILTER_NEAREST; //Don't interpolate
	float4 p = read_imagef(img_input, smp, coords);
	p.x = 1.0 - p.x;
	write_imagef(img_output,coords,p);
}

error: pathspec 'CLdemos/CL/Invert2D_A.cl' did not match any file(s) known to git


Render closer objects over top of further objects (using time of ray intersection)

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/emr4378/GPU-Ray-Tracer.git/'


Moved __constant to bfgs parameter list

Moved __constant to bfgs parameter list

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/HongjianLi/idock.git/'


Added cuda example.

Added cuda example.

(headers
    ("../common/book.h" :local t)
    ("../common/cpu_bitmap.h" :local t))

(template sq (x) (* x x))
(define !dim 1000)

(struct cu-complex (
    (r real)
    (i real)))

(template cu-complex-decl (rv iv)
    (cast (arr-decl rv iv) (struct cu-complex)))

(func cu-complex-magnitude float ((x cu-complex))
    (return (+ (sq (.> x i)) (sq (.> x r)))))

(func cu-complex-mul cu-complex ((x cu-complex) (y cu-complex))
    (var z cu-complex)
    (= (.> z r) (-
                    (* (.> x r) (.> y r))
                    (* (.> x i) (.> y i))))
    (= (.> z i) (+
                    (* (.> x i) (.> y r))
                    (* (.> x r) (.> y i))))
    (return z))

(func cu-complex-add cu-complex ((x cu-complex) (y cu-complex))
    (var z cu-complex)
    (= (.> z r) (+ (.> x r) (.> y r)))
    (= (.> z i) (+ (.> x i) (.> y i)))
    (return z))

(cuda/device julia int (x y)
    (const scale float 1.5)
    (template jvar (v)
        (var (sym/add j v) float
            (* scale (cast (/ (- (/ !dim 2) x) (/ !dim 2))))))
    (jvar x) (jvar y)
    (template cvar (v x y)
        (var v (struct cu-complex) (cu-complex-decl x y)))
    (cvar c -9.8 0.156) (cvar a jx jy)
    (var i int 0)
    (for (= i 0) (< i 200) (++ i)
        (= a (@cu-complex-add (@cu-complex-mul a a) c))
        (if (> (@cu-complex-magnitude a) 1000) (return 0)))
    (return 1)
)

(cuda/global kernel void (((pt ptr) char nil unsigned))
    (var x int block/idx/x)
    (var y int block/idx/y)
    (var offset int (+ x (* y grid/dim/x)))
    (var julia-value int (@julia x y))
    (= ([]ptr (+ 0 (* offset 4))) (* 255 julia-value))
    (= ([]ptr (+ 1 (* offset 4))) 0)
    (= ([]ptr (+ 2 (* offset 4))) 0)
    (= ([]ptr (+ 3 (* offset 4))) 255))

(syn cpubitmap "CPUbitmap")

(main
    (var (@bitmap !dim !dim) cpubitmap)
    (var (pt dev-bitmap) char nil unsigned)
    (@!handle-error
        (@cuda/malloc
            (cast (addr dev-bitmap) (typ* void 2))
            (.> bitmap (@image-size))))
    (var (@grid !dim !dim) dim3)
    (cuda/call kernel (grid 1) dev-bitmap)
    (@!handle-error
        (@cuda/memcpy
            (.> bitmap (@get-ptr))
            dev-bitmap
            (.> bitmap (@image-size))
            cuda/dev->host))
    (.> bitmap (@display-and-exit))
    (@!handle-error
        (@cuda/free dev-bitmap)))

error: pathspec 'cuda.cl' did not match any file(s) known to git