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 int newId = stringIdsMap->size() + 1;
118 auto aItInsertedPair = stringIdsMap->insert( std::pair( string, newId ));
119 return aItInsertedPair.first->second;
120}
121
123{
124 delete stringIdsMap;
125 stringIdsMap = nullptr;
126}
127
128VectorRef::VectorRef( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int idx ) :
129 DynamicKernelArgument(config, s, ft), mpClmem(nullptr), mnIndex(idx), forceStringsToZero( false )
130{
131 if (mnIndex)
132 {
133 outputstream ss;
134 ss << mSymName << "s" << mnIndex;
135 mSymName = ss.str();
136 }
137}
138
140{
141 if (mpClmem)
142 {
143 cl_int err;
144 err = clReleaseMemObject(mpClmem);
145 SAL_WARN_IF(err != CL_SUCCESS, "sc.opencl", "clReleaseMemObject failed: " << openclwrapper::errorString(err));
146 }
147}
148
151{
152 ss << "__global double *" << mSymName;
153}
154
157{
159}
160
162std::string VectorRef::GenSlidingWindowDeclRef( bool nested ) const
163{
164 outputstream ss;
167 if (pSVR && !nested)
168 ss << "(gid0 < " << pSVR->GetArrayLength() << "?";
169 ss << mSymName << "[gid0]";
170 if (pSVR && !nested)
171 ss << ":NAN)";
172 return ss.str();
173}
174
176
178{
179 FormulaToken* pCur = mFormulaTree->GetFormulaToken();
180 assert(pCur);
181 if (const formula::DoubleVectorRefToken* pCurDVR =
182 dynamic_cast<const formula::DoubleVectorRefToken*>(pCur))
183 {
184 return pCurDVR->GetRefRowSize();
185 }
186 else if (dynamic_cast<const formula::SingleVectorRefToken*>(pCur))
187 {
188 // Prepare intermediate results (on CPU for now)
189 return 1;
190 }
191 else
192 {
193 throw Unhandled(__FILE__, __LINE__);
194 }
195}
196
197std::string VectorRef::DumpOpName() const
198{
199 return std::string("");
200}
201
202void VectorRef::DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const {}
203
204const std::string& VectorRef::GetName() const
205{
206 return mSymName;
207}
208
210{
211 return mpClmem;
212}
213
215{
216 return false;
217}
218
220 const FormulaTreeNodeRef& ft, int index )
221 : VectorRef( config, s, ft, index )
222{
223 forceStringsToZero = true;
224}
225
226void SlidingFunctionBase::GenerateArg( const char* name, int arg, SubArguments& vSubArguments,
227 outputstream& ss, EmptyArgType empty, GenerateArgTypeType generateType )
228{
229 assert( arg < int( vSubArguments.size()));
230 FormulaToken *token = vSubArguments[arg]->GetFormulaToken();
231 if( token == nullptr )
232 throw Unhandled( __FILE__, __LINE__ );
233 if(token->GetOpCode() == ocPush)
234 {
235 if(token->GetType() == formula::svSingleVectorRef)
236 {
238 static_cast<const formula::SingleVectorRefToken *>(token);
239 ss << " double " << name << " = NAN;\n";
240 if( generateType == GenerateArgType )
241 ss << " bool " << name << "_is_string = false;\n";
242 ss << " if (gid0 < " << svr->GetArrayLength() << ")\n";
243 if( generateType == GenerateArgType )
244 ss << " {\n";
245 ss << " " << name << " = ";
246 ss << vSubArguments[arg]->GenSlidingWindowDeclRef( true ) << ";\n";
247 if( generateType == GenerateArgType )
248 {
249 ss << " " << name << "_is_string = ";
250 ss << vSubArguments[arg]->GenIsString( true ) << ";\n";
251 ss << " }\n";
252 }
253 switch( empty )
254 {
255 case EmptyIsZero:
256 ss << " if( isnan( " << name << " ))\n";
257 ss << " " << name << " = 0;\n";
258 break;
259 case EmptyIsNan:
260 break;
261 case SkipEmpty:
262 abort();
263 break;
264 }
265 }
266 else if(token->GetType() == formula::svDouble)
267 {
268 ss << " double " << name << " = " << token->GetDouble() << ";\n";
269 if( generateType == GenerateArgType )
270 ss << " bool " << name << "_is_string = "
271 << vSubArguments[arg]->GenIsString() << ";\n";
272 }
273 else if(token->GetType() == formula::svString)
274 {
275 if( forceStringsToZero())
276 assert( dynamic_cast<DynamicKernelStringToZeroArgument*>(vSubArguments[arg].get()));
277 else if( !takeString())
278 throw Unhandled( __FILE__, __LINE__ );
279 ss << " double " << name << " = 0.0;\n";
280 if( generateType == GenerateArgType )
281 ss << " bool " << name << "_is_string = "
282 << vSubArguments[arg]->GenIsString() << ";\n";
283 }
284 else
285 throw Unhandled( __FILE__, __LINE__ );
286 }
287 else
288 {
289 ss << " double " << name << " = ";
290 ss << vSubArguments[arg]->GenSlidingWindowDeclRef() << ";\n";
291 if( generateType == GenerateArgType )
292 ss << " bool " << name << "_is_string = "
293 << vSubArguments[arg]->GenIsString() << ";\n";
294 }
295}
296
298 EmptyArgType empty, GenerateArgTypeType generateType )
299{
300 OString buf = "arg" + OString::number(arg);
301 GenerateArg( buf.getStr(), arg, vSubArguments, ss, empty, generateType );
302}
303
304void SlidingFunctionBase::GenerateArgWithDefault( const char* name, int arg, double def,
305 SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty )
306{
307 if( arg < int(vSubArguments.size()))
308 GenerateArg( name, arg, vSubArguments, ss, empty );
309 else
310 ss << " double " << name << " = " << def << ";\n";
311}
312
313void SlidingFunctionBase::GenerateRangeArgs( int firstArg, int lastArg, SubArguments& vSubArguments,
314 outputstream& ss, EmptyArgType empty, const char* code )
315{
316 assert( firstArg >= 0 );
317 assert( firstArg <= lastArg );
318 assert( lastArg < int( vSubArguments.size()));
319 for( int i = firstArg;
320 i <= lastArg;
321 ++i )
322 {
323 FormulaToken *token = vSubArguments[i]->GetFormulaToken();
324 if( token == nullptr )
325 throw Unhandled( __FILE__, __LINE__ );
326 if(token->GetOpCode() == ocPush)
327 {
328 if (token->GetType() == formula::svDoubleVectorRef)
329 {
331 static_cast<const formula::DoubleVectorRefToken *>(token);
332 GenerateDoubleVectorLoopHeader( ss, pDVR, nullptr );
333 ss << " double arg = ";
334 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
335 ss << ";\n";
336 switch( empty )
337 {
338 case EmptyIsZero:
339 ss << " if( isnan( arg ))\n";
340 ss << " arg = 0;\n";
341 break;
342 case EmptyIsNan:
343 break;
344 case SkipEmpty:
345 ss << " if( isnan( arg ))\n";
346 ss << " continue;\n";
347 break;
348 }
349 ss << code;
350 ss << " }\n";
351 }
352 else if (token->GetType() == formula::svSingleVectorRef)
353 {
355 static_cast< const formula::SingleVectorRefToken*>(token);
356 ss << " if (gid0 < " << pSVR->GetArrayLength() << ")\n";
357 ss << " {\n";
358 ss << " double arg = ";
359 ss << vSubArguments[i]->GenSlidingWindowDeclRef() << ";\n";
360 switch( empty )
361 {
362 case EmptyIsZero:
363 ss << " if( isnan( arg ))\n";
364 ss << " arg = 0;\n";
365 ss << code;
366 break;
367 case EmptyIsNan:
368 ss << code;
369 break;
370 case SkipEmpty:
371 ss << " if( !isnan( arg ))\n";
372 ss << " {\n";
373 ss << code;
374 ss << " }\n";
375 break;
376 }
377 ss << " }\n";
378 }
379 else if(token->GetType() == formula::svDouble)
380 {
381 ss << " {\n";
382 ss << " double arg = " << token->GetDouble() << ";\n";
383 ss << code;
384 ss << " }\n";
385 }
386 else if(token->GetType() == formula::svString)
387 {
388 assert( dynamic_cast<DynamicKernelStringToZeroArgument*>(vSubArguments[i].get()));
389 ss << " {\n";
390 ss << " double arg = 0.0;\n";
391 ss << code;
392 ss << " }\n";
393 }
394 else
395 throw Unhandled( __FILE__, __LINE__ );
396 }
397 else
398 {
399 ss << " {\n";
400 ss << " double arg = ";
401 ss << vSubArguments[i]->GenSlidingWindowDeclRef() << ";\n";
402 ss << code;
403 ss << " }\n";
404 }
405 }
406}
407
409 outputstream& ss, EmptyArgType empty, const char* code )
410{
411 GenerateRangeArgs( 0, vSubArguments.size() - 1, vSubArguments, ss, empty, code );
412}
413
415 outputstream& ss, EmptyArgType empty, const char* code )
416{
417 GenerateRangeArgs( arg, arg, vSubArguments, ss, empty, code );
418}
419
420void SlidingFunctionBase::GenerateRangeArgPair( int arg1, int arg2, SubArguments& vSubArguments,
421 outputstream& ss, EmptyArgType empty, const char* code, const char* firstElementDiff )
422{
423 assert( arg1 >= 0 && arg1 < int (vSubArguments.size()));
424 assert( arg2 >= 0 && arg2 < int (vSubArguments.size()));
425 assert( arg1 != arg2 );
426 FormulaToken *token1 = vSubArguments[arg1]->GetFormulaToken();
427 if( token1 == nullptr )
428 throw Unhandled( __FILE__, __LINE__ );
429 FormulaToken *token2 = vSubArguments[arg2]->GetFormulaToken();
430 if( token2 == nullptr )
431 throw Unhandled( __FILE__, __LINE__ );
432 if(token1->GetType() != formula::svDoubleVectorRef
433 || token2->GetType() != formula::svDoubleVectorRef)
434 {
435 throw Unhandled( __FILE__, __LINE__ );
436 }
437 const formula::DoubleVectorRefToken* pDVR1 =
438 static_cast<const formula::DoubleVectorRefToken *>(token1);
439 const formula::DoubleVectorRefToken* pDVR2 =
440 static_cast<const formula::DoubleVectorRefToken *>(token2);
441
442 size_t nCurWindowSize1 = pDVR1->GetRefRowSize();
443 size_t nCurWindowSize2 = pDVR2->GetRefRowSize();
444
445 if(nCurWindowSize1 != nCurWindowSize2)
446 throw Unhandled( __FILE__, __LINE__ );
447 if(pDVR1->IsStartFixed() != pDVR2->IsStartFixed()
448 || pDVR1->IsEndFixed() != pDVR2->IsEndFixed())
449 {
450 throw Unhandled( __FILE__, __LINE__ );
451 }
452
453 // If either of the ranges ends with empty cells, it will not include those last
454 // nan values (its GetArrayLength() will be less than its GetRefRowSize().
455 // If we skip empty cells, just iterate until both ranges have elements, but if
456 // we need to iterate even over empty cells, so use the longer one.
457 // FIXME: If both ranges end with empty cells, this does not actually iterate
458 // over all empty cells.
459 const formula::DoubleVectorRefToken* loopDVR;
460 bool checkBounds;
461 if( empty == SkipEmpty )
462 {
463 loopDVR = pDVR1->GetArrayLength() < pDVR2->GetArrayLength() ? pDVR1 : pDVR2;
464 checkBounds = false;
465 }
466 else
467 {
468 loopDVR = pDVR1->GetArrayLength() > pDVR2->GetArrayLength() ? pDVR1 : pDVR2;
469 checkBounds = true;
470 }
471 GenerateDoubleVectorLoopHeader( ss, loopDVR, firstElementDiff );
472 ss << " double arg1 = ";
473 ss << vSubArguments[arg1]->GenSlidingWindowDeclRef(!checkBounds) << ";\n";
474 ss << " double arg2 = ";
475 ss << vSubArguments[arg2]->GenSlidingWindowDeclRef(!checkBounds) << ";\n";
476 switch( empty )
477 {
478 case EmptyIsZero:
479 ss << " if( isnan( arg1 ))\n";
480 ss << " arg1 = 0;\n";
481 ss << " if( isnan( arg2 ))\n";
482 ss << " arg2 = 0;\n";
483 break;
484 case EmptyIsNan:
485 break;
486 case SkipEmpty:
487 ss << " if( isnan( arg1 ) || isnan( arg2 ))\n";
488 ss << " continue;\n";
489 break;
490 }
491 ss << code;
492 ss << " }\n";
493}
494
495void SlidingFunctionBase::GenerateRangeArgElement( const char* name, int arg, const char* element,
496 SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty )
497{
498 assert( arg >= 0 && arg < int (vSubArguments.size()));
499 FormulaToken *token = vSubArguments[arg]->GetFormulaToken();
500 if( token == nullptr )
501 throw Unhandled( __FILE__, __LINE__ );
502 if(token->GetType() != formula::svDoubleVectorRef)
503 throw Unhandled( __FILE__, __LINE__ );
505 static_cast<const formula::DoubleVectorRefToken *>(token);
506 ss << " double " << name << " = NAN;\n";
507 ss << " {\n";
508 // GenSlidingWindowDeclRef() may refer to 'i' variable.
509 ss << " int i = 0;\n";
510 ss << " if( ";
511 if( !pDVR->IsStartFixed())
512 ss << "gid0 + ";
513 ss << element << " < " << pDVR->GetArrayLength() << " )\n";
514 ss << " " << name << " = " << vSubArguments[arg]->GenSlidingWindowDeclRef(true) << ";\n";
515 ss << " }\n";
516 switch( empty )
517 {
518 case EmptyIsZero:
519 ss << " if( isnan( " << name << " ))\n";
520 ss << " " << name << " = 0;\n";
521 break;
522 case EmptyIsNan:
523 break;
524 case SkipEmpty:
525 abort();
526 break;
527 }
528}
529
531 const formula::DoubleVectorRefToken* pDVR, const char* firstElementDiff )
532{
533 size_t nCurWindowSize = pDVR->GetRefRowSize();
534 std::string startDiff;
535 if( firstElementDiff )
536 startDiff = std::string( " + " ) + firstElementDiff;
537 ss << " for (int i = ";
538 if (!pDVR->IsStartFixed() && pDVR->IsEndFixed())
539 {
540 ss << "gid0" << startDiff << "; i < " << pDVR->GetArrayLength();
541 ss << " && i < " << nCurWindowSize << "; i++)\n";
542 ss << " {\n";
543 }
544 else if (pDVR->IsStartFixed() && !pDVR->IsEndFixed())
545 {
546 ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength();
547 ss << " && i < gid0+" << nCurWindowSize << "; i++)\n";
548 ss << " {\n";
549 }
550 else if (!pDVR->IsStartFixed() && !pDVR->IsEndFixed())
551 {
552 ss << "0" << startDiff << "; i + gid0 < " << pDVR->GetArrayLength();
553 ss << " && i < " << nCurWindowSize << "; i++)\n";
554 ss << " {\n";
555 }
556 else
557 {
558 ss << "0" << startDiff << "; i < " << pDVR->GetArrayLength() << "; i++)\n";
559 ss << " {\n";
560 }
561}
562
563void SlidingFunctionBase::GenerateFunctionDeclaration( const std::string& sSymName,
564 SubArguments& vSubArguments, outputstream& ss )
565{
566 ss << "\ndouble " << sSymName;
567 ss << "_"<< BinFuncName() <<"(";
568 for (size_t i = 0; i < vSubArguments.size(); i++)
569 {
570 if (i)
571 ss << ", ";
572 vSubArguments[i]->GenSlidingWindowDecl(ss);
573 }
574 ss << ")\n";
575}
576
578 outputstream& ss, const std::string& sSymName, SubArguments& vSubArguments )
579{
580 GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
581 ss << "{\n\t";
582 ss << "double tmp = " << GetBottom() << ";\n\t";
583 ss << "int gid0 = get_global_id(0);\n\t";
584 ss << "tmp = ";
585 std::vector<std::string> argVector;
586 for (size_t i = 0; i < vSubArguments.size(); i++)
587 argVector.push_back(vSubArguments[i]->GenSlidingWindowDeclRef());
588 ss << Gen(argVector);
589 ss << ";\n\t";
590 ss << "return tmp;\n";
591 ss << "}";
592}
593
595 outputstream& ss, const SubArguments& vSubArguments )
596{
597 for (size_t i = 0; i < vSubArguments.size(); i++)
598 {
599 ss << " double tmp";
600 ss << i;
601 ss << ";\n";
602 }
603}
604
606 SubArguments& vSubArguments, int argumentNum )
607{
608 int i = argumentNum;
609 if (vSubArguments[i]->GetFormulaToken()->GetType() ==
611 {
612 const formula::SingleVectorRefToken* pTmpDVR1 =
613 static_cast<const formula::SingleVectorRefToken*>(vSubArguments[i]->GetFormulaToken());
614 ss << " if(singleIndex>=";
615 ss << pTmpDVR1->GetArrayLength();
616 ss << " ||";
617 ss << "isnan(";
618 ss << vSubArguments[i]->GenSlidingWindowDeclRef(true);
619 ss << "))\n";
620 ss << " tmp";
621 ss << i;
622 ss << "=0;\n else \n";
623 ss << " tmp";
624 ss << i;
625 ss << "=";
626 ss << vSubArguments[i]->GenSlidingWindowDeclRef(true);
627 ss << ";\n";
628 }
629 if (vSubArguments[i]->GetFormulaToken()->GetType() ==
631 {
632 const formula::DoubleVectorRefToken* pTmpDVR2 =
633 static_cast<const formula::DoubleVectorRefToken*>(vSubArguments[i]->GetFormulaToken());
634 ss << " if(doubleIndex>=";
635 ss << pTmpDVR2->GetArrayLength();
636 ss << " ||";
637 ss << "isnan(";
638 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
639 ss << "))\n";
640 ss << " tmp";
641 ss << i;
642 ss << "=0;\n else \n";
643 ss << " tmp";
644 ss << i;
645 ss << "=";
646 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
647 ss << ";\n";
648 }
649 if (vSubArguments[i]->GetFormulaToken()->GetType() == formula::svDouble ||
650 vSubArguments[i]->GetFormulaToken()->GetOpCode() != ocPush)
651 {
652 ss << " if(";
653 ss << "isnan(";
654 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
655 ss << "))\n";
656 ss << " tmp";
657 ss << i;
658 ss << "=0;\n else \n";
659 ss << " tmp";
660 ss << i;
661 ss << "=";
662 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
663 ss << ";\n";
664
665 }
666
667}
668
670 SubArguments& vSubArguments, int argumentNum, const std::string& p )
671{
672 int i = argumentNum;
673 if (vSubArguments[i]->GetFormulaToken()->GetType() == formula::svDouble)
674 {
675 ss << " tmp";
676 ss << i;
677 ss << "=";
678 vSubArguments[i]->GenDeclRef(ss);
679 ss << ";\n";
680 return;
681 }
682
683 ss << " tmp";
684 ss << i;
685 ss << "= fsum(";
686 vSubArguments[i]->GenDeclRef(ss);
687 if (vSubArguments[i]->GetFormulaToken()->GetType() ==
689 ss << "[" << p.c_str() << "]";
690 else if (vSubArguments[i]->GetFormulaToken()->GetType() ==
692 ss << "[get_group_id(1)]";
693 ss << ", 0);\n";
694}
695
697 outputstream& ss, SubArguments& vSubArguments )
698{
699 ss << " int k = gid0;\n";
700 for (size_t i = 0; i < vSubArguments.size(); i++)
701 {
702 CheckSubArgumentIsNan(ss, vSubArguments, i);
703 }
704}
705
707 const outputstream& unrollstr, const formula::DoubleVectorRefToken* pCurDVR,
708 int nCurWindowSize )
709{
710 int unrollSize = 16;
711 if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
712 {
713 ss << " loop = (" << nCurWindowSize << " - gid0)/";
714 ss << unrollSize << ";\n";
715 }
716 else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
717 {
718 ss << " loop = (" << nCurWindowSize << " + gid0)/";
719 ss << unrollSize << ";\n";
720
721 }
722 else
723 {
724 ss << " loop = " << nCurWindowSize << "/" << unrollSize << ";\n";
725 }
726
727 ss << " for ( int j = 0;j< loop; j++)\n";
728 ss << " {\n";
729 ss << " int i = ";
730 if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
731 {
732 ss << "gid0 + j * " << unrollSize << ";\n";
733 }
734 else
735 {
736 ss << "j * " << unrollSize << ";\n";
737 }
738
739 if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
740 {
741 ss << " int doubleIndex = i+gid0;\n";
742 }
743 else
744 {
745 ss << " int doubleIndex = i;\n";
746 }
747
748 for (int j = 0; j < unrollSize; j++)
749 {
750 ss << unrollstr.str();
751 ss << "i++;\n";
752 ss << "doubleIndex++;\n";
753 }
754 ss << " }\n";
755 ss << " for (int i = ";
756 if (!pCurDVR->IsStartFixed() && pCurDVR->IsEndFixed())
757 {
758 ss << "gid0 + loop *" << unrollSize << "; i < ";
759 ss << nCurWindowSize << "; i++)\n";
760 }
761 else if (pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
762 {
763 ss << "0 + loop *" << unrollSize << "; i < gid0+";
764 ss << nCurWindowSize << "; i++)\n";
765 }
766 else
767 {
768 ss << "0 + loop *" << unrollSize << "; i < ";
769 ss << nCurWindowSize << "; i++)\n";
770 }
771 ss << " {\n";
772 if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
773 {
774 ss << " int doubleIndex = i+gid0;\n";
775 }
776 else
777 {
778 ss << " int doubleIndex = i;\n";
779 }
780 ss << unrollstr.str();
781 ss << " }\n";
782}
783
785 const std::string& sSymName, SubArguments& vSubArguments )
786{
787 GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
788 ss << "{\n";
789 ss << "double tmp = " << GetBottom() << ";\n";
790 ss << "int gid0 = get_global_id(0);\n";
791 if (isAverage() || isMinOrMax())
792 ss << "int nCount = 0;\n";
793 ss << "double tmpBottom;\n";
794 unsigned i = vSubArguments.size();
795 while (i--)
796 {
797 if (NumericRange* NR = dynamic_cast<NumericRange*>(vSubArguments[i].get()))
798 {
799 bool needBody;
800 NR->GenReductionLoopHeader(ss, needBody);
801 if (!needBody)
802 continue;
803 }
804 else if (NumericRangeStringsToZero* NRS = dynamic_cast<NumericRangeStringsToZero*>(vSubArguments[i].get()))
805 {
806 bool needBody;
807 NRS->GenReductionLoopHeader(ss, needBody);
808 if (!needBody)
809 continue;
810 }
811 else if (ParallelNumericRange* PNR = dynamic_cast<ParallelNumericRange*>(vSubArguments[i].get()))
812 {
813 //did not handle yet
814 bool bNeedBody = false;
815 PNR->GenReductionLoopHeader(ss, mnResultSize, bNeedBody);
816 if (!bNeedBody)
817 continue;
818 }
819 else if (StringRange* SR = dynamic_cast<StringRange*>(vSubArguments[i].get()))
820 {
821 //did not handle yet
822 bool needBody;
823 SR->GenReductionLoopHeader(ss, needBody);
824 if (!needBody)
825 continue;
826 }
827 else
828 {
829 FormulaToken* pCur = vSubArguments[i]->GetFormulaToken();
830 if( pCur == nullptr || pCur->GetType() == formula::svDoubleVectorRef )
831 {
832 throw Unhandled(__FILE__, __LINE__);
833 }
834 ss << "{\n";
835 }
836 if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode())
837 {
838 bool bNanHandled = HandleNaNArgument(ss, i, vSubArguments);
839
840 ss << " tmpBottom = " << GetBottom() << ";\n";
841
842 if (!bNanHandled)
843 {
844 ss << " if (isnan(";
845 ss << vSubArguments[i]->GenSlidingWindowDeclRef();
846 ss << "))\n";
847 if (ZeroReturnZero())
848 ss << " return 0;\n";
849 else
850 {
851 ss << " tmp = ";
852 ss << Gen2("tmpBottom", "tmp") << ";\n";
853 }
854 ss << " else\n";
855 }
856 ss << " tmp = ";
857 ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
858 ss << ";\n";
859 }
860 else
861 {
862 ss << " tmp = ";
863 ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
864 ss << ";\n";
865 }
866 ss << "}\n";
867 }
868 if (isAverage())
869 ss <<
870 "if (nCount==0)\n"
871 " return CreateDoubleError(DivisionByZero);\n";
872 else if (isMinOrMax())
873 ss <<
874 "if (nCount==0)\n"
875 " return 0;\n";
876 ss << "return tmp";
877 if (isAverage())
878 ss << "/(double)nCount";
879 ss << ";\n}";
880}
881
882}
883
884/* 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:669
static void CheckSubArgumentIsNan(outputstream &ss, SubArguments &vSubArguments, int argumentNum)
Definition: opbase.cxx:605
static void GenTmpVariables(outputstream &ss, const SubArguments &vSubArguments)
Definition: opbase.cxx:594
static void UnrollDoubleVector(outputstream &ss, const outputstream &unrollstr, const formula::DoubleVectorRefToken *pCurDVR, int nCurWindowSize)
Definition: opbase.cxx:706
static void CheckAllSubArgumentIsNan(outputstream &ss, SubArguments &vSubArguments)
Definition: opbase.cxx:696
(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:577
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:784
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:226
static void GenerateDoubleVectorLoopHeader(outputstream &ss, const formula::DoubleVectorRefToken *pDVR, const char *firstElementDiff)
Definition: opbase.cxx:530
static void GenerateRangeArgElement(const char *name, int arg, const char *element, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty)
Definition: opbase.cxx:495
static void GenerateRangeArg(int arg, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty, const char *code)
Definition: opbase.cxx:414
void GenerateArgWithDefault(const char *name, int arg, double def, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty=EmptyIsZero)
Definition: opbase.cxx:304
void GenerateFunctionDeclaration(const std::string &sSymName, SubArguments &vSubArguments, outputstream &ss)
Definition: opbase.cxx:563
static void GenerateRangeArgPair(int arg1, int arg2, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty, const char *code, const char *firstElementDiff=nullptr)
Definition: opbase.cxx:420
static void GenerateRangeArgs(int firstArg, int lastArg, SubArguments &vSubArguments, outputstream &ss, EmptyArgType empty, const char *code)
Definition: opbase.cxx:313
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:219
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:128
virtual bool NeedParallelReduction() const override
Definition: opbase.cxx:214
virtual void GenSlidingWindowDecl(outputstream &ss) const override
When declared as input to a sliding window function.
Definition: opbase.cxx:156
virtual std::string GenSlidingWindowDeclRef(bool=false) const override
When referenced in a sliding window function.
Definition: opbase.cxx:162
virtual void GenDecl(outputstream &ss) const override
Generate declaration.
Definition: opbase.cxx:150
const std::string & GetName() const
Definition: opbase.cxx:204
virtual void DumpInlineFun(std::set< std::string > &, std::set< std::string > &) const override
Definition: opbase.cxx:202
cl_mem GetCLBuffer() const
Definition: opbase.cxx:209
virtual std::string DumpOpName() const override
Definition: opbase.cxx:197
virtual size_t GetWindowSize() const override
Definition: opbase.cxx:177
virtual ~VectorRef() override
Definition: opbase.cxx:139
virtual void GenSlidingWindowFunction(outputstream &) override
Definition: opbase.cxx:175
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