1 #ifndef CPPAD_CG_CODE_HANDLER_IMPL_INCLUDED 2 #define CPPAD_CG_CODE_HANDLER_IMPL_INCLUDED 22 CodeHandler<Base>::CodeHandler(
size_t varCount) :
26 _idSparseArrayCount(1),
31 _evaluationOrder(*this),
32 _lastUsageOrder(*this),
33 _totalUseCount(*this),
35 _scopedVariableOrder(1),
36 _atomicFunctionsOrder(nullptr),
40 _currentScopeColor(0),
42 _minTemporaryVarID(0),
43 _zeroDependents(false),
59 v->handler_ =
nullptr;
75 for (
auto& v : variables) {
89 _independentVariables.push_back(makeNode(CGOpCode::Inv));
90 variable.makeVariable(*_independentVariables.back());
95 return _independentVariables.size();
142 typename std::vector<Node*>::const_iterator it =
143 std::find(_independentVariables.begin(), _independentVariables.end(), &var);
144 if (it == _independentVariables.end()) {
145 throw CGException(
"Variable not found in the independent variable vector");
148 return it - _independentVariables.begin();
158 assert(_idVisit < std::numeric_limits<size_t>::max());
178 typename std::map<size_t, CGAbstractAtomicFun<Base>*>::const_iterator it;
181 return &(it->second->afun_name());
203 return _loops.getLoopName(
id);
207 inline const std::vector<typename CodeHandler<Base>::ScopePath>&
217 const std::string& jobName) {
225 std::vector<CGB>& dependent,
227 const std::string& jobName) {
237 const std::string& jobName) {
238 std::vector<std::string> atomicFunctions;
239 generateCode(out, lang, dependent, nameGen, atomicFunctions, jobName);
247 std::vector<std::string>& atomicFunctions,
248 const std::string& jobName) {
250 generateCode(out, lang, deps, nameGen, atomicFunctions, jobName);
256 std::vector<CGB>& dependent,
258 std::vector<std::string>& atomicFunctions,
259 const std::string& jobName) {
261 generateCode(out, lang, deps, nameGen, atomicFunctions, jobName);
269 std::vector<std::string>& atomicFunctions,
270 const std::string& jobName) {
271 using namespace std::chrono;
272 steady_clock::time_point beginTime;
275 _jobTimer->startingJob(
"source for '" + jobName +
"'");
276 }
else if (_verbose) {
277 std::cout <<
"generating source for '" << jobName <<
"' ... ";
279 beginTime = steady_clock::now();
285 _idSparseArrayCount = 1;
287 _dependents = &dependent;
292 _loops.prepare4NewSourceGen();
293 _scopeColorCount = 0;
294 _currentScopeColor = 0;
297 _alteredNodes.clear();
304 for (
size_t i = 0; i < atomicFunctions.size(); i++) {
318 size_t n = _independentVariables.size();
319 for (
size_t j = 0; j < n; j++) {
320 _varId[*_independentVariables[j]] = _idCount++;
323 size_t m = dependent.
size();
324 for (
size_t i = 0; i < m; i++) {
325 Node* node = dependent[i].getOperationNode();
326 if (node !=
nullptr &&
_varId[*node] == 0) {
327 _varId[*node] = _idCount++;
331 _minTemporaryVarID = _idCount;
336 for (
size_t i = 0; i < m; i++) {
337 Node* node = dependent[i].getOperationNode();
338 if (node !=
nullptr) {
348 startNewOperationTreeVisit();
350 for (
size_t i = 0; i < m; i++) {
351 CGB& var = dependent[i];
352 if (var.getOperationNode() !=
nullptr) {
353 Node& code = *var.getOperationNode();
354 if (!isVisited(code)) {
361 if ((
_varId[code] == 0 || !isIndependent(code)) && !isVisited(code)) {
362 addToEvaluationQueue(code);
384 addScopeToVarOrder(0, e);
393 setEvaluationOrder(arg, p + 1);
412 nameGen.
setTemporaryVariableID(_minTemporaryVarID, _idCount - 1, _idArrayCount - 1, _idSparseArrayCount - 1);
414 std::map<std::string, size_t> atomicFunctionName2Id;
415 typename std::map<size_t, CGAbstractAtomicFun < Base>*>::iterator itA;
417 atomicFunctionName2Id[itA->second->afun_name()] = itA->first;
420 std::map<size_t, size_t> atomicFunctionId2Index;
421 std::map<size_t, std::string> atomicFunctionId2Name;
423 const std::string& atomicName = (*_atomicFunctionsOrder)[i];
424 std::map<std::string, size_t>::const_iterator it = atomicFunctionName2Id.find(atomicName);
425 if (it != atomicFunctionName2Id.end()) {
426 atomicFunctionId2Index[it->second] = i;
427 atomicFunctionId2Name[it->second] = atomicName;
437 atomicFunctionId2Index, atomicFunctionId2Name,
440 _loops.indexes, _loops.indexRandomPatterns,
441 _loops.dependentIndexPatterns, _loops.independentIndexPatterns,
444 lang.generateSourceCode(out,
_info);
452 for (
const auto& itAlt : _alteredNodes) {
453 Node* tmp = itAlt.first;
454 Node* opClone = itAlt.second;
460 _alteredNodes.clear();
464 }
else if (_verbose) {
466 duration<float> dt = steady_clock::now() - beginTime;
467 std::cout <<
"done [" << std::fixed << std::setprecision(3) << dt.count() <<
"]" << std::endl;
476 return _idCount - _minTemporaryVarID;
481 return _idArrayCount - 1;
486 return _idSparseArrayCount - 1;
495 _independentVariables.clear();
498 _idSparseArrayCount = 1;
521 return manageOperationNode(
new Node(n));
526 return manageOperationNode(
new Node(
this, op));
532 return manageOperationNode(
new Node(
this, op, arg));
537 std::vector<Arg>&& args) {
538 return manageOperationNode(
new Node(
this, op, std::move(args)));
543 std::vector<size_t>&& info,
544 std::vector<Arg>&& args) {
545 return manageOperationNode(
new Node(
this, op, std::move(info), std::move(args)));
550 const std::vector<size_t>& info,
551 const std::vector<Arg>& args) {
552 return manageOperationNode(
new Node(
this, op, info, args));
557 size_t iterationCount) {
559 manageOperationNode(n);
567 manageOperationNode(n);
573 const std::vector<Arg>& endArgs) {
575 manageOperationNode(n);
582 const std::string& after) {
584 manageOperationNode(n);
591 manageOperationNode(n);
598 manageOperationNode(n);
605 manageOperationNode(n);
614 manageOperationNode(n);
624 manageOperationNode(n);
630 CPPADCG_ASSERT_KNOWN(!name.empty(),
"index name cannot be empty");
631 auto* n = manageOperationNode(
new Node(
this, CGOpCode::IndexDeclaration));
651 start = std::min<size_t>(start,
_codeBlocks.size());
654 for (
size_t i = start; i < end; ++i) {
660 for (
size_t i = start; i <
_codeBlocks.size(); ++i) {
665 v->nodesErased(start, end);
682 std::set<RandomIndexPattern*>& found) {
686 if (ip->getType() == IndexPatternType::Random1D || ip->getType() == IndexPatternType::Random2D) {
687 found.insert(static_cast<RandomIndexPattern*> (ip));
689 std::set<IndexPattern*> indexes;
690 ip->getSubIndexes(indexes);
692 if (sip->getType() == IndexPatternType::Random1D || sip->getType() == IndexPatternType::Random2D)
693 found.insert(static_cast<RandomIndexPattern*> (sip));
705 manageOperationNode(code);
735 increaseTotalUsageCount(code);
738 if (isIndependent(code)) {
740 }
else if (op == CGOpCode::Alias) {
745 CPPADCG_ASSERT_UNKNOWN(code.
getArguments().size() == 1);
747 if (arg !=
nullptr) {
754 size_t previousScope = _currentScopeColor;
756 _scope[code] = _currentScopeColor;
759 if (op == CGOpCode::LoopStart || op == CGOpCode::StartIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
761 ScopePath& sPath = _scopes[_currentScopeColor];
762 CPPADCG_ASSERT_UNKNOWN(sPath.back().beginning ==
nullptr);
763 if (op == CGOpCode::LoopStart || op == CGOpCode::StartIf) {
764 sPath.back().beginning = &code;
768 code.
getArguments()[0].getOperation()->getOperationType() == CGOpCode::StartIf);
769 sPath.back().beginning = code.
getArguments()[0].getOperation();
771 _currentScopeColor = sPath.size() > 1 ? sPath[sPath.size() - 2].color : 0;
774 if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
776 _currentScopeColor = ++_scopeColorCount;
778 _scopes.resize(_currentScopeColor + 1);
779 _scopes[_currentScopeColor] = _scopes[previousScope];
782 if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf) {
790 if (op == CGOpCode::LoopEnd) {
791 _loops.addLoopEndNode(code);
799 if (it.getOperation() !=
nullptr) {
804 if (op == CGOpCode::Index) {
807 if (inode.isDefinedLocally()) {
808 _loops.indexes.insert(&inode.getIndex());
810 }
else if (op == CGOpCode::LoopIndexedIndep || op == CGOpCode::LoopIndexedDep || op == CGOpCode::IndexAssign) {
812 if (op == CGOpCode::LoopIndexedDep) {
813 size_t pos = code.
getInfo()[0];
814 ip = _loops.dependentIndexPatterns[pos];
815 }
else if (op == CGOpCode::LoopIndexedIndep) {
816 size_t pos = code.
getInfo()[1];
817 ip = _loops.independentIndexPatterns[pos];
822 findRandomIndexPatterns(ip, _loops.indexRandomPatterns);
824 }
else if (op == CGOpCode::DependentRefRhs) {
825 CPPADCG_ASSERT_UNKNOWN(code.
getInfo().size() == 1);
826 size_t depIndex = code.
getInfo()[0];
828 CPPADCG_ASSERT_UNKNOWN(_dependents->size() > depIndex);
829 Node* depNode = (*_dependents)[depIndex].getOperationNode();
830 CPPADCG_ASSERT_UNKNOWN(depNode !=
nullptr && depNode->getOperationType() != CGOpCode::Inv);
832 _varId[code] = _varId[*depNode];
838 if (previousScope != _currentScopeColor) {
839 _currentScopeColor = previousScope;
845 if (op == CGOpCode::Tmp && !code.
getInfo().empty()) {
851 if (
_scope[code] == _currentScopeColor) {
858 }
else if (
_scope[code] != _currentScopeColor && op != CGOpCode::LoopIndexedIndep) {
859 ScopeIDType oldScope =
_scope[code];
868 ScopeIDType newScope;
872 newScope = _scopes[_currentScopeColor][depth - 1].color;
874 if (oldScope != newScope) {
887 size_t aSize = args.size();
888 for (
size_t a = 0; a < aSize; a++) {
889 updateVarScopeUsage(args[a].getOperation(), newScope, oldScope);
901 if (_currentScopeColor == 0)
907 CPPADCG_ASSERT_KNOWN(code.
getOperationType() != CGOpCode::ArrayCreation,
"Not supported yet");
908 CPPADCG_ASSERT_KNOWN(code.
getOperationType() != CGOpCode::SparseArrayCreation,
"Not supported yet");
913 std::vector<size_t> iterationRegions;
914 Node* bScopeNewEnd = _scopes[_currentScopeColor].back().end;
915 Node* bScopeOldEnd = _scopes[oldScope].back().end;
920 if ((bNewOp == CGOpCode::EndIf || bNewOp == CGOpCode::Else || bNewOp == CGOpCode::ElseIf) &&
921 (bOldOp == CGOpCode::EndIf || bOldOp == CGOpCode::Else || bOldOp == CGOpCode::ElseIf)) {
931 iterationRegions = ifBranchIterationRanges(bScopeNew, newIterIndexOp);
932 CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2);
935 std::vector<size_t> oldIterRegions = ifBranchIterationRanges(bScopeOld, oldIterIndexOp);
936 combineOverlapingIterationRanges(iterationRegions, oldIterRegions);
937 CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2);
938 CPPADCG_ASSERT_UNKNOWN(newIterIndexOp !=
nullptr && newIterIndexOp == oldIterIndexOp);
940 if (iterationRegions.size() > 2 ||
941 iterationRegions[0] != 0 ||
942 iterationRegions[1] != std::numeric_limits<size_t>::max()) {
956 const std::vector<size_t>& iterationRegions,
957 ScopeIDType oldScope,
958 ScopeIDType commonScopeColor) {
967 Node* tmpDclVar = makeNode(CGOpCode::TmpDcl);
968 Arg tmpArg(*tmpDclVar);
970 Node* cond = makeNode(CGOpCode::IndexCondExpr, iterationRegions, {iterationIndexOp});
973 Node* ifStart = makeNode(CGOpCode::StartIf, *cond);
975 Node* tmpAssign = makeNode(CGOpCode::LoopIndexedTmp, {tmpArg, *opClone});
976 Node* ifAssign = makeNode(CGOpCode::CondResult, {*ifStart, *tmpAssign});
979 Node* endIf = makeNode(CGOpCode::EndIf, {*ifStart, *ifAssign});
999 size_t newScopeColor = ++_scopeColorCount;
1000 _scopes.resize(newScopeColor + 1);
1001 _scopes[newScopeColor] = _scopes[commonScopeColor];
1007 _scope[*tmpDclVar] = commonScopeColor;
1008 _scope[*ifStart] = newScopeColor;
1009 _scope[*cond] = newScopeColor;
1010 _scope[*opClone] = newScopeColor;
1011 _scope[*ifAssign] = newScopeColor;
1012 _scope[*tmpAssign] = newScopeColor;
1013 _scope[*endIf] = commonScopeColor;
1014 _scope[tmp] = commonScopeColor;
1017 setTotalUsageCount(*tmpDclVar, 1);
1018 setTotalUsageCount(*ifStart, 1);
1019 setTotalUsageCount(*cond, 1);
1020 setTotalUsageCount(*opClone, 1);
1021 setTotalUsageCount(*ifAssign, 1);
1022 setTotalUsageCount(*tmpAssign, 1);
1023 setTotalUsageCount(*endIf, 1);
1028 const std::vector<Arg>& cargs = opClone->
getArguments();
1029 size_t aSize = cargs.size();
1030 for (
size_t a = 0; a < aSize; a++) {
1031 updateVarScopeUsage(cargs[a].getOperation(), newScopeColor, oldScope);
1034 _alteredNodes.push_back(std::make_pair(&tmp, opClone));
1037 template<
class Base>
1039 if (
_scope[code] != _currentScopeColor) {
1046 if (_currentScopeColor == 0)
1054 ScopeIDType oldScope =
_scope[code];
1059 ScopeIDType newScope = depth == 0 ? 0 : _scopes[_currentScopeColor][depth - 1].color;
1064 std::vector<size_t> iterationRegions;
1065 Node* bScopeNewEnd = _scopes[_currentScopeColor].back().end;
1068 Node* bScopeOldEnd = _scopes[
_scope[*endif]].back().end;
1072 if (bNewOp == CGOpCode::EndIf || bNewOp == CGOpCode::Else || bNewOp == CGOpCode::ElseIf) {
1082 iterationRegions = ifBranchIterationRanges(bScopeNew, newIterIndexOp);
1083 CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2);
1086 const std::vector<size_t> oldIterRegions = ifBranchIterationRanges(bScopeOld, oldIterIndexOp);
1087 combineOverlapingIterationRanges(iterationRegions, oldIterRegions);
1088 CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2);
1089 CPPADCG_ASSERT_UNKNOWN(newIterIndexOp !=
nullptr && newIterIndexOp == oldIterIndexOp);
1091 if (iterationRegions.size() == 2 &&
1092 (iterationRegions[0] == 0 ||
1093 iterationRegions[1] == std::numeric_limits<size_t>::max())) {
1098 }
else if (oldIterRegions != iterationRegions) {
1100 CPPADCG_ASSERT_UNKNOWN(cond->
getOperationType() == CGOpCode::IndexCondExpr);
1101 cond->
getInfo() = iterationRegions;
1106 if (oldScope != newScope) {
1112 size_t aSize = cargs.size();
1113 for (
size_t a = 0; a < aSize; a++) {
1114 updateVarScopeUsage(cargs[a].getOperation(), newScope, oldScope);
1120 template<
class Base>
1131 _scope[tmp] = _currentScopeColor;
1137 size_t aSize = args.size();
1138 for (
size_t a = 0; a < aSize; a++) {
1139 updateVarScopeUsage(args[a].getOperation(), _currentScopeColor,
_scope[*opClone]);
1143 template<
class Base>
1151 _scope[*tmp] = _currentScopeColor;
1157 size_t aSize = args.size();
1158 for (
size_t a = 0; a < aSize; a++) {
1159 updateVarScopeUsage(args[a].getOperation(), _currentScopeColor,
_scope[*opClone]);
1163 template<
class Base>
1165 ScopeIDType usageScope,
1166 ScopeIDType oldUsageScope) {
1167 if (node ==
nullptr ||
_scope[*node] == usageScope)
1171 ScopeIDType oldScope =
_scope[*node];
1172 ScopeIDType newScope;
1174 if (oldScope == oldUsageScope) {
1175 newScope = usageScope;
1179 newScope = (depth == 0) ? 0 : _scopes[usageScope][depth - 1].color;
1182 if (newScope == oldScope)
1185 _scope[*node] = newScope;
1188 size_t aSize = args.size();
1189 for (
size_t a = 0; a < aSize; a++) {
1190 updateVarScopeUsage(args[a].getOperation(), newScope, oldScope);
1194 template<
class Base>
1199 const size_t vsize = vorder.size();
1200 for (
size_t p = 0; p < vsize; p++) {
1201 Node* node = vorder[p];
1204 if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
1208 CPPADCG_ASSERT_UNKNOWN(beginScopeNode !=
nullptr);
1210 addScopeToVarOrder(
_scope[*beginScopeNode], e);
1218 template<
class Base>
1221 CPPADCG_ASSERT_UNKNOWN(color1 < _scopes.size());
1222 CPPADCG_ASSERT_UNKNOWN(color2 < _scopes.size());
1224 ScopePath& scopePath1 = _scopes[color1];
1225 ScopePath& scopePath2 = _scopes[color2];
1227 size_t s1 = scopePath1.size();
1228 size_t s2 = scopePath2.size();
1230 for (depth = 0; depth < s1 && depth < s2; depth++) {
1231 if (scopePath1[depth].color != scopePath2[depth].color) {
1239 template<
class Base>
1247 for (
long p = vorder.size() - 1; p > 0; p--) {
1248 Node* endIf = vorder[p];
1254 if (vorder[p1]->getOperationType() == CGOpCode::TmpDcl) {
1260 Node* endIf1 = vorder[p1];
1281 ScopeIDType ifScope =
_scope[*startIf];
1282 ScopeIDType ifScope1 =
_scope[*startIf1];
1286 startNewOperationTreeVisit();
1289 for (
size_t a = 1; a < eArgs.size(); a++) {
1290 CPPADCG_ASSERT_UNKNOWN(eArgs[a].getOperation() !=
nullptr && eArgs[a].getOperation()->getOperationType() == CGOpCode::CondResult);
1292 replaceScope(eArgs[a].getOperation(), ifScope, ifScope1);
1295 vorderIf1.insert(vorderIf1.end(), vorderIf.begin() + 1, vorderIf.end());
1300 for (
size_t a = 1; a < eArgs.size(); a++) {
1301 CPPADCG_ASSERT_UNKNOWN(eArgs[a].getOperation() !=
nullptr && eArgs[a].getOperation()->getOperationType() == CGOpCode::CondResult);
1302 eArgs[a].getOperation()->getArguments()[0] =
Arg(*startIf1);
1306 eArgs1.insert(eArgs1.end(), eArgs.begin() + 1, eArgs.end());
1312 vorder.erase(vorder.begin() + p);
1315 for (
long pp = p1; pp < p - 1; pp++) {
1316 vorder[pp] = vorder[pp + 1];
1318 vorder[p - 1] = endIf1;
1324 template<
class Base>
1326 ScopeIDType oldScope,
1327 ScopeIDType newScope) {
1328 if (node ==
nullptr ||
_scope[*node] != oldScope)
1331 _scope[*node] = newScope;
1334 for (
size_t a = 0; a < args.size(); a++) {
1335 replaceScope(args[a].getOperation(), oldScope, newScope);
1339 template<
class Base>
1343 if (node ==
nullptr || isVisited(*node))
1351 if (op == CGOpCode::Tmp && args.size() > 1) {
1352 Node* arg = args[1].getOperation();
1356 args.erase(args.begin() + 1);
1360 if (!containedInScope(*node, scope)) {
1364 for (
size_t a = 0; a < args.size(); a++) {
1365 Node* arg = args[a].getOperation();
1367 if (op == CGOpCode::StartIf || op == CGOpCode::LoopStart) {
1368 args.erase(args.begin() + a);
1377 template<
class Base>
1379 ScopeIDType scope) {
1380 ScopeIDType nScope =
_scope[node];
1381 if (nScope == scope)
1384 return _scopes[nScope].size() >= _scopes[scope].size() &&
1385 _scopes[nScope][_scopes[scope].size() - 1].color == scope;
1388 template<
class Base>
1392 for (
size_t a = 0; a < args.size(); a++) {
1393 if (args[a].getOperation() == &arg) {
1400 template<
class Base>
1402 size_t id = atomic.
getId();
1407 }
else if(it->second != &atomic) {
1408 throw CGException(
"The same atomic function ID (",
id,
") is being used for different atomic functions: '",
1409 atomic.afun_name(),
"' (", &atomic,
") and '", it->second->afun_name(),
"' (", it->second,
").");
1413 template<
class Base>
1417 size_t aSize = args.size();
1418 for (
size_t argIndex = 0; argIndex < aSize; argIndex++) {
1419 if (args[argIndex].getOperation() ==
nullptr) {
1423 Node& arg = *args[argIndex].getOperation();
1426 if (!isVisited(arg)) {
1430 if (aType == CGOpCode::LoopEnd || aType == CGOpCode::ElseIf || aType == CGOpCode::Else || aType == CGOpCode::EndIf) {
1433 _varId[arg] = std::numeric_limits<size_t>::max();
1435 }
else if (aType == CGOpCode::AtomicForward || aType == CGOpCode::AtomicReverse) {
1440 CPPADCG_ASSERT_UNKNOWN(arg.
getInfo().size() > 1);
1445 std::map<std::string, size_t>::const_iterator itName2Idx;
1455 pos = itName2Idx->second;
1458 if (aType == CGOpCode::AtomicForward) {
1472 if (
_varId[arg] == 0 || !isIndependent(arg)) {
1473 if (aType == CGOpCode::LoopIndexedIndep) {
1475 _varId[arg] = std::numeric_limits<size_t>::max();
1476 }
else if (aType == CGOpCode::Alias) {
1478 }
else if (aType == CGOpCode::Tmp) {
1479 _varId[arg] = std::numeric_limits<size_t>::max();
1480 }
else if (aType == CGOpCode::LoopStart ||
1481 aType == CGOpCode::LoopEnd ||
1482 aType == CGOpCode::StartIf ||
1483 aType == CGOpCode::ElseIf ||
1484 aType == CGOpCode::Else ||
1485 aType == CGOpCode::EndIf) {
1490 addToEvaluationQueue(arg);
1493 _varId[arg] = std::numeric_limits<size_t>::max();
1495 }
else if (aType == CGOpCode::Pri) {
1496 addToEvaluationQueue(arg);
1499 _varId[arg] = std::numeric_limits<size_t>::max();
1501 }
else if (aType == CGOpCode::TmpDcl) {
1502 addToEvaluationQueue(arg);
1510 addToEvaluationQueue(arg);
1513 if (aType == CGOpCode::AtomicForward || aType == CGOpCode::AtomicReverse) {
1514 _varId[arg] = _idAtomicCount;
1516 }
else if (aType == CGOpCode::LoopIndexedDep || aType == CGOpCode::LoopIndexedTmp) {
1518 _varId[arg] = std::numeric_limits<size_t>::max();
1519 }
else if (aType == CGOpCode::ArrayCreation) {
1522 _varId[arg] = _idArrayCount;
1523 _idArrayCount += arraySize;
1524 }
else if (aType == CGOpCode::SparseArrayCreation) {
1527 _varId[arg] = _idSparseArrayCount;
1528 _idSparseArrayCount += nnz;
1546 template<
class Base>
1548 ScopeIDType scope =
_scope[arg];
1555 _scopes[scope].back().end->getArguments()[0].getOperation() != &arg) {
1563 if (varOrder.size() == varOrder.capacity()) {
1564 varOrder.reserve((varOrder.size() * 3) / 2 + 1);
1567 varOrder.push_back(&arg);
1570 template<
class Base>
1578 startNewOperationTreeVisit();
1580 for (
size_t i = 0; i < dependent.
size(); i++) {
1581 Node* node = dependent[i].getOperationNode();
1582 if (node !=
nullptr) {
1583 if (!isVisited(*node)) {
1592 std::vector<std::vector<Node*>> tempVarRelease(
_variableOrder.size());
1595 if (isTemporary(*var) || isTemporaryArray(*var) || isTemporarySparseArray(*var)) {
1596 size_t releaseLocation = getLastUsageEvaluationOrder(*var) - 1;
1597 tempVarRelease[releaseLocation].push_back(var);
1605 std::vector<size_t> freedVariables;
1606 _idCount = _minTemporaryVarID;
1613 const std::vector<Node*>& released = tempVarRelease[i];
1614 for (
size_t r = 0; r < released.size(); r++) {
1615 if (isTemporary(*released[r])) {
1616 freedVariables.push_back(
_varId[*released[r]]);
1617 }
else if (isTemporaryArray(*released[r])) {
1618 arrayComp.addFreeArraySpace(*released[r]);
1619 }
else if (isTemporarySparseArray(*released[r])) {
1620 sparseArrayComp.addFreeArraySpace(*released[r]);
1624 if (isTemporary(var)) {
1626 if (freedVariables.empty()) {
1630 size_t id = freedVariables.back();
1631 freedVariables.pop_back();
1634 }
else if (isTemporaryArray(var)) {
1637 _varId[var] = arrayStart + 1;
1638 }
else if (isTemporarySparseArray(var)) {
1641 _varId[var] = arrayStart + 1;
1646 _idArrayCount = arrayComp.getIdCount();
1647 _idSparseArrayCount = sparseArrayComp.getIdCount();
1650 template<
class Base>
1653 startNewOperationTreeVisit();
1656 for (
size_t i = 0; i < dependent.
size(); ++i) {
1657 Node* node = dependent[i].getOperationNode();
1658 if (node !=
nullptr) {
1665 const std::vector<Arg>& args = endNode->
getArguments();
1666 for (
size_t i = 1; i < args.size(); ++i) {
1667 CPPADCG_ASSERT_UNKNOWN(args[i].getOperation() !=
nullptr);
1669 if (args[i].getOperation()->getOperationType() == CGOpCode::LoopIndexedDep) {
1676 template<
class Base>
1681 size_t depPos = getEvaluationOrder(node);
1682 size_t lastTmpPos = depPos;
1683 if (!isVisited(node)) {
1692 if (lastTmpPos == depPos || lastTmpPos + 1 == depPos) {
1697 bool foundTemporaries =
false;
1699 for (
size_t l = lastTmpPos + 1; l < depPos; ++l) {
1701 if (isTemporary(*n) || isTemporaryArray(*n) || isTemporarySparseArray(*n)) {
1702 foundTemporaries =
true;
1709 CGOpCode op = n->getOperationType();
1710 if (op == CGOpCode::StartIf) {
1713 while (l < depPos) {
1715 if (node2->getOperationType() == CGOpCode::EndIf &&
1716 node2->getArguments()[0].getOperation() == n) {
1722 }
else if (op == CGOpCode::LoopStart) {
1725 while (l < depPos) {
1727 if (node2->getOperationType() == CGOpCode::LoopEnd &&
1737 if (foundTemporaries) {
1739 repositionEvaluationQueue(depPos, newPos);
1743 template<
class Base>
1745 size_t depOrder = getEvaluationOrder(node);
1746 size_t maxTmpOrder = 0;
1747 for (
const Arg& it : node) {
1748 if (it.getOperation() !=
nullptr) {
1749 Node& arg = *it.getOperation();
1751 if (aOp == CGOpCode::LoopEnd || aOp == CGOpCode::EndIf || aOp == CGOpCode::ElseIf || aOp == CGOpCode::Else) {
1755 if (aOp == CGOpCode::Index) {
1757 if (iorder > maxTmpOrder)
1758 maxTmpOrder = iorder;
1759 }
else if (getEvaluationOrder(arg) == depOrder) {
1762 if (orderNew > maxTmpOrder)
1763 maxTmpOrder = orderNew;
1766 if (getEvaluationOrder(arg) > maxTmpOrder)
1767 maxTmpOrder = getEvaluationOrder(arg);
1772 return maxTmpOrder == 0 ? depOrder : maxTmpOrder;
1775 template<
class Base>
1779 CPPADCG_ASSERT_UNKNOWN(fromPos > toPos);
1783 for (
size_t l = fromPos - 1; l > toPos - 1; --l) {
1789 updateEvaluationQueueOrder(*node, toPos);
1792 template<
class Base>
1796 if (op == CGOpCode::LoopEnd) {
1799 _loops.outerVars.resize(_loops.depth + 1);
1800 _loops.startEvalOrder.push_back(getEvaluationOrder(loopEnd.getLoopStart()));
1802 }
else if (op == CGOpCode::LoopStart) {
1810 if (it.getOperation() !=
nullptr) {
1811 Node& arg = *it.getOperation();
1813 if (!isVisited(arg)) {
1820 size_t order = getEvaluationOrder(node);
1821 Node* aa = getOperationFromAlias(arg);
1822 if (aa !=
nullptr) {
1823 if (getLastUsageEvaluationOrder(*aa) < order) {
1824 setLastUsageEvaluationOrder(*aa, order);
1827 if (_loops.depth >= 0 &&
1828 getEvaluationOrder(*aa) < _loops.startEvalOrder[_loops.depth] &&
1831 _loops.outerVars[_loops.depth].insert(aa);
1837 if (op == CGOpCode::LoopEnd) {
1842 size_t order = getEvaluationOrder(node);
1844 const std::set<Node*>& outerLoopUsages = _loops.outerVars.back();
1845 for (
Node* outerVar : outerLoopUsages) {
1846 Node* aa = getOperationFromAlias(*outerVar);
1847 if (aa !=
nullptr && getLastUsageEvaluationOrder(*aa) < order)
1848 setLastUsageEvaluationOrder(*aa, order);
1852 _loops.outerVars.pop_back();
1853 _loops.startEvalOrder.pop_back();
1855 }
else if (op == CGOpCode::LoopStart) {
1861 template<
class Base>
1864 if (a.getOperation() !=
nullptr) {
1865 Node& arg = *a.getOperation();
1866 if (getEvaluationOrder(arg) == 0) {
1867 setEvaluationOrder(arg, getEvaluationOrder(node));
1874 template<
class Base>
1876 size_t newEvalOrder) {
1877 size_t oldEvalOrder = getEvaluationOrder(node);
1879 setEvaluationOrder(node, newEvalOrder);
1882 if (a.getOperation() !=
nullptr) {
1883 Node& arg = *a.getOperation();
1884 if (getEvaluationOrder(arg) == oldEvalOrder)
1885 updateEvaluationQueueOrder(arg, newEvalOrder);
1890 template<
class Base>
1898 startNewOperationTreeVisit();
1900 for (
const auto& a : var) {
1901 if (a.getOperation() !=
nullptr) {
1908 template<
class Base>
1911 if (!isVisited(node)) {
1917 for (
const auto& a : node) {
1918 if (a.getOperation() !=
nullptr) {
1926 template<
class Base>
1931 template<
class Base>
1934 return op != CGOpCode::ArrayCreation &&
1935 op != CGOpCode::SparseArrayCreation &&
1936 op != CGOpCode::AtomicForward &&
1937 op != CGOpCode::AtomicReverse &&
1938 op != CGOpCode::LoopStart &&
1939 op != CGOpCode::LoopEnd &&
1940 op != CGOpCode::StartIf &&
1941 op != CGOpCode::ElseIf &&
1942 op != CGOpCode::Else &&
1943 op != CGOpCode::EndIf &&
1944 op != CGOpCode::LoopIndexedDep &&
1945 op != CGOpCode::LoopIndexedIndep &&
1946 op != CGOpCode::LoopIndexedTmp &&
1947 op != CGOpCode::Index &&
1948 op != CGOpCode::IndexAssign &&
1949 op != CGOpCode::Tmp &&
1950 _varId[arg] >= _minTemporaryVarID;
1953 template<
class Base>
1958 template<
class Base>
1963 template<
class Base>
1970 CPPADCG_ASSERT_UNKNOWN(aa->
getArguments().size() == 1);
1977 template<
class Base>
1982 template<
class Base>
1989 template<
class Base>
1994 template<
class Base>
2001 if (op == CGOpCode::ArrayElement) {
2003 CPPADCG_ASSERT_UNKNOWN(array->
getOperationType() == CGOpCode::ArrayCreation);
2004 if (getLastUsageEvaluationOrder(*array) < last) {
2005 setLastUsageEvaluationOrder(*array, last);
2007 }
else if (op == CGOpCode::Tmp) {
2010 if (getLastUsageEvaluationOrder(*declr) < last) {
2011 setLastUsageEvaluationOrder(*declr, last);
2016 template<
class Base>
2021 template<
class Base>
2027 template<
class Base>
2032 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
const std::string * getAtomicFunctionName(size_t id) const
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
std::unique_ptr< LanguageGenerationData< Base > > _info
void makeVariables(VectorCG &variables)
bool handleTemporaryVarInDiffScopes(Node &code, size_t oldScope, size_t newScope)
const std::map< size_t, CGAbstractAtomicFun< Base > *> & getAtomicFunctions() const
size_t reserveArraySpace(const OperationNode< Base > &newArray)
void reorderOperation(Node &node)
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