[Libreoffice-commits] core.git: 22 commits - sc/inc sc/Library_sc.mk sc/qa sc/source

Kohei Yoshida kohei.yoshida at gmail.com
Wed Jul 10 21:25:06 PDT 2013


 sc/Library_sc.mk                         |    1 
 sc/inc/column.hxx                        |   31 
 sc/inc/formulagroup.hxx                  |    3 
 sc/inc/sharedformula.hxx                 |   92 +
 sc/qa/unit/ucalc.cxx                     |   77 -
 sc/qa/unit/ucalc.hxx                     |   18 
 sc/qa/unit/ucalc_sharedformula.cxx       |   80 +
 sc/source/core/data/column.cxx           |  114 +
 sc/source/core/data/column2.cxx          |    8 
 sc/source/core/data/column3.cxx          |  323 +---
 sc/source/core/data/formulacell.cxx      |    8 
 sc/source/core/opencl/formulagroupcl.cxx |  247 ++-
 sc/source/core/opencl/oclkernels.hxx     |  207 +-
 sc/source/core/opencl/openclwrapper.cxx  | 2159 +++++++++++++++++++++----------
 sc/source/core/opencl/openclwrapper.hxx  |  145 +-
 sc/source/core/tool/formulagroup.cxx     |   14 
 sc/source/core/tool/sharedformula.cxx    |  144 ++
 17 files changed, 2456 insertions(+), 1215 deletions(-)

New commits:
commit 76c6a4e328546d96f97daadbaf846be0a72c112a
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Wed Jul 10 22:09:29 2013 -0400

    Parse the token array in the RPN order.
    
    Change-Id: I3770269e23980597c16dd613704bd7a9feb0aec9

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index 04a67d2..dee465e 100755
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -295,7 +295,7 @@ public:
                            const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode);
 };
 
-#define RETURN_IF_FAIL(a,b) do { if (!(a)) { fprintf (stderr,b); return false; } } while (0)
+#define RETURN_IF_FAIL(a,b) do { if (!(a)) { fprintf (stderr,b"\n"); return false; } } while (0)
 
 #include "compiler.hxx"
 
@@ -313,61 +313,36 @@ bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAdd
     const double *pArrayToSubtractOneElementFrom;
     const double *pGroundWaterDataArray;
 
-    // Output:
-    std::vector<double> aMatrixContent;
+    const formula::FormulaToken* p = rCode.FirstRPN();
+    RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocPush && p->GetType() == formula::svDoubleVectorRef, "double vector ref expected");
 
-    const formula::FormulaToken *p;
+    // Get the range reference vector.
+    const formula::DoubleVectorRefToken* pDvr = static_cast<const formula::DoubleVectorRefToken*>(p);
+    const std::vector<const double*>& rArrays = pDvr->GetArrays();
+    RETURN_IF_FAIL(rArrays.size() == 1, "unexpectedly large double ref array");
+    RETURN_IF_FAIL(pDvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong double ref length");
+    RETURN_IF_FAIL(pDvr->IsStartFixed() && pDvr->IsEndFixed(), "non-fixed ranges )");
+    pGroundWaterDataArray = rArrays[0];
 
-    // special cased formula parser:
+    // Function:
+    p = rCode.NextRPN();
+    RETURN_IF_FAIL(p != NULL, "no operator");
+    eOp = p->GetOpCode();
+    RETURN_IF_FAIL(eOp == ocAverage || eOp == ocMax || eOp == ocMin, "unexpected opcode - expected either average, max, or min");
 
-    p = rCode.FirstNoSpaces();
-    RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocOpen, "no opening (");
+    p = rCode.NextRPN();
+    RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocPush && p->GetType() == formula::svSingleVectorRef, "single vector ref expected");
 
-    {
-        p = rCode.NextNoSpaces();
-        RETURN_IF_FAIL(p != NULL, "no operator");
-
-        // Function:
-        eOp = p->GetOpCode();
-        RETURN_IF_FAIL(eOp == ocAverage || eOp == ocMax || eOp == ocMin, "unexpected opcode");
-
-        { // function arguments
-            p = rCode.NextNoSpaces();
-            RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocOpen, "missing opening (");
-
-            p = rCode.NextNoSpaces();
-            RETURN_IF_FAIL(p != NULL, "no function argument");
-            RETURN_IF_FAIL(p->GetType() == formula::svDoubleVectorRef, "wrong type of fn argument");
-            const formula::DoubleVectorRefToken* pDvr = static_cast<const formula::DoubleVectorRefToken*>(p);
-            const std::vector<const double*>& rArrays = pDvr->GetArrays();
-            RETURN_IF_FAIL(rArrays.size() == 1, "unexpectedly large double ref array");
-            RETURN_IF_FAIL(pDvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong double ref length");
-            RETURN_IF_FAIL(pDvr->IsStartFixed() && pDvr->IsEndFixed(), "non-fixed ranges )");
-            pGroundWaterDataArray = rArrays[0];
-
-            p = rCode.NextNoSpaces();
-            RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocClose, "missing closing )");
-        }
+    // Get the single reference vector.
+    const formula::SingleVectorRefToken* pSvr = static_cast<const formula::SingleVectorRefToken*>(p);
+    pArrayToSubtractOneElementFrom = pSvr->GetArray();
+    RETURN_IF_FAIL(pSvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong single ref length");
 
-        // Subtract operator
-        p = rCode.NextNoSpaces();
-        RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocSub, "missing subtract opcode");
-
-        { // subtract parameter
-            p = rCode.NextNoSpaces();
-            RETURN_IF_FAIL(p != NULL, "no tokens");
-            RETURN_IF_FAIL(p->GetType() == formula::svSingleVectorRef, "not a single ref");
-            const formula::SingleVectorRefToken* pSvr = static_cast<const formula::SingleVectorRefToken*>(p);
-            pArrayToSubtractOneElementFrom = pSvr->GetArray();
-            RETURN_IF_FAIL(pSvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong single ref length");
-        }
-
-        p = rCode.NextNoSpaces();
-        RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocClose, "missing closing )");
-    }
+    p = rCode.NextRPN();
+    RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocSub, "missing subtract opcode");
 
-    p = rCode.NextNoSpaces();
-    RETURN_IF_FAIL(p == NULL, "has 5th");
+    p = rCode.NextRPN();
+    RETURN_IF_FAIL(p == NULL, "there should be no more token");
 
     static OclCalc ocl_calc;
 
@@ -380,7 +355,7 @@ bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAdd
     //   pArrayToSubtractOneElementFrom => contains L$5:L$7701 (ie. a copy)
     //   length of this array -> xGroup->mnLength
 
-    fprintf (stderr, "Calculate !\n");
+    fprintf (stderr, "Calculate !");
 
     double *pResult = ocl_calc.OclSimpleDeltaOperation( eOp, pGroundWaterDataArray,
                                                         pArrayToSubtractOneElementFrom,
commit de9dc7b88d7d7437ebc583b029fb46e2f1db8319
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Wed Jul 10 19:46:46 2013 -0400

    Move more methods to SharedFormulaUtil.
    
    Change-Id: Ibd58f5d15292805d50823223d1ebe94e7b51b808

diff --git a/sc/inc/sharedformula.hxx b/sc/inc/sharedformula.hxx
index 6767d4a..fa75e80 100644
--- a/sc/inc/sharedformula.hxx
+++ b/sc/inc/sharedformula.hxx
@@ -66,6 +66,16 @@ public:
     static void splitFormulaCellGroup(const CellStoreType::position_type& aPos);
 
     /**
+     * See if two specified adjacent formula cells can be merged, and if they
+     * can, merge them into the same group.
+     *
+     * @param rPos position object of the first cell
+     * @param rCell1 first cell
+     * @param rCell2 second cell located immediately below the first cell.
+     */
+    static void joinFormulaCells(
+        const CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2);
+    /**
      * Merge with an existing formula group (if any) located immediately above
      * if the cell at specified position is a formula cell, and its formula
      * tokens are identical to that of the above formula group.
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index de8adde..2136e04 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -306,69 +306,6 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( SCROW nRow )
     return GetPositionToInsert(maCells.begin(), nRow);
 }
 
-namespace {
-
-void joinFormulaCells(const sc::CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2)
-{
-    ScFormulaCell::CompareState eState = rCell1.CompareByTokenArray(rCell2);
-    if (eState == ScFormulaCell::NotEqual)
-        return;
-
-    SCROW nRow = rPos.first->position + rPos.second;
-
-    // Formula tokens equal those of the previous formula cell.
-    ScFormulaCellGroupRef xGroup1 = rCell1.GetCellGroup();
-    ScFormulaCellGroupRef xGroup2 = rCell2.GetCellGroup();
-    if (xGroup1)
-    {
-        if (xGroup2)
-        {
-            // Both cell 1 and cell 2 are shared. Merge them together.
-            if (xGroup1.get() == xGroup2.get())
-                // They belong to the same group.
-                return;
-
-            // Set the group object from cell 1 to all cells in group 2.
-            xGroup1->mnLength += xGroup2->mnLength;
-            size_t nOffset = rPos.second + 1; // position of cell 2
-            for (size_t i = 0, n = xGroup2->mnLength; i < n; ++i)
-            {
-                ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, nOffset+i);
-                rCell.SetCellGroup(xGroup1);
-            }
-        }
-        else
-        {
-            // cell 1 is shared but cell 2 is not.
-            rCell2.SetCellGroup(xGroup1);
-            ++xGroup1->mnLength;
-        }
-    }
-    else
-    {
-        if (xGroup2)
-        {
-            // cell 1 is not shared, but cell 2 is already shared.
-            rCell1.SetCellGroup(xGroup2);
-            xGroup2->mnStart = nRow;
-            ++xGroup2->mnLength;
-        }
-        else
-        {
-            // neither cells are shared.
-            xGroup1.reset(new ScFormulaCellGroup);
-            xGroup1->mnStart = nRow;
-            xGroup1->mbInvariant = (eState == ScFormulaCell::EqualInvariant);
-            xGroup1->mnLength = 2;
-
-            rCell1.SetCellGroup(xGroup1);
-            rCell2.SetCellGroup(xGroup1);
-        }
-    }
-}
-
-}
-
 void ScColumn::JoinNewFormulaCell(
     const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const
 {
@@ -378,14 +315,14 @@ void ScColumn::JoinNewFormulaCell(
         ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
         sc::CellStoreType::position_type aPosPrev = aPos;
         --aPosPrev.second;
-        joinFormulaCells(aPosPrev, rPrev, rCell);
+        sc::SharedFormulaUtil::joinFormulaCells(aPosPrev, rPrev, rCell);
     }
 
     // Check the next row position for possible grouping.
     if (aPos.first->type == sc::element_type_formula && aPos.second+1 < aPos.first->size)
     {
         ScFormulaCell& rNext = *sc::formula_block::at(*aPos.first->data, aPos.second+1);
-        joinFormulaCells(aPos, rCell, rNext);
+        sc::SharedFormulaUtil::joinFormulaCells(aPos, rCell, rNext);
     }
 }
 
diff --git a/sc/source/core/tool/sharedformula.cxx b/sc/source/core/tool/sharedformula.cxx
index c1bc564..5cdfc785 100644
--- a/sc/source/core/tool/sharedformula.cxx
+++ b/sc/source/core/tool/sharedformula.cxx
@@ -62,9 +62,7 @@ void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type
     }
 }
 
-namespace {
-
-void joinFormulaCells(const sc::CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2)
+void SharedFormulaUtil::joinFormulaCells(const CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2)
 {
     ScFormulaCell::CompareState eState = rCell1.CompareByTokenArray(rCell2);
     if (eState == ScFormulaCell::NotEqual)
@@ -123,8 +121,6 @@ void joinFormulaCells(const sc::CellStoreType::position_type& rPos, ScFormulaCel
     }
 }
 
-}
-
 void SharedFormulaUtil::joinFormulaCellAbove(const CellStoreType::position_type& aPos)
 {
     if (aPos.first->type != sc::element_type_formula)
commit 1fd0ab0c53e73b50857e5bfed4b307468202354f
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Wed Jul 10 19:34:34 2013 -0400

    Move these methods out of ScColumn since they don't operate on column.
    
    Change-Id: I1a03b9b18dd236138306fd545e961a5443e22bc8

diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index 01e9ef7..2c59b77 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -503,15 +503,6 @@ public:
     void UnshareFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const;
 
     /**
-     * Split existing shared formula range at specified position. The cell at
-     * specified position becomes the top cell of the lower shared formula
-     * range after this call.
-     */
-    void SplitFormulaCellGroup( const sc::CellStoreType::position_type& aPos ) const;
-
-    void JoinFormulaCellAbove( const sc::CellStoreType::position_type& aPos ) const;
-
-    /**
      * Regroup formula cells for the entire column.
      */
     void RegroupFormulaCells();
diff --git a/sc/inc/sharedformula.hxx b/sc/inc/sharedformula.hxx
index fcab6d7..6767d4a 100644
--- a/sc/inc/sharedformula.hxx
+++ b/sc/inc/sharedformula.hxx
@@ -11,6 +11,7 @@
 #define SC_SHAREDFORMULA_HXX
 
 #include "formulacell.hxx"
+#include "mtvelements.hxx"
 
 namespace sc {
 
@@ -18,6 +19,10 @@ class SharedFormulaUtil
 {
 public:
 
+    /**
+     * Group formula cells stored in the passed container. The formula cells
+     * in the container are assumed to be all <b>non-shared</b>.
+     */
     template<typename _Iter>
     static void groupFormulaCells(const _Iter& itBeg, const _Iter& itEnd)
     {
@@ -49,6 +54,25 @@ public:
             pCur->SetCellGroup(xGroup);
         }
     }
+
+    /**
+     * Split existing shared formula range at specified position. The cell at
+     * specified position becomes the top cell of the lower shared formula
+     * range after this call.  This method does nothing if the cell at
+     * specified position is not a formula cell.
+     *
+     * @param aPos position of cell to examine.
+     */
+    static void splitFormulaCellGroup(const CellStoreType::position_type& aPos);
+
+    /**
+     * Merge with an existing formula group (if any) located immediately above
+     * if the cell at specified position is a formula cell, and its formula
+     * tokens are identical to that of the above formula group.
+     *
+     * @param aPos position of cell to examine.
+     */
+    static void joinFormulaCellAbove(const CellStoreType::position_type& aPos);
 };
 
 }
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index b777905..730fed4 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -1383,12 +1383,12 @@ public:
                 sc::CellStoreType::position_type aPos =
                     rDestCells.position(maDestPos.miCellPos, nTopRow);
                 maDestPos.miCellPos = aPos.first;
-                mrDestCol.JoinFormulaCellAbove(aPos);
+                sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
                 size_t nLastRow = nTopRow + nDataSize;
                 if (nLastRow < static_cast<size_t>(MAXROW))
                 {
                     aPos = rDestCells.position(maDestPos.miCellPos, nLastRow+1);
-                    mrDestCol.JoinFormulaCellAbove(aPos);
+                    sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
                 }
 
                 setDefaultAttrsToDest(nTopRow, nDataSize);
@@ -2170,15 +2170,15 @@ void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
 
     // Split the formula grouping at the top and bottom boundaries.
     sc::CellStoreType::position_type aPos = maCells.position(nStartRow);
-    SplitFormulaCellGroup(aPos);
+    sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
     aPos = maCells.position(aPos.first, nEndRow+1);
-    SplitFormulaCellGroup(aPos);
+    sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
 
     // Do the same with the destination column.
     aPos = rCol.maCells.position(nStartRow);
-    rCol.SplitFormulaCellGroup(aPos);
+    sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
     aPos = rCol.maCells.position(aPos.first, nEndRow+1);
-    rCol.SplitFormulaCellGroup(aPos);
+    sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
 
     // Move the broadcasters to the destination column.
     maBroadcasters.transfer(nStartRow, nEndRow, rCol.maBroadcasters, nStartRow);
@@ -2187,9 +2187,9 @@ void ScColumn::MoveTo(SCROW nStartRow, SCROW nEndRow, ScColumn& rCol)
 
     // Re-group transferred formula cells.
     aPos = rCol.maCells.position(nStartRow);
-    rCol.JoinFormulaCellAbove(aPos);
+    sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
     aPos = rCol.maCells.position(aPos.first, nEndRow+1);
-    rCol.JoinFormulaCellAbove(aPos);
+    sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
 
     CellStorageModified();
     rCol.CellStorageModified();
@@ -2315,11 +2315,11 @@ bool ScColumn::UpdateReferenceOnCopy(
 
     // The formula groups at the top and bottom boundaries are expected to
     // have been split prior to this call. Here, we only do the joining.
-    JoinFormulaCellAbove(aPos);
+    sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
     if (rRange.aEnd.Row() < MAXROW)
     {
         aPos = maCells.position(aPos.first, rRange.aEnd.Row()+1);
-        JoinFormulaCellAbove(aPos);
+        sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
     }
 
     return aHandler.isUpdated();
@@ -2341,12 +2341,12 @@ bool ScColumn::UpdateReference(
         if (ValidRow(nSplitPos))
         {
             sc::CellStoreType::position_type aPos = maCells.position(nSplitPos);
-            SplitFormulaCellGroup(aPos);
+            sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
             nSplitPos = rRange.aEnd.Row() + 1;
             if (ValidRow(nSplitPos))
             {
                 aPos = maCells.position(aPos.first, nSplitPos);
-                SplitFormulaCellGroup(aPos);
+                sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
             }
         }
     }
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 4fb06c3..de8adde 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -281,7 +281,7 @@ void ScColumn::DeleteRow( SCROW nStartRow, SCSIZE nSize )
     ShiftFormulaPosHandler aShiftFormulaFunc;
     sc::ProcessFormula(aPos.first, maCells, nStartRow, MAXROW, aShiftFormulaFunc);
 
-    JoinFormulaCellAbove(aPos);
+    sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
 
     // Single cell broadcasts on deleted cells.
     BroadcastCells(aDeleteRowsFunc.getNonEmptyRows());
@@ -420,13 +420,13 @@ void ScColumn::DetachFormulaCells(
     const sc::CellStoreType::position_type& aPos, size_t nLength )
 {
     // Split formula grouping at the top and bottom boundaries.
-    SplitFormulaCellGroup(aPos);
+    sc::SharedFormulaUtil::splitFormulaCellGroup(aPos);
     size_t nRow = aPos.first->position + aPos.second;
     size_t nNextTopRow = nRow + nLength; // start row of next formula group.
     if (ValidRow(nNextTopRow))
     {
         sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow);
-        SplitFormulaCellGroup(aPos2);
+        sc::SharedFormulaUtil::splitFormulaCellGroup(aPos2);
     }
 
     if (pDocument->IsClipOrUndo())
@@ -555,74 +555,6 @@ void ScColumn::UnshareFormulaCell(
     rCell.SetCellGroup(xNone);
 }
 
-void ScColumn::SplitFormulaCellGroup( const sc::CellStoreType::position_type& aPos ) const
-{
-    SCROW nRow = aPos.first->position + aPos.second;
-
-    if (aPos.first->type != sc::element_type_formula)
-        // Not a formula cell block.
-        return;
-
-    if (aPos.second == 0)
-        // Split position coincides with the block border. Nothing to do.
-        return;
-
-    sc::formula_block::iterator it = sc::formula_block::begin(*aPos.first->data);
-    std::advance(it, aPos.second);
-    ScFormulaCell& rTop = **it;
-    if (!rTop.IsShared())
-        // Not a shared formula.
-        return;
-
-    if (nRow == rTop.GetSharedTopRow())
-        // Already the top cell of a shared group.
-        return;
-
-    ScFormulaCellGroupRef xGroup = rTop.GetCellGroup();
-
-    ScFormulaCellGroupRef xGroup2(new ScFormulaCellGroup);
-    xGroup2->mbInvariant = xGroup->mbInvariant;
-    xGroup2->mnStart = nRow;
-    xGroup2->mnLength = xGroup->mnStart + xGroup->mnLength - nRow;
-
-    xGroup->mnLength = nRow - xGroup->mnStart;
-
-    // Apply the lower group object to the lower cells.
-#if DEBUG_COLUMN_STORAGE
-        if (xGroup2->mnStart + xGroup2->mnLength > aPos.first->position + aPos.first->size)
-        {
-            cerr << "ScColumn::SplitFormulaCellGroup: Shared formula region goes beyond the formula block. Not good." << endl;
-            cerr.flush();
-            abort();
-        }
-#endif
-    sc::formula_block::iterator itEnd = it;
-    std::advance(itEnd, xGroup2->mnLength);
-    for (; it != itEnd; ++it)
-    {
-        ScFormulaCell& rCell = **it;
-        rCell.SetCellGroup(xGroup2);
-    }
-}
-
-void ScColumn::JoinFormulaCellAbove( const sc::CellStoreType::position_type& aPos ) const
-{
-    if (aPos.first->type != sc::element_type_formula)
-        // This is not a formula cell.
-        return;
-
-    if (aPos.second == 0)
-        // This cell is already the top cell in a formula block; the previous
-        // cell is not a formula cell.
-        return;
-
-    ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
-    ScFormulaCell& rCell = *sc::formula_block::at(*aPos.first->data, aPos.second);
-    sc::CellStoreType::position_type aPosPrev = aPos;
-    --aPosPrev.second;
-    joinFormulaCells(aPosPrev, rPrev, rCell);
-}
-
 sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreType::iterator& it, SCROW nRow )
 {
     // See if we are overwriting an existing formula cell.
@@ -1545,14 +1477,14 @@ public:
 
                     // Merge with the previous formula group (if any).
                     aPos = rDestCells.position(itDestPos, nDestRow);
-                    mrDestColumn.JoinFormulaCellAbove(aPos);
+                    sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
 
                     // Merge with the next formula group (if any).
                     size_t nNextRow = nDestRow + it->size;
                     if (ValidRow(nNextRow))
                     {
                         aPos = rDestCells.position(aPos.first, nNextRow);
-                        mrDestColumn.JoinFormulaCellAbove(aPos);
+                        sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
                     }
                 }
                 break;
diff --git a/sc/source/core/tool/sharedformula.cxx b/sc/source/core/tool/sharedformula.cxx
index 7b6ac84..c1bc564 100644
--- a/sc/source/core/tool/sharedformula.cxx
+++ b/sc/source/core/tool/sharedformula.cxx
@@ -8,10 +8,140 @@
  */
 
 #include "sharedformula.hxx"
+#include "calcmacros.hxx"
 
 namespace sc {
 
+void SharedFormulaUtil::splitFormulaCellGroup(const CellStoreType::position_type& aPos)
+{
+    SCROW nRow = aPos.first->position + aPos.second;
 
+    if (aPos.first->type != sc::element_type_formula)
+        // Not a formula cell block.
+        return;
+
+    if (aPos.second == 0)
+        // Split position coincides with the block border. Nothing to do.
+        return;
+
+    sc::formula_block::iterator it = sc::formula_block::begin(*aPos.first->data);
+    std::advance(it, aPos.second);
+    ScFormulaCell& rTop = **it;
+    if (!rTop.IsShared())
+        // Not a shared formula.
+        return;
+
+    if (nRow == rTop.GetSharedTopRow())
+        // Already the top cell of a shared group.
+        return;
+
+    ScFormulaCellGroupRef xGroup = rTop.GetCellGroup();
+
+    ScFormulaCellGroupRef xGroup2(new ScFormulaCellGroup);
+    xGroup2->mbInvariant = xGroup->mbInvariant;
+    xGroup2->mnStart = nRow;
+    xGroup2->mnLength = xGroup->mnStart + xGroup->mnLength - nRow;
+
+    xGroup->mnLength = nRow - xGroup->mnStart;
+
+    // Apply the lower group object to the lower cells.
+#if DEBUG_COLUMN_STORAGE
+        if (xGroup2->mnStart + xGroup2->mnLength > aPos.first->position + aPos.first->size)
+        {
+            cerr << "ScColumn::SplitFormulaCellGroup: Shared formula region goes beyond the formula block. Not good." << endl;
+            cerr.flush();
+            abort();
+        }
+#endif
+    sc::formula_block::iterator itEnd = it;
+    std::advance(itEnd, xGroup2->mnLength);
+    for (; it != itEnd; ++it)
+    {
+        ScFormulaCell& rCell = **it;
+        rCell.SetCellGroup(xGroup2);
+    }
+}
+
+namespace {
+
+void joinFormulaCells(const sc::CellStoreType::position_type& rPos, ScFormulaCell& rCell1, ScFormulaCell& rCell2)
+{
+    ScFormulaCell::CompareState eState = rCell1.CompareByTokenArray(rCell2);
+    if (eState == ScFormulaCell::NotEqual)
+        return;
+
+    SCROW nRow = rPos.first->position + rPos.second;
+
+    // Formula tokens equal those of the previous formula cell.
+    ScFormulaCellGroupRef xGroup1 = rCell1.GetCellGroup();
+    ScFormulaCellGroupRef xGroup2 = rCell2.GetCellGroup();
+    if (xGroup1)
+    {
+        if (xGroup2)
+        {
+            // Both cell 1 and cell 2 are shared. Merge them together.
+            if (xGroup1.get() == xGroup2.get())
+                // They belong to the same group.
+                return;
+
+            // Set the group object from cell 1 to all cells in group 2.
+            xGroup1->mnLength += xGroup2->mnLength;
+            size_t nOffset = rPos.second + 1; // position of cell 2
+            for (size_t i = 0, n = xGroup2->mnLength; i < n; ++i)
+            {
+                ScFormulaCell& rCell = *sc::formula_block::at(*rPos.first->data, nOffset+i);
+                rCell.SetCellGroup(xGroup1);
+            }
+        }
+        else
+        {
+            // cell 1 is shared but cell 2 is not.
+            rCell2.SetCellGroup(xGroup1);
+            ++xGroup1->mnLength;
+        }
+    }
+    else
+    {
+        if (xGroup2)
+        {
+            // cell 1 is not shared, but cell 2 is already shared.
+            rCell1.SetCellGroup(xGroup2);
+            xGroup2->mnStart = nRow;
+            ++xGroup2->mnLength;
+        }
+        else
+        {
+            // neither cells are shared.
+            xGroup1.reset(new ScFormulaCellGroup);
+            xGroup1->mnStart = nRow;
+            xGroup1->mbInvariant = (eState == ScFormulaCell::EqualInvariant);
+            xGroup1->mnLength = 2;
+
+            rCell1.SetCellGroup(xGroup1);
+            rCell2.SetCellGroup(xGroup1);
+        }
+    }
+}
+
+}
+
+void SharedFormulaUtil::joinFormulaCellAbove(const CellStoreType::position_type& aPos)
+{
+    if (aPos.first->type != sc::element_type_formula)
+        // This is not a formula cell.
+        return;
+
+    if (aPos.second == 0)
+        // This cell is already the top cell in a formula block; the previous
+        // cell is not a formula cell.
+        return;
+
+    ScFormulaCell& rPrev = *sc::formula_block::at(*aPos.first->data, aPos.second-1);
+    ScFormulaCell& rCell = *sc::formula_block::at(*aPos.first->data, aPos.second);
+    sc::CellStoreType::position_type aPosPrev = aPos;
+    --aPosPrev.second;
+    joinFormulaCells(aPosPrev, rPrev, rCell);
+}
 
 }
 
commit 0797dd8714413f8319515df9831a86703b589558
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Wed Jul 10 16:32:39 2013 -0400

    Group formula cells in ScColumn::MixData().
    
    Change-Id: I38186e2bf82ed56fbe859b17dcc1d31f36471bd8

diff --git a/sc/Library_sc.mk b/sc/Library_sc.mk
index 5815fd0..d431c3c 100644
--- a/sc/Library_sc.mk
+++ b/sc/Library_sc.mk
@@ -251,6 +251,7 @@ $(eval $(call gb_Library_add_exception_objects,sc,\
 	sc/source/core/tool/refupdat \
 	sc/source/core/tool/scmatrix \
 	sc/source/core/tool/scopetools \
+	sc/source/core/tool/sharedformula \
 	sc/source/core/tool/simplerangelist \
 	sc/source/core/tool/stringutil \
 	sc/source/core/tool/stylehelper \
diff --git a/sc/inc/column.hxx b/sc/inc/column.hxx
index d024007..01e9ef7 100644
--- a/sc/inc/column.hxx
+++ b/sc/inc/column.hxx
@@ -487,17 +487,18 @@ public:
     bool HasBroadcaster() const;
 
     void BroadcastCells( const std::vector<SCROW>& rRows );
-    void EndFormulaListening( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 );
 
     void InterpretDirtyCells( SCROW nRow1, SCROW nRow2 );
 
     void JoinNewFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const;
 
     /**
-     * Detouch a formula cell that's about to be deleted, or removed from
+     * Detach a formula cell that's about to be deleted, or removed from
      * document storage (if that ever happens).
      */
-    void DetouchFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const;
+    void DetachFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell );
+
+    void DetachFormulaCells( const sc::CellStoreType::position_type& aPos, size_t nLength );
 
     void UnshareFormulaCell( const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const;
 
@@ -515,14 +516,6 @@ public:
      */
     void RegroupFormulaCells();
 
-    /**
-     * Regroup existing formula cells when a range of new cells are inserted.
-     *
-     * @param nRow1 first row of inserted new cell span.
-     * @param nRow2 last row of inserted new cell span.
-     */
-    void RegroupFormulaCells( SCROW nRow1, SCROW nRow2 );
-
 #if DEBUG_COLUMN_STORAGE
     void DumpFormulaGroups() const;
 #endif
diff --git a/sc/inc/sharedformula.hxx b/sc/inc/sharedformula.hxx
new file mode 100644
index 0000000..fcab6d7
--- /dev/null
+++ b/sc/inc/sharedformula.hxx
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#ifndef SC_SHAREDFORMULA_HXX
+#define SC_SHAREDFORMULA_HXX
+
+#include "formulacell.hxx"
+
+namespace sc {
+
+class SharedFormulaUtil
+{
+public:
+
+    template<typename _Iter>
+    static void groupFormulaCells(const _Iter& itBeg, const _Iter& itEnd)
+    {
+        _Iter it = itBeg;
+        ScFormulaCell* pPrev = *it;
+        ScFormulaCell* pCur = NULL;
+        for (++it; it != itEnd; ++it, pPrev = pCur)
+        {
+            pCur = *it;
+            ScFormulaCell::CompareState eState = pPrev->CompareByTokenArray(*pPrev);
+            if (eState == ScFormulaCell::NotEqual)
+                continue;
+
+            ScFormulaCellGroupRef xGroup = pPrev->GetCellGroup();
+            if (xGroup)
+            {
+                // Extend the group.
+                ++xGroup->mnLength;
+                pCur->SetCellGroup(xGroup);
+                continue;
+            }
+
+            // Create a new group.
+            xGroup.reset(new ScFormulaCellGroup);
+            xGroup->mnStart = pPrev->aPos.Row();
+            xGroup->mnLength = 2;
+            xGroup->mbInvariant = (eState == ScFormulaCell::EqualInvariant);
+            pPrev->SetCellGroup(xGroup);
+            pCur->SetCellGroup(xGroup);
+        }
+    }
+};
+
+}
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/data/column.cxx b/sc/source/core/data/column.cxx
index ad51473..b777905 100644
--- a/sc/source/core/data/column.cxx
+++ b/sc/source/core/data/column.cxx
@@ -39,6 +39,7 @@
 #include "mtvcellfunc.hxx"
 #include "columnspanset.hxx"
 #include "scopetools.hxx"
+#include "sharedformula.hxx"
 
 #include <svl/poolcach.hxx>
 #include <svl/zforlist.hxx>
@@ -868,8 +869,8 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
                 // TODO: Find out a way to adjust references without cloning new instances.
                 boost::scoped_ptr<ScFormulaCell> pOld1(*itf1);
                 boost::scoped_ptr<ScFormulaCell> pOld2(*itf2);
-                DetouchFormulaCell(aPos1, **itf1);
-                DetouchFormulaCell(aPos2, **itf2);
+                DetachFormulaCell(aPos1, **itf1);
+                DetachFormulaCell(aPos2, **itf2);
                 ScFormulaCell* pNew1 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *pOld2);
                 ScFormulaCell* pNew2 = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *pOld1);
                 *itf1 = pNew1;
