move code out of formulagroupcl.cxx to op_math* and opbase*

formulagroupcl.cxx is already large enough, move away code that
implements some operations and also move some type declarations
to a header.

Change-Id: I28fe59275f4fb89c3e530d77b08e7f2fcad02781
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139971
Tested-by: Jenkins
Reviewed-by: Luboš Luňák <l.lunak@collabora.com>
This commit is contained in:
Luboš Luňák
2022-09-19 17:29:58 +02:00
parent b0ad8a9175
commit bbc07c964e
5 changed files with 1010 additions and 910 deletions
File diff suppressed because it is too large Load Diff
+399
View File
@@ -217,6 +217,15 @@ void OpLn::GenerateCode( outputstream& ss ) const
ss << " return log1p(arg0-1);\n";
}
void OpInt::BinInlineFun(std::set<std::string>& decls,
std::set<std::string>& funs)
{
decls.insert(is_representable_integerDecl);
funs.insert(is_representable_integer);
decls.insert(approx_equalDecl);
funs.insert(approx_equal);
}
void OpInt::GenerateCode( outputstream& ss ) const
{
ss << " int intTmp = (int)arg0;\n";
@@ -464,6 +473,72 @@ void OpQuotient::GenerateCode( outputstream& ss ) const
ss << " return trunc(arg0/arg1);\n";
}
void OpEqual::BinInlineFun(std::set<std::string>& decls,
std::set<std::string>& funs)
{
decls.insert(is_representable_integerDecl);
funs.insert(is_representable_integer);
decls.insert(approx_equalDecl);
funs.insert(approx_equal);
}
void OpEqual::GenerateCode( outputstream& ss ) const
{
ss << " return approx_equal( arg0, arg1 );\n";
}
void OpNotEqual::BinInlineFun(std::set<std::string>& decls,
std::set<std::string>& funs)
{
decls.insert(is_representable_integerDecl);
funs.insert(is_representable_integer);
decls.insert(approx_equalDecl);
funs.insert(approx_equal);
}
void OpNotEqual::GenerateCode( outputstream& ss ) const
{
ss << " return !approx_equal( arg0, arg1 );\n";
}
void OpLessEqual::BinInlineFun(std::set<std::string>& decls,
std::set<std::string>& funs)
{
decls.insert(is_representable_integerDecl);
funs.insert(is_representable_integer);
decls.insert(approx_equalDecl);
funs.insert(approx_equal);
}
void OpLessEqual::GenerateCode( outputstream& ss ) const
{
ss << " return approx_equal( arg0, arg1 ) || arg0 <= arg1;\n";
}
void OpLess::GenerateCode( outputstream& ss ) const
{
ss << " return arg0 < arg1;\n";
}
void OpGreaterEqual::BinInlineFun(std::set<std::string>& decls,
std::set<std::string>& funs)
{
decls.insert(is_representable_integerDecl);
funs.insert(is_representable_integer);
decls.insert(approx_equalDecl);
funs.insert(approx_equal);
}
void OpGreaterEqual::GenerateCode( outputstream& ss ) const
{
ss << " return approx_equal( arg0, arg1 ) || arg0 >= arg1;\n";
}
void OpGreater::GenerateCode( outputstream& ss ) const
{
ss << " return arg0 > arg1;\n";
}
void OpLog::GenSlidingWindowFunction(outputstream &ss,
const std::string &sSymName, SubArguments &vSubArguments)
{
@@ -1584,6 +1659,330 @@ void OpSeriesSum::GenSlidingWindowFunction(outputstream &ss,
ss << " return res;\n";
ss << "}";
}
void SumOfProduct::GenSlidingWindowFunction( outputstream& ss,
const std::string& sSymName, SubArguments& vSubArguments )
{
size_t nCurWindowSize = 0;
FormulaToken* tmpCur = nullptr;
const formula::DoubleVectorRefToken* pCurDVR = nullptr;
GenerateFunctionDeclaration( sSymName, vSubArguments, ss );
ss << "{\n";
for (size_t i = 0; i < vSubArguments.size(); i++)
{
size_t nCurChildWindowSize = vSubArguments[i]->GetWindowSize();
nCurWindowSize = (nCurWindowSize < nCurChildWindowSize) ?
nCurChildWindowSize : nCurWindowSize;
tmpCur = vSubArguments[i]->GetFormulaToken();
if (ocPush == tmpCur->GetOpCode())
{
pCurDVR = static_cast<const formula::DoubleVectorRefToken*>(tmpCur);
if (pCurDVR->IsStartFixed() != pCurDVR->IsEndFixed())
throw Unhandled(__FILE__, __LINE__);
}
}
ss << " double tmp = 0.0;\n";
ss << " int gid0 = get_global_id(0);\n";
ss << "\tint i;\n\t";
ss << "int currentCount0;\n";
for (size_t i = 0; i < vSubArguments.size() - 1; i++)
ss << "int currentCount" << i + 1 << ";\n";
outputstream temp3, temp4;
int outLoopSize = UNROLLING_FACTOR;
if (nCurWindowSize / outLoopSize != 0)
{
ss << "for(int outLoop=0; outLoop<" <<
nCurWindowSize / outLoopSize << "; outLoop++){\n\t";
for (int count = 0; count < outLoopSize; count++)
{
ss << "i = outLoop*" << outLoopSize << "+" << count << ";\n";
if (count == 0)
{
for (size_t i = 0; i < vSubArguments.size(); i++)
{
tmpCur = vSubArguments[i]->GetFormulaToken();
if (ocPush == tmpCur->GetOpCode())
{
pCurDVR = static_cast<const formula::DoubleVectorRefToken*>(tmpCur);
if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
{
temp3 << " currentCount";
temp3 << i;
temp3 << " =i+gid0+1;\n";
}
else
{
temp3 << " currentCount";
temp3 << i;
temp3 << " =i+1;\n";
}
}
}
temp3 << "tmp = fsum(";
for (size_t i = 0; i < vSubArguments.size(); i++)
{
if (i)
temp3 << "*";
if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode())
{
temp3 << "(";
temp3 << "(currentCount";
temp3 << i;
temp3 << ">";
if (vSubArguments[i]->GetFormulaToken()->GetType() ==
formula::svSingleVectorRef)
{
const formula::SingleVectorRefToken* pSVR =
static_cast<const formula::SingleVectorRefToken*>
(vSubArguments[i]->GetFormulaToken());
temp3 << pSVR->GetArrayLength();
temp3 << ")||isnan(" << vSubArguments[i]
->GenSlidingWindowDeclRef();
temp3 << ")?0:";
temp3 << vSubArguments[i]->GenSlidingWindowDeclRef();
temp3 << ")";
}
else if (vSubArguments[i]->GetFormulaToken()->GetType() ==
formula::svDoubleVectorRef)
{
const formula::DoubleVectorRefToken* pSVR =
static_cast<const formula::DoubleVectorRefToken*>
(vSubArguments[i]->GetFormulaToken());
temp3 << pSVR->GetArrayLength();
temp3 << ")||isnan(" << vSubArguments[i]
->GenSlidingWindowDeclRef(true);
temp3 << ")?0:";
temp3 << vSubArguments[i]->GenSlidingWindowDeclRef(true);
temp3 << ")";
}
}
else
temp3 << vSubArguments[i]->GenSlidingWindowDeclRef(true);
}
temp3 << ", tmp);\n\t";
}
ss << temp3.str();
}
ss << "}\n\t";
}
//The residual of mod outLoopSize
for (size_t count = nCurWindowSize / outLoopSize * outLoopSize;
count < nCurWindowSize; count++)
{
ss << "i =" << count << ";\n";
if (count == nCurWindowSize / outLoopSize * outLoopSize)
{
for (size_t i = 0; i < vSubArguments.size(); i++)
{
tmpCur = vSubArguments[i]->GetFormulaToken();
if (ocPush == tmpCur->GetOpCode())
{
pCurDVR = static_cast<const formula::DoubleVectorRefToken*>(tmpCur);
if (!pCurDVR->IsStartFixed() && !pCurDVR->IsEndFixed())
{
temp4 << " currentCount";
temp4 << i;
temp4 << " =i+gid0+1;\n";
}
else
{
temp4 << " currentCount";
temp4 << i;
temp4 << " =i+1;\n";
}
}
}
temp4 << "tmp = fsum(";
for (size_t i = 0; i < vSubArguments.size(); i++)
{
if (i)
temp4 << "*";
if (ocPush == vSubArguments[i]->GetFormulaToken()->GetOpCode())
{
temp4 << "(";
temp4 << "(currentCount";
temp4 << i;
temp4 << ">";
if (vSubArguments[i]->GetFormulaToken()->GetType() ==
formula::svSingleVectorRef)
{
const formula::SingleVectorRefToken* pSVR =
static_cast<const formula::SingleVectorRefToken*>
(vSubArguments[i]->GetFormulaToken());
temp4 << pSVR->GetArrayLength();
temp4 << ")||isnan(" << vSubArguments[i]
->GenSlidingWindowDeclRef();
temp4 << ")?0:";
temp4 << vSubArguments[i]->GenSlidingWindowDeclRef();
temp4 << ")";
}
else if (vSubArguments[i]->GetFormulaToken()->GetType() ==
formula::svDoubleVectorRef)
{
const formula::DoubleVectorRefToken* pSVR =
static_cast<const formula::DoubleVectorRefToken*>
(vSubArguments[i]->GetFormulaToken());
temp4 << pSVR->GetArrayLength();
temp4 << ")||isnan(" << vSubArguments[i]
->GenSlidingWindowDeclRef(true);
temp4 << ")?0:";
temp4 << vSubArguments[i]->GenSlidingWindowDeclRef(true);
temp4 << ")";
}
}
else
{
temp4 << vSubArguments[i]
->GenSlidingWindowDeclRef(true);
}
}
temp4 << ", tmp);\n\t";
}
ss << temp4.str();
}
ss << "return tmp;\n";
ss << "}";
}
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;
}
else if (ParallelNumericRange* PNR = dynamic_cast<ParallelNumericRange*>(vSubArguments[i].get()))
{
//did not handle yet
bool bNeedBody = false;
PNR->GenReductionLoopHeader(ss, mnResultSize, bNeedBody);
if (!bNeedBody)
continue;
}
else if (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();
assert(pCur);
assert(pCur->GetType() != formula::svDoubleVectorRef);
if (pCur->GetType() == formula::svSingleVectorRef ||
pCur->GetType() == formula::svDouble)
{
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 << "{";
ss << " tmp = ";
ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
ss << ";\n";
ss << " }\n";
ss << "}\n";
}
else
{
ss << "tmp = ";
ss << Gen2(vSubArguments[i]->GenSlidingWindowDeclRef(), "tmp");
ss << ";\n";
}
}
if (isAverage())
ss <<
"if (nCount==0)\n"
" return CreateDoubleError(DivisionByZero);\n";
else if (isMinOrMax())
ss <<
"if (nCount==0)\n"
" return 0;\n";
ss << "return tmp";
if (isAverage())
ss << "/(double)nCount";
ss << ";\n}";
}
void OpSum::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs)
{
decls.insert(is_representable_integerDecl);
funs.insert(is_representable_integer);
decls.insert(approx_equalDecl);
funs.insert(approx_equal);
decls.insert(fsum_approxDecl);
funs.insert(fsum_approx);
}
void OpAverage::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs)
{
decls.insert(fsum_countDecl);
funs.insert(fsum_count);
}
void OpSub::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs)
{
decls.insert(is_representable_integerDecl);
funs.insert(is_representable_integer);
decls.insert(approx_equalDecl);
funs.insert(approx_equal);
decls.insert(fsub_approxDecl);
funs.insert(fsub_approx);
}
void OpMin::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs)
{
decls.insert(fmin_countDecl);
funs.insert(fmin_count);
}
void OpMax::BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs)
{
decls.insert(fmax_countDecl);
funs.insert(fmax_count);
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+253
View File
@@ -34,6 +34,7 @@ class OpMathTwoArguments : public Normal
virtual void GenerateCode( outputstream& ss ) const = 0;
};
class OpCos: public OpMathOneArgument
{
public:
@@ -275,6 +276,7 @@ class OpInt: public OpMathOneArgument
public:
virtual std::string BinFuncName() const override { return "Int"; }
virtual void GenerateCode( outputstream& ss ) const override;
virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override;
};
class OpRadians: public OpMathOneArgument
@@ -501,6 +503,257 @@ public:
virtual void GenerateCode( outputstream& ss ) const override;
};
class OpEqual : public OpMathTwoArguments
{
public:
virtual void GenerateCode( outputstream& ss ) const override;
virtual std::string BinFuncName() const override { return "eq"; }
virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override;
};
class OpNotEqual : public OpMathTwoArguments
{
public:
virtual void GenerateCode( outputstream& ss ) const override;
virtual std::string BinFuncName() const override { return "neq"; }
virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override;
};
class OpLessEqual : public OpMathTwoArguments
{
public:
virtual void GenerateCode( outputstream& ss ) const override;
virtual std::string BinFuncName() const override { return "le"; }
virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override;
};
class OpLess : public OpMathTwoArguments
{
public:
virtual void GenerateCode( outputstream& ss ) const override;
virtual std::string BinFuncName() const override { return "lt"; }
};
class OpGreaterEqual : public OpMathTwoArguments
{
public:
virtual void GenerateCode( outputstream& ss ) const override;
virtual std::string BinFuncName() const override { return "ge"; }
virtual void BinInlineFun(std::set<std::string>& , std::set<std::string>& ) override;
};
class OpGreater : public OpMathTwoArguments
{
public:
virtual void GenerateCode( outputstream& ss ) const override;
virtual std::string BinFuncName() const override { return "gt"; }
};
class SumOfProduct : public SlidingFunctionBase
{
public:
virtual void GenSlidingWindowFunction( outputstream& ss,
const std::string& sSymName, SubArguments& vSubArguments ) override;
virtual bool takeString() const override { return false; }
virtual bool takeNumeric() const override { return true; }
};
class OpSumProduct : public SumOfProduct
{
public:
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
return lhs + "*" + rhs;
}
virtual std::string BinFuncName() const override { return "fsop"; }
};
class Reduction : public SlidingFunctionBase
{
int const mnResultSize;
public:
explicit Reduction(int nResultSize) : mnResultSize(nResultSize) {}
typedef DynamicKernelSlidingArgument<VectorRef> NumericRange;
typedef DynamicKernelSlidingArgument<DynamicKernelStringArgument> StringRange;
typedef ParallelReductionVectorRef<VectorRef> ParallelNumericRange;
virtual bool HandleNaNArgument( outputstream&, unsigned, SubArguments& ) const
{
return false;
}
virtual void GenSlidingWindowFunction( outputstream& ss,
const std::string& sSymName, SubArguments& vSubArguments ) override;
virtual bool isAverage() const { return false; }
virtual bool isMinOrMax() const { return false; }
virtual bool takeString() const override { return false; }
virtual bool takeNumeric() const override { return true; }
};
/// operator traits
class OpNop : public Reduction
{
public:
explicit OpNop(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "0"; }
virtual std::string Gen2( const std::string& lhs, const std::string& ) const override
{
return lhs;
}
virtual std::string BinFuncName() const override { return "nop"; }
};
class OpCount : public Reduction
{
public:
explicit OpCount(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "0"; }
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
outputstream ss;
ss << "(isnan(" << lhs << ")?" << rhs << ":" << rhs << "+1.0)";
return ss.str();
}
virtual std::string BinFuncName() const override { return "fcount"; }
virtual bool canHandleMultiVector() const override { return true; }
};
class OpSum : public Reduction
{
public:
explicit OpSum(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "0"; }
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
outputstream ss;
ss << "fsum_approx((" << lhs << "),(" << rhs << "))";
return ss.str();
}
virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override;
virtual std::string BinFuncName() const override { return "fsum"; }
// All arguments are simply summed, so it doesn't matter if SvDoubleVector is split.
virtual bool canHandleMultiVector() const override { return true; }
};
class OpAverage : public Reduction
{
public:
explicit OpAverage(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "0"; }
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
outputstream ss;
ss << "fsum_count(" << lhs << "," << rhs << ", &nCount)";
return ss.str();
}
virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override;
virtual std::string BinFuncName() const override { return "average"; }
virtual bool isAverage() const override { return true; }
virtual bool canHandleMultiVector() const override { return true; }
};
class OpSub : public Reduction
{
public:
explicit OpSub(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "0"; }
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
return "fsub_approx(" + lhs + "," + rhs + ")";
}
virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override;
virtual std::string BinFuncName() const override { return "fsub"; }
};
class OpMul : public Reduction
{
public:
explicit OpMul(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "1"; }
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
return lhs + "*" + rhs;
}
virtual std::string BinFuncName() const override { return "fmul"; }
virtual bool ZeroReturnZero() override { return true; }
};
/// Technically not a reduction, but fits the framework.
class OpDiv : public Reduction
{
public:
explicit OpDiv(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "1.0"; }
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
return "(" + rhs + "==0 ? CreateDoubleError(DivisionByZero) : (" + lhs + "/" + rhs + ") )";
}
virtual std::string BinFuncName() const override { return "fdiv"; }
virtual bool HandleNaNArgument( outputstream& ss, unsigned argno, SubArguments& vSubArguments ) const override
{
if (argno == 1)
{
ss <<
"if (isnan(" << vSubArguments[argno]->GenSlidingWindowDeclRef() << ")) {\n"
" return CreateDoubleError(DivisionByZero);\n"
"}\n";
return true;
}
else if (argno == 0)
{
ss <<
"if (isnan(" << vSubArguments[argno]->GenSlidingWindowDeclRef() << ") &&\n"
" !(isnan(" << vSubArguments[1]->GenSlidingWindowDeclRef() << ") || " << vSubArguments[1]->GenSlidingWindowDeclRef() << " == 0)) {\n"
" return 0;\n"
"}\n";
}
return false;
}
};
class OpMin : public Reduction
{
public:
explicit OpMin(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "NAN"; }
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
return "fmin_count(" + lhs + "," + rhs + ", &nCount)";
}
virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override;
virtual std::string BinFuncName() const override { return "min"; }
virtual bool isMinOrMax() const override { return true; }
virtual bool canHandleMultiVector() const override { return true; }
};
class OpMax : public Reduction
{
public:
explicit OpMax(int nResultSize) : Reduction(nResultSize) {}
virtual std::string GetBottom() override { return "NAN"; }
virtual std::string Gen2( const std::string& lhs, const std::string& rhs ) const override
{
return "fmax_count(" + lhs + "," + rhs + ", &nCount)";
}
virtual void BinInlineFun(std::set<std::string>& decls,std::set<std::string>& funs) override;
virtual std::string BinFuncName() const override { return "max"; }
virtual bool isMinOrMax() const override { return true; }
virtual bool canHandleMultiVector() const override { return true; }
};
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+76
View File
@@ -86,4 +86,80 @@ const char atan2Content[] =
" return a;\n"
"}\n";
const char fsum_countDecl[] = "double fsum_count(double a, double b, __private int *p);\n";
const char fsum_count[] =
"double fsum_count(double a, double b, __private int *p) {\n"
" bool t = isnan(a);\n"
" (*p) += t?0:1;\n"
" return t?b:a+b;\n"
"}\n";
const char fmin_countDecl[] = "double fmin_count(double a, double b, __private int *p);\n";
const char fmin_count[] =
"double fmin_count(double a, double b, __private int *p) {\n"
" double result = fmin(a, b);\n"
" bool t = isnan(result);\n"
" (*p) += t?0:1;\n"
" return result;\n"
"}\n";
const char fmax_countDecl[] = "double fmax_count(double a, double b, __private int *p);\n";
const char fmax_count[] =
"double fmax_count(double a, double b, __private int *p) {\n"
" double result = fmax(a, b);\n"
" bool t = isnan(result);\n"
" (*p) += t?0:1;\n"
" return result;\n"
"}\n";
const char is_representable_integerDecl[] = "int is_representable_integer(double a);\n";
const char is_representable_integer[] =
"int is_representable_integer(double a) {\n"
" long kMaxInt = (1L << 53) - 1;\n"
" if (a <= as_double(kMaxInt))\n"
" {\n"
" long nInt = as_long(a);\n"
" double fInt;\n"
" return (nInt <= kMaxInt &&\n"
" (!((fInt = as_double(nInt)) < a) && !(fInt > a)));\n"
" }\n"
" return 0;\n"
"}\n";
const char approx_equalDecl[] = "int approx_equal(double a, double b);\n";
const char approx_equal[] =
"int approx_equal(double a, double b) {\n"
" double e48 = 1.0 / (16777216.0 * 16777216.0);\n"
" double e44 = e48 * 16.0;\n"
" if (a == b)\n"
" return 1;\n"
" if (a == 0.0 || b == 0.0)\n"
" return 0;\n"
" double d = fabs(a - b);\n"
" if (!isfinite(d))\n"
" return 0; // Nan or Inf involved\n"
" if (d > ((a = fabs(a)) * e44) || d > ((b = fabs(b)) * e44))\n"
" return 0;\n"
" if (is_representable_integer(d) && is_representable_integer(a) && is_representable_integer(b))\n"
" return 0; // special case for representable integers.\n"
" return (d < a * e48 && d < b * e48);\n"
"}\n";
const char fsum_approxDecl[] = "double fsum_approx(double a, double b);\n";
const char fsum_approx[] =
"double fsum_approx(double a, double b) {\n"
" if ( ((a < 0.0 && b > 0.0) || (b < 0.0 && a > 0.0))\n"
" && approx_equal( a, -b ) )\n"
" return 0.0;\n"
" return a + b;\n"
"}\n";
const char fsub_approxDecl[] = "double fsub_approx(double a, double b);\n";
const char fsub_approx[] =
"double fsub_approx(double a, double b) {\n"
" if ( ((a < 0.0 && b < 0.0) || (a > 0.0 && b > 0.0)) && approx_equal( a, b ) )\n"
" return 0.0;\n"
" return a - b;\n"
"}\n";
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
+98 -2
View File
@@ -12,17 +12,25 @@
#include <clew/clew.h>
#include <formula/token.hxx>
#include <formula/types.hxx>
#include <formula/vectortoken.hxx>
#include <memory>
#include <set>
#include <vector>
#include "utils.hxx"
namespace formula { class DoubleVectorRefToken; }
namespace formula { class FormulaToken; }
struct ScCalcConfig;
namespace sc::opencl {
// FIXME: The idea that somebody would bother to (now and then? once a year? once a month?) manually
// edit a source file and change the value of some #defined constant and run some ill-defined
// "correctness test" is of course ludicrous. Either things are checked in normal unit tests, in
// every 'make check', or not at all. The below comments are ridiculous.
#define REDUCE_THRESHOLD 201 // set to 4 for correctness testing. priority 1
#define UNROLLING_FACTOR 16 // set to 4 for correctness testing (if no reduce)
class FormulaTreeNode;
/// Exceptions
@@ -194,6 +202,27 @@ protected:
const int mnIndex;
};
/// A vector of strings
class DynamicKernelStringArgument : public VectorRef
{
public:
DynamicKernelStringArgument( const ScCalcConfig& config, const std::string& s,
const FormulaTreeNodeRef& ft, int index = 0 ) :
VectorRef(config, s, ft, index) { }
virtual void GenSlidingWindowFunction( outputstream& ) override { }
/// Generate declaration
virtual void GenDecl( outputstream& ss ) const override
{
ss << "__global unsigned int *" << mSymName;
}
virtual void GenSlidingWindowDecl( outputstream& ss ) const override
{
DynamicKernelStringArgument::GenDecl(ss);
}
virtual size_t Marshal( cl_kernel, int, int, cl_program ) override;
};
/// Abstract class for code generation
class OpBase
{
@@ -262,6 +291,73 @@ public:
int nCurWindowSize );
};
class OpAverage;
class OpCount;
/// Handling a Double Vector that is used as a sliding window input
/// to either a sliding window average or sum-of-products
/// Generate a sequential loop for reductions
template<class Base>
class DynamicKernelSlidingArgument : public Base
{
public:
DynamicKernelSlidingArgument(const ScCalcConfig& config, const std::string& s,
const FormulaTreeNodeRef& ft,
std::shared_ptr<SlidingFunctionBase> CodeGen, int index);
// Should only be called by SumIfs. Yikes!
virtual bool NeedParallelReduction() const;
virtual void GenSlidingWindowFunction( outputstream& ) { }
std::string GenSlidingWindowDeclRef( bool nested = false ) const;
/// Controls how the elements in the DoubleVectorRef are traversed
size_t GenReductionLoopHeader( outputstream& ss, bool& needBody );
size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
bool GetStartFixed() const { return bIsStartFixed; }
bool GetEndFixed() const { return bIsEndFixed; }
protected:
bool bIsStartFixed, bIsEndFixed;
const formula::DoubleVectorRefToken* mpDVR;
// from parent nodes
std::shared_ptr<SlidingFunctionBase> mpCodeGen;
};
/// Handling a Double Vector that is used as a sliding window input
/// Performs parallel reduction based on given operator
template<class Base>
class ParallelReductionVectorRef : public Base
{
public:
ParallelReductionVectorRef(const ScCalcConfig& config, const std::string& s,
const FormulaTreeNodeRef& ft,
std::shared_ptr<SlidingFunctionBase> CodeGen, int index);
~ParallelReductionVectorRef();
/// Emit the definition for the auxiliary reduction kernel
virtual void GenSlidingWindowFunction( outputstream& ss );
virtual std::string GenSlidingWindowDeclRef( bool ) const;
/// Controls how the elements in the DoubleVectorRef are traversed
size_t GenReductionLoopHeader( outputstream& ss, int nResultSize, bool& needBody );
virtual size_t Marshal( cl_kernel k, int argno, int w, cl_program mpProgram );
size_t GetArrayLength() const { return mpDVR->GetArrayLength(); }
size_t GetWindowSize() const { return mpDVR->GetRefRowSize(); }
bool GetStartFixed() const { return bIsStartFixed; }
bool GetEndFixed() const { return bIsEndFixed; }
protected:
bool bIsStartFixed, bIsEndFixed;
const formula::DoubleVectorRefToken* mpDVR;
// from parent nodes
std::shared_ptr<SlidingFunctionBase> mpCodeGen;
// controls whether to invoke the reduction kernel during marshaling or not
cl_mem mpClmem2;
};
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */