[Libreoffice-commits] core.git: Branch 'libreoffice-6-2' - 13 commits - officecfg/registry sc/inc sc/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Tue Dec 4 16:47:07 UTC 2018


 officecfg/registry/schema/org/openoffice/Office/Calc.xcs |    2 
 sc/inc/column.hxx                                        |    3 
 sc/inc/document.hxx                                      |    3 
 sc/inc/formulacell.hxx                                   |    2 
 sc/inc/table.hxx                                         |    3 
 sc/source/core/data/column2.cxx                          |   29 +
 sc/source/core/data/document.cxx                         |    9 
 sc/source/core/data/formulacell.cxx                      |   43 +
 sc/source/core/data/grouptokenconverter.cxx              |   19 
 sc/source/core/data/table1.cxx                           |    9 
 sc/source/core/opencl/formulagroupcl.cxx                 |  399 ++++++++++++++-
 sc/source/core/opencl/op_financial.cxx                   |   67 +-
 sc/source/core/opencl/op_math.cxx                        |   29 -
 sc/source/core/opencl/op_statistical.cxx                 |   19 
 sc/source/core/tool/calcconfig.cxx                       |    5 
 15 files changed, 585 insertions(+), 56 deletions(-)

New commits:
commit b8be6d4432fb2e8b382a075d3ae1f31fca9c236b
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Thu Nov 29 13:19:36 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:46:27 2018 +0100

    restore incorrectly removed code
    
    149a4d7566 removed NeedParallelReduction() even though the code should
    be there. I'm not sure about GenSlidingWindowFunction(), since the base
    class is a template, but better revert that one too.
    Also revert that part of 73e6a7975b that removed the subsequently
    no longer used functions.
    
    Change-Id: I932ffd58f9528ec840c4575078f8356640eb5420
    Reviewed-on: https://gerrit.libreoffice.org/64249
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 27f27e107730cc2242df578fd3e6dbb1a7117066)
    Reviewed-on: https://gerrit.libreoffice.org/64468

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index 4449b0f1e0e1..04c95a8de21f 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -971,6 +971,17 @@ public:
         bIsEndFixed = mpDVR->IsEndFixed();
     }
 
+    // Should only be called by SumIfs. Yikes!
+    virtual bool NeedParallelReduction() const
+    {
+        assert(dynamic_cast<OpSumIfs*>(mpCodeGen.get()));
+        return GetWindowSize() > 100 &&
+               ((GetStartFixed() && GetEndFixed()) ||
+            (!GetStartFixed() && !GetEndFixed()));
+    }
+
+    virtual void GenSlidingWindowFunction( std::stringstream& ) { }
+
     std::string GenSlidingWindowDeclRef( bool nested = false ) const
     {
         size_t nArrayLength = mpDVR->GetArrayLength();
@@ -1112,6 +1123,12 @@ public:
 
     size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
 
+    size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
+
+    size_t GetStartFixed() const { return bIsStartFixed; }
+
+    size_t GetEndFixed() const { return bIsEndFixed; }
+
 protected:
     bool bIsStartFixed, bIsEndFixed;
     const formula::DoubleVectorRefToken* mpDVR;
commit 26f20fc63168ade7cebc6e1f198972256ac19350
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 30 21:36:03 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:46:12 2018 +0100

    add ^ (=power) and - (=unary minus) to OpenCLSubsetOpCodes
    
    Both of these are trivial and quite common mathematical operations.
    Unary minus is a bit complicated in that unary '-' is the same symbol
    as binary '-' and so there needs to be a hack to expand the '-'
    from the list to both of the opcodes ocSub and ocNegSub.
    
    Change-Id: I556e20e161c22dc89919afffbf904c1ef1d552ff
    Reviewed-on: https://gerrit.libreoffice.org/64362
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit f7e7a59f38682dcd1f916c63fe8e2a437ecb5cf1)
    Reviewed-on: https://gerrit.libreoffice.org/64467

diff --git a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
index 7951d4bf91cc..e5b3318ff701 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
@@ -1480,7 +1480,7 @@
             true, and a formula contains only these operators and
             functions, it might be calculated using OpenCL.</desc>
           </info>
-          <value>+;-;*;/;RAND;SIN;COS;TAN;ATAN;EXP;LN;SQRT;NORMSDIST;NORMSINV;ROUND;POWER;SUMPRODUCT;MIN;MAX;SUM;PRODUCT;AVERAGE;COUNT;VAR;NORMDIST;VLOOKUP;CORREL;COVAR;PEARSON;SLOPE;SUMIFS</value>
+          <value>+;-;*;/;^;RAND;SIN;COS;TAN;ATAN;EXP;LN;SQRT;NORMSDIST;NORMSINV;ROUND;POWER;SUMPRODUCT;MIN;MAX;SUM;PRODUCT;AVERAGE;COUNT;VAR;NORMDIST;VLOOKUP;CORREL;COVAR;PEARSON;SLOPE;SUMIFS</value>
         </prop>
         <prop oor:name="OpenCLAutoSelect" oor:type="xs:boolean" oor:nillable="false">
           <info>
diff --git a/sc/source/core/tool/calcconfig.cxx b/sc/source/core/tool/calcconfig.cxx
index 784bd4690df0..b695463b7357 100644
--- a/sc/source/core/tool/calcconfig.cxx
+++ b/sc/source/core/tool/calcconfig.cxx
@@ -114,8 +114,10 @@ void ScCalcConfig::setOpenCLConfigToDefault()
     static OpCodeSet pDefaultOpenCLSubsetOpCodes(new std::set<OpCode>({
         ocAdd,
         ocSub,
+        ocNegSub,
         ocMul,
         ocDiv,
+        ocPow,
         ocRandom,
         ocSin,
         ocCos,
@@ -239,6 +241,9 @@ ScCalcConfig::OpCodeSet ScStringToOpCodeSet(const OUString& rOpCodes)
         }
         fromIndex = semicolon+1;
     }
+    // HACK: Both unary and binary minus have the same string but different opcodes.
+    if( result->find( ocSub ) != result->end())
+        result->insert( ocNegSub );
     return result;
 }
 
commit 75395a68afa46dab3906275c46cd8542019c0f4c
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 30 12:43:13 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:45:56 2018 +0100

    fix OpenCL PEARSON()
    
    Some error checking, but also simply use "if(cond) code;" rather than
    "if(!cond) try-to-set-benign-values-that-will-break-things-nevertheless".
    
    Change-Id: Ic0c296273ba4c174dba5e96eadeeee4005988142
    Reviewed-on: https://gerrit.libreoffice.org/64342
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit ac439c8c838a14db6ae02dff72dc8e8fffc333ef)
    Reviewed-on: https://gerrit.libreoffice.org/64466

