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:
File diff suppressed because it is too large
Load Diff
@@ -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: */
|
||||
|
||||
@@ -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: */
|
||||
|
||||
@@ -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: */
|
||||
|
||||
@@ -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: */
|
||||
|
||||
Reference in New Issue
Block a user