@@ -920,7 +921,7 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
             {
                 // cell 1 is empty and cell 2 is a formula cell.
                 ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
-                DetouchFormulaCell(aPos2, *aCell2.mpFormula);
+                DetachFormulaCell(aPos2, *aCell2.mpFormula);
                 it1 = maCells.set(it1, nRow1, pNew);
                 maCells.set_empty(it1, nRow2, nRow2); // original formula cell gets deleted.
                 ActivateNewFormulaCell(it1, nRow1, *pNew);
@@ -964,7 +965,7 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
             {
                 // cell 1 is a formula cell and cell 2 is empty.
                 ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *aCell1.mpFormula);
-                DetouchFormulaCell(aPos1, *aCell1.mpFormula);
+                DetachFormulaCell(aPos1, *aCell1.mpFormula);
                 it1 = maCells.set_empty(it1, nRow1, nRow1); // original formula cell is gone.
                 it1 = maCells.set(it1, nRow2, pNew);
                 ActivateNewFormulaCell(it1, nRow2, *pNew);
@@ -999,7 +1000,7 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
                 break;
                 case CELLTYPE_FORMULA:
                 {
-                    DetouchFormulaCell(aPos2, *aCell2.mpFormula);
+                    DetachFormulaCell(aPos2, *aCell2.mpFormula);
                     ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
                     it1 = maCells.set(it1, nRow1, pNew);
                     ActivateNewFormulaCell(it1, nRow1, *pNew);
@@ -1032,7 +1033,7 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
                 case CELLTYPE_FORMULA:
                 {
                     // cell 1 - string, cell 2 - formula
-                    DetouchFormulaCell(aPos2, *aCell2.mpFormula);
+                    DetachFormulaCell(aPos2, *aCell2.mpFormula);
                     ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
                     it1 = maCells.set(it1, nRow1, pNew);
                     ActivateNewFormulaCell(it1, nRow1, *pNew);
@@ -1061,7 +1062,7 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
                 break;
                 case CELLTYPE_FORMULA:
                 {
-                    DetouchFormulaCell(aPos2, *aCell2.mpFormula);
+                    DetachFormulaCell(aPos2, *aCell2.mpFormula);
                     ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow1, nTab), *aCell2.mpFormula);
                     it1 = maCells.set(it1, nRow1, pNew);
                     ActivateNewFormulaCell(it1, nRow1, *pNew);
@@ -1078,7 +1079,7 @@ void ScColumn::SwapRow(SCROW nRow1, SCROW nRow2)
         case CELLTYPE_FORMULA:
         {
             // cell 1 is a formula cell and cell 2 is not.
-            DetouchFormulaCell(aPos1, *aCell1.mpFormula);
+            DetachFormulaCell(aPos1, *aCell1.mpFormula);
             ScFormulaCell* pNew = cloneFormulaCell(pDocument, ScAddress(nCol, nRow2, nTab), *aCell1.mpFormula);
             switch (aCell2.meType)
             {
@@ -1371,7 +1372,8 @@ public:
                 }
 
                 // Group the cloned formula cells.
-                groupFormulaCells(aCloned);
+                if (!aCloned.empty())
+                    sc::SharedFormulaUtil::groupFormulaCells(aCloned.begin(), aCloned.end());
 
                 sc::CellStoreType& rDestCells = mrDestCol.GetCellStore();
                 maDestPos.miCellPos = rDestCells.set(
diff --git a/sc/source/core/data/column2.cxx b/sc/source/core/data/column2.cxx
index aa4dd0e..7b38918 100644
--- a/sc/source/core/data/column2.cxx
+++ b/sc/source/core/data/column2.cxx
@@ -1530,10 +1530,6 @@ void ScColumn::CellStorageModified()
 #endif
 }
 
-void ScColumn::RegroupFormulaCells( SCROW /*nRow1*/, SCROW /*nRow2*/ )
-{
-}
-
 #if DEBUG_COLUMN_STORAGE
 
 namespace {
diff --git a/sc/source/core/data/column3.cxx b/sc/source/core/data/column3.cxx
index 8352d46..4fb06c3 100644
--- a/sc/source/core/data/column3.cxx
+++ b/sc/source/core/data/column3.cxx
@@ -45,6 +45,7 @@
 #include "mtvcellfunc.hxx"
 #include "scopetools.hxx"
 #include "editutil.hxx"
+#include "sharedformula.hxx"
 
 #include <com/sun/star/i18n/LocaleDataItem.hpp>
 
@@ -91,29 +92,6 @@ void ScColumn::BroadcastCells( const std::vector<SCROW>& rRows )
     broadcastCells(*pDocument, nCol, nTab, rRows);
 }
 
-namespace {
-
-class EndListeningHandler
-{
-    ScDocument* mpDoc;
-public:
-    EndListeningHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
-
-    void operator() (size_t, ScFormulaCell* p)
-    {
-        p->EndListeningTo(mpDoc);
-    }
-};
-
-}
-
-void ScColumn::EndFormulaListening( sc::ColumnBlockPosition& rBlockPos, SCROW nRow1, SCROW nRow2 )
-{
-    EndListeningHandler aFunc(pDocument);
-    rBlockPos.miCellPos =
-        sc::ProcessFormula(rBlockPos.miCellPos, maCells, nRow1, nRow2, aFunc);
-}
-
 struct DirtyCellInterpreter
 {
     void operator() (size_t, ScFormulaCell* p)
@@ -411,8 +389,8 @@ void ScColumn::JoinNewFormulaCell(
     }
 }
 
-void ScColumn::DetouchFormulaCell(
-    const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const
+void ScColumn::DetachFormulaCell(
+    const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell )
 {
     if (!pDocument->IsClipOrUndo())
         // Have the dying formula cell stop listening.
@@ -422,6 +400,42 @@ void ScColumn::DetouchFormulaCell(
         UnshareFormulaCell(aPos, rCell);
 }
 
+namespace {
+
+class DetachFormulaCellsHandler
+{
+    ScDocument* mpDoc;
+public:
+    DetachFormulaCellsHandler(ScDocument* pDoc) : mpDoc(pDoc) {}
+
+    void operator() (size_t /*nRow*/, ScFormulaCell* pCell)
+    {
+        pCell->EndListeningTo(mpDoc);
+    }
+};
+
+}
+
+void ScColumn::DetachFormulaCells(
+    const sc::CellStoreType::position_type& aPos, size_t nLength )
+{
+    // Split formula grouping at the top and bottom boundaries.
+    SplitFormulaCellGroup(aPos);
+    size_t nRow = aPos.first->position + aPos.second;
+    size_t nNextTopRow = nRow + nLength; // start row of next formula group.
+    if (ValidRow(nNextTopRow))
+    {
+        sc::CellStoreType::position_type aPos2 = maCells.position(aPos.first, nNextTopRow);
+        SplitFormulaCellGroup(aPos2);
+    }
+
+    if (pDocument->IsClipOrUndo())
+        return;
+
+    DetachFormulaCellsHandler aFunc(pDocument);
+    sc::ProcessFormula(aPos.first, maCells, nRow, nNextTopRow-1, aFunc);
+}
+
 void ScColumn::UnshareFormulaCell(
     const sc::CellStoreType::position_type& aPos, ScFormulaCell& rCell ) const
 {
@@ -617,7 +631,7 @@ sc::CellStoreType::iterator ScColumn::GetPositionToInsert( const sc::CellStoreTy
     if (itRet->type == sc::element_type_formula)
     {
         ScFormulaCell& rCell = *sc::formula_block::at(*itRet->data, aPos.second);
-        DetouchFormulaCell(aPos, rCell);
+        DetachFormulaCell(aPos, rCell);
     }
 
     return itRet;
@@ -1240,11 +1254,7 @@ void lcl_AddCode( ScTokenArray& rArr, const ScFormulaCell* pCell )
 class MixDataHandler
 {
     ScColumn& mrDestColumn;
-
-    sc::CellStoreType& mrDestCells;
-    sc::CellStoreType::iterator miDestPos;
-
-    sc::CellTextAttrStoreType& mrDestAttrs;
+    sc::ColumnBlockPosition& mrBlockPos;
 
     sc::CellStoreType maNewCells;
     sc::CellStoreType::iterator miNewCellsPos;
@@ -1256,37 +1266,30 @@ class MixDataHandler
 
 public:
     MixDataHandler(
-        sc::ColumnBlockPosition* pBlockPos,
+        sc::ColumnBlockPosition& rBlockPos,
         ScColumn& rDestColumn,
-        sc::CellStoreType& rDestCells,
-        sc::CellTextAttrStoreType& rDestAttrs,
         SCROW nRow1, SCROW nRow2,
         sal_uInt16 nFunction, bool bSkipEmpty) :
         mrDestColumn(rDestColumn),
-        mrDestCells(rDestCells),
-        mrDestAttrs(rDestAttrs),
+        mrBlockPos(rBlockPos),
         maNewCells(nRow2 - nRow1 + 1),
         miNewCellsPos(maNewCells.begin()),
         mnRowOffset(nRow1),
         mnFunction(nFunction),
         mbSkipEmpty(bSkipEmpty)
     {
-        if (pBlockPos)
-            miDestPos = pBlockPos->miCellPos;
-        else
-            miDestPos = mrDestCells.begin();
     }
 
     void operator() (size_t nRow, double f)
     {
-        std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nRow);
-        miDestPos = aPos.first;
-        switch (miDestPos->type)
+        sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
+        mrBlockPos.miCellPos = aPos.first;
+        switch (aPos.first->type)
         {
             case sc::element_type_numeric:
             {
                 // Both src and dest are of numeric type.
-                bool bOk = lcl_DoFunction(f, sc::numeric_block::at(*miDestPos->data, aPos.second), mnFunction);
+                bool bOk = lcl_DoFunction(f, sc::numeric_block::at(*aPos.first->data, aPos.second), mnFunction);
 
                 if (bOk)
                     miNewCellsPos = maNewCells.set(miNewCellsPos, nRow-mnRowOffset, f);
@@ -1321,7 +1324,7 @@ public:
                 aArr.AddOpCode(eOp); // Function
 
                 // Second row
-                ScFormulaCell* pDest = sc::formula_block::at(*miDestPos->data, aPos.second);
+                ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
                 lcl_AddCode(aArr, pDest);
 
                 miNewCellsPos = maNewCells.set(
@@ -1355,9 +1358,9 @@ public:
 
     void operator() (size_t nRow, const ScFormulaCell* p)
     {
-        std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nRow);
-        miDestPos = aPos.first;
-        switch (miDestPos->type)
+        sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nRow);
+        mrBlockPos.miCellPos = aPos.first;
+        switch (aPos.first->type)
         {
             case sc::element_type_numeric:
             {
@@ -1379,7 +1382,7 @@ public:
                 aArr.AddOpCode(eOp); // Function
 
                 // Second row
-                aArr.AddDouble(sc::numeric_block::at(*miDestPos->data, aPos.second));
+                aArr.AddDouble(sc::numeric_block::at(*aPos.first->data, aPos.second));
 
                 miNewCellsPos = maNewCells.set(
                     miNewCellsPos, nRow-mnRowOffset,
@@ -1407,7 +1410,7 @@ public:
                 aArr.AddOpCode(eOp); // Function
 
                 // Second row
-                ScFormulaCell* pDest = sc::formula_block::at(*miDestPos->data, aPos.second);
+                ScFormulaCell* pDest = sc::formula_block::at(*aPos.first->data, aPos.second);
                 lcl_AddCode(aArr, pDest);
 
                 miNewCellsPos = maNewCells.set(
@@ -1443,9 +1446,9 @@ public:
         for (size_t i = 0; i < nDataSize; ++i)
         {
             size_t nDestRow = nTopRow + i;
-            std::pair<sc::CellStoreType::iterator, size_t> aPos = mrDestCells.position(miDestPos, nDestRow);
-            miDestPos = aPos.first;
-            switch (miDestPos->type)
+            sc::CellStoreType::position_type aPos = mrDestColumn.GetCellStore().position(mrBlockPos.miCellPos, nDestRow);
+            mrBlockPos.miCellPos = aPos.first;
+            switch (aPos.first->type)
             {
                 case sc::element_type_numeric:
                 case sc::element_type_string:
@@ -1457,7 +1460,7 @@ public:
                     ScTokenArray aArr;
 
                     // First row
-                    ScFormulaCell* pSrc = sc::formula_block::at(*miDestPos->data, aPos.second);
+                    ScFormulaCell* pSrc = sc::formula_block::at(*aPos.first->data, aPos.second);
                     lcl_AddCode( aArr, pSrc);
 
                     // Operator
@@ -1488,21 +1491,17 @@ public:
     /**
      * Set the new cells to the destination (this) column.
      */
-    void commit(sc::ColumnBlockPosition* pDestBlockPos)
+    void commit()
     {
-        sc::ColumnBlockPosition aDestBlockPos;
-        if (pDestBlockPos)
-            aDestBlockPos = *pDestBlockPos;
-        else
-            mrDestColumn.InitBlockPosition(aDestBlockPos);
+        sc::CellStoreType& rDestCells = mrDestColumn.GetCellStore();
 
         // Stop all formula cells in the destination range first.
-        sc::ColumnBlockPosition aCopy = aDestBlockPos;
-        mrDestColumn.EndFormulaListening(aCopy, mnRowOffset, mnRowOffset + maNewCells.size() - 1);
+        sc::CellStoreType::position_type aPos = rDestCells.position(mrBlockPos.miCellPos, mnRowOffset);
+        mrDestColumn.DetachFormulaCells(aPos, maNewCells.size());
 
         // Move the new cells to the destination range.
-        sc::CellStoreType::iterator& itDestPos = aDestBlockPos.miCellPos;
-        sc::CellTextAttrStoreType::iterator& itDestAttrPos = aDestBlockPos.miCellTextAttrPos;
+        sc::CellStoreType::iterator& itDestPos = mrBlockPos.miCellPos;
+        sc::CellTextAttrStoreType::iterator& itDestAttrPos = mrBlockPos.miCellTextAttrPos;
 
         sc::CellStoreType::iterator it = maNewCells.begin(), itEnd = maNewCells.end();
         for (; it != itEnd; ++it)
@@ -1516,33 +1515,50 @@ public:
                 {
                     sc::numeric_block::iterator itData = sc::numeric_block::begin(*it->data);
                     sc::numeric_block::iterator itDataEnd = sc::numeric_block::end(*it->data);
-                    itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+                    itDestPos = mrDestColumn.GetCellStore().set(itDestPos, nDestRow, itData, itDataEnd);
                 }
                 break;
                 case sc::element_type_string:
                 {
                     sc::string_block::iterator itData = sc::string_block::begin(*it->data);
                     sc::string_block::iterator itDataEnd = sc::string_block::end(*it->data);
-                    itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+                    itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
                 }
                 break;
                 case sc::element_type_edittext:
                 {
                     sc::edittext_block::iterator itData = sc::edittext_block::begin(*it->data);
                     sc::edittext_block::iterator itDataEnd = sc::edittext_block::end(*it->data);
-                    itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+                    itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
                 }
                 break;
                 case sc::element_type_formula:
                 {
                     sc::formula_block::iterator itData = sc::formula_block::begin(*it->data);
                     sc::formula_block::iterator itDataEnd = sc::formula_block::end(*it->data);
-                    itDestPos = mrDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+
+                    // Group new formula cells before inserting them.
+                    sc::SharedFormulaUtil::groupFormulaCells(itData, itDataEnd);
+
+                    // Insert the formula cells to the column.
+                    itDestPos = rDestCells.set(itDestPos, nDestRow, itData, itDataEnd);
+
+                    // Merge with the previous formula group (if any).
+                    aPos = rDestCells.position(itDestPos, nDestRow);
+                    mrDestColumn.JoinFormulaCellAbove(aPos);
+
+                    // Merge with the next formula group (if any).
+                    size_t nNextRow = nDestRow + it->size;
+                    if (ValidRow(nNextRow))
+                    {
+                        aPos = rDestCells.position(aPos.first, nNextRow);
+                        mrDestColumn.JoinFormulaCellAbove(aPos);
+                    }
                 }
                 break;
                 case sc::element_type_empty:
                 {
-                    itDestPos = mrDestCells.set_empty(itDestPos, nDestRow, nDestRow+it->size-1);
+                    itDestPos = rDestCells.set_empty(itDestPos, nDestRow, nDestRow+it->size-1);
                     bHasContent = false;
                 }
                 break;
@@ -1550,19 +1566,17 @@ public:
                     ;
             }
 
+            sc::CellTextAttrStoreType& rDestAttrs = mrDestColumn.GetCellAttrStore();
             if (bHasContent)
             {
                 std::vector<sc::CellTextAttr> aAttrs(it->size, sc::CellTextAttr());
-                itDestAttrPos = mrDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
+                itDestAttrPos = rDestAttrs.set(itDestAttrPos, nDestRow, aAttrs.begin(), aAttrs.end());
             }
             else
-                itDestAttrPos = mrDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+it->size-1);
+                itDestAttrPos = rDestAttrs.set_empty(itDestAttrPos, nDestRow, nDestRow+it->size-1);
         }
 
         maNewCells.release();
-
-        if (pDestBlockPos)
-            *pDestBlockPos = aDestBlockPos;
     }
 };
 
@@ -1575,11 +1589,13 @@ void ScColumn::MixData(
     // destination (this column) block position.
 
     sc::ColumnBlockPosition* p = rCxt.getBlockPosition(nTab, nCol);
-    MixDataHandler aFunc(p, *this, maCells, maCellTextAttrs, nRow1, nRow2, nFunction, bSkipEmpty);
+    if (!p)
+        return;
+
+    MixDataHandler aFunc(*p, *this, nRow1, nRow2, nFunction, bSkipEmpty);
     sc::ParseAll(rSrcCol.maCells.begin(), rSrcCol.maCells, nRow1, nRow2, aFunc, aFunc);
 
-    aFunc.commit(p);
-    RegroupFormulaCells(nRow1, nRow2);
+    aFunc.commit();
     CellStorageModified();
 }
 
diff --git a/sc/source/core/tool/sharedformula.cxx b/sc/source/core/tool/sharedformula.cxx
new file mode 100644
index 0000000..7b6ac84
--- /dev/null
+++ b/sc/source/core/tool/sharedformula.cxx
@@ -0,0 +1,18 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "sharedformula.hxx"
+
+namespace sc {
+
+
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 217896aa33e40b113fafdaa109d02992f7d9506a
Author: Kohei Yoshida <kohei.yoshida at gmail.com>
Date:   Wed Jul 10 11:58:49 2013 -0400

    Generate Reverse Polish token array (RPN) at the start.
    
    Change-Id: Idcac01820fab536cebebcc437e206b6900511600

diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index e645968..9963fc9 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -39,6 +39,9 @@ class SC_DLLPUBLIC FormulaGroupInterpreter
  protected:
     FormulaGroupInterpreter() {}
     virtual ~FormulaGroupInterpreter() {}
+
+    static void generateRPNCode(ScDocument& rDoc, const ScAddress& rPos, ScTokenArray& rCode);
+
  public:
     static FormulaGroupInterpreter *getStatic();
 
diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index 8bc0224..04a67d2 100755
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -65,6 +65,8 @@ ScMatrixRef FormulaGroupInterpreterOpenCL::inverseMatrix(const ScMatrix& /* rMat
 bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress& rTopPos,
                                               const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode)
 {
+    generateRPNCode(rDoc, rTopPos, rCode);
+
     size_t rowSize = xGroup->mnLength;
     fprintf(stderr,"rowSize at begin is ...%ld.\n",(long)rowSize);
     // The row quantity can be gotten from p2->GetArrayLength()
@@ -193,9 +195,7 @@ bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress&
         if(!getenv("SC_GPU")||!ocl_calc.GetOpenclState())
         {
             fprintf(stderr,"ccCPU flow...\n\n");
-            ScCompiler aComp(&rDoc, aTmpPos, aCode2);
-            aComp.SetGrammar(rDoc.GetGrammar());
-            aComp.CompileTokenArray(); // Create RPN token array.
+            generateRPNCode(rDoc, aTmpPos, aCode2);
             ScInterpreter aInterpreter(pDest, &rDoc, aTmpPos, aCode2);
             aInterpreter.Interpret();
             pDest->SetResultToken(aInterpreter.GetResultToken().get());
@@ -306,6 +306,8 @@ bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAdd
                                                    const ScFormulaCellGroupRef& xGroup,
                                                    ScTokenArray& rCode)
 {
+    generateRPNCode(rDoc, rTopPos, rCode);
+
     // Inputs: both of length xGroup->mnLength
     OpCode eOp; // type of operation: ocAverage, ocMax, ocMin
     const double *pArrayToSubtractOneElementFrom;
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 627c5f5..5a23511 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -96,9 +96,7 @@ bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddres
         if (!pDest)
             return false;
 
-        ScCompiler aComp(&rDoc, aTmpPos, aCode2);
-        aComp.SetGrammar(rDoc.GetGrammar());
-        aComp.CompileTokenArray(); // Create RPN token array.
+        generateRPNCode(rDoc, aTmpPos, aCode2);
         ScInterpreter aInterpreter(pDest, &rDoc, aTmpPos, aCode2);
         aInterpreter.Interpret();
         aResults.push_back(aInterpreter.GetResultToken()->GetDouble());
@@ -190,6 +188,15 @@ FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
     return msInstance;
 }
 
+void FormulaGroupInterpreter::generateRPNCode(ScDocument& rDoc, const ScAddress& rPos, ScTokenArray& rCode)
+{
+    // First, generate an RPN (reverse polish notation) token array.
+    ScCompiler aComp(&rDoc, rPos, rCode);
+    aComp.SetGrammar(rDoc.GetGrammar());
+    aComp.CompileTokenArray(); // Create RPN token array.
+    // Now, calling FirstRPN() and NextRPN() will return tokens from the RPN token array.
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 9ed6e520afb8905596cd382e1e7fa79ba20063b5
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Tue Jul 9 12:02:43 2013 +0100

    better opencl error reporting / diagnostics.

diff --git a/sc/source/core/opencl/openclwrapper.cxx b/sc/source/core/opencl/openclwrapper.cxx
index 31f1589..0c94721 100755
--- a/sc/source/core/opencl/openclwrapper.cxx
+++ b/sc/source/core/opencl/openclwrapper.cxx
@@ -2131,6 +2131,7 @@ double *OclCalc::OclSimpleDeltaOperation(OpCode eOp, const double *pOpArray,
     size_t global_work_size[1];
 
     kEnv.mpkKernel = clCreateKernel(kEnv.mpkProgram,kernelName, &clStatus);
+    CHECK_OPENCL(clStatus);
 
     // Ugh - horrible redundant copying ...
     cl_mem valuesCl   = allocateDoubleBuffer(kEnv, pOpArray, nElements, &clStatus);
@@ -2147,12 +2148,16 @@ double *OclCalc::OclSimpleDeltaOperation(OpCode eOp, const double *pOpArray,
 
     clStatus = clSetKernelArg(kEnv.mpkKernel, 0, sizeof(cl_mem),
                               (void *)&valuesCl);
+    CHECK_OPENCL(clStatus);
     clStatus = clSetKernelArg(kEnv.mpkKernel, 1, sizeof(cl_mem),
                               (void *)&subtractCl);
-    clStatus = clSetKernelArg(kEnv.mpkKernel, 2, sizeof(cl_mem),
+    CHECK_OPENCL(clStatus);
+    clStatus = clSetKernelArg(kEnv.mpkKernel, 2, sizeof(cl_int),
                               (void *)&start);
-    clStatus = clSetKernelArg(kEnv.mpkKernel, 3, sizeof(cl_mem),
+    CHECK_OPENCL(clStatus);
+    clStatus = clSetKernelArg(kEnv.mpkKernel, 3, sizeof(cl_int),
                               (void *)&end);
+    CHECK_OPENCL(clStatus);
     clStatus = clSetKernelArg(kEnv.mpkKernel, 4, sizeof(cl_mem),
                               (void *)&outputCl);
     CHECK_OPENCL(clStatus);
diff --git a/sc/source/core/opencl/openclwrapper.hxx b/sc/source/core/opencl/openclwrapper.hxx
index a0c132a..fe62554 100755
--- a/sc/source/core/opencl/openclwrapper.hxx
+++ b/sc/source/core/opencl/openclwrapper.hxx
@@ -12,6 +12,7 @@
 
 #include <config_features.h>
 #include <formula/opcode.hxx>
+#include <sal/detail/log.h>
 #include <cassert>
 #include <CL/cl.h>
 #endif
@@ -55,7 +56,7 @@ typedef int (*cl_kernel_function)(void **userdata, KernelEnv *kenv);
 #define CHECK_OPENCL(status)              \
 if(status != CL_SUCCESS)                  \
 {                                          \
-    printf ("error code is %d.\n",status);    \
+    printf ("OpenCL error code is %d at " SAL_DETAIL_WHERE "\n", status);    \
     return 0;                            \
 }
 
commit 98e811e43209faced8e8144267ded2032d44f4bc
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Jul 8 21:49:31 2013 +0100

    try harder to setup the kernel environment.

diff --git a/sc/source/core/opencl/openclwrapper.cxx b/sc/source/core/opencl/openclwrapper.cxx
index 3030a2e..31f1589 100755
--- a/sc/source/core/opencl/openclwrapper.cxx
+++ b/sc/source/core/opencl/openclwrapper.cxx
@@ -2111,6 +2111,7 @@ double *OclCalc::OclSimpleDeltaOperation(OpCode eOp, const double *pOpArray,
                                          const double *pSubtractSingle, size_t nElements)
 {
     KernelEnv kEnv;
+    SetKernelEnv(&kEnv);
 
     // select a kernel: cut & paste coding is utterly evil.
     const char *kernelName;
commit c6fd693a8a1efb9e301bd623d29411dfa2378e5c
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Jul 8 21:35:26 2013 +0100

    cleanup formulagroupcl and add opencl kernel for averagedelta.
    
    Conflicts:
    	sc/source/core/opencl/openclwrapper.hxx
    
    Change-Id: Id4777d3854d34ab34dd29b050cd329a803023a39

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index d92a471..8bc0224 100755
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -310,11 +310,8 @@ bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAdd
     OpCode eOp; // type of operation: ocAverage, ocMax, ocMin
     const double *pArrayToSubtractOneElementFrom;
     const double *pGroundWaterDataArray;
-    size_t        nGroundWaterDataArrayLen;
 
     // Output:
-    double *pResult = new double[xGroup->mnLength];
-    RETURN_IF_FAIL(pResult != NULL, "buffer alloc failed");
     std::vector<double> aMatrixContent;
 
     const formula::FormulaToken *p;
@@ -338,36 +335,13 @@ bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAdd
 
             p = rCode.NextNoSpaces();
             RETURN_IF_FAIL(p != NULL, "no function argument");
-            if (p->GetType() == formula::svDoubleVectorRef)
-            {
-                // FIXME: this is what I would expect; but table1.cxx's
-                // ScColumn::ResolveStaticReference as called from
-                // GroupTokenConverter::convert returns an ScMatrixToken un-conditionally
-                const formula::DoubleVectorRefToken* pDvr = static_cast<const formula::DoubleVectorRefToken*>(p);
-                const std::vector<const double*>& rArrays = pDvr->GetArrays();
-                RETURN_IF_FAIL(rArrays.size() == 1, "unexpectedly large double ref array");
-                RETURN_IF_FAIL(pDvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong double ref length");
-                RETURN_IF_FAIL(pDvr->IsStartFixed() && pDvr->IsEndFixed(), "non-fixed ranges )");
-                pGroundWaterDataArray = rArrays[0];
-                nGroundWaterDataArrayLen = xGroup->mnLength;
-            }
-            else
-            {
-                RETURN_IF_FAIL(p->GetType() == formula::svMatrix, "unexpected fn. param type");
-                const ScMatrixToken *pMatTok = static_cast<const ScMatrixToken *>(p);
-                pMatTok->GetMatrix()->GetDoubleArray( aMatrixContent );
-                // FIXME: horrible hackery: the legacy / excel shared formula oddness,
-                // such that the 1st entry is not truly shared, making these a different
-                // shape.
-                if (aMatrixContent.size() > (size_t)xGroup->mnLength + 1)
-                {
-                    fprintf(stderr, "Error size range mismatch: %ld vs %ld\n",
-                            (long)aMatrixContent.size(), (long)xGroup->mnLength);
-                    return false;
-                }
-                pGroundWaterDataArray = &aMatrixContent[0];
-                nGroundWaterDataArrayLen = aMatrixContent.size();
-            }
+            RETURN_IF_FAIL(p->GetType() == formula::svDoubleVectorRef, "wrong type of fn argument");
+            const formula::DoubleVectorRefToken* pDvr = static_cast<const formula::DoubleVectorRefToken*>(p);
+            const std::vector<const double*>& rArrays = pDvr->GetArrays();
+            RETURN_IF_FAIL(rArrays.size() == 1, "unexpectedly large double ref array");
+            RETURN_IF_FAIL(pDvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong double ref length");
+            RETURN_IF_FAIL(pDvr->IsStartFixed() && pDvr->IsEndFixed(), "non-fixed ranges )");
+            pGroundWaterDataArray = rArrays[0];
 
             p = rCode.NextNoSpaces();
             RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocClose, "missing closing )");
@@ -400,17 +374,22 @@ bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAdd
     //   =AVERAGE(L$6:L$7701) - L6
     // we would get:
     //   eOp => ocAverage
-    //   pGroundWaterDataArray => contains L$6:L$7701
-    //   pGroundWaterDataArrayLen => 7701 - 6 + 1
-    //   pArrayToSubtractOneElementFrom => contains L$5:L$7701 (overlapping)
+    //   pGroundWaterDataArray => contains L$5:L$7701
+    //   pArrayToSubtractOneElementFrom => contains L$5:L$7701 (ie. a copy)
     //   length of this array -> xGroup->mnLength
 
     fprintf (stderr, "Calculate !\n");
 
+    double *pResult = ocl_calc.OclSimpleDeltaOperation( eOp, pGroundWaterDataArray,
+                                                        pArrayToSubtractOneElementFrom,
+                                                        (size_t) xGroup->mnLength );
+    RETURN_IF_FAIL(pResult != NULL, "buffer alloc / calculaton failed");
+
     // Insert the double data, in rResult[i] back into the document
     rDoc.SetFormulaResults(rTopPos, pResult, xGroup->mnLength);
 
     delete [] pResult;
+
     SAL_DEBUG ("exit cleanly !");
     return true;
 }
diff --git a/sc/source/core/opencl/oclkernels.hxx b/sc/source/core/opencl/oclkernels.hxx
index 6c90126..e13c24a 100755
--- a/sc/source/core/opencl/oclkernels.hxx
+++ b/sc/source/core/opencl/oclkernels.hxx
@@ -142,7 +142,6 @@ __kernel void oclFormulaAverage(__global float *input,__global int *start,__glob
     for(i = start[id];i<=end[id];i++)
         sum += input[i];
     output[id] = sum / (end[id]-start[id]+1);
-
 }
 
 //Sumproduct
@@ -162,6 +161,33 @@ __kernel void oclFormulaMinverse(__global float *data,
 
 }
 
+// Double precision is a requirement of spreadsheets
+#if 0
+#if defined(cl_khr_fp64)  // Khronos extension
+#pragma OPENCL EXTENSION cl_khr_fp64 : enable
+#elif defined(cl_amd_fp64)  // AMD extension
+#pragma OPENCL EXTENSION cl_amd_fp64 : enable
+#endif
+typedef double fp_t;
+#else
+typedef float fp_t;
+#endif
+
+__kernel void oclAverageDelta(__global fp_t *values, __global fp_t *subtract, __global int start, __global int end, __global fp_t *output)
+{
+    const unsigned int id = get_global_id(0);
+
+    // Average
+    int i;
+    fp_t sum = 0.0;
+    for(i = start; i < end; i++)
+        sum += values[i];
+    fp_t val = sum/(end-start);
+
+    // Subtract & output
+    output[id] = val - subtract[id];
+}
+
 );
 
 #endif // USE_EXTERNAL_KERNEL
diff --git a/sc/source/core/opencl/openclwrapper.cxx b/sc/source/core/opencl/openclwrapper.cxx
index 597f370..3030a2e 100755
--- a/sc/source/core/opencl/openclwrapper.cxx
+++ b/sc/source/core/opencl/openclwrapper.cxx
@@ -76,16 +76,17 @@ int OpenclDevice::ReleaseOpenclRunEnv() {
 }
 ///////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////
-inline int OpenclDevice::AddKernelConfig(int kCount, const char *kName) {
+inline int OpenclDevice::AddKernelConfig(int kCount, const char *kName)
+{
     strcpy(gpuEnv.mArrykernelNames[kCount], kName);
     gpuEnv.mnKernelCount++;
     return 0;
 }
 
-int OpenclDevice::RegistOpenclKernel() {
-    if (!gpuEnv.mnIsUserCreated) {
+int OpenclDevice::RegistOpenclKernel()
+{
+    if (!gpuEnv.mnIsUserCreated)
         memset(&gpuEnv, 0, sizeof(gpuEnv));
-    }
 
     gpuEnv.mnFileCount = 0; //argc;
     gpuEnv.mnKernelCount = 0UL;
@@ -100,17 +101,22 @@ int OpenclDevice::RegistOpenclKernel() {
     AddKernelConfig(7, (const char*) "oclFormulaSumproduct");
     AddKernelConfig(8, (const char*) "oclFormulaMinverse");
 
-    AddKernelConfig(9,    (const char*) "oclSignedAdd");
+    AddKernelConfig(9,  (const char*) "oclSignedAdd");
     AddKernelConfig(10, (const char*) "oclSignedSub");
     AddKernelConfig(11, (const char*) "oclSignedMul");
     AddKernelConfig(12, (const char*) "oclSignedDiv");
+    AddKernelConfig(13, (const char*) "oclAverageDelta");
+
     return 0;
 }
-OpenclDevice::OpenclDevice(){
+
+OpenclDevice::OpenclDevice()
+{
     //InitEnv();
 }
 
-OpenclDevice::~OpenclDevice() {
+OpenclDevice::~OpenclDevice()
+{
     //ReleaseOpenclRunEnv();
 }
 
@@ -122,13 +128,15 @@ int OpenclDevice::SetKernelEnv(KernelEnv *envInfo)
 
     return 1;
 }
-int OpenclDevice::CheckKernelName(KernelEnv *envInfo,const char *kernelName){
+
+int OpenclDevice::CheckKernelName(KernelEnv *envInfo,const char *kernelName)
+{
     //printf("CheckKernelName,total count of kernels...%d\n", gpuEnv.kernelCount);
     int kCount;
     for(kCount=0; kCount < gpuEnv.mnKernelCount; kCount++) {
         if(strcasecmp(kernelName, gpuEnv.mArrykernelNames[kCount]) == 0) {
-        printf("match  %s kernel right\n",kernelName);
-        break;
+            printf("match %s kernel right\n",kernelName);
+            break;
         }
     }
     envInfo->mpkKernel = gpuEnv.mpArryKernels[kCount];
@@ -141,7 +149,8 @@ int OpenclDevice::CheckKernelName(KernelEnv *envInfo,const char *kernelName){
     return 1;
 }
 
-int OpenclDevice::ConvertToString(const char *filename, char **source) {
+int OpenclDevice::ConvertToString(const char *filename, char **source)
+{
     int file_size;
     size_t result;
     FILE *file = NULL;
@@ -174,8 +183,9 @@ int OpenclDevice::ConvertToString(const char *filename, char **source) {
     return 0;
 }
 
-int OpenclDevice::BinaryGenerated(const char * clFileName, FILE ** fhandle) {
-        unsigned int i = 0;
+int OpenclDevice::BinaryGenerated(const char * clFileName, FILE ** fhandle)
+{
+    unsigned int i = 0;
     cl_int status;
     char *str = NULL;
     FILE *fd = NULL;
@@ -208,7 +218,8 @@ int OpenclDevice::BinaryGenerated(const char * clFileName, FILE ** fhandle) {
 }
 
 int OpenclDevice::WriteBinaryToFile(const char* fileName, const char* birary,
-        size_t numBytes) {
+        size_t numBytes)
+{
     FILE *output = NULL;
     output = fopen(fileName, "wb");
     if (output == NULL) {
@@ -223,7 +234,8 @@ int OpenclDevice::WriteBinaryToFile(const char* fileName, const char* birary,
 }
 
 int OpenclDevice::GeneratBinFromKernelSource(cl_program program,
-        const char * clFileName) {
+                                             const char * clFileName)
+{
      unsigned int i = 0;
     cl_int status;
     size_t *binarySizes, numDevices;
@@ -319,10 +331,10 @@ int OpenclDevice::GeneratBinFromKernelSource(cl_program program,
     return 1;
 }
 
-int OpenclDevice::InitOpenclAttr(OpenCLEnv * env) {
-    if (gpuEnv.mnIsUserCreated) {
+int OpenclDevice::InitOpenclAttr(OpenCLEnv * env)
+{
+    if (gpuEnv.mnIsUserCreated)
         return 1;
-    }
 
     gpuEnv.mpContext    = env->mpOclContext;
     gpuEnv.mpPlatformID = env->mpOclPlatformID;
@@ -334,21 +346,24 @@ int OpenclDevice::InitOpenclAttr(OpenCLEnv * env) {
     return 0;
 }
 
-int OpenclDevice::CreateKernel(char * kernelname, KernelEnv * env) {
+int OpenclDevice::CreateKernel(char * kernelname, KernelEnv * env)
+{
     int status;
 
-    env->mpkKernel     = clCreateKernel(gpuEnv.mpArryPrograms[0], kernelname, &status);
+    env->mpkKernel   = clCreateKernel(gpuEnv.mpArryPrograms[0], kernelname, &status);
     env->mpkContext  = gpuEnv.mpContext;
     env->mpkCmdQueue = gpuEnv.mpCmdQueue;
     return status != CL_SUCCESS ? 1 : 0;
 }
 
-int OpenclDevice::ReleaseKernel(KernelEnv * env) {
+int OpenclDevice::ReleaseKernel(KernelEnv * env)
+{
     int status = clReleaseKernel(env->mpkKernel);
     return status != CL_SUCCESS ? 1 : 0;
 }
 
-int OpenclDevice::ReleaseOpenclEnv(GPUEnv *gpuInfo) {
+int OpenclDevice::ReleaseOpenclEnv(GPUEnv *gpuInfo)
+{
     int i = 0;
     int status = 0;
 
@@ -378,7 +393,8 @@ int OpenclDevice::ReleaseOpenclEnv(GPUEnv *gpuInfo) {
 }
 
 int OpenclDevice::RunKernelWrapper(cl_kernel_function function,
-        const char * kernelName, void **usrdata) {
+                                   const char * kernelName, void **usrdata)
+{
     printf("oclwrapper:RunKernel_wrapper...\n");
     if (RegisterKernelWrapper(kernelName, function) != 1) {
         fprintf(stderr,
@@ -389,8 +405,9 @@ int OpenclDevice::RunKernelWrapper(cl_kernel_function function,
 }
 
 int OpenclDevice::CachedOfKernerPrg(const GPUEnv *gpuEnvCached,
-        const char * clFileName) {
-  int i;
+                                    const char * clFileName)
+{
+    int i;
     for (i = 0; i < gpuEnvCached->mnFileCount; i++) {
         if (strcasecmp(gpuEnvCached->mArryKnelSrcFile[i], clFileName) == 0) {
             if (gpuEnvCached->mpArryPrograms[i] != NULL) {
@@ -574,6 +591,7 @@ int OpenclDevice::RunKernel(const char *kernelName, void **userdata) {
     }
     return 0;
 }
+
 int OpenclDevice::InitOpenclRunEnv(int argc, const char *buildOptionKernelfiles)
 {
     int status = 0;
@@ -1007,6 +1025,7 @@ int OclCalc::OclHostFormulaMax(double *srcData,int *start,int *end,double *outpu
     CHECK_OPENCL(clStatus);
     return 0;
 }
+
 int OclCalc::OclHostFormulaMin(double *srcData,int *start,int *end,double *output,int size)
 {
     KernelEnv kEnv;
@@ -1590,7 +1609,6 @@ int OclCalc::OclHostFormulaMin32Bits(float *fpSrcData,uint *npStartPos,uint *npE
     clStatus = clReleaseMemObject(outputCl);
     CHECK_OPENCL(clStatus);
     return 0;
-
 }
 
 int OclCalc::OclHostFormulaAverage32Bits(float *fpSrcData,uint *npStartPos,uint *npEndPos,double *output,int size)
@@ -2066,4 +2084,111 @@ int OclCalc::OclHostFormulaSumProduct(float *dpSrcData,int *npStart,int *npEnd,f
 }
 #endif
 
+#if 0
+typedef double fp_;
+#else
+typedef float fp_t;
+#endif
+
+// FIXME: should be templatised in <double> - double buffering [sic] rocks
+static cl_mem allocateDoubleBuffer(KernelEnv &rEnv, const double *_pValues,
+                                   size_t nElements, cl_int *pStatus)
+{
+    // Ugh - horrible redundant copying ...
+    cl_mem xValues = clCreateBuffer(rEnv.mpkContext,(cl_mem_flags) (CL_MEM_READ_WRITE),
+                                    nElements * sizeof(double), NULL, pStatus);
+    fp_t *pValues = (fp_t *)clEnqueueMapBuffer(rEnv.mpkCmdQueue,xValues,CL_TRUE,CL_MAP_WRITE,0,
+                                                   nElements * sizeof(fp_t),0,NULL,NULL,NULL);
+    for(int i=0;i<nElements;i++)
+        pValues[i] = (fp_t)_pValues[i];
+
+    clEnqueueUnmapMemObject(rEnv.mpkCmdQueue,xValues,pValues,0,NULL,NULL);
+
+    return xValues;
+}
+
+double *OclCalc::OclSimpleDeltaOperation(OpCode eOp, const double *pOpArray,
+                                         const double *pSubtractSingle, size_t nElements)
+{
+    KernelEnv kEnv;
+
+    // select a kernel: cut & paste coding is utterly evil.
+    const char *kernelName;
+    switch (eOp) {
+    case ocMax:
+    case ocMin:
+        ; // FIXME: fallthrough for now
+    case ocAverage:
+        kernelName = "oclAverageDelta";
+        break;
+    default:
+        assert(false);
+    }
+    CheckKernelName(&kEnv,kernelName);
+
+    cl_int clStatus;
+    size_t global_work_size[1];
+
+    kEnv.mpkKernel = clCreateKernel(kEnv.mpkProgram,kernelName, &clStatus);
+
+    // Ugh - horrible redundant copying ...
+    cl_mem valuesCl   = allocateDoubleBuffer(kEnv, pOpArray, nElements, &clStatus);
+    cl_mem subtractCl = allocateDoubleBuffer(kEnv, pSubtractSingle, nElements, &clStatus);
+
+    cl_int start = 0;
+    cl_int end = (cl_int) nElements;
+    cl_mem outputCl = clCreateBuffer(kEnv.mpkContext,
+                                     CL_MEM_READ_WRITE,
+                                     nElements * sizeof(fp_t),
+                                     NULL,
+                                     &clStatus);
+    CHECK_OPENCL(clStatus);
+
+    clStatus = clSetKernelArg(kEnv.mpkKernel, 0, sizeof(cl_mem),
+                              (void *)&valuesCl);
+    clStatus = clSetKernelArg(kEnv.mpkKernel, 1, sizeof(cl_mem),
+                              (void *)&subtractCl);
+    clStatus = clSetKernelArg(kEnv.mpkKernel, 2, sizeof(cl_mem),
+                              (void *)&start);
+    clStatus = clSetKernelArg(kEnv.mpkKernel, 3, sizeof(cl_mem),
+                              (void *)&end);
+    clStatus = clSetKernelArg(kEnv.mpkKernel, 4, sizeof(cl_mem),
+                              (void *)&outputCl);
+    CHECK_OPENCL(clStatus);
+
+    fprintf(stderr, "prior to enqueue range kernel\n");
+
+    global_work_size[0] = nElements;
+    clStatus = clEnqueueNDRangeKernel(kEnv.mpkCmdQueue, kEnv.mpkKernel, 1,
+                                      NULL, global_work_size, NULL, 0, NULL, NULL);
+    CHECK_OPENCL(clStatus);
+
+    double *pResult = new double[nElements];
+    if(!pResult)
+        return NULL; // leak.
+
+    fp_t *pOutput = (fp_t *)clEnqueueMapBuffer(kEnv.mpkCmdQueue,outputCl,CL_TRUE,
+                                               CL_MAP_READ,0,nElements*sizeof(fp_t),
+                                               0,NULL,NULL,NULL);
+    for(int i = 0; i < nElements; i++)
+        pResult[i] = (double)pOutput[i];
+
+    clEnqueueUnmapMemObject(kEnv.mpkCmdQueue,outputCl,pOutput,0,NULL,NULL);
+
+    clStatus = clFinish(kEnv.mpkCmdQueue);
+    CHECK_OPENCL(clStatus);
+    clStatus = clReleaseKernel(kEnv.mpkKernel);
+    CHECK_OPENCL(clStatus);
+    clStatus = clReleaseMemObject(valuesCl);
+    CHECK_OPENCL(clStatus);
+    clStatus = clReleaseMemObject(subtractCl);
+    CHECK_OPENCL(clStatus);
+    clStatus = clReleaseMemObject(outputCl);
+    CHECK_OPENCL(clStatus);
+
+    fprintf(stderr, "completed opencl delta operation\n");
+
+    return pResult;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/opencl/openclwrapper.hxx b/sc/source/core/opencl/openclwrapper.hxx
index 3e87f84..a0c132a 100755
--- a/sc/source/core/opencl/openclwrapper.hxx
+++ b/sc/source/core/opencl/openclwrapper.hxx
@@ -11,10 +11,8 @@
 #define _OPENCL_WRAPPER_H_
 
 #include <config_features.h>
-
-#ifdef __APPLE__
-#include <OpenCL/cl.h>
-#else
+#include <formula/opcode.hxx>
+#include <cassert>
 #include <CL/cl.h>
 #endif
 
@@ -212,6 +210,7 @@ public:
     int OclHostFormulaMax32Bits(float *fpSrcData,uint *npStartPos,uint *npEndPos,double *output,int outputSize);
     int OclHostFormulaMin32Bits(float *fpSrcData,uint *npStartPos,uint *npEndPos,double *output,int outputSize);
     int OclHostFormulaAverage32Bits(float *fpSrcData,uint *npStartPos,uint *npEndPos,double *output,int outputSize);
+    double *OclSimpleDeltaOperation(OpCode eOp, const double *pOpArray, const double *pSubtractSingle, size_t nElements);
 
     //int OclHostFormulaCount(int *startPos,int *endPos,float *output,int outputSize);
     //int OclHostFormulaSum(float *srcData,int *startPos,int *endPos,float *output,int outputSize);
commit d5ae61ed2394b6945b969c61aea0adac2234f702
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Jul 8 14:17:35 2013 +0100

    Add new opencl placeholder backend for specific scenarios.

diff --git a/sc/source/core/data/formulacell.cxx b/sc/source/core/data/formulacell.cxx
index 17653c9..55f5010 100644
--- a/sc/source/core/data/formulacell.cxx
+++ b/sc/source/core/data/formulacell.cxx
@@ -3064,6 +3064,14 @@ public:
 
     bool convert(ScTokenArray& rCode)
     {
+        { // debug to start with:
+            ScCompiler aComp( &mrDoc, mrPos, rCode);
+            aComp.SetGrammar(formula::FormulaGrammar::GRAM_NATIVE_XL_R1C1);
+            OUStringBuffer aAsString;
+            aComp.CreateStringFromTokenArray(aAsString);
+            SAL_DEBUG("interpret formula: " << aAsString.makeStringAndClear());
+        }
+
         rCode.Reset();
         for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
         {
diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index 857f045..d92a471 100755
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -275,10 +275,153 @@ bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress&
     return true;
 }
 
+/// Special case of formula compiler for groundwatering
+class FormulaGroupInterpreterGroundwater : public FormulaGroupInterpreterSoftware
+{
+public:
+    FormulaGroupInterpreterGroundwater() :
+        FormulaGroupInterpreterSoftware()
+    {
+        fprintf(stderr,"\n\n ***** Groundwater Backend *****\n\n\n");
+        OclCalc::InitEnv();
+    }
+    virtual ~FormulaGroupInterpreterGroundwater()
+    {
+        OclCalc::ReleaseOpenclRunEnv();
+    }
+
+    virtual ScMatrixRef inverseMatrix(const ScMatrix& /* rMat */) { return ScMatrixRef(); }
+    virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos,
+                           const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode);
+};
+
+#define RETURN_IF_FAIL(a,b) do { if (!(a)) { fprintf (stderr,b); return false; } } while (0)
+
+#include "compiler.hxx"
+
+// FIXME: really we should compile the formula and operate on the
+// RPN representation which -should- be more compact and have no Open / Close
+// or precedence issues; cf. rCode.FirstRPN() etc.
+bool FormulaGroupInterpreterGroundwater::interpret(ScDocument& rDoc, const ScAddress& rTopPos,
+                                                   const ScFormulaCellGroupRef& xGroup,
+                                                   ScTokenArray& rCode)
+{
+    // Inputs: both of length xGroup->mnLength
+    OpCode eOp; // type of operation: ocAverage, ocMax, ocMin
+    const double *pArrayToSubtractOneElementFrom;
+    const double *pGroundWaterDataArray;
+    size_t        nGroundWaterDataArrayLen;
+
+    // Output:
+    double *pResult = new double[xGroup->mnLength];
+    RETURN_IF_FAIL(pResult != NULL, "buffer alloc failed");
+    std::vector<double> aMatrixContent;
+
+    const formula::FormulaToken *p;
+
+    // special cased formula parser:
+
+    p = rCode.FirstNoSpaces();
+    RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocOpen, "no opening (");
+
+    {
+        p = rCode.NextNoSpaces();
+        RETURN_IF_FAIL(p != NULL, "no operator");
+
+        // Function:
+        eOp = p->GetOpCode();
+        RETURN_IF_FAIL(eOp == ocAverage || eOp == ocMax || eOp == ocMin, "unexpected opcode");
+
+        { // function arguments
+            p = rCode.NextNoSpaces();
+            RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocOpen, "missing opening (");
+
+            p = rCode.NextNoSpaces();
+            RETURN_IF_FAIL(p != NULL, "no function argument");
+            if (p->GetType() == formula::svDoubleVectorRef)
+            {
+                // FIXME: this is what I would expect; but table1.cxx's
+                // ScColumn::ResolveStaticReference as called from
+                // GroupTokenConverter::convert returns an ScMatrixToken un-conditionally
+                const formula::DoubleVectorRefToken* pDvr = static_cast<const formula::DoubleVectorRefToken*>(p);
+                const std::vector<const double*>& rArrays = pDvr->GetArrays();
+                RETURN_IF_FAIL(rArrays.size() == 1, "unexpectedly large double ref array");
+                RETURN_IF_FAIL(pDvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong double ref length");
+                RETURN_IF_FAIL(pDvr->IsStartFixed() && pDvr->IsEndFixed(), "non-fixed ranges )");
+                pGroundWaterDataArray = rArrays[0];
+                nGroundWaterDataArrayLen = xGroup->mnLength;
+            }
+            else
+            {
+                RETURN_IF_FAIL(p->GetType() == formula::svMatrix, "unexpected fn. param type");
+                const ScMatrixToken *pMatTok = static_cast<const ScMatrixToken *>(p);
+                pMatTok->GetMatrix()->GetDoubleArray( aMatrixContent );
+                // FIXME: horrible hackery: the legacy / excel shared formula oddness,
+                // such that the 1st entry is not truly shared, making these a different
+                // shape.
+                if (aMatrixContent.size() > (size_t)xGroup->mnLength + 1)
+                {
+                    fprintf(stderr, "Error size range mismatch: %ld vs %ld\n",
+                            (long)aMatrixContent.size(), (long)xGroup->mnLength);
+                    return false;
+                }
+                pGroundWaterDataArray = &aMatrixContent[0];
+                nGroundWaterDataArrayLen = aMatrixContent.size();
+            }
+
+            p = rCode.NextNoSpaces();
+            RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocClose, "missing closing )");
+        }
+
+        // Subtract operator
+        p = rCode.NextNoSpaces();
+        RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocSub, "missing subtract opcode");
+
+        { // subtract parameter
+            p = rCode.NextNoSpaces();
+            RETURN_IF_FAIL(p != NULL, "no tokens");
+            RETURN_IF_FAIL(p->GetType() == formula::svSingleVectorRef, "not a single ref");
+            const formula::SingleVectorRefToken* pSvr = static_cast<const formula::SingleVectorRefToken*>(p);
+            pArrayToSubtractOneElementFrom = pSvr->GetArray();
+            RETURN_IF_FAIL(pSvr->GetArrayLength() == (size_t)xGroup->mnLength, "wrong single ref length");
+        }
+
+        p = rCode.NextNoSpaces();
+        RETURN_IF_FAIL(p != NULL && p->GetOpCode() == ocClose, "missing closing )");
+    }
+
+    p = rCode.NextNoSpaces();
+    RETURN_IF_FAIL(p == NULL, "has 5th");
+
+    static OclCalc ocl_calc;
+
+    // Here we have all the data we need to dispatch our openCL kernel [ I hope ]
+    // so for:
+    //   =AVERAGE(L$6:L$7701) - L6
+    // we would get:
+    //   eOp => ocAverage
+    //   pGroundWaterDataArray => contains L$6:L$7701
+    //   pGroundWaterDataArrayLen => 7701 - 6 + 1
+    //   pArrayToSubtractOneElementFrom => contains L$5:L$7701 (overlapping)
+    //   length of this array -> xGroup->mnLength
+
+    fprintf (stderr, "Calculate !\n");
+
+    // Insert the double data, in rResult[i] back into the document
+    rDoc.SetFormulaResults(rTopPos, pResult, xGroup->mnLength);
+
+    delete [] pResult;
+    SAL_DEBUG ("exit cleanly !");
+    return true;
+}
+
 namespace opencl {
     sc::FormulaGroupInterpreter *createFormulaGroupInterpreter()
     {
-        return new sc::FormulaGroupInterpreterOpenCL();
+        if (getenv("SC_GROUNDWATER"))
+            return new sc::FormulaGroupInterpreterGroundwater();
+        else
+            return new sc::FormulaGroupInterpreterOpenCL();
     }
 } // namespace opencl
 
commit e67ae6c1ca5d0df2fb3b94dda32519288225fb30
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Jul 8 11:57:39 2013 +0100

    avoid regular re-creation of the formulagroup interpreter.

diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 221a768..627c5f5 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -172,6 +172,7 @@ FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
     if ( msInstance &&
          bOpenCLEnabled != ScInterpreter::GetGlobalConfig().mbOpenCLEnabled )
     {
+        bOpenCLEnabled = ScInterpreter::GetGlobalConfig().mbOpenCLEnabled;
         delete msInstance;
         msInstance = NULL;
     }
commit d05ec5563621f0b51757dd42737565d29fbadd2b
Author: Michael Meeks <michael.meeks at suse.com>
Date:   Mon Jul 8 10:49:05 2013 +0100

    Latest cleanup and improvements of opencl backend.
    
    Conflicts:
    	sc/source/core/opencl/openclwrapper.cxx
    
    Change-Id: I3fdc90570e90a156ccecb511fc04b473752018bd

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
old mode 100644
new mode 100755
index 6a96129..857f045
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -65,35 +65,32 @@ ScMatrixRef FormulaGroupInterpreterOpenCL::inverseMatrix(const ScMatrix& /* rMat
 bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress& rTopPos,
                                               const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode)
 {
-    size_t rowSize = xGroup->mnLength; //, srcSize = 0;
+    size_t rowSize = xGroup->mnLength;
     fprintf(stderr,"rowSize at begin is ...%ld.\n",(long)rowSize);
-    int *rangeStart =NULL; // The first position for calculation,for example,the A1 in (=MAX(A1:A100))
-    int *rangeEnd = NULL; // The last position for calculation,for example, the A100 in (=MAX(A1:A100))
     // The row quantity can be gotten from p2->GetArrayLength()
-    int count1 =0,count2 =0,count3=0;
-    int oclOp=0;
-    double *srcData = NULL; // Point to the input data from CPU
-    double *rResult=NULL; // Point to the output data from GPU
-    double *leftData=NULL; // Left input for binary operator(+,-,*,/),for example,(=leftData+rightData)
-    double *rightData=NULL; // Right input for binary operator(+,-,*,/),for example,(=leftData/rightData)
-                            // The rightData can't be zero for "/"
-
-    leftData  = (double *)malloc(sizeof(double) * rowSize);
-    rightData = (double *)malloc(sizeof(double) * rowSize);
-    rResult   = (double *)malloc(sizeof(double) * rowSize*2);// For 2 columns(B,C)
-    srcData = (double *)calloc(rowSize,sizeof(double));
-
-    rangeStart =(int *)malloc(sizeof(int) * rowSize);
-    rangeEnd   =(int *)malloc(sizeof(int) * rowSize);
-
-    memset(rResult,0,rowSize);
-    if(NULL==leftData||NULL==rightData||
-           NULL==rResult||NULL==rangeStart||NULL==rangeEnd)
+    int nCount1 = 0, nCount2 = 0, nCount3 = 0;
+    int nOclOp = 0;
+    double *rResult = NULL; // Point to the output data from GPU
+    rResult = (double *)malloc(sizeof(double) * rowSize*2);// For 2 columns(B,C)
+    if(NULL==rResult)
     {
         printf("malloc err\n");
         return false;
     }
-    // printf("rowSize is %d.\n",rowsize);
+    memset(rResult,0,rowSize);
+    float * fpOclSrcData = NULL; // Point to the input data from CPU
+    uint * npOclStartPos = NULL; // The first position for calculation,for example,the A1 in (=MAX(A1:A100))
+    uint * npOclEndPos     = NULL; // The last position for calculation,for example, the A100 in (=MAX(A1:A100))
+    float * fpLeftData     = NULL; // Left input for binary operator(+,-,*,/),for example,(=leftData+rightData)
+    float * fpRightData  = NULL; // Right input for binary operator(+,-,*,/),for example,(=leftData/rightData)
+                                 // The rightData can't be zero for "/"
+    static OclCalc ocl_calc;
+    // Don't know how large the size will be applied previously, so create them as the rowSize or 65536
+    // Don't know which formulae will be used previously, so create buffers for different formulae used probably
+    ocl_calc.CreateBuffer(fpOclSrcData,npOclStartPos,npOclEndPos,rowSize);
+    ocl_calc.CreateBuffer(fpLeftData,fpRightData,rowSize);
+    //printf("pptrr is %d,%d,%d\n",fpOclSrcData,npOclStartPos,npOclEndPos);
+///////////////////////////////////////////////////////////////////////////////////////////
 
     // Until we implement group calculation for real, decompose the group into
     // individual formula token arrays for individual calculation.
@@ -125,26 +122,23 @@ bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress&
                     size_t nRowSize = nRowEnd - nRowStart + 1;
                     ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize, 0.0));
 
-                    //srcSize = rowSize+nRowSize-rowSize%nRowSize;//align as nRowSize
-                    //srcData = (double *)calloc(srcSize,sizeof(double));
-                    rangeStart[i] = nRowStart;//record the start position
-                    rangeEnd[i] = nRowEnd;//record the end position
+                    npOclStartPos[i] = nRowStart; // record the start position
+                    npOclEndPos[i]     = nRowEnd;   // record the end position
 
                     for (size_t nCol = 0; nCol < nColSize; ++nCol)
                     {
                         const double* pArray = rArrays[nCol];
-
-                        //printf("pArray is %p.\n",pArray);
                         if( NULL==pArray )
                         {
                             fprintf(stderr,"Error: pArray is NULL!\n");
                             return false;
                         }
-                        //fprintf(stderr,"(rowSize+nRowSize-1) is %d.\n",rowSize+nRowSize-1);
+
                         for( size_t u=0; u<rowSize; u++ )
                         {
-                            srcData[u] = pArray[u];// note:rowSize<=srcSize
-                            //fprintf(stderr,"srcData[%d] is %f.\n",u,srcData[u]);
+                            // Many video cards can't support double type in kernel, so need transfer the double to float
+                            fpOclSrcData[u] = (float)pArray[u];
+                            //fprintf(stderr,"fpOclSrcData[%d] is %f.\n",u,fpOclSrcData[u]);
                         }
 
                         for (size_t nRow = 0; nRow < nRowSize; ++nRow)
@@ -177,26 +171,26 @@ bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress&
             OpCode eOp = pCur->GetOpCode();
             if(eOp==0)
             {
-                  if(count3%2==0)
-                    leftData[count1++] = pCur->GetDouble();
-                   else
-                    rightData[count2++] = pCur->GetDouble();
-                count3++;
-               }
-               else if( eOp!=ocOpen && eOp!=ocClose )
-                oclOp = eOp;
-
-//            if(count1>0){//dbg
-//                fprintf(stderr,"leftData is %f.\n",leftData[count1-1]);
-//                count1--;
-//            }
-//            if(count2>0){//dbg
-//                fprintf(stderr,"rightData is %f.\n",rightData[count2-1]);
-//                count2--;
-//            }
+                 if(nCount3%2==0)
+                     fpLeftData[nCount1++] = (float)pCur->GetDouble();
+                 else
+                     fpRightData[nCount2++] = (float)pCur->GetDouble();
+                 nCount3++;
+            }
+            else if( eOp!=ocOpen && eOp!=ocClose )
+                nOclOp = eOp;
+
+//              if(count1>0){//dbg
+//                  fprintf(stderr,"leftData is %f.\n",leftData[count1-1]);
+//                  count1--;
+//              }
+//              if(count2>0){//dbg
+//                  fprintf(stderr,"rightData is %f.\n",rightData[count2-1]);
+//                  count2--;
+//              }
         }
 
-        if(!getenv("SC_GPU"))
+        if(!getenv("SC_GPU")||!ocl_calc.GetOpenclState())
         {
             fprintf(stderr,"ccCPU flow...\n\n");
             ScCompiler aComp(&rDoc, aTmpPos, aCode2);
@@ -211,34 +205,42 @@ bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress&
     } // for loop end (xGroup->mnLength)
 
     // For GPU calculation
-    if(getenv("SC_GPU"))
+    if(getenv("SC_GPU")&&ocl_calc.GetOpenclState())
     {
             fprintf(stderr,"ggGPU flow...\n\n");
-            printf(" oclOp is... %d\n",oclOp);
+            printf(" oclOp is... %d\n",nOclOp);
             osl_getSystemTime(&aTimeBefore); //timer
-            static OclCalc ocl_calc;
-            switch(oclOp)
+            switch(nOclOp)
             {
                 case ocAdd:
-                       ocl_calc.OclHostSignedAdd(leftData,rightData,rResult,count1);
+                    ocl_calc.OclHostSignedAdd32Bits(fpLeftData,fpRightData,rResult,nCount1);
                     break;
                 case ocSub:
-                    ocl_calc.OclHostSignedSub(leftData,rightData,rResult,count1);
+                    ocl_calc.OclHostSignedSub32Bits(fpLeftData,fpRightData,rResult,nCount1);
                     break;
                 case ocMul:
-                    ocl_calc.OclHostSignedMul(leftData,rightData,rResult,count1);
+                    ocl_calc.OclHostSignedMul32Bits(fpLeftData,fpRightData,rResult,nCount1);
                     break;
                 case ocDiv:
-                    ocl_calc.OclHostSignedDiv(leftData,rightData,rResult,count1);
+                    ocl_calc.OclHostSignedDiv32Bits(fpLeftData,fpRightData,rResult,nCount1);
                     break;
                 case ocMax:
-                    ocl_calc.OclHostFormulaMax(srcData,rangeStart,rangeEnd,rResult,rowSize);
+                    ocl_calc.OclHostFormulaMax32Bits(fpOclSrcData,npOclStartPos,npOclEndPos,rResult,rowSize);
                     break;
                 case ocMin:
-                    ocl_calc.OclHostFormulaMin(srcData,rangeStart,rangeEnd,rResult,rowSize);
+                    ocl_calc.OclHostFormulaMin32Bits(fpOclSrcData,npOclStartPos,npOclEndPos,rResult,rowSize);
                     break;
                 case ocAverage:
-                    ocl_calc.OclHostFormulaAverage(srcData,rangeStart,rangeEnd,rResult,rowSize);
+                    ocl_calc.OclHostFormulaAverage32Bits(fpOclSrcData,npOclStartPos,npOclEndPos,rResult,rowSize);
+                    break;
+                case ocSum:
+                    //ocl_calc.OclHostFormulaSum(srcData,rangeStart,rangeEnd,rResult,rowSize);
+                    break;
+                case ocCount:
+                    //ocl_calc.OclHostFormulaCount(rangeStart,rangeEnd,rResult,rowSize);
+                    break;
+                case ocSumProduct:
+                    //ocl_calc.OclHostFormulaSumProduct(srcData,rangeStart,rangeEnd,rResult,rowSize);
                     break;
                 default:
                     fprintf(stderr,"No OpenCL function for this calculation.\n");
@@ -254,26 +256,16 @@ bool FormulaGroupInterpreterOpenCL::interpret(ScDocument& rDoc, const ScAddress&
 /////////////////////////////////////////////////////
 
 //rResult[i];
-//            for(sal_Int32 i = 0; i < rowSize; ++i){//dbg output results
-//                fprintf(stderr,"After GPU,rRsults[%d] is ...%f\n",i,rResult[i]);
-//            }
+//           for(sal_Int32 i = 0; i < rowSize; ++i){//dbg output results
+//               fprintf(stderr,"After GPU,rRsults[%d] is ...%f\n",i,rResult[i]);
+//           }
 
             // Insert the double data, in rResult[i] back into the document
             rDoc.SetFormulaResults(rTopPos, rResult, xGroup->mnLength);
         }
 
-        if(leftData)
-            free(leftData);
-        if(rightData)
-            free(rightData);
-        if(rangeStart)
-            free(rangeStart);
-        if(rangeEnd)
-            free(rangeEnd);
         if(rResult)
             free(rResult);
-        if(srcData)
-            free(srcData);
 
         if(getenv("SC_GPUSAMPLE")){
             //fprintf(stderr,"FormulaGroupInterpreter::interpret(),iniflag...%d\n",ocl_calc.GetOpenclState());
diff --git a/sc/source/core/opencl/oclkernels.hxx b/sc/source/core/opencl/oclkernels.hxx
old mode 100644
new mode 100755
index 3269f3a..6c90126
--- a/sc/source/core/opencl/oclkernels.hxx
+++ b/sc/source/core/opencl/oclkernels.hxx
@@ -6,153 +6,158 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  */
+
 #ifndef _OCL_KERNEL_H_
 #define _OCL_KERNEL_H_
 
 #ifndef USE_EXTERNAL_KERNEL
 #define KERNEL( ... )# __VA_ARGS__
 
-
 /////////////////////////////////////////////
 const char *kernel_src = KERNEL(
 __kernel void hello(__global uint *buffer)
 
 {
-size_t idx = get_global_id(0);
-
-buffer[idx]=idx;
-
+    size_t idx = get_global_id(0);
+    buffer[idx]=idx;
 }
 
 __kernel void oclformula(__global float *data,
-					   const uint type)
+                       const uint type)
 {
-	const unsigned int i = get_global_id(0);
-
-	switch (type)
-	{
-		case 0:          //MAX
-		{
-			//printf("%i ?%f>%f\n",i,data[2*i],data[2*i+1]);
-			if(data[2*i]>data[2*i+1])
-				data[i] = data[2*i];
-			else
-				data[i] = data[2*i+1];
-			break;
-		}
-		case 1:          //MIN
-		{
-			//printf("%d ?%d<%d\n",i,data[2*i],data[2*i+1]);
-			if(data[2*i]<data[2*i+1])
-				data[i] = data[2*i];
-			else
-				data[i] = data[2*i+1];
-			break;
-		}
-		case 2:          //SUM
-		case 3:          //AVG
-		{
-			//printf("%d %d+%d\n",i,data[2*i],data[2*i+1]);
-			data[i] = data[2*i] + data[2*i+1];
-			break;
-		}
-		default:
-			break;
-
-	}
+    const unsigned int i = get_global_id(0);
+
+    switch (type)
+    {
+        case 0:          //MAX
+        {
+            //printf("%i ?%f>%f\n",i,data[2*i],data[2*i+1]);
+            if(data[2*i]>data[2*i+1])
+                data[i] = data[2*i];
+            else
+                data[i] = data[2*i+1];
+            break;
+        }
+        case 1:          //MIN
+        {
+            //printf("%d ?%d<%d\n",i,data[2*i],data[2*i+1]);
+            if(data[2*i]<data[2*i+1])
+                data[i] = data[2*i];
+            else
+                data[i] = data[2*i+1];
+            break;
+        }
+        case 2:          //SUM
+        case 3:          //AVG
+        {
+            //printf("%d %d+%d\n",i,data[2*i],data[2*i+1]);
+            data[i] = data[2*i] + data[2*i+1];
+            break;
+        }
+        default:
+            break;
+
+    }
 }
 
 
 __kernel void oclSignedAdd(__global float *ltData,__global float *rtData,__global float *otData)
 {
-	const unsigned int id = get_global_id(0);
-	otData[id] = ltData[id] + rtData[id];
+    const unsigned int id = get_global_id(0);
+    otData[id] = ltData[id] + rtData[id];
 }
 
 
 __kernel void oclSignedSub(__global float *ltData,__global float *rtData,__global float *otData)
 {
-	const unsigned int id = get_global_id(0);
-	otData[id] = ltData[id] - rtData[id];
+    const unsigned int id = get_global_id(0);
+    otData[id] = ltData[id] - rtData[id];
 
 }
 
 __kernel void oclSignedMul(__global float *ltData,__global float *rtData,__global float *otData)
 {
-	int id = get_global_id(0);
-	otData[id] =ltData[id] * rtData[id];
+    int id = get_global_id(0);
+    otData[id] =ltData[id] * rtData[id];
 }
 
 __kernel void oclSignedDiv(__global float *ltData,__global float *rtData,__global float *otData)
 {
-	const unsigned int id = get_global_id(0);
-	otData[id] = ltData[id] / rtData[id];
+    const unsigned int id = get_global_id(0);
+    otData[id] = ltData[id] / rtData[id];
 }
 
 __kernel void oclFormulaMin(__global float *input,__global int *start,__global int *end,__global float *output)
 {
-	const unsigned int id = get_global_id(0);
-	int i=0;
-	unsigned int startFlag = start[id];
-	unsigned int endFlag = end[id];
-	float min = input[startFlag];
-	for(i=startFlag;i<=endFlag;i++)
-	{
-		if(input[i]<min)
-			min = input[i];
-	}
-	output[id] = min;
+    const unsigned int id = get_global_id(0);
+    int i=0;
+    unsigned int startFlag = start[id];
+    unsigned int endFlag = end[id];
+    float min = input[startFlag];
+    for(i=startFlag;i<=endFlag;i++)
+    {
+        if(input[i]<min)
+            min = input[i];
+    }
+    output[id] = min;
 
 }
 

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list