CppADCodeGen  HEAD
A C++ Algorithmic Differentiation Package with Source Code Generation
code_handler_impl.hpp
1 #ifndef CPPAD_CG_CODE_HANDLER_IMPL_INCLUDED
2 #define CPPAD_CG_CODE_HANDLER_IMPL_INCLUDED
3 /* --------------------------------------------------------------------------
4  * CppADCodeGen: C++ Algorithmic Differentiation with Source Code Generation:
5  * Copyright (C) 2016 Ciengis
6  * Copyright (C) 2019 Joao Leal
7  *
8  * CppADCodeGen is distributed under multiple licenses:
9  *
10  * - Eclipse Public License Version 1.0 (EPL1), and
11  * - GNU General Public License Version 3 (GPL3).
12  *
13  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
14  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
15  * ----------------------------------------------------------------------------
16  * Author: Joao Leal
17  */
18 
19 namespace CppAD {
20 namespace cg {
21 
22 template<class Base>
23 CodeHandler<Base>::CodeHandler(size_t varCount) :
24  _idVisit(1),
25  _idCount(1),
26  _idArrayCount(1),
27  _idSparseArrayCount(1),
28  _idAtomicCount(1),
29  _dependents(nullptr),
30  _lastVisit(*this),
31  _scope(*this),
32  _evaluationOrder(*this),
33  _lastUsageOrder(*this),
34  _totalUseCount(*this),
35  _operationCount(*this),
36  _varId(*this),
37  _scopedVariableOrder(1),
38  _atomicFunctionsOrder(nullptr),
39  _used(false),
40  _reuseIDs(true),
41  _scopeColorCount(0),
42  _currentScopeColor(0),
43  _lang(nullptr),
44  _minTemporaryVarID(0),
45  _zeroDependents(false),
46  _verbose(false),
47  _jobTimer(nullptr) {
48  _codeBlocks.reserve(varCount);
49  //_variableOrder.reserve(1 + varCount / 3);
50  _scopedVariableOrder[0].reserve(1 + varCount / 3);
51 
52  _auxIndexI = makeIndexDclrNode("i");
53  _auxIterationIndexOp = makeIndexNode(*_auxIndexI);
54 }
55 
56 template<class Base>
58  reset();
59 
60  for (auto* v : _managedVectors) {
61  v->handler_ = nullptr;
62  }
63 }
64 
65 template<class Base>
66 inline void CodeHandler<Base>::setReuseVariableIDs(bool reuse) {
67  _reuseIDs = reuse;
68 }
69 
70 template<class Base>
72  return _reuseIDs;
73 }
74 
75 template<class Base>
76 inline void CodeHandler<Base>::makeVariables(std::vector<AD<CGB> >& variables) {
77  for (auto& v : variables) {
78  makeVariable(v);
79  }
80 }
81 
82 template<class Base>
83 inline void CodeHandler<Base>::makeVariable(AD<CGB>& variable) {
84  CGB v;
85  makeVariable(v); // make it a codegen variable
86  variable = v; // variable id now the same as v
87 }
88 
89 template<class Base>
90 inline void CodeHandler<Base>::makeVariable(CGB& variable) {
91  _independentVariables.push_back(makeNode(CGOpCode::Inv));
92  variable.makeVariable(*_independentVariables.back());
93 }
94 
95 template<class Base>
97  return _independentVariables.size();
98 }
99 
100 template<class Base>
102  return _varId;
103 }
104 
105 template<class Base>
106 inline size_t CodeHandler<Base>::getMaximumVariableID() const {
107  return _idCount;
108 }
109 
110 template<class Base>
111 inline bool CodeHandler<Base>::isVerbose() const {
112  return _verbose;
113 }
114 
115 template<class Base>
116 inline void CodeHandler<Base>::setVerbose(bool verbose) {
117  _verbose = verbose;
118 }
119 
120 template<class Base>
122  return _jobTimer;
123 }
124 
125 template<class Base>
126 inline void CodeHandler<Base>::setJobTimer(JobTimer* jobTimer) {
127  _jobTimer = jobTimer;
128 }
129 
130 template<class Base>
132  return _zeroDependents;
133 }
134 
135 template<class Base>
136 inline void CodeHandler<Base>::setZeroDependents(bool zeroDependents) {
137  _zeroDependents = zeroDependents;
138 }
139 
140 template<class Base>
142  CPPADCG_ASSERT_UNKNOWN(var.getOperationType() == CGOpCode::Inv);
143 
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");
147  }
148 
149  return it - _independentVariables.begin();
150 }
151 
152 template<class Base>
153 inline size_t CodeHandler<Base>::getOperationTreeVisitId() const {
154  return _idVisit;
155 }
156 
157 template<class Base>
159  assert(_idVisit < (std::numeric_limits<size_t>::max)());
160 
161  _lastVisit.adjustSize();
162  _idVisit++;
163 }
164 
165 template<class Base>
166 inline bool CodeHandler<Base>::isVisited(const Node& node) const {
167  size_t p = node.getHandlerPosition();
168  return p < _lastVisit.size() && _lastVisit[node] == _idVisit;
169 }
170 
171 template<class Base>
172 inline void CodeHandler<Base>::markVisited(const Node& node) {
173  _lastVisit.adjustSize(node);
174  _lastVisit[node] = _idVisit;
175 }
176 
177 template<class Base>
178 inline std::string CodeHandler<Base>::getAtomicFunctionName(size_t id) const {
179  typename std::map<size_t, CGAbstractAtomicFun<Base>*>::const_iterator it;
180  it = _atomicFunctions.find(id);
181  if (it != _atomicFunctions.end())
182  return it->second->atomic_name();
183  else
184  return std::string();
185 }
186 
187 template<class Base>
188 inline const std::map<size_t, CGAbstractAtomicFun<Base>* >& CodeHandler<Base>::getAtomicFunctions() const {
189  return _atomicFunctions;
190 }
191 
192 template<class Base>
193 const std::vector<int>& CodeHandler<Base>::getExternalFuncMaxForwardOrder() const {
195 }
196 
197 template<class Base>
198 const std::vector<int>& CodeHandler<Base>::getExternalFuncMaxReverseOrder() const {
200 }
201 
202 template<class Base>
203 inline const std::string* CodeHandler<Base>::getLoopName(size_t id) const {
204  return _loops.getLoopName(id);
205 }
206 
207 template<class Base>
208 inline const std::vector<typename CodeHandler<Base>::ScopePath>&
210  return _scopes;
211 }
212 
213 template<class Base>
214 void CodeHandler<Base>::generateCode(std::ostream& out,
215  Language<Base>& lang,
216  CppAD::vector<CGB>& dependent,
218  const std::string& jobName) {
219  ArrayView<CGB> deps(dependent);
220  generateCode(out, lang, deps, nameGen, jobName);
221 }
222 
223 template<class Base>
224 void CodeHandler<Base>::generateCode(std::ostream& out,
225  Language<Base>& lang,
226  std::vector<CGB>& dependent,
228  const std::string& jobName) {
229  ArrayView<CGB> deps(dependent);
230  generateCode(out, lang, deps, nameGen, jobName);
231 }
232 
233 template<class Base>
234 void CodeHandler<Base>::generateCode(std::ostream& out,
235  Language<Base>& lang,
236  ArrayView<CGB>& dependent,
238  const std::string& jobName) {
239  std::vector<std::string> atomicFunctions;
240  generateCode(out, lang, dependent, nameGen, atomicFunctions, jobName);
241 }
242 
243 template<class Base>
244 void CodeHandler<Base>::generateCode(std::ostream& out,
245  Language<Base>& lang,
246  CppAD::vector<CGB>& dependent,
248  std::vector<std::string>& atomicFunctions,
249  const std::string& jobName) {
250  ArrayView<CGB> deps(dependent);
251  generateCode(out, lang, deps, nameGen, atomicFunctions, jobName);
252 }
253 
254 template<class Base>
255 void CodeHandler<Base>::generateCode(std::ostream& out,
256  Language<Base>& lang,
257  std::vector<CGB>& dependent,
259  std::vector<std::string>& atomicFunctions,
260  const std::string& jobName) {
261  ArrayView<CGB> deps(dependent);
262  generateCode(out, lang, deps, nameGen, atomicFunctions, jobName);
263 }
264 
265 template<class Base>
266 void CodeHandler<Base>::generateCode(std::ostream& out,
267  Language<Base>& lang,
268  ArrayView<CGB>& dependent,
270  std::vector<std::string>& atomicFunctions,
271  const std::string& jobName) {
272  using namespace std::chrono;
273  steady_clock::time_point beginTime;
274 
275  if (_jobTimer != nullptr) {
276  _jobTimer->startingJob("source for '" + jobName + "'");
277  } else if (_verbose) {
278  std::cout << "generating source for '" << jobName << "' ... ";
279  std::cout.flush();
280  beginTime = steady_clock::now();
281  }
282 
283  _lang = &lang;
284  _idCount = 1;
285  _idArrayCount = 1;
286  _idSparseArrayCount = 1;
287  _idAtomicCount = 1;
288  _dependents = &dependent;
289  _atomicFunctionsOrder = &atomicFunctions;
290  _atomicFunctionsMaxForward.resize(atomicFunctions.size());
291  _atomicFunctionsMaxReverse.resize(atomicFunctions.size());
293  _loops.prepare4NewSourceGen();
294  _scopeColorCount = 0;
295  _currentScopeColor = 0;
296  _scopes.reserve(4);
297  _scopes.resize(1);
298  _alteredNodes.clear();
299  _evaluationOrder.adjustSize();
300  _lastUsageOrder.adjustSize();
301  _totalUseCount.adjustSize();
302  _operationCount.adjustSize();
303  _varId.adjustSize();
304  _scope.adjustSize();
305 
306  for (size_t i = 0; i < atomicFunctions.size(); i++) {
307  _atomicFunctionName2Index[atomicFunctions[i]] = i;
308  }
309  std::fill(_atomicFunctionsMaxForward.begin(), _atomicFunctionsMaxForward.end(), -1);
310  std::fill(_atomicFunctionsMaxReverse.begin(), _atomicFunctionsMaxReverse.end(), -1);
311 
312  if (_used) {
313  resetManagedNodes();
314  }
315  _used = true;
316 
320  size_t n = _independentVariables.size();
321  for (size_t j = 0; j < n; j++) {
322  _varId[*_independentVariables[j]] = _idCount++;
323  }
324 
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++;
330  }
331  }
332 
333  _minTemporaryVarID = _idCount;
334 
338  for (size_t i = 0; i < m; i++) {
339  Node* node = dependent[i].getOperationNode();
340  if (node != nullptr) {
341  markCodeBlockUsed(*node);
342  }
343  }
344 
348  _scopedVariableOrder.reserve(std::max<size_t>(size_t(1), _scopes.size()) + 10); // some additional scopes might still be added
349 
350  startNewOperationTreeVisit();
351 
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)) {
357  // dependencies not visited yet
358  checkVariableCreation(code);
359 
360  // make sure new temporary variables are NOT created for
361  // the independent variables and that a dependency did
362  // not use it first
363  if ((_varId[code] == 0 || !isIndependent(code)) && !isVisited(code)) {
364  addToEvaluationQueue(code);
365  }
366  }
367  markVisited(code);
368  }
369  }
370 
374  if (_scopedVariableOrder.size() == 1) {
375  _variableOrder.swap(_scopedVariableOrder[0]); // most common situation
376  } else {
377  optimizeIfs(); // reduce the number of adjoining ifs
378 
379  size_t vosize = 0;
380  for (size_t s = 0; s < _scopedVariableOrder.size(); s++) {
381  vosize += _scopedVariableOrder[s].size();
382  }
383  _variableOrder.resize(vosize);
384 
385  size_t e = 0;
386  addScopeToVarOrder(0, e);
387 
388  // if e > vosize then some nodes (marking the beginning of scopes)
389  // must have been added more than once
390  CPPADCG_ASSERT_UNKNOWN(_variableOrder.size() == e)
391  }
392 
393  for (size_t p = 0; p < _variableOrder.size(); p++) {
394  Node& arg = *_variableOrder[p];
395  setEvaluationOrder(arg, p + 1);
397  }
398 
402  if (_reuseIDs) {
403  reduceTemporaryVariables(dependent);
404  }
405 
409  _variableDependencies.clear();
410  if(lang.requiresVariableDependencies()) {
412  }
413 
414  nameGen.setTemporaryVariableID(_minTemporaryVarID, _idCount - 1, _idArrayCount - 1, _idSparseArrayCount - 1);
415 
416  std::map<std::string, size_t> atomicFunctionName2Id;
417  for (const auto& pair: _atomicFunctions) {
418  atomicFunctionName2Id[pair.second->atomic_name()] = pair.first;
419  }
420 
421  std::map<size_t, size_t> atomicFunctionId2Index;
422  std::map<size_t, std::string> atomicFunctionId2Name;
423  for (size_t i = 0; i < _atomicFunctionsOrder->size(); i++) {
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;
429  }
430  }
431 
436  std::unique_ptr<LanguageGenerationData<Base> > _info(new LanguageGenerationData<Base>(_independentVariables, dependent,
437  _minTemporaryVarID, _varId, _variableOrder, _variableDependencies,
438  nameGen,
439  atomicFunctionId2Index, atomicFunctionId2Name,
441  _reuseIDs,
442  _loops.indexes, _loops.indexRandomPatterns,
443  _loops.dependentIndexPatterns, _loops.independentIndexPatterns,
445  _zeroDependents));
446 
447  lang.generateSourceCode(out, std::move(_info));
448 
453 
454  // restore altered nodes
455  for (const auto& itAlt : _alteredNodes) {
456  Node* tmp = itAlt.first;
457  Node* opClone = itAlt.second;
458  if (tmp->getOperationType() == CGOpCode::Tmp && !tmp->getInfo().empty()) { // some might have already been restored
459  tmp->setOperation(opClone->getOperationType(), opClone->getArguments());
460  tmp->getInfo() = opClone->getInfo();
461  }
462  }
463  _alteredNodes.clear();
464 
465  if (_jobTimer != nullptr) {
466  _jobTimer->finishedJob();
467  } else if (_verbose) {
468  OStreamConfigRestore osr(std::cout);
469  duration<float> dt = steady_clock::now() - beginTime;
470  std::cout << "done [" << std::fixed << std::setprecision(3) << dt.count() << "]" << std::endl;
471  }
472 }
473 
474 template<class Base>
476  if (_idCount == 1)
477  return 0; // no code generated
478  else
479  return _idCount - _minTemporaryVarID;
480 }
481 
482 template<class Base>
484  return _idArrayCount - 1;
485 }
486 
487 template<class Base>
489  return _idSparseArrayCount - 1;
490 }
491 
492 template<class Base>
494  for (Node* n : _codeBlocks) {
495  delete n;
496  }
497  _codeBlocks.clear();
498  _independentVariables.clear();
499  _idCount = 1;
500  _idArrayCount = 1;
501  _idSparseArrayCount = 1;
502  _idAtomicCount = 1;
503 
504  _loops.reset();
505 
506  _used = false;
507 }
508 
509 template<class Base>
511  _scope.fill(0);
512  _evaluationOrder.fill(0);
513  _lastUsageOrder.fill(0);
514  _totalUseCount.fill(0);
515  _operationCount.fill(0);
516  _varId.fill(0);
517 }
518 
519 /******************************************************************************
520 * access to managed memory
521 ******************************************************************************/
522 
523 template<class Base>
525  return manageOperationNode(new Node(n));
526 }
527 
528 template<class Base>
530  return manageOperationNode(new Node(this, op));
531 }
532 
533 template<class Base>
535  const Arg& arg) {
536  return manageOperationNode(new Node(this, op, arg));
537 }
538 
539 template<class Base>
541  std::vector<Arg>&& args) {
542  return manageOperationNode(new Node(this, op, std::move(args)));
543 }
544 
545 template<class Base>
547  std::vector<size_t>&& info,
548  std::vector<Arg>&& args) {
549  return manageOperationNode(new Node(this, op, std::move(info), std::move(args)));
550 }
551 
552 template<class Base>
554  const std::vector<size_t>& info,
555  const std::vector<Arg>& args) {
556  return manageOperationNode(new Node(this, op, info, args));
557 }
558 
559 template<class Base>
561  size_t iterationCount) {
562  auto* n = new LoopStartOperationNode<Base>(this, indexDcl, iterationCount);
563  manageOperationNode(n);
564  return n;
565 }
566 
567 template<class Base>
569  IndexOperationNode<Base>& iterCount) {
570  auto* n = new LoopStartOperationNode<Base>(this, indexDcl, iterCount);
571  manageOperationNode(n);
572  return n;
573 }
574 
575 template<class Base>
577  const std::vector<Arg>& endArgs) {
578  auto* n = new LoopEndOperationNode<Base>(this, loopStart, endArgs);
579  manageOperationNode(n);
580  return n;
581 }
582 
583 template<class Base>
584 inline PrintOperationNode<Base>* CodeHandler<Base>::makePrintNode(const std::string& before,
585  const Arg& arg,
586  const std::string& after) {
587  auto* n = new PrintOperationNode<Base>(this, before, arg, after);
588  manageOperationNode(n);
589  return n;
590 }
591 
592 template<class Base>
594  auto* n = new IndexOperationNode<Base>(this, indexDcl);
595  manageOperationNode(n);
596  return n;
597 }
598 
599 template<class Base>
601  auto* n = new IndexOperationNode<Base>(this, loopStart);
602  manageOperationNode(n);
603  return n;
604 }
605 
606 template<class Base>
608  auto* n = new IndexOperationNode<Base>(this, indexAssign);
609  manageOperationNode(n);
610  return n;
611 }
612 
613 template<class Base>
615  IndexPattern& indexPattern,
616  IndexOperationNode<Base>& index1) {
617  auto* n = new IndexAssignOperationNode<Base>(this, index, indexPattern, index1);
618  manageOperationNode(n);
619  return n;
620 }
621 
622 template<class Base>
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);
629  return n;
630 }
631 
632 template<class Base>
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));
636  n->setName(name);
637  return n;
638 }
639 
640 template<class Base>
642  return _codeBlocks.size();
643 }
644 
645 template<class Base>
646 inline const std::vector<OperationNode<Base> *>& CodeHandler<Base>::getManagedNodes() const {
647  return _codeBlocks;
648 }
649 
650 template<class Base>
651 inline void CodeHandler<Base>::deleteManagedNodes(size_t start, size_t end) {
652  if (start >= end)
653  return;
654 
655  start = std::min<size_t>(start, _codeBlocks.size());
656  end = std::min<size_t>(end, _codeBlocks.size());
657 
658  for (size_t i = start; i < end; ++i) {
659  delete _codeBlocks[i];
660  }
661  _codeBlocks.erase(_codeBlocks.begin() + start, _codeBlocks.begin() + end);
662 
663  // update positions
664  for (size_t i = start; i < _codeBlocks.size(); ++i) {
665  _codeBlocks[i]->setHandlerPosition(i);
666  }
667 
668  for (auto* v : _managedVectors) {
669  v->nodesErased(start, end);
670  }
671 }
672 
673 /******************************************************************************
674  * Value generation
675  *****************************************************************************/
676 template<class Base>
678  return CGB(arg);
679 }
680 
681 /******************************************************************************
682  * Index patterns
683  *****************************************************************************/
684 template<class Base>
686  std::set<RandomIndexPattern*>& found) {
687  if (ip == nullptr)
688  return;
689 
690  if (ip->getType() == IndexPatternType::Random1D || ip->getType() == IndexPatternType::Random2D) {
691  found.insert(static_cast<RandomIndexPattern*> (ip));
692  } else {
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));
698  }
699  }
700 }
701 
702 /**************************************************************************
703  * Operation graph manipulation
704  *************************************************************************/
705 template<class Base>
707  size_t pos = code->getHandlerPosition();
708  if (pos >= _codeBlocks.size() || code != _codeBlocks[pos]) {
709  manageOperationNode(code);
710  return false;
711  }
712  return true;
713 }
714 
715 template<class Base>
717  //CPPADCG_ASSERT_UNKNOWN(std::find(_codeBlocks.begin(), _codeBlocks.end(), code) == _codeBlocks.end()); // <<< too great of an impact in performance
718  if (_codeBlocks.capacity() == _codeBlocks.size()) {
719  _codeBlocks.reserve((_codeBlocks.size() * 3) / 2 + 1);
720  }
721 
722  code->setHandlerPosition(_codeBlocks.size());
723  _codeBlocks.push_back(code);
724  return code;
725 }
726 
727 template<class Base>
729  _managedVectors.insert(v);
730 }
731 
732 template<class Base>
734  _managedVectors.erase(v);
735 }
736 
737 template<class Base>
739 
740  auto startAnalysis = [this](OperationStackData<Base>& stackEl,
741  OperationStack<Base>& stack) {
742 
743  auto& code = stackEl.node();
744 
745  increaseTotalUsageCount(code);
746 
747  CGOpCode op = code.getOperationType();
748  if (isIndependent(code)) {
749  return false; // nothing to do (go up)
750 
751  } else if (op == CGOpCode::Alias) {
756  CPPADCG_ASSERT_UNKNOWN(code.getArguments().size() == 1)
757  stack.emplace_back(code, 0, _currentScopeColor);
758 
759  return false;
760 
761  } else if (getTotalUsageCount(code) == 1) {
762  // first time this operation is visited
763 
764  size_t previousScope = _currentScopeColor;
765 
766  _scope[code] = _currentScopeColor;
767 
768  // check if there is a scope change
769  if (op == CGOpCode::LoopStart || op == CGOpCode::StartIf || op == CGOpCode::ElseIf ||
770  op == CGOpCode::Else) {
771  // leaving a scope
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; // save the initial node
776  } else {
777  CPPADCG_ASSERT_UNKNOWN(!code.getArguments().empty() &&
778  code.getArguments()[0].getOperation() != nullptr &&
779  code.getArguments()[0].getOperation()->getOperationType() ==
780  CGOpCode::StartIf)
781  sPath.back().beginning = code.getArguments()[0].getOperation(); // save the initial node
782  }
783  _currentScopeColor = sPath.size() > 1 ? sPath[sPath.size() - 2].color : 0;
784  }
785 
786  if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
787  // entering a new scope
788  _currentScopeColor = ++_scopeColorCount;
789 
790  _scopes.resize(_currentScopeColor + 1);
791  _scopes[_currentScopeColor] = _scopes[previousScope];
792 
793  // change current scope
794  if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf) {
795  // one more scope level
796  _scopes[_currentScopeColor].push_back(ScopePathElement<Base>(_currentScopeColor, &code));
797  } else {
798  // same level but different scope
799  _scopes[_currentScopeColor].back() = ScopePathElement<Base>(_currentScopeColor, &code);
800  }
801 
802  if (op == CGOpCode::LoopEnd) {
803  _loops.addLoopEndNode(code);
804  }
805  }
806 
810  stack.pushNodeArguments(code, _currentScopeColor);
811 
812  return true;
813 
814  } else {
815  // been to this node before
816 
817  if (op == CGOpCode::Tmp && !code.getInfo().empty()) {
823  if (_scope[code] == _currentScopeColor) {
824  // outside an if (defined for all iterations)
825  restoreTemporaryVar(code);
826  } else {
828  }
829 
830  } else if (_scope[code] != _currentScopeColor && op != CGOpCode::LoopIndexedIndep) {
831  ScopeIDType oldScope = _scope[code];
837  size_t depth = findFirstDifferentScope(oldScope, _currentScopeColor);
838 
839  // update the scope where it should be defined
840  ScopeIDType newScope;
841  if (depth == 0)
842  newScope = 0;
843  else
844  newScope = _scopes[_currentScopeColor][depth - 1].color;
845 
846  if (oldScope != newScope) {
850  bool addedIf = handleTemporaryVarInDiffScopes(code, oldScope, newScope);
851 
852  if (!addedIf) {
853  _scope[code] = newScope;
854 
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);
862  }
863  }
864  }
865  }
866 
867  return false;
868  }
869  };
870 
871 
872  auto endAnalysis = [this](OperationStackData<Base>& stackEl) {
873  // executed after all children have been visited
874 
875  Node& code = stackEl.node();
876  size_t previousScope = stackEl.parentNodeScope;
877 
878  CGOpCode op = code.getOperationType();
879 
880  if (op == CGOpCode::Index) {
881  const auto& inode = static_cast<const IndexOperationNode <Base>&> (code);
882  // indexes that don't depend on a loop start or an index assignment are declared elsewhere
883  if (inode.isDefinedLocally()) {
884  _loops.indexes.insert(&inode.getIndex());
885  }
886  } else if (op == CGOpCode::LoopIndexedIndep || op == CGOpCode::LoopIndexedDep ||
887  op == CGOpCode::IndexAssign) {
888  IndexPattern* ip;
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];
895  } else {
896  ip = &static_cast<IndexAssignOperationNode <Base>&> (code).getIndexPattern();
897  }
898 
899  findRandomIndexPatterns(ip, _loops.indexRandomPatterns);
900 
901  } else if (op == CGOpCode::DependentRefRhs) {
902  CPPADCG_ASSERT_UNKNOWN(code.getInfo().size() == 1)
903  size_t depIndex = code.getInfo()[0];
904 
905  CPPADCG_ASSERT_UNKNOWN(_dependents->size() > depIndex)
906  Node * depNode = (*_dependents)[depIndex].getOperationNode();
907  CPPADCG_ASSERT_UNKNOWN(depNode != nullptr && depNode->getOperationType() != CGOpCode::Inv)
908 
909  _varId[code] = _varId[*depNode];
910  }
911 
915  _currentScopeColor = previousScope;
916 
917  };
918 
919  depthFirstGraphNavigation(root,
920  _currentScopeColor,
921  startAnalysis,
922  endAnalysis,
923  true);
924 }
925 
926 template<class Base>
928  size_t oldScope,
929  size_t newScope) {
930  if (_currentScopeColor == 0)
931  return false;
932 
936  CPPADCG_ASSERT_KNOWN(code.getOperationType() != CGOpCode::ArrayCreation, "Not supported yet")
937  CPPADCG_ASSERT_KNOWN(code.getOperationType() != CGOpCode::SparseArrayCreation, "Not supported yet")
938 
942  std::vector<size_t> iterationRegions;
943  Node* bScopeNewEnd = _scopes[_currentScopeColor].back().end;
944  Node* bScopeOldEnd = _scopes[oldScope].back().end;
945 
946  CGOpCode bNewOp = bScopeNewEnd->getOperationType();
947  CGOpCode bOldOp = bScopeOldEnd->getOperationType();
948 
949  if ((bNewOp == CGOpCode::EndIf || bNewOp == CGOpCode::Else || bNewOp == CGOpCode::ElseIf) &&
950  (bOldOp == CGOpCode::EndIf || bOldOp == CGOpCode::Else || bOldOp == CGOpCode::ElseIf)) {
951  // used in 2 different if/else branches
952 
956  Node* bScopeNew = bScopeNewEnd->getArguments()[0].getOperation();
957  Node* bScopeOld = bScopeOldEnd->getArguments()[0].getOperation();
958 
959  IndexOperationNode<Base>* newIterIndexOp = nullptr;
960  iterationRegions = ifBranchIterationRanges(bScopeNew, newIterIndexOp);
961  CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2)
962 
963  IndexOperationNode<Base>* oldIterIndexOp = nullptr;
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)
968 
969  if (iterationRegions.size() > 2 ||
970  iterationRegions[0] != 0 ||
971  iterationRegions[1] != (std::numeric_limits<size_t>::max)()) {
972  // this temporary variable is not used by all iterations
973 
974  replaceWithConditionalTempVar(code, *newIterIndexOp, iterationRegions, oldScope, newScope);
975  return true;
976  }
977  }
978 
979  return false;
980 }
981 
982 template<class Base>
984  IndexOperationNode<Base>& iterationIndexOp,
985  const std::vector<size_t>& iterationRegions,
986  ScopeIDType oldScope,
987  ScopeIDType commonScopeColor) {
991  Node* opClone = cloneNode(tmp);
992 
996  Node* tmpDclVar = makeNode(CGOpCode::TmpDcl);
997  Arg tmpArg(*tmpDclVar);
998 
999  Node* cond = makeNode(CGOpCode::IndexCondExpr, iterationRegions, {iterationIndexOp});
1000 
1001  // if
1002  Node* ifStart = makeNode(CGOpCode::StartIf, *cond);
1003 
1004  Node* tmpAssign = makeNode(CGOpCode::LoopIndexedTmp, {tmpArg, *opClone});
1005  Node* ifAssign = makeNode(CGOpCode::CondResult, {*ifStart, *tmpAssign});
1006 
1007  // end if
1008  Node* endIf = makeNode(CGOpCode::EndIf, {*ifStart, *ifAssign});
1009 
1013  tmp.setOperation(CGOpCode::Tmp, {tmpArg, *endIf});
1014  tmp.getInfo().resize(1); // used to mark that this node was altered here
1015 
1016  // created new nodes, must adjust vector sizes
1017  _scope.adjustSize();
1018  _lastVisit.adjustSize();
1019  _scope.adjustSize();
1020  _evaluationOrder.adjustSize();
1021  _lastUsageOrder.adjustSize();
1022  _totalUseCount.adjustSize();
1023  _operationCount.adjustSize();
1024  _varId.adjustSize();
1025 
1029  size_t newScopeColor = ++_scopeColorCount;
1030  _scopes.resize(newScopeColor + 1);
1031  _scopes[newScopeColor] = _scopes[commonScopeColor];
1032 
1033  // one more scope level
1034  _scopes[newScopeColor].push_back(ScopePathElement<Base>(newScopeColor, endIf, ifStart));
1035 
1036  // apply scope colors
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;
1045 
1046  // total usage count
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);
1054 
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);
1062  }
1063 
1064  _alteredNodes.push_back(std::make_pair(&tmp, opClone));
1065 }
1066 
1067 template<class Base>
1069  if (_scope[code] != _currentScopeColor) {
1070  return; //nothing to change
1071  }
1072 
1076  if (_currentScopeColor == 0)
1077  restoreTemporaryVar(code);
1078 
1084  ScopeIDType oldScope = _scope[code];
1085 
1086  size_t depth = findFirstDifferentScope(oldScope, _currentScopeColor);
1087 
1088  // update the scope where it should be defined
1089  ScopeIDType newScope = depth == 0 ? 0 : _scopes[_currentScopeColor][depth - 1].color;
1090 
1094  std::vector<size_t> iterationRegions;
1095  Node* bScopeNewEnd = _scopes[_currentScopeColor].back().end;
1096  Node* endif = code.getArguments()[0].getOperation();
1097  CPPADCG_ASSERT_UNKNOWN(endif->getOperationType() == CGOpCode::EndIf)
1098  Node* bScopeOldEnd = _scopes[_scope[*endif]].back().end;
1099 
1100  CGOpCode bNewOp = bScopeNewEnd->getOperationType();
1101 
1102  if (bNewOp == CGOpCode::EndIf || bNewOp == CGOpCode::Else || bNewOp == CGOpCode::ElseIf) {
1103  // used in 2 different if/else branches
1104 
1108  Node* bScopeNew = bScopeNewEnd->getArguments()[0].getOperation();
1109  Node* bScopeOld = bScopeOldEnd->getArguments()[0].getOperation();
1110 
1111  IndexOperationNode<Base>* newIterIndexOp = nullptr;
1112  iterationRegions = ifBranchIterationRanges(bScopeNew, newIterIndexOp);
1113  CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2)
1114 
1115  IndexOperationNode<Base>* oldIterIndexOp = nullptr;
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)
1120 
1121  if (iterationRegions.size() == 2 &&
1122  (iterationRegions[0] == 0 ||
1123  iterationRegions[1] == (std::numeric_limits<size_t>::max)())) {
1124  // this temporary variable is used by all iterations
1125  // there is no need for an 'if'
1126  restoreTemporaryVar(code);
1127 
1128  } else if (oldIterRegions != iterationRegions) {
1129  Node* cond = bScopeOld->getArguments()[0].getOperation();
1130  CPPADCG_ASSERT_UNKNOWN(cond->getOperationType() == CGOpCode::IndexCondExpr)
1131  cond->getInfo() = iterationRegions;
1132  }
1133 
1134  }
1135 
1136  if (oldScope != newScope) {
1137  _scope[code] = newScope;
1141  const std::vector<Arg>& cargs = code.getArguments();
1142  size_t aSize = cargs.size();
1143  for (size_t a = 0; a < aSize; a++) {
1144  updateVarScopeUsage(cargs[a].getOperation(), newScope, oldScope);
1145  }
1146  }
1147 
1148 }
1149 
1150 template<class Base>
1152  CPPADCG_ASSERT_UNKNOWN(tmp.getOperationType() == CGOpCode::Tmp && !tmp.getInfo().empty())
1153 
1154  Node* endIf = tmp.getArguments()[1].getOperation();
1155  Node* ifAssign = endIf->getArguments()[1].getOperation();
1156  Node* tmpAssign = ifAssign->getArguments()[1].getOperation();
1157  Node* opClone = tmpAssign->getArguments()[1].getOperation();
1158  tmp.setOperation(opClone->getOperationType(), opClone->getArguments());
1159  tmp.getInfo() = opClone->getInfo();
1160 
1161  _scope[tmp] = _currentScopeColor;
1162 
1166  const std::vector<Arg>& args = tmp.getArguments();
1167  size_t aSize = args.size();
1168  for (size_t a = 0; a < aSize; a++) {
1169  updateVarScopeUsage(args[a].getOperation(), _currentScopeColor, _scope[*opClone]);
1170  }
1171 }
1172 
1173 template<class Base>
1175  Node* opClone) {
1176  CPPADCG_ASSERT_UNKNOWN(tmp->getOperationType() == CGOpCode::Tmp && !tmp->getInfo().empty())
1177 
1178  tmp->setOperation(opClone->getOperationType(), opClone->getArguments());
1179  tmp->getInfo() = opClone->getInfo();
1180 
1181  _scope[*tmp] = _currentScopeColor;
1182 
1186  const std::vector<Arg>& args = tmp->getArguments();
1187  size_t aSize = args.size();
1188  for (size_t a = 0; a < aSize; a++) {
1189  updateVarScopeUsage(args[a].getOperation(), _currentScopeColor, _scope[*opClone]);
1190  }
1191 }
1192 
1193 template<class Base>
1195  ScopeIDType usageScope,
1196  ScopeIDType oldUsageScope) {
1197  if (node == nullptr || _scope[*node] == usageScope)
1198  return;
1199 
1200 
1201  ScopeIDType oldScope = _scope[*node];
1202  ScopeIDType newScope;
1203 
1204  if (oldScope == oldUsageScope) {
1205  newScope = usageScope;
1206  } else {
1207  size_t depth = findFirstDifferentScope(oldScope, usageScope);
1208 
1209  newScope = (depth == 0) ? 0 : _scopes[usageScope][depth - 1].color;
1210  }
1211 
1212  if (newScope == oldScope)
1213  return;
1214 
1215  _scope[*node] = newScope;
1216 
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);
1221  }
1222 }
1223 
1224 template<class Base>
1225 inline void CodeHandler<Base>::addScopeToVarOrder(size_t scope,
1226  size_t& e) {
1227  std::vector<Node*>& vorder = _scopedVariableOrder[scope];
1228 
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();
1233 
1234  if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
1235  CPPADCG_ASSERT_UNKNOWN(!node->getArguments().empty())
1236 
1237  Node* beginScopeNode = node->getArguments()[0].getOperation();
1238  CPPADCG_ASSERT_UNKNOWN(beginScopeNode != nullptr)
1239 
1240  addScopeToVarOrder(_scope[*beginScopeNode], e);
1241  }
1242 
1243  //std::cout << "e:" << e << " " << vorder[p] << " scope:" << scope << " p:" << p << " " << *vorder[p] << std::endl;
1244  _variableOrder[e++] = vorder[p];
1245  }
1246 }
1247 
1248 template<class Base>
1250  size_t color2) {
1251  CPPADCG_ASSERT_UNKNOWN(color1 < _scopes.size())
1252  CPPADCG_ASSERT_UNKNOWN(color2 < _scopes.size())
1253 
1254  ScopePath& scopePath1 = _scopes[color1];
1255  ScopePath& scopePath2 = _scopes[color2];
1256 
1257  size_t s1 = scopePath1.size();
1258  size_t s2 = scopePath2.size();
1259  size_t depth;
1260  for (depth = 0; depth < s1 && depth < s2; depth++) {
1261  if (scopePath1[depth].color != scopePath2[depth].color) {
1262  break;
1263  }
1264  }
1265 
1266  return depth;
1267 }
1268 
1269 template<class Base>
1271  if (_scopedVariableOrder.size() < 3)
1272  return; // there has to be at least 2 ifs
1273 
1274  for (size_t scope = 0; scope < _scopedVariableOrder.size(); scope++) {
1275  std::vector<Node*>& vorder = _scopedVariableOrder[scope];
1276 
1277  for (long p = vorder.size() - 1; p > 0; p--) {
1278  Node* endIf = vorder[p];
1279  if (endIf->getOperationType() != CGOpCode::EndIf)
1280  continue;
1281 
1282  long p1 = p - 1;
1283  while (p1 >= 0) {
1284  if (vorder[p1]->getOperationType() == CGOpCode::TmpDcl) {
1285  p1--;
1286  } else {
1287  break;
1288  }
1289  }
1290  Node* endIf1 = vorder[p1];
1291  if (endIf1->getOperationType() != CGOpCode::EndIf)
1292  continue;
1293 
1294  // 2 consecutive ifs
1295  Node* startIf = endIf->getArguments()[0].getOperation();
1296  Node* startIf1 = endIf1->getArguments()[0].getOperation();
1297  if (startIf->getOperationType() != CGOpCode::StartIf || startIf1->getOperationType() != CGOpCode::StartIf)
1298  continue;
1299 
1300  Node* cond = startIf->getArguments()[0].getOperation();
1301  Node* cond1 = startIf1->getArguments()[0].getOperation();
1302 
1303  CPPADCG_ASSERT_UNKNOWN(cond->getOperationType() == CGOpCode::IndexCondExpr || cond1->getOperationType() == CGOpCode::IndexCondExpr)
1304  if (cond->getInfo() == cond1->getInfo()) {
1308  const std::vector<Arg>& eArgs = endIf->getArguments();
1309  std::vector<Arg>& eArgs1 = endIf1->getArguments();
1310 
1311  ScopeIDType ifScope = _scope[*startIf];
1312  ScopeIDType ifScope1 = _scope[*startIf1];
1313  std::vector<Node*>& vorderIf = _scopedVariableOrder[ifScope];
1314  std::vector<Node*>& vorderIf1 = _scopedVariableOrder[ifScope1];
1315 
1316  startNewOperationTreeVisit();
1317 
1318  // break cycles caused by dependencies on the previous if
1319  for (size_t a = 1; a < eArgs.size(); a++) { // exclude the initial startIf
1320  CPPADCG_ASSERT_UNKNOWN(eArgs[a].getOperation() != nullptr && eArgs[a].getOperation()->getOperationType() == CGOpCode::CondResult)
1321  breakCyclicDependency(eArgs[a].getOperation(), ifScope, endIf1);
1322  replaceScope(eArgs[a].getOperation(), ifScope, ifScope1); // update scope
1323  }
1324 
1325  vorderIf1.insert(vorderIf1.end(), vorderIf.begin() + 1, vorderIf.end()); // exclude the initial startIf
1326 
1327  vorderIf.clear();
1328 
1329  // update startIf
1330  for (size_t a = 1; a < eArgs.size(); a++) { // exclude the initial startIf
1331  CPPADCG_ASSERT_UNKNOWN(eArgs[a].getOperation() != nullptr && eArgs[a].getOperation()->getOperationType() == CGOpCode::CondResult)
1332  eArgs[a].getOperation()->getArguments()[0] = Arg(*startIf1);
1333  }
1334 
1335  // update endIf
1336  eArgs1.insert(eArgs1.end(), eArgs.begin() + 1, eArgs.end());
1337 
1338  // replace endIf
1339  endIf->setOperation(CGOpCode::Alias, {*endIf1});
1340 
1341  // remove one of the ifs
1342  vorder.erase(vorder.begin() + p);
1343 
1344  // move nodes in scope containing the ifs
1345  for (long pp = p1; pp < p - 1; pp++) {
1346  vorder[pp] = vorder[pp + 1];
1347  }
1348  vorder[p - 1] = endIf1;
1349  }
1350  }
1351  }
1352 }
1353 
1354 template<class Base>
1355 inline void CodeHandler<Base>::replaceScope(Node* node,
1356  ScopeIDType oldScope,
1357  ScopeIDType newScope) {
1358  if (node == nullptr || _scope[*node] != oldScope)
1359  return;
1360 
1361  _scope[*node] = newScope;
1362 
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);
1366  }
1367 }
1368 
1369 template<class Base>
1371  size_t scope,
1372  Node* endIf) {
1373  if (node == nullptr || isVisited(*node))
1374  return;
1375 
1376  markVisited(*node);
1377 
1378  CGOpCode op = node->getOperationType();
1379  std::vector<Arg>& args = node->getArguments();
1380 
1381  if (op == CGOpCode::Tmp && args.size() > 1) {
1382  Node* arg = args[1].getOperation();
1383  if (arg == endIf) {
1384  // a dependency on LoopIndexedTmp could be added but
1385  // it is not required since variable order was already decided
1386  args.erase(args.begin() + 1);
1387  }
1388  }
1389 
1390  if (!containedInScope(*node, scope)) {
1391  return;
1392  }
1393 
1394  for (size_t a = 0; a < args.size(); a++) {
1395  Node* arg = args[a].getOperation();
1396  if (arg == endIf) {
1397  if (op == CGOpCode::StartIf || op == CGOpCode::LoopStart) {
1398  args.erase(args.begin() + a);
1399  a--;
1400  }
1401  } else {
1402  breakCyclicDependency(arg, scope, endIf);
1403  }
1404  }
1405 }
1406 
1407 template<class Base>
1408 inline bool CodeHandler<Base>::containedInScope(const Node& node,
1409  ScopeIDType scope) {
1410  ScopeIDType nScope = _scope[node];
1411  if (nScope == scope)
1412  return true;
1413 
1414  return _scopes[nScope].size() >= _scopes[scope].size() &&
1415  _scopes[nScope][_scopes[scope].size() - 1].color == scope;
1416 }
1417 
1418 template<class Base>
1419 inline bool CodeHandler<Base>::containsArgument(const Node& node,
1420  const Node& arg) {
1421  const std::vector<Arg>& args = node.getArguments();
1422  for (size_t a = 0; a < args.size(); a++) {
1423  if (args[a].getOperation() == &arg) {
1424  return true;
1425  }
1426  }
1427  return false;
1428 }
1429 
1430 template<class Base>
1432  size_t id = atomic.getId();
1433  auto it = _atomicFunctions.lower_bound(id);
1434  if (it == _atomicFunctions.end() || it->first != id) {
1435  if (it != _atomicFunctions.end()) ++it;
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, ").");
1440  }
1441 }
1442 
1443 template<class Base>
1445 
1446  auto startAnalysis = [this](OperationStackData<Base>& stackEl,
1447  OperationStack<Base>& stack) {
1448  auto& arg = stackEl.node();
1449 
1450  if (isVisited(arg)) {
1451  return false;
1452  } else {
1453  stack.pushNodeArguments(stackEl.node(), 0);
1454  return true;
1455  }
1456  };
1457 
1458  auto completeAnalysis = [this](OperationStackData<Base>& stackEl) {
1459  auto& arg = stackEl.node();
1460 
1461  if (isVisited(arg)) {
1462  return;
1463  }
1464 
1465  CGOpCode aType = arg.getOperationType();
1466 
1467  if (aType == CGOpCode::LoopEnd || aType == CGOpCode::ElseIf ||
1468  aType == CGOpCode::Else || aType == CGOpCode::EndIf) {
1469  if (_varId[arg] == 0) {
1470  // ID value is not really used but must be non-zero
1471  _varId[arg] = (std::numeric_limits<size_t>::max)();
1472  }
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];
1480 
1481  size_t pos;
1482  const std::string& atomicName = _atomicFunctions.at(id)->atomic_name();
1483  std::map<std::string, size_t>::const_iterator itName2Idx;
1484  itName2Idx = _atomicFunctionName2Index.find(atomicName);
1485 
1486  if (itName2Idx == _atomicFunctionName2Index.end()) {
1487  pos = _atomicFunctionsOrder->size();
1488  _atomicFunctionsOrder->push_back(atomicName);
1489  _atomicFunctionName2Index[atomicName] = pos;
1490  _atomicFunctionsMaxForward.push_back(-1);
1491  _atomicFunctionsMaxReverse.push_back(-1);
1492  } else {
1493  pos = itName2Idx->second;
1494  }
1495 
1496  if (aType == CGOpCode::AtomicForward) {
1497  int p = arg.getInfo()[2];
1498  _atomicFunctionsMaxForward[pos] = std::max<int>(_atomicFunctionsMaxForward[pos],
1499  p);
1500  } else {
1501  int p = arg.getInfo()[1];
1502  _atomicFunctionsMaxReverse[pos] = std::max<int>(_atomicFunctionsMaxReverse[pos],
1503  p);
1504  }
1505  }
1506 
1512  if (_varId[arg] == 0 || !isIndependent(arg)) {
1513  auto& code = stackEl.parent();
1514  size_t argIndex = stackEl.argumentIndex();
1515 
1516  if (aType == CGOpCode::LoopIndexedIndep) {
1517  // ID value not really used but must be non-zero
1518  _varId[arg] = (std::numeric_limits<size_t>::max)();
1519  } else if (aType == CGOpCode::Alias) {
1520  return; // should never be added to the evaluation queue
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);
1534  if (_varId[arg] == 0) {
1535  // ID value is not really used but must be non-zero
1536  _varId[arg] = (std::numeric_limits<size_t>::max)();
1537  }
1538  } else if (aType == CGOpCode::Pri) {
1539  addToEvaluationQueue(arg);
1540  if (_varId[arg] == 0) {
1541  // ID value is not really used but must be non-zero
1542  _varId[arg] = (std::numeric_limits<size_t>::max)();
1543  }
1544  } else if (aType == CGOpCode::TmpDcl) {
1545  addToEvaluationQueue(arg);
1546 
1547  _varId[arg] = _idCount;
1548  _idCount++;
1549 
1550  } else {
1551 
1552  // determine the number of operations required to compute this variable
1553  size_t& opCount = _operationCount[arg];
1554 
1555  opCount = 1;
1556  for (const auto& a: arg) {
1557  if (a.getOperation() != nullptr) {
1558  auto& n = *a.getOperation();
1559  if (_varId[n] == 0) {
1560  opCount += _operationCount[n];
1561  }
1562  }
1563  }
1564 
1565  // determine if this variable should be temporary/dependent variable
1566  if (_lang->createsNewVariable(arg, getTotalUsageCount(arg), opCount) ||
1567  _lang->requiresVariableArgument(code.getOperationType(), argIndex)) {
1568 
1569  addToEvaluationQueue(arg);
1570 
1571  if (_varId[arg] == 0) {
1572  if (aType == CGOpCode::AtomicForward ||
1573  aType == CGOpCode::AtomicReverse) {
1574  _varId[arg] = _idAtomicCount;
1575  _idAtomicCount++;
1576  } else if (aType == CGOpCode::LoopIndexedDep ||
1577  aType == CGOpCode::LoopIndexedTmp) {
1578  // ID value not really used but must be non-zero
1579  _varId[arg] = (std::numeric_limits<size_t>::max)();
1580  } else if (aType == CGOpCode::ArrayCreation) {
1581  // a temporary array
1582  size_t arraySize = arg.getArguments().size();
1583  _varId[arg] = _idArrayCount;
1584  _idArrayCount += arraySize;
1585  } else if (aType == CGOpCode::SparseArrayCreation) {
1586  // a temporary array
1587  size_t nnz = arg.getArguments().size();
1588  _varId[arg] = _idSparseArrayCount;
1589  _idSparseArrayCount += nnz;
1590  } else {
1591  // a single temporary variable
1592  _varId[arg] = _idCount;
1593  _idCount++;
1594  }
1595  }
1596  }
1597  }
1598 
1599  }
1600 
1601  markVisited(arg);
1602  };
1603 
1604  depthFirstGraphNavigation(root,
1605  _currentScopeColor,
1606  startAnalysis,
1607  completeAnalysis,
1608  false);
1609 }
1610 
1611 template<class Base>
1613  ScopeIDType scope = _scope[arg];
1614  if (scope >= _scopedVariableOrder.size()) {
1615  _scopedVariableOrder.resize(scope + 1);
1616  }
1617 
1618  if (_scopedVariableOrder[scope].empty() &&
1619  scope != 0 && // the upper most scope does not need any special node at the beginning
1620  _scopes[scope].back().end->getArguments()[0].getOperation() != &arg) {
1621  // the first node must be a beginning of a scope
1622  checkVariableCreation(*_scopes[scope].back().end); // go inside a scope from the end
1623  }
1624 
1625  // must be after checkVariableCreation() because _scopedVariableOrder might be resized
1626  std::vector<Node*>& varOrder = _scopedVariableOrder[scope];
1627 
1628  if (varOrder.size() == varOrder.capacity()) {
1629  varOrder.reserve((varOrder.size() * 3) / 2 + 1);
1630  }
1631 
1632  varOrder.push_back(&arg);
1633 }
1634 
1635 template<class Base>
1637 
1638  reorderOperations(dependent);
1639 
1643  startNewOperationTreeVisit();
1644 
1645  for (size_t i = 0; i < dependent.size(); i++) {
1646  Node* node = dependent[i].getOperationNode();
1647  if (node != nullptr) {
1648  if (!isVisited(*node)) {
1649  // dependencies not visited yet
1651  }
1652  markVisited(*node);
1653  }
1654  }
1655 
1656  // where temporary variables can be released
1657  std::vector<std::vector<Node*>> tempVarRelease(_variableOrder.size());
1658  for (size_t i = 0; i < _variableOrder.size(); i++) {
1659  Node* var = _variableOrder[i];
1660  if (isTemporary(*var) || isTemporaryArray(*var) || isTemporarySparseArray(*var)) {
1661  size_t releaseLocation = getLastUsageEvaluationOrder(*var) - 1;
1662  tempVarRelease[releaseLocation].push_back(var);
1663  }
1664  }
1665 
1666 
1670  std::vector<size_t> freedVariables; // variable IDs no longer in use
1671  _idCount = _minTemporaryVarID;
1672  ArrayIdCompresser<Base> arrayComp(_varId, _idArrayCount);
1673  ArrayIdCompresser<Base> sparseArrayComp(_varId, _idSparseArrayCount);
1674 
1675  for (size_t i = 0; i < _variableOrder.size(); i++) {
1676  Node& var = *_variableOrder[i];
1677 
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]);
1686  }
1687  }
1688 
1689  if (isTemporary(var)) {
1690  // a single temporary variable
1691  if (freedVariables.empty()) {
1692  _varId[var] = _idCount;
1693  _idCount++;
1694  } else {
1695  size_t id = freedVariables.back();
1696  freedVariables.pop_back();
1697  _varId[var] = id;
1698  }
1699  } else if (isTemporaryArray(var)) {
1700  // a temporary array
1701  size_t arrayStart = arrayComp.reserveArraySpace(var);
1702  _varId[var] = arrayStart + 1;
1703  } else if (isTemporarySparseArray(var)) {
1704  // a temporary array
1705  size_t arrayStart = sparseArrayComp.reserveArraySpace(var);
1706  _varId[var] = arrayStart + 1;
1707  }
1708 
1709  }
1710 
1711  _idArrayCount = arrayComp.getIdCount();
1712  _idSparseArrayCount = sparseArrayComp.getIdCount();
1713 }
1714 
1715 template<class Base>
1717  // determine the location of the last temporary variable used for each dependent
1718  startNewOperationTreeVisit();
1719 
1720  // normal dependent nodes
1721  for (size_t i = 0; i < dependent.size(); ++i) {
1722  Node* node = dependent[i].getOperationNode();
1723  if (node != nullptr) {
1724  reorderOperation(*node);
1725  }
1726  }
1727 
1728  // dependent nodes defined inside loops
1729  for (const LoopEndOperationNode<Base>* endNode : _loops.endNodes) {
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)
1733  // TODO: also consider CGOpCode::LoopIndexedDep inside a CGOpCode::endIf
1734  if (args[i].getOperation()->getOperationType() == CGOpCode::LoopIndexedDep) {
1735  reorderOperation(*args[i].getOperation());
1736  }
1737  }
1738  }
1739 }
1740 
1741 template<class Base>
1746  size_t depPos = getEvaluationOrder(node);
1747  size_t lastTmpPos = depPos;
1748  if (!isVisited(node)) {
1749  // dependencies not visited yet
1750  lastTmpPos = findLastTemporaryLocation(node);
1751  }
1752  markVisited(node);
1753 
1757  if (lastTmpPos == depPos || lastTmpPos + 1 == depPos) {
1758  return; // should not change location of the evaluation of this dependent
1759  }
1760 
1761  // should only move if there are temporaries which could use other temporaries released by the dependent
1762  bool foundTemporaries = false;
1763  size_t newPos;
1764  for (size_t l = lastTmpPos + 1; l < depPos; ++l) {
1765  const auto* n = _variableOrder[l - 1];
1766  if (isTemporary(*n) || isTemporaryArray(*n) || isTemporarySparseArray(*n)) {
1767  foundTemporaries = true;
1768  newPos = l;
1769  break;
1770  } else {
1774  CGOpCode op = n->getOperationType();
1775  if (op == CGOpCode::StartIf) {
1776  // must not change scope (find the end of this conditional statement)
1777  ++l;
1778  while (l < depPos) {
1779  const auto* node2 = _variableOrder[l - 1];
1780  if (node2->getOperationType() == CGOpCode::EndIf &&
1781  node2->getArguments()[0].getOperation() == n) {
1782  break; // found the end (returned to the same scope)
1783  }
1784  ++l;
1785  }
1786 
1787  } else if (op == CGOpCode::LoopStart) {
1788  // must not change scope (find the end of this loop statement)
1789  ++l;
1790  while (l < depPos) {
1791  const auto* node2 = _variableOrder[l - 1];
1792  if (node2->getOperationType() == CGOpCode::LoopEnd &&
1793  &static_cast<const LoopEndOperationNode<Base>*> (node2)->getLoopStart() == n) {
1794  break; // found the end (returned to the same scope)
1795  }
1796  ++l;
1797  }
1798  }
1799  }
1800  }
1801 
1802  if (foundTemporaries) {
1803  // move variables
1804  repositionEvaluationQueue(depPos, newPos);
1805  }
1806 }
1807 
1808 template<class Base>
1810 
1811  size_t depOrder = getEvaluationOrder(root);
1812  size_t maxTmpOrder = depOrder; // lowest possible value is 1
1813 
1814  auto nodeAnalysis = [&](SimpleOperationStackData<Base>& stackEl,
1815  SimpleOperationStack<Base>& stack) {
1816  auto& node = stackEl.node();
1817 
1818  const auto& args = node.getArguments();
1819 
1820  for (size_t i = 0; i < args.size(); ++i) {
1821  if (args[i].getOperation() == nullptr) {
1822  continue;
1823  }
1824 
1825  Node& arg = *args[i].getOperation();
1826  CGOpCode aOp = arg.getOperationType();
1827 
1828  if (aOp == CGOpCode::LoopEnd || aOp == CGOpCode::EndIf || aOp == CGOpCode::ElseIf || aOp == CGOpCode::Else) {
1829  continue; //should not move variables to a different scope
1830  }
1831 
1832  if (aOp == CGOpCode::Index) {
1833  size_t iorder = getEvaluationOrder(static_cast<IndexOperationNode <Base>&> (arg).getIndexCreationNode());
1834  if (iorder > maxTmpOrder)
1835  maxTmpOrder = iorder;
1836 
1837  } else if (getEvaluationOrder(arg) == depOrder) {
1838  // dependencies not visited yet
1839  stack.emplace_back(node, i);
1840 
1841  } else {
1842  // no need to visit dependencies
1843  if (getEvaluationOrder(arg) > maxTmpOrder)
1844  maxTmpOrder = getEvaluationOrder(arg);
1845  }
1846 
1847  }
1848  };
1849 
1850  depthFirstGraphNavigation(root, nodeAnalysis, true);
1851 
1852  return maxTmpOrder;
1853 }
1854 
1855 template<class Base>
1856 inline void CodeHandler<Base>::repositionEvaluationQueue(size_t fromPos, size_t toPos) {
1857  // Warning: there is an offset of 1 between the evaluation order saved
1858  // in the node and the actual location in the _variableOrder
1859  CPPADCG_ASSERT_UNKNOWN(fromPos > toPos)
1860  Node* node = _variableOrder[fromPos - 1]; // node to be moved
1861 
1862  // move variables in between the order change
1863  for (size_t l = fromPos - 1; l > toPos - 1; --l) {
1864  _variableOrder[l] = _variableOrder[l - 1];
1865  updateEvaluationQueueOrder(*_variableOrder[l], l + 1);
1866  }
1867 
1868  _variableOrder[toPos - 1] = node;
1869  updateEvaluationQueueOrder(*node, toPos);
1870 }
1871 
1872 template<class Base>
1874 
1875  auto startAnalysis = [this](OperationStackData<Base>& stackEl,
1876  OperationStack<Base>& stack) {
1877  auto& node = stackEl.node();
1878  CGOpCode op = node.getOperationType();
1879 
1880  markVisited(node);
1881 
1882  if (op == CGOpCode::LoopEnd) {
1883  auto& loopEnd = static_cast<LoopEndOperationNode<Base>&> (node);
1884  _loops.depth++;
1885  _loops.outerVars.resize(_loops.depth + 1);
1886  _loops.startEvalOrder.push_back(getEvaluationOrder(loopEnd.getLoopStart()));
1887 
1888  } else if (op == CGOpCode::LoopStart) {
1889  _loops.depth--; // leaving the current loop
1890  }
1891 
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();
1899 
1900  if (!isVisited(arg)) {
1901  // dependencies not visited yet
1902  stack.emplace_back(node, i, 0);
1903  }
1904  }
1905  }
1906 
1907  return true;
1908  };
1909 
1910  auto endAnalysis = [this](OperationStackData<Base>& stackEl) {
1911  // executed after all children have been visited
1912 
1913  auto& node = stackEl.node();
1914  CGOpCode op = node.getOperationType();
1915 
1916  for (const Arg& it : node.getArguments()) {
1917  if (it.getOperation() != nullptr) {
1918  Node& arg = *it.getOperation();
1919 
1920  size_t order = getEvaluationOrder(node);
1921  Node* aa = getOperationFromAlias(arg); // follow alias!
1922  if (aa != nullptr) {
1923  if (getLastUsageEvaluationOrder(*aa) < order) {
1924  setLastUsageEvaluationOrder(*aa, order);
1925  }
1926 
1927  if (_loops.depth >= 0 &&
1928  getEvaluationOrder(*aa) < _loops.startEvalOrder[_loops.depth] &&
1929  isTemporary(*aa)) {
1930  // outer variable used inside the loop
1931  _loops.outerVars[_loops.depth].insert(aa);
1932  }
1933  }
1934  }
1935  }
1936 
1937  if (op == CGOpCode::LoopEnd) {
1942  size_t order = getEvaluationOrder(node);
1943 
1944  const std::set<Node*>& outerLoopUsages = _loops.outerVars.back();
1945  for (Node* outerVar : outerLoopUsages) {
1946  Node* aa = getOperationFromAlias(*outerVar); // follow alias!
1947  if (aa != nullptr && getLastUsageEvaluationOrder(*aa) < order)
1948  setLastUsageEvaluationOrder(*aa, order);
1949  }
1950 
1951  _loops.depth--;
1952  _loops.outerVars.pop_back();
1953  _loops.startEvalOrder.pop_back();
1954 
1955  } else if (op == CGOpCode::LoopStart) {
1956  _loops.depth++; // coming back to the loop
1957  }
1958 
1959  };
1960 
1961  depthFirstGraphNavigation(root,
1962  0,
1963  startAnalysis,
1964  endAnalysis,
1965  true);
1966 
1967 }
1968 
1969 template<class Base>
1971 
1972  auto analyse = [this](SimpleOperationStackData<Base>& stackEl,
1973  SimpleOperationStack<Base>& stack) {
1974  auto& node = stackEl.parent();
1975  auto& arg = stackEl.node();
1976 
1977  if (getEvaluationOrder(arg) == 0) {
1978  setEvaluationOrder(arg, getEvaluationOrder(node));
1979 
1980  stack.pushNodeArguments(arg);
1981  }
1982  };
1983 
1984  depthFirstGraphNavigation(root, analyse, false);
1985 
1986 }
1987 
1988 template<class Base>
1990  size_t newEvalOrder) {
1991 
1992  auto analyse = [&](SimpleOperationStackData<Base>& stackEl,
1993  SimpleOperationStack<Base>& stack) {
1994  auto& node = stackEl.node();
1995  size_t oldEvalOrder = getEvaluationOrder(node);
1996 
1997  setEvaluationOrder(node, newEvalOrder);
1998 
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);
2004  }
2005  }
2006  };
2007 
2008  depthFirstGraphNavigation(root, analyse, true);
2009 }
2010 
2011 template<class Base>
2013  _variableDependencies.resize(_variableOrder.size());
2014 
2015  for (size_t i = 0; i < _variableOrder.size(); i++) {
2016  Node& var = *_variableOrder[i];
2017 
2018  _variableDependencies[i].clear();
2019  startNewOperationTreeVisit();
2020 
2021  for (const auto& a : var) {
2022  if (a.getOperation() != nullptr) {
2023  findVariableDependencies(i, *a.getOperation());
2024  }
2025  }
2026  }
2027 }
2028 
2029 template<class Base>
2030 inline void CodeHandler<Base>::findVariableDependencies(size_t i,
2031  Node& root) {
2032 
2033  auto analyse = [&](SimpleOperationStackData<Base>& stackEl,
2034  SimpleOperationStack<Base>& stack) {
2035  auto& node = stackEl.node();
2036 
2037  if (!isVisited(node)) {
2038  markVisited(node);
2039 
2040  if(_varId[node] != 0) {
2041  _variableDependencies[i].insert(&node);
2042  } else {
2043  stack.pushNodeArguments(node);
2044  }
2045  }
2046  };
2047 
2048  depthFirstGraphNavigation(root, analyse, true);
2049 }
2050 
2051 template<class Base>
2052 inline bool CodeHandler<Base>::isIndependent(const Node& arg) const {
2053  return arg.getOperationType() == CGOpCode::Inv;
2054 }
2055 
2056 template<class Base>
2057 inline bool CodeHandler<Base>::isTemporary(const Node& arg) const {
2058  CGOpCode op = arg.getOperationType();
2059  return op != CGOpCode::ArrayCreation && // classified as TemporaryArray
2060  op != CGOpCode::SparseArrayCreation && // classified as TemporarySparseArray
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 && // not considered as a temporary (the temporary is CGTmpDclOp)
2072  op != CGOpCode::Index &&
2073  op != CGOpCode::IndexAssign &&
2074  op != CGOpCode::Tmp && // not considered as a temporary (the temporary is CGTmpDclOp)
2075  _varId[arg] >= _minTemporaryVarID;
2076 }
2077 
2078 template<class Base>
2079 inline bool CodeHandler<Base>::isTemporaryArray(const Node& arg) {
2080  return arg.getOperationType() == CGOpCode::ArrayCreation;
2081 }
2082 
2083 template<class Base>
2084 inline bool CodeHandler<Base>::isTemporarySparseArray(const Node& arg) {
2085  return arg.getOperationType() == CGOpCode::SparseArrayCreation;
2086 }
2087 
2088 template<class Base>
2090  if (alias.getOperationType() != CGOpCode::Alias) {
2091  return &alias;
2092  } else {
2093  Node* aa = &alias;
2094  do {
2095  CPPADCG_ASSERT_UNKNOWN(aa->getArguments().size() == 1)
2096  aa = aa->getArguments()[0].getOperation();
2097  } while (aa != nullptr && aa->getOperationType() == CGOpCode::Alias);
2098  return aa;
2099  }
2100 }
2101 
2102 template<class Base>
2103 inline size_t CodeHandler<Base>::getEvaluationOrder(const Node& node) const {
2104  return _evaluationOrder[node];
2105 }
2106 
2107 template<class Base>
2109  size_t order) {
2110  CPPADCG_ASSERT_UNKNOWN(order <= _variableOrder.size())
2111  _evaluationOrder[node] = order;
2112 }
2113 
2114 template<class Base>
2115 inline size_t CodeHandler<Base>::getLastUsageEvaluationOrder(const Node& node) const {
2116  return _lastUsageOrder[node];
2117 }
2118 
2119 template<class Base>
2121  size_t last) {
2122  CPPADCG_ASSERT_UNKNOWN(last <= _variableOrder.size()) // _lastUsageOrder[node] = 0 means that it was never used
2123  _lastUsageOrder[node] = last;
2124 
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);
2131  }
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);
2137  }
2138  }
2139 }
2140 
2141 template<class Base>
2142 inline size_t CodeHandler<Base>::getTotalUsageCount(const Node& node) const {
2143  return _totalUseCount[node];
2144 }
2145 
2146 template<class Base>
2147 inline void CodeHandler<Base>::setTotalUsageCount(const Node& node,
2148  size_t cout) {
2149  _totalUseCount[node] = cout;
2150 }
2151 
2152 template<class Base>
2153 inline void CodeHandler<Base>::increaseTotalUsageCount(const Node& node) {
2154  _totalUseCount[node]++;
2155 }
2156 
2157 template<class Base>
2159  _variableOrder.clear();
2160  _scopedVariableOrder.resize(1);
2161  _scopedVariableOrder[0].clear();
2162  _evaluationOrder.fill(0);
2163  _lastUsageOrder.fill(0);
2164  _totalUseCount.fill(0);
2165  _operationCount.fill(0);
2166  _varId.fill(0);
2167  _scope.fill(0);
2168 }
2169 
2170 } // END cg namespace
2171 } // END CppAD namespace
2172 
2173 #endif
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
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
Definition: array_view.hpp:202
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")
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