/* -*- 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/.
*/
UnhandledToken::UnhandledToken( constchar* m, std::string fn, int ln ) :
mMessage(m), mFile(std::move(fn)), mLineNumber(ln) {}
OpenCLError::OpenCLError( std::string function, cl_int error, std::string file, int line ) :
mFunction(std::move(function)), mError(error), mFile(std::move(file)), mLineNumber(line)
{ // Not sure if this SAL_INFO() is useful; the place in // CLInterpreterContext::launchKernel() where OpenCLError is // caught already uses SAL_WARN() to display it.
// Strings and OpenCL: // * Strings are non-trivial types and so passing them to OpenCL and handling them there // would be rather complex. However, in practice most string operations are checking // string equality, so only such string usage is supported (other cases will be // handled by Calc core when they get rejected for OpenCL). // * Strings from Calc core come from svl::SharedString, which already ensures that // equal strings have equal rtl_uString. // * Strings are passed to opencl as integer IDs, each uniquely identifying a different // string. // * OpenCL code generally handles all values as doubles, so merely converting rtl_uString* // to double could lead to loss of precision (double can store 52bits of precision). // This could lead to two strings possibly being considered equal by mistake (unlikely, // but not impossible). Therefore all rtl_uString* are mapped to internal integer IDs. // * Functions that can handle strings properly should override OpBase::takeString() // to return true. They should // * Empty string Id is 0. Empty cell Id is NAN. // * Since strings are marshalled as doubles too, it is important to check whether a value // is a real double or a string. Use e.g. GenerateArgType to generate also 'xxx_is_string' // variable, there is cell_equal() function to compare two cells.
// If either of the ranges ends with empty cells, it will not include those last // nan values (its GetArrayLength() will be less than its GetRefRowSize(). // If we skip empty cells, just iterate until both ranges have elements, but if // we need to iterate even over empty cells, so use the longer one. // FIXME: If both ranges end with empty cells, this does not actually iterate // over all empty cells. const formula::DoubleVectorRefToken* loopDVR; bool checkBounds; if( empty == SkipEmpty )
{
loopDVR = pDVR1->GetArrayLength() < pDVR2->GetArrayLength() ? pDVR1 : pDVR2;
checkBounds = false;
} else
{
loopDVR = pDVR1->GetArrayLength() > pDVR2->GetArrayLength() ? pDVR1 : pDVR2;
checkBounds = true;
}
GenerateDoubleVectorLoopHeader( ss, loopDVR, firstElementDiff );
ss << " double arg1 = ";
ss << vSubArguments[arg1]->GenSlidingWindowDeclRef(!checkBounds) << ";\n";
ss << " double arg2 = ";
ss << vSubArguments[arg2]->GenSlidingWindowDeclRef(!checkBounds) << ";\n"; switch( empty )
{ case EmptyIsZero:
ss << " if( isnan( arg1 ))\n";
ss << " arg1 = 0;\n";
ss << " if( isnan( arg2 ))\n";
ss << " arg2 = 0;\n"; break; case EmptyIsNan: break; case SkipEmpty:
ss << " if( isnan( arg1 ) || isnan( arg2 ))\n";
ss << " continue;\n"; break;
}
ss << code;
ss << " }\n";
}
void SlidingFunctionBase::GenerateRangeArgElement( constchar* name, int arg, constchar* element,
SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty )
{
assert( arg >= 0 && arg < int (vSubArguments.size()));
FormulaToken *token = vSubArguments[arg]->GetFormulaToken(); if( token == nullptr ) throw Unhandled( __FILE__, __LINE__ ); if(token->GetType() != formula::svDoubleVectorRef) throw Unhandled( __FILE__, __LINE__ ); const formula::DoubleVectorRefToken* pDVR = static_cast<const formula::DoubleVectorRefToken *>(token);
ss << " double " << name << " = NAN;\n";
ss << " {\n"; // GenSlidingWindowDeclRef() may refer to 'i' variable.
ss << " int i = 0;\n";
ss << " if( "; if( !pDVR->IsStartFixed())
ss << "gid0 + ";
ss << element << " < " << pDVR->GetArrayLength() << " )\n";
ss << " " << name << " = " << vSubArguments[arg]->GenSlidingWindowDeclRef(true) << ";\n";
ss << " }\n"; switch( empty )
{ case EmptyIsZero:
ss << " if( isnan( " << name << " ))\n";
ss << " " << name << " = 0;\n"; break; case EmptyIsNan: break; case SkipEmpty:
abort(); break;
}
}
void SlidingFunctionBase::GenerateDoubleVectorLoopHeader( outputstream& ss, const formula::DoubleVectorRefToken* pDVR, constchar* firstElementDiff )
{
size_t nCurWindowSize = pDVR->GetRefRowSize();
std::string startDiff; if( firstElementDiff )
startDiff = std::string( " + " ) + firstElementDiff;
ss << " for (int i = "; if (!pDVR->IsStartFixed() && pDVR->IsEndFixed())
{
ss << "gid0" << startDiff << "; i < " << pDVR->GetArrayLength();
ss << " && i < " << nCurWindowSize << "; i++)\n";
ss << " {\n";
} elseif (pDVR->IsStartFixed() && !pDVR->IsEndFixed())
{
ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength();
ss << " && i < gid0+" << nCurWindowSize << "; i++)\n";
ss << " {\n";
} elseif (!pDVR->IsStartFixed() && !pDVR->IsEndFixed())
{
ss << "0" << startDiff << "; i + gid0 < " << pDVR->GetArrayLength();
ss << " && i < " << nCurWindowSize << "; i++)\n";
ss << " {\n";
} else
{
ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength() << "; i++)\n";
ss << " {\n";
}
}
void SlidingFunctionBase::GenerateFunctionDeclaration( const std::string& sSymName,
SubArguments& vSubArguments, outputstream& ss )
{
ss << "\ndouble " << sSymName;
ss << "_"<< BinFuncName() <<"("; for (size_t i = 0; i < vSubArguments.size(); i++)
{ if (i)
ss << ", ";
vSubArguments[i]->GenSlidingWindowDecl(ss);
}
ss << ")\n";
}
void Normal::GenSlidingWindowFunction(
outputstream& ss, const std::string& sSymName, SubArguments& vSubArguments )
{
GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
ss << "{\n\t";
ss << "double tmp = " << GetBottom() << ";\n\t";
ss << "int gid0 = get_global_id(0);\n\t";
ss << "tmp = ";
std::vector<std::string> argVector; for (size_t i = 0; i < vSubArguments.size(); i++)
argVector.push_back(vSubArguments[i]->GenSlidingWindowDeclRef());
ss << Gen(argVector);
ss << ";\n\t";
ss << "return tmp;\n";
ss << "}";
}
void CheckVariables::GenTmpVariables(
outputstream& ss, const SubArguments& vSubArguments )
{ for (size_t i = 0; i < vSubArguments.size(); i++)
{
ss << " double tmp";
ss << i;
ss << ";\n";
}
}
void CheckVariables::CheckSubArgumentIsNan( outputstream& ss,
SubArguments& vSubArguments, int argumentNum )
{ int i = argumentNum; if (vSubArguments[i]->GetFormulaToken()->GetType() ==
formula::svSingleVectorRef)
{ const formula::SingleVectorRefToken* pTmpDVR1 = static_cast<const formula::SingleVectorRefToken*>(vSubArguments[i]->GetFormulaToken());
ss << " if(singleIndex>=";
ss << pTmpDVR1->GetArrayLength();
ss << " ||";
ss << "isnan(";
ss << vSubArguments[i]->GenSlidingWindowDeclRef(true);
ss << "))\n";
ss << " tmp";
ss << i;
ss << "=0;\n else \n";
ss << " tmp";
ss << i;
ss << "=";
ss << vSubArguments[i]->GenSlidingWindowDeclRef(true);
ss << ";\n";
} if (vSubArguments[i]->GetFormulaToken()->GetType() ==
formula::svDoubleVectorRef)
{ const formula::DoubleVectorRefToken* pTmpDVR2 = static_cast<const formula::DoubleVectorRefToken*>(vSubArguments[i]->GetFormulaToken());
ss << " if(doubleIndex>=";
ss << pTmpDVR2->GetArrayLength();
ss << " ||";
ss << "isnan(";
ss << vSubArguments[i]->GenSlidingWindowDeclRef();
ss << "))\n";
ss << " tmp";
ss << i;
ss << "=0;\n else \n";
ss << " tmp";
ss << i;
ss << "=";
ss << vSubArguments[i]->GenSlidingWindowDeclRef();
ss << ";\n";
} if (vSubArguments[i]->GetFormulaToken()->GetType() == formula::svDouble ||
vSubArguments[i]->GetFormulaToken()->GetOpCode() != ocPush)
{
ss << " if(";
ss << "isnan(";
ss << vSubArguments[i]->GenSlidingWindowDeclRef();
ss << "))\n";
ss << " tmp";
ss << i;
ss << "=0;\n else \n";
ss << " tmp";
ss << i;
ss << "=";
ss << vSubArguments[i]->GenSlidingWindowDeclRef();
ss << ";\n";
}
}
void CheckVariables::CheckSubArgumentIsNan2( outputstream& ss,
SubArguments& vSubArguments, int argumentNum, const std::string& p )
{ int i = argumentNum; if (vSubArguments[i]->GetFormulaToken()->GetType() == formula::svDouble)
{
ss << " tmp";
ss << i;
ss << "=";
vSubArguments[i]->GenDeclRef(ss);
ss << ";\n"; return;
}
ss << " tmp";
ss << i;
ss << "= fsum(";
vSubArguments[i]->GenDeclRef(ss); if (vSubArguments[i]->GetFormulaToken()->GetType() ==
formula::svDoubleVectorRef)
ss << "[" << p.c_str() << "]"; elseif (vSubArguments[i]->GetFormulaToken()->GetType() ==
formula::svSingleVectorRef)
ss << "[get_group_id(1)]";
ss << ", 0);\n";
}
void CheckVariables::CheckAllSubArgumentIsNan(
outputstream& ss, SubArguments& vSubArguments )
{
ss << " int k = gid0;\n"; for (size_t i = 0; i < vSubArguments.size(); i++)
{
CheckSubArgumentIsNan(ss, vSubArguments, i);
}
}
void CheckVariables::UnrollDoubleVector( outputstream& ss, const outputstream& unrollstr, const formula::DoubleVectorRefToken* pCurDVR, int nCurWindowSize )
{ int unrollSize = 16; if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
{
ss << " loop = (" << nCurWindowSize << " - gid0)/";
ss << unrollSize << ";\n";
} elseif (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
{
ss << " loop = (" << nCurWindowSize << " + gid0)/";
ss << unrollSize << ";\n";
ss << " for ( int j = 0;j< loop; j++)\n";
ss << " {\n";
ss << " int i = "; if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
{
ss << "gid0 + j * " << unrollSize << ";\n";
} else
{
ss << "j * " << unrollSize << ";\n";
}
if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
{
ss << " int doubleIndex = i+gid0;\n";
} else
{
ss << " int doubleIndex = i;\n";
}
for (int j = 0; j < unrollSize; j++)
{
ss << unrollstr.str();
ss << "i++;\n";
ss << "doubleIndex++;\n";
}
ss << " }\n";
ss << " for (int i = "; if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
{
ss << "gid0 + loop *" << unrollSize << "; i < ";
ss << nCurWindowSize << "; i++)\n";
} elseif (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
{
ss << "0 + loop *" << unrollSize << "; i < gid0+";
ss << nCurWindowSize << "; i++)\n";
} else
{
ss << "0 + loop *" << unrollSize << "; i < ";
ss << nCurWindowSize << "; i++)\n";
}
ss << " {\n"; if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
{
ss << " int doubleIndex = i+gid0;\n";
} else
{
ss << " int doubleIndex = i;\n";
}
ss << unrollstr.str();
ss << " }\n";
}
void Reduction::GenSlidingWindowFunction( outputstream& ss, const std::string& sSymName, SubArguments& vSubArguments )
{
GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
ss << "{\n";
ss << "double tmp = " << GetBottom() << ";\n";
ss << "int gid0 = get_global_id(0);\n"; if (isAverage() || isMinOrMax())
ss << "int nCount = 0;\n";
ss << "double tmpBottom;\n"; unsigned i = vSubArguments.size(); while (i--)
{ if (NumericRange* NR = dynamic_cast<NumericRange*>(vSubArguments[i].get()))
{ bool needBody;
NR->GenReductionLoopHeader(ss, needBody); if (!needBody) continue;
} elseif (NumericRangeStringsToZero* NRS = dynamic_cast<NumericRangeStringsToZero*>(vSubArguments[i].get()))
{ bool needBody;
NRS->GenReductionLoopHeader(ss, needBody); if (!needBody) continue;
} elseif (ParallelNumericRange* PNR = dynamic_cast<ParallelNumericRange*>(vSubArguments[i].get()))
{ //did not handle yet bool bNeedBody = false;
PNR->GenReductionLoopHeader(ss, mnResultSize, bNeedBody); if (!bNeedBody) continue;
} elseif (StringRange* SR = dynamic_cast<StringRange*>(vSubArguments[i].get()))
{ //did not handle yet bool needBody;
SR->GenReductionLoopHeader(ss, needBody); if (!needBody) continue;
} else
{
FormulaToken* pCur = vSubArguments[i]->GetFormulaToken(); if( pCur == nullptr || pCur->GetType() == formula::svDoubleVectorRef )
{ throw Unhandled(__FILE__, __LINE__);
}
ss << "{\n";
} if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode())
{ bool bNanHandled = HandleNaNArgument(ss, i, vSubArguments);
ss << " tmpBottom = " << GetBottom() << ";\n";
if (!bNanHandled)
{
ss << " if (isnan(";
ss << vSubArguments[i]->GenSlidingWindowDeclRef();
ss << "))\n"; if (ZeroReturnZero())
ss << " return 0;\n"; else
{
ss << " tmp = ";
ss << Gen2("tmpBottom", "tmp") << ";\n";
}
ss << " else\n";
}
ss << " tmp = ";
ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
ss << ";\n";
} else
{
ss << " tmp = ";
ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
ss << ";\n";
}
ss << "}\n";
} if (isAverage())
ss << "if (nCount==0)\n" " return CreateDoubleError(DivisionByZero);\n"; elseif (isMinOrMax())
ss << "if (nCount==0)\n" " return 0;\n";
ss << "return tmp"; if (isAverage())
ss << "/(double)nCount";
ss << ";\n}";
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.