LibreOffice Module sc (master) 1
opbase.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
12#include <rtl/string.hxx>
13#include <sal/log.hxx>
14#include <utility>
15#include <unordered_map>
16
17#include "opbase.hxx"
18
19using namespace formula;
20
21namespace sc::opencl {
22
24 const char* m, std::string fn, int ln ) :
25 mMessage(m), mFile(std::move(fn)), mLineNumber(ln) {}
26
27OpenCLError::OpenCLError( std::string function, cl_int error, std::string file, int line ) :
28 mFunction(std::move(function)), mError(error), mFile(std::move(file)), mLineNumber(line)
29{
30 // Not sure if this SAL_INFO() is useful; the place in
31 // CLInterpreterContext::launchKernel() where OpenCLError is
32 // caught already uses SAL_WARN() to display it.
33
34 // SAL_INFO("sc.opencl", "OpenCL error: " << openclwrapper::errorString(mError));
35}
36
37Unhandled::Unhandled( std::string fn, int ln ) :
38 mFile(std::move(fn)), mLineNumber(ln) {}
39
40InvalidParameterCount::InvalidParameterCount( int parameterCount, std::string file, int ln ) :
41 mParameterCount(parameterCount), mFile(std::move(file)), mLineNumber(ln) {}
42
45 mCalcConfig(config), mSymName(std::move(s)), mFormulaTree(std::move(ft)) { }
46
48{
49 return std::string("");
50}
51
54{
55 return std::string("");
56}
57
60{
61 ss << mSymName;
62}
63
65
67{
68 return mFormulaTree->GetFormulaToken();
69}
70
72{
73 return std::string("");
74}
75
76void DynamicKernelArgument::DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const {}
77
78const std::string& DynamicKernelArgument::GetName() const
79{
80 return mSymName;
81}
82
84{
85 return false;
86}
87
88// Strings and OpenCL:
89// * Strings are non-trivial types and so passing them to OpenCL and handling them there
90// would be rather complex. However, in practice most string operations are checking
91// string equality, so only such string usage is supported (other cases will be
92// handled by Calc core when they get rejected for OpenCL).
93// * Strings from Calc core come from svl::SharedString, which already ensures that
94// equal strings have equal rtl_uString.
95// * Strings are passed to opencl as integer IDs, each uniquely identifying a different
96// string.
97// * OpenCL code generally handles all values as doubles, so merely converting rtl_uString*
98// to double could lead to loss of precision (double can store 52bits of precision).
99// This could lead to two strings possibly being considered equal by mistake (unlikely,
100// but not impossible). Therefore all rtl_uString* are mapped to internal integer IDs.
101// * Functions that can handle strings properly should override OpBase::takeString()
102// to return true. They should
103// * Empty string Id is 0. Empty cell Id is NAN.
104// * Since strings are marshalled as doubles too, it is important to check whether a value
105// is a real double or a string. Use e.g. GenerateArgType to generate also 'xxx_is_string'
106// variable, there is cell_equal() function to compare two cells.
107
108static std::unordered_map<const rtl_uString*, int>* stringIdsMap;
109
110int DynamicKernelArgument::GetStringId( const rtl_uString* string )
111{
112 assert( string != nullptr );
113 if( string->length == 0 )
114 return 0;
115 if( stringIdsMap == nullptr )
116 stringIdsMap = new std::unordered_map<const rtl_uString*, int>;
117 std::unordered_map<const rtl_uString*, int>::iterator it = stringIdsMap->find( string );
118 if( it != stringIdsMap->end())
119 return it->second;
120 int newId = stringIdsMap->size() + 1;
121 stringIdsMap->insert( std::pair( string, newId ));
122 return newId;
123}
124
126{
127 delete stringIdsMap;
128 stringIdsMap = nullptr;
129}
130
131VectorRef::VectorRef( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int idx ) :
132 DynamicKernelArgument(config, s, ft), mpClmem(nullptr), mnIndex(idx), forceStringsToZero( false )
133{
134 if (mnIndex)
135 {
136 outputstream ss;
137 ss << mSymName << "s" << mnIndex;
138 mSymName = ss.str();
139 }
140}
141
143{
144 if (mpClmem)
145 {
146 cl_int err;
147 err = clReleaseMemObject(mpClmem);
148 SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject failed: " << openclwrapper::errorString(err));
149 }
150}
151
154{
155 ss << "__global double *" << mSymName;
156}
157
160{
162}
163
165std::string VectorRef::GenSlidingWindowDeclRef( bool nested ) const
166{
167 outputstream ss;
170 if (pSVR && !nested)
171 ss << "(gid0 < " << pSVR->GetArrayLength() << "?";
172 ss << mSymName << "[gid0]";
173 if (pSVR && !nested)
174 ss << ":NAN)";
175 return ss.str();
176}
177
179
181{
182 FormulaToken* pCur = mFormulaTree->GetFormulaToken();
183 assert(pCur);
184 if (const formula::DoubleVectorRefToken* pCurDVR =
185 dynamic_cast<const formula::DoubleVectorRefToken*>(pCur))
186 {
187 return pCurDVR->GetRefRowSize();
188 }
189 else if (dynamic_cast<const formula::SingleVectorRefToken*>(pCur))
190 {
191 // Prepare intermediate results (on CPU for now)
192 return 1;
193 }
194 else
195 {
196 throw Unhandled(__FILE__, __LINE__);
197 }
198}
199
200std::string VectorRef::DumpOpName() const
201{
202 return std::string("");
203}
204
205void VectorRef::DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const {}
206
207const std::string& VectorRef::GetName() const
208{
209 return mSymName;
210}
211
213{
214 return mpClmem;
215}
216
218{
219 return false;
220}
221
223 const FormulaTreeNodeRef& ft, int index )
224 : VectorRef( config, s, ft, index )
225{
226 forceStringsToZero = true;
227}
228
229void SlidingFunctionBase::GenerateArg( const char* name, int arg, SubArguments& vSubArguments,
230 outputstream& ss, EmptyArgType empty, GenerateArgTypeType generateType )
231{
232 assert( arg < int( vSubArguments.size()));
233 FormulaToken *token = vSubArguments[arg]->GetFormulaToken();
234 if( token == nullptr )
235 throw Unhandled( __FILE__, __LINE__ );
236 if(token->GetOpCode() == ocPush)
237 {
238 if(token->GetType() == formula::svSingleVectorRef)
239 {
241 static_cast<const formula::SingleVectorRefToken *>(token);
242 ss << " double " << name << " = NAN;\n";
243 if( generateType == GenerateArgType )
244 ss << " bool " << name << "_is_string = false;\n";
245 ss << " if (gid0 < " << svr->GetArrayLength() << ")\n";
246 if( generateType == GenerateArgType )
247 ss << " {\n";
248 ss << " " << name << " = ";
249 ss << vSubArguments[arg]->GenSlidingWindowDeclRef( true ) << ";\n";
250 if( generateType == GenerateArgType )
251 {
252 ss << " " << name << "_is_string = ";
253 ss << vSubArguments[arg]->GenIsString( true ) << ";\n";
254 ss << " }\n";
255 }
256 switch( empty )
257 {
258 case EmptyIsZero:
259 ss << " if( isnan( " << name << " ))\n";
260 ss << " " << name << " = 0;\n";
261 break;
262 case EmptyIsNan:
263 break;
264 case SkipEmpty:
265 abort();
266 break;
267 }
268 }
269 else if(token->GetType() == formula::svDouble)
270 {
271 ss << " double " << name << " = " << token->GetDouble() << ";\n";
272 if( generateType == GenerateArgType )
273 ss << " bool " << name << "_is_string = "
274 << vSubArguments[arg]->GenIsString() << ";\n";
275 }
276 else if(token->GetType() == formula::svString)
277 {
278 if( forceStringsToZero())
279 assert( dynamic_cast<DynamicKernelStringToZeroArgument*>(vSubArguments[arg].get()));
280 else if( !takeString())
281 throw Unhandled( __FILE__, __LINE__ );
282 ss << " double " << name << " = 0.0;\n";
283 if( generateType == GenerateArgType )
284 ss << " bool " << name << "_is_string = "
285 << vSubArguments[arg]->GenIsString() << ";\n";
286 }
287 else
288 throw Unhandled( __FILE__, __LINE__ );
289 }
290 else
291 {
292 ss << " double " << name << " = ";
293 ss << vSubArguments[arg]->GenSlidingWindowDeclRef() << ";\n";
294 if( generateType == GenerateArgType )
295 ss << " bool " << name << "_is_string = "
296 << vSubArguments[arg]->GenIsString() << ";\n";
297 }
298}
299
301 EmptyArgType empty, GenerateArgTypeType generateType )
302{
303 OString buf = "arg" + OString::number(arg);
304 GenerateArg( buf.getStr(), arg, vSubArguments, ss, empty, generateType );
305}
306
307void SlidingFunctionBase::GenerateArgWithDefault( const char* name, int arg, double def,
308 SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty )
309{
310 if( arg < int(vSubArguments.size()))
311 GenerateArg( name, arg, vSubArguments, ss, empty );
312 else
313 ss << " double " << name << " = " << def << ";\n";
314}
315
316void SlidingFunctionBase::GenerateRangeArgs( int firstArg, int lastArg, SubArguments& vSubArguments,
317 outputstream& ss, EmptyArgType empty, const char* code )
318{
319 assert( firstArg >= 0 );
320 assert( firstArg <= lastArg );
321 assert( lastArg < int( vSubArguments.size()));
322 for( int i = firstArg;
323 i <= lastArg;
324 ++i )
325 {
326 FormulaToken *token = vSubArguments[i]->GetFormulaToken();
327 if( token == nullptr )
328 throw Unhandled( __FILE__, __LINE__ );
329 if(token->GetOpCode() == ocPush)
330 {
331 if (token->GetType() == formula::svDoubleVectorRef)
332 {
334 static_cast<const formula::DoubleVectorRefToken *>(token);
335 GenerateDoubleVectorLoopHeader( ss, pDVR, nullptr );
336 ss << " double arg = ";
337 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
338 ss << ";\n";
339 switch( empty )
340 {
341 case EmptyIsZero:
342 ss << " if( isnan( arg ))\n";
343 ss << " arg = 0;\n";
344 break;
345 case EmptyIsNan:
346 break;
347 case SkipEmpty:
348 ss << " if( isnan( arg ))\n";
349 ss << " continue;\n";
350 break;
351 }
352 ss << code;
353 ss << " }\n";
354 }
355 else if (token->GetType() == formula::svSingleVectorRef)
356 {
358 static_cast< const formula::SingleVectorRefToken*>(token);
359 ss << " if (gid0 < " << pSVR->GetArrayLength() << ")\n";
360 ss << " {\n";
361 ss << " double arg = ";
362 ss << vSubArguments[i]->GenSlidingWindowDeclRef() << ";\n";
363 switch( empty )
364 {
365 case EmptyIsZero:
366 ss << " if( isnan( arg ))\n";
367 ss << " arg = 0;\n";
368 ss << code;
369 break;
370 case EmptyIsNan:
371 ss << code;
372 break;
373 case SkipEmpty:
374 ss << " if( !isnan( arg ))\n";
375 ss << " {\n";
376 ss << code;
377 ss << " }\n";
378 break;
379 }
380 ss << " }\n";
381 }
382 else if(token->GetType() == formula::svDouble)
383 {
384 ss << " {\n";
385 ss << " double arg = " << token->GetDouble() << ";\n";
386 ss << code;
387 ss << " }\n";
388 }
389 else if(token->GetType() == formula::svString)
390 {
391 assert( dynamic_cast<DynamicKernelStringToZeroArgument*>(vSubArguments[i].get()));
392 ss << " {\n";
393 ss << " double arg = 0.0;\n";
394 ss << code;
395 ss << " }\n";
396 }
397 else
398 throw Unhandled( __FILE__, __LINE__ );
399 }
400 else
401 {
402 ss << " {\n";
403 ss << " double arg = ";
404 ss << vSubArguments[i]->GenSlidingWindowDeclRef() << ";\n";
405 ss << code;
406 ss << " }\n";
407 }
408 }
409}
410
412 outputstream& ss, EmptyArgType empty, const char* code )
413{
414 GenerateRangeArgs( 0, vSubArguments.size() - 1, vSubArguments, ss, empty, code );
415}
416
418 outputstream& ss, EmptyArgType empty, const char* code )
419{
420 GenerateRangeArgs( arg, arg, vSubArguments, ss, empty, code );
421}
422
423void SlidingFunctionBase::GenerateRangeArgPair( int arg1, int arg2, SubArguments& vSubArguments,
424 outputstream& ss, EmptyArgType empty, const char* code, const char* firstElementDiff )
425{
426 assert( arg1 >= 0 && arg1 < int (vSubArguments.size()));
427 assert( arg2 >= 0 && arg2 < int (vSubArguments.size()));
428 assert( arg1 != arg2 );
429 FormulaToken *token1 = vSubArguments[arg1]->GetFormulaToken();
430 if( token1 == nullptr )
431 throw Unhandled( __FILE__, __LINE__ );
432 FormulaToken *token2 = vSubArguments[arg2]->GetFormulaToken();
433 if( token2 == nullptr )
434 throw Unhandled( __FILE__, __LINE__ );
435 if(token1->GetType() != formula::svDoubleVectorRef
436 || token2->GetType() != formula::svDoubleVectorRef)
437 {
438 throw Unhandled( __FILE__, __LINE__ );
439 }
440 const formula::DoubleVectorRefToken* pDVR1 =
441 static_cast<const formula::DoubleVectorRefToken *>(token1);
442 const formula::DoubleVectorRefToken* pDVR2 =
443 static_cast<const formula::DoubleVectorRefToken *>(token2);
444
445 size_t nCurWindowSize1 = pDVR1->GetRefRowSize();
446 size_t nCurWindowSize2 = pDVR2->GetRefRowSize();
447
448 if(nCurWindowSize1 != nCurWindowSize2)
449 throw Unhandled( __FILE__, __LINE__ );
450 if(pDVR1->IsStartFixed() != pDVR2->IsStartFixed()
451 || pDVR1->IsEndFixed() != pDVR2->IsEndFixed())
452 {
453 throw Unhandled( __FILE__, __LINE__ );
454 }
455
456 // If either of the ranges ends with empty cells, it will not include those last
457 // nan values (its GetArrayLength() will be less than its GetRefRowSize().
458 // If we skip empty cells, just iterate until both ranges have elements, but if
459 // we need to iterate even over empty cells, so use the longer one.
460 // FIXME: If both ranges end with empty cells, this does not actually iterate
461 // over all empty cells.
462 const formula::DoubleVectorRefToken* loopDVR;
463 bool checkBounds;
464 if( empty == SkipEmpty )
465 {
466 loopDVR = pDVR1->GetArrayLength() < pDVR2->GetArrayLength() ? pDVR1 : pDVR2;
467 checkBounds = false;
468 }
469 else
470 {
471 loopDVR = pDVR1->GetArrayLength() > pDVR2->GetArrayLength() ? pDVR1 : pDVR2;
472 checkBounds = true;
473 }
474 GenerateDoubleVectorLoopHeader( ss, loopDVR, firstElementDiff );
475 ss << " double arg1 = ";
476 ss << vSubArguments[arg1]->GenSlidingWindowDeclRef(!checkBounds) << ";\n";
477 ss << " double arg2 = ";
478 ss << vSubArguments[arg2]->GenSlidingWindowDeclRef(!checkBounds) << ";\n";
479 switch( empty )
480 {
481 case EmptyIsZero:
482 ss << " if( isnan( arg1 ))\n";
483 ss << " arg1 = 0;\n";
484 ss << " if( isnan( arg2 ))\n";
485 ss << " arg2 = 0;\n";
486 break;
487 case EmptyIsNan:
488 break;
489 case SkipEmpty:
490 ss << " if( isnan( arg1 ) || isnan( arg2 ))\n";
491 ss << " continue;\n";
492 break;
493 }
494 ss << code;
495 ss << " }\n";
496}
497
498void SlidingFunctionBase::GenerateRangeArgElement( const char* name, int arg, const char* element,
499 SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty )
500{
501 assert( arg >= 0 && arg < int (vSubArguments.size()));
502 FormulaToken *token = vSubArguments[arg]->GetFormulaToken();
503 if( token == nullptr )
504 throw Unhandled( __FILE__, __LINE__ );
505 if(token->GetType() != formula::svDoubleVectorRef)
506 throw Unhandled( __FILE__, __LINE__ );
508 static_cast<const formula::DoubleVectorRefToken *>(token);
509 ss << " double " << name << " = NAN;\n";
510 ss << " {\n";
511 // GenSlidingWindowDeclRef() may refer to 'i' variable.
512 ss << " int i = 0;\n";
513 ss << " if( ";
514 if( !pDVR->IsStartFixed())
515 ss << "gid0 + ";
516 ss << element << " < " << pDVR->GetArrayLength() << " )\n";
517 ss << " " << name << " = " << vSubArguments[arg]->GenSlidingWindowDeclRef(true) << ";\n";
518 ss << " }\n";
519 switch( empty )
520 {
521 case EmptyIsZero:
522 ss << " if( isnan( " << name << " ))\n";
523 ss << " " << name << " = 0;\n";
524 break;
525 case EmptyIsNan:
526 break;
527 case SkipEmpty:
528 abort();
529 break;
530 }
531}
532
534 const formula::DoubleVectorRefToken* pDVR, const char* firstElementDiff )
535{
536 size_t nCurWindowSize = pDVR->GetRefRowSize();
537 std::string startDiff;
538 if( firstElementDiff )
539 startDiff = std::string( " + " ) + firstElementDiff;
540 ss << " for (int i = ";
541 if (!pDVR->IsStartFixed() && pDVR->IsEndFixed())
542 {
543 ss << "gid0" << startDiff << "; i < " << pDVR->GetArrayLength();
544 ss << " && i < " << nCurWindowSize << "; i++)\n";
545 ss << " {\n";
546 }
547 else if (pDVR->IsStartFixed() && !pDVR->IsEndFixed())
548 {
549 ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength();
550 ss << " && i < gid0+" << nCurWindowSize << "; i++)\n";
551 ss << " {\n";
552 }
553 else if (!pDVR->IsStartFixed() && !pDVR->IsEndFixed())
554 {
555 ss << "0" << startDiff << "; i + gid0 < " << pDVR->GetArrayLength();
556 ss << " && i < " << nCurWindowSize << "; i++)\n";
557 ss << " {\n";
558 }
559 else
560 {
561 ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength() << "; i++)\n";
562 ss << " {\n";
563 }
564}
565
566void SlidingFunctionBase::GenerateFunctionDeclaration( const std::string& sSymName,
567 SubArguments& vSubArguments, outputstream& ss )
568{
569 ss << "\ndouble " << sSymName;
570 ss << "_"<< BinFuncName() <<"(";
571 for (size_t i = 0; i < vSubArguments.size(); i++)
572 {
573 if (i)
574 ss << ", ";
575 vSubArguments[i]->GenSlidingWindowDecl(ss);
576 }
577 ss << ")\n";
578}
579
581 outputstream& ss, const std::string& sSymName, SubArguments& vSubArguments )
582{
583 GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
584 ss << "{\n\t";
585 ss << "double tmp = " << GetBottom() << ";\n\t";
586 ss << "int gid0 = get_global_id(0);\n\t";
587 ss << "tmp = ";
588 std::vector<std::string> argVector;
589 for (size_t i = 0; i < vSubArguments.size(); i++)
590 argVector.push_back(vSubArguments[i]->GenSlidingWindowDeclRef());
591 ss << Gen(argVector);
592 ss << ";\n\t";
593 ss << "return tmp;\n";
594 ss << "}";
595}
596
598 outputstream& ss, const SubArguments& vSubArguments )
599{
600 for (size_t i = 0; i < vSubArguments.size(); i++)
601 {
602 ss << " double tmp";
603 ss << i;
604 ss << ";\n";
605 }
606}
607
609 SubArguments& vSubArguments, int argumentNum )
610{
611 int i = argumentNum;
612 if (vSubArguments[i]->GetFormulaToken()->GetType() ==
614 {
615 const formula::SingleVectorRefToken* pTmpDVR1 =
616 static_cast<const formula::SingleVectorRefToken*>(vSubArguments[i]->GetFormulaToken());
617 ss << " if(singleIndex>=";
618 ss << pTmpDVR1->GetArrayLength();
619 ss << " ||";
620 ss << "isnan(";
621 ss << vSubArguments[i]->GenSlidingWindowDeclRef(true);
622 ss << "))\n";
623 ss << " tmp";
624 ss << i;
625 ss << "=0;\n else \n";
626 ss << " tmp";
627 ss << i;
628 ss << "=";
629 ss << vSubArguments[i]->GenSlidingWindowDeclRef(true);
630 ss << ";\n";
631 }
632 if (vSubArguments[i]->GetFormulaToken()->GetType() ==
634 {
635 const formula::DoubleVectorRefToken* pTmpDVR2 =
636 static_cast<const formula::DoubleVectorRefToken*>(vSubArguments[i]->GetFormulaToken());
637 ss << " if(doubleIndex>=";
638 ss << pTmpDVR2->GetArrayLength();
639 ss << " ||";
640 ss << "isnan(";
641 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
642 ss << "))\n";
643 ss << " tmp";
644 ss << i;
645 ss << "=0;\n else \n";
646 ss << " tmp";
647 ss << i;
648 ss << "=";
649 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
650 ss << ";\n";
651 }
652 if (vSubArguments[i]->GetFormulaToken()->GetType() == formula::svDouble ||
653 vSubArguments[i]->GetFormulaToken()->GetOpCode() != ocPush)
654 {
655 ss << " if(";
656 ss << "isnan(";
657 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
658 ss << "))\n";
659 ss << " tmp";
660 ss << i;
661 ss << "=0;\n else \n";
662 ss << " tmp";
663 ss << i;
664 ss << "=";
665 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
666 ss << ";\n";
667
668 }
669
670}
671
673 SubArguments& vSubArguments, int argumentNum, const std::string& p )
674{
675 int i = argumentNum;
676 if (vSubArguments[i]->GetFormulaToken()->GetType() == formula::svDouble)
677 {
678 ss << " tmp";
679 ss << i;
680 ss << "=";
681 vSubArguments[i]->GenDeclRef(ss);
682 ss << ";\n";
683 return;
684 }
685
686 ss << " tmp";
687 ss << i;
688 ss << "= fsum(";
689 vSubArguments[i]->GenDeclRef(ss);
690 if (vSubArguments[i]->GetFormulaToken()->GetType() ==
692 ss << "[" << p.c_str() << "]";
693 else if (vSubArguments[i]->GetFormulaToken()->GetType() ==
695 ss << "[get_group_id(1)]";
696 ss << ", 0);\n";
697}
698
700 outputstream& ss, SubArguments& vSubArguments )
701{
702 ss << " int k = gid0;\n";
703 for (size_t i = 0; i < vSubArguments.size(); i++)
704 {
705 CheckSubArgumentIsNan(ss, vSubArguments, i);
706 }
707}
708
710 const outputstream& unrollstr, const formula::DoubleVectorRefToken* pCurDVR,
711 int nCurWindowSize )
712{
713 int unrollSize = 16;
714 if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
715 {
716 ss << " loop = (" << nCurWindowSize << " - gid0)/";
717 ss << unrollSize << ";\n";
718 }
719 else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
720 {
721 ss << " loop = (" << nCurWindowSize << " + gid0)/";
722 ss << unrollSize << ";\n";
723
724 }
725 else
726 {
727 ss << " loop = " << nCurWindowSize << "/" << unrollSize << ";\n";
728 }
729
730 ss << " for ( int j = 0;j< loop; j++)\n";
731 ss << " {\n";
732 ss << " int i = ";
733 if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
734 {
735 ss << "gid0 + j * " << unrollSize << ";\n";
736 }
737 else
738 {
739 ss << "j * " << unrollSize << ";\n";
740 }
741
742 if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
743 {
744 ss << " int doubleIndex = i+gid0;\n";
745 }
746 else
747 {
748 ss << " int doubleIndex = i;\n";
749 }
750
751 for (int j = 0; j < unrollSize; j++)
752 {
753 ss << unrollstr.str();
754 ss << "i++;\n";
755 ss << "doubleIndex++;\n";
756 }
757 ss << " }\n";
758 ss << " for (int i = ";
759 if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
760 {
761 ss << "gid0 + loop *" << unrollSize << "; i < ";
762 ss << nCurWindowSize << "; i++)\n";
763 }
764 else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
765 {
766 ss << "0 + loop *" << unrollSize << "; i < gid0+";
767 ss << nCurWindowSize << "; i++)\n";
768 }
769 else
770 {
771 ss << "0 + loop *" << unrollSize << "; i < ";
772 ss << nCurWindowSize << "; i++)\n";
773 }
774 ss << " {\n";
775 if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
776 {
777 ss << " int doubleIndex = i+gid0;\n";
778 }
779 else
780 {
781 ss << " int doubleIndex = i;\n";
782 }
783 ss << unrollstr.str();
784 ss << " }\n";
785}
786
788 const std::string& sSymName, SubArguments& vSubArguments )
789{
790 GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
791 ss << "{\n";
792 ss << "double tmp = " << GetBottom() << ";\n";
793 ss << "int gid0 = get_global_id(0);\n";
794 if (isAverage() || isMinOrMax())
795 ss << "int nCount = 0;\n";
796 ss << "double tmpBottom;\n";
797 unsigned i = vSubArguments.size();
798 while (i--)
799 {
800 if (NumericRange* NR = dynamic_cast<NumericRange*>(vSubArguments[i].get()))
801 {
802 bool needBody;
803 NR->GenReductionLoopHeader(ss, needBody);
804 if (!needBody)
805 continue;
806 }
807 else if (NumericRangeStringsToZero* NRS = dynamic_cast<NumericRangeStringsToZero*>(vSubArguments[i].get()))
808 {
809 bool needBody;
810 NRS->GenReductionLoopHeader(ss, needBody);
811 if (!needBody)
812 continue;
813 }
814 else if (ParallelNumericRange* PNR = dynamic_cast<ParallelNumericRange*>(vSubArguments[i].get()))
815 {
816 //did not handle yet
817 bool bNeedBody = false;
818 PNR->GenReductionLoopHeader(ss, mnResultSize, bNeedBody);
819 if (!bNeedBody)
820 continue;
821 }
822 else if (StringRange* SR = dynamic_cast<StringRange*>(vSubArguments[i].get()))
823 {
824 //did not handle yet
825 bool needBody;
826 SR->GenReductionLoopHeader(ss, needBody);
827 if (!needBody)
828 continue;
829 }
830 else
831 {
832 FormulaToken* pCur = vSubArguments[i]->GetFormulaToken();
833 if( pCur == nullptr || pCur->GetType() == formula::svDoubleVectorRef )
834 {
835 throw Unhandled(__FILE__, __LINE__);
836 }
837 ss << "{\n";
838 }
839 if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode())
840 {
841 bool bNanHandled = HandleNaNArgument(ss, i, vSubArguments);
842
843 ss << " tmpBottom = " << GetBottom() << ";\n";
844
845 if (!bNanHandled)
846 {
847 ss << " if (isnan(";
848 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
849 ss << "))\n";
850 if (ZeroReturnZero())
851 ss << " return 0;\n";
852 else
853 {
854 ss << " tmp = ";
855 ss << Gen2("tmpBottom", "tmp") << ";\n";
856 }
857 ss << " else\n";
858 }
859 ss << " tmp = ";
860 ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
861 ss << ";\n";
862 }
863 else
864 {
865 ss << " tmp = ";
866 ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
867 ss << ";\n";
868 }
869 ss << "}\n";
870 }
871 if (isAverage())
872 ss <<
873 "if (nCount==0)\n"
874 " return CreateDoubleError(DivisionByZero);\n";
875 else if (isMinOrMax())
876 ss <<
877 "if (nCount==0)\n"
878 " return 0;\n";
879 ss << "return tmp";
880 if (isAverage())
881 ss << "/(double)nCount";
882 ss << ";\n}";
883}
884
885}
886
887/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
OpCode GetOpCode() const
StackVar GetType() const
virtual double GetDouble() const
static void CheckSubArgumentIsNan2(outputstream &ss, SubArguments &vSubArguments, int argumentNum, const std::string &p)
Definition: opbase.cxx:672
static void CheckSubArgumentIsNan(outputstream &ss, SubArguments &vSubArguments, int argumentNum)
Definition: opbase.cxx:608
static void GenTmpVariables(outputstream &ss, const SubArguments &vSubArguments)
Definition: opbase.cxx:597
static void UnrollDoubleVector(outputstream &ss, const outputstream &unrollstr, const formula::DoubleVectorRefToken *pCurDVR, int nCurWindowSize)
Definition: opbase.cxx:709
static void CheckAllSubArgumentIsNan(outputstream &ss, SubArguments &vSubArguments)
Definition: opbase.cxx:699
(Partially) abstract base class for an operand
Definition: opbase.hxx:125
virtual std::string GenStringSlidingWindowDeclRef(bool=false) const
When Mix, it will be called.
Definition: opbase.cxx:53
static int GetStringId(const rtl_uString *string)
Definition: opbase.cxx:110
virtual void DumpInlineFun(std::set< std::string > &, std::set< std::string > &) const
Definition: opbase.cxx:76
virtual std::string DumpOpName() const
Definition: opbase.cxx:71
formula::FormulaToken * GetFormulaToken() const
Definition: opbase.cxx:66
virtual bool NeedParallelReduction() const
Definition: opbase.cxx:83
virtual void GenDeclRef(outputstream &ss) const
Generate use/references to the argument.
Definition: opbase.cxx:59
const std::string & GetName() const
Definition: opbase.cxx:78
virtual void GenSlidingWindowFunction(outputstream &)
Definition: opbase.cxx:64
DynamicKernelArgument(const DynamicKernelArgument &)=delete
delete copy constructor
FormulaTreeNodeRef mFormulaTree
Definition: opbase.hxx:176
virtual std::string GenDoubleSlidingWindowDeclRef(bool=false) const
When Mix, it will be called.
Definition: opbase.cxx:47
Handling a Double Vector that is used as a sliding window input to either a sliding window average or...
Definition: opbase.hxx:440
InvalidParameterCount(int parameterCount, std::string file, int ln)
Definition: opbase.cxx:40
virtual void GenSlidingWindowFunction(outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) override
Definition: opbase.cxx:580
virtual std::string GetBottom()
Definition: opbase.hxx:325
virtual bool ZeroReturnZero()
Definition: opbase.hxx:338
virtual std::string Gen2(const std::string &, const std::string &) const
Definition: opbase.hxx:326
static std::string Gen(std::vector< std::string > &)
Definition: opbase.hxx:328
virtual bool takeString() const =0
virtual std::string BinFuncName() const
Definition: opbase.hxx:329
virtual bool forceStringsToZero() const
Definition: opbase.hxx:340
OpenCLError(std::string function, cl_int error, std::string file, int line)
Definition: opbase.cxx:27
Handling a Double Vector that is used as a sliding window input Performs parallel reduction based on ...
Definition: opbase.hxx:472
int const mnResultSize
Definition: opbase.hxx:501
virtual bool isMinOrMax() const
Definition: opbase.hxx:518
virtual void GenSlidingWindowFunction(outputstream &ss, const std::string &sSymName, SubArguments &vSubArguments) override
Definition: opbase.cxx:787
virtual bool isAverage() const
Definition: opbase.hxx:517
virtual bool HandleNaNArgument(outputstream &, unsigned, SubArguments &) const
Definition: opbase.hxx:510
void GenerateArg(const char *name, int arg, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty=EmptyIsZero, GenerateArgTypeType generateType=DoNotGenerateArgType)
Definition: opbase.cxx:229
static void GenerateDoubleVectorLoopHeader(outputstream &ss, const formula::DoubleVectorRefToken *pDVR, const char *firstElementDiff)
Definition: opbase.cxx:533
static void GenerateRangeArgElement(const char *name, int arg, const char *element, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty)
Definition: opbase.cxx:498
static void GenerateRangeArg(int arg, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty, const char *code)
Definition: opbase.cxx:417
void GenerateArgWithDefault(const char *name, int arg, double def, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty=EmptyIsZero)
Definition: opbase.cxx:307
void GenerateFunctionDeclaration(const std::string &sSymName, SubArguments &vSubArguments, outputstream &ss)
Definition: opbase.cxx:566
static void GenerateRangeArgPair(int arg1, int arg2, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty, const char *code, const char *firstElementDiff=nullptr)
Definition: opbase.cxx:423
static void GenerateRangeArgs(int firstArg, int lastArg, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty, const char *code)
Definition: opbase.cxx:316
std::vector< DynamicKernelArgumentRef > SubArguments
Definition: opbase.hxx:347
UnhandledToken(const char *m, std::string fn, int ln)
Definition: opbase.cxx:23
Inconsistent state.
Definition: opbase.hxx:65
Unhandled(std::string fn, int ln)
Definition: opbase.cxx:37
VectorRefStringsToZero(const ScCalcConfig &config, const std::string &s, const FormulaTreeNodeRef &ft, int index=0)
Definition: opbase.cxx:222
Holds an input (read-only) argument reference to a SingleVectorRef.
Definition: opbase.hxx:188
VectorRef(const ScCalcConfig &config, const std::string &s, const FormulaTreeNodeRef &ft, int index=0)
Definition: opbase.cxx:131
virtual bool NeedParallelReduction() const override
Definition: opbase.cxx:217
virtual void GenSlidingWindowDecl(outputstream &ss) const override
When declared as input to a sliding window function.
Definition: opbase.cxx:159
virtual std::string GenSlidingWindowDeclRef(bool=false) const override
When referenced in a sliding window function.
Definition: opbase.cxx:165
virtual void GenDecl(outputstream &ss) const override
Generate declaration.
Definition: opbase.cxx:153
const std::string & GetName() const
Definition: opbase.cxx:207
virtual void DumpInlineFun(std::set< std::string > &, std::set< std::string > &) const override
Definition: opbase.cxx:205
cl_mem GetCLBuffer() const
Definition: opbase.cxx:212
virtual std::string DumpOpName() const override
Definition: opbase.cxx:200
virtual size_t GetWindowSize() const override
Definition: opbase.cxx:180
virtual ~VectorRef() override
Definition: opbase.cxx:142
virtual void GenSlidingWindowFunction(outputstream &) override
Definition: opbase.cxx:178
ScCalcConfig mCalcConfig
const char * name
const sal_uInt16 idx[]
void * p
#define SAL_WARN_IF(condition, area, stream)
err
config
int i
line
index
m
const char * errorString(cl_int nError)
static std::unordered_map< const rtl_uString *, int > * stringIdsMap
Definition: opbase.cxx:108
std::shared_ptr< FormulaTreeNode > FormulaTreeNodeRef
Definition: opbase.hxx:104
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
sal_Unicode code
ocPush
Configuration options for formula interpreter.
Definition: calcconfig.hxx:44
sal_uInt32 mnIndex