tdf#130857 qt weld: Implement QtInstanceWidget::strip_mnemonic
[LibreOffice.git] / sc / source / core / opencl / opbase.hxx
blob3b5991275b179ab728a734deb92f0880bdb2f682
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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 */
10 #pragma once
12 #include <clew/clew.h>
13 #include <formula/token.hxx>
14 #include <formula/types.hxx>
15 #include <formula/vectortoken.hxx>
16 #include <opencl/OpenCLZone.hxx>
17 #include <sal/log.hxx>
18 #include <memory>
19 #include <set>
20 #include <vector>
21 #include "utils.hxx"
23 struct ScCalcConfig;
25 namespace sc::opencl {
27 // FIXME: The idea that somebody would bother to (now and then? once a year? once a month?) manually
28 // edit a source file and change the value of some #defined constant and run some ill-defined
29 // "correctness test" is of course ludicrous. Either things are checked in normal unit tests, in
30 // every 'make check', or not at all. The below comments are ridiculous.
32 constexpr auto REDUCE_THRESHOLD = 201; // set to 4 for correctness testing. priority 1
33 constexpr auto UNROLLING_FACTOR = 16; // set to 4 for correctness testing (if no reduce)
36 class FormulaTreeNode;
38 /// Exceptions
40 /// Failed in parsing
41 class UnhandledToken
43 public:
44 UnhandledToken( const char* m, std::string fn, int ln );
46 std::string mMessage;
47 std::string mFile;
48 int mLineNumber;
51 /// Failed in marshaling
52 class OpenCLError
54 public:
55 OpenCLError( std::string function, cl_int error, std::string file, int line );
57 std::string mFunction;
58 cl_int mError;
59 std::string mFile;
60 int mLineNumber;
63 /// Inconsistent state
64 class Unhandled
66 public:
67 Unhandled( std::string fn, int ln );
69 std::string mFile;
70 int mLineNumber;
73 class InvalidParameterCount
75 public:
76 InvalidParameterCount( int parameterCount, std::string file, int ln );
78 int mParameterCount;
79 std::string mFile;
80 int const mLineNumber;
83 // Helper macros to be used in code emitting OpenCL code for Calc functions.
84 // Require the vSubArguments parameter.
85 #define CHECK_PARAMETER_COUNT(min, max) \
86 do { \
87 const int count = vSubArguments.size(); \
88 if( count < ( min ) || count > ( max )) \
89 throw InvalidParameterCount( count, __FILE__, __LINE__ ); \
90 } while( false )
91 #define CHECK_PARAMETER_COUNT_MIN(min) \
92 do { \
93 const int count = vSubArguments.size(); \
94 if( count < ( min )) \
95 throw InvalidParameterCount( count, __FILE__, __LINE__ ); \
96 } while( false )
97 #define CHECK_PARAMETER_DOUBLEVECTORREF(arg) \
98 do { \
99 formula::FormulaToken *token = vSubArguments[arg]->GetFormulaToken(); \
100 if (token == nullptr || token->GetType() != formula::svDoubleVectorRef) \
101 throw Unhandled(__FILE__, __LINE__); \
102 } while( false )
104 typedef std::shared_ptr<FormulaTreeNode> FormulaTreeNodeRef;
106 class FormulaTreeNode
108 public:
109 explicit FormulaTreeNode( const formula::FormulaToken* ft ) : mpCurrentFormula(ft)
111 Children.reserve(8);
113 std::vector<FormulaTreeNodeRef> Children;
114 formula::FormulaToken* GetFormulaToken() const
116 return const_cast<formula::FormulaToken*>(mpCurrentFormula.get());
119 private:
120 formula::FormulaConstTokenRef mpCurrentFormula;
123 /// (Partially) abstract base class for an operand
124 class DynamicKernelArgument
126 public:
127 /// delete copy constructor
128 DynamicKernelArgument( const DynamicKernelArgument& ) = delete;
130 /// delete copy-assignment operator
131 const DynamicKernelArgument& operator=( const DynamicKernelArgument& ) = delete;
133 DynamicKernelArgument( const ScCalcConfig& config, std::string s, FormulaTreeNodeRef ft );
134 virtual ~DynamicKernelArgument() {}
136 /// Generate declaration
137 virtual void GenDecl( outputstream& ss ) const = 0;
139 /// When declared as input to a sliding window function
140 virtual void GenSlidingWindowDecl( outputstream& ss ) const = 0;
142 /// When referenced in a sliding window function
143 virtual std::string GenSlidingWindowDeclRef( bool = false ) const = 0;
145 /// Create buffer and pass the buffer to a given kernel
146 virtual size_t Marshal( cl_kernel, int, int, cl_program ) = 0;
148 virtual size_t GetWindowSize() const = 0;
150 /// When Mix, it will be called
151 virtual std::string GenDoubleSlidingWindowDeclRef( bool = false ) const;
153 /// When Mix, it will be called
154 virtual std::string GenStringSlidingWindowDeclRef( bool = false ) const;
156 /// Will generate value saying whether the value is a string.
157 virtual std::string GenIsString( bool = false ) const { return "false"; }
159 /// Generate use/references to the argument
160 virtual void GenDeclRef( outputstream& ss ) const;
162 virtual void GenSlidingWindowFunction( outputstream& );
163 formula::FormulaToken* GetFormulaToken() const;
164 virtual std::string DumpOpName() const;
165 virtual void DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const;
166 const std::string& GetName() const;
167 virtual bool NeedParallelReduction() const;
168 /// If there's actually no argument, i.e. it expands to no code.
169 virtual bool IsEmpty() const { return false; }
171 static void ClearStringIds();
173 protected:
174 const ScCalcConfig& mCalcConfig;
175 std::string mSymName;
176 FormulaTreeNodeRef mFormulaTree;
177 static int GetStringId( const rtl_uString* string );
180 typedef std::shared_ptr<DynamicKernelArgument> DynamicKernelArgumentRef;
182 /// Holds an input (read-only) argument reference to a SingleVectorRef.
183 /// or a DoubleVectorRef for non-sliding-window argument of complex functions
184 /// like SumOfProduct
185 /// In most of the cases the argument is introduced
186 /// by a Push operation in the given RPN.
187 class VectorRef : public DynamicKernelArgument
189 public:
190 VectorRef( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int index = 0 );
191 virtual ~VectorRef() override;
193 /// Generate declaration
194 virtual void GenDecl( outputstream& ss ) const override;
195 /// When declared as input to a sliding window function
196 virtual void GenSlidingWindowDecl( outputstream& ss ) const override;
198 /// When referenced in a sliding window function
199 virtual std::string GenSlidingWindowDeclRef( bool = false ) const override;
201 /// Create buffer and pass the buffer to a given kernel
202 virtual size_t Marshal( cl_kernel, int, int, cl_program ) override;
204 virtual void GenSlidingWindowFunction( outputstream& ) override;
205 virtual size_t GetWindowSize() const override;
206 virtual std::string DumpOpName() const override;
207 virtual void DumpInlineFun( std::set<std::string>&, std::set<std::string>& ) const override;
208 const std::string& GetName() const;
209 cl_mem GetCLBuffer() const;
210 virtual bool NeedParallelReduction() const override;
212 protected:
213 // Used by marshaling
214 cl_mem mpClmem;
215 // index in multiple double vector refs that have multiple ranges
216 const int mnIndex;
217 // Makes Marshall convert strings to 0 values.
218 bool forceStringsToZero;
219 // Used for storing when the data needs to be modified before sending to OpenCL.
220 std::vector< double > dataBuffer;
223 // Sets VectorRef::forceStringsToZero.
224 class VectorRefStringsToZero : public VectorRef
226 public:
227 VectorRefStringsToZero( const ScCalcConfig& config, const std::string& s, const FormulaTreeNodeRef& ft, int index = 0 );
230 /// A vector of strings
231 class DynamicKernelStringArgument : public VectorRef
233 public:
234 DynamicKernelStringArgument( const ScCalcConfig& config, const std::string& s,
235 const FormulaTreeNodeRef& ft, int index = 0 ) :
236 VectorRef(config, s, ft, index) { }
238 virtual void GenSlidingWindowFunction( outputstream& ) override { }
239 /// Generate declaration
240 virtual void GenDecl( outputstream& ss ) const override
242 ss << "__global double *" << mSymName;
244 virtual void GenSlidingWindowDecl( outputstream& ss ) const override
246 DynamicKernelStringArgument::GenDecl(ss);
248 virtual std::string GenIsString( bool = false ) const override;
249 virtual size_t Marshal( cl_kernel, int, int, cl_program ) override;
252 /// Arguments that are actually compile-time constants
253 class DynamicKernelConstantArgument : public DynamicKernelArgument
255 public:
256 DynamicKernelConstantArgument( const ScCalcConfig& config, const std::string& s,
257 const FormulaTreeNodeRef& ft ) :
258 DynamicKernelArgument(config, s, ft) { }
259 /// Generate declaration
260 virtual void GenDecl( outputstream& ss ) const override
262 ss << "double " << mSymName;
264 virtual void GenDeclRef( outputstream& ss ) const override
266 ss << mSymName;
268 virtual void GenSlidingWindowDecl( outputstream& ss ) const override
270 GenDecl(ss);
272 virtual std::string GenSlidingWindowDeclRef( bool = false ) const override
274 if (GetFormulaToken()->GetType() != formula::svDouble)
275 throw Unhandled(__FILE__, __LINE__);
276 return mSymName;
278 virtual size_t GetWindowSize() const override
280 return 1;
282 virtual double GetDouble() const
284 formula::FormulaToken* Tok = GetFormulaToken();
285 if (Tok->GetType() != formula::svDouble)
286 throw Unhandled(__FILE__, __LINE__);
287 return Tok->GetDouble();
289 /// Create buffer and pass the buffer to a given kernel
290 virtual size_t Marshal( cl_kernel k, int argno, int, cl_program ) override
292 OpenCLZone zone;
293 double tmp = GetDouble();
294 // Pass the scalar result back to the rest of the formula kernel
295 SAL_INFO("sc.opencl", "Kernel " << k << " arg " << argno << ": double: " << preciseFloat( tmp ));
296 cl_int err = clSetKernelArg(k, argno, sizeof(double), static_cast<void*>(&tmp));
297 if (CL_SUCCESS != err)
298 throw OpenCLError("clSetKernelArg", err, __FILE__, __LINE__);
299 return 1;
303 // Constant 0 argument when a string is forced to zero.
304 class DynamicKernelStringToZeroArgument : public DynamicKernelConstantArgument
306 public:
307 DynamicKernelStringToZeroArgument( const ScCalcConfig& config, const std::string& s,
308 const FormulaTreeNodeRef& ft ) :
309 DynamicKernelConstantArgument(config, s, ft) { }
310 virtual std::string GenSlidingWindowDeclRef( bool = false ) const override
312 return mSymName;
314 virtual double GetDouble() const override { return 0; }
318 /// Abstract class for code generation
319 class OpBase
321 public:
322 // FIXME: What exactly is this? It seems to be a starting value for some calculations
323 // (1 for OpMul, MAXFLOAT for OpMin), but it's often used pointlessly and sometimes
324 // even incorrectly (default value for when the cell is empty).
325 virtual std::string GetBottom() { return "";};
326 virtual std::string Gen2( const std::string&/*lhs*/,
327 const std::string&/*rhs*/ ) const { return "";}
328 static std::string Gen( std::vector<std::string>& /*argVector*/ ) { return "";};
329 virtual std::string BinFuncName() const { return "";};
330 virtual void BinInlineFun( std::set<std::string>&,
331 std::set<std::string>& ) { }
332 virtual bool takeString() const = 0;
333 virtual bool takeNumeric() const = 0;
334 // Whether DoubleRef containing more than one column is handled properly.
335 virtual bool canHandleMultiVector() const { return false; }
336 //Continue process 'Zero' or Not(like OpMul, not continue process when meet
337 // 'Zero'
338 virtual bool ZeroReturnZero() { return false;}
339 // For use with COUNTA() etc, input strings will be converted to 0 in data.
340 virtual bool forceStringsToZero() const { return false; }
341 virtual ~OpBase() { }
344 class SlidingFunctionBase : public OpBase
346 public:
347 typedef std::vector<DynamicKernelArgumentRef> SubArguments;
348 virtual void GenSlidingWindowFunction( outputstream&,
349 const std::string&, SubArguments& ) = 0;
350 protected:
351 // This enum controls how the generated code will handle empty cells in ranges.
352 enum EmptyArgType
354 EmptyIsZero, // empty cells become 0.0
355 EmptyIsNan, // empty cells become NAN, use isnan() to check in code
356 SkipEmpty // empty cells will be skipped
358 // This enum controls whether the generated code will also include variable
359 // <name>_is_string that will be set depending on the value type.
360 enum GenerateArgTypeType
362 DoNotGenerateArgType,
363 GenerateArgType
365 void GenerateFunctionDeclaration( const std::string& sSymName,
366 SubArguments& vSubArguments, outputstream& ss );
367 // Generate code for "double <name> = <value>;" from vSubArguments, svDoubleVectorRef is not supported.
368 void GenerateArg( const char* name, int arg, SubArguments& vSubArguments, outputstream& ss,
369 EmptyArgType empty = EmptyIsZero, GenerateArgTypeType generateType = DoNotGenerateArgType );
370 // overload, variable will be named "arg<arg>"
371 void GenerateArg( int arg, SubArguments& vSubArguments, outputstream& ss,
372 EmptyArgType empty = EmptyIsZero, GenerateArgTypeType generateType = DoNotGenerateArgType );
373 // generate code for "double <name> = <value>;" from vSubArguments, if it exists,
374 // otherwise set to <def>
375 void GenerateArgWithDefault( const char* name, int arg, double def, SubArguments& vSubArguments,
376 outputstream& ss, EmptyArgType empty = EmptyIsZero );
377 // Generate code that will handle all arguments firstArg-lastArg (zero-based, inclusive),
378 // including range arguments (svDoubleVectorRef) and each value will be processed by 'code',
379 // value will be named "arg".
380 static void GenerateRangeArgs( int firstArg, int lastArg, SubArguments& vSubArguments,
381 outputstream& ss, EmptyArgType empty, const char* code );
382 // overload, handle all arguments
383 static void GenerateRangeArgs( SubArguments& vSubArguments, outputstream& ss,
384 EmptyArgType empty, const char* code );
385 // overload, handle the given argument
386 static void GenerateRangeArg( int arg, SubArguments& vSubArguments, outputstream& ss,
387 EmptyArgType empty, const char* code );
388 // Overload.
389 // Both arguments must be svDoubleRef of the same size.
390 // If 'firstElementDiff' is set, the loop start will be offset by '+ firstElementDiff'.
391 void GenerateRangeArg( int arg1, int arg2, SubArguments& vSubArguments,
392 outputstream& ss, EmptyArgType empty, const char* code, const char* firstElementDiff = nullptr );
393 // Generate code that will handle the given two arguments in one loop where n-th element of arg1 and arg2
394 // will be handled at the same time, named 'arg1' and 'arg2'.
395 // Both arguments must be svDoubleRef of the same size.
396 // If 'firstElementDiff' is set, the loop start will be offset by '+ firstElementDiff'.
397 static void GenerateRangeArgPair( int arg1, int arg2, SubArguments& vSubArguments,
398 outputstream& ss, EmptyArgType empty, const char* code, const char* firstElementDiff = nullptr );
399 // Generate code for "double <name> = range[<element>]" from vSubArguments.
400 // The argument must be svDoubleRef.
401 static void GenerateRangeArgElement( const char* name, int arg, const char* element,
402 SubArguments& vSubArguments, outputstream& ss, EmptyArgType empty );
403 static void GenerateDoubleVectorLoopHeader( outputstream& ss,
404 const formula::DoubleVectorRefToken* pDVR, const char* firstElementDiff );
407 class Normal : public SlidingFunctionBase
409 public:
410 virtual void GenSlidingWindowFunction( outputstream& ss,
411 const std::string& sSymName, SubArguments& vSubArguments ) override;
412 virtual bool takeString() const override { return false; }
413 virtual bool takeNumeric() const override { return true; }
416 class CheckVariables : public Normal
418 public:
419 static void GenTmpVariables( outputstream& ss, const SubArguments& vSubArguments );
420 static void CheckSubArgumentIsNan( outputstream& ss,
421 SubArguments& vSubArguments, int argumentNum );
422 static void CheckAllSubArgumentIsNan( outputstream& ss,
423 SubArguments& vSubArguments );
424 // only check isnan
425 static void CheckSubArgumentIsNan2( outputstream& ss,
426 SubArguments& vSubArguments, int argumentNum, const std::string& p );
427 static void UnrollDoubleVector( outputstream& ss,
428 const outputstream& unrollstr, const formula::DoubleVectorRefToken* pCurDVR,
429 int nCurWindowSize );
432 class OpAverage;
433 class OpCount;
435 /// Handling a Double Vector that is used as a sliding window input
436 /// to either a sliding window average or sum-of-products
437 /// Generate a sequential loop for reductions
438 template<class Base>
439 class DynamicKernelSlidingArgument : public Base
441 public:
442 DynamicKernelSlidingArgument(const ScCalcConfig& config, const std::string& s,
443 const FormulaTreeNodeRef& ft,
444 std::shared_ptr<SlidingFunctionBase> CodeGen, int index);
445 // Should only be called by SumIfs. Yikes!
446 virtual bool NeedParallelReduction() const;
447 virtual void GenSlidingWindowFunction( outputstream& ) { }
449 std::string GenSlidingWindowDeclRef( bool nested = false ) const;
450 /// Controls how the elements in the DoubleVectorRef are traversed
451 size_t GenReductionLoopHeader( outputstream& ss, bool& needBody );
453 size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
455 size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
457 bool GetStartFixed() const { return bIsStartFixed; }
459 bool GetEndFixed() const { return bIsEndFixed; }
461 protected:
462 bool bIsStartFixed, bIsEndFixed;
463 const formula::DoubleVectorRefToken* mpDVR;
464 // from parent nodes
465 std::shared_ptr<SlidingFunctionBase> mpCodeGen;
468 /// Handling a Double Vector that is used as a sliding window input
469 /// Performs parallel reduction based on given operator
470 template<class Base>
471 class ParallelReductionVectorRef : public Base
473 public:
474 ParallelReductionVectorRef(const ScCalcConfig& config, const std::string& s,
475 const FormulaTreeNodeRef& ft,
476 std::shared_ptr<SlidingFunctionBase> CodeGen, int index);
477 ~ParallelReductionVectorRef();
479 /// Emit the definition for the auxiliary reduction kernel
480 virtual void GenSlidingWindowFunction( outputstream& ss );
481 virtual std::string GenSlidingWindowDeclRef( bool ) const;
482 /// Controls how the elements in the DoubleVectorRef are traversed
483 size_t GenReductionLoopHeader( outputstream& ss, int nResultSize, bool& needBody );
484 virtual size_t Marshal( cl_kernel k, int argno, int w, cl_program mpProgram );
485 size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
486 size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
487 bool GetStartFixed() const { return bIsStartFixed; }
488 bool GetEndFixed() const { return bIsEndFixed; }
490 protected:
491 bool bIsStartFixed, bIsEndFixed;
492 const formula::DoubleVectorRefToken* mpDVR;
493 // from parent nodes
494 std::shared_ptr<SlidingFunctionBase> mpCodeGen;
495 // controls whether to invoke the reduction kernel during marshaling or not
496 cl_mem mpClmem2;
499 class Reduction : public SlidingFunctionBase
501 int const mnResultSize;
502 public:
503 explicit Reduction(int nResultSize) : mnResultSize(nResultSize) {}
505 typedef DynamicKernelSlidingArgument<VectorRef> NumericRange;
506 typedef DynamicKernelSlidingArgument<VectorRefStringsToZero> NumericRangeStringsToZero;
507 typedef DynamicKernelSlidingArgument<DynamicKernelStringArgument> StringRange;
508 typedef ParallelReductionVectorRef<VectorRef> ParallelNumericRange;
510 virtual bool HandleNaNArgument( outputstream&, unsigned, SubArguments& ) const
512 return false;
515 virtual void GenSlidingWindowFunction( outputstream& ss,
516 const std::string& sSymName, SubArguments& vSubArguments ) override;
517 virtual bool isAverage() const { return false; }
518 virtual bool isMinOrMax() const { return false; }
519 virtual bool takeString() const override { return false; }
520 virtual bool takeNumeric() const override { return true; }
525 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */