sc/source/core/opencl/formulagroupcl.cxx  | 1088 +++++-------------------------
 sc/source/core/opencl/op_math.cxx         |  399 +++++++++++
 sc/source/core/opencl/op_math.hxx         |  253 ++++++
 sc/source/core/opencl/op_math_helpers.hxx |   76 ++
 sc/source/core/opencl/opbase.hxx          |  100 ++
 5 files changed, 1008 insertions(+), 908 deletions(-)

New commits:
commit bbc07c964ef9a4698b3867ff554259adcf81bc58
Author:     Luboš Luňák <l.lu...@collabora.com>
AuthorDate: Thu Sep 15 09:57:16 2022 +0200
Commit:     Luboš Luňák <l.lu...@collabora.com>
CommitDate: Mon Sep 19 17:29:58 2022 +0200

    move code out of formulagroupcl.cxx to op_math* and opbase*
    
    formulagroupcl.cxx is already large enough, move away code that
    implements some operations and also move some type declarations
    to a header.
    
    Change-Id: I28fe59275f4fb89c3e530d77b08e7f2fcad02781
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139971
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lu...@collabora.com>

diff --git a/sc/source/core/opencl/formulagroupcl.cxx 
b/sc/source/core/opencl/formulagroupcl.cxx
index 28b4c87fdb07..564ee9cc6393 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -14,7 +14,6 @@
 #include <tokenarray.hxx>
 #include <compiler.hxx>
 #include <comphelper/random.hxx>
-#include <formula/vectortoken.hxx>
 #include <scmatrix.hxx>
 #include <sal/log.hxx>
 
@@ -34,14 +33,6 @@
 
 #include <com/sun/star/sheet/FormulaLanguage.hpp>
 
-// FIXME: The idea that somebody would bother to (now and then? once a year? 
once a month?) manually
-// edit a source file and change the value of some #defined constant and run 
some ill-defined
-// "correctness test" is of course ludicrous. Either things are checked in 
normal unit tests, in
-// every 'make check', or not at all. The below comments are ridiculous.
-
-#define REDUCE_THRESHOLD 201  // set to 4 for correctness testing. priority 1
-#define UNROLLING_FACTOR 16  // set to 4 for correctness testing (if no reduce)
-
 const char* const publicFunc =
  "\n"
  "#define IllegalArgument 502\n"
@@ -61,76 +52,8 @@ const char* const publicFunc =
 // "    return nan(nErr);\n"
  "}\n"
  "\n"
- "uint GetDoubleErrorValue(double fVal)\n"
- "{\n"
- "    if (isfinite(fVal))\n"
- "        return 0;\n"
- "    if (isinf(fVal))\n"
- "        return IllegalFPOperation; // normal INF\n"
- "    if (as_ulong(fVal) & 0XFFFF0000u)\n"
- "        return NoValue;            // just a normal NAN\n"
- "    return (as_ulong(fVal) & 0XFFFF); // any other error\n"
- "}\n"
- "\n"
- "double fsum_count(double a, double b, __private int *p) {\n"
- "    bool t = isnan(a);\n"
- "    (*p) += t?0:1;\n"
- "    return t?b:a+b;\n"
- "}\n"
- "double fmin_count(double a, double b, __private int *p) {\n"
- "    double result = fmin(a, b);\n"
- "    bool t = isnan(result);\n"
- "    (*p) += t?0:1;\n"
- "    return result;\n"
- "}\n"
- "double fmax_count(double a, double b, __private int *p) {\n"
- "    double result = fmax(a, b);\n"
- "    bool t = isnan(result);\n"
- "    (*p) += t?0:1;\n"
- "    return result;\n"
- "}\n"
  "double fsum(double a, double b) { return isnan(a)?b:a+b; }\n"
  "double legalize(double a, double b) { return isnan(a)?b:a;}\n"
- "double fsub(double a, double b) { return a-b; }\n"
- "double fdiv(double a, double b) { return a/b; }\n"
- "int is_representable_integer(double a) {\n"
- "    long kMaxInt = (1L << 53) - 1;\n"
- "    if (a <= as_double(kMaxInt))\n"
- "    {\n"
- "        long nInt = as_long(a);\n"
- "        double fInt;\n"
- "        return (nInt <= kMaxInt &&\n"
- "                (!((fInt = as_double(nInt)) < a) && !(fInt > a)));\n"
- "    }\n"
- "    return 0;\n"
- "}\n"
- "int approx_equal(double a, double b) {\n"
- "    double e48 = 1.0 / (16777216.0 * 16777216.0);\n"
- "    double e44 = e48 * 16.0;\n"
- "    if (a == b)\n"
- "        return 1;\n"
- "    if (a == 0.0 || b == 0.0)\n"
- "        return 0;\n"
- "    double d = fabs(a - b);\n"
- "    if (!isfinite(d))\n"
- "        return 0;   // Nan or Inf involved\n"
- "    if (d > ((a = fabs(a)) * e44) || d > ((b = fabs(b)) * e44))\n"
- "        return 0;\n"
- "    if (is_representable_integer(d) && is_representable_integer(a) && 
is_representable_integer(b))\n"
- "        return 0;   // special case for representable integers.\n"
- "    return (d < a * e48 && d < b * e48);\n"
- "}\n"
- "double fsum_approx(double a, double b) {\n"
- "    if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0))\n"
- "         && approx_equal( a, -b ) )\n"
- "        return 0.0;\n"
- "    return a + b;\n"
- "}\n"
- "double fsub_approx(double a, double b) {\n"
- "    if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approx_equal( a, 
b ) )\n"
- "        return 0.0;\n"
- "    return a - b;\n"
- "}\n"
  ;
 
 #include <utility>
@@ -868,27 +791,6 @@ threefry2x32 (threefry2x32_ctr_t in, threefry2x32_key_t 
k)\n\
     }
 };
 
-/// A vector of strings
-class DynamicKernelStringArgument : public VectorRef
-{
-public:
-    DynamicKernelStringArgument( const ScCalcConfig& config, const 
std::string& s,
-        const FormulaTreeNodeRef& ft, int index = 0 ) :
-        VectorRef(config, s, ft, index) { }
-
-    virtual void GenSlidingWindowFunction( outputstream& ) override { }
-    /// Generate declaration
-    virtual void GenDecl( outputstream& ss ) const override
-    {
-        ss << "__global unsigned int *" << mSymName;
-    }
-    virtual void GenSlidingWindowDecl( outputstream& ss ) const override
-    {
-        DynamicKernelStringArgument::GenDecl(ss);
-    }
-    virtual size_t Marshal( cl_kernel, int, int, cl_program ) override;
-};
-
 }
 
 /// Marshal a string vector reference
@@ -1042,191 +944,174 @@ protected:
     DynamicKernelStringArgument mStringArgument;
 };
 
-/// Handling a Double Vector that is used as a sliding window input
-/// to either a sliding window average or sum-of-products
-/// Generate a sequential loop for reductions
+}
+
 template<class Base>
-class DynamicKernelSlidingArgument : public Base
+DynamicKernelSlidingArgument<Base>::DynamicKernelSlidingArgument(
+    const ScCalcConfig& config, const std::string& s, const 
FormulaTreeNodeRef& ft,
+    std::shared_ptr<SlidingFunctionBase> CodeGen, int index)
+    : Base(config, s, ft, index)
+    , mpCodeGen(std::move(CodeGen))
 {
-public:
-    DynamicKernelSlidingArgument(const ScCalcConfig& config, const 
std::string& s,
-                                 const FormulaTreeNodeRef& ft,
-                                 std::shared_ptr<SlidingFunctionBase> CodeGen, 
int index)
-        : Base(config, s, ft, index)
-        , mpCodeGen(std::move(CodeGen))
+    FormulaToken* t = ft->GetFormulaToken();
+    if (t->GetType() != formula::svDoubleVectorRef)
+        throw Unhandled(__FILE__, __LINE__);
+    mpDVR = static_cast<const formula::DoubleVectorRefToken*>(t);
+    bIsStartFixed = mpDVR->IsStartFixed();
+    bIsEndFixed = mpDVR->IsEndFixed();
+}
+
+template<class Base>
+bool DynamicKernelSlidingArgument<Base>::NeedParallelReduction() const
+{
+    assert(dynamic_cast<OpSumIfs*>(mpCodeGen.get()));
+    return GetWindowSize() > 100 &&
+           ((GetStartFixed() && GetEndFixed()) ||
+        (!GetStartFixed() && !GetEndFixed()));
+}
+
+template<class Base>
+std::string DynamicKernelSlidingArgument<Base>::GenSlidingWindowDeclRef( bool 
nested ) const
+{
+    size_t nArrayLength = mpDVR->GetArrayLength();
+    outputstream ss;
+    if (!bIsStartFixed && !bIsEndFixed)
     {
-        FormulaToken* t = ft->GetFormulaToken();
-        if (t->GetType() != formula::svDoubleVectorRef)
-            throw Unhandled(__FILE__, __LINE__);
-        mpDVR = static_cast<const formula::DoubleVectorRefToken*>(t);
-        bIsStartFixed = mpDVR->IsStartFixed();
-        bIsEndFixed = mpDVR->IsEndFixed();
+        if (nested)
+            ss << "((i+gid0) <" << nArrayLength << "?";
+        ss << Base::GetName() << "[i + gid0]";
+        if (nested)
+            ss << ":NAN)";
     }
-
-    // Should only be called by SumIfs. Yikes!
-    virtual bool NeedParallelReduction() const
+    else
     {
-        assert(dynamic_cast<OpSumIfs*>(mpCodeGen.get()));
-        return GetWindowSize() > 100 &&
-               ((GetStartFixed() && GetEndFixed()) ||
-            (!GetStartFixed() && !GetEndFixed()));
+        if (nested)
+            ss << "(i <" << nArrayLength << "?";
+        ss << Base::GetName() << "[i]";
+        if (nested)
+            ss << ":NAN)";
     }
+    return ss.str();
+}
 
-    virtual void GenSlidingWindowFunction( outputstream& ) { }
+template<class Base>
+size_t DynamicKernelSlidingArgument<Base>::GenReductionLoopHeader( 
outputstream& ss, bool& needBody )
+{
+    assert(mpDVR);
+    size_t nCurWindowSize = mpDVR->GetRefRowSize();
 
-    std::string GenSlidingWindowDeclRef( bool nested = false ) const
+    if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
     {
-        size_t nArrayLength = mpDVR->GetArrayLength();
-        outputstream ss;
-        if (!bIsStartFixed && !bIsEndFixed)
-        {
-            if (nested)
-                ss << "((i+gid0) <" << nArrayLength << "?";
-            ss << Base::GetName() << "[i + gid0]";
-            if (nested)
-                ss << ":NAN)";
-        }
-        else
-        {
-            if (nested)
-                ss << "(i <" << nArrayLength << "?";
-            ss << Base::GetName() << "[i]";
-            if (nested)
-                ss << ":NAN)";
-        }
-        return ss.str();
+        ss << "for (int i = ";
+        ss << "gid0; i < " << mpDVR->GetArrayLength();
+        ss << " && i < " << nCurWindowSize  << "; i++){\n\t\t";
+        needBody = true;
+        return nCurWindowSize;
     }
-    /// Controls how the elements in the DoubleVectorRef are traversed
-    size_t GenReductionLoopHeader(
-        outputstream& ss, bool& needBody )
+    else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
     {
-        assert(mpDVR);
-        size_t nCurWindowSize = mpDVR->GetRefRowSize();
-
+        ss << "for (int i = ";
+        ss << "0; i < " << mpDVR->GetArrayLength();
+        ss << " && i < gid0+" << nCurWindowSize << "; i++){\n\t\t";
+        needBody = true;
+        return nCurWindowSize;
+    }
+    else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+    {
+        ss << "tmpBottom = " << mpCodeGen->GetBottom() << ";\n\t";
+        ss << "{int i;\n\t";
+        outputstream temp1, temp2;
+        int outLoopSize = UNROLLING_FACTOR;
+        if (nCurWindowSize / outLoopSize != 0)
         {
-            if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
+            ss << "for(int outLoop=0; outLoop<" << nCurWindowSize / 
outLoopSize << "; outLoop++){\n\t";
+            for (int count = 0; count < outLoopSize; count++)
             {
-                ss << "for (int i = ";
-                ss << "gid0; i < " << mpDVR->GetArrayLength();
-                ss << " && i < " << nCurWindowSize  << "; i++){\n\t\t";
-                needBody = true;
-                return nCurWindowSize;
+                ss << "i = outLoop*" << outLoopSize << "+" << count << ";\n\t";
+                if (count == 0)
+                {
+                    temp1 << "if(i + gid0 < " << mpDVR->GetArrayLength();
+                    temp1 << "){\n\t\t";
+                    temp1 << "tmp = legalize(";
+                    temp1 <<  mpCodeGen->Gen2(GenSlidingWindowDeclRef(), 
"tmp");
+                    temp1 << ", tmp);\n\t\t\t";
+                    temp1 << "}\n\t";
+                }
+                ss << temp1.str();
             }
-            else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+            ss << "}\n\t";
+        }
+        // The residual of mod outLoopSize
+        for (size_t count = nCurWindowSize / outLoopSize * outLoopSize; count 
< nCurWindowSize; count++)
+        {
+            ss << "i = " << count << ";\n\t";
+            if (count == nCurWindowSize / outLoopSize * outLoopSize)
             {
-                ss << "for (int i = ";
-                ss << "0; i < " << mpDVR->GetArrayLength();
-                ss << " && i < gid0+" << nCurWindowSize << "; i++){\n\t\t";
-                needBody = true;
-                return nCurWindowSize;
+                temp2 << "if(i + gid0 < " << mpDVR->GetArrayLength();
+                temp2 << "){\n\t\t";
+                temp2 << "tmp = legalize(";
+                temp2 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp");
+                temp2 << ", tmp);\n\t\t\t";
+                temp2 << "}\n\t";
             }
-            else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+            ss << temp2.str();
+        }
+        ss << "}\n";
+        needBody = false;
+        return nCurWindowSize;
+    }
+    // (mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
+    else
+    {
+        ss << "\n\t";
+        ss << "tmpBottom = " << mpCodeGen->GetBottom() << ";\n\t";
+        ss << "{int i;\n\t";
+        outputstream temp1, temp2;
+        int outLoopSize = UNROLLING_FACTOR;
+        if (nCurWindowSize / outLoopSize != 0)
+        {
+            ss << "for(int outLoop=0; outLoop<" << nCurWindowSize / 
outLoopSize << "; outLoop++){\n\t";
+            for (int count = 0; count < outLoopSize; count++)
             {
-                ss << "tmpBottom = " << mpCodeGen->GetBottom() << ";\n\t";
-                ss << "{int i;\n\t";
-                outputstream temp1, temp2;
-                int outLoopSize = UNROLLING_FACTOR;
-                if (nCurWindowSize / outLoopSize != 0)
-                {
-                    ss << "for(int outLoop=0; outLoop<" << nCurWindowSize / 
outLoopSize << "; outLoop++){\n\t";
-                    for (int count = 0; count < outLoopSize; count++)
-                    {
-                        ss << "i = outLoop*" << outLoopSize << "+" << count << 
";\n\t";
-                        if (count == 0)
-                        {
-                            temp1 << "if(i + gid0 < " << 
mpDVR->GetArrayLength();
-                            temp1 << "){\n\t\t";
-                            temp1 << "tmp = legalize(";
-                            temp1 <<  
mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp");
-                            temp1 << ", tmp);\n\t\t\t";
-                            temp1 << "}\n\t";
-                        }
-                        ss << temp1.str();
-                    }
-                    ss << "}\n\t";
-                }
-                // The residual of mod outLoopSize
-                for (size_t count = nCurWindowSize / outLoopSize * 
outLoopSize; count < nCurWindowSize; count++)
+                ss << "i = outLoop*" << outLoopSize << "+" << count << ";\n\t";
+                if (count == 0)
                 {
-                    ss << "i = " << count << ";\n\t";
-                    if (count == nCurWindowSize / outLoopSize * outLoopSize)
-                    {
-                        temp2 << "if(i + gid0 < " << mpDVR->GetArrayLength();
-                        temp2 << "){\n\t\t";
-                        temp2 << "tmp = legalize(";
-                        temp2 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), 
"tmp");
-                        temp2 << ", tmp);\n\t\t\t";
-                        temp2 << "}\n\t";
-                    }
-                    ss << temp2.str();
+                    temp1 << "if(i < " << mpDVR->GetArrayLength();
+                    temp1 << "){\n\t\t";
+                    temp1 << "tmp = legalize(";
+                    temp1 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp");
+                    temp1 << ", tmp);\n\t\t\t";
+                    temp1 << "}\n\t";
                 }
-                ss << "}\n";
-                needBody = false;
-                return nCurWindowSize;
+                ss << temp1.str();
             }
-            // (mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
-            else
+            ss << "}\n\t";
+        }
+        // The residual of mod outLoopSize
+        for (size_t count = nCurWindowSize / outLoopSize * outLoopSize; count 
< nCurWindowSize; count++)
+        {
+            ss << "i = " << count << ";\n\t";
+            if (count == nCurWindowSize / outLoopSize * outLoopSize)
             {
-                ss << "\n\t";
-                ss << "tmpBottom = " << mpCodeGen->GetBottom() << ";\n\t";
-                ss << "{int i;\n\t";
-                outputstream temp1, temp2;
-                int outLoopSize = UNROLLING_FACTOR;
-                if (nCurWindowSize / outLoopSize != 0)
-                {
-                    ss << "for(int outLoop=0; outLoop<" << nCurWindowSize / 
outLoopSize << "; outLoop++){\n\t";
-                    for (int count = 0; count < outLoopSize; count++)
-                    {
-                        ss << "i = outLoop*" << outLoopSize << "+" << count << 
";\n\t";
-                        if (count == 0)
-                        {
-                            temp1 << "if(i < " << mpDVR->GetArrayLength();
-                            temp1 << "){\n\t\t";
-                            temp1 << "tmp = legalize(";
-                            temp1 << 
mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp");
-                            temp1 << ", tmp);\n\t\t\t";
-                            temp1 << "}\n\t";
-                        }
-                        ss << temp1.str();
-                    }
-                    ss << "}\n\t";
-                }
-                // The residual of mod outLoopSize
-                for (size_t count = nCurWindowSize / outLoopSize * 
outLoopSize; count < nCurWindowSize; count++)
-                {
-                    ss << "i = " << count << ";\n\t";
-                    if (count == nCurWindowSize / outLoopSize * outLoopSize)
-                    {
-                        temp2 << "if(i < " << mpDVR->GetArrayLength();
-                        temp2 << "){\n\t\t";
-                        temp2 << "tmp = legalize(";
-                        temp2 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), 
"tmp");
-                        temp2 << ", tmp);\n\t\t\t";
-                        temp2 << "}\n\t";
-                    }
-                    ss << temp2.str();
-                }
-                ss << "}\n";
-                needBody = false;
-                return nCurWindowSize;
+                temp2 << "if(i < " << mpDVR->GetArrayLength();
+                temp2 << "){\n\t\t";
+                temp2 << "tmp = legalize(";
+                temp2 << mpCodeGen->Gen2(GenSlidingWindowDeclRef(), "tmp");
+                temp2 << ", tmp);\n\t\t\t";
+                temp2 << "}\n\t";
             }
+            ss << temp2.str();
         }
+        ss << "}\n";
+        needBody = false;
+        return nCurWindowSize;
     }
+}
 
-    size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
-
-    size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
-
-    bool GetStartFixed() const { return bIsStartFixed; }
-
-    bool GetEndFixed() const { return bIsEndFixed; }
+template class DynamicKernelSlidingArgument<VectorRef>;
+template class DynamicKernelSlidingArgument<DynamicKernelStringArgument>;
 
-protected:
-    bool bIsStartFixed, bIsEndFixed;
-    const formula::DoubleVectorRefToken* mpDVR;
-    // from parent nodes
-    std::shared_ptr<SlidingFunctionBase> mpCodeGen;
-};
+namespace {
 
 /// A mixed string/numeric vector
 class DynamicKernelMixedSlidingArgument : public VectorRef
@@ -1320,8 +1205,6 @@ private:
     std::vector<DynamicKernelArgumentRef> mParams;
 };
 
-}
-
 void SymbolTable::Marshal( cl_kernel k, int nVectorWidth, cl_program pProgram )
 {
     int i = 1; //The first argument is reserved for results
@@ -1331,656 +1214,23 @@ void SymbolTable::Marshal( cl_kernel k, int 
nVectorWidth, cl_program pProgram )
     }
 }
 
-namespace {
+}
 
-/// Handling a Double Vector that is used as a sliding window input
-/// Performs parallel reduction based on given operator
 template<class Base>
-class ParallelReductionVectorRef : public Base
-{
-public:
-    ParallelReductionVectorRef(const ScCalcConfig& config, const std::string& 
s,
-                               const FormulaTreeNodeRef& ft,
-                               std::shared_ptr<SlidingFunctionBase> CodeGen, 
int index)
-        : Base(config, s, ft, index)
-        , mpCodeGen(std::move(CodeGen))
-        , mpClmem2(nullptr)
-    {
-        FormulaToken* t = ft->GetFormulaToken();
-        if (t->GetType() != formula::svDoubleVectorRef)
-            throw Unhandled(__FILE__, __LINE__);
-        mpDVR = static_cast<const formula::DoubleVectorRefToken*>(t);
-        bIsStartFixed = mpDVR->IsStartFixed();
-        bIsEndFixed = mpDVR->IsEndFixed();
-    }
-
-    /// Emit the definition for the auxiliary reduction kernel
-    virtual void GenSlidingWindowFunction( outputstream& ss );
-
-    virtual std::string GenSlidingWindowDeclRef( bool ) const
-    {
-        outputstream ss;
-        if (!bIsStartFixed && !bIsEndFixed)
-            ss << Base::GetName() << "[i + gid0]";
-        else
-            ss << Base::GetName() << "[i]";
-        return ss.str();
-    }
-
-    /// Controls how the elements in the DoubleVectorRef are traversed
-    size_t GenReductionLoopHeader(
-        outputstream& ss, int nResultSize, bool& needBody );
-
-    virtual size_t Marshal( cl_kernel k, int argno, int w, cl_program 
mpProgram );
-
-    ~ParallelReductionVectorRef()
-    {
-        if (mpClmem2)
-        {
-            cl_int err;
-            err = clReleaseMemObject(mpClmem2);
-            SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject 
failed: " << openclwrapper::errorString(err));
-            mpClmem2 = nullptr;
-        }
-    }
-
-    size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
-
-    size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
-
-    bool GetStartFixed() const { return bIsStartFixed; }
-
-    bool GetEndFixed() const { return bIsEndFixed; }
-
-protected:
-    bool bIsStartFixed, bIsEndFixed;
-    const formula::DoubleVectorRefToken* mpDVR;
-    // from parent nodes
-    std::shared_ptr<SlidingFunctionBase> mpCodeGen;
-    // controls whether to invoke the reduction kernel during marshaling or not
-    cl_mem mpClmem2;
-};
-
-class Reduction : public SlidingFunctionBase
-{
-    int mnResultSize;
-public:
-    explicit Reduction(int nResultSize) : mnResultSize(nResultSize) {}
-
-    typedef DynamicKernelSlidingArgument<VectorRef> NumericRange;
-    typedef DynamicKernelSlidingArgument<DynamicKernelStringArgument> 
StringRange;
-    typedef ParallelReductionVectorRef<VectorRef> ParallelNumericRange;
-
-    virtual bool HandleNaNArgument( outputstream&, unsigned, SubArguments& ) 
const
-    {
-        return false;
-    }
-
-    virtual void GenSlidingWindowFunction( outputstream& ss,
-        const std::string& sSymName, SubArguments& vSubArguments ) override
-    {
-        GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
-        ss << "{\n";
-        ss << "double tmp = " << GetBottom() << ";\n";
-        ss << "int gid0 = get_global_id(0);\n";
-        if (isAverage() || isMinOrMax())
-            ss << "int nCount = 0;\n";
-        ss << "double tmpBottom;\n";
-        unsigned i = vSubArguments.size();
-        while (i--)
-        {
-            if (NumericRange* NR =
-                dynamic_cast<NumericRange*>(vSubArguments[i].get()))
-            {
-                bool needBody;
-                NR->GenReductionLoopHeader(ss, needBody);
-                if (!needBody)
-                    continue;
-            }
-            else if (ParallelNumericRange* PNR =
-                dynamic_cast<ParallelNumericRange*>(vSubArguments[i].get()))
-            {
-                //did not handle yet
-                bool bNeedBody = false;
-                PNR->GenReductionLoopHeader(ss, mnResultSize, bNeedBody);
-                if (!bNeedBody)
-                    continue;
-            }
-            else if (StringRange* SR =
-                dynamic_cast<StringRange*>(vSubArguments[i].get()))
-            {
-                //did not handle yet
-                bool needBody;
-                SR->GenReductionLoopHeader(ss, needBody);
-                if (!needBody)
-                    continue;
-            }
-            else
-            {
-                FormulaToken* pCur = vSubArguments[i]->GetFormulaToken();
-                assert(pCur);
-                assert(pCur->GetType() != formula::svDoubleVectorRef);
-
-                if (pCur->GetType() == formula::svSingleVectorRef ||
-                    pCur->GetType() == formula::svDouble)
-                {
-                    ss << "{\n";
-                }
-            }
-            if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode())
-            {
-                bool bNanHandled = HandleNaNArgument(ss, i, vSubArguments);
-
-                ss << "tmpBottom = " << GetBottom() << ";\n";
-
-                if (!bNanHandled)
-                {
-                    ss << "if (isnan(";
-                    ss << vSubArguments[i]->GenSlidingWindowDeclRef();
-                    ss << "))\n";
-                    if (ZeroReturnZero())
-                        ss << "    return 0;\n";
-                    else
-                    {
-                        ss << "    tmp = ";
-                        ss << Gen2("tmpBottom", "tmp") << ";\n";
-                    }
-                    ss << "else\n";
-                }
-                ss << "{";
-                ss << "        tmp = ";
-                ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
-                ss << ";\n";
-                ss << "    }\n";
-                ss << "}\n";
-            }
-            else
-            {
-                ss << "tmp = ";
-                ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
-                ss << ";\n";
-            }
-        }
-        if (isAverage())
-            ss <<
-                "if (nCount==0)\n"
-                "    return CreateDoubleError(DivisionByZero);\n";
-        else if (isMinOrMax())
-            ss <<
-                "if (nCount==0)\n"
-                "    return 0;\n";
-        ss << "return tmp";
-        if (isAverage())
-            ss << "/(double)nCount";
-        ss << ";\n}";
-    }
-    virtual bool isAverage() const { return false; }
-    virtual bool isMinOrMax() const { return false; }
-    virtual bool takeString() const override { return false; }
-    virtual bool takeNumeric() const override { return true; }
-};
-
-// Strictly binary operators
-class Binary : public SlidingFunctionBase
-{
-public:
-    virtual void GenSlidingWindowFunction( outputstream& ss,
-        const std::string& sSymName, SubArguments& vSubArguments ) override
-    {
-        CHECK_PARAMETER_COUNT( 2, 2 );
-        GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
-        ss << "{\n\t";
-        ss << "int gid0 = get_global_id(0), i = 0;\n\t";
-        ss << "double tmp = ";
-        ss << Gen2(vSubArguments[0]->GenSlidingWindowDeclRef(),
-            vSubArguments[1]->GenSlidingWindowDeclRef()) << ";\n\t";
-        ss << "return tmp;\n}";
-    }
-    virtual bool takeString() const override { return false; }
-    virtual bool takeNumeric() const override { return true; }
-};
-
-class SumOfProduct : public SlidingFunctionBase
-{
-public:
-    virtual void GenSlidingWindowFunction( outputstream& ss,
-        const std::string& sSymName, SubArguments& vSubArguments ) override
-    {
-        size_t nCurWindowSize = 0;
-        FormulaToken* tmpCur = nullptr;
-        const formula::DoubleVectorRefToken* pCurDVR = nullptr;
-        GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
-        ss << "{\n";
-        for (size_t i = 0; i < vSubArguments.size(); i++)
-        {
-            size_t nCurChildWindowSize = vSubArguments[i]->GetWindowSize();
-            nCurWindowSize = (nCurWindowSize < nCurChildWindowSize) ?
-                nCurChildWindowSize : nCurWindowSize;
-            tmpCur = vSubArguments[i]->GetFormulaToken();
-            if (ocPush == tmpCur->GetOpCode())
-            {
-
-                pCurDVR = static_cast<const 
formula::DoubleVectorRefToken*>(tmpCur);
-                if (pCurDVR->IsStartFixed() != pCurDVR->IsEndFixed())
-                    throw Unhandled(__FILE__, __LINE__);
-            }
-        }
-        ss << "    double tmp = 0.0;\n";
-        ss << "    int gid0 = get_global_id(0);\n";
-
-        ss << "\tint i;\n\t";
-        ss << "int currentCount0;\n";
-        for (size_t i = 0; i < vSubArguments.size() - 1; i++)
-            ss << "int currentCount" << i + 1 << ";\n";
-        outputstream temp3, temp4;
-        int outLoopSize = UNROLLING_FACTOR;
-        if (nCurWindowSize / outLoopSize != 0)
-        {
-            ss << "for(int outLoop=0; outLoop<" <<
-                nCurWindowSize / outLoopSize << "; outLoop++){\n\t";
-            for (int count = 0; count < outLoopSize; count++)
-            {
-                ss << "i = outLoop*" << outLoopSize << "+" << count << ";\n";
-                if (count == 0)
-                {
-                    for (size_t i = 0; i < vSubArguments.size(); i++)
-                    {
-                        tmpCur = vSubArguments[i]->GetFormulaToken();
-                        if (ocPush == tmpCur->GetOpCode())
-                        {
-                            pCurDVR = static_cast<const 
formula::DoubleVectorRefToken*>(tmpCur);
-                            if (!pCurDVR->IsStartFixed() && 
!pCurDVR->IsEndFixed())
-                            {
-                                temp3 << "        currentCount";
-                                temp3 << i;
-                                temp3 << " =i+gid0+1;\n";
-                            }
-                            else
-                            {
-                                temp3 << "        currentCount";
-                                temp3 << i;
-                                temp3 << " =i+1;\n";
-                            }
-                        }
-                    }
-
-                    temp3 << "tmp = fsum(";
-                    for (size_t i = 0; i < vSubArguments.size(); i++)
-                    {
-                        if (i)
-                            temp3 << "*";
-                        if (ocPush == 
vSubArguments[i]->GetFormulaToken()->GetOpCode())
-                        {
-                            temp3 << "(";
-                            temp3 << "(currentCount";
-                            temp3 << i;
-                            temp3 << ">";
-                            if (vSubArguments[i]->GetFormulaToken()->GetType() 
==
-                                    formula::svSingleVectorRef)
-                            {
-                                const formula::SingleVectorRefToken* pSVR =
-                                    static_cast<const 
formula::SingleVectorRefToken*>
-                                    (vSubArguments[i]->GetFormulaToken());
-                                temp3 << pSVR->GetArrayLength();
-                                temp3 << ")||isnan(" << vSubArguments[i]
-                                    ->GenSlidingWindowDeclRef();
-                                temp3 << ")?0:";
-                                temp3 << 
vSubArguments[i]->GenSlidingWindowDeclRef();
-                                temp3  << ")";
-                            }
-                            else if 
(vSubArguments[i]->GetFormulaToken()->GetType() ==
-                                    formula::svDoubleVectorRef)
-                            {
-                                const formula::DoubleVectorRefToken* pSVR =
-                                    static_cast<const 
formula::DoubleVectorRefToken*>
-                                    (vSubArguments[i]->GetFormulaToken());
-                                temp3 << pSVR->GetArrayLength();
-                                temp3 << ")||isnan(" << vSubArguments[i]
-                                    ->GenSlidingWindowDeclRef(true);
-                                temp3 << ")?0:";
-                                temp3 << 
vSubArguments[i]->GenSlidingWindowDeclRef(true);
-                                temp3  << ")";
-                            }
-
-                        }
-                        else
-                            temp3 << 
vSubArguments[i]->GenSlidingWindowDeclRef(true);
-                    }
-                    temp3 << ", tmp);\n\t";
-                }
-                ss << temp3.str();
-            }
-            ss << "}\n\t";
-        }
-        //The residual of mod outLoopSize
-        for (size_t count = nCurWindowSize / outLoopSize * outLoopSize;
-            count < nCurWindowSize; count++)
-        {
-            ss << "i =" << count << ";\n";
-            if (count == nCurWindowSize / outLoopSize * outLoopSize)
-            {
-                for (size_t i = 0; i < vSubArguments.size(); i++)
-                {
-                    tmpCur = vSubArguments[i]->GetFormulaToken();
-                    if (ocPush == tmpCur->GetOpCode())
-                    {
-                        pCurDVR = static_cast<const 
formula::DoubleVectorRefToken*>(tmpCur);
-                        if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
-                        {
-                            temp4 << "        currentCount";
-                            temp4 << i;
-                            temp4 << " =i+gid0+1;\n";
-                        }
-                        else
-                        {
-                            temp4 << "        currentCount";
-                            temp4 << i;
-                            temp4 << " =i+1;\n";
-                        }
-                    }
-                }
-
-                temp4 << "tmp = fsum(";
-                for (size_t i = 0; i < vSubArguments.size(); i++)
-                {
-                    if (i)
-                        temp4 << "*";
-                    if (ocPush == 
vSubArguments[i]->GetFormulaToken()->GetOpCode())
-                    {
-                        temp4 << "(";
-                        temp4 << "(currentCount";
-                        temp4 << i;
-                        temp4 << ">";
-                        if (vSubArguments[i]->GetFormulaToken()->GetType() ==
-                                formula::svSingleVectorRef)
-                        {
-                            const formula::SingleVectorRefToken* pSVR =
-                                static_cast<const 
formula::SingleVectorRefToken*>
-                                (vSubArguments[i]->GetFormulaToken());
-                            temp4 << pSVR->GetArrayLength();
-                            temp4 << ")||isnan(" << vSubArguments[i]
-                                ->GenSlidingWindowDeclRef();
-                            temp4 << ")?0:";
-                            temp4 << 
vSubArguments[i]->GenSlidingWindowDeclRef();
-                            temp4  << ")";
-                        }
-                        else if 
(vSubArguments[i]->GetFormulaToken()->GetType() ==
-                                formula::svDoubleVectorRef)
-                        {
-                            const formula::DoubleVectorRefToken* pSVR =
-                                static_cast<const 
formula::DoubleVectorRefToken*>
-                                (vSubArguments[i]->GetFormulaToken());
-                            temp4 << pSVR->GetArrayLength();
-                            temp4 << ")||isnan(" << vSubArguments[i]
-                                ->GenSlidingWindowDeclRef(true);
-                            temp4 << ")?0:";
-                            temp4 << 
vSubArguments[i]->GenSlidingWindowDeclRef(true);
-                            temp4  << ")";
-                        }
-
-                    }
-                    else
-                    {
-                        temp4 << vSubArguments[i]
-                            ->GenSlidingWindowDeclRef(true);
-                    }
-                }
-                temp4 << ", tmp);\n\t";
-            }
-            ss << temp4.str();
-        }
-        ss << "return tmp;\n";
-        ss << "}";
-    }
-    virtual bool takeString() const override { return false; }
-    virtual bool takeNumeric() const override { return true; }
-};
-
-/// operator traits
-class OpNop : public Reduction
-{
-public:
-    explicit OpNop(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& ) 
const override
-    {
-        return lhs;
-    }
-    virtual std::string BinFuncName() const override { return "nop"; }
-};
-
-class OpCount : public Reduction
-{
-public:
-    explicit OpCount(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "(isnan(" << lhs << ")?" << rhs << ":" << rhs << "+1.0)";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "fcount"; }
-    virtual bool canHandleMultiVector() const override { return true; }
-};
-
-class OpEqual : public Binary
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "approx_equal(" << lhs << "," << rhs << ")";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "eq"; }
-};
-
-class OpNotEqual : public Binary
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "!approx_equal(" << lhs << "," << rhs << ")";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "neq"; }
-};
-
-class OpLessEqual : public Binary
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "(approx_equal(" << lhs << "," << rhs << ") || " << lhs << "<=" 
<< rhs << ")";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "le"; }
-};
-
-class OpLess : public Binary
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "(" << lhs << "<" << rhs << ")";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "lt"; }
-};
-
-class OpGreater : public Binary
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "(" << lhs << ">" << rhs << ")";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "gt"; }
-};
-
-class OpGreaterEqual : public Binary
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "(approx_equal(" << lhs << "," << rhs << ") || " << lhs << ">=" 
<< rhs << ")";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "ge"; }
-};
-
-class OpSum : public Reduction
-{
-public:
-    explicit OpSum(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "fsum_approx((" << lhs << "),(" << rhs << "))";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "fsum"; }
-    // All arguments are simply summed, so it doesn't matter if SvDoubleVector 
is split.
-    virtual bool canHandleMultiVector() const override { return true; }
-};
-
-class OpAverage : public Reduction
-{
-public:
-    explicit OpAverage(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        outputstream ss;
-        ss << "fsum_count(" << lhs << "," << rhs << ", &nCount)";
-        return ss.str();
-    }
-    virtual std::string BinFuncName() const override { return "average"; }
-    virtual bool isAverage() const override { return true; }
-    virtual bool canHandleMultiVector() const override { return true; }
-};
-
-class OpSub : public Reduction
-{
-public:
-    explicit OpSub(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        return "fsub_approx(" + lhs + "," + rhs + ")";
-    }
-    virtual std::string BinFuncName() const override { return "fsub"; }
-};
-
-class OpMul : public Reduction
-{
-public:
-    explicit OpMul(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "1"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        return lhs + "*" + rhs;
-    }
-    virtual std::string BinFuncName() const override { return "fmul"; }
-    virtual bool ZeroReturnZero() override { return true; }
-};
-
-/// Technically not a reduction, but fits the framework.
-class OpDiv : public Reduction
-{
-public:
-    explicit OpDiv(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "1.0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        return "(" + rhs + "==0 ? CreateDoubleError(DivisionByZero) : (" + lhs 
+ "/" + rhs + ") )";
-    }
-    virtual std::string BinFuncName() const override { return "fdiv"; }
-
-    virtual bool HandleNaNArgument( outputstream& ss, unsigned argno, 
SubArguments& vSubArguments ) const override
-    {
-        if (argno == 1)
-        {
-            ss <<
-                "if (isnan(" << 
vSubArguments[argno]->GenSlidingWindowDeclRef() << ")) {\n"
-                "    return CreateDoubleError(DivisionByZero);\n"
-                "}\n";
-            return true;
-        }
-        else if (argno == 0)
-        {
-            ss <<
-                "if (isnan(" << 
vSubArguments[argno]->GenSlidingWindowDeclRef() << ") &&\n"
-                "    !(isnan(" << vSubArguments[1]->GenSlidingWindowDeclRef() 
<< ") || " << vSubArguments[1]->GenSlidingWindowDeclRef() << " == 0)) {\n"
-                "    return 0;\n"
-                "}\n";
-        }
-        return false;
-    }
-
-};
-
-class OpMin : public Reduction
+ParallelReductionVectorRef<Base>::ParallelReductionVectorRef(
+    const ScCalcConfig& config, const std::string& s, const 
FormulaTreeNodeRef& ft,
+    std::shared_ptr<SlidingFunctionBase> CodeGen, int index)
+    : Base(config, s, ft, index)
+    , mpCodeGen(std::move(CodeGen))
+    , mpClmem2(nullptr)
 {
-public:
-    explicit OpMin(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "NAN"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        return "fmin_count(" + lhs + "," + rhs + ", &nCount)";
-    }
-    virtual std::string BinFuncName() const override { return "min"; }
-    virtual bool isMinOrMax() const override { return true; }
-    virtual bool canHandleMultiVector() const override { return true; }
-};
-
-class OpMax : public Reduction
-{
-public:
-    explicit OpMax(int nResultSize) : Reduction(nResultSize) {}
-
-    virtual std::string GetBottom() override { return "NAN"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        return "fmax_count(" + lhs + "," + rhs + ", &nCount)";
-    }
-    virtual std::string BinFuncName() const override { return "max"; }
-    virtual bool isMinOrMax() const override { return true; }
-    virtual bool canHandleMultiVector() const override { return true; }
-};
-
-class OpSumProduct : public SumOfProduct
-{
-public:
-    virtual std::string GetBottom() override { return "0"; }
-    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
-    {
-        return lhs + "*" + rhs;
-    }
-    virtual std::string BinFuncName() const override { return "fsop"; }
-};
+    FormulaToken* t = ft->GetFormulaToken();
+    if (t->GetType() != formula::svDoubleVectorRef)
+        throw Unhandled(__FILE__, __LINE__);
+    mpDVR = static_cast<const formula::DoubleVectorRefToken*>(t);
+    bIsStartFixed = mpDVR->IsStartFixed();
+    bIsEndFixed = mpDVR->IsEndFixed();
+}
 
 template<class Base>
 void ParallelReductionVectorRef<Base>::GenSlidingWindowFunction( outputstream& 
ss )
@@ -2160,7 +1410,17 @@ void 
ParallelReductionVectorRef<Base>::GenSlidingWindowFunction( outputstream& s
         ss << "        result[writePos] = current_result;\n";
         ss << "}\n";
     }
+}
 
+template<class Base>
+std::string ParallelReductionVectorRef<Base>::GenSlidingWindowDeclRef( bool ) 
const
+{
+    outputstream ss;
+    if (!bIsStartFixed && !bIsEndFixed)
+        ss << Base::GetName() << "[i + gid0]";
+    else
+        ss << Base::GetName() << "[i]";
+    return ss.str();
 }
 
 template<class Base>
@@ -2356,6 +1616,22 @@ size_t ParallelReductionVectorRef<Base>::Marshal( 
cl_kernel k, int argno, int w,
     return 1;
 }
 
+template<class Base>
+ParallelReductionVectorRef<Base>::~ParallelReductionVectorRef()
+{
+    if (mpClmem2)
+    {
+        cl_int err;
+        err = clReleaseMemObject(mpClmem2);
+        SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject 
failed: " << openclwrapper::errorString(err));
+        mpClmem2 = nullptr;
+    }
+}
+
+template class ParallelReductionVectorRef<VectorRef>;
+
+namespace {
+
 struct SumIfsArgs
 {
     explicit SumIfsArgs(cl_mem x) : mCLMem(x), mConst(0.0) { }
diff --git a/sc/source/core/opencl/op_math.cxx 
b/sc/source/core/opencl/op_math.cxx
index 82452b181899..7c501fc1e5f7 100644
--- a/sc/source/core/opencl/op_math.cxx
+++ b/sc/source/core/opencl/op_math.cxx
@@ -217,6 +217,15 @@ void OpLn::GenerateCode( outputstream& ss ) const
     ss << "    return log1p(arg0-1);\n";
 }
 
+void OpInt::BinInlineFun(std::set<std::string>& decls,
+    std::set<std::string>& funs)
+{
+    decls.insert(is_representable_integerDecl);
+    funs.insert(is_representable_integer);
+    decls.insert(approx_equalDecl);
+    funs.insert(approx_equal);
+}
+
 void OpInt::GenerateCode( outputstream& ss ) const
 {
     ss << "    int intTmp = (int)arg0;\n";
@@ -464,6 +473,72 @@ void OpQuotient::GenerateCode( outputstream& ss ) const
     ss << "    return trunc(arg0/arg1);\n";
 }
 
+void OpEqual::BinInlineFun(std::set<std::string>& decls,
+    std::set<std::string>& funs)
+{
+    decls.insert(is_representable_integerDecl);
+    funs.insert(is_representable_integer);
+    decls.insert(approx_equalDecl);
+    funs.insert(approx_equal);
+}
+
+void OpEqual::GenerateCode( outputstream& ss ) const
+{
+    ss << "    return approx_equal( arg0, arg1 );\n";
+}
+
+void OpNotEqual::BinInlineFun(std::set<std::string>& decls,
+    std::set<std::string>& funs)
+{
+    decls.insert(is_representable_integerDecl);
+    funs.insert(is_representable_integer);
+    decls.insert(approx_equalDecl);
+    funs.insert(approx_equal);
+}
+
+void OpNotEqual::GenerateCode( outputstream& ss ) const
+{
+    ss << "    return !approx_equal( arg0, arg1 );\n";
+}
+
+void OpLessEqual::BinInlineFun(std::set<std::string>& decls,
+    std::set<std::string>& funs)
+{
+    decls.insert(is_representable_integerDecl);
+    funs.insert(is_representable_integer);
+    decls.insert(approx_equalDecl);
+    funs.insert(approx_equal);
+}
+
+void OpLessEqual::GenerateCode( outputstream& ss ) const
+{
+    ss << "    return approx_equal( arg0, arg1 ) || arg0 <= arg1;\n";
+}
+
+void OpLess::GenerateCode( outputstream& ss ) const
+{
+    ss << "    return arg0 < arg1;\n";
+}
+
+void OpGreaterEqual::BinInlineFun(std::set<std::string>& decls,
+    std::set<std::string>& funs)
+{
+    decls.insert(is_representable_integerDecl);
+    funs.insert(is_representable_integer);
+    decls.insert(approx_equalDecl);
+    funs.insert(approx_equal);
+}
+
+void OpGreaterEqual::GenerateCode( outputstream& ss ) const
+{
+    ss << "    return approx_equal( arg0, arg1 ) || arg0 >= arg1;\n";
+}
+
+void OpGreater::GenerateCode( outputstream& ss ) const
+{
+    ss << "    return arg0 > arg1;\n";
+}
+
 void OpLog::GenSlidingWindowFunction(outputstream &ss,
             const std::string &sSymName, SubArguments &vSubArguments)
 {
@@ -1584,6 +1659,330 @@ void OpSeriesSum::GenSlidingWindowFunction(outputstream 
&ss,
     ss << "    return res;\n";
     ss << "}";
 }
+
+void SumOfProduct::GenSlidingWindowFunction( outputstream& ss,
+    const std::string& sSymName, SubArguments& vSubArguments )
+{
+    size_t nCurWindowSize = 0;
+    FormulaToken* tmpCur = nullptr;
+    const formula::DoubleVectorRefToken* pCurDVR = nullptr;
+    GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
+    ss << "{\n";
+    for (size_t i = 0; i < vSubArguments.size(); i++)
+    {
+        size_t nCurChildWindowSize = vSubArguments[i]->GetWindowSize();
+        nCurWindowSize = (nCurWindowSize < nCurChildWindowSize) ?
+            nCurChildWindowSize : nCurWindowSize;
+        tmpCur = vSubArguments[i]->GetFormulaToken();
+        if (ocPush == tmpCur->GetOpCode())
+        {
+            pCurDVR = static_cast<const 
formula::DoubleVectorRefToken*>(tmpCur);
+            if (pCurDVR->IsStartFixed() != pCurDVR->IsEndFixed())
+                throw Unhandled(__FILE__, __LINE__);
+        }
+    }
+    ss << "    double tmp = 0.0;\n";
+    ss << "    int gid0 = get_global_id(0);\n";
+
+    ss << "\tint i;\n\t";
+    ss << "int currentCount0;\n";
+    for (size_t i = 0; i < vSubArguments.size() - 1; i++)
+        ss << "int currentCount" << i + 1 << ";\n";
+    outputstream temp3, temp4;
+    int outLoopSize = UNROLLING_FACTOR;
+    if (nCurWindowSize / outLoopSize != 0)
+    {
+        ss << "for(int outLoop=0; outLoop<" <<
+            nCurWindowSize / outLoopSize << "; outLoop++){\n\t";
+        for (int count = 0; count < outLoopSize; count++)
+        {
+            ss << "i = outLoop*" << outLoopSize << "+" << count << ";\n";
+            if (count == 0)
+            {
+                for (size_t i = 0; i < vSubArguments.size(); i++)
+                {
+                    tmpCur = vSubArguments[i]->GetFormulaToken();
+                    if (ocPush == tmpCur->GetOpCode())
+                    {
+                        pCurDVR = static_cast<const 
formula::DoubleVectorRefToken*>(tmpCur);
+                        if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
+                        {
+                            temp3 << "        currentCount";
+                            temp3 << i;
+                            temp3 << " =i+gid0+1;\n";
+                        }
+                        else
+                        {
+                            temp3 << "        currentCount";
+                            temp3 << i;
+                            temp3 << " =i+1;\n";
+                        }
+                    }
+                }
+
+                temp3 << "tmp = fsum(";
+                for (size_t i = 0; i < vSubArguments.size(); i++)
+                {
+                    if (i)
+                        temp3 << "*";
+                    if (ocPush == 
vSubArguments[i]->GetFormulaToken()->GetOpCode())
+                    {
+                        temp3 << "(";
+                        temp3 << "(currentCount";
+                        temp3 << i;
+                        temp3 << ">";
+                        if (vSubArguments[i]->GetFormulaToken()->GetType() ==
+                                formula::svSingleVectorRef)
+                        {
+                            const formula::SingleVectorRefToken* pSVR =
+                                static_cast<const 
formula::SingleVectorRefToken*>
+                                (vSubArguments[i]->GetFormulaToken());
+                            temp3 << pSVR->GetArrayLength();
+                            temp3 << ")||isnan(" << vSubArguments[i]
+                                ->GenSlidingWindowDeclRef();
+                            temp3 << ")?0:";
+                            temp3 << 
vSubArguments[i]->GenSlidingWindowDeclRef();
+                            temp3  << ")";
+                        }
+                        else if 
(vSubArguments[i]->GetFormulaToken()->GetType() ==
+                                formula::svDoubleVectorRef)
+                        {
+                            const formula::DoubleVectorRefToken* pSVR =
+                                static_cast<const 
formula::DoubleVectorRefToken*>
+                                (vSubArguments[i]->GetFormulaToken());
+                            temp3 << pSVR->GetArrayLength();
+                            temp3 << ")||isnan(" << vSubArguments[i]
+                                ->GenSlidingWindowDeclRef(true);
+                            temp3 << ")?0:";
+                            temp3 << 
vSubArguments[i]->GenSlidingWindowDeclRef(true);
+                            temp3  << ")";
+                        }
+
+                    }
+                    else
+                        temp3 << 
vSubArguments[i]->GenSlidingWindowDeclRef(true);
+                }
+                temp3 << ", tmp);\n\t";
+            }
+            ss << temp3.str();
+        }
+        ss << "}\n\t";
+    }
+    //The residual of mod outLoopSize
+    for (size_t count = nCurWindowSize / outLoopSize * outLoopSize;
+        count < nCurWindowSize; count++)
+    {
+        ss << "i =" << count << ";\n";
+        if (count == nCurWindowSize / outLoopSize * outLoopSize)
+        {
+            for (size_t i = 0; i < vSubArguments.size(); i++)
+            {
+                tmpCur = vSubArguments[i]->GetFormulaToken();
+                if (ocPush == tmpCur->GetOpCode())
+                {
+                    pCurDVR = static_cast<const 
formula::DoubleVectorRefToken*>(tmpCur);
+                    if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
+                    {
+                        temp4 << "        currentCount";
+                        temp4 << i;
+                        temp4 << " =i+gid0+1;\n";
+                    }
+                    else
+                    {
+                        temp4 << "        currentCount";
+                        temp4 << i;
+                        temp4 << " =i+1;\n";
+                    }
+                }
+            }
+
+            temp4 << "tmp = fsum(";
+            for (size_t i = 0; i < vSubArguments.size(); i++)
+            {
+                if (i)
+                    temp4 << "*";
+                if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode())
+                {
+                    temp4 << "(";
+                    temp4 << "(currentCount";
+                    temp4 << i;
+                    temp4 << ">";
+                    if (vSubArguments[i]->GetFormulaToken()->GetType() ==
+                            formula::svSingleVectorRef)
+                    {
+                        const formula::SingleVectorRefToken* pSVR =
+                            static_cast<const formula::SingleVectorRefToken*>
+                            (vSubArguments[i]->GetFormulaToken());
+                        temp4 << pSVR->GetArrayLength();
+                        temp4 << ")||isnan(" << vSubArguments[i]
+                            ->GenSlidingWindowDeclRef();
+                        temp4 << ")?0:";
+                        temp4 << vSubArguments[i]->GenSlidingWindowDeclRef();
+                        temp4  << ")";
+                    }
+                    else if (vSubArguments[i]->GetFormulaToken()->GetType() ==
+                            formula::svDoubleVectorRef)
+                    {
+                        const formula::DoubleVectorRefToken* pSVR =
+                            static_cast<const formula::DoubleVectorRefToken*>
+                            (vSubArguments[i]->GetFormulaToken());
+                        temp4 << pSVR->GetArrayLength();
+                        temp4 << ")||isnan(" << vSubArguments[i]
+                            ->GenSlidingWindowDeclRef(true);
+                        temp4 << ")?0:";
+                        temp4 << 
vSubArguments[i]->GenSlidingWindowDeclRef(true);
+                        temp4  << ")";
+                    }
+
+                }
+                else
+                {
+                    temp4 << vSubArguments[i]
+                        ->GenSlidingWindowDeclRef(true);
+                }
+            }
+            temp4 << ", tmp);\n\t";
+        }
+        ss << temp4.str();
+    }
+    ss << "return tmp;\n";
+    ss << "}";
+}
+
+void Reduction::GenSlidingWindowFunction( outputstream& ss,
+    const std::string& sSymName, SubArguments& vSubArguments )
+{
+    GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
+    ss << "{\n";
+    ss << "double tmp = " << GetBottom() << ";\n";
+    ss << "int gid0 = get_global_id(0);\n";
+    if (isAverage() || isMinOrMax())
+        ss << "int nCount = 0;\n";
+    ss << "double tmpBottom;\n";
+    unsigned i = vSubArguments.size();
+    while (i--)
+    {
+        if (NumericRange* NR = 
dynamic_cast<NumericRange*>(vSubArguments[i].get()))
+        {
+            bool needBody;
+            NR->GenReductionLoopHeader(ss, needBody);
+            if (!needBody)
+                continue;
+        }
+        else if (ParallelNumericRange* PNR = 
dynamic_cast<ParallelNumericRange*>(vSubArguments[i].get()))
+        {
+            //did not handle yet
+            bool bNeedBody = false;
+            PNR->GenReductionLoopHeader(ss, mnResultSize, bNeedBody);
+            if (!bNeedBody)
+                continue;
+        }
+        else if (StringRange* SR = 
dynamic_cast<StringRange*>(vSubArguments[i].get()))
+        {
+            //did not handle yet
+            bool needBody;
+            SR->GenReductionLoopHeader(ss, needBody);
+            if (!needBody)
+                continue;
+        }
+        else
+        {
+            FormulaToken* pCur = vSubArguments[i]->GetFormulaToken();
+            assert(pCur);
+            assert(pCur->GetType() != formula::svDoubleVectorRef);
+
+            if (pCur->GetType() == formula::svSingleVectorRef ||
+                pCur->GetType() == formula::svDouble)
+            {
+                ss << "{\n";
+            }
+        }
+        if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode())
+        {
+            bool bNanHandled = HandleNaNArgument(ss, i, vSubArguments);
+
+            ss << "tmpBottom = " << GetBottom() << ";\n";
+
+            if (!bNanHandled)
+            {
+                ss << "if (isnan(";
+                ss << vSubArguments[i]->GenSlidingWindowDeclRef();
+                ss << "))\n";
+                if (ZeroReturnZero())
+                    ss << "    return 0;\n";
+                else
+                {
+                    ss << "    tmp = ";
+                    ss << Gen2("tmpBottom", "tmp") << ";\n";
+                }
+                ss << "else\n";
+            }
+            ss << "{";
+            ss << "        tmp = ";
+            ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
+            ss << ";\n";
+            ss << "    }\n";
+            ss << "}\n";
+        }
+        else
+        {
+            ss << "tmp = ";
+            ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
+            ss << ";\n";
+        }
+    }
+    if (isAverage())
+        ss <<
+            "if (nCount==0)\n"
+            "    return CreateDoubleError(DivisionByZero);\n";
+    else if (isMinOrMax())
+        ss <<
+            "if (nCount==0)\n"
+            "    return 0;\n";
+    ss << "return tmp";
+    if (isAverage())
+        ss << "/(double)nCount";
+    ss << ";\n}";
+}
+
+void OpSum::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& 
funs)
+{
+    decls.insert(is_representable_integerDecl);
+    funs.insert(is_representable_integer);
+    decls.insert(approx_equalDecl);
+    funs.insert(approx_equal);
+    decls.insert(fsum_approxDecl);
+    funs.insert(fsum_approx);
+}
+
+void OpAverage::BinInlineFun(std::set<std::string>& 
decls,std::set<std::string>& funs)
+{
+    decls.insert(fsum_countDecl);
+    funs.insert(fsum_count);
+}
+
+void OpSub::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& 
funs)
+{
+    decls.insert(is_representable_integerDecl);
+    funs.insert(is_representable_integer);
+    decls.insert(approx_equalDecl);
+    funs.insert(approx_equal);
+    decls.insert(fsub_approxDecl);
+    funs.insert(fsub_approx);
+}
+
+void OpMin::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& 
funs)
+{
+    decls.insert(fmin_countDecl);
+    funs.insert(fmin_count);
+}
+
+void OpMax::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& 
funs)
+{
+    decls.insert(fmax_countDecl);
+    funs.insert(fmax_count);
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/opencl/op_math.hxx 
b/sc/source/core/opencl/op_math.hxx
index 82ef12643dd0..a1cfa5de0b61 100644
--- a/sc/source/core/opencl/op_math.hxx
+++ b/sc/source/core/opencl/op_math.hxx
@@ -34,6 +34,7 @@ class OpMathTwoArguments : public Normal
     virtual void GenerateCode( outputstream& ss ) const = 0;
 };
 
