Fix absolute include path in sample vs2013 generation

(use-package :regexp)

(load "cl-fad/load.lisp" :verbose nil)

(defstruct rdata start-marker end-marker replacement-callback include-markers)

(setq project-file-extension "vcxproj")
(setq solution-file-extension "sln")
(setq filters-file-extension "filters")

(defun regexp-replace (string pat repl)
  (reduce #'(lambda (x y) (string-concat x repl y))
          (regexp:regexp-split pat string))
)

(defun file-string (path)
  (with-open-file (infile path :if-does-not-exist nil)
    (cond ((not (null infile))
            (format nil "~{~A~^~%~}"
              (loop
                for line = (read-line infile nil)
                while line
                collect line
              )
            )
          )
          (t nil) ; file not found
    )
  )
)

(defun write-file (file-name content)
  (with-open-file (outfile file-name
      :direction :output
      :if-exists :supersede
      :if-does-not-exist :create)
  (format outfile "~A" content)))

(defmacro get-next-substr-index (str &key start-marker end-marker start-index end-index include-markers (next-index 0))
  `(progn
    (let ((start-m (match ,start-marker ,str :start ,next-index))
         )
      (cond ((null start-m) nil)
            (t
              (setq ,start-index  (if include-markers
                                     (match-start start-m)
                                     (match-end start-m)
                                  )
              )
              (let ((end-m (match ,end-marker ,str :start (match-end start-m))))
                (cond ((null end-m) nil)
                      (t
                        (setq ,end-index  (if include-markers
                                             (match-end end-m)
                                             (match-start end-m)
                                          )
                        )
                        (match-end end-m)
                      )
                )
              )
            )
      )
    )
  )
)
(defun concat-string-list (s)
  (let ((CUSTOM:*PPRINT-FIRST-NEWLINE* nil))
    (format nil "~{~A~}" s)
  )
)

(defun parse-replace (str template)
    (concat-string-list
      (let ((sm (rdata-start-marker template))
            (em (rdata-end-marker template))
            (callback (rdata-replacement-callback template))
            (include-markers (rdata-include-markers template))
            )
           ;(write-line (format nil "Replacing: ~A to ~A" sm em))
           (loop  with index = 0
                  do (setq next-index (get-next-substr-index str :start-marker sm
                               :end-marker em
                               :start-index si
                               :end-index ei
                               :next-index index
                               :include-markers include-markers))
                  if (null next-index)
                    collect (progn ;(write-line (format nil "~A -> ~A" index (length str)))
                              (subseq str index)
                             )
                  while next-index
                  collect (subseq str index si)
                  collect (funcall callback (subseq str si ei))
                  collect (subseq str ei next-index)
                  do (progn ;(write-line (format nil "~A -> [~A ~A] -> ~A" index si ei next-index))
                        (setq index next-index)
                      )
           )
      )
    )
)

(defun apply-replacement-templates (str templates)
  (cond ((null templates) str)
        (t (apply-replacement-templates
            (parse-replace str (car templates))
            (cdr templates)
           )
        )
  )
)

(defun apply-parse-file (file-name-in file-name-out templates)
  (write-file file-name-out
    (apply-replacement-templates (file-string file-name-in) templates)
  )
)

(defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part
is replaced with replacement."
  (with-output-to-string (out)
    (loop with part-length = (length part)
       for old-pos = 0 then (+ pos part-length)
       for pos = (search part string
                         :start2 old-pos
                         :test test)
       do (write-string string out
                        :start old-pos
                        :end (or pos (length string)))
       when pos do (write-string replacement out)
       while pos)))

(defmacro create-rdata-list (listname addname)
  `(progn
    (setq ,listname nil)
    (defun ,addname (&rest args)
      (let ((rd (apply #'make-rdata args)))
        (setq ,listname (cons rd ,listname))
      )
    )
  )
)

(create-rdata-list proj-data-list add-projdata)
(create-rdata-list sln-data-list add-slndata)
(create-rdata-list filter-data-list add-filterdata)

(setq tp1 (make-rdata :start-marker "<data[^>]*>"
                     :end-marker "</data>"
                     :replacement-callback (lambda (str) "_123_")
                     :include-markers T))

(defun back-to-forward-slashes (str)
  (replace-all str "\\" "/")
)

(setq lambda-build-path-to-sln-dir (lambda (str) (regexp-replace (back-to-forward-slashes str)
                                                                 (back-to-forward-slashes build-dir)
                                                                 "$(SolutionDir)")))
(setq lambda-source-path-to-source-dir (lambda (str) (regexp-replace (back-to-forward-slashes str)
                                                                     (back-to-forward-slashes source-dir)
                                                                     "$(SolutionDir)..")))
(setq lambda-convert-include-path (lambda (str) (funcall lambda-build-path-to-sln-dir
                                                         (funcall lambda-source-path-to-source-dir str)
                                                         )))
(setq lambda-int-dir-to-obj-dir (lambda (str) (regexp-replace (back-to-forward-slashes str)
                                                              "[^.]*[.]dir"
                                                              "obj")))
(setq lambda-remove (lambda (str) ""))

(add-projdata :start-marker "<AdditionalIncludeDirectories>"
              :end-marker "</AdditionalIncludeDirectories>"
              :replacement-callback lambda-convert-include-path)
(add-projdata :start-marker "<OutDir[^>]*>"
              :end-marker "</OutDir>"
              :replacement-callback lambda-build-path-to-sln-dir)
(add-projdata :start-marker "<ImportLibrary[^>]*>"
              :end-marker "</ImportLibrary>"
              :replacement-callback lambda-build-path-to-sln-dir)
(add-projdata :start-marker "<ProgramDataBaseFile[^>]*>"
              :end-marker "</ProgramDataBaseFile>"
              :replacement-callback lambda-build-path-to-sln-dir)
(add-projdata :start-marker "[^<>]*<ItemGroup[^>]*>[^<]*<CustomBuild[^>]*CMakeLists[.]txt[^>]*>"
              :end-marker "</ItemGroup>"
              :replacement-callback lambda-remove
              :include-markers T)
(add-projdata :start-marker "[^<>]*<ItemGroup[^>]*>[^<]*<ProjectReference[^>]*ZERO_CHECK[.]vcxproj[^>]*>"
              :end-marker "</ItemGroup>"
              :replacement-callback lambda-remove
              :include-markers T)
(add-projdata :start-marker "CMAKE_INTDIR="
              :end-marker ";"
              :replacement-callback lambda-remove
              :include-markers T)
(add-projdata :start-marker "<Cl\\(Include\\|Compile\\)[^iI>]*Include=\""
              :end-marker "\""
              :replacement-callback lambda-source-path-to-source-dir)
(add-projdata :start-marker "<IntDir[^>]*>"
              :end-marker "<"
              :replacement-callback lambda-int-dir-to-obj-dir)

(add-filterdata :start-marker "<Cl\\(Include\\|Compile\\)[^iI>]*Include=\""
              :end-marker "\""
              :replacement-callback lambda-source-path-to-source-dir)
(add-filterdata :start-marker "[^<>]*<ItemGroup[^>]*>[^<]*<CustomBuild[^>]*CMakeLists[.]txt[^>]*>"
              :end-marker "</ItemGroup>"
              :replacement-callback lambda-remove
              :include-markers T)

(add-slndata  :start-marker "Project([^,]*\\(ALL_BUILD\\|CMakePredefinedTargets\\|ZERO_CHECK\\)"
              :end-marker "EndProject"
              :replacement-callback lambda-remove
              :include-markers T)

(defun mapc-directory-tree (fn directory)
  (dolist (entry (cl-fad:list-directory directory))
    (when (cl-fad:directory-pathname-p entry)
      (mapc-directory-tree fn entry))
    (funcall fn entry)))

(defun get-temp-filename (fn)
  (format nil "~A.tmp" fn))

(defun process-file (filename-in file-extension)
  (let ((filename-out (get-temp-filename filename-in))
        (data-list (cond ((equal file-extension solution-file-extension) sln-data-list)
                         ((equal file-extension filters-file-extension) filter-data-list)
                         (t proj-data-list)))
       )
    (apply-parse-file filename-in filename-out data-list)
    (delete-file filename-in)
    (rename-file filename-out filename-in)
  )
)

(defun process (build-path source-path)
  (setq build-dir build-path)
  (setq source-dir source-path)
  (let ((target-directory (if (null build-dir)
                              (ext:cd)
                              build-dir)))
    (write-line (format nil "Base directory: ~A~%" target-directory))
    (mapc-directory-tree (lambda (x)
                           (let ((file-extension (pathname-type x)))
                             (when (or (equal file-extension project-file-extension)
                                       (equal file-extension filters-file-extension)
                                       (equal file-extension solution-file-extension))
                               (write-line (format nil "~A"
                                                   (enough-namestring x target-directory)
                                                   ))
                               (process-file (namestring x) file-extension))
                           )
                         )
                         target-directory)))

(defun _ () (load "parse-replace.cl" :verbose nil))

(when (>= (length *args*) 2)
  (let ((build-path (car *args*))
        (source-path (cadr *args*))
        )
    (process build-path source-path)
  )
)

(use-package :regexp)

(load "cl-fad/load.lisp" :verbose nil)

(defstruct rdata start-marker end-marker replacement-callback include-markers)

(setq project-file-extension "vcxproj")
(setq solution-file-extension "sln")
(setq filters-file-extension "filters")

(defun regexp-replace (string pat repl)
  (reduce #'(lambda (x y) (string-concat x repl y))
          (regexp:regexp-split pat string))
)

(defun file-string (path)
  (with-open-file (infile path :if-does-not-exist nil)
    (cond ((not (null infile))
            (format nil "~{~A~^~%~}"
              (loop
                for line = (read-line infile nil)
                while line
                collect line
              )
            )
          )
          (t nil) ; file not found
    )
  )
)

(defun write-file (file-name content)
  (with-open-file (outfile file-name
      :direction :output
      :if-exists :supersede
      :if-does-not-exist :create)
  (format outfile "~A" content)))

(defmacro get-next-substr-index (str &key start-marker end-marker start-index end-index include-markers (next-index 0))
  `(progn
    (let ((start-m (match ,start-marker ,str :start ,next-index))
         )
      (cond ((null start-m) nil)
            (t
              (setq ,start-index  (if include-markers
                                     (match-start start-m)
                                     (match-end start-m)
                                  )
              )
              (let ((end-m (match ,end-marker ,str :start (match-end start-m))))
                (cond ((null end-m) nil)
                      (t
                        (setq ,end-index  (if include-markers
                                             (match-end end-m)
                                             (match-start end-m)
                                          )
                        )
                        (match-end end-m)
                      )
                )
              )
            )
      )
    )
  )
)
(defun concat-string-list (s)
  (let ((CUSTOM:*PPRINT-FIRST-NEWLINE* nil))
    (format nil "~{~A~}" s)
  )
)

(defun parse-replace (str template)
    (concat-string-list
      (let ((sm (rdata-start-marker template))
            (em (rdata-end-marker template))
            (callback (rdata-replacement-callback template))
            (include-markers (rdata-include-markers template))
            )
           ;(write-line (format nil "Replacing: ~A to ~A" sm em))
           (loop  with index = 0
                  do (setq next-index (get-next-substr-index str :start-marker sm
                               :end-marker em
                               :start-index si
                               :end-index ei
                               :next-index index
                               :include-markers include-markers))
                  if (null next-index)
                    collect (progn ;(write-line (format nil "~A -> ~A" index (length str)))
                              (subseq str index)
                             )
                  while next-index
                  collect (subseq str index si)
                  collect (funcall callback (subseq str si ei))
                  collect (subseq str ei next-index)
                  do (progn ;(write-line (format nil "~A -> [~A ~A] -> ~A" index si ei next-index))
                        (setq index next-index)
                      )
           )
      )
    )
)

(defun apply-replacement-templates (str templates)
  (cond ((null templates) str)
        (t (apply-replacement-templates
            (parse-replace str (car templates))
            (cdr templates)
           )
        )
  )
)

(defun apply-parse-file (file-name-in file-name-out templates)
  (write-file file-name-out
    (apply-replacement-templates (file-string file-name-in) templates)
  )
)

(defun replace-all (string part replacement &key (test #'char=))
  "Returns a new string in which all the occurences of the part
is replaced with replacement."
  (with-output-to-string (out)
    (loop with part-length = (length part)
       for old-pos = 0 then (+ pos part-length)
       for pos = (search part string
                         :start2 old-pos
                         :test test)
       do (write-string string out
                        :start old-pos
                        :end (or pos (length string)))
       when pos do (write-string replacement out)
       while pos)))

(defmacro create-rdata-list (listname addname)
  `(progn
    (setq ,listname nil)
    (defun ,addname (&rest args)
      (let ((rd (apply #'make-rdata args)))
        (setq ,listname (cons rd ,listname))
      )
    )
  )
)

(create-rdata-list proj-data-list add-projdata)
(create-rdata-list sln-data-list add-slndata)
(create-rdata-list filter-data-list add-filterdata)

(setq tp1 (make-rdata :start-marker "<data[^>]*>"
                     :end-marker "</data>"
                     :replacement-callback (lambda (str) "_123_")
                     :include-markers T))

(defun back-to-forward-slashes (str)
  (replace-all str "\\" "/")
)

(setq lambda-build-path-to-sln-dir (lambda (str) (regexp-replace (back-to-forward-slashes str)
                                                                 (back-to-forward-slashes build-dir)
                                                                 "$(SolutionDir)")))
(setq lambda-source-path-to-source-dir (lambda (str) (regexp-replace (back-to-forward-slashes str)
                                                                     (back-to-forward-slashes source-dir)
                                                                     "$(SolutionDir)..")))
(setq lambda-int-dir-to-obj-dir (lambda (str) (regexp-replace (back-to-forward-slashes str)
                                                              "[^.]*[.]dir"
                                                              "obj")))
(setq lambda-remove (lambda (str) ""))

(add-projdata :start-marker "<AdditionalIncludeDirectories>"
              :end-marker "</AdditionalIncludeDirectories>"
              :replacement-callback lambda-build-path-to-sln-dir)
(add-projdata :start-marker "<OutDir[^>]*>"
              :end-marker "</OutDir>"
              :replacement-callback lambda-build-path-to-sln-dir)
(add-projdata :start-marker "<ImportLibrary[^>]*>"
              :end-marker "</ImportLibrary>"
              :replacement-callback lambda-build-path-to-sln-dir)
(add-projdata :start-marker "<ProgramDataBaseFile[^>]*>"
              :end-marker "</ProgramDataBaseFile>"
              :replacement-callback lambda-build-path-to-sln-dir)
(add-projdata :start-marker "[^<>]*<ItemGroup[^>]*>[^<]*<CustomBuild[^>]*CMakeLists[.]txt[^>]*>"
              :end-marker "</ItemGroup>"
              :replacement-callback lambda-remove
              :include-markers T)
(add-projdata :start-marker "[^<>]*<ItemGroup[^>]*>[^<]*<ProjectReference[^>]*ZERO_CHECK[.]vcxproj[^>]*>"
              :end-marker "</ItemGroup>"
              :replacement-callback lambda-remove
              :include-markers T)
(add-projdata :start-marker "CMAKE_INTDIR="
              :end-marker ";"
              :replacement-callback lambda-remove
              :include-markers T)
(add-projdata :start-marker "<Cl\\(Include\\|Compile\\)[^iI]*Include=\""
              :end-marker "\""
              :replacement-callback lambda-source-path-to-source-dir)
(add-projdata :start-marker "<IntDir[^>]*>"
              :end-marker "<"
              :replacement-callback lambda-int-dir-to-obj-dir)

(add-filterdata :start-marker "<Cl\\(Include\\|Compile\\)[^iI]*Include=\""
              :end-marker "\""
              :replacement-callback lambda-source-path-to-source-dir)
(add-filterdata :start-marker "[^<>]*<ItemGroup[^>]*>[^<]*<CustomBuild[^>]*CMakeLists[.]txt[^>]*>"
              :end-marker "</ItemGroup>"
              :replacement-callback lambda-remove
              :include-markers T)

(add-slndata  :start-marker "Project([^,]*\\(ALL_BUILD\\|CMakePredefinedTargets\\|ZERO_CHECK\\)"
              :end-marker "EndProject"
              :replacement-callback lambda-remove
              :include-markers T)

(defun mapc-directory-tree (fn directory)
  (dolist (entry (cl-fad:list-directory directory))
    (when (cl-fad:directory-pathname-p entry)
      (mapc-directory-tree fn entry))
    (funcall fn entry)))

(defun get-temp-filename (fn)
  (format nil "~A.tmp" fn))

(defun process-file (filename-in file-extension)
  (let ((filename-out (get-temp-filename filename-in))
        (data-list (cond ((equal file-extension solution-file-extension) sln-data-list)
                         ((equal file-extension filters-file-extension) filter-data-list)
                         (t proj-data-list)))
       )
    (apply-parse-file filename-in filename-out data-list)
    (delete-file filename-in)
    (rename-file filename-out filename-in)
  )
)

(defun process (build-path source-path)
  (setq build-dir build-path)
  (setq source-dir source-path)
  (let ((target-directory (if (null build-dir)
                              (ext:cd)
                              build-dir)))
    (write-line (format nil "Base directory: ~A~%" target-directory))
    (mapc-directory-tree (lambda (x)
                           (let ((file-extension (pathname-type x)))
                             (when (or (equal file-extension project-file-extension)
                                       (equal file-extension filters-file-extension)
                                       (equal file-extension solution-file-extension))
                               (write-line (format nil "~A"
                                                   (enough-namestring x target-directory)
                                                   ))
                               (process-file (namestring x) file-extension))
                           )
                         )
                         target-directory)))

(defun _ () (load "parse-replace.cl" :verbose nil))

(when (>= (length *args*) 2)
  (let ((build-path (car *args*))
        (source-path (cadr *args*))
        )
    (process build-path source-path)
  )
)


runs stride 2 forward

runs stride 2 forward

/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#define _FLOAT float
#define _FLOAT2 float2
#define _FLOAT4 float4
#define _FLOAT8 float8

#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F /* max value */
#endif

#define UNUSED __attribute__((__unused__))

#define DBG_OUT_OF_RNGE 0

// calculating the size of the area for weights prefetch

__attribute__((always_inline)) uint iDiv(uint v, uint d)
{
    uint r = (uint)((float)v * (1.0f / (float)d) + 0.00001f);
    return (r);
}

__attribute__((always_inline)) uint iMod(uint v, uint u, uint d)
{
    uint r = v - mul24(u, d);
    return (r);
}

__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);
    uint batch_id = iDiv(gbl_id0, MLO_MAP_SZ4); // batch
    uint pos      = iMod(gbl_id0, batch_id, MLO_MAP_SZ4);

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos * MLO_READ_UNIT;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        for(uint o = 0, wei_off1 = wei_off; o < MLO_N_LCL_OUT_MAPS; ++o,
                 wei_off1 +=
#if MLO_DIR_FORWARD == 1
                                                                    MLO_WEI_BSTRIDE
#else
                                                                    MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            for(uint c = 0, wei_off2 = wei_off1; c < MLO_N_LCL_IN_MAPS; ++c,
                     wei_off2 +=
#if MLO_DIR_FORWARD == 1
                                                                        MLO_WEI_CHANNEL_STRIDE
#else
                                                                        MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = wei_ptr[wei_off2];
            }
        }

        // convolve with all weights
        // read data
        for(uint j = 0, gbl_in_off1 = gbl_in_off; j < MLO_N_LCL_IN_MAPS;
            ++j, gbl_in_off1 += MLO_IN_CHANNEL_STRIDE)
        {
            for(uint i = 0; i < MLO_READ_UNIT; ++i)
            {
                dat[j][i] = in_ptr[gbl_in_off1 + i];
            }
        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
                }
            }
        }
    }

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + pos * MLO_READ_UNIT + out_id * MLO_OUT_CHANNEL_STRIDE;
    for(uint o = 0, gbl_out_off1 = gbl_out_off; o < MLO_N_LCL_OUT_MAPS;
        ++o, gbl_out_off1 += MLO_OUT_CHANNEL_STRIDE)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            out_ptr[gbl_out_off1 + i] = accum[o][i];
        }
    }
}