diff --git a/sc/source/core/opencl/op_statistical.cxx b/sc/source/core/opencl/op_statistical.cxx
index 62f35865c7c7..374b383dcc4c 100644
--- a/sc/source/core/opencl/op_statistical.cxx
+++ b/sc/source/core/opencl/op_statistical.cxx
@@ -3274,11 +3274,14 @@ void OpPearson::GenSlidingWindowFunction(
     ss << ";\n";
     ss << "          fIny = "<<vSubArguments[1]->GenSlidingWindowDeclRef(true);
     ss << "  ;\n";
-    ss << " if(isnan(fInx)||isnan(fIny)){fInx=0.0;fIny=0.0;fCount = fCount-1;}\n";
+    ss << " if(!isnan(fInx)&&!isnan(fIny)){\n";
     ss << "       fSumX += fInx;\n";
     ss << "       fSumY += fIny;\n";
     ss << "       fCount = fCount + 1;\n";
+    ss << "      }\n";
     ss << "     }\n";
+    ss << " if(fCount < 1)\n";
+    ss << "   return CreateDoubleError(NoValue);\n";
     ss << "       double fMeanX = fSumX / fCount;\n";
     ss << "       double fMeanY = fSumY / fCount;\n";
     ss << "       fSumX = 0.0;\n";
@@ -3301,15 +3304,15 @@ void OpPearson::GenSlidingWindowFunction(
     ss << " ;\n";
     ss << "           fIny = "<<vSubArguments[1]->GenSlidingWindowDeclRef(true);
     ss << " ;\n";
-    ss << " if(isnan(fInx)||isnan(fIny)){fInx=0.0;fIny=0.0;}\n";
+    ss << " if(!isnan(fInx)&&!isnan(fIny)){\n";
     ss << "           fSumDeltaXDeltaY += (fInx - fMeanX) * (fIny - fMeanY);\n";
-    ss << "           fSumX += pow(fInx - fMeanX,2);\n";
-    ss << "           fSumY += pow(fIny - fMeanY,2);\n";
+    ss << "           fSumX += (fInx - fMeanX) * (fInx - fMeanX);\n";
+    ss << "           fSumY += (fIny - fMeanY) * (fIny - fMeanY);\n";
+    ss << "         }\n";
     ss << "       }\n";
-    ss << "      double tmp = ( fSumDeltaXDeltaY / ";
-    ss << "sqrt( fSumX * fSumY));\n\t";
-    ss << "      if (isnan(tmp))\n";
-    ss << "          return CreateDoubleError(NoValue);\n";
+    ss << "      if (fSumX == 0 || fSumY == 0)\n";
+    ss << "          return CreateDoubleError(DivisionByZero);\n";
+    ss << "      double tmp = ( fSumDeltaXDeltaY / sqrt( fSumX * fSumY));\n";
     ss << "      return tmp;\n";
     ss << "}\n";
 }
commit b0c87ae5b671b9092c5460828c0a3c96f987e65c
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Wed Nov 28 16:33:02 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:45:40 2018 +0100

    make OpenCL SUM() treat empty cells properly
    
    The data vector may not have all values (if last cells are empty).
    In that case GetRefRowSize() is larger than GetArrayLength().
    Other cases in this function had a similar check, this one was
    missing it for some reason (with the 'gid0' removed, since it's
    a fixed position).
    
    Change-Id: I01692b51d6ed22ee6db419508cacf556fb9e644d
    Reviewed-on: https://gerrit.libreoffice.org/64237
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit a0b059a37e775a466c6fb0043335aae4d3e93fbf)
    Reviewed-on: https://gerrit.libreoffice.org/64464

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index 95863339c252..4449b0f1e0e1 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -1077,9 +1077,12 @@ public:
                         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();
                     }
@@ -1091,9 +1094,12 @@ public:
                     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();
                 }
commit 0152a5651d0c5dbaf8630a4db023aeb400378564
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Wed Nov 28 15:32:20 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:45:04 2018 +0100

    make sure FetchVectorRefArray() never triggers Interpret()
    
    Test::testFormulaRefUpdateRange could trigger this, leading to recursion
    that wasn't handled properly by the code, since it wasn't expected
    to happen at late time (ScDependantsCalculator should have already
    caught it). This is all caused by the fact that FetchVectorRefArray()
    fetches also all rows before the given rows (to make the caching simpler
    I suppose). But that fetching could lead to Interpret() calls.
    Therefore, make ScDependantsCalculator in OpenCL mode check also all
    rows above.
    
    Change-Id: Iaecc105663df21b01443759287cec605470d34a5
    Reviewed-on: https://gerrit.libreoffice.org/64236
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 99014ec9ded70a679220fe59e09ab4073512c249)
    Reviewed-on: https://gerrit.libreoffice.org/64463

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index bdaeccde0afe..0a328f001ce4 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -575,6 +575,9 @@ public:
     void FillMatrix( ScMatrix& rMat, size_t nMatCol, SCROW nRow1, SCROW nRow2, svl::SharedStringPool* pPool ) const;
     formula::VectorRefArray FetchVectorRefArray( SCROW nRow1, SCROW nRow2 );
     bool HandleRefArrayForParallelism( SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup );
+#ifdef DBG_UTIL
+    void AssertNoInterpretNeeded( SCROW nRow1, SCROW nRow2 );
+#endif
     void SetFormulaResults( SCROW nRow, const double* pResults, size_t nLen );
 
     void CalculateInThread( ScInterpreterContext& rContext, SCROW nRow, size_t nLen, unsigned nThisThread, unsigned nThreadsTotal );
diff --git a/sc/inc/document.hxx b/sc/inc/document.hxx
index dd9757aac61b..04ff9a0c1319 100644
--- a/sc/inc/document.hxx
+++ b/sc/inc/document.hxx
@@ -2398,6 +2398,9 @@ public:
 
     formula::VectorRefArray FetchVectorRefArray( const ScAddress& rPos, SCROW nLength );
     bool HandleRefArrayForParallelism( const ScAddress& rPos, SCROW nLength, const ScFormulaCellGroupRef& mxGroup );
+#ifdef DBG_UTIL
+    void AssertNoInterpretNeeded( const ScAddress& rPos, SCROW nLength );
+#endif
 
     /**
      * Call this before any operations that might trigger one or more formula
diff --git a/sc/inc/formulacell.hxx b/sc/inc/formulacell.hxx
index f5b4da63b65c..f344b46034da 100644
--- a/sc/inc/formulacell.hxx
+++ b/sc/inc/formulacell.hxx
@@ -143,7 +143,7 @@ private:
 
     ScFormulaCell( const ScFormulaCell& ) = delete;
 
-    bool CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope);
+    bool CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope, bool fromFirstRow = false);
     bool InterpretFormulaGroupThreading(sc::FormulaLogger::GroupScope& aScope,
                                         bool& bDependencyComputed,
                                         bool& bDependencyCheckFailed);
diff --git a/sc/inc/table.hxx b/sc/inc/table.hxx
index 0e5b62837b92..aae436ea8756 100644
--- a/sc/inc/table.hxx
+++ b/sc/inc/table.hxx
@@ -992,6 +992,9 @@ public:
     formula::FormulaTokenRef ResolveStaticReference( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 );
     formula::VectorRefArray FetchVectorRefArray( SCCOL nCol, SCROW nRow1, SCROW nRow2 );
     bool HandleRefArrayForParallelism( SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup );
+#ifdef DBG_UTIL
+    void AssertNoInterpretNeeded( SCCOL nCol, SCROW nRow1, SCROW nRow2 );
+#endif
 
     void SplitFormulaGroups( SCCOL nCol, std::vector<SCROW>& rRows );
     void UnshareFormulaCells( SCCOL nCol, std::vector<SCROW>& rRows );
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index a4078e75427d..d2e81de5de3b 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -2834,6 +2834,35 @@ formula::VectorRefArray ScColumn::FetchVectorRefArray( SCROW nRow1, SCROW nRow2
     return formula::VectorRefArray(formula::VectorRefArray::Invalid);
 }
 
+#ifdef DBG_UTIL
+static void assertNoInterpretNeededHelper( const sc::CellStoreType::value_type& node,
+    size_t nOffset, size_t nDataSize )
+{
+    switch (node.type)
+    {
+        case sc::element_type_formula:
+        {
+            sc::formula_block::const_iterator it = sc::formula_block::begin(*node.data);
+            std::advance(it, nOffset);
+            sc::formula_block::const_iterator itEnd = it;
+            std::advance(itEnd, nDataSize);
+            for (; it != itEnd; ++it)
+            {
+                const ScFormulaCell* pCell = *it;
+                assert( !pCell->NeedsInterpret());
+            }
+            break;
+        }
+    }
+}
+void ScColumn::AssertNoInterpretNeeded( SCROW nRow1, SCROW nRow2 )
+{
+    assert(nRow2 >= nRow1);
+    sc::ParseBlock( maCells.begin(), maCells, assertNoInterpretNeededHelper, 0, nRow2 );
+}
+#endif
+
+
 bool ScColumn::HandleRefArrayForParallelism( SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup )
 {
     if (nRow1 > nRow2)
diff --git a/sc/source/core/data/document.cxx b/sc/source/core/data/document.cxx
index abda9f677f36..9693edffda3e 100644
--- a/sc/source/core/data/document.cxx
+++ b/sc/source/core/data/document.cxx
@@ -1774,6 +1774,15 @@ formula::VectorRefArray ScDocument::FetchVectorRefArray( const ScAddress& rPos,
     return maTabs[nTab]->FetchVectorRefArray(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
 }
 
+#ifdef DBG_UTIL
+void ScDocument::AssertNoInterpretNeeded( const ScAddress& rPos, SCROW nLength )
+{
+    SCTAB nTab = rPos.Tab();
+    assert(TableExists(nTab));
+    return maTabs[nTab]->AssertNoInterpretNeeded(rPos.Col(), rPos.Row(), rPos.Row()+nLength-1);
+}
+#endif
+
 void ScDocument::UnlockAdjustHeight()
 {
     assert(nAdjustHeightLock > 0);
diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index c3f12663b3c3..edbf1ab6e92e 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -4233,17 +4233,24 @@ struct ScDependantsCalculator
     const ScFormulaCellGroupRef& mxGroup;
     const SCROW mnLen;
     const ScAddress& mrPos;
+    const bool mFromFirstRow;
 
-    ScDependantsCalculator(ScDocument& rDoc, const ScTokenArray& rCode, const ScFormulaCell& rCell, const ScAddress& rPos) :
+    ScDependantsCalculator(ScDocument& rDoc, const ScTokenArray& rCode, const ScFormulaCell& rCell,
+            const ScAddress& rPos, bool fromFirstRow) :
         mrDoc(rDoc),
         mrCode(rCode),
         mxGroup(rCell.GetCellGroup()),
         mnLen(mxGroup->mnLength),
-        mrPos(rPos)
+        mrPos(rPos),
+        // ScColumn::FetchVectorRefArray() always fetches data from row 0, even if the data is used
+        // only from further rows. This data fetching could also lead to Interpret() calls, so
+        // in OpenCL mode the formula in practice depends on those cells too.
+        mFromFirstRow(fromFirstRow)
     {
     }
 
     // FIXME: copy-pasted from ScGroupTokenConverter. factor out somewhere else
+    // (note already modified a bit, mFromFirstRow)
 
     // I think what this function does is to check whether the relative row reference nRelRow points
     // to a row that is inside the range of rows covered by the formula group.
@@ -4268,6 +4275,9 @@ struct ScDependantsCalculator
             nTest += nRelRow;
             if (nTest <= nEndRow)
                 return true;
+            // If pointing below the formula, it's always included if going from first row.
+            if (mFromFirstRow)
+                return true;
         }
 
         return false;
@@ -4288,7 +4298,8 @@ struct ScDependantsCalculator
         if (rRefPos.Row() < mrPos.Row())
             return false;
 
-        if (rRefPos.Row() > nEndRow)
+        // If pointing below the formula, it's always included if going from first row.
+        if (rRefPos.Row() > nEndRow && !mFromFirstRow)
             return false;
 
         return true;
@@ -4324,6 +4335,11 @@ struct ScDependantsCalculator
             nRefStartRow <= nStartRow && nRefEndRow >= nEndRow)
             return true;
 
+        // If going from first row, the referenced range must be entirely above the formula,
+        // otherwise the formula would be included.
+        if (mFromFirstRow && nRefEndRow >= nStartRow)
+            return true;
+
         return false;
     }
 
@@ -4480,8 +4496,15 @@ struct ScDependantsCalculator
             assert(rRange.aStart.Tab() == rRange.aEnd.Tab());
             for (auto nCol = rRange.aStart.Col(); nCol <= rRange.aEnd.Col(); nCol++)
             {
-                if (!mrDoc.HandleRefArrayForParallelism(ScAddress(nCol, rRange.aStart.Row(), rRange.aStart.Tab()),
-                                                        rRange.aEnd.Row() - rRange.aStart.Row() + 1, mxGroup))
+                SCROW nStartRow = rRange.aStart.Row();
+                SCROW nLength = rRange.aEnd.Row() - rRange.aStart.Row() + 1;
+                if( mFromFirstRow )
+                {   // include also all previous rows
+                    nLength += nStartRow;
+                    nStartRow = 0;
+                }
+                if (!mrDoc.HandleRefArrayForParallelism(ScAddress(nCol, nStartRow, rRange.aStart.Tab()),
+                                                        nLength, mxGroup))
                     return false;
             }
         }
@@ -4562,7 +4585,7 @@ bool ScFormulaCell::InterpretFormulaGroup()
     return false;
 }
 
-bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope)
+bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rScope, bool fromFirstRow)
 {
     ScRecursionHelper& rRecursionHelper = pDocument->GetRecursionHelper();
     // iterate over code in the formula ...
@@ -4580,7 +4603,7 @@ bool ScFormulaCell::CheckComputeDependencies(sc::FormulaLogger::GroupScope& rSco
         }
 
         ScFormulaGroupDependencyComputeGuard aDepComputeGuard(rRecursionHelper);
-        ScDependantsCalculator aCalculator(*pDocument, *pCode, *this, mxGroup->mpTopCell->aPos);
+        ScDependantsCalculator aCalculator(*pDocument, *pCode, *this, mxGroup->mpTopCell->aPos, fromFirstRow);
         bOKToParallelize = aCalculator.DoIt();
     }
 
@@ -4764,7 +4787,7 @@ bool ScFormulaCell::InterpretFormulaGroupOpenCL(sc::FormulaLogger::GroupScope& a
     if (bDependencyCheckFailed)
         return false;
 
-    if(!bDependencyComputed && !CheckComputeDependencies(aScope))
+    if(!bDependencyComputed && !CheckComputeDependencies(aScope, true))
     {
         bDependencyComputed = true;
         bDependencyCheckFailed = true;
diff --git a/sc/source/core/data/grouptokenconverter.cxx b/sc/source/core/data/grouptokenconverter.cxx
index 1e9f5e5aa8c9..9da4dc476ea2 100644
--- a/sc/source/core/data/grouptokenconverter.cxx
+++ b/sc/source/core/data/grouptokenconverter.cxx
@@ -135,7 +135,20 @@ bool ScGroupTokenConverter::convert( const ScTokenArray& rCode, sc::FormulaLogge
 
                     formula::VectorRefArray aArray;
                     if (nTrimLen)
+                    {
+#ifdef DBG_UTIL
+                        // All the necessary Interpret() calls for all the cells
+                        // should have been already handled by ScDependantsCalculator
+                        // calling HandleRefArrayForParallelism(), and that handling also checks
+                        // for cycles etc. Recursively calling Interpret() from here (which shouldn't
+                        // happen) could lead to unhandled problems.
+                        // Also, because of caching FetchVectorRefArray() fetches values for all rows
+                        // up to the maximum one, so check those too.
+                        mrDoc.AssertNoInterpretNeeded(
+                            ScAddress(aRefPos.Col(), 0, aRefPos.Tab()), nTrimLen + aRefPos.Row());
+#endif
                         aArray = mrDoc.FetchVectorRefArray(aRefPos, nTrimLen);
+                    }
 
                     if (!aArray.isValid())
                         return false;
@@ -230,7 +243,13 @@ bool ScGroupTokenConverter::convert( const ScTokenArray& rCode, sc::FormulaLogge
                     aRefPos.SetCol(i);
                     formula::VectorRefArray aArray;
                     if (nArrayLength)
+                    {
+#ifdef DBG_UTIL
+                        mrDoc.AssertNoInterpretNeeded(
+                            ScAddress(aRefPos.Col(), 0, aRefPos.Tab()), nArrayLength + aRefPos.Row());
+#endif
                         aArray = mrDoc.FetchVectorRefArray(aRefPos, nArrayLength);
+                    }
 
                     if (!aArray.isValid())
                         return false;
diff --git a/sc/source/core/data/table1.cxx b/sc/source/core/data/table1.cxx
index 48a9ec2d4f36..ede4096b7f3d 100644
--- a/sc/source/core/data/table1.cxx
+++ b/sc/source/core/data/table1.cxx
@@ -2336,6 +2336,15 @@ formula::VectorRefArray ScTable::FetchVectorRefArray( SCCOL nCol, SCROW nRow1, S
     return aCol[nCol].FetchVectorRefArray(nRow1, nRow2);
 }
 
+#ifdef DBG_UTIL
+void ScTable::AssertNoInterpretNeeded( SCCOL nCol, SCROW nRow1, SCROW nRow2 )
+{
+    assert( nRow2 >= nRow1 );
+    assert( IsColValid( nCol ) && ValidRow( nRow1 ) && ValidRow( nRow2 ) );
+    return aCol[nCol].AssertNoInterpretNeeded(nRow1, nRow2);
+}
+#endif
+
 bool ScTable::HandleRefArrayForParallelism( SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScFormulaCellGroupRef& mxGroup )
 {
     if (nRow2 < nRow1)
commit d6c04fab56efc892948181a826ed76c4dcce39de
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Wed Nov 28 13:49:01 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:44:41 2018 +0100

    restore functionality of OpenCL ParallelReductionVectorRef class
    
    These functions were removed in 149a4d7566, although they quite clearly
    do serve a purpose, and then e9586cf0b5 removed the no longer used
    variables.
    Without this, ParallelReductionVectorRef class simply does not work.
    E.g. SUM(B1:B250) would not sum all the cells, but just one (testcase
    is Test::testFormulaRefUpdateRange with OpenCL forced).
    
    Change-Id: Iad1aeba2fbae2b4fc1d4236030adbb9ce6d972a1
    Reviewed-on: https://gerrit.libreoffice.org/64235
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 1b489b74fe28007749bec8a3ebd56901a7652734)
    Reviewed-on: https://gerrit.libreoffice.org/64462

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index b85a0a3166af..95863339c252 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -1225,6 +1225,7 @@ public:
                                std::shared_ptr<SlidingFunctionBase>& CodeGen, int index)
         : Base(config, s, ft, index)
         , mpCodeGen(CodeGen)
+        , mpClmem2(nullptr)
     {
         FormulaToken* t = ft->GetFormulaToken();
         if (t->GetType() != formula::svDoubleVectorRef)
@@ -1233,6 +1234,198 @@ public:
         bIsStartFixed = mpDVR->IsStartFixed();
         bIsEndFixed = mpDVR->IsEndFixed();
     }
+
+    /// Emit the definition for the auxiliary reduction kernel
+    virtual void GenSlidingWindowFunction( std::stringstream& ss )
+    {
+        if (!dynamic_cast<OpAverage*>(mpCodeGen.get()))
+        {
+            std::string name = Base::GetName();
+            ss << "__kernel void " << name;
+            ss << "_reduction(__global double* A, "
+                "__global double *result,int arrayLength,int windowSize){\n";
+            ss << "    double tmp, current_result =" <<
+                mpCodeGen->GetBottom();
+            ss << ";\n";
+            ss << "    int writePos = get_group_id(1);\n";
+            ss << "    int lidx = get_local_id(0);\n";
+            ss << "    __local double shm_buf[256];\n";
+            if (mpDVR->IsStartFixed())
+                ss << "    int offset = 0;\n";
+            else // if (!mpDVR->IsStartFixed())
+                ss << "    int offset = get_group_id(1);\n";
+            if (mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
+                ss << "    int end = windowSize;\n";
+            else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+                ss << "    int end = offset + windowSize;\n";
+            else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+                ss << "    int end = windowSize + get_group_id(1);\n";
+            else if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
+                ss << "    int end = windowSize;\n";
+            ss << "    end = min(end, arrayLength);\n";
+
+            ss << "    barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    int loop = arrayLength/512 + 1;\n";
+            ss << "    for (int l=0; l<loop; l++){\n";
+            ss << "    tmp = " << mpCodeGen->GetBottom() << ";\n";
+            ss << "    int loopOffset = l*512;\n";
+            ss << "    if((loopOffset + lidx + offset + 256) < end) {\n";
+            ss << "        tmp = legalize(" << mpCodeGen->Gen2(
+                "A[loopOffset + lidx + offset]", "tmp") << ", tmp);\n";
+            ss << "        tmp = legalize(" << mpCodeGen->Gen2(
+                "A[loopOffset + lidx + offset + 256]", "tmp") << ", tmp);\n";
+            ss << "    } else if ((loopOffset + lidx + offset) < end)\n";
+            ss << "        tmp = legalize(" << mpCodeGen->Gen2(
+                "A[loopOffset + lidx + offset]", "tmp") << ", tmp);\n";
+            ss << "    shm_buf[lidx] = tmp;\n";
+            ss << "    barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    for (int i = 128; i >0; i/=2) {\n";
+            ss << "        if (lidx < i)\n";
+            ss << "            shm_buf[lidx] = ";
+            // Special case count
+            if (dynamic_cast<OpCount*>(mpCodeGen.get()))
+                ss << "shm_buf[lidx] + shm_buf[lidx + i];\n";
+            else
+                ss << mpCodeGen->Gen2("shm_buf[lidx]", "shm_buf[lidx + i]") << ";\n";
+            ss << "        barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    }\n";
+            ss << "        if (lidx == 0)\n";
+            ss << "            current_result =";
+            if (dynamic_cast<OpCount*>(mpCodeGen.get()))
+                ss << "current_result + shm_buf[0]";
+            else
+                ss << mpCodeGen->Gen2("current_result", "shm_buf[0]");
+            ss << ";\n";
+            ss << "        barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    }\n";
+            ss << "    if (lidx == 0)\n";
+            ss << "        result[writePos] = current_result;\n";
+            ss << "}\n";
+        }
+        else
+        {
+            std::string name = Base::GetName();
+            /*sum reduction*/
+            ss << "__kernel void " << name << "_sum";
+            ss << "_reduction(__global double* A, "
+                "__global double *result,int arrayLength,int windowSize){\n";
+            ss << "    double tmp, current_result =" <<
+                mpCodeGen->GetBottom();
+            ss << ";\n";
+            ss << "    int writePos = get_group_id(1);\n";
+            ss << "    int lidx = get_local_id(0);\n";
+            ss << "    __local double shm_buf[256];\n";
+            if (mpDVR->IsStartFixed())
+                ss << "    int offset = 0;\n";
+            else // if (!mpDVR->IsStartFixed())
+                ss << "    int offset = get_group_id(1);\n";
+            if (mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
+                ss << "    int end = windowSize;\n";
+            else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+                ss << "    int end = offset + windowSize;\n";
+            else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+                ss << "    int end = windowSize + get_group_id(1);\n";
+            else if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
+                ss << "    int end = windowSize;\n";
+            ss << "    end = min(end, arrayLength);\n";
+            ss << "    barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    int loop = arrayLength/512 + 1;\n";
+            ss << "    for (int l=0; l<loop; l++){\n";
+            ss << "    tmp = " << mpCodeGen->GetBottom() << ";\n";
+            ss << "    int loopOffset = l*512;\n";
+            ss << "    if((loopOffset + lidx + offset + 256) < end) {\n";
+            ss << "        tmp = legalize(";
+            ss << "(A[loopOffset + lidx + offset]+ tmp)";
+            ss << ", tmp);\n";
+            ss << "        tmp = legalize((A[loopOffset + lidx + offset + 256]+ tmp)";
+            ss << ", tmp);\n";
+            ss << "    } else if ((loopOffset + lidx + offset) < end)\n";
+            ss << "        tmp = legalize((A[loopOffset + lidx + offset] + tmp)";
+            ss << ", tmp);\n";
+            ss << "    shm_buf[lidx] = tmp;\n";
+            ss << "    barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    for (int i = 128; i >0; i/=2) {\n";
+            ss << "        if (lidx < i)\n";
+            ss << "            shm_buf[lidx] = ";
+            ss << "shm_buf[lidx] + shm_buf[lidx + i];\n";
+            ss << "        barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    }\n";
+            ss << "        if (lidx == 0)\n";
+            ss << "            current_result =";
+            ss << "current_result + shm_buf[0]";
+            ss << ";\n";
+            ss << "        barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    }\n";
+            ss << "    if (lidx == 0)\n";
+            ss << "        result[writePos] = current_result;\n";
+            ss << "}\n";
+            /*count reduction*/
+            ss << "__kernel void " << name << "_count";
+            ss << "_reduction(__global double* A, "
+                "__global double *result,int arrayLength,int windowSize){\n";
+            ss << "    double tmp, current_result =" <<
+                mpCodeGen->GetBottom();
+            ss << ";\n";
+            ss << "    int writePos = get_group_id(1);\n";
+            ss << "    int lidx = get_local_id(0);\n";
+            ss << "    __local double shm_buf[256];\n";
+            if (mpDVR->IsStartFixed())
+                ss << "    int offset = 0;\n";
+            else // if (!mpDVR->IsStartFixed())
+                ss << "    int offset = get_group_id(1);\n";
+            if (mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
+                ss << "    int end = windowSize;\n";
+            else if (!mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+                ss << "    int end = offset + windowSize;\n";
+            else if (mpDVR->IsStartFixed() && !mpDVR->IsEndFixed())
+                ss << "    int end = windowSize + get_group_id(1);\n";
+            else if (!mpDVR->IsStartFixed() && mpDVR->IsEndFixed())
+                ss << "    int end = windowSize;\n";
+            ss << "    end = min(end, arrayLength);\n";
+            ss << "    barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    int loop = arrayLength/512 + 1;\n";
+            ss << "    for (int l=0; l<loop; l++){\n";
+            ss << "    tmp = " << mpCodeGen->GetBottom() << ";\n";
+            ss << "    int loopOffset = l*512;\n";
+            ss << "    if((loopOffset + lidx + offset + 256) < end) {\n";
+            ss << "        tmp = legalize((isnan(A[loopOffset + lidx + offset])?tmp:tmp+1.0)";
+            ss << ", tmp);\n";
+            ss << "        tmp = legalize((isnan(A[loopOffset + lidx + offset+256])?tmp:tmp+1.0)";
+            ss << ", tmp);\n";
+            ss << "    } else if ((loopOffset + lidx + offset) < end)\n";
+            ss << "        tmp = legalize((isnan(A[loopOffset + lidx + offset])?tmp:tmp+1.0)";
+            ss << ", tmp);\n";
+            ss << "    shm_buf[lidx] = tmp;\n";
+            ss << "    barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    for (int i = 128; i >0; i/=2) {\n";
+            ss << "        if (lidx < i)\n";
+            ss << "            shm_buf[lidx] = ";
+            ss << "shm_buf[lidx] + shm_buf[lidx + i];\n";
+            ss << "        barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    }\n";
+            ss << "        if (lidx == 0)\n";
+            ss << "            current_result =";
+            ss << "current_result + shm_buf[0];";
+            ss << ";\n";
+            ss << "        barrier(CLK_LOCAL_MEM_FENCE);\n";
+            ss << "    }\n";
+            ss << "    if (lidx == 0)\n";
+            ss << "        result[writePos] = current_result;\n";
+            ss << "}\n";
+        }
+
+    }
+
+    virtual std::string GenSlidingWindowDeclRef( bool ) const
+    {
+        std::stringstream 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(
         std::stringstream& ss, int nResultSize, bool& needBody )
@@ -1258,6 +1451,183 @@ public:
         return nCurWindowSize;
     }
 
+    virtual size_t Marshal( cl_kernel k, int argno, int w, cl_program mpProgram )
+    {
+        assert(Base::mpClmem == nullptr);
+
+        openclwrapper::KernelEnv kEnv;
+        openclwrapper::setKernelEnv(&kEnv);
+        cl_int err;
+        size_t nInput = mpDVR->GetArrayLength();
+        size_t nCurWindowSize = mpDVR->GetRefRowSize();
+        // create clmem buffer
+        if (mpDVR->GetArrays()[Base::mnIndex].mpNumericArray == nullptr)
+            throw Unhandled(__FILE__, __LINE__);
+        double* pHostBuffer = const_cast<double*>(
+            mpDVR->GetArrays()[Base::mnIndex].mpNumericArray);
+        size_t szHostBuffer = nInput * sizeof(double);
+        Base::mpClmem = clCreateBuffer(kEnv.mpkContext,
+            cl_mem_flags(CL_MEM_READ_ONLY) | CL_MEM_USE_HOST_PTR,
+            szHostBuffer,
+            pHostBuffer, &err);
+        SAL_INFO("sc.opencl", "Created buffer " << Base::mpClmem << " size " << nInput << "*" << sizeof(double) << "=" << szHostBuffer << " using host buffer " << pHostBuffer);
+
+        mpClmem2 = clCreateBuffer(kEnv.mpkContext,
+            CL_MEM_READ_WRITE | CL_MEM_ALLOC_HOST_PTR,
+            sizeof(double) * w, nullptr, nullptr);
+        if (CL_SUCCESS != err)
+            throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__);
+        SAL_INFO("sc.opencl", "Created buffer " << mpClmem2 << " size " << sizeof(double) << "*" << w << "=" << (sizeof(double)*w));
+
+        // reproduce the reduction function name
+        std::string kernelName;
+        if (!dynamic_cast<OpAverage*>(mpCodeGen.get()))
+            kernelName = Base::GetName() + "_reduction";
+        else
+            kernelName = Base::GetName() + "_sum_reduction";
+        cl_kernel redKernel = clCreateKernel(mpProgram, kernelName.c_str(), &err);
+        if (err != CL_SUCCESS)
+            throw OpenCLError("clCreateKernel", err, __FILE__, __LINE__);
+        SAL_INFO("sc.opencl", "Created kernel " << redKernel << " with name " << kernelName << " in program " << mpProgram);
+
+        // set kernel arg of reduction kernel
+        // TODO(Wei Wei): use unique name for kernel
+        cl_mem buf = Base::GetCLBuffer();
+        SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 0 << ": cl_mem: " << buf);
+        err = clSetKernelArg(redKernel, 0, sizeof(cl_mem),
+            static_cast<void*>(&buf));
+        if (CL_SUCCESS != err)
+            throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+
+        SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 1 << ": cl_mem: " << mpClmem2);
+        err = clSetKernelArg(redKernel, 1, sizeof(cl_mem), &mpClmem2);
+        if (CL_SUCCESS != err)
+            throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+
+        SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 2 << ": cl_int: " << nInput);
+        err = clSetKernelArg(redKernel, 2, sizeof(cl_int), static_cast<void*>(&nInput));
+        if (CL_SUCCESS != err)
+            throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+
+        SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 3 << ": cl_int: " << nCurWindowSize);
+        err = clSetKernelArg(redKernel, 3, sizeof(cl_int), static_cast<void*>(&nCurWindowSize));
+        if (CL_SUCCESS != err)
+            throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+
+        // set work group size and execute
+        size_t global_work_size[] = { 256, static_cast<size_t>(w) };
+        size_t const local_work_size[] = { 256, 1 };
+        SAL_INFO("sc.opencl", "Enqueing kernel " << redKernel);
+        err = clEnqueueNDRangeKernel(kEnv.mpkCmdQueue, redKernel, 2, nullptr,
+            global_work_size, local_work_size, 0, nullptr, nullptr);
+        if (CL_SUCCESS != err)
+            throw OpenCLError("clEnqueueNDRangeKernel", err, __FILE__, __LINE__);
+        err = clFinish(kEnv.mpkCmdQueue);
+        if (CL_SUCCESS != err)
+            throw OpenCLError("clFinish", err, __FILE__, __LINE__);
+        if (dynamic_cast<OpAverage*>(mpCodeGen.get()))
+        {
+            /*average need more reduction kernel for count computing*/
+            std::unique_ptr<double[]> pAllBuffer(new double[2 * w]);
+            double* resbuf = static_cast<double*>(clEnqueueMapBuffer(kEnv.mpkCmdQueue,
+                mpClmem2,
+                CL_TRUE, CL_MAP_READ, 0,
+                sizeof(double) * w, 0, nullptr, nullptr,
+                &err));
+            if (err != CL_SUCCESS)
+                throw OpenCLError("clEnqueueMapBuffer", err, __FILE__, __LINE__);
+
+            for (int i = 0; i < w; i++)
+                pAllBuffer[i] = resbuf[i];
+            err = clEnqueueUnmapMemObject(kEnv.mpkCmdQueue, mpClmem2, resbuf, 0, nullptr, nullptr);
+            if (err != CL_SUCCESS)
+                throw OpenCLError("clEnqueueUnmapMemObject", err, __FILE__, __LINE__);
+
+            kernelName = Base::GetName() + "_count_reduction";
+            redKernel = clCreateKernel(mpProgram, kernelName.c_str(), &err);
+            if (err != CL_SUCCESS)
+                throw OpenCLError("clCreateKernel", err, __FILE__, __LINE__);
+            SAL_INFO("sc.opencl", "Created kernel " << redKernel << " with name " << kernelName << " in program " << mpProgram);
+
+            // set kernel arg of reduction kernel
+            buf = Base::GetCLBuffer();
+            SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 0 << ": cl_mem: " << buf);
+            err = clSetKernelArg(redKernel, 0, sizeof(cl_mem),
+                static_cast<void*>(&buf));
+            if (CL_SUCCESS != err)
+                throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+
+            SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 1 << ": cl_mem: " << mpClmem2);
+            err = clSetKernelArg(redKernel, 1, sizeof(cl_mem), &mpClmem2);
+            if (CL_SUCCESS != err)
+                throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+
+            SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 2 << ": cl_int: " << nInput);
+            err = clSetKernelArg(redKernel, 2, sizeof(cl_int), static_cast<void*>(&nInput));
+            if (CL_SUCCESS != err)
+                throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+
+            SAL_INFO("sc.opencl", "Kernel " << redKernel << " arg " << 3 << ": cl_int: " << nCurWindowSize);
+            err = clSetKernelArg(redKernel, 3, sizeof(cl_int), static_cast<void*>(&nCurWindowSize));
+            if (CL_SUCCESS != err)
+                throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+
+            // set work group size and execute
+            size_t global_work_size1[] = { 256, static_cast<size_t>(w) };
+            size_t const local_work_size1[] = { 256, 1 };
+            SAL_INFO("sc.opencl", "Enqueing kernel " << redKernel);
+            err = clEnqueueNDRangeKernel(kEnv.mpkCmdQueue, redKernel, 2, nullptr,
+                global_work_size1, local_work_size1, 0, nullptr, nullptr);
+            if (CL_SUCCESS != err)
+                throw OpenCLError("clEnqueueNDRangeKernel", err, __FILE__, __LINE__);
+            err = clFinish(kEnv.mpkCmdQueue);
+            if (CL_SUCCESS != err)
+                throw OpenCLError("clFinish", err, __FILE__, __LINE__);
+            resbuf = static_cast<double*>(clEnqueueMapBuffer(kEnv.mpkCmdQueue,
+                mpClmem2,
+                CL_TRUE, CL_MAP_READ, 0,
+                sizeof(double) * w, 0, nullptr, nullptr,
+                &err));
+            if (err != CL_SUCCESS)
+                throw OpenCLError("clEnqueueMapBuffer", err, __FILE__, __LINE__);
+            for (int i = 0; i < w; i++)
+                pAllBuffer[i + w] = resbuf[i];
+            err = clEnqueueUnmapMemObject(kEnv.mpkCmdQueue, mpClmem2, resbuf, 0, nullptr, nullptr);
+            // FIXME: Is it intentional to not throw an OpenCLError even if the clEnqueueUnmapMemObject() fails?
+            if (CL_SUCCESS != err)
+                SAL_WARN("sc.opencl", "clEnqueueUnmapMemObject failed: " << openclwrapper::errorString(err));
+            if (mpClmem2)
+            {
+                err = clReleaseMemObject(mpClmem2);
+                SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject failed: " << openclwrapper::errorString(err));
+                mpClmem2 = nullptr;
+            }
+            mpClmem2 = clCreateBuffer(kEnv.mpkContext,
+                cl_mem_flags(CL_MEM_READ_WRITE) | CL_MEM_COPY_HOST_PTR,
+                w * sizeof(double) * 2, pAllBuffer.get(), &err);
+            if (CL_SUCCESS != err)
+                throw OpenCLError("clCreateBuffer", err, __FILE__, __LINE__);
+            SAL_INFO("sc.opencl", "Created buffer " << mpClmem2 << " size " << w << "*" << sizeof(double) << "=" << (w*sizeof(double)) << " copying host buffer " << pAllBuffer.get());
+        }
+        // set kernel arg
+        SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": cl_mem: " << mpClmem2);
+        err = clSetKernelArg(k, argno, sizeof(cl_mem), &(mpClmem2));
+        if (CL_SUCCESS != err)
+            throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
+        return 1;
+    }
+
+    ~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(); }
@@ -1271,6 +1641,8 @@ protected:
     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
commit a7ef1795314de8c9e98a47716562e3c1b85e38c4
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Tue Nov 27 21:40:22 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:44:31 2018 +0100

    fix OpenCL PRODUCT when there are actually no values
    
    PRODUCT() when there are no arguments (or all cells are empty) is 0.
    
    Change-Id: I4bcb9afe84d08833526255da0c61f6847d68ea36
    Reviewed-on: https://gerrit.libreoffice.org/64232
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 353bc9db255ca802c70b15e4d5d2e2fcbcee4fe8)
    Reviewed-on: https://gerrit.libreoffice.org/64461

diff --git a/sc/source/core/opencl/op_math.cxx b/sc/source/core/opencl/op_math.cxx
index 040c0afc4a55..45306aee893e 100644
--- a/sc/source/core/opencl/op_math.cxx
+++ b/sc/source/core/opencl/op_math.cxx
@@ -2711,7 +2711,8 @@ void OpProduct::GenSlidingWindowFunction(std::stringstream &ss,
     ss << ") {\n";
     ss << "    int gid0 = get_global_id(0);\n";
     ss << "    int i = 0;\n";
-    ss << "    double product=1.0;\n\n";
+    ss << "    double product=1.0;\n";
+    ss << "    int count = 0;\n\n";
     for (DynamicKernelArgumentRef & rArg : vSubArguments)
     {
         FormulaToken *pCur = rArg->GetFormulaToken();
@@ -2747,25 +2748,35 @@ void OpProduct::GenSlidingWindowFunction(std::stringstream &ss,
                  ss << "0; i < " << pDVR->GetArrayLength() << "; i++)\n";
                  ss << "    {\n";
             }
-            ss << "if(!isnan("<<rArg->GenSlidingWindowDeclRef()<<"))\n";
-            ss << "product = product*";
+            ss << "        if(!isnan("<<rArg->GenSlidingWindowDeclRef()<<"))\n";
+            ss << "        {\n";
+            ss << "            product = product*";
             ss << rArg->GenSlidingWindowDeclRef()<<";\n";
+            ss << "            ++count;\n";
+            ss << "        }\n";
             ss << "    }\n";
         }
         else if (pCur->GetType() == formula::svSingleVectorRef)
         {
-            ss << "if(!isnan("<<rArg->GenSlidingWindowDeclRef()<<"))\n";
-            ss << "product = product*";
+            ss << "    if(!isnan("<<rArg->GenSlidingWindowDeclRef()<<"))\n";
+            ss << "    {\n";
+            ss << "        product = product*";
             ss << rArg->GenSlidingWindowDeclRef()<<";\n";
-
+            ss << "        ++count;\n";
+            ss << "    }\n";
         }
         else
         {
-            ss << "if(!isnan("<<rArg->GenSlidingWindowDeclRef()<<"))\n";
-            ss << "product = product*";
+            ss << "    if(!isnan("<<rArg->GenSlidingWindowDeclRef()<<"))\n";
+            ss << "    {\n";
+            ss << "        product = product*";
             ss << rArg->GenSlidingWindowDeclRef()<<";\n";
+            ss << "        ++count;\n";
+            ss << "    }\n";
         }
     }
+    ss << "    if(count == 0)\n";
+    ss << "        return 0;\n";
     ss << "    return product;\n";
     ss << "}";
 }
commit e28b719ee82354d6cef0847d9dd601d1a0423460
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 16 19:42:03 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:44:15 2018 +0100

    make sure opencl is not used from withing ocTableOp
    
    Table operations do some tricks with reusing a cell with different values,
    and this confuses opencl handling, which operates on a group as a whole.
    Possibly relevant only with SC_FORCE_CALCULATION=opencl,
    sc_subsequent_filters_test fails in testDataTableOneVarXLSX().
    
    Change-Id: I55e0d238061c8a45a2388ccf6c769ff6a1fddbcc
    Reviewed-on: https://gerrit.libreoffice.org/64230
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 43922f1aaa3d7bced4b02f6662c5c12ee698132f)
    Reviewed-on: https://gerrit.libreoffice.org/64460

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index b45e04873cd1..c3f12663b3c3 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -4757,6 +4757,10 @@ bool ScFormulaCell::InterpretFormulaGroupOpenCL(sc::FormulaLogger::GroupScope& a
         return false;
     }
 
+    // TableOp does tricks with using a cell with different values, just bail out.
+    if(pDocument->IsInInterpreterTableOp())
+        return false;
+
     if (bDependencyCheckFailed)
         return false;
 
commit 0351f5b78795d1fbd52e1d073d7e50dc70626ecf
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 16 17:08:59 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:44:01 2018 +0100

    fix opencl INTRATE
    
    No idea why somebody thought pow() would be better than a mere division.
    Without this the unittest fails because of a slightly different result.
    
    Change-Id: Ibbde8b872049be310ac98389634aab6eab154ca6
    Reviewed-on: https://gerrit.libreoffice.org/64229
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 54ea2630358c9881d7efac592155924bd152db71)
    Reviewed-on: https://gerrit.libreoffice.org/64459

diff --git a/sc/source/core/opencl/op_financial.cxx b/sc/source/core/opencl/op_financial.cxx
index 747d8a764343..6b108eeed2d3 100644
--- a/sc/source/core/opencl/op_financial.cxx
+++ b/sc/source/core/opencl/op_financial.cxx
@@ -378,9 +378,8 @@ void OpINTRATE::GenSlidingWindowFunction(std::stringstream& ss,
         }
     }
     ss << "    int nNullDate = GetNullDate();\n";
-    ss << "    tmp = arg3 * pow(arg2,-1) - 1.0;\n";
-    ss << "    tmp = tmp * pow(GetYearDiff_new(nNullDate, (int)arg0,";
-    ss << " (int)arg1,(int)arg4),-1);\n";
+    ss << "    tmp = ((arg3 / arg2) - 1) / GetYearDiff_new(nNullDate, (int)arg0,";
+    ss << "             (int)arg1,(int)arg4);\n";
     ss << "    return tmp;\n";
     ss << "}";
 }
