1 #ifndef CPPAD_CG_CODE_HANDLER_IMPL_INCLUDED
2 #define CPPAD_CG_CODE_HANDLER_IMPL_INCLUDED
23 CodeHandler<Base>::CodeHandler(
size_t varCount) :
27 _idSparseArrayCount(1),
32 _evaluationOrder(*this),
33 _lastUsageOrder(*this),
34 _totalUseCount(*this),
35 _operationCount(*this),
37 _scopedVariableOrder(1),
38 _atomicFunctionsOrder(nullptr),
42 _currentScopeColor(0),
44 _minTemporaryVarID(0),
45 _zeroDependents(false),
61 v->handler_ =
nullptr;
77 for (
auto& v : variables) {
91 _independentVariables.push_back(makeNode(CGOpCode::Inv));
92 variable.makeVariable(*_independentVariables.back());
97 return _independentVariables.size();
111 inline bool CodeHandler<Base>::isVerbose()
const {
116 inline void CodeHandler<Base>::setVerbose(
bool verbose) {
121 inline JobTimer* CodeHandler<Base>::getJobTimer()
const {
126 inline void CodeHandler<Base>::setJobTimer(JobTimer* jobTimer) {
144 auto it = std::find(_independentVariables.begin(), _independentVariables.end(), &var);
145 if (it == _independentVariables.end()) {
146 throw CGException(
"Variable not found in the independent variable vector");
149 return it - _independentVariables.begin();
158 inline void CodeHandler<Base>::startNewOperationTreeVisit() {
159 assert(_idVisit < (std::numeric_limits<size_t>::max)());
166 inline bool CodeHandler<Base>::isVisited(
const Node& node)
const {
167 size_t p = node.getHandlerPosition();
172 inline void CodeHandler<Base>::markVisited(
const Node& node) {
179 typename std::map<size_t, CGAbstractAtomicFun<Base>*>::const_iterator it;
182 return it->second->atomic_name();
184 return std::string();
208 inline const std::vector<typename CodeHandler<Base>::ScopePath>&
218 const std::string& jobName) {
226 std::vector<CGB>& dependent,
228 const std::string& jobName) {
235 Language<Base>& lang,
236 ArrayView<CGB>& dependent,
237 VariableNameGenerator<Base>& nameGen,
238 const std::string& jobName) {
239 std::vector<std::string> atomicFunctions;
240 generateCode(out, lang, dependent, nameGen, atomicFunctions, jobName);
248 std::vector<std::string>& atomicFunctions,
249 const std::string& jobName) {
251 generateCode(out, lang, deps, nameGen, atomicFunctions, jobName);
257 std::vector<CGB>& dependent,
259 std::vector<std::string>& atomicFunctions,
260 const std::string& jobName) {
262 generateCode(out, lang, deps, nameGen, atomicFunctions, jobName);
270 std::vector<std::string>& atomicFunctions,
271 const std::string& jobName) {
272 using namespace std::chrono;
273 steady_clock::time_point beginTime;
276 _jobTimer->startingJob(
"source for '" + jobName +
"'");
277 }
else if (_verbose) {
278 std::cout <<
"generating source for '" << jobName <<
"' ... ";
280 beginTime = steady_clock::now();
286 _idSparseArrayCount = 1;
288 _dependents = &dependent;
293 _loops.prepare4NewSourceGen();
294 _scopeColorCount = 0;
295 _currentScopeColor = 0;
298 _alteredNodes.clear();
306 for (
size_t i = 0; i < atomicFunctions.size(); i++) {
320 size_t n = _independentVariables.size();
321 for (
size_t j = 0; j < n; j++) {
322 _varId[*_independentVariables[j]] = _idCount++;
325 size_t m = dependent.
size();
326 for (
size_t i = 0; i < m; i++) {
327 Node* node = dependent[i].getOperationNode();
328 if (node !=
nullptr &&
_varId[*node] == 0) {
329 _varId[*node] = _idCount++;
333 _minTemporaryVarID = _idCount;
338 for (
size_t i = 0; i < m; i++) {
339 Node* node = dependent[i].getOperationNode();
340 if (node !=
nullptr) {
350 startNewOperationTreeVisit();
352 for (
size_t i = 0; i < m; i++) {
353 CGB& var = dependent[i];
354 if (var.getOperationNode() !=
nullptr) {
355 Node& code = *var.getOperationNode();
356 if (!isVisited(code)) {
363 if ((
_varId[code] == 0 || !isIndependent(code)) && !isVisited(code)) {
364 addToEvaluationQueue(code);
386 addScopeToVarOrder(0, e);
395 setEvaluationOrder(arg, p + 1);
414 nameGen.
setTemporaryVariableID(_minTemporaryVarID, _idCount - 1, _idArrayCount - 1, _idSparseArrayCount - 1);
416 std::map<std::string, size_t> atomicFunctionName2Id;
418 atomicFunctionName2Id[pair.second->atomic_name()] = pair.first;
421 std::map<size_t, size_t> atomicFunctionId2Index;
422 std::map<size_t, std::string> atomicFunctionId2Name;
424 const std::string& atomicName = (*_atomicFunctionsOrder)[i];
425 std::map<std::string, size_t>::const_iterator it = atomicFunctionName2Id.find(atomicName);
426 if (it != atomicFunctionName2Id.end()) {
427 atomicFunctionId2Index[it->second] = i;
428 atomicFunctionId2Name[it->second] = atomicName;
439 atomicFunctionId2Index, atomicFunctionId2Name,
442 _loops.indexes, _loops.indexRandomPatterns,
443 _loops.dependentIndexPatterns, _loops.independentIndexPatterns,
447 lang.generateSourceCode(out, std::move(_info));
455 for (
const auto& itAlt : _alteredNodes) {
456 Node* tmp = itAlt.first;
457 Node* opClone = itAlt.second;
463 _alteredNodes.clear();
467 }
else if (_verbose) {
469 duration<float> dt = steady_clock::now() - beginTime;
470 std::cout <<
"done [" << std::fixed << std::setprecision(3) << dt.count() <<
"]" << std::endl;
479 return _idCount - _minTemporaryVarID;
483 size_t CodeHandler<Base>::getTemporaryArraySize()
const {
484 return _idArrayCount - 1;
488 size_t CodeHandler<Base>::getTemporarySparseArraySize()
const {
489 return _idSparseArrayCount - 1;
498 _independentVariables.clear();
501 _idSparseArrayCount = 1;
525 return manageOperationNode(
new Node(n));
530 return manageOperationNode(
new Node(
this, op));
534 inline OperationNode<Base>* CodeHandler<Base>::makeNode(CGOpCode op,
536 return manageOperationNode(
new Node(
this, op, arg));
540 inline OperationNode<Base>* CodeHandler<Base>::makeNode(CGOpCode op,
541 std::vector<Arg>&& args) {
542 return manageOperationNode(
new Node(
this, op, std::move(args)));
546 inline OperationNode<Base>* CodeHandler<Base>::makeNode(CGOpCode op,
547 std::vector<size_t>&& info,
548 std::vector<Arg>&& args) {
549 return manageOperationNode(
new Node(
this, op, std::move(info), std::move(args)));
553 inline OperationNode<Base>* CodeHandler<Base>::makeNode(CGOpCode op,
554 const std::vector<size_t>& info,
555 const std::vector<Arg>& args) {
556 return manageOperationNode(
new Node(
this, op, info, args));
560 inline LoopStartOperationNode<Base>* CodeHandler<Base>::makeLoopStartNode(Node& indexDcl,
561 size_t iterationCount) {
562 auto* n =
new LoopStartOperationNode<Base>(
this, indexDcl, iterationCount);
563 manageOperationNode(n);
568 inline LoopStartOperationNode<Base>* CodeHandler<Base>::makeLoopStartNode(Node& indexDcl,
569 IndexOperationNode<Base>& iterCount) {
570 auto* n =
new LoopStartOperationNode<Base>(
this, indexDcl, iterCount);
571 manageOperationNode(n);
576 inline LoopEndOperationNode<Base>* CodeHandler<Base>::makeLoopEndNode(LoopStartOperationNode<Base>& loopStart,
577 const std::vector<Arg>& endArgs) {
578 auto* n =
new LoopEndOperationNode<Base>(
this, loopStart, endArgs);
579 manageOperationNode(n);
584 inline PrintOperationNode<Base>* CodeHandler<Base>::makePrintNode(
const std::string& before,
586 const std::string& after) {
587 auto* n =
new PrintOperationNode<Base>(
this, before, arg, after);
588 manageOperationNode(n);
593 inline IndexOperationNode<Base>* CodeHandler<Base>::makeIndexNode(Node& indexDcl) {
594 auto* n =
new IndexOperationNode<Base>(
this, indexDcl);
595 manageOperationNode(n);
600 inline IndexOperationNode<Base>* CodeHandler<Base>::makeIndexNode(LoopStartOperationNode<Base>& loopStart) {
601 auto* n =
new IndexOperationNode<Base>(
this, loopStart);
602 manageOperationNode(n);
607 inline IndexOperationNode<Base>* CodeHandler<Base>::makeIndexNode(IndexAssignOperationNode<Base>& indexAssign) {
608 auto* n =
new IndexOperationNode<Base>(
this, indexAssign);
609 manageOperationNode(n);
614 inline IndexAssignOperationNode<Base>* CodeHandler<Base>::makeIndexAssignNode(Node& index,
615 IndexPattern& indexPattern,
616 IndexOperationNode<Base>& index1) {
617 auto* n =
new IndexAssignOperationNode<Base>(
this, index, indexPattern, index1);
618 manageOperationNode(n);
623 inline IndexAssignOperationNode<Base>* CodeHandler<Base>::makeIndexAssignNode(Node& index,
624 IndexPattern& indexPattern,
625 IndexOperationNode<Base>* index1,
626 IndexOperationNode<Base>* index2) {
627 auto* n =
new IndexAssignOperationNode<Base>(
this, index, indexPattern, index1, index2);
628 manageOperationNode(n);
633 inline OperationNode<Base>* CodeHandler<Base>::makeIndexDclrNode(
const std::string& name) {
634 CPPADCG_ASSERT_KNOWN(!name.empty(),
"index name cannot be empty")
635 auto* n = manageOperationNode(new Node(this, CGOpCode::IndexDeclaration));
655 start = std::min<size_t>(start,
_codeBlocks.size());
658 for (
size_t i = start; i < end; ++i) {
664 for (
size_t i = start; i <
_codeBlocks.size(); ++i) {
669 v->nodesErased(start, end);
685 inline void CodeHandler<Base>::findRandomIndexPatterns(IndexPattern* ip,
686 std::set<RandomIndexPattern*>& found) {
690 if (ip->getType() == IndexPatternType::Random1D || ip->getType() == IndexPatternType::Random2D) {
691 found.insert(
static_cast<RandomIndexPattern*
> (ip));
693 std::set<IndexPattern*> indexes;
694 ip->getSubIndexes(indexes);
695 for (IndexPattern* sip : indexes) {
696 if (sip->getType() == IndexPatternType::Random1D || sip->getType() == IndexPatternType::Random2D)
697 found.insert(
static_cast<RandomIndexPattern*
> (sip));
709 manageOperationNode(code);
728 inline void CodeHandler<Base>::addVector(CodeHandlerVectorSync<Base>* v) {
733 inline void CodeHandler<Base>::removeVector(CodeHandlerVectorSync<Base>* v) {
743 auto& code = stackEl.node();
745 increaseTotalUsageCount(code);
747 CGOpCode op = code.getOperationType();
748 if (isIndependent(code)) {
751 }
else if (op == CGOpCode::Alias) {
756 CPPADCG_ASSERT_UNKNOWN(code.getArguments().size() == 1)
757 stack.emplace_back(code, 0, _currentScopeColor);
764 size_t previousScope = _currentScopeColor;
766 _scope[code] = _currentScopeColor;
769 if (op == CGOpCode::LoopStart || op == CGOpCode::StartIf || op == CGOpCode::ElseIf ||
770 op == CGOpCode::Else) {
772 ScopePath& sPath = _scopes[_currentScopeColor];
773 CPPADCG_ASSERT_UNKNOWN(sPath.back().beginning ==
nullptr)
774 if (op == CGOpCode::LoopStart || op == CGOpCode::StartIf) {
775 sPath.back().beginning = &code;
777 CPPADCG_ASSERT_UNKNOWN(!code.getArguments().empty() &&
778 code.getArguments()[0].getOperation() !=
nullptr &&
779 code.getArguments()[0].getOperation()->getOperationType() ==
781 sPath.back().beginning = code.getArguments()[0].getOperation();
783 _currentScopeColor = sPath.size() > 1 ? sPath[sPath.size() - 2].color : 0;
786 if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
788 _currentScopeColor = ++_scopeColorCount;
790 _scopes.resize(_currentScopeColor + 1);
791 _scopes[_currentScopeColor] = _scopes[previousScope];
794 if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf) {
802 if (op == CGOpCode::LoopEnd) {
803 _loops.addLoopEndNode(code);
810 stack.pushNodeArguments(code, _currentScopeColor);
817 if (op == CGOpCode::Tmp && !code.getInfo().empty()) {
823 if (
_scope[code] == _currentScopeColor) {
830 }
else if (
_scope[code] != _currentScopeColor && op != CGOpCode::LoopIndexedIndep) {
831 ScopeIDType oldScope =
_scope[code];
840 ScopeIDType newScope;
844 newScope = _scopes[_currentScopeColor][depth - 1].color;
846 if (oldScope != newScope) {
858 const std::vector<Arg>& args = code.getArguments();
859 size_t aSize = args.size();
860 for (
size_t a = 0; a < aSize; a++) {
861 updateVarScopeUsage(args[a].getOperation(), newScope, oldScope);
875 Node& code = stackEl.node();
876 size_t previousScope = stackEl.parentNodeScope;
880 if (op == CGOpCode::Index) {
883 if (inode.isDefinedLocally()) {
884 _loops.indexes.insert(&inode.getIndex());
886 }
else if (op == CGOpCode::LoopIndexedIndep || op == CGOpCode::LoopIndexedDep ||
887 op == CGOpCode::IndexAssign) {
889 if (op == CGOpCode::LoopIndexedDep) {
890 size_t pos = code.
getInfo()[0];
891 ip = _loops.dependentIndexPatterns[pos];
892 }
else if (op == CGOpCode::LoopIndexedIndep) {
893 size_t pos = code.
getInfo()[1];
894 ip = _loops.independentIndexPatterns[pos];
899 findRandomIndexPatterns(ip, _loops.indexRandomPatterns);
901 }
else if (op == CGOpCode::DependentRefRhs) {
902 CPPADCG_ASSERT_UNKNOWN(code.
getInfo().size() == 1)
903 size_t depIndex = code.
getInfo()[0];
905 CPPADCG_ASSERT_UNKNOWN(_dependents->size() > depIndex)
906 Node * depNode = (*_dependents)[depIndex].getOperationNode();
907 CPPADCG_ASSERT_UNKNOWN(depNode !=
nullptr && depNode->
getOperationType() != CGOpCode::Inv)
915 _currentScopeColor = previousScope;
919 depthFirstGraphNavigation(root,
930 if (_currentScopeColor == 0)
936 CPPADCG_ASSERT_KNOWN(code.
getOperationType() != CGOpCode::ArrayCreation,
"Not supported yet")
937 CPPADCG_ASSERT_KNOWN(code.
getOperationType() != CGOpCode::SparseArrayCreation,
"Not supported yet")
942 std::vector<size_t> iterationRegions;
943 Node* bScopeNewEnd = _scopes[_currentScopeColor].back().end;
944 Node* bScopeOldEnd = _scopes[oldScope].back().end;
949 if ((bNewOp == CGOpCode::EndIf || bNewOp == CGOpCode::Else || bNewOp == CGOpCode::ElseIf) &&
950 (bOldOp == CGOpCode::EndIf || bOldOp == CGOpCode::Else || bOldOp == CGOpCode::ElseIf)) {
960 iterationRegions = ifBranchIterationRanges(bScopeNew, newIterIndexOp);
961 CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2)
964 std::vector<size_t> oldIterRegions = ifBranchIterationRanges(bScopeOld, oldIterIndexOp);
965 combineOverlapingIterationRanges(iterationRegions, oldIterRegions);
966 CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2)
967 CPPADCG_ASSERT_UNKNOWN(newIterIndexOp !=
nullptr && newIterIndexOp == oldIterIndexOp)
969 if (iterationRegions.size() > 2 ||
970 iterationRegions[0] != 0 ||
971 iterationRegions[1] != (std::numeric_limits<size_t>::max)()) {
985 const std::vector<size_t>& iterationRegions,
986 ScopeIDType oldScope,
987 ScopeIDType commonScopeColor) {
996 Node* tmpDclVar = makeNode(CGOpCode::TmpDcl);
997 Arg tmpArg(*tmpDclVar);
999 Node* cond = makeNode(CGOpCode::IndexCondExpr, iterationRegions, {iterationIndexOp});
1002 Node* ifStart = makeNode(CGOpCode::StartIf, *cond);
1004 Node* tmpAssign = makeNode(CGOpCode::LoopIndexedTmp, {tmpArg, *opClone});
1005 Node* ifAssign = makeNode(CGOpCode::CondResult, {*ifStart, *tmpAssign});
1008 Node* endIf = makeNode(CGOpCode::EndIf, {*ifStart, *ifAssign});
1029 size_t newScopeColor = ++_scopeColorCount;
1030 _scopes.resize(newScopeColor + 1);
1031 _scopes[newScopeColor] = _scopes[commonScopeColor];
1037 _scope[*tmpDclVar] = commonScopeColor;
1038 _scope[*ifStart] = newScopeColor;
1039 _scope[*cond] = newScopeColor;
1040 _scope[*opClone] = newScopeColor;
1041 _scope[*ifAssign] = newScopeColor;
1042 _scope[*tmpAssign] = newScopeColor;
1043 _scope[*endIf] = commonScopeColor;
1044 _scope[tmp] = commonScopeColor;
1047 setTotalUsageCount(*tmpDclVar, 1);
1048 setTotalUsageCount(*ifStart, 1);
1049 setTotalUsageCount(*cond, 1);
1050 setTotalUsageCount(*opClone, 1);
1051 setTotalUsageCount(*ifAssign, 1);
1052 setTotalUsageCount(*tmpAssign, 1);
1053 setTotalUsageCount(*endIf, 1);
1058 const std::vector<Arg>& cargs = opClone->
getArguments();
1059 size_t aSize = cargs.size();
1060 for (
size_t a = 0; a < aSize; a++) {
1061 updateVarScopeUsage(cargs[a].getOperation(), newScopeColor, oldScope);
1064 _alteredNodes.push_back(std::make_pair(&tmp, opClone));
1067 template<
class Base>
1069 if (
_scope[code] != _currentScopeColor) {
1076 if (_currentScopeColor == 0)
1084 ScopeIDType oldScope =
_scope[code];
1089 ScopeIDType newScope = depth == 0 ? 0 : _scopes[_currentScopeColor][depth - 1].color;
1094 std::vector<size_t> iterationRegions;
1095 Node* bScopeNewEnd = _scopes[_currentScopeColor].back().end;
1098 Node* bScopeOldEnd = _scopes[
_scope[*endif]].back().end;
1102 if (bNewOp == CGOpCode::EndIf || bNewOp == CGOpCode::Else || bNewOp == CGOpCode::ElseIf) {
1112 iterationRegions = ifBranchIterationRanges(bScopeNew, newIterIndexOp);
1113 CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2)
1116 const std::vector<size_t> oldIterRegions = ifBranchIterationRanges(bScopeOld, oldIterIndexOp);
1117 combineOverlapingIterationRanges(iterationRegions, oldIterRegions);
1118 CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2)
1119 CPPADCG_ASSERT_UNKNOWN(newIterIndexOp !=
nullptr && newIterIndexOp == oldIterIndexOp)
1121 if (iterationRegions.size() == 2 &&
1122 (iterationRegions[0] == 0 ||
1123 iterationRegions[1] == (std::numeric_limits<size_t>::max)())) {
1128 }
else if (oldIterRegions != iterationRegions) {
1130 CPPADCG_ASSERT_UNKNOWN(cond->
getOperationType() == CGOpCode::IndexCondExpr)
1131 cond->
getInfo() = iterationRegions;
1136 if (oldScope != newScope) {
1142 size_t aSize = cargs.size();
1143 for (
size_t a = 0; a < aSize; a++) {
1144 updateVarScopeUsage(cargs[a].getOperation(), newScope, oldScope);
1150 template<
class Base>
1161 _scope[tmp] = _currentScopeColor;
1167 size_t aSize = args.size();
1168 for (
size_t a = 0; a < aSize; a++) {
1169 updateVarScopeUsage(args[a].getOperation(), _currentScopeColor,
_scope[*opClone]);
1173 template<
class Base>
1181 _scope[*tmp] = _currentScopeColor;
1187 size_t aSize = args.size();
1188 for (
size_t a = 0; a < aSize; a++) {
1189 updateVarScopeUsage(args[a].getOperation(), _currentScopeColor,
_scope[*opClone]);
1193 template<
class Base>
1195 ScopeIDType usageScope,
1196 ScopeIDType oldUsageScope) {
1197 if (node ==
nullptr ||
_scope[*node] == usageScope)
1201 ScopeIDType oldScope =
_scope[*node];
1202 ScopeIDType newScope;
1204 if (oldScope == oldUsageScope) {
1205 newScope = usageScope;
1209 newScope = (depth == 0) ? 0 : _scopes[usageScope][depth - 1].color;
1212 if (newScope == oldScope)
1215 _scope[*node] = newScope;
1217 const std::vector<Arg>& args = node->getArguments();
1218 size_t aSize = args.size();
1219 for (
size_t a = 0; a < aSize; a++) {
1220 updateVarScopeUsage(args[a].getOperation(), newScope, oldScope);
1224 template<
class Base>
1225 inline void CodeHandler<Base>::addScopeToVarOrder(
size_t scope,
1229 const size_t vsize = vorder.size();
1230 for (
size_t p = 0; p < vsize; p++) {
1231 Node* node = vorder[p];
1232 CGOpCode op = node->getOperationType();
1234 if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
1235 CPPADCG_ASSERT_UNKNOWN(!node->getArguments().empty())
1237 Node* beginScopeNode = node->getArguments()[0].getOperation();
1238 CPPADCG_ASSERT_UNKNOWN(beginScopeNode !=
nullptr)
1240 addScopeToVarOrder(
_scope[*beginScopeNode], e);
1248 template<class Base>
1251 CPPADCG_ASSERT_UNKNOWN(color1 < _scopes.size())
1252 CPPADCG_ASSERT_UNKNOWN(color2 < _scopes.size())
1254 ScopePath& scopePath1 = _scopes[color1];
1255 ScopePath& scopePath2 = _scopes[color2];
1257 size_t s1 = scopePath1.size();
1258 size_t s2 = scopePath2.size();
1260 for (depth = 0; depth < s1 && depth < s2; depth++) {
1261 if (scopePath1[depth].color != scopePath2[depth].color) {
1269 template<
class Base>
1277 for (
long p = vorder.size() - 1; p > 0; p--) {
1278 Node* endIf = vorder[p];
1284 if (vorder[p1]->getOperationType() == CGOpCode::TmpDcl) {
1290 Node* endIf1 = vorder[p1];
1311 ScopeIDType ifScope =
_scope[*startIf];
1312 ScopeIDType ifScope1 =
_scope[*startIf1];
1316 startNewOperationTreeVisit();
1319 for (
size_t a = 1; a < eArgs.size(); a++) {
1320 CPPADCG_ASSERT_UNKNOWN(eArgs[a].getOperation() !=
nullptr && eArgs[a].getOperation()->getOperationType() == CGOpCode::CondResult)
1322 replaceScope(eArgs[a].getOperation(), ifScope, ifScope1);
1325 vorderIf1.insert(vorderIf1.end(), vorderIf.begin() + 1, vorderIf.end());
1330 for (
size_t a = 1; a < eArgs.size(); a++) {
1331 CPPADCG_ASSERT_UNKNOWN(eArgs[a].getOperation() !=
nullptr && eArgs[a].getOperation()->getOperationType() == CGOpCode::CondResult)
1332 eArgs[a].getOperation()->getArguments()[0] =
Arg(*startIf1);
1336 eArgs1.insert(eArgs1.end(), eArgs.begin() + 1, eArgs.end());
1342 vorder.erase(vorder.begin() + p);
1345 for (
long pp = p1; pp < p - 1; pp++) {
1346 vorder[pp] = vorder[pp + 1];
1348 vorder[p - 1] = endIf1;
1354 template<
class Base>
1356 ScopeIDType oldScope,
1357 ScopeIDType newScope) {
1358 if (node ==
nullptr ||
_scope[*node] != oldScope)
1361 _scope[*node] = newScope;
1363 const std::vector<Arg>& args = node->getArguments();
1364 for (
size_t a = 0; a < args.size(); a++) {
1365 replaceScope(args[a].getOperation(), oldScope, newScope);
1369 template<
class Base>
1373 if (node ==
nullptr || isVisited(*node))
1381 if (op == CGOpCode::Tmp && args.size() > 1) {
1382 Node* arg = args[1].getOperation();
1386 args.erase(args.begin() + 1);
1390 if (!containedInScope(*node, scope)) {
1394 for (
size_t a = 0; a < args.size(); a++) {
1395 Node* arg = args[a].getOperation();
1397 if (op == CGOpCode::StartIf || op == CGOpCode::LoopStart) {
1398 args.erase(args.begin() + a);
1407 template<
class Base>
1409 ScopeIDType scope) {
1410 ScopeIDType nScope =
_scope[node];
1411 if (nScope == scope)
1414 return _scopes[nScope].size() >= _scopes[scope].size() &&
1415 _scopes[nScope][_scopes[scope].size() - 1].color == scope;
1418 template<
class Base>
1419 inline bool CodeHandler<Base>::containsArgument(
const Node& node,
1421 const std::vector<Arg>& args = node.getArguments();
1422 for (
size_t a = 0; a < args.size(); a++) {
1423 if (args[a].getOperation() == &arg) {
1430 template<
class Base>
1431 void CodeHandler<Base>::registerAtomicFunction(CGAbstractAtomicFun<Base>& atomic) {
1432 size_t id = atomic.getId();
1436 _atomicFunctions.insert(it, std::pair<
size_t, CGAbstractAtomicFun<Base>*>(atomic.getId(), &atomic));
1437 }
else if(it->second != &atomic) {
1438 throw CGException(
"The same atomic function ID (",
id,
") is being used for different atomic functions: '",
1439 atomic.atomic_name(),
"' (", &atomic,
") and '", it->second->atomic_name(),
"' (", it->second,
").");
1443 template<
class Base>
1448 auto& arg = stackEl.node();
1450 if (isVisited(arg)) {
1453 stack.pushNodeArguments(stackEl.node(), 0);
1459 auto& arg = stackEl.node();
1461 if (isVisited(arg)) {
1465 CGOpCode aType = arg.getOperationType();
1467 if (aType == CGOpCode::LoopEnd || aType == CGOpCode::ElseIf ||
1468 aType == CGOpCode::Else || aType == CGOpCode::EndIf) {
1471 _varId[arg] = (std::numeric_limits<size_t>::max)();
1473 }
else if (aType == CGOpCode::AtomicForward || aType == CGOpCode::AtomicReverse) {
1477 CPPADCG_ASSERT_UNKNOWN(arg.getArguments().size() > 1)
1478 CPPADCG_ASSERT_UNKNOWN(arg.getInfo().size() > 1)
1479 size_t id = arg.getInfo()[0];
1483 std::map<std::string, size_t>::const_iterator itName2Idx;
1493 pos = itName2Idx->second;
1496 if (aType == CGOpCode::AtomicForward) {
1497 int p = arg.getInfo()[2];
1501 int p = arg.getInfo()[1];
1512 if (
_varId[arg] == 0 || !isIndependent(arg)) {
1513 auto& code = stackEl.parent();
1514 size_t argIndex = stackEl.argumentIndex();
1516 if (aType == CGOpCode::LoopIndexedIndep) {
1518 _varId[arg] = (std::numeric_limits<size_t>::max)();
1519 }
else if (aType == CGOpCode::Alias) {
1521 }
else if (aType == CGOpCode::Tmp) {
1522 _varId[arg] = (std::numeric_limits<size_t>::max)();
1523 }
else if (aType == CGOpCode::LoopStart ||
1524 aType == CGOpCode::LoopEnd ||
1525 aType == CGOpCode::StartIf ||
1526 aType == CGOpCode::ElseIf ||
1527 aType == CGOpCode::Else ||
1528 aType == CGOpCode::EndIf) {
1533 addToEvaluationQueue(arg);
1536 _varId[arg] = (std::numeric_limits<size_t>::max)();
1538 }
else if (aType == CGOpCode::Pri) {
1539 addToEvaluationQueue(arg);
1542 _varId[arg] = (std::numeric_limits<size_t>::max)();
1544 }
else if (aType == CGOpCode::TmpDcl) {
1545 addToEvaluationQueue(arg);
1556 for (
const auto& a: arg) {
1557 if (a.getOperation() !=
nullptr) {
1558 auto& n = *a.getOperation();
1567 _lang->requiresVariableArgument(code.getOperationType(), argIndex)) {
1569 addToEvaluationQueue(arg);
1572 if (aType == CGOpCode::AtomicForward ||
1573 aType == CGOpCode::AtomicReverse) {
1574 _varId[arg] = _idAtomicCount;
1576 }
else if (aType == CGOpCode::LoopIndexedDep ||
1577 aType == CGOpCode::LoopIndexedTmp) {
1579 _varId[arg] = (std::numeric_limits<size_t>::max)();
1580 }
else if (aType == CGOpCode::ArrayCreation) {
1582 size_t arraySize = arg.getArguments().size();
1583 _varId[arg] = _idArrayCount;
1584 _idArrayCount += arraySize;
1585 }
else if (aType == CGOpCode::SparseArrayCreation) {
1587 size_t nnz = arg.getArguments().size();
1588 _varId[arg] = _idSparseArrayCount;
1589 _idSparseArrayCount += nnz;
1604 depthFirstGraphNavigation(root,
1611 template<
class Base>
1613 ScopeIDType scope =
_scope[arg];
1620 _scopes[scope].back().end->getArguments()[0].getOperation() != &arg) {
1628 if (varOrder.size() == varOrder.capacity()) {
1629 varOrder.reserve((varOrder.size() * 3) / 2 + 1);
1632 varOrder.push_back(&arg);
1635 template<
class Base>
1643 startNewOperationTreeVisit();
1645 for (
size_t i = 0; i < dependent.
size(); i++) {
1646 Node* node = dependent[i].getOperationNode();
1647 if (node !=
nullptr) {
1648 if (!isVisited(*node)) {
1657 std::vector<std::vector<Node*>> tempVarRelease(
_variableOrder.size());
1660 if (isTemporary(*var) || isTemporaryArray(*var) || isTemporarySparseArray(*var)) {
1661 size_t releaseLocation = getLastUsageEvaluationOrder(*var) - 1;
1662 tempVarRelease[releaseLocation].push_back(var);
1670 std::vector<size_t> freedVariables;
1671 _idCount = _minTemporaryVarID;
1678 const std::vector<Node*>& released = tempVarRelease[i];
1679 for (
size_t r = 0; r < released.size(); r++) {
1680 if (isTemporary(*released[r])) {
1681 freedVariables.push_back(
_varId[*released[r]]);
1682 }
else if (isTemporaryArray(*released[r])) {
1683 arrayComp.addFreeArraySpace(*released[r]);
1684 }
else if (isTemporarySparseArray(*released[r])) {
1685 sparseArrayComp.addFreeArraySpace(*released[r]);
1689 if (isTemporary(var)) {
1691 if (freedVariables.empty()) {
1695 size_t id = freedVariables.back();
1696 freedVariables.pop_back();
1699 }
else if (isTemporaryArray(var)) {
1702 _varId[var] = arrayStart + 1;
1703 }
else if (isTemporarySparseArray(var)) {
1706 _varId[var] = arrayStart + 1;
1711 _idArrayCount = arrayComp.getIdCount();
1712 _idSparseArrayCount = sparseArrayComp.getIdCount();
1715 template<
class Base>
1718 startNewOperationTreeVisit();
1721 for (
size_t i = 0; i < dependent.
size(); ++i) {
1722 Node* node = dependent[i].getOperationNode();
1723 if (node !=
nullptr) {
1730 const std::vector<Arg>& args = endNode->getArguments();
1731 for (
size_t i = 1; i < args.size(); ++i) {
1732 CPPADCG_ASSERT_UNKNOWN(args[i].getOperation() !=
nullptr)
1734 if (args[i].getOperation()->getOperationType() == CGOpCode::LoopIndexedDep) {
1741 template<
class Base>
1746 size_t depPos = getEvaluationOrder(node);
1747 size_t lastTmpPos = depPos;
1748 if (!isVisited(node)) {
1757 if (lastTmpPos == depPos || lastTmpPos + 1 == depPos) {
1762 bool foundTemporaries =
false;
1764 for (
size_t l = lastTmpPos + 1; l < depPos; ++l) {
1766 if (isTemporary(*n) || isTemporaryArray(*n) || isTemporarySparseArray(*n)) {
1767 foundTemporaries =
true;
1774 CGOpCode op = n->getOperationType();
1775 if (op == CGOpCode::StartIf) {
1778 while (l < depPos) {
1780 if (node2->getOperationType() == CGOpCode::EndIf &&
1781 node2->getArguments()[0].getOperation() == n) {
1787 }
else if (op == CGOpCode::LoopStart) {
1790 while (l < depPos) {
1792 if (node2->getOperationType() == CGOpCode::LoopEnd &&
1802 if (foundTemporaries) {
1804 repositionEvaluationQueue(depPos, newPos);
1808 template<
class Base>
1811 size_t depOrder = getEvaluationOrder(root);
1812 size_t maxTmpOrder = depOrder;
1816 auto& node = stackEl.node();
1818 const auto& args = node.getArguments();
1820 for (
size_t i = 0; i < args.size(); ++i) {
1821 if (args[i].getOperation() ==
nullptr) {
1825 Node& arg = *args[i].getOperation();
1828 if (aOp == CGOpCode::LoopEnd || aOp == CGOpCode::EndIf || aOp == CGOpCode::ElseIf || aOp == CGOpCode::Else) {
1832 if (aOp == CGOpCode::Index) {
1834 if (iorder > maxTmpOrder)
1835 maxTmpOrder = iorder;
1837 }
else if (getEvaluationOrder(arg) == depOrder) {
1839 stack.emplace_back(node, i);
1843 if (getEvaluationOrder(arg) > maxTmpOrder)
1844 maxTmpOrder = getEvaluationOrder(arg);
1850 depthFirstGraphNavigation(root, nodeAnalysis,
true);
1855 template<
class Base>
1859 CPPADCG_ASSERT_UNKNOWN(fromPos > toPos)
1863 for (
size_t l = fromPos - 1; l > toPos - 1; --l) {
1869 updateEvaluationQueueOrder(*node, toPos);
1872 template<
class Base>
1877 auto& node = stackEl.node();
1878 CGOpCode op = node.getOperationType();
1882 if (op == CGOpCode::LoopEnd) {
1885 _loops.outerVars.resize(_loops.depth + 1);
1886 _loops.startEvalOrder.push_back(getEvaluationOrder(loopEnd.getLoopStart()));
1888 }
else if (op == CGOpCode::LoopStart) {
1895 auto& args = node.getArguments();
1896 for (
size_t i = 0; i < args.size(); ++i) {
1897 if (args[i].getOperation() !=
nullptr) {
1898 Node& arg = *args[i].getOperation();
1900 if (!isVisited(arg)) {
1902 stack.emplace_back(node, i, 0);
1913 auto& node = stackEl.node();
1914 CGOpCode op = node.getOperationType();
1916 for (
const Arg& it : node.getArguments()) {
1917 if (it.getOperation() !=
nullptr) {
1918 Node& arg = *it.getOperation();
1920 size_t order = getEvaluationOrder(node);
1921 Node* aa = getOperationFromAlias(arg);
1922 if (aa !=
nullptr) {
1923 if (getLastUsageEvaluationOrder(*aa) < order) {
1924 setLastUsageEvaluationOrder(*aa, order);
1927 if (_loops.depth >= 0 &&
1928 getEvaluationOrder(*aa) < _loops.startEvalOrder[_loops.depth] &&
1931 _loops.outerVars[_loops.depth].insert(aa);
1937 if (op == CGOpCode::LoopEnd) {
1942 size_t order = getEvaluationOrder(node);
1944 const std::set<Node*>& outerLoopUsages = _loops.outerVars.back();
1945 for (
Node* outerVar : outerLoopUsages) {
1946 Node* aa = getOperationFromAlias(*outerVar);
1947 if (aa !=
nullptr && getLastUsageEvaluationOrder(*aa) < order)
1948 setLastUsageEvaluationOrder(*aa, order);
1952 _loops.outerVars.pop_back();
1953 _loops.startEvalOrder.pop_back();
1955 }
else if (op == CGOpCode::LoopStart) {
1961 depthFirstGraphNavigation(root,
1969 template<
class Base>
1974 auto& node = stackEl.parent();
1975 auto& arg = stackEl.node();
1977 if (getEvaluationOrder(arg) == 0) {
1978 setEvaluationOrder(arg, getEvaluationOrder(node));
1980 stack.pushNodeArguments(arg);
1984 depthFirstGraphNavigation(root, analyse,
false);
1988 template<
class Base>
1990 size_t newEvalOrder) {
1994 auto& node = stackEl.node();
1995 size_t oldEvalOrder = getEvaluationOrder(node);
1997 setEvaluationOrder(node, newEvalOrder);
1999 for (
const Arg& a : node.getArguments()) {
2000 if (a.getOperation() !=
nullptr) {
2001 Node& arg = *a.getOperation();
2002 if (getEvaluationOrder(arg) == oldEvalOrder)
2003 stack.pushNodeArguments(arg);
2008 depthFirstGraphNavigation(root, analyse,
true);
2011 template<
class Base>
2019 startNewOperationTreeVisit();
2021 for (
const auto& a : var) {
2022 if (a.getOperation() !=
nullptr) {
2029 template<
class Base>
2035 auto& node = stackEl.node();
2037 if (!isVisited(node)) {
2043 stack.pushNodeArguments(node);
2048 depthFirstGraphNavigation(root, analyse,
true);
2051 template<
class Base>
2052 inline bool CodeHandler<Base>::isIndependent(
const Node& arg)
const {
2053 return arg.getOperationType() == CGOpCode::Inv;
2056 template<
class Base>
2057 inline bool CodeHandler<Base>::isTemporary(
const Node& arg)
const {
2058 CGOpCode op = arg.getOperationType();
2059 return op != CGOpCode::ArrayCreation &&
2060 op != CGOpCode::SparseArrayCreation &&
2061 op != CGOpCode::AtomicForward &&
2062 op != CGOpCode::AtomicReverse &&
2063 op != CGOpCode::LoopStart &&
2064 op != CGOpCode::LoopEnd &&
2065 op != CGOpCode::StartIf &&
2066 op != CGOpCode::ElseIf &&
2067 op != CGOpCode::Else &&
2068 op != CGOpCode::EndIf &&
2069 op != CGOpCode::LoopIndexedDep &&
2070 op != CGOpCode::LoopIndexedIndep &&
2071 op != CGOpCode::LoopIndexedTmp &&
2072 op != CGOpCode::Index &&
2073 op != CGOpCode::IndexAssign &&
2074 op != CGOpCode::Tmp &&
2075 _varId[arg] >= _minTemporaryVarID;
2078 template<
class Base>
2079 inline bool CodeHandler<Base>::isTemporaryArray(
const Node& arg) {
2080 return arg.getOperationType() == CGOpCode::ArrayCreation;
2083 template<
class Base>
2084 inline bool CodeHandler<Base>::isTemporarySparseArray(
const Node& arg) {
2085 return arg.getOperationType() == CGOpCode::SparseArrayCreation;
2088 template<
class Base>
2089 inline OperationNode<Base>* CodeHandler<Base>::getOperationFromAlias(Node& alias) {
2090 if (alias.getOperationType() != CGOpCode::Alias) {
2095 CPPADCG_ASSERT_UNKNOWN(aa->getArguments().size() == 1)
2096 aa = aa->getArguments()[0].getOperation();
2097 } while (aa !=
nullptr && aa->getOperationType() == CGOpCode::Alias);
2102 template<class Base>
2103 inline
size_t CodeHandler<Base>::getEvaluationOrder(const Node& node)
const {
2107 template<
class Base>
2108 inline void CodeHandler<Base>::setEvaluationOrder(Node& node,
2114 template<class Base>
2115 inline
size_t CodeHandler<Base>::getLastUsageEvaluationOrder(const Node& node)
const {
2119 template<
class Base>
2120 inline void CodeHandler<Base>::setLastUsageEvaluationOrder(
const Node& node,
2125 CGOpCode op = node.getOperationType();
2126 if (op == CGOpCode::ArrayElement) {
2127 Node* array = node.getArguments()[0].getOperation();
2128 CPPADCG_ASSERT_UNKNOWN(array->getOperationType() == CGOpCode::ArrayCreation)
2129 if (getLastUsageEvaluationOrder(*array) < last) {
2130 setLastUsageEvaluationOrder(*array, last);
2132 }
else if (op == CGOpCode::Tmp) {
2133 Node* declr = node.getArguments()[0].getOperation();
2134 CPPADCG_ASSERT_UNKNOWN(declr->getOperationType() == CGOpCode::TmpDcl)
2135 if (getLastUsageEvaluationOrder(*declr) < last) {
2136 setLastUsageEvaluationOrder(*declr, last);
2141 template<
class Base>
2146 template<
class Base>
2152 template<
class Base>
2153 inline void CodeHandler<Base>::increaseTotalUsageCount(
const Node& node) {
2157 template<
class Base>
2158 inline void CodeHandler<Base>::resetManagedNodes() {