/************************************************************************
stride and padding
*************************************************************************/
__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1pquv(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);

    uint batch_id = iDiv(gbl_id0, MLO_MAP_SZ4); // batch
    uint pos      = iMod(gbl_id0, batch_id, MLO_MAP_SZ4);
	uint pos_out_y    = iDiv(pos, MLO_OUT_WIDTH4);
	uint pos_out_x    = iMod(pos, pos_out_y, MLO_OUT_WIDTH4);

#if MLO_DIR_FORWARD == 1
	uint pos_in_y = pos_out_y*MLO_FILTER_STRIDE1;
	uint pos_in_x = pos_out_x*MLO_FILTER_STRIDE0;
#else
	uint pos_in_y = pos_out_y/MLO_FILTER_STRIDE1;
	uint pos_in_x = pos_out_x; //MLO_FILTER_STRIDE0;  - divided already
#endif

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos_in_y*MLO_IN_STRIDE + pos_in_x * MLO_READ_UNIT;
//	bool vis = (pos_in_y < MLO_IN_HEIGHT);
//	gbl_in_off = (vis) ? gbl_in_off : 0;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        for(uint o = 0, wei_off1 = wei_off; o < MLO_N_LCL_OUT_MAPS; ++o,
                 wei_off1 +=
#if MLO_DIR_FORWARD == 1
                                                                    MLO_WEI_BSTRIDE
