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();
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();
159 assert(_idVisit < (std::numeric_limits<size_t>::max)());
179 typename std::map<size_t, CGAbstractAtomicFun<Base>*>::const_iterator it;
182 return it->second->atomic_name();
184 return std::string();
204 return _loops.getLoopName(
id);
208 inline const std::vector<typename CodeHandler<Base>::ScopePath>&
218 const std::string& jobName) {
226 std::vector<CGB>& dependent,
228 const std::string& jobName) {
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;
484 return _idArrayCount - 1;
489 return _idSparseArrayCount - 1;
498 _independentVariables.clear();
501 _idSparseArrayCount = 1;
525 return manageOperationNode(
new Node(n));
530 return manageOperationNode(
new Node(
this, op));
536 return manageOperationNode(
new Node(
this, op, arg));
541 std::vector<Arg>&& args) {
542 return manageOperationNode(
new Node(
this, op, std::move(args)));
547 std::vector<size_t>&& info,
548 std::vector<Arg>&& args) {
549 return manageOperationNode(
new Node(
this, op, std::move(info), std::move(args)));
554 const std::vector<size_t>& info,
555 const std::vector<Arg>& args) {
556 return manageOperationNode(
new Node(
this, op, info, args));
561 size_t iterationCount) {
563 manageOperationNode(n);
571 manageOperationNode(n);
577 const std::vector<Arg>& endArgs) {
579 manageOperationNode(n);
586 const std::string& after) {
588 manageOperationNode(n);
595 manageOperationNode(n);
602 manageOperationNode(n);
609 manageOperationNode(n);
618 manageOperationNode(n);
628 manageOperationNode(n);
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);
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);
696 if (sip->getType() == IndexPatternType::Random1D || sip->getType() == IndexPatternType::Random2D)
697 found.insert(static_cast<RandomIndexPattern*> (sip));
709 manageOperationNode(code);
743 auto& code = stackEl.node();
745 increaseTotalUsageCount(code);
748 if (isIndependent(code)) {
751 }
else if (op == CGOpCode::Alias) {
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;
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) {
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;
946 CGOpCode bNewOp = bScopeNewEnd->getOperationType();
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;
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>
1229 const size_t vsize = vorder.size();
1230 for (
size_t p = 0; p < vsize; p++) {
1231 Node* node = vorder[p];
1234 if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
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;
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>
1422 for (
size_t a = 0; a < args.size(); a++) {
1423 if (args[a].getOperation() == &arg) {
1430 template<
class Base>
1432 size_t id = atomic.
getId();
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)) {
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) {
1478 CPPADCG_ASSERT_UNKNOWN(arg.
getInfo().size() > 1)
1483 std::map<std::string, size_t>::const_iterator itName2Idx;
1493 pos = itName2Idx->second;
1496 if (aType == CGOpCode::AtomicForward) {
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();
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();
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();
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) {
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();
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);
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>
2056 template<
class Base>
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>
2083 template<
class Base>
2088 template<
class Base>
2102 template<
class Base>
2107 template<
class Base>
2114 template<
class Base>
2119 template<
class Base>
2126 if (op == CGOpCode::ArrayElement) {
2128 CPPADCG_ASSERT_UNKNOWN(array->
getOperationType() == CGOpCode::ArrayCreation)
2129 if (getLastUsageEvaluationOrder(*array) < last) {
2130 setLastUsageEvaluationOrder(*array, last);
2132 }
else if (op == CGOpCode::Tmp) {
2135 if (getLastUsageEvaluationOrder(*declr) < last) {
2136 setLastUsageEvaluationOrder(*declr, last);
2141 template<
class Base>
2146 template<
class Base>
2152 template<
class Base>
2157 template<
class Base>
virtual void markCodeBlockUsed(Node &code)
std::vector< int > _atomicFunctionsMaxReverse
Node * cloneNode(const Node &n)
void updateTemporaryVarInDiffScopes(Node &code)
std::vector< std::string > * _atomicFunctionsOrder
void reorderOperations(ArrayView< CGB > &dependent)
void deleteManagedNodes(size_t start, size_t end)
const std::vector< Argument< Base > > & getArguments() const
void findVariableDependencies()
CodeHandlerVector< Base, size_t > _lastVisit
void dependentAdded2EvaluationQueue(Node &node)
std::set< CodeHandlerVectorSync< Base > * > _managedVectors
const CodeHandlerVector< Base, size_t > & getVariablesIDs() const
bool manageOperationNodeMemory(Node *code)
const std::vector< Node * > & getManagedNodes() const
size_t getHandlerPosition() const
CodeHandlerVector< Base, size_t > _evaluationOrder
size_t findLastTemporaryLocation(Node &node)
std::vector< std::vector< Node * > > _scopedVariableOrder
std::map< std::string, size_t > _atomicFunctionName2Index
std::vector< int > _atomicFunctionsMaxForward
size_t findFirstDifferentScope(size_t color1, size_t color2)
CodeHandlerVector< Base, ScopeIDType > _scope
void determineLastTempVarUsage(Node &node)
size_t getIndependentVariableSize() const
const std::string * getLoopName(size_t id) const
const std::vector< int > & getExternalFuncMaxForwardOrder() const
CGOpCode getOperationType() const
virtual void setTemporaryVariableID(size_t minTempID, size_t maxTempID, size_t maxTempArrayID, size_t maxTempSparseArrayID)=0
void makeVariables(VectorCG &variables)
bool handleTemporaryVarInDiffScopes(Node &code, size_t oldScope, size_t newScope)
CodeHandlerVector< Base, size_t > _operationCount
const std::map< size_t, CGAbstractAtomicFun< Base > *> & getAtomicFunctions() const
size_t reserveArraySpace(const OperationNode< Base > &newArray)
void reorderOperation(Node &node)
std::string getAtomicFunctionName(size_t id) const
void makeVariable(AD< CGB > &variable)
std::vector< Node * > _variableOrder
std::map< size_t, CGAbstractAtomicFun< Base > * > _atomicFunctions
CodeHandlerVector< Base, size_t > _totalUseCount
void replaceWithConditionalTempVar(Node &tmp, IndexOperationNode< Base > &iterationIndexOp, const std::vector< size_t > &iterationRegions, ScopeIDType oldScope, ScopeIDType commonScopeColor)
size_t getManagedNodesCount() const
size_t getIndependentVariableIndex(const Node &var) const
void reduceTemporaryVariables(ArrayView< CGB > &dependent)
void setZeroDependents(bool zeroDependents)
std::vector< std::set< Node * > > _variableDependencies
size_t getTotalUsageCount(const Node &node) const
virtual bool requiresVariableDependencies() const =0
virtual void checkVariableCreation(Node &code)
IndexOperationNode< Base > * _auxIterationIndexOp
void setReuseVariableIDs(bool reuse)
const std::vector< int > & getExternalFuncMaxReverseOrder() const
size_t size() const noexcept
bool isZeroDependents() const
void restoreTemporaryVar(Node &tmp)
void setOperation(CGOpCode op, const std::vector< Argument< Base > > &arguments=std::vector< Argument< Base > >())
std::vector< Node * > _codeBlocks
virtual void generateCode(std::ostream &out, Language< Base > &lang, CppAD::vector< CGB > &dependent, VariableNameGenerator< Base > &nameGen, const std::string &jobName="source")
bool isReuseVariableIDs() const
CodeHandlerVector< Base, size_t > _varId
const std::vector< size_t > & getInfo() const
void breakCyclicDependency(Node *node, size_t scope, Node *endIf)
CodeHandlerVector< Base, size_t > _lastUsageOrder