commit 5134c88cc6ca384e21419141400a843e64656503
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 16 16:49:29 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:43:42 2018 +0100

    sync PI value used in opencl SQRTPI to the one used in scaddins
    
    Otherwise the sqrtpi unittest fails in opencl mode. This value is less
    precise, but consistency should be more important here, not to mention
    that float doesn't have that high precision anyway.
    
    Change-Id: I8e85b7029d33932c81009e5d48e0fe2164c68dcf
    Reviewed-on: https://gerrit.libreoffice.org/64228
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 62b0bcfd85eb34ddd96d82c9f96a50588b9c4d80)
    Reviewed-on: https://gerrit.libreoffice.org/64458

diff --git a/sc/source/core/opencl/op_math.cxx b/sc/source/core/opencl/op_math.cxx
index 7f8305ecf708..040c0afc4a55 100644
--- a/sc/source/core/opencl/op_math.cxx
+++ b/sc/source/core/opencl/op_math.cxx
@@ -2483,7 +2483,7 @@ void OpSqrtPi::GenSlidingWindowFunction(std::stringstream &ss,
         ss << ";\n";
     }
     ss << "    return (double)sqrt(arg0 *";
-    ss << " 3.1415926535897932384626433832795f);\n";
+    ss << " 3.1415926535897932);\n";
     ss << "}";
 }
 void OpCeil::GenSlidingWindowFunction(std::stringstream &ss,
commit 496f5805e99821ff05966a915e006d53bd771de5
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 9 17:34:53 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:43:24 2018 +0100

    treat second argument of opencl's dollarde/dollarfr as integer
    
    That's how the scaddins implementation works, and the unittests fail
    in opencl mode without this.
    
    Change-Id: I08ea7dd0a0222408abf899d2da649be53f314a4c
    Reviewed-on: https://gerrit.libreoffice.org/64227
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 3441edd25e2f006db46a6c9f2351558910c6a614)
    Reviewed-on: https://gerrit.libreoffice.org/64457