#else
                                                                    MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            for(uint c = 0, wei_off2 = wei_off1; c < MLO_N_LCL_IN_MAPS; ++c,
                     wei_off2 +=
#if MLO_DIR_FORWARD == 1
                                                                        MLO_WEI_CHANNEL_STRIDE
#else
                                                                        MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = wei_ptr[wei_off2];
            }
        }

        // convolve with all weights
        // read data
        for(uint j = 0, gbl_in_off1 = gbl_in_off; j < MLO_N_LCL_IN_MAPS;
            ++j, gbl_in_off1 += MLO_IN_CHANNEL_STRIDE)
        {
			uint i = 0;
#if MLO_READ_UNIT > 1
            for(; i < MLO_READ_UNIT - 1; ++i)
            {
				uint off = gbl_in_off1 + i
#if MLO_DIR_FORWARD == 1
				*MLO_FILTER_STRIDE0
#endif
				;
                dat[j][i] = in_ptr[off];
            }
#endif

            for(; i < MLO_READ_UNIT; ++i)
            {
//				vis &= (pos_in_x + i*MLO_FILTER_STRIDE0 < MLO_IN_WIDTH);
				uint off = gbl_in_off1 + i
#if MLO_DIR_FORWARD == 1
				*MLO_FILTER_STRIDE0
#endif
				;
//				off = (vis) ? off : 0;
				_FLOAT val = in_ptr[off];
                dat[j][i] = val;
//              dat[j][i] = (vis)? dat[j][i] : 0;

            }

        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
#if 1
				if (get_global_id(0) == 1 && get_global_id(1) ==0 && o == 0 && i == 0)
				{
					printf((__constant char *)"K:c: %f %f %f %f\n",
					accum[o][i],
					dat[c][i] * weights[o][c],
					dat[c][i],
					weights[o][c]
					);
				}
#endif

                }
            }
        }
    }

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + out_id * MLO_OUT_CHANNEL_STRIDE + pos_out_y * MLO_OUT_STRIDE
		+ pos_out_x * MLO_READ_UNIT
#if MLO_DIR_FORWARD == 0
        * MLO_FILTER_STRIDE0
#endif
		;
    for(uint o = 0, gbl_out_off1 = gbl_out_off; o < MLO_N_LCL_OUT_MAPS;
        ++o, gbl_out_off1 += MLO_OUT_CHANNEL_STRIDE)
    {

        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
			uint out_off = gbl_out_off1 + i
#if MLO_DIR_FORWARD == 0
				*MLO_FILTER_STRIDE0
#endif
			;
            out_ptr[out_off] = accum[o][i];
#if MLO_DIR_FORWARD == 0
			for(uint s = 1; s < MLO_FILTER_STRIDE0; ++s)
			{
				out_ptr[out_off + s ] = 0;
			}
#endif
        }

#if MLO_DIR_FORWARD == 0
		for(uint j = 1; j < MLO_FILTER_STRIDE1; ++j)
		{
			uint out_off = gbl_out_off1 + j*MLO_OUT_STRIDE;
			for(uint s = 0; s < MLO_READ_UNIT* MLO_FILTER_STRIDE0; ++s)
			{
				out_ptr[out_off + s ] = 0;
			}

		}
#endif
    }
}

/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#define _FLOAT float
#define _FLOAT2 float2
#define _FLOAT4 float4
#define _FLOAT8 float8

#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F /* max value */
#endif

#define UNUSED __attribute__((__unused__))

#define DBG_OUT_OF_RNGE 0

// calculating the size of the area for weights prefetch

__attribute__((always_inline)) uint iDiv(uint v, uint d)
{
    uint r = (uint)((float)v * (1.0f / (float)d) + 0.00001f);
    return (r);
}

__attribute__((always_inline)) uint iMod(uint v, uint u, uint d)
{
    uint r = v - mul24(u, d);
    return (r);
}

__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);
    uint batch_id = iDiv(gbl_id0, MLO_MAP_SZ4); // batch
    uint pos      = iMod(gbl_id0, batch_id, MLO_MAP_SZ4);

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos * MLO_READ_UNIT;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        for(uint o = 0, wei_off1 = wei_off; o < MLO_N_LCL_OUT_MAPS; ++o,
                 wei_off1 +=
#if MLO_DIR_FORWARD == 1
                                                                    MLO_WEI_BSTRIDE
#else
                                                                    MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            for(uint c = 0, wei_off2 = wei_off1; c < MLO_N_LCL_IN_MAPS; ++c,
                     wei_off2 +=
#if MLO_DIR_FORWARD == 1
                                                                        MLO_WEI_CHANNEL_STRIDE
#else
                                                                        MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = wei_ptr[wei_off2];
            }
        }

        // convolve with all weights
        // read data
        for(uint j = 0, gbl_in_off1 = gbl_in_off; j < MLO_N_LCL_IN_MAPS;
            ++j, gbl_in_off1 += MLO_IN_CHANNEL_STRIDE)
        {
            for(uint i = 0; i < MLO_READ_UNIT; ++i)
            {
                dat[j][i] = in_ptr[gbl_in_off1 + i];
            }
        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
                }
            }
        }
    }

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + pos * MLO_READ_UNIT + out_id * MLO_OUT_CHANNEL_STRIDE;
    for(uint o = 0, gbl_out_off1 = gbl_out_off; o < MLO_N_LCL_OUT_MAPS;
        ++o, gbl_out_off1 += MLO_OUT_CHANNEL_STRIDE)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            out_ptr[gbl_out_off1 + i] = accum[o][i];
        }
    }
}

