CppADCodeGen  2.3.0
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  *
7  * CppADCodeGen is distributed under multiple licenses:
8  *
9  * - Eclipse Public License Version 1.0 (EPL1), and
10  * - GNU General Public License Version 3 (GPL3).
11  *
12  * EPL1 terms and conditions can be found in the file "epl-v10.txt", while
13  * terms and conditions for the GPL3 can be found in the file "gpl3.txt".
14  * ----------------------------------------------------------------------------
15  * Author: Joao Leal
16  */
17 
18 namespace CppAD {
19 namespace cg {
20 
21 template<class Base>
22 CodeHandler<Base>::CodeHandler(size_t varCount) :
23  _idVisit(1),
24  _idCount(1),
25  _idArrayCount(1),
26  _idSparseArrayCount(1),
27  _idAtomicCount(1),
28  _dependents(nullptr),
29  _lastVisit(*this),
30  _scope(*this),
31  _evaluationOrder(*this),
32  _lastUsageOrder(*this),
33  _totalUseCount(*this),
34  _varId(*this),
35  _scopedVariableOrder(1),
36  _atomicFunctionsOrder(nullptr),
37  _used(false),
38  _reuseIDs(true),
39  _scopeColorCount(0),
40  _currentScopeColor(0),
41  _lang(nullptr),
42  _minTemporaryVarID(0),
43  _zeroDependents(false),
44  _verbose(false),
45  _jobTimer(nullptr) {
46  _codeBlocks.reserve(varCount);
47  //_variableOrder.reserve(1 + varCount / 3);
48  _scopedVariableOrder[0].reserve(1 + varCount / 3);
49 
50  _auxIndexI = makeIndexDclrNode("i");
51  _auxIterationIndexOp = makeIndexNode(*_auxIndexI);
52 }
53 
54 template<class Base>
56  reset();
57 
58  for (auto* v : _managedVectors) {
59  v->handler_ = nullptr;
60  }
61 }
62 
63 template<class Base>
64 inline void CodeHandler<Base>::setReuseVariableIDs(bool reuse) {
65  _reuseIDs = reuse;
66 }
67 
68 template<class Base>
70  return _reuseIDs;
71 }
72 
73 template<class Base>
74 inline void CodeHandler<Base>::makeVariables(std::vector<AD<CGB> >& variables) {
75  for (auto& v : variables) {
76  makeVariable(v);
77  }
78 }
79 
80 template<class Base>
81 inline void CodeHandler<Base>::makeVariable(AD<CGB>& variable) {
82  CGB v;
83  makeVariable(v); // make it a codegen variable
84  variable = v; // variable id now the same as v
85 }
86 
87 template<class Base>
88 inline void CodeHandler<Base>::makeVariable(CGB& variable) {
89  _independentVariables.push_back(makeNode(CGOpCode::Inv));
90  variable.makeVariable(*_independentVariables.back());
91 }
92 
93 template<class Base>
95  return _independentVariables.size();
96 }
97 
98 template<class Base>
100  return _varId;
101 }
102 
103 template<class Base>
104 inline size_t CodeHandler<Base>::getMaximumVariableID() const {
105  return _idCount;
106 }
107 
108 template<class Base>
109 inline bool CodeHandler<Base>::isVerbose() const {
110  return _verbose;
111 }
112 
113 template<class Base>
114 inline void CodeHandler<Base>::setVerbose(bool verbose) {
115  _verbose = verbose;
116 }
117 
118 template<class Base>
120  return _jobTimer;
121 }
122 
123 template<class Base>
124 inline void CodeHandler<Base>::setJobTimer(JobTimer* jobTimer) {
125  _jobTimer = jobTimer;
126 }
127 
128 template<class Base>
130  return _zeroDependents;
131 }
132 
133 template<class Base>
134 inline void CodeHandler<Base>::setZeroDependents(bool zeroDependents) {
135  _zeroDependents = zeroDependents;
136 }
137 
138 template<class Base>
140  CPPADCG_ASSERT_UNKNOWN(var.getOperationType() == CGOpCode::Inv);
141 
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");
146  }
147 
148  return it - _independentVariables.begin();
149 }
150 
151 template<class Base>
152 inline size_t CodeHandler<Base>::getOperationTreeVisitId() const {
153  return _idVisit;
154 }
155 
156 template<class Base>
158  assert(_idVisit < std::numeric_limits<size_t>::max());
159 
160  _lastVisit.adjustSize();
161  _idVisit++;
162 }
163 
164 template<class Base>
165 inline bool CodeHandler<Base>::isVisited(const Node& node) const {
166  size_t p = node.getHandlerPosition();
167  return p < _lastVisit.size() && _lastVisit[node] == _idVisit;
168 }
169 
170 template<class Base>
171 inline void CodeHandler<Base>::markVisited(const Node& node) {
172  _lastVisit.adjustSize(node);
173  _lastVisit[node] = _idVisit;
174 }
175 
176 template<class Base>
177 inline const std::string* CodeHandler<Base>::getAtomicFunctionName(size_t id) const {
178  typename std::map<size_t, CGAbstractAtomicFun<Base>*>::const_iterator it;
179  it = _atomicFunctions.find(id);
180  if (it != _atomicFunctions.end())
181  return &(it->second->afun_name());
182  else
183  return nullptr;
184 }
185 
186 template<class Base>
187 inline const std::map<size_t, CGAbstractAtomicFun<Base>* >& CodeHandler<Base>::getAtomicFunctions() const {
188  return _atomicFunctions;
189 }
190 
191 template<class Base>
192 const std::vector<int>& CodeHandler<Base>::getExternalFuncMaxForwardOrder() const {
194 }
195 
196 template<class Base>
197 const std::vector<int>& CodeHandler<Base>::getExternalFuncMaxReverseOrder() const {
199 }
200 
201 template<class Base>
202 inline const std::string* CodeHandler<Base>::getLoopName(size_t id) const {
203  return _loops.getLoopName(id);
204 }
205 
206 template<class Base>
207 inline const std::vector<typename CodeHandler<Base>::ScopePath>&
209  return _scopes;
210 }
211 
212 template<class Base>
213 void CodeHandler<Base>::generateCode(std::ostream& out,
214  Language<Base>& lang,
215  CppAD::vector<CGB>& dependent,
217  const std::string& jobName) {
218  ArrayView<CGB> deps(dependent);
219  generateCode(out, lang, deps, nameGen, jobName);
220 }
221 
222 template<class Base>
223 void CodeHandler<Base>::generateCode(std::ostream& out,
224  Language<Base>& lang,
225  std::vector<CGB>& dependent,
227  const std::string& jobName) {
228  ArrayView<CGB> deps(dependent);
229  generateCode(out, lang, deps, nameGen, jobName);
230 }
231 
232 template<class Base>
233 void CodeHandler<Base>::generateCode(std::ostream& out,
234  Language<Base>& lang,
235  ArrayView<CGB>& dependent,
237  const std::string& jobName) {
238  std::vector<std::string> atomicFunctions;
239  generateCode(out, lang, dependent, nameGen, atomicFunctions, jobName);
240 }
241 
242 template<class Base>
243 void CodeHandler<Base>::generateCode(std::ostream& out,
244  Language<Base>& lang,
245  CppAD::vector<CGB>& dependent,
247  std::vector<std::string>& atomicFunctions,
248  const std::string& jobName) {
249  ArrayView<CGB> deps(dependent);
250  generateCode(out, lang, deps, nameGen, atomicFunctions, jobName);
251 }
252 
253 template<class Base>
254 void CodeHandler<Base>::generateCode(std::ostream& out,
255  Language<Base>& lang,
256  std::vector<CGB>& dependent,
258  std::vector<std::string>& atomicFunctions,
259  const std::string& jobName) {
260  ArrayView<CGB> deps(dependent);
261  generateCode(out, lang, deps, nameGen, atomicFunctions, jobName);
262 }
263 
264 template<class Base>
265 void CodeHandler<Base>::generateCode(std::ostream& out,
266  Language<Base>& lang,
267  ArrayView<CGB>& dependent,
269  std::vector<std::string>& atomicFunctions,
270  const std::string& jobName) {
271  using namespace std::chrono;
272  steady_clock::time_point beginTime;
273 
274  if (_jobTimer != nullptr) {
275  _jobTimer->startingJob("source for '" + jobName + "'");
276  } else if (_verbose) {
277  std::cout << "generating source for '" << jobName << "' ... ";
278  std::cout.flush();
279  beginTime = steady_clock::now();
280  }
281 
282  _lang = &lang;
283  _idCount = 1;
284  _idArrayCount = 1;
285  _idSparseArrayCount = 1;
286  _idAtomicCount = 1;
287  _dependents = &dependent;
288  _atomicFunctionsOrder = &atomicFunctions;
289  _atomicFunctionsMaxForward.resize(atomicFunctions.size());
290  _atomicFunctionsMaxReverse.resize(atomicFunctions.size());
292  _loops.prepare4NewSourceGen();
293  _scopeColorCount = 0;
294  _currentScopeColor = 0;
295  _scopes.reserve(4);
296  _scopes.resize(1);
297  _alteredNodes.clear();
298  _evaluationOrder.adjustSize();
299  _lastUsageOrder.adjustSize();
300  _totalUseCount.adjustSize();
301  _varId.adjustSize();
302  _scope.adjustSize();
303 
304  for (size_t i = 0; i < atomicFunctions.size(); i++) {
305  _atomicFunctionName2Index[atomicFunctions[i]] = i;
306  }
307  std::fill(_atomicFunctionsMaxForward.begin(), _atomicFunctionsMaxForward.end(), -1);
308  std::fill(_atomicFunctionsMaxReverse.begin(), _atomicFunctionsMaxReverse.end(), -1);
309 
310  if (_used) {
311  resetManagedNodes();
312  }
313  _used = true;
314 
318  size_t n = _independentVariables.size();
319  for (size_t j = 0; j < n; j++) {
320  _varId[*_independentVariables[j]] = _idCount++;
321  }
322 
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++;
328  }
329  }
330 
331  _minTemporaryVarID = _idCount;
332 
336  for (size_t i = 0; i < m; i++) {
337  Node* node = dependent[i].getOperationNode();
338  if (node != nullptr) {
339  markCodeBlockUsed(*node);
340  }
341  }
342 
346  _scopedVariableOrder.reserve(std::max(size_t(1), _scopes.size()) + 10); // some additional scopes might still be added
347 
348  startNewOperationTreeVisit();
349 
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)) {
355  // dependencies not visited yet
356  checkVariableCreation(code);
357 
358  // make sure new temporary variables are NOT created for
359  // the independent variables and that a dependency did
360  // not use it first
361  if ((_varId[code] == 0 || !isIndependent(code)) && !isVisited(code)) {
362  addToEvaluationQueue(code);
363  }
364  }
365  markVisited(code);
366  }
367  }
368 
372  if (_scopedVariableOrder.size() == 1) {
373  _variableOrder.swap(_scopedVariableOrder[0]); // most common situation
374  } else {
375  optimizeIfs(); // reduce the number of adjoining ifs
376 
377  size_t vosize = 0;
378  for (size_t s = 0; s < _scopedVariableOrder.size(); s++) {
379  vosize += _scopedVariableOrder[s].size();
380  }
381  _variableOrder.resize(vosize);
382 
383  size_t e = 0;
384  addScopeToVarOrder(0, e);
385 
386  // if e > vosize then some nodes (marking the beginning of scopes)
387  // must have been added more than once
388  CPPADCG_ASSERT_UNKNOWN(_variableOrder.size() == e);
389  }
390 
391  for (size_t p = 0; p < _variableOrder.size(); p++) {
392  Node& arg = *_variableOrder[p];
393  setEvaluationOrder(arg, p + 1);
395  }
396 
400  if (_reuseIDs) {
401  reduceTemporaryVariables(dependent);
402  }
403 
407  _variableDependencies.clear();
408  if(lang.requiresVariableDependencies()) {
410  }
411 
412  nameGen.setTemporaryVariableID(_minTemporaryVarID, _idCount - 1, _idArrayCount - 1, _idSparseArrayCount - 1);
413 
414  std::map<std::string, size_t> atomicFunctionName2Id;
415  typename std::map<size_t, CGAbstractAtomicFun < Base>*>::iterator itA;
416  for (itA = _atomicFunctions.begin(); itA != _atomicFunctions.end(); ++itA) {
417  atomicFunctionName2Id[itA->second->afun_name()] = itA->first;
418  }
419 
420  std::map<size_t, size_t> atomicFunctionId2Index;
421  std::map<size_t, std::string> atomicFunctionId2Name;
422  for (size_t i = 0; i < _atomicFunctionsOrder->size(); i++) {
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;
428  }
429  }
430 
434  _info.reset(new LanguageGenerationData<Base>(_independentVariables, dependent,
435  _minTemporaryVarID, _varId, _variableOrder, _variableDependencies,
436  nameGen,
437  atomicFunctionId2Index, atomicFunctionId2Name,
439  _reuseIDs,
440  _loops.indexes, _loops.indexRandomPatterns,
441  _loops.dependentIndexPatterns, _loops.independentIndexPatterns,
443  _zeroDependents));
444  lang.generateSourceCode(out, _info);
445 
450 
451  // restore altered nodes
452  for (const auto& itAlt : _alteredNodes) {
453  Node* tmp = itAlt.first;
454  Node* opClone = itAlt.second;
455  if (tmp->getOperationType() == CGOpCode::Tmp && !tmp->getInfo().empty()) { // some might have already been restored
456  tmp->setOperation(opClone->getOperationType(), opClone->getArguments());
457  tmp->getInfo() = opClone->getInfo();
458  }
459  }
460  _alteredNodes.clear();
461 
462  if (_jobTimer != nullptr) {
463  _jobTimer->finishedJob();
464  } else if (_verbose) {
465  OStreamConfigRestore osr(std::cout);
466  duration<float> dt = steady_clock::now() - beginTime;
467  std::cout << "done [" << std::fixed << std::setprecision(3) << dt.count() << "]" << std::endl;
468  }
469 }
470 
471 template<class Base>
473  if (_idCount == 1)
474  return 0; // no code generated
475  else
476  return _idCount - _minTemporaryVarID;
477 }
478 
479 template<class Base>
481  return _idArrayCount - 1;
482 }
483 
484 template<class Base>
486  return _idSparseArrayCount - 1;
487 }
488 
489 template<class Base>
491  for (Node* n : _codeBlocks) {
492  delete n;
493  }
494  _codeBlocks.clear();
495  _independentVariables.clear();
496  _idCount = 1;
497  _idArrayCount = 1;
498  _idSparseArrayCount = 1;
499  _idAtomicCount = 1;
500 
501  _loops.reset();
502 
503  _used = false;
504 }
505 
506 template<class Base>
508  _scope.fill(0);
509  _evaluationOrder.fill(0);
510  _lastUsageOrder.fill(0);
511  _totalUseCount.fill(0);
512  _varId.fill(0);
513 }
514 
515 /******************************************************************************
516 * access to managed memory
517 ******************************************************************************/
518 
519 template<class Base>
521  return manageOperationNode(new Node(n));
522 }
523 
524 template<class Base>
526  return manageOperationNode(new Node(this, op));
527 }
528 
529 template<class Base>
531  const Arg& arg) {
532  return manageOperationNode(new Node(this, op, arg));
533 }
534 
535 template<class Base>
537  std::vector<Arg>&& args) {
538  return manageOperationNode(new Node(this, op, std::move(args)));
539 }
540 
541 template<class Base>
543  std::vector<size_t>&& info,
544  std::vector<Arg>&& args) {
545  return manageOperationNode(new Node(this, op, std::move(info), std::move(args)));
546 }
547 
548 template<class Base>
550  const std::vector<size_t>& info,
551  const std::vector<Arg>& args) {
552  return manageOperationNode(new Node(this, op, info, args));
553 }
554 
555 template<class Base>
557  size_t iterationCount) {
558  auto* n = new LoopStartOperationNode<Base>(this, indexDcl, iterationCount);
559  manageOperationNode(n);
560  return n;
561 }
562 
563 template<class Base>
565  IndexOperationNode<Base>& iterCount) {
566  auto* n = new LoopStartOperationNode<Base>(this, indexDcl, iterCount);
567  manageOperationNode(n);
568  return n;
569 }
570 
571 template<class Base>
573  const std::vector<Arg>& endArgs) {
574  auto* n = new LoopEndOperationNode<Base>(this, loopStart, endArgs);
575  manageOperationNode(n);
576  return n;
577 }
578 
579 template<class Base>
580 inline PrintOperationNode<Base>* CodeHandler<Base>::makePrintNode(const std::string& before,
581  const Arg& arg,
582  const std::string& after) {
583  auto* n = new PrintOperationNode<Base>(this, before, arg, after);
584  manageOperationNode(n);
585  return n;
586 }
587 
588 template<class Base>
590  auto* n = new IndexOperationNode<Base>(this, indexDcl);
591  manageOperationNode(n);
592  return n;
593 }
594 
595 template<class Base>
597  auto* n = new IndexOperationNode<Base>(this, loopStart);
598  manageOperationNode(n);
599  return n;
600 }
601 
602 template<class Base>
604  auto* n = new IndexOperationNode<Base>(this, indexAssign);
605  manageOperationNode(n);
606  return n;
607 }
608 
609 template<class Base>
611  IndexPattern& indexPattern,
612  IndexOperationNode<Base>& index1) {
613  auto* n = new IndexAssignOperationNode<Base>(this, index, indexPattern, index1);
614  manageOperationNode(n);
615  return n;
616 }
617 
618 template<class Base>
620  IndexPattern& indexPattern,
621  IndexOperationNode<Base>* index1,
622  IndexOperationNode<Base>* index2) {
623  auto* n = new IndexAssignOperationNode<Base>(this, index, indexPattern, index1, index2);
624  manageOperationNode(n);
625  return n;
626 }
627 
628 template<class Base>
629 inline OperationNode<Base>* CodeHandler<Base>::makeIndexDclrNode(const std::string& name) {
630  CPPADCG_ASSERT_KNOWN(!name.empty(), "index name cannot be empty");
631  auto* n = manageOperationNode(new Node(this, CGOpCode::IndexDeclaration));
632  n->setName(name);
633  return n;
634 }
635 
636 template<class Base>
638  return _codeBlocks.size();
639 }
640 
641 template<class Base>
642 inline const std::vector<OperationNode<Base> *>& CodeHandler<Base>::getManagedNodes() const {
643  return _codeBlocks;
644 }
645 
646 template<class Base>
647 inline void CodeHandler<Base>::deleteManagedNodes(size_t start, size_t end) {
648  if (start >= end)
649  return;
650 
651  start = std::min<size_t>(start, _codeBlocks.size());
652  end = std::min<size_t>(end, _codeBlocks.size());
653 
654  for (size_t i = start; i < end; ++i) {
655  delete _codeBlocks[i];
656  }
657  _codeBlocks.erase(_codeBlocks.begin() + start, _codeBlocks.begin() + end);
658 
659  // update positions
660  for (size_t i = start; i < _codeBlocks.size(); ++i) {
661  _codeBlocks[i]->setHandlerPosition(i);
662  }
663 
664  for (auto* v : _managedVectors) {
665  v->nodesErased(start, end);
666  }
667 }
668 
669 /******************************************************************************
670  * Value generation
671  *****************************************************************************/
672 template<class Base>
674  return CGB(arg);
675 }
676 
677 /******************************************************************************
678  * Index patterns
679  *****************************************************************************/
680 template<class Base>
682  std::set<RandomIndexPattern*>& found) {
683  if (ip == nullptr)
684  return;
685 
686  if (ip->getType() == IndexPatternType::Random1D || ip->getType() == IndexPatternType::Random2D) {
687  found.insert(static_cast<RandomIndexPattern*> (ip));
688  } else {
689  std::set<IndexPattern*> indexes;
690  ip->getSubIndexes(indexes);
691  for (IndexPattern* sip : indexes) {
692  if (sip->getType() == IndexPatternType::Random1D || sip->getType() == IndexPatternType::Random2D)
693  found.insert(static_cast<RandomIndexPattern*> (sip));
694  }
695  }
696 }
697 
698 /**************************************************************************
699  * Operation graph manipulation
700  *************************************************************************/
701 template<class Base>
703  size_t pos = code->getHandlerPosition();
704  if (pos >= _codeBlocks.size() || code != _codeBlocks[pos]) {
705  manageOperationNode(code);
706  return false;
707  }
708  return true;
709 }
710 
711 template<class Base>
713  //CPPADCG_ASSERT_UNKNOWN(std::find(_codeBlocks.begin(), _codeBlocks.end(), code) == _codeBlocks.end()); // <<< too great of an impact in performance
714  if (_codeBlocks.capacity() == _codeBlocks.size()) {
715  _codeBlocks.reserve((_codeBlocks.size() * 3) / 2 + 1);
716  }
717 
718  code->setHandlerPosition(_codeBlocks.size());
719  _codeBlocks.push_back(code);
720  return code;
721 }
722 
723 template<class Base>
725  _managedVectors.insert(v);
726 }
727 
728 template<class Base>
730  _managedVectors.erase(v);
731 }
732 
733 template<class Base>
735  increaseTotalUsageCount(code);
736 
737  CGOpCode op = code.getOperationType();
738  if (isIndependent(code)) {
739  return; // nothing to do
740  } else if (op == CGOpCode::Alias) {
745  CPPADCG_ASSERT_UNKNOWN(code.getArguments().size() == 1);
746  Node* arg = code.getArguments()[0].getOperation();
747  if (arg != nullptr) {
748  markCodeBlockUsed(*arg);
749  }
750 
751  } else if (getTotalUsageCount(code) == 1) {
752  // first time this operation is visited
753 
754  size_t previousScope = _currentScopeColor;
755 
756  _scope[code] = _currentScopeColor;
757 
758  // check if there is a scope change
759  if (op == CGOpCode::LoopStart || op == CGOpCode::StartIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
760  // leaving a scope
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; // save the initial node
765  } else {
766  CPPADCG_ASSERT_UNKNOWN(!code.getArguments().empty() &&
767  code.getArguments()[0].getOperation() != nullptr &&
768  code.getArguments()[0].getOperation()->getOperationType() == CGOpCode::StartIf);
769  sPath.back().beginning = code.getArguments()[0].getOperation(); // save the initial node
770  }
771  _currentScopeColor = sPath.size() > 1 ? sPath[sPath.size() - 2].color : 0;
772  }
773 
774  if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
775  // entering a new scope
776  _currentScopeColor = ++_scopeColorCount;
777 
778  _scopes.resize(_currentScopeColor + 1);
779  _scopes[_currentScopeColor] = _scopes[previousScope];
780 
781  // change current scope
782  if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf) {
783  // one more scope level
784  _scopes[_currentScopeColor].push_back(ScopePathElement<Base>(_currentScopeColor, &code));
785  } else {
786  // same level but different scope
787  _scopes[_currentScopeColor].back() = ScopePathElement<Base>(_currentScopeColor, &code);
788  }
789 
790  if (op == CGOpCode::LoopEnd) {
791  _loops.addLoopEndNode(code);
792  }
793  }
794 
798  for (const Arg& it : code.getArguments()) {
799  if (it.getOperation() != nullptr) {
800  markCodeBlockUsed(*it.getOperation());
801  }
802  }
803 
804  if (op == CGOpCode::Index) {
805  const IndexOperationNode<Base>& inode = static_cast<const IndexOperationNode<Base>&> (code);
806  // indexes that don't depend on a loop start or an index assignment are declared elsewhere
807  if (inode.isDefinedLocally()) {
808  _loops.indexes.insert(&inode.getIndex());
809  }
810  } else if (op == CGOpCode::LoopIndexedIndep || op == CGOpCode::LoopIndexedDep || op == CGOpCode::IndexAssign) {
811  IndexPattern* ip;
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];
818  } else {
819  ip = &static_cast<IndexAssignOperationNode<Base>&> (code).getIndexPattern();
820  }
821 
822  findRandomIndexPatterns(ip, _loops.indexRandomPatterns);
823 
824  } else if (op == CGOpCode::DependentRefRhs) {
825  CPPADCG_ASSERT_UNKNOWN(code.getInfo().size() == 1);
826  size_t depIndex = code.getInfo()[0];
827 
828  CPPADCG_ASSERT_UNKNOWN(_dependents->size() > depIndex);
829  Node* depNode = (*_dependents)[depIndex].getOperationNode();
830  CPPADCG_ASSERT_UNKNOWN(depNode != nullptr && depNode->getOperationType() != CGOpCode::Inv);
831 
832  _varId[code] = _varId[*depNode];
833  }
834 
838  if (previousScope != _currentScopeColor) {
839  _currentScopeColor = previousScope;
840  }
841 
842  } else {
843  // been to this node before
844 
845  if (op == CGOpCode::Tmp && !code.getInfo().empty()) {
851  if (_scope[code] == _currentScopeColor) {
852  // outside an if (defined for all iterations)
853  restoreTemporaryVar(code);
854  } else {
856  }
857 
858  } else if (_scope[code] != _currentScopeColor && op != CGOpCode::LoopIndexedIndep) {
859  ScopeIDType oldScope = _scope[code];
865  size_t depth = findFirstDifferentScope(oldScope, _currentScopeColor);
866 
867  // update the scope where it should be defined
868  ScopeIDType newScope;
869  if (depth == 0)
870  newScope = 0;
871  else
872  newScope = _scopes[_currentScopeColor][depth - 1].color;
873 
874  if (oldScope != newScope) {
878  bool addedIf = handleTemporaryVarInDiffScopes(code, oldScope, newScope);
879 
880  if (!addedIf) {
881  _scope[code] = newScope;
882 
886  const std::vector<Arg>& args = code.getArguments();
887  size_t aSize = args.size();
888  for (size_t a = 0; a < aSize; a++) {
889  updateVarScopeUsage(args[a].getOperation(), newScope, oldScope);
890  }
891  }
892  }
893  }
894  }
895 }
896 
897 template<class Base>
899  size_t oldScope,
900  size_t newScope) {
901  if (_currentScopeColor == 0)
902  return false;
903 
907  CPPADCG_ASSERT_KNOWN(code.getOperationType() != CGOpCode::ArrayCreation, "Not supported yet");
908  CPPADCG_ASSERT_KNOWN(code.getOperationType() != CGOpCode::SparseArrayCreation, "Not supported yet");
909 
913  std::vector<size_t> iterationRegions;
914  Node* bScopeNewEnd = _scopes[_currentScopeColor].back().end;
915  Node* bScopeOldEnd = _scopes[oldScope].back().end;
916 
917  CGOpCode bNewOp = bScopeNewEnd->getOperationType();
918  CGOpCode bOldOp = bScopeOldEnd->getOperationType();
919 
920  if ((bNewOp == CGOpCode::EndIf || bNewOp == CGOpCode::Else || bNewOp == CGOpCode::ElseIf) &&
921  (bOldOp == CGOpCode::EndIf || bOldOp == CGOpCode::Else || bOldOp == CGOpCode::ElseIf)) {
922  // used in 2 different if/else branches
923 
927  Node* bScopeNew = bScopeNewEnd->getArguments()[0].getOperation();
928  Node* bScopeOld = bScopeOldEnd->getArguments()[0].getOperation();
929 
930  IndexOperationNode<Base>* newIterIndexOp = nullptr;
931  iterationRegions = ifBranchIterationRanges(bScopeNew, newIterIndexOp);
932  CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2);
933 
934  IndexOperationNode<Base>* oldIterIndexOp = nullptr;
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);
939 
940  if (iterationRegions.size() > 2 ||
941  iterationRegions[0] != 0 ||
942  iterationRegions[1] != std::numeric_limits<size_t>::max()) {
943  // this temporary variable is not used by all iterations
944 
945  replaceWithConditionalTempVar(code, *newIterIndexOp, iterationRegions, oldScope, newScope);
946  return true;
947  }
948  }
949 
950  return false;
951 }
952 
953 template<class Base>
955  IndexOperationNode<Base>& iterationIndexOp,
956  const std::vector<size_t>& iterationRegions,
957  ScopeIDType oldScope,
958  ScopeIDType commonScopeColor) {
962  Node* opClone = cloneNode(tmp);
963 
967  Node* tmpDclVar = makeNode(CGOpCode::TmpDcl);
968  Arg tmpArg(*tmpDclVar);
969 
970  Node* cond = makeNode(CGOpCode::IndexCondExpr, iterationRegions, {iterationIndexOp});
971 
972  // if
973  Node* ifStart = makeNode(CGOpCode::StartIf, *cond);
974 
975  Node* tmpAssign = makeNode(CGOpCode::LoopIndexedTmp, {tmpArg, *opClone});
976  Node* ifAssign = makeNode(CGOpCode::CondResult, {*ifStart, *tmpAssign});
977 
978  // end if
979  Node* endIf = makeNode(CGOpCode::EndIf, {*ifStart, *ifAssign});
980 
984  tmp.setOperation(CGOpCode::Tmp, {tmpArg, *endIf});
985  tmp.getInfo().resize(1); // used to mark that this node was altered here
986 
987  // created new nodes, must adjust vector sizes
988  _scope.adjustSize();
989  _lastVisit.adjustSize();
990  _scope.adjustSize();
991  _evaluationOrder.adjustSize();
992  _lastUsageOrder.adjustSize();
993  _totalUseCount.adjustSize();
994  _varId.adjustSize();
995 
999  size_t newScopeColor = ++_scopeColorCount;
1000  _scopes.resize(newScopeColor + 1);
1001  _scopes[newScopeColor] = _scopes[commonScopeColor];
1002 
1003  // one more scope level
1004  _scopes[newScopeColor].push_back(ScopePathElement<Base>(newScopeColor, endIf, ifStart));
1005 
1006  // apply scope colors
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;
1015 
1016  // total usage count
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);
1024 
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);
1032  }
1033 
1034  _alteredNodes.push_back(std::make_pair(&tmp, opClone));
1035 }
1036 
1037 template<class Base>
1039  if (_scope[code] != _currentScopeColor) {
1040  return; //nothing to change
1041  }
1042 
1046  if (_currentScopeColor == 0)
1047  restoreTemporaryVar(code);
1048 
1054  ScopeIDType oldScope = _scope[code];
1055 
1056  size_t depth = findFirstDifferentScope(oldScope, _currentScopeColor);
1057 
1058  // update the scope where it should be defined
1059  ScopeIDType newScope = depth == 0 ? 0 : _scopes[_currentScopeColor][depth - 1].color;
1060 
1064  std::vector<size_t> iterationRegions;
1065  Node* bScopeNewEnd = _scopes[_currentScopeColor].back().end;
1066  Node* endif = code.getArguments()[0].getOperation();
1067  CPPADCG_ASSERT_UNKNOWN(endif->getOperationType() == CGOpCode::EndIf);
1068  Node* bScopeOldEnd = _scopes[_scope[*endif]].back().end;
1069 
1070  CGOpCode bNewOp = bScopeNewEnd->getOperationType();
1071 
1072  if (bNewOp == CGOpCode::EndIf || bNewOp == CGOpCode::Else || bNewOp == CGOpCode::ElseIf) {
1073  // used in 2 different if/else branches
1074 
1078  Node* bScopeNew = bScopeNewEnd->getArguments()[0].getOperation();
1079  Node* bScopeOld = bScopeOldEnd->getArguments()[0].getOperation();
1080 
1081  IndexOperationNode<Base>* newIterIndexOp = nullptr;
1082  iterationRegions = ifBranchIterationRanges(bScopeNew, newIterIndexOp);
1083  CPPADCG_ASSERT_UNKNOWN(iterationRegions.size() >= 2);
1084 
1085  IndexOperationNode<Base>* oldIterIndexOp = nullptr;
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);
1090 
1091  if (iterationRegions.size() == 2 &&
1092  (iterationRegions[0] == 0 ||
1093  iterationRegions[1] == std::numeric_limits<size_t>::max())) {
1094  // this temporary variable is used by all iterations
1095  // there is no need for an 'if'
1096  restoreTemporaryVar(code);
1097 
1098  } else if (oldIterRegions != iterationRegions) {
1099  Node* cond = bScopeOld->getArguments()[0].getOperation();
1100  CPPADCG_ASSERT_UNKNOWN(cond->getOperationType() == CGOpCode::IndexCondExpr);
1101  cond->getInfo() = iterationRegions;
1102  }
1103 
1104  }
1105 
1106  if (oldScope != newScope) {
1107  _scope[code] = newScope;
1111  const std::vector<Arg>& cargs = code.getArguments();
1112  size_t aSize = cargs.size();
1113  for (size_t a = 0; a < aSize; a++) {
1114  updateVarScopeUsage(cargs[a].getOperation(), newScope, oldScope);
1115  }
1116  }
1117 
1118 }
1119 
1120 template<class Base>
1122  CPPADCG_ASSERT_UNKNOWN(tmp.getOperationType() == CGOpCode::Tmp && !tmp.getInfo().empty());
1123 
1124  Node* endIf = tmp.getArguments()[1].getOperation();
1125  Node* ifAssign = endIf->getArguments()[1].getOperation();
1126  Node* tmpAssign = ifAssign->getArguments()[1].getOperation();
1127  Node* opClone = tmpAssign->getArguments()[1].getOperation();
1128  tmp.setOperation(opClone->getOperationType(), opClone->getArguments());
1129  tmp.getInfo() = opClone->getInfo();
1130 
1131  _scope[tmp] = _currentScopeColor;
1132 
1136  const std::vector<Arg>& args = tmp.getArguments();
1137  size_t aSize = args.size();
1138  for (size_t a = 0; a < aSize; a++) {
1139  updateVarScopeUsage(args[a].getOperation(), _currentScopeColor, _scope[*opClone]);
1140  }
1141 }
1142 
1143 template<class Base>
1145  Node* opClone) {
1146  CPPADCG_ASSERT_UNKNOWN(tmp->getOperationType() == CGOpCode::Tmp && !tmp->getInfo().empty());
1147 
1148  tmp->setOperation(opClone->getOperationType(), opClone->getArguments());
1149  tmp->getInfo() = opClone->getInfo();
1150 
1151  _scope[*tmp] = _currentScopeColor;
1152 
1156  const std::vector<Arg>& args = tmp->getArguments();
1157  size_t aSize = args.size();
1158  for (size_t a = 0; a < aSize; a++) {
1159  updateVarScopeUsage(args[a].getOperation(), _currentScopeColor, _scope[*opClone]);
1160  }
1161 }
1162 
1163 template<class Base>
1165  ScopeIDType usageScope,
1166  ScopeIDType oldUsageScope) {
1167  if (node == nullptr || _scope[*node] == usageScope)
1168  return;
1169 
1170 
1171  ScopeIDType oldScope = _scope[*node];
1172  ScopeIDType newScope;
1173 
1174  if (oldScope == oldUsageScope) {
1175  newScope = usageScope;
1176  } else {
1177  size_t depth = findFirstDifferentScope(oldScope, usageScope);
1178 
1179  newScope = (depth == 0) ? 0 : _scopes[usageScope][depth - 1].color;
1180  }
1181 
1182  if (newScope == oldScope)
1183  return;
1184 
1185  _scope[*node] = newScope;
1186 
1187  const std::vector<Arg>& args = node->getArguments();
1188  size_t aSize = args.size();
1189  for (size_t a = 0; a < aSize; a++) {
1190  updateVarScopeUsage(args[a].getOperation(), newScope, oldScope);
1191  }
1192 }
1193 
1194 template<class Base>
1195 inline void CodeHandler<Base>::addScopeToVarOrder(size_t scope,
1196  size_t& e) {
1197  std::vector<Node*>& vorder = _scopedVariableOrder[scope];
1198 
1199  const size_t vsize = vorder.size();
1200  for (size_t p = 0; p < vsize; p++) {
1201  Node* node = vorder[p];
1202  CGOpCode op = node->getOperationType();
1203 
1204  if (op == CGOpCode::LoopEnd || op == CGOpCode::EndIf || op == CGOpCode::ElseIf || op == CGOpCode::Else) {
1205  CPPADCG_ASSERT_UNKNOWN(!node->getArguments().empty());
1206 
1207  Node* beginScopeNode = node->getArguments()[0].getOperation();
1208  CPPADCG_ASSERT_UNKNOWN(beginScopeNode != nullptr);
1209 
1210  addScopeToVarOrder(_scope[*beginScopeNode], e);
1211  }
1212 
1213  //std::cout << "e:" << e << " " << vorder[p] << " scope:" << scope << " p:" << p << " " << *vorder[p] << std::endl;
1214  _variableOrder[e++] = vorder[p];
1215  }
1216 }
1217 
1218 template<class Base>
1220  size_t color2) {
1221  CPPADCG_ASSERT_UNKNOWN(color1 < _scopes.size());
1222  CPPADCG_ASSERT_UNKNOWN(color2 < _scopes.size());
1223 
1224  ScopePath& scopePath1 = _scopes[color1];
1225  ScopePath& scopePath2 = _scopes[color2];
1226 
1227  size_t s1 = scopePath1.size();
1228  size_t s2 = scopePath2.size();
1229  size_t depth;
1230  for (depth = 0; depth < s1 && depth < s2; depth++) {
1231  if (scopePath1[depth].color != scopePath2[depth].color) {
1232  break;
1233  }
1234  }
1235 
1236  return depth;
1237 }
1238 
1239 template<class Base>
1241  if (_scopedVariableOrder.size() < 3)
1242  return; // there has to be at least 2 ifs
1243 
1244  for (size_t scope = 0; scope < _scopedVariableOrder.size(); scope++) {
1245  std::vector<Node*>& vorder = _scopedVariableOrder[scope];
1246 
1247  for (long p = vorder.size() - 1; p > 0; p--) {
1248  Node* endIf = vorder[p];
1249  if (endIf->getOperationType() != CGOpCode::EndIf)
1250  continue;
1251 
1252  long p1 = p - 1;
1253  while (p1 >= 0) {
1254  if (vorder[p1]->getOperationType() == CGOpCode::TmpDcl) {
1255  p1--;
1256  } else {
1257  break;
1258  }
1259  }
1260  Node* endIf1 = vorder[p1];
1261  if (endIf1->getOperationType() != CGOpCode::EndIf)
1262  continue;
1263 
1264  // 2 consecutive ifs
1265  Node* startIf = endIf->getArguments()[0].getOperation();
1266  Node* startIf1 = endIf1->getArguments()[0].getOperation();
1267  if (startIf->getOperationType() != CGOpCode::StartIf || startIf1->getOperationType() != CGOpCode::StartIf)
1268  continue;
1269 
1270  Node* cond = startIf->getArguments()[0].getOperation();
1271  Node* cond1 = startIf1->getArguments()[0].getOperation();
1272 
1273  CPPADCG_ASSERT_UNKNOWN(cond->getOperationType() == CGOpCode::IndexCondExpr || cond1->getOperationType() == CGOpCode::IndexCondExpr);
1274  if (cond->getInfo() == cond1->getInfo()) {
1278  const std::vector<Arg>& eArgs = endIf->getArguments();
1279  std::vector<Arg>& eArgs1 = endIf1->getArguments();
1280 
1281  ScopeIDType ifScope = _scope[*startIf];
1282  ScopeIDType ifScope1 = _scope[*startIf1];
1283  std::vector<Node*>& vorderIf = _scopedVariableOrder[ifScope];
1284  std::vector<Node*>& vorderIf1 = _scopedVariableOrder[ifScope1];
1285 
1286  startNewOperationTreeVisit();
1287 
1288  // break cycles caused by dependencies on the previous if
1289  for (size_t a = 1; a < eArgs.size(); a++) { // exclude the initial startIf
1290  CPPADCG_ASSERT_UNKNOWN(eArgs[a].getOperation() != nullptr && eArgs[a].getOperation()->getOperationType() == CGOpCode::CondResult);
1291  breakCyclicDependency(eArgs[a].getOperation(), ifScope, endIf1);
1292  replaceScope(eArgs[a].getOperation(), ifScope, ifScope1); // update scope
1293  }
1294 
1295  vorderIf1.insert(vorderIf1.end(), vorderIf.begin() + 1, vorderIf.end()); // exclude the initial startIf
1296 
1297  vorderIf.clear();
1298 
1299  // update startIf
1300  for (size_t a = 1; a < eArgs.size(); a++) { // exclude the initial startIf
1301  CPPADCG_ASSERT_UNKNOWN(eArgs[a].getOperation() != nullptr && eArgs[a].getOperation()->getOperationType() == CGOpCode::CondResult);
1302  eArgs[a].getOperation()->getArguments()[0] = Arg(*startIf1);
1303  }
1304 
1305  // update endIf
1306  eArgs1.insert(eArgs1.end(), eArgs.begin() + 1, eArgs.end());
1307 
1308  // replace endIf
1309  endIf->setOperation(CGOpCode::Alias, {*endIf1});
1310 
1311  // remove one of the ifs
1312  vorder.erase(vorder.begin() + p);
1313 
1314  // move nodes in scope containing the ifs
1315  for (long pp = p1; pp < p - 1; pp++) {
1316  vorder[pp] = vorder[pp + 1];
1317  }
1318  vorder[p - 1] = endIf1;
1319  }
1320  }
1321  }
1322 }
1323 
1324 template<class Base>
1325 inline void CodeHandler<Base>::replaceScope(Node* node,
1326  ScopeIDType oldScope,
1327  ScopeIDType newScope) {
1328  if (node == nullptr || _scope[*node] != oldScope)
1329  return;
1330 
1331  _scope[*node] = newScope;
1332 
1333  const std::vector<Arg>& args = node->getArguments();
1334  for (size_t a = 0; a < args.size(); a++) {
1335  replaceScope(args[a].getOperation(), oldScope, newScope);
1336  }
1337 }
1338 
1339 template<class Base>
1341  size_t scope,
1342  Node* endIf) {
1343  if (node == nullptr || isVisited(*node))
1344  return;
1345 
1346  markVisited(*node);
1347 
1348  CGOpCode op = node->getOperationType();
1349  std::vector<Arg>& args = node->getArguments();
1350 
1351  if (op == CGOpCode::Tmp && args.size() > 1) {
1352  Node* arg = args[1].getOperation();
1353  if (arg == endIf) {
1354  // a dependency on LoopIndexedTmp could be added but
1355  // it is not required since variable order was already decided
1356  args.erase(args.begin() + 1);
1357  }
1358  }
1359 
1360  if (!containedInScope(*node, scope)) {
1361  return;
1362  }
1363 
1364  for (size_t a = 0; a < args.size(); a++) {
1365  Node* arg = args[a].getOperation();
1366  if (arg == endIf) {
1367  if (op == CGOpCode::StartIf || op == CGOpCode::LoopStart) {
1368  args.erase(args.begin() + a);
1369  a--;
1370  }
1371  } else {
1372  breakCyclicDependency(arg, scope, endIf);
1373  }
1374  }
1375 }
1376 
1377 template<class Base>
1378 inline bool CodeHandler<Base>::containedInScope(const Node& node,
1379  ScopeIDType scope) {
1380  ScopeIDType nScope = _scope[node];
1381  if (nScope == scope)
1382  return true;
1383 
1384  return _scopes[nScope].size() >= _scopes[scope].size() &&
1385  _scopes[nScope][_scopes[scope].size() - 1].color == scope;
1386 }
1387 
1388 template<class Base>
1389 inline bool CodeHandler<Base>::containsArgument(const Node& node,
1390  const Node& arg) {
1391  const std::vector<Arg>& args = node.getArguments();
1392  for (size_t a = 0; a < args.size(); a++) {
1393  if (args[a].getOperation() == &arg) {
1394  return true;
1395  }
1396  }
1397  return false;
1398 }
1399 
1400 template<class Base>
1402  size_t id = atomic.getId();
1403  auto it = _atomicFunctions.lower_bound(id);
1404  if (it == _atomicFunctions.end() || it->first != id) {
1405  if (it != _atomicFunctions.end()) ++it;
1406  _atomicFunctions.insert(it, std::pair<size_t, CGAbstractAtomicFun<Base>*>(atomic.getId(), &atomic));
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, ").");
1410  }
1411 }
1412 
1413 template<class Base>
1415  const std::vector<Arg>& args = code.getArguments();
1416 
1417  size_t aSize = args.size();
1418  for (size_t argIndex = 0; argIndex < aSize; argIndex++) {
1419  if (args[argIndex].getOperation() == nullptr) {
1420  continue;
1421  }
1422 
1423  Node& arg = *args[argIndex].getOperation();
1424  CGOpCode aType = arg.getOperationType();
1425 
1426  if (!isVisited(arg)) {
1427  // dependencies not visited yet
1428  checkVariableCreation(arg);
1429 
1430  if (aType == CGOpCode::LoopEnd || aType == CGOpCode::ElseIf || aType == CGOpCode::Else || aType == CGOpCode::EndIf) {
1431  if (_varId[arg] == 0) {
1432  // ID value is not really used but must be non-zero
1433  _varId[arg] = std::numeric_limits<size_t>::max();
1434  }
1435  } else if (aType == CGOpCode::AtomicForward || aType == CGOpCode::AtomicReverse) {
1439  CPPADCG_ASSERT_UNKNOWN(arg.getArguments().size() > 1);
1440  CPPADCG_ASSERT_UNKNOWN(arg.getInfo().size() > 1);
1441  size_t id = arg.getInfo()[0];
1442 
1443  size_t pos;
1444  const std::string& atomicName = _atomicFunctions.at(id)->afun_name();
1445  std::map<std::string, size_t>::const_iterator itName2Idx;
1446  itName2Idx = _atomicFunctionName2Index.find(atomicName);
1447 
1448  if (itName2Idx == _atomicFunctionName2Index.end()) {
1449  pos = _atomicFunctionsOrder->size();
1450  _atomicFunctionsOrder->push_back(atomicName);
1451  _atomicFunctionName2Index[atomicName] = pos;
1452  _atomicFunctionsMaxForward.push_back(-1);
1453  _atomicFunctionsMaxReverse.push_back(-1);
1454  } else {
1455  pos = itName2Idx->second;
1456  }
1457 
1458  if (aType == CGOpCode::AtomicForward) {
1459  int p = arg.getInfo()[2];
1460  _atomicFunctionsMaxForward[pos] = std::max(_atomicFunctionsMaxForward[pos], p);
1461  } else {
1462  int p = arg.getInfo()[1];
1463  _atomicFunctionsMaxReverse[pos] = std::max(_atomicFunctionsMaxReverse[pos], p);
1464  }
1465  }
1466 
1472  if (_varId[arg] == 0 || !isIndependent(arg)) {
1473  if (aType == CGOpCode::LoopIndexedIndep) {
1474  // ID value not really used but must be non-zero
1475  _varId[arg] = std::numeric_limits<size_t>::max();
1476  } else if (aType == CGOpCode::Alias) {
1477  continue; // should never be added to the evaluation queue
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);
1491  if (_varId[arg] == 0) {
1492  // ID value is not really used but must be non-zero
1493  _varId[arg] = std::numeric_limits<size_t>::max();
1494  }
1495  } else if (aType == CGOpCode::Pri) {
1496  addToEvaluationQueue(arg);
1497  if (_varId[arg] == 0) {
1498  // ID value is not really used but must be non-zero
1499  _varId[arg] = std::numeric_limits<size_t>::max();
1500  }
1501  } else if (aType == CGOpCode::TmpDcl) {
1502  addToEvaluationQueue(arg);
1503 
1504  _varId[arg] = _idCount;
1505  _idCount++;
1506 
1507  } else if (_lang->createsNewVariable(arg, getTotalUsageCount(arg)) ||
1508  _lang->requiresVariableArgument(code.getOperationType(), argIndex)) {
1509 
1510  addToEvaluationQueue(arg);
1511 
1512  if (_varId[arg] == 0) {
1513  if (aType == CGOpCode::AtomicForward || aType == CGOpCode::AtomicReverse) {
1514  _varId[arg] = _idAtomicCount;
1515  _idAtomicCount++;
1516  } else if (aType == CGOpCode::LoopIndexedDep || aType == CGOpCode::LoopIndexedTmp) {
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::ArrayCreation) {
1520  // a temporary array
1521  size_t arraySize = arg.getArguments().size();
1522  _varId[arg] = _idArrayCount;
1523  _idArrayCount += arraySize;
1524  } else if (aType == CGOpCode::SparseArrayCreation) {
1525  // a temporary array
1526  size_t nnz = arg.getArguments().size();
1527  _varId[arg] = _idSparseArrayCount;
1528  _idSparseArrayCount += nnz;
1529  } else {
1530  // a single temporary variable
1531  _varId[arg] = _idCount;
1532  _idCount++;
1533  }
1534  }
1535  }
1536 
1537  }
1538  }
1539 
1540  markVisited(arg);
1541 
1542  }
1543 
1544 }
1545 
1546 template<class Base>
1548  ScopeIDType scope = _scope[arg];
1549  if (scope >= _scopedVariableOrder.size()) {
1550  _scopedVariableOrder.resize(scope + 1);
1551  }
1552 
1553  if (_scopedVariableOrder[scope].empty() &&
1554  scope != 0 && // the upper most scope does not need any special node at the beginning
1555  _scopes[scope].back().end->getArguments()[0].getOperation() != &arg) {
1556  // the first node must be a beginning of a scope
1557  checkVariableCreation(*_scopes[scope].back().end); // go inside a scope from the end
1558  }
1559 
1560  // must be after checkVariableCreation() because _scopedVariableOrder might be resized
1561  std::vector<Node*>& varOrder = _scopedVariableOrder[scope];
1562 
1563  if (varOrder.size() == varOrder.capacity()) {
1564  varOrder.reserve((varOrder.size() * 3) / 2 + 1);
1565  }
1566 
1567  varOrder.push_back(&arg);
1568 }
1569 
1570 template<class Base>
1572 
1573  reorderOperations(dependent);
1574 
1578  startNewOperationTreeVisit();
1579 
1580  for (size_t i = 0; i < dependent.size(); i++) {
1581  Node* node = dependent[i].getOperationNode();
1582  if (node != nullptr) {
1583  if (!isVisited(*node)) {
1584  // dependencies not visited yet
1586  }
1587  markVisited(*node);
1588  }
1589  }
1590 
1591  // where temporary variables can be released
1592  std::vector<std::vector<Node*>> tempVarRelease(_variableOrder.size());
1593  for (size_t i = 0; i < _variableOrder.size(); i++) {
1594  Node* var = _variableOrder[i];
1595  if (isTemporary(*var) || isTemporaryArray(*var) || isTemporarySparseArray(*var)) {
1596  size_t releaseLocation = getLastUsageEvaluationOrder(*var) - 1;
1597  tempVarRelease[releaseLocation].push_back(var);
1598  }
1599  }
1600 
1601 
1605  std::vector<size_t> freedVariables; // variable IDs no longer in use
1606  _idCount = _minTemporaryVarID;
1607  ArrayIdCompresser<Base> arrayComp(_varId, _idArrayCount);
1608  ArrayIdCompresser<Base> sparseArrayComp(_varId, _idSparseArrayCount);
1609 
1610  for (size_t i = 0; i < _variableOrder.size(); i++) {
1611  Node& var = *_variableOrder[i];
1612 
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]);
1621  }
1622  }
1623 
1624  if (isTemporary(var)) {
1625  // a single temporary variable
1626  if (freedVariables.empty()) {
1627  _varId[var] = _idCount;
1628  _idCount++;
1629  } else {
1630  size_t id = freedVariables.back();
1631  freedVariables.pop_back();
1632  _varId[var] = id;
1633  }
1634  } else if (isTemporaryArray(var)) {
1635  // a temporary array
1636  size_t arrayStart = arrayComp.reserveArraySpace(var);
1637  _varId[var] = arrayStart + 1;
1638  } else if (isTemporarySparseArray(var)) {
1639  // a temporary array
1640  size_t arrayStart = sparseArrayComp.reserveArraySpace(var);
1641  _varId[var] = arrayStart + 1;
1642  }
1643 
1644  }
1645 
1646  _idArrayCount = arrayComp.getIdCount();
1647  _idSparseArrayCount = sparseArrayComp.getIdCount();
1648 }
1649 
1650 template<class Base>
1652  // determine the location of the last temporary variable used for each dependent
1653  startNewOperationTreeVisit();
1654 
1655  // normal dependent nodes
1656  for (size_t i = 0; i < dependent.size(); ++i) {
1657  Node* node = dependent[i].getOperationNode();
1658  if (node != nullptr) {
1659  reorderOperation(*node);
1660  }
1661  }
1662 
1663  // dependent nodes defined inside loops
1664  for (const LoopEndOperationNode<Base>* endNode : _loops.endNodes) {
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);
1668  // TODO: also consider CGOpCode::LoopIndexedDep inside a CGOpCode::endIf
1669  if (args[i].getOperation()->getOperationType() == CGOpCode::LoopIndexedDep) {
1670  reorderOperation(*args[i].getOperation());
1671  }
1672  }
1673  }
1674 }
1675 
1676 template<class Base>
1681  size_t depPos = getEvaluationOrder(node);
1682  size_t lastTmpPos = depPos;
1683  if (!isVisited(node)) {
1684  // dependencies not visited yet
1685  lastTmpPos = findLastTemporaryLocation(node);
1686  }
1687  markVisited(node);
1688 
1692  if (lastTmpPos == depPos || lastTmpPos + 1 == depPos) {
1693  return; // should not change location of the evaluation of this dependent
1694  }
1695 
1696  // should only move if there are temporaries which could use other temporaries released by the dependent
1697  bool foundTemporaries = false;
1698  size_t newPos;
1699  for (size_t l = lastTmpPos + 1; l < depPos; ++l) {
1700  const auto* n = _variableOrder[l - 1];
1701  if (isTemporary(*n) || isTemporaryArray(*n) || isTemporarySparseArray(*n)) {
1702  foundTemporaries = true;
1703  newPos = l;
1704  break;
1705  } else {
1709  CGOpCode op = n->getOperationType();
1710  if (op == CGOpCode::StartIf) {
1711  // must not change scope (find the end of this conditional statement)
1712  ++l;
1713  while (l < depPos) {
1714  const auto* node2 = _variableOrder[l - 1];
1715  if (node2->getOperationType() == CGOpCode::EndIf &&
1716  node2->getArguments()[0].getOperation() == n) {
1717  break; // found the end (returned to the same scope)
1718  }
1719  ++l;
1720  }
1721 
1722  } else if (op == CGOpCode::LoopStart) {
1723  // must not change scope (find the end of this loop statement)
1724  ++l;
1725  while (l < depPos) {
1726  const auto* node2 = _variableOrder[l - 1];
1727  if (node2->getOperationType() == CGOpCode::LoopEnd &&
1728  &static_cast<const LoopEndOperationNode<Base>*> (node2)->getLoopStart() == n) {
1729  break; // found the end (returned to the same scope)
1730  }
1731  ++l;
1732  }
1733  }
1734  }
1735  }
1736 
1737  if (foundTemporaries) {
1738  // move variables
1739  repositionEvaluationQueue(depPos, newPos);
1740  }
1741 }
1742 
1743 template<class Base>
1745  size_t depOrder = getEvaluationOrder(node);
1746  size_t maxTmpOrder = 0; // lowest possible value is 1
1747  for (const Arg& it : node) {
1748  if (it.getOperation() != nullptr) {
1749  Node& arg = *it.getOperation();
1750  CGOpCode aOp = arg.getOperationType();
1751  if (aOp == CGOpCode::LoopEnd || aOp == CGOpCode::EndIf || aOp == CGOpCode::ElseIf || aOp == CGOpCode::Else) {
1752  continue; //should not move variables to a different scope
1753  }
1754 
1755  if (aOp == CGOpCode::Index) {
1756  size_t iorder = getEvaluationOrder(static_cast<IndexOperationNode<Base>&> (arg).getIndexCreationNode());
1757  if (iorder > maxTmpOrder)
1758  maxTmpOrder = iorder;
1759  } else if (getEvaluationOrder(arg) == depOrder) {
1760  // dependencies not visited yet
1761  size_t orderNew = findLastTemporaryLocation(arg);
1762  if (orderNew > maxTmpOrder)
1763  maxTmpOrder = orderNew;
1764  } else {
1765  // no need to visit dependencies
1766  if (getEvaluationOrder(arg) > maxTmpOrder)
1767  maxTmpOrder = getEvaluationOrder(arg);
1768  }
1769  }
1770  }
1771 
1772  return maxTmpOrder == 0 ? depOrder : maxTmpOrder;
1773 }
1774 
1775 template<class Base>
1776 inline void CodeHandler<Base>::repositionEvaluationQueue(size_t fromPos, size_t toPos) {
1777  // Warning: there is an offset of 1 between the evaluation order saved
1778  // in the node and the actual location in the _variableOrder
1779  CPPADCG_ASSERT_UNKNOWN(fromPos > toPos);
1780  Node* node = _variableOrder[fromPos - 1]; // node to be moved
1781 
1782  // move variables in between the order change
1783  for (size_t l = fromPos - 1; l > toPos - 1; --l) {
1784  _variableOrder[l] = _variableOrder[l - 1];
1785  updateEvaluationQueueOrder(*_variableOrder[l], l + 1);
1786  }
1787 
1788  _variableOrder[toPos - 1] = node;
1789  updateEvaluationQueueOrder(*node, toPos);
1790 }
1791 
1792 template<class Base>
1794  CGOpCode op = node.getOperationType();
1795 
1796  if (op == CGOpCode::LoopEnd) {
1797  LoopEndOperationNode<Base>& loopEnd = static_cast<LoopEndOperationNode<Base>&> (node);
1798  _loops.depth++;
1799  _loops.outerVars.resize(_loops.depth + 1);
1800  _loops.startEvalOrder.push_back(getEvaluationOrder(loopEnd.getLoopStart()));
1801 
1802  } else if (op == CGOpCode::LoopStart) {
1803  _loops.depth--; // leaving the current loop
1804  }
1805 
1809  for (const Arg& it : node.getArguments()) {
1810  if (it.getOperation() != nullptr) {
1811  Node& arg = *it.getOperation();
1812 
1813  if (!isVisited(arg)) {
1814  // dependencies not visited yet
1816  }
1817 
1818  markVisited(arg);
1819 
1820  size_t order = getEvaluationOrder(node);
1821  Node* aa = getOperationFromAlias(arg); // follow alias!
1822  if (aa != nullptr) {
1823  if (getLastUsageEvaluationOrder(*aa) < order) {
1824  setLastUsageEvaluationOrder(*aa, order);
1825  }
1826 
1827  if (_loops.depth >= 0 &&
1828  getEvaluationOrder(*aa) < _loops.startEvalOrder[_loops.depth] &&
1829  isTemporary(*aa)) {
1830  // outer variable used inside the loop
1831  _loops.outerVars[_loops.depth].insert(aa);
1832  }
1833  }
1834  }
1835  }
1836 
1837  if (op == CGOpCode::LoopEnd) {
1842  size_t order = getEvaluationOrder(node);
1843 
1844  const std::set<Node*>& outerLoopUsages = _loops.outerVars.back();
1845  for (Node* outerVar : outerLoopUsages) {
1846  Node* aa = getOperationFromAlias(*outerVar); // follow alias!
1847  if (aa != nullptr && getLastUsageEvaluationOrder(*aa) < order)
1848  setLastUsageEvaluationOrder(*aa, order);
1849  }
1850 
1851  _loops.depth--;
1852  _loops.outerVars.pop_back();
1853  _loops.startEvalOrder.pop_back();
1854 
1855  } else if (op == CGOpCode::LoopStart) {
1856  _loops.depth++; // coming back to the loop
1857  }
1858 
1859 }
1860 
1861 template<class Base>
1863  for (const Arg& a : node.getArguments()) {
1864  if (a.getOperation() != nullptr) {
1865  Node& arg = *a.getOperation();
1866  if (getEvaluationOrder(arg) == 0) {
1867  setEvaluationOrder(arg, getEvaluationOrder(node));
1869  }
1870  }
1871  }
1872 }
1873 
1874 template<class Base>
1876  size_t newEvalOrder) {
1877  size_t oldEvalOrder = getEvaluationOrder(node);
1878 
1879  setEvaluationOrder(node, newEvalOrder);
1880 
1881  for (const Arg& a : node.getArguments()) {
1882  if (a.getOperation() != nullptr) {
1883  Node& arg = *a.getOperation();
1884  if (getEvaluationOrder(arg) == oldEvalOrder)
1885  updateEvaluationQueueOrder(arg, newEvalOrder);
1886  }
1887  }
1888 }
1889 
1890 template<class Base>
1892  _variableDependencies.resize(_variableOrder.size());
1893 
1894  for (size_t i = 0; i < _variableOrder.size(); i++) {
1895  Node& var = *_variableOrder[i];
1896 
1897  _variableDependencies[i].clear();
1898  startNewOperationTreeVisit();
1899 
1900  for (const auto& a : var) {
1901  if (a.getOperation() != nullptr) {
1902  findVariableDependencies(i, *a.getOperation());
1903  }
1904  }
1905  }
1906 }
1907 
1908 template<class Base>
1909 inline void CodeHandler<Base>::findVariableDependencies(size_t i,
1910  Node& node) {
1911  if (!isVisited(node)) {
1912  markVisited(node);
1913 
1914  if(_varId[node] != 0) {
1915  _variableDependencies[i].insert(&node);
1916  } else {
1917  for (const auto& a : node) {
1918  if (a.getOperation() != nullptr) {
1919  findVariableDependencies(i, *a.getOperation());
1920  }
1921  }
1922  }
1923  }
1924 }
1925 
1926 template<class Base>
1927 inline bool CodeHandler<Base>::isIndependent(const Node& arg) const {
1928  return arg.getOperationType() == CGOpCode::Inv;
1929 }
1930 
1931 template<class Base>
1932 inline bool CodeHandler<Base>::isTemporary(const Node& arg) const {
1933  CGOpCode op = arg.getOperationType();
1934  return op != CGOpCode::ArrayCreation && // classified as TemporaryArray
1935  op != CGOpCode::SparseArrayCreation && // classified as TemporarySparseArray
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 && // not considered as a temporary (the temporary is CGTmpDclOp)
1947  op != CGOpCode::Index &&
1948  op != CGOpCode::IndexAssign &&
1949  op != CGOpCode::Tmp && // not considered as a temporary (the temporary is CGTmpDclOp)
1950  _varId[arg] >= _minTemporaryVarID;
1951 }
1952 
1953 template<class Base>
1954 inline bool CodeHandler<Base>::isTemporaryArray(const Node& arg) {
1955  return arg.getOperationType() == CGOpCode::ArrayCreation;
1956 }
1957 
1958 template<class Base>
1959 inline bool CodeHandler<Base>::isTemporarySparseArray(const Node& arg) {
1960  return arg.getOperationType() == CGOpCode::SparseArrayCreation;
1961 }
1962 
1963 template<class Base>
1965  if (alias.getOperationType() != CGOpCode::Alias) {
1966  return &alias;
1967  } else {
1968  Node* aa = &alias;
1969  do {
1970  CPPADCG_ASSERT_UNKNOWN(aa->getArguments().size() == 1);
1971  aa = aa->getArguments()[0].getOperation();
1972  } while (aa != nullptr && aa->getOperationType() == CGOpCode::Alias);
1973  return aa;
1974  }
1975 }
1976 
1977 template<class Base>
1978 inline size_t CodeHandler<Base>::getEvaluationOrder(const Node& node) const {
1979  return _evaluationOrder[node];
1980 }
1981 
1982 template<class Base>
1984  size_t order) {
1985  CPPADCG_ASSERT_UNKNOWN(order <= _variableOrder.size());
1986  _evaluationOrder[node] = order;
1987 }
1988 
1989 template<class Base>
1990 inline size_t CodeHandler<Base>::getLastUsageEvaluationOrder(const Node& node) const {
1991  return _lastUsageOrder[node];
1992 }
1993 
1994 template<class Base>
1996  size_t last) {
1997  CPPADCG_ASSERT_UNKNOWN(last <= _variableOrder.size()); // _lastUsageOrder[node] = 0 means that it was never used
1998  _lastUsageOrder[node] = last;
1999 
2000  CGOpCode op = node.getOperationType();
2001  if (op == CGOpCode::ArrayElement) {
2002  Node* array = node.getArguments()[0].getOperation();
2003  CPPADCG_ASSERT_UNKNOWN(array->getOperationType() == CGOpCode::ArrayCreation);
2004  if (getLastUsageEvaluationOrder(*array) < last) {
2005  setLastUsageEvaluationOrder(*array, last);
2006  }
2007  } else if (op == CGOpCode::Tmp) {
2008  Node* declr = node.getArguments()[0].getOperation();
2009  CPPADCG_ASSERT_UNKNOWN(declr->getOperationType() == CGOpCode::TmpDcl);
2010  if (getLastUsageEvaluationOrder(*declr) < last) {
2011  setLastUsageEvaluationOrder(*declr, last);
2012  }
2013  }
2014 }
2015 
2016 template<class Base>
2017 inline size_t CodeHandler<Base>::getTotalUsageCount(const Node& node) const {
2018  return _totalUseCount[node];
2019 }
2020 
2021 template<class Base>
2022 inline void CodeHandler<Base>::setTotalUsageCount(const Node& node,
2023  size_t cout) {
2024  _totalUseCount[node] = cout;
2025 }
2026 
2027 template<class Base>
2028 inline void CodeHandler<Base>::increaseTotalUsageCount(const Node& node) {
2029  _totalUseCount[node]++;
2030 }
2031 
2032 template<class Base>
2034  _variableOrder.clear();
2035  _scopedVariableOrder.resize(1);
2036  _scopedVariableOrder[0].clear();
2037  _evaluationOrder.fill(0);
2038  _lastUsageOrder.fill(0);
2039  _totalUseCount.fill(0);
2040  _varId.fill(0);
2041  _scope.fill(0);
2042 }
2043 
2044 } // END cg namespace
2045 } // END CppAD namespace
2046 
2047 #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
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
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