+
 class OpCos: public OpMathOneArgument
 {
 public:
@@ -275,6 +276,7 @@ class OpInt: public OpMathOneArgument
 public:
     virtual std::string BinFuncName() const override { return "Int"; }
     virtual void GenerateCode( outputstream& ss ) const override;
+    virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& 
) override;
 };
 
 class OpRadians: public OpMathOneArgument
@@ -501,6 +503,257 @@ public:
     virtual void GenerateCode( outputstream& ss ) const override;
 };
 
+class OpEqual : public OpMathTwoArguments
+{
+public:
+    virtual void GenerateCode( outputstream& ss ) const override;
+    virtual std::string BinFuncName() const override { return "eq"; }
+    virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& 
) override;
+};
+
+class OpNotEqual : public OpMathTwoArguments
+{
+public:
+    virtual void GenerateCode( outputstream& ss ) const override;
+    virtual std::string BinFuncName() const override { return "neq"; }
+    virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& 
) override;
+};
+
+class OpLessEqual : public OpMathTwoArguments
+{
+public:
+    virtual void GenerateCode( outputstream& ss ) const override;
+    virtual std::string BinFuncName() const override { return "le"; }
+    virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& 
) override;
+};
+
+class OpLess : public OpMathTwoArguments
+{
+public:
+    virtual void GenerateCode( outputstream& ss ) const override;
+    virtual std::string BinFuncName() const override { return "lt"; }
+};
+
+class OpGreaterEqual : public OpMathTwoArguments
+{
+public:
+    virtual void GenerateCode( outputstream& ss ) const override;
+    virtual std::string BinFuncName() const override { return "ge"; }
+    virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& 
) override;
+};
+
+class OpGreater : public OpMathTwoArguments
+{
+public:
+    virtual void GenerateCode( outputstream& ss ) const override;
+    virtual std::string BinFuncName() const override { return "gt"; }
+};
+
+class SumOfProduct : public SlidingFunctionBase
+{
+public:
+    virtual void GenSlidingWindowFunction( outputstream& ss,
+        const std::string& sSymName, SubArguments& vSubArguments ) override;
+    virtual bool takeString() const override { return false; }
+    virtual bool takeNumeric() const override { return true; }
+};
+
+class OpSumProduct : public SumOfProduct
+{
+public:
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        return lhs + "*" + rhs;
+    }
+    virtual std::string BinFuncName() const override { return "fsop"; }
+};
+
+class Reduction : public SlidingFunctionBase
+{
+    int const mnResultSize;
+public:
+    explicit Reduction(int nResultSize) : mnResultSize(nResultSize) {}
+
+    typedef DynamicKernelSlidingArgument<VectorRef> NumericRange;
+    typedef DynamicKernelSlidingArgument<DynamicKernelStringArgument> 
StringRange;
+    typedef ParallelReductionVectorRef<VectorRef> ParallelNumericRange;
+
+    virtual bool HandleNaNArgument( outputstream&, unsigned, SubArguments& ) 
const
+    {
+        return false;
+    }
+
+    virtual void GenSlidingWindowFunction( outputstream& ss,
+        const std::string& sSymName, SubArguments& vSubArguments ) override;
+    virtual bool isAverage() const { return false; }
+    virtual bool isMinOrMax() const { return false; }
+    virtual bool takeString() const override { return false; }
+    virtual bool takeNumeric() const override { return true; }
+};
+
+/// operator traits
+class OpNop : public Reduction
+{
+public:
+    explicit OpNop(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "0"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& ) 
const override
+    {
+        return lhs;
+    }
+    virtual std::string BinFuncName() const override { return "nop"; }
+};
+
+class OpCount : public Reduction
+{
+public:
+    explicit OpCount(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "0"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        outputstream ss;
+        ss << "(isnan(" << lhs << ")?" << rhs << ":" << rhs << "+1.0)";
+        return ss.str();
+    }
+    virtual std::string BinFuncName() const override { return "fcount"; }
+    virtual bool canHandleMultiVector() const override { return true; }
+};
+
+class OpSum : public Reduction
+{
+public:
+    explicit OpSum(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "0"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        outputstream ss;
+        ss << "fsum_approx((" << lhs << "),(" << rhs << "))";
+        return ss.str();
+    }
+    virtual void BinInlineFun(std::set<std::string>& 
decls,std::set<std::string>& funs) override;
+    virtual std::string BinFuncName() const override { return "fsum"; }
+    // All arguments are simply summed, so it doesn't matter if SvDoubleVector 
is split.
+    virtual bool canHandleMultiVector() const override { return true; }
+};
+
+class OpAverage : public Reduction
+{
+public:
+    explicit OpAverage(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "0"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        outputstream ss;
+        ss << "fsum_count(" << lhs << "," << rhs << ", &nCount)";
+        return ss.str();
+    }
+    virtual void BinInlineFun(std::set<std::string>& 
decls,std::set<std::string>& funs) override;
+    virtual std::string BinFuncName() const override { return "average"; }
+    virtual bool isAverage() const override { return true; }
+    virtual bool canHandleMultiVector() const override { return true; }
+};
+
+class OpSub : public Reduction
+{
+public:
+    explicit OpSub(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "0"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        return "fsub_approx(" + lhs + "," + rhs + ")";
+    }
+    virtual void BinInlineFun(std::set<std::string>& 
decls,std::set<std::string>& funs) override;
+    virtual std::string BinFuncName() const override { return "fsub"; }
+};
+
+class OpMul : public Reduction
+{
+public:
+    explicit OpMul(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "1"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        return lhs + "*" + rhs;
+    }
+    virtual std::string BinFuncName() const override { return "fmul"; }
+    virtual bool ZeroReturnZero() override { return true; }
+};
+
+/// Technically not a reduction, but fits the framework.
+class OpDiv : public Reduction
+{
+public:
+    explicit OpDiv(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "1.0"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        return "(" + rhs + "==0 ? CreateDoubleError(DivisionByZero) : (" + lhs 
+ "/" + rhs + ") )";
+    }
+    virtual std::string BinFuncName() const override { return "fdiv"; }
+
+    virtual bool HandleNaNArgument( outputstream& ss, unsigned argno, 
SubArguments& vSubArguments ) const override
+    {
+        if (argno == 1)
+        {
+            ss <<
+                "if (isnan(" << 
vSubArguments[argno]->GenSlidingWindowDeclRef() << ")) {\n"
+                "    return CreateDoubleError(DivisionByZero);\n"
+                "}\n";
+            return true;
+        }
+        else if (argno == 0)
+        {
+            ss <<
+                "if (isnan(" << 
vSubArguments[argno]->GenSlidingWindowDeclRef() << ") &&\n"
+                "    !(isnan(" << vSubArguments[1]->GenSlidingWindowDeclRef() 
<< ") || " << vSubArguments[1]->GenSlidingWindowDeclRef() << " == 0)) {\n"
+                "    return 0;\n"
+                "}\n";
+        }
+        return false;
+    }
+
+};
+
+class OpMin : public Reduction
+{
+public:
+    explicit OpMin(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "NAN"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        return "fmin_count(" + lhs + "," + rhs + ", &nCount)";
+    }
+    virtual void BinInlineFun(std::set<std::string>& 
decls,std::set<std::string>& funs) override;
+    virtual std::string BinFuncName() const override { return "min"; }
+    virtual bool isMinOrMax() const override { return true; }
+    virtual bool canHandleMultiVector() const override { return true; }
+};
+
+class OpMax : public Reduction
+{
+public:
+    explicit OpMax(int nResultSize) : Reduction(nResultSize) {}
+
+    virtual std::string GetBottom() override { return "NAN"; }
+    virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) 
const override
+    {
+        return "fmax_count(" + lhs + "," + rhs + ", &nCount)";
+    }
+    virtual void BinInlineFun(std::set<std::string>& 
decls,std::set<std::string>& funs) override;
+    virtual std::string BinFuncName() const override { return "max"; }
+    virtual bool isMinOrMax() const override { return true; }
+    virtual bool canHandleMultiVector() const override { return true; }
+};
+
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/opencl/op_math_helpers.hxx 
b/sc/source/core/opencl/op_math_helpers.hxx
index f18cc7f39249..ada1cf8f50c6 100644
--- a/sc/source/core/opencl/op_math_helpers.hxx
+++ b/sc/source/core/opencl/op_math_helpers.hxx
@@ -86,4 +86,80 @@ const char atan2Content[] =
 "    return a;\n"
 "}\n";
 
+const char fsum_countDecl[] = "double fsum_count(double a, double b, __private 
int *p);\n";
+const char fsum_count[] =
+"double fsum_count(double a, double b, __private int *p) {\n"
+"    bool t = isnan(a);\n"
+"    (*p) += t?0:1;\n"
+"    return t?b:a+b;\n"
+"}\n";
+
+const char fmin_countDecl[] = "double fmin_count(double a, double b, __private 
int *p);\n";
+const char fmin_count[] =
+"double fmin_count(double a, double b, __private int *p) {\n"
+"    double result = fmin(a, b);\n"
+"    bool t = isnan(result);\n"
+"    (*p) += t?0:1;\n"
+"    return result;\n"
+"}\n";
+
+const char fmax_countDecl[] =  "double fmax_count(double a, double b, 
__private int *p);\n";
+const char fmax_count[] =
+"double fmax_count(double a, double b, __private int *p) {\n"
+"    double result = fmax(a, b);\n"
+"    bool t = isnan(result);\n"
+"    (*p) += t?0:1;\n"
+"    return result;\n"
+"}\n";
+
+const char is_representable_integerDecl[] =  "int 
is_representable_integer(double a);\n";
+const char is_representable_integer[] =
+"int is_representable_integer(double a) {\n"
+"    long kMaxInt = (1L << 53) - 1;\n"
+"    if (a <= as_double(kMaxInt))\n"
+"    {\n"
+"        long nInt = as_long(a);\n"
+"        double fInt;\n"
+"        return (nInt <= kMaxInt &&\n"
+"                (!((fInt = as_double(nInt)) < a) && !(fInt > a)));\n"
+"    }\n"
+"    return 0;\n"
+"}\n";
+
+const char approx_equalDecl[] = "int approx_equal(double a, double b);\n";
+const char approx_equal[] =
+"int approx_equal(double a, double b) {\n"
+"    double e48 = 1.0 / (16777216.0 * 16777216.0);\n"
+"    double e44 = e48 * 16.0;\n"
+"    if (a == b)\n"
+"        return 1;\n"
+"    if (a == 0.0 || b == 0.0)\n"
+"        return 0;\n"
+"    double d = fabs(a - b);\n"
+"    if (!isfinite(d))\n"
+"        return 0;   // Nan or Inf involved\n"
+"    if (d > ((a = fabs(a)) * e44) || d > ((b = fabs(b)) * e44))\n"
+"        return 0;\n"
+"    if (is_representable_integer(d) && is_representable_integer(a) && 
is_representable_integer(b))\n"
+"        return 0;   // special case for representable integers.\n"
+"    return (d < a * e48 && d < b * e48);\n"
+"}\n";
+
+const char fsum_approxDecl[] = "double fsum_approx(double a, double b);\n";
+const char fsum_approx[] =
+"double fsum_approx(double a, double b) {\n"
+"    if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0))\n"
+"         && approx_equal( a, -b ) )\n"
+"        return 0.0;\n"
+"    return a + b;\n"
+"}\n";
+
+const char fsub_approxDecl[] = "double fsub_approx(double a, double b);\n";
+const char fsub_approx[] =
+"double fsub_approx(double a, double b) {\n"
+"    if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approx_equal( a, b 
) )\n"
+"        return 0.0;\n"
+"    return a - b;\n"
+"}\n";
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/opencl/opbase.hxx b/sc/source/core/opencl/opbase.hxx
index 05208db73247..370cbcf2bba2 100644
--- a/sc/source/core/opencl/opbase.hxx
+++ b/sc/source/core/opencl/opbase.hxx
@@ -12,17 +12,25 @@
 #include <clew/clew.h>
 #include <formula/token.hxx>
 #include <formula/types.hxx>