/************************************************************************
stride and padding
*************************************************************************/
__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1pquv(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);

    uint batch_id = iDiv(gbl_id0, MLO_MAP_SZ4); // batch
    uint pos      = iMod(gbl_id0, batch_id, MLO_MAP_SZ4);
	uint pos_out_y    = iDiv(pos, MLO_OUT_WIDTH4);
	uint pos_out_x    = iMod(pos, pos_out_y, MLO_OUT_WIDTH4);

#if MLO_DIR_FORWARD == 1
	uint pos_in_y = pos_out_y*MLO_FILTER_STRIDE1;
	uint pos_in_x = pos_out_x*MLO_FILTER_STRIDE0;
#else
	uint pos_in_y = pos_out_y/MLO_FILTER_STRIDE1;
	uint pos_in_x = pos_out_x; //MLO_FILTER_STRIDE0;  - divided already
#endif

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos_in_y*MLO_IN_STRIDE + pos_in_x * MLO_READ_UNIT;
//	bool vis = (pos_in_y < MLO_IN_HEIGHT);
//	gbl_in_off = (vis) ? gbl_in_off : 0;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        for(uint o = 0, wei_off1 = wei_off; o < MLO_N_LCL_OUT_MAPS; ++o,
                 wei_off1 +=
#if MLO_DIR_FORWARD == 1
                                                                    MLO_WEI_BSTRIDE
#else
                                                                    MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            for(uint c = 0, wei_off2 = wei_off1; c < MLO_N_LCL_IN_MAPS; ++c,
                     wei_off2 +=
#if MLO_DIR_FORWARD == 1
                                                                        MLO_WEI_CHANNEL_STRIDE
#else
                                                                        MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = wei_ptr[wei_off2];
            }
        }

        // convolve with all weights
        // read data
        for(uint j = 0, gbl_in_off1 = gbl_in_off; j < MLO_N_LCL_IN_MAPS;
            ++j, gbl_in_off1 += MLO_IN_CHANNEL_STRIDE)
        {
			uint i = 0;
#if MLO_READ_UNIT > 1
            for(; i < MLO_READ_UNIT - 1; ++i)
            {
				uint off = gbl_in_off1 + i
#if MLO_DIR_FORWARD == 1
				*MLO_FILTER_STRIDE0
#endif
				;
                dat[j][i] = in_ptr[off];
            }
#endif

            for(; i < MLO_READ_UNIT; ++i)
            {
//				vis &= (pos_in_x + i*MLO_FILTER_STRIDE0 < MLO_IN_WIDTH);
				uint off = gbl_in_off1 + i
#if MLO_DIR_FORWARD == 1
				*MLO_FILTER_STRIDE0
#endif
				;
//				off = (vis) ? off : 0;
				_FLOAT val = in_ptr[off];
                dat[j][i] = val;
//              dat[j][i] = (vis)? dat[j][i] : 0;

            }

        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
#if 0
				if (get_global_id(0) == 2 && get_global_id(1) ==0 && o == 0 && i == 0)
				{
					printf((__constant char *)"K:c: %f %f %f %f\n",
					accum[o][i],
					dat[c][i] * weights[o][c],
					dat[c][i],
					weights[o][c]
					);
				}
#endif

                }
            }
        }
    }

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + out_id * MLO_OUT_CHANNEL_STRIDE + pos_out_y * MLO_OUT_STRIDE
		+ pos_out_x *MLO_FILTER_STRIDE0 * MLO_READ_UNIT
		;
    for(uint o = 0, gbl_out_off1 = gbl_out_off; o < MLO_N_LCL_OUT_MAPS;
        ++o, gbl_out_off1 += MLO_OUT_CHANNEL_STRIDE)
    {

        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
			uint out_off = gbl_out_off1 + i
#if MLO_DIR_FORWARD == 0
				*MLO_FILTER_STRIDE0
#endif
			;
            out_ptr[out_off] = accum[o][i];
#if MLO_DIR_FORWARD == 0
			for(uint s = 1; s < MLO_FILTER_STRIDE0; ++s)
			{
				out_ptr[out_off + s ] = 0;
			}
#endif
        }

#if MLO_DIR_FORWARD == 0
		for(uint j = 1; j < MLO_FILTER_STRIDE1; ++j)
		{
			uint out_off = gbl_out_off1 + j*MLO_OUT_STRIDE;
			for(uint s = 0; s < MLO_READ_UNIT* MLO_FILTER_STRIDE0; ++s)
			{
				out_ptr[out_off + s ] = 0;
			}

		}
#endif
    }
}


Revert "Added linking in bulitins to test_safeptr_builtin test, but for some reason name mangling does not to exact same result for builtin symbol names."

This reverts commit 05bd7344caeeb027a5f858cf592d4e572edc4069.

// RUN: $OCLANG $TEST_SRC -S -o $OUT_FILE.ll &&
// RUN: opt -load $CLAMP_PLUGIN -clamp-pointers -S $OUT_FILE.ll -o $OUT_FILE.clamped.ll &&
// RUN: echo "Checking that fully overflowing data is made safe" &&
// RUN: ($RUN_KERNEL $OUT_FILE.clamped.ll test_kernel 2 "(float,{1.0f,2.0f,3.0f,4.0f}):(int,4)" | grep "1: -42, -42, -42, -42") &&
// RUN: echo "Checking that original data is preserved when overflowing fully" &&
// RUN: ($RUN_KERNEL $OUT_FILE.clamped.ll test_kernel 2 "(float,{1.0f,2.0f,3.0f,4.0f}):(int,4)" | grep "0: 1, 2, 3, 4") &&
// RUN: echo "Checking that partially overflowing data is made safe" &&
// RUN: ($RUN_KERNEL $OUT_FILE.clamped.ll test_kernel 2 "(float,{1.0f,2.0f,3.0f,4.0f,6.0f}):(int,5)" | grep "1: -42, -42, -42, -42") &&
// RUN: echo "Checking that original data is preserved overflowing partially" &&
// RUN: ($RUN_KERNEL $OUT_FILE.clamped.ll test_kernel 2 "(float,{1.0f,2.0f,3.0f,4.0f,6.0f}):(int,5)" | grep "0: 1, 2, 3, 4") &&
// RUN: true

__kernel void test_kernel(__global float* in) {
  int i = get_global_id(0);
  float4 loaded = vload4(i, in);
  printf("%d: %d, %d, %d, %d\n", i, (int) loaded.s0, (int) loaded.s1, (int) loaded.s2, (int) loaded.s3);
}