diff --git a/sc/source/core/opencl/op_financial.cxx b/sc/source/core/opencl/op_financial.cxx
index 7504cad66617..747d8a764343 100644
--- a/sc/source/core/opencl/op_financial.cxx
+++ b/sc/source/core/opencl/op_financial.cxx
@@ -185,9 +185,9 @@ void OpDollarde::GenSlidingWindowFunction(
     ss << vSubArguments[1]->GenSlidingWindowDeclRef();
     ss<<"))\n\t\t";
     ss<<"fFrac = 0;\n\telse \n\t\t";
-    ss<<"fFrac = ";
+    ss<<"fFrac = (int)(";
     ss << vSubArguments[1]->GenSlidingWindowDeclRef();
-    ss<<";\n\t";
+    ss<<");\n\t";
     ss << "tmp = modf( dollar , &fInt );\n\t";
     ss << "tmp /= fFrac;\n\t";
     ss << "tmp *= pow( 10.0 , ceil( log10(fFrac ) ) );\n\t";
@@ -236,9 +236,9 @@ void OpDollarfr::GenSlidingWindowFunction(std::stringstream &ss,
     ss << vSubArguments[1]->GenSlidingWindowDeclRef();
     ss<<"))\n\t\t";
     ss<<"fFrac = 0;\n\telse \n\t\t";
-    ss<<"fFrac = ";
+    ss<<"fFrac = (int)(";
     ss << vSubArguments[1]->GenSlidingWindowDeclRef();
-    ss<<";\n\t";
+    ss<<");\n\t";
     ss << "tmp = modf( dollar , &fInt );\n\t";
     ss << "tmp *= fFrac;\n\t";
     ss << "tmp *= pow( 10.0 , -ceil( log10(fFrac ) ) );\n\t";
commit 355ff6333b3129dc4df9d5bc0e78b36b99a73686
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 9 13:53:19 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:43:05 2018 +0100

    disable opencl implementation of AMORDEGRC
    
    It fails sc_financial_functions_test with SC_FORCE_CALCULATION=opencl.
    
    Change-Id: If43928df8b1382eb7518fc99b6eee1759d822058
    Reviewed-on: https://gerrit.libreoffice.org/64225
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 4a9ace13b905189063f6792c9490a570e0eae59b)
    Reviewed-on: https://gerrit.libreoffice.org/64456

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index e18eeb9932d0..b85a0a3166af 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -3165,11 +3165,11 @@ DynamicKernelSoPArguments::DynamicKernelSoPArguments(const ScCalcConfig& config,
                     mvSubArguments.push_back(
                         SoPHelper(mCalcConfig, ts, ft->Children[i], new OpDuration_ADD));
                 }*/
-                else if (pChild->GetExternal() == "com.sun.star.sheet.addin.Analysis.getAmordegrc")
+                /*else if (pChild->GetExternal() == "com.sun.star.sheet.addin.Analysis.getAmordegrc")
                 {
                     mvSubArguments.push_back(SoPHelper(mCalcConfig, ts, ft->Children[i],
                             new OpAmordegrc, nResultSize));
-                }
+                }*/
                 else if (pChild->GetExternal() == "com.sun.star.sheet.addin.Analysis.getAmorlinc")
                 {
                     mvSubArguments.push_back(SoPHelper(mCalcConfig, ts, ft->Children[i],
commit 15427670da4efbfca43f44f47846543bd1a8d4d5
Author:     Luboš Luňák <l.lunak at collabora.com>
AuthorDate: Fri Nov 9 13:52:12 2018 +0100
Commit:     Luboš Luňák <l.lunak at collabora.com>
CommitDate: Tue Dec 4 17:42:38 2018 +0100

    avoid crash in opencl AMORDEGRC and AMORLINT argument handling
    
    The last argument is optional and defaults to 0 according to docs.
    
    Change-Id: I2e3aeb1da13b119e03e5bca18a63447e0fdc77fa
    Reviewed-on: https://gerrit.libreoffice.org/64224
    Tested-by: Jenkins
    Reviewed-by: Luboš Luňák <l.lunak at collabora.com>
    (cherry picked from commit 07e15bb76225d259a9be4c7a47b2af0c6cc5b033)
    Reviewed-on: https://gerrit.libreoffice.org/64455

diff --git a/sc/source/core/opencl/op_financial.cxx b/sc/source/core/opencl/op_financial.cxx
index c276e680f8ba..7504cad66617 100644
--- a/sc/source/core/opencl/op_financial.cxx
+++ b/sc/source/core/opencl/op_financial.cxx
@@ -3543,7 +3543,7 @@ void OpAmordegrc::GenSlidingWindowFunction(std::stringstream &ss,
     FormulaToken *tmpCur3 = vSubArguments[3]->GetFormulaToken();
     FormulaToken *tmpCur4 = vSubArguments[4]->GetFormulaToken();
     FormulaToken *tmpCur5 = vSubArguments[5]->GetFormulaToken();
-    FormulaToken *tmpCur6 = vSubArguments[6]->GetFormulaToken();
+    FormulaToken *tmpCur6 = vSubArguments.size() < 7 ? nullptr : vSubArguments[6]->GetFormulaToken();
     if(tmpCur0->GetType() == formula::svSingleVectorRef)
     {
     const formula::SingleVectorRefToken*tmpCurDVR0= static_cast<const
@@ -3610,17 +3610,24 @@ void OpAmordegrc::GenSlidingWindowFunction(std::stringstream &ss,
     ss << "        fRate=";
     ss << vSubArguments[5]->GenSlidingWindowDeclRef();
     ss << ";\n";
-    if(tmpCur6->GetType() == formula::svSingleVectorRef)
+    if(tmpCur6 == nullptr)
     {
-    const formula::SingleVectorRefToken*tmpCurDVR6= static_cast<const
-    formula::SingleVectorRefToken *>(tmpCur6);
-    ss <<"    if(isnan(" <<vSubArguments[6]->GenSlidingWindowDeclRef();
-    ss <<")||(gid0 >="<<tmpCurDVR6->GetArrayLength()<<"))\n";
-    ss <<"        nBase = 0;\n    else\n";
+        ss << "        nBase = 0;\n";
+    }
+    else
+    {
+        if(tmpCur6->GetType() == formula::svSingleVectorRef)
+        {
+            const formula::SingleVectorRefToken*tmpCurDVR6=
+                static_cast<const formula::SingleVectorRefToken *>(tmpCur6);
+            ss <<"    if(isnan(" <<vSubArguments[6]->GenSlidingWindowDeclRef();
+            ss <<")||(gid0 >="<<tmpCurDVR6->GetArrayLength()<<"))\n";
+            ss <<"        nBase = 0;\n    else\n";
+        }
+        ss << "        nBase = (int)";
+        ss << vSubArguments[6]->GenSlidingWindowDeclRef();
+        ss << ";\n";
     }
-    ss << "        nBase = (int)";
-    ss << vSubArguments[6]->GenSlidingWindowDeclRef();
-    ss << ";\n";
     ss <<"    uint nPer = convert_int( fPer );\n";
     ss <<"    double fUsePer = 1.0 *pow( fRate,-1);\n";
     ss <<"    double fAmorCoeff;\n";
@@ -3691,7 +3698,7 @@ void OpAmorlinc::GenSlidingWindowFunction(std::stringstream &ss,
     FormulaToken *tmpCur3 = vSubArguments[3]->GetFormulaToken();
     FormulaToken *tmpCur4 = vSubArguments[4]->GetFormulaToken();
     FormulaToken *tmpCur5 = vSubArguments[5]->GetFormulaToken();
-    FormulaToken *tmpCur6 = vSubArguments[6]->GetFormulaToken();
+    FormulaToken *tmpCur6 = vSubArguments.size() < 7 ? nullptr : vSubArguments[6]->GetFormulaToken();
     if(tmpCur0->GetType() == formula::svSingleVectorRef)
     {
     const formula::SingleVectorRefToken*tmpCurDVR0= static_cast<const
@@ -3758,17 +3765,24 @@ void OpAmorlinc::GenSlidingWindowFunction(std::stringstream &ss,
     ss << "        fRate=";
     ss << vSubArguments[5]->GenSlidingWindowDeclRef();
     ss << ";\n";
-    if(tmpCur6->GetType() == formula::svSingleVectorRef)
+    if(tmpCur6 == nullptr)
     {
-    const formula::SingleVectorRefToken*tmpCurDVR6= static_cast<const
-    formula::SingleVectorRefToken *>(tmpCur6);
-    ss <<"    if(isnan(" <<vSubArguments[6]->GenSlidingWindowDeclRef();
-    ss <<")||(gid0 >="<<tmpCurDVR6->GetArrayLength()<<"))\n";
-    ss <<"        nBase = 0;\n    else\n";
+        ss << "        nBase = 0;\n";
+    }
+    else
+    {
+        if(tmpCur6->GetType() == formula::svSingleVectorRef)
+        {
+            const formula::SingleVectorRefToken*tmpCurDVR6=
+                static_cast<const formula::SingleVectorRefToken *>(tmpCur6);
+            ss <<"    if(isnan(" <<vSubArguments[6]->GenSlidingWindowDeclRef();
+            ss <<")||(gid0 >="<<tmpCurDVR6->GetArrayLength()<<"))\n";
+            ss <<"        nBase = 0;\n    else\n";
+        }
+        ss << "        nBase = (int)";
+        ss << vSubArguments[6]->GenSlidingWindowDeclRef();
+        ss << ";\n";
     }
-    ss << "        nBase = (int)";
-    ss << vSubArguments[6]->GenSlidingWindowDeclRef();
-    ss << ";\n";
     ss <<"    int  nPer = convert_int( fPer );\n";
     ss <<"    double fOneRate = fCost * fRate;\n";
     ss <<"    double fCostDelta = fCost - fRestVal;\n";


More information about the Libreoffice-commits mailing list