+#include <formula/vectortoken.hxx>
 #include <memory>
 #include <set>
 #include <vector>
 #include "utils.hxx"
 
-namespace formula { class DoubleVectorRefToken; }
-namespace formula { class FormulaToken; }
 struct ScCalcConfig;
 
 namespace sc::opencl {
 
+// FIXME: The idea that somebody would bother to (now and then? once a year? 
once a month?) manually
+// edit a source file and change the value of some #defined constant and run 
some ill-defined
+// "correctness test" is of course ludicrous. Either things are checked in 
normal unit tests, in
+// every 'make check', or not at all. The below comments are ridiculous.
+
+#define REDUCE_THRESHOLD 201  // set to 4 for correctness testing. priority 1
+#define UNROLLING_FACTOR 16  // set to 4 for correctness testing (if no reduce)
+
+
 class FormulaTreeNode;
 
 /// Exceptions
@@ -194,6 +202,27 @@ protected:
     const int mnIndex;
 };
 
+/// A vector of strings
+class DynamicKernelStringArgument : public VectorRef
+{
+public:
+    DynamicKernelStringArgument( const ScCalcConfig& config, const 
std::string& s,
+        const FormulaTreeNodeRef& ft, int index = 0 ) :
+        VectorRef(config, s, ft, index) { }
+
+    virtual void GenSlidingWindowFunction( outputstream& ) override { }
+    /// Generate declaration
+    virtual void GenDecl( outputstream& ss ) const override
+    {
+        ss << "__global unsigned int *" << mSymName;
+    }
+    virtual void GenSlidingWindowDecl( outputstream& ss ) const override
+    {
+        DynamicKernelStringArgument::GenDecl(ss);
+    }
+    virtual size_t Marshal( cl_kernel, int, int, cl_program ) override;
+};
+
 /// Abstract class for code generation
 class OpBase
 {
@@ -262,6 +291,73 @@ public:
         int nCurWindowSize );
 };
 
+class OpAverage;
+class OpCount;
+
+/// Handling a Double Vector that is used as a sliding window input
+/// to either a sliding window average or sum-of-products
+/// Generate a sequential loop for reductions
+template<class Base>
+class DynamicKernelSlidingArgument : public Base
+{
+public:
+    DynamicKernelSlidingArgument(const ScCalcConfig& config, const 
std::string& s,
+                                 const FormulaTreeNodeRef& ft,
+                                 std::shared_ptr<SlidingFunctionBase> CodeGen, 
int index);
+    // Should only be called by SumIfs. Yikes!
+    virtual bool NeedParallelReduction() const;
+    virtual void GenSlidingWindowFunction( outputstream& ) { }
+
+    std::string GenSlidingWindowDeclRef( bool nested = false ) const;
+    /// Controls how the elements in the DoubleVectorRef are traversed
+    size_t GenReductionLoopHeader( outputstream& ss, bool& needBody );
+
+    size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
+
+    size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
+
+    bool GetStartFixed() const { return bIsStartFixed; }
+
+    bool GetEndFixed() const { return bIsEndFixed; }
+
+protected:
+    bool bIsStartFixed, bIsEndFixed;
+    const formula::DoubleVectorRefToken* mpDVR;
+    // from parent nodes
+    std::shared_ptr<SlidingFunctionBase> mpCodeGen;
+};
+
+/// Handling a Double Vector that is used as a sliding window input
+/// Performs parallel reduction based on given operator
+template<class Base>
+class ParallelReductionVectorRef : public Base
+{
+public:
+    ParallelReductionVectorRef(const ScCalcConfig& config, const std::string& 
s,
+                               const FormulaTreeNodeRef& ft,
+                               std::shared_ptr<SlidingFunctionBase> CodeGen, 
int index);
+    ~ParallelReductionVectorRef();
+
+    /// Emit the definition for the auxiliary reduction kernel
+    virtual void GenSlidingWindowFunction( outputstream& ss );
+    virtual std::string GenSlidingWindowDeclRef( bool ) const;
+    /// Controls how the elements in the DoubleVectorRef are traversed
+    size_t GenReductionLoopHeader( outputstream& ss, int nResultSize, bool& 
needBody );
+    virtual size_t Marshal( cl_kernel k, int argno, int w, cl_program 
mpProgram );
+    size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
+    size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
+    bool GetStartFixed() const { return bIsStartFixed; }
+    bool GetEndFixed() const { return bIsEndFixed; }
+
+protected:
+    bool bIsStartFixed, bIsEndFixed;
+    const formula::DoubleVectorRefToken* mpDVR;
+    // from parent nodes
+    std::shared_ptr<SlidingFunctionBase> mpCodeGen;
+    // controls whether to invoke the reduction kernel during marshaling or not
+    cl_mem mpClmem2;
+};
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Reply via email to