// RUN: $OCLANG $TEST_SRC -S -o $OUT_FILE.ll &&
// RUN: opt -debug -load $CLAMP_PLUGIN -clamp-pointers -S $OUT_FILE.ll -o $OUT_FILE.clamped.ll &&
// RUN: echo "float4 _cl_overloadable vload4(long i, __global float* in) { return (float4)(in[i], in[i+1], in[i+2], in[i+3]); } IMPLEMENT_SAFE_VLOAD(float, __global, 4, (-42, -42, -42, -42) );" > vload4_builtins.cl &&
// RUN: $OCLANG vload4_builtins.cl -S -o vload4_builtins.ll &&
// RUN: llvm-link $OUT_FILE.clamped.ll vload4_builtins.ll -S -o $OUT_FILE.clamped.linked.ll &&
// RUN: echo "Checking that fully overflowing data is made safe" &&
// RUN: ($RUN_KERNEL $OUT_FILE.clamped.linked.ll test_kernel 2 "(float,{1.0f,2.0f,3.0f,4.0f}):(int,4)" | grep "1: -42, -42, -42, -42") &&
// RUN: echo "Checking that original data is preserved when overflowing fully" &&
// RUN: ($RUN_KERNEL $OUT_FILE.clamped.linked.ll test_kernel 2 "(float,{1.0f,2.0f,3.0f,4.0f}):(int,4)" | grep "0: 1, 2, 3, 4") &&
// RUN: echo "Checking that partially overflowing data is made safe" &&
// RUN: ($RUN_KERNEL $OUT_FILE.clamped.linked.ll test_kernel 2 "(float,{1.0f,2.0f,3.0f,4.0f,6.0f}):(int,5)" | grep "1: -42, -42, -42, -42") &&
// RUN: echo "Checking that original data is preserved overflowing partially" &&
// RUN: ($RUN_KERNEL $OUT_FILE.clamped.linked.ll test_kernel 2 "(float,{1.0f,2.0f,3.0f,4.0f,6.0f}):(int,5)" | grep "0: 1, 2, 3, 4") &&
// RUN: true

__kernel void test_kernel(__global float* in) {
  int i = get_global_id(0);
  float4 loaded = vload4(i, in);
  printf("%d: %d, %d, %d, %d\n", i, (int) loaded.s0, (int) loaded.s1, (int) loaded.s2, (int) loaded.s3);
}


rearranged

rearranged

/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#define _FLOAT float
#define _FLOAT2 float2
#define _FLOAT4 float4
#define _FLOAT8 float8

#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F /* max value */
#endif

#define UNUSED __attribute__((__unused__))

#define DBG_OUT_OF_RNGE 0

// calculating the size of the area for weights prefetch

__attribute__((always_inline)) uint iDiv(uint v, uint d)
{
    uint r = (uint)((float)v * (1.0f / (float)d) + 0.00001f);
    return (r);
}

__attribute__((always_inline)) uint iMod(uint v, uint u, uint d)
{
    uint r = v - mul24(u, d);
    return (r);
}

__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);
    uint batch_id = iDiv(gbl_id0, MLO_MAP_SZ4); // batch
    uint pos      = iMod(gbl_id0, batch_id, MLO_MAP_SZ4);

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos * MLO_READ_UNIT;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        for(uint o = 0, wei_off1 = wei_off; o < MLO_N_LCL_OUT_MAPS; ++o,
                 wei_off1 +=
#if MLO_DIR_FORWARD == 1
                                                                    MLO_WEI_BSTRIDE
#else
                                                                    MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            for(uint c = 0, wei_off2 = wei_off1; c < MLO_N_LCL_IN_MAPS; ++c,
                     wei_off2 +=
#if MLO_DIR_FORWARD == 1
                                                                        MLO_WEI_CHANNEL_STRIDE
#else
                                                                        MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = wei_ptr[wei_off2];
            }
        }

        // convolve with all weights
        // read data
        for(uint j = 0, gbl_in_off1 = gbl_in_off; j < MLO_N_LCL_IN_MAPS;
            ++j, gbl_in_off1 += MLO_IN_CHANNEL_STRIDE)
        {
            for(uint i = 0; i < MLO_READ_UNIT; ++i)
            {
                dat[j][i] = in_ptr[gbl_in_off1 + i];
            }
        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
                }
            }
        }
    }

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + pos * MLO_READ_UNIT + out_id * MLO_OUT_CHANNEL_STRIDE;
    for(uint o = 0, gbl_out_off1 = gbl_out_off; o < MLO_N_LCL_OUT_MAPS;
        ++o, gbl_out_off1 += MLO_OUT_CHANNEL_STRIDE)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            out_ptr[gbl_out_off1 + i] = accum[o][i];
        }
    }
}

/************************************************************************
stride and padding
*************************************************************************/
__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1pquv(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);

    uint batch_id = iDiv(gbl_id0, MLO_MAP_SZ4); // batch
    uint pos      = iMod(gbl_id0, batch_id, MLO_MAP_SZ4);
	uint pos_out_y    = iDiv(pos, MLO_OUT_WIDTH4);
	uint pos_out_x    = iMod(pos, pos_out_y, MLO_OUT_WIDTH4);

#if MLO_DIR_FORWARD == 1
	uint pos_in_y = pos_out_y*MLO_FILTER_STRIDE1;
	uint pos_in_x = pos_out_x*MLO_FILTER_STRIDE0;
#else
	uint pos_in_y = pos_out_y; ///MLO_FILTER_STRIDE1;   - divided already
	uint pos_in_x = pos_out_x; //MLO_FILTER_STRIDE0;  - divided already
#endif

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos_in_y*MLO_IN_STRIDE + pos_in_x * MLO_READ_UNIT;
//	bool vis = (pos_in_y < MLO_IN_HEIGHT);
//	gbl_in_off = (vis) ? gbl_in_off : 0;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

	const __global _FLOAT* i_ptr = &in_ptr[gbl_in_off];
	__constant _FLOAT* w_ptr = &wei_ptr[wei_off];
    for(uint ci = 0; ci < MLO_CLOOP0; ++ci)
    {

        // convolve with all weights
        // read data

        for(uint j = 0; j < MLO_N_LCL_IN_MAPS; ++j)
        {
			uint i = 0;
#if MLO_READ_UNIT > 1
            for(; i < MLO_READ_UNIT - 1; ++i)
            {
				uint off = i
#if MLO_DIR_FORWARD == 1
				*MLO_FILTER_STRIDE0
#endif
				;
                dat[j][i] = i_ptr[off];
            }
#endif

            for(; i < MLO_READ_UNIT; ++i)
            {
//				vis &= (pos_in_x + i*MLO_FILTER_STRIDE0 < MLO_IN_WIDTH);
				uint off = i
#if MLO_DIR_FORWARD == 1
				*MLO_FILTER_STRIDE0
#endif
				;
//				off = (vis) ? off : 0;
				_FLOAT val = i_ptr[off];
                dat[j][i] = val;
//              dat[j][i] = (vis)? dat[j][i] : 0;

            }

			i_ptr += MLO_IN_CHANNEL_STRIDE;

        }
        // read weights
		__constant _FLOAT* w_ptr0 = w_ptr;

        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {

			__constant _FLOAT* w_ptr1 = w_ptr0;

            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c
                )
            {
                weights[o][c] = *w_ptr1;
				w_ptr1 +=
#if MLO_DIR_FORWARD == 1
                                                                        MLO_WEI_CHANNEL_STRIDE
#else
                                                                        MLO_WEI_BSTRIDE
#endif
					;
            }

			w_ptr0 +=
#if MLO_DIR_FORWARD == 1
                                                                    MLO_WEI_BSTRIDE
#else
                                                                    MLO_WEI_CHANNEL_STRIDE
#endif
				;
        }

		w_ptr  += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
		;
        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
#if 0
				if (get_global_id(0) == 4 && get_global_id(1) ==0 && o == 0 && i == 0)
				{
					printf((__constant char *)"K:c: %f %f %f %f\n",
					accum[o][i],
					dat[c][i] * weights[o][c],
					dat[c][i],
					weights[o][c]
					);
				}
#endif

                }
            }
        }
    }

	uint out_y = pos_out_y
#if MLO_DIR_FORWARD == 0
		* MLO_FILTER_STRIDE1
#endif
	;
	uint out_x =  pos_out_x
#if MLO_DIR_FORWARD == 0
        * MLO_FILTER_STRIDE0
#endif
	;

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + out_id * MLO_OUT_CHANNEL_STRIDE + out_y * MLO_OUT_STRIDE + out_x * MLO_READ_UNIT;

    for(uint o = 0, gbl_out_off1 = gbl_out_off; o < MLO_N_LCL_OUT_MAPS;
        ++o, gbl_out_off1 += MLO_OUT_CHANNEL_STRIDE)
    {

        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
			uint out_off = gbl_out_off1 + i
#if MLO_DIR_FORWARD == 0
				*MLO_FILTER_STRIDE0
#endif
			;
            out_ptr[out_off] = accum[o][i];

#if MLO_DIR_FORWARD == 0
			for(uint s = 1; s < MLO_FILTER_STRIDE0; ++s)
			{
#if MLO_HORIZ_ALIGNED == 0
				if ( out_x  + s < MLO_OUT_WIDTH)
#endif
				{
					out_ptr[out_off + s ] = 0;
				}
			}
#endif
        }

#if MLO_DIR_FORWARD == 0
		for(uint j = 1; j < MLO_FILTER_STRIDE1; ++j)
		{
#if MLO_VERT_ALIGNED == 0
			if ( out_y  + j < MLO_OUT_HEIGHT)
#endif
			{
				uint out_off = gbl_out_off1 + j*MLO_OUT_STRIDE;
				for(uint s = 0; s < MLO_READ_UNIT* MLO_FILTER_STRIDE0; ++s)
				{
#if MLO_HORIZ_ALIGNED == 0
					if ( out_x  + s < MLO_OUT_WIDTH)
#endif
					{
						out_ptr[out_off + s ] = 0;
					}
				}
			}
		}
#endif
    }
}

/*******************************************************************************
 *
 * MIT License
 *
 * Copyright (c) 2017 Advanced Micro Devices, Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 *******************************************************************************/

#define _FLOAT float
#define _FLOAT2 float2
#define _FLOAT4 float4
#define _FLOAT8 float8

#ifndef FLT_MAX
#define FLT_MAX 3.402823466e+38F /* max value */
#endif

#define UNUSED __attribute__((__unused__))

#define DBG_OUT_OF_RNGE 0

// calculating the size of the area for weights prefetch

__attribute__((always_inline)) uint iDiv(uint v, uint d)
{
    uint r = (uint)((float)v * (1.0f / (float)d) + 0.00001f);
    return (r);
}

__attribute__((always_inline)) uint iMod(uint v, uint u, uint d)
{
    uint r = v - mul24(u, d);
    return (r);
}

__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);
    uint batch_id = iDiv(gbl_id0, MLO_MAP_SZ4); // batch
    uint pos      = iMod(gbl_id0, batch_id, MLO_MAP_SZ4);

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos * MLO_READ_UNIT;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        for(uint o = 0, wei_off1 = wei_off; o < MLO_N_LCL_OUT_MAPS; ++o,
                 wei_off1 +=
#if MLO_DIR_FORWARD == 1
                                                                    MLO_WEI_BSTRIDE
#else
                                                                    MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            for(uint c = 0, wei_off2 = wei_off1; c < MLO_N_LCL_IN_MAPS; ++c,
                     wei_off2 +=
#if MLO_DIR_FORWARD == 1
                                                                        MLO_WEI_CHANNEL_STRIDE
#else
                                                                        MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = wei_ptr[wei_off2];
            }
        }

        // convolve with all weights
        // read data
        for(uint j = 0, gbl_in_off1 = gbl_in_off; j < MLO_N_LCL_IN_MAPS;
            ++j, gbl_in_off1 += MLO_IN_CHANNEL_STRIDE)
        {
            for(uint i = 0; i < MLO_READ_UNIT; ++i)
            {
                dat[j][i] = in_ptr[gbl_in_off1 + i];
            }
        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
                }
            }
        }
    }

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + pos * MLO_READ_UNIT + out_id * MLO_OUT_CHANNEL_STRIDE;
    for(uint o = 0, gbl_out_off1 = gbl_out_off; o < MLO_N_LCL_OUT_MAPS;
        ++o, gbl_out_off1 += MLO_OUT_CHANNEL_STRIDE)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            out_ptr[gbl_out_off1 + i] = accum[o][i];
        }
    }
}

/************************************************************************
stride and padding
*************************************************************************/
__attribute__((reqd_work_group_size(MLO_GRP_SZ0, MLO_GRP_SZ1, MLO_GRP_SZ2))) __kernel void
MIOpenConv1x1pquv(const __global _FLOAT* __restrict in_ptr,
              __constant _FLOAT* __restrict wei_ptr,
#if MLO_CONV_BIAS
              const __global _FLOAT* __restrict bias,
#endif
              __global _FLOAT* __restrict out_ptr,
              UNUSED _FLOAT dummy_val // nothing
              )
{

    _FLOAT weights[MLO_N_LCL_OUT_MAPS][MLO_N_LCL_IN_MAPS];

    uint gbl_id0  = get_global_id(0);

    uint batch_id = iDiv(gbl_id0, MLO_MAP_SZ4); // batch
    uint pos      = iMod(gbl_id0, batch_id, MLO_MAP_SZ4);
	uint pos_out_y    = iDiv(pos, MLO_OUT_WIDTH4);
	uint pos_out_x    = iMod(pos, pos_out_y, MLO_OUT_WIDTH4);

#if MLO_DIR_FORWARD == 1
	uint pos_in_y = pos_out_y*MLO_FILTER_STRIDE1;
	uint pos_in_x = pos_out_x*MLO_FILTER_STRIDE0;
#else
	uint pos_in_y = pos_out_y; ///MLO_FILTER_STRIDE1;   - divided already
	uint pos_in_x = pos_out_x; //MLO_FILTER_STRIDE0;  - divided already
#endif

    uint out_grp_block = get_group_id(1); // block of outputs for the entire group
    uint out_id        = out_grp_block * MLO_N_LCL_OUT_MAPS;

    uint gbl_in_off = batch_id * MLO_IN_BATCH_STRIDE + pos_in_y*MLO_IN_STRIDE + pos_in_x * MLO_READ_UNIT;
//	bool vis = (pos_in_y < MLO_IN_HEIGHT);
//	gbl_in_off = (vis) ? gbl_in_off : 0;

    uint wei_off = out_id *
#if MLO_DIR_FORWARD == 1
                   MLO_WEI_BSTRIDE
#else
                   MLO_WEI_CHANNEL_STRIDE
#endif
        ;

    _FLOAT accum[MLO_N_LCL_OUT_MAPS][MLO_READ_UNIT];
    _FLOAT dat[MLO_N_LCL_IN_MAPS][MLO_READ_UNIT];

    for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
    {
        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
            accum[o][i] = 0;
        }
    }

    for(uint ci = 0; ci < MLO_CLOOP0; ++ci,
             // move input offset
                                      gbl_in_off += MLO_N_LCL_IN_MAPS * MLO_IN_CHANNEL_STRIDE,

             // move weights offset
                                      wei_off += MLO_N_LCL_IN_MAPS *
#if MLO_DIR_FORWARD == 1
                                                 MLO_WEI_CHANNEL_STRIDE
#else
                                                 MLO_WEI_BSTRIDE
#endif
        )
    {
        // read weights

        for(uint o = 0, wei_off1 = wei_off; o < MLO_N_LCL_OUT_MAPS; ++o,
                 wei_off1 +=
#if MLO_DIR_FORWARD == 1
                                                                    MLO_WEI_BSTRIDE
#else
                                                                    MLO_WEI_CHANNEL_STRIDE
#endif
            )
        {
            for(uint c = 0, wei_off2 = wei_off1; c < MLO_N_LCL_IN_MAPS; ++c,
                     wei_off2 +=
#if MLO_DIR_FORWARD == 1
                                                                        MLO_WEI_CHANNEL_STRIDE
#else
                                                                        MLO_WEI_BSTRIDE
#endif
                )
            {
                weights[o][c] = wei_ptr[wei_off2];
            }
        }

        // convolve with all weights
        // read data
        for(uint j = 0, gbl_in_off1 = gbl_in_off; j < MLO_N_LCL_IN_MAPS;
            ++j, gbl_in_off1 += MLO_IN_CHANNEL_STRIDE)
        {
			uint i = 0;
#if MLO_READ_UNIT > 1
            for(; i < MLO_READ_UNIT - 1; ++i)
            {
				uint off = gbl_in_off1 + i
#if MLO_DIR_FORWARD == 1
				*MLO_FILTER_STRIDE0
#endif
				;
                dat[j][i] = in_ptr[off];
            }
#endif

            for(; i < MLO_READ_UNIT; ++i)
            {
//				vis &= (pos_in_x + i*MLO_FILTER_STRIDE0 < MLO_IN_WIDTH);
				uint off = gbl_in_off1 + i
#if MLO_DIR_FORWARD == 1
				*MLO_FILTER_STRIDE0
#endif
				;
//				off = (vis) ? off : 0;
				_FLOAT val = in_ptr[off];
                dat[j][i] = val;
//              dat[j][i] = (vis)? dat[j][i] : 0;

            }

        }

        // convolve
        for(uint o = 0; o < MLO_N_LCL_OUT_MAPS; ++o)
        {
            for(uint c = 0; c < MLO_N_LCL_IN_MAPS; ++c)
            {
                for(uint i = 0; i < MLO_READ_UNIT; ++i)
                {
                    accum[o][i] += dat[c][i] * weights[o][c];
#if 0
				if (get_global_id(0) == 4 && get_global_id(1) ==0 && o == 0 && i == 0)
				{
					printf((__constant char *)"K:c: %f %f %f %f\n",
					accum[o][i],
					dat[c][i] * weights[o][c],
					dat[c][i],
					weights[o][c]
					);
				}
#endif

                }
            }
        }
    }

	uint out_y = pos_out_y
#if MLO_DIR_FORWARD == 0
		* MLO_FILTER_STRIDE1
#endif
	;
	uint out_x =  pos_out_x
#if MLO_DIR_FORWARD == 0
        * MLO_FILTER_STRIDE0
#endif
	;

    uint gbl_out_off =
        batch_id * MLO_OUT_BATCH_STRIDE + out_id * MLO_OUT_CHANNEL_STRIDE + out_y * MLO_OUT_STRIDE + out_x * MLO_READ_UNIT;

    for(uint o = 0, gbl_out_off1 = gbl_out_off; o < MLO_N_LCL_OUT_MAPS;
        ++o, gbl_out_off1 += MLO_OUT_CHANNEL_STRIDE)
    {

        for(uint i = 0; i < MLO_READ_UNIT; ++i)
        {
			uint out_off = gbl_out_off1 + i
#if MLO_DIR_FORWARD == 0
				*MLO_FILTER_STRIDE0
#endif
			;
            out_ptr[out_off] = accum[o][i];

#if MLO_DIR_FORWARD == 0
			for(uint s = 1; s < MLO_FILTER_STRIDE0; ++s)
			{
#if MLO_HORIZ_ALIGNED == 0
				if ( out_x  + s < MLO_OUT_WIDTH)
#endif
				{
					out_ptr[out_off + s ] = 0;
				}
			}
#endif
        }

#if MLO_DIR_FORWARD == 0
		for(uint j = 1; j < MLO_FILTER_STRIDE1; ++j)
		{
#if MLO_VERT_ALIGNED == 0
			if ( out_y  + j < MLO_OUT_HEIGHT)
#endif
			{
				uint out_off = gbl_out_off1 + j*MLO_OUT_STRIDE;
				for(uint s = 0; s < MLO_READ_UNIT* MLO_FILTER_STRIDE0; ++s)
				{
#if MLO_HORIZ_ALIGNED == 0
					if ( out_x  + s < MLO_OUT_WIDTH)
#endif
					{
						out_ptr[out_off + s ] = 0;
					}
				}
			}
		}
#endif
    }
}