CppADCodeGen 2.4.3
A C++ Algorithmic Differentiation Package with Source Code Generation
Loading...
Searching...
No Matches
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
19namespace CppAD {
20namespace cg {
21
22template<class Base>
23CodeHandler<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
56template<class Base>
58 reset();
59
60 for (auto* v : _managedVectors) {
61 v->handler_ = nullptr;
62 }
63}
64
65template<class Base>
67 _reuseIDs = reuse;
68}
69
70template<class Base>
72 return _reuseIDs;
73}
74
75template<class Base>
76inline void CodeHandler<Base>::makeVariables(std::vector<AD<CGB> >& variables) {
77 for (auto& v : variables) {
78 makeVariable(v);
79 }
80}
81
82template<class Base>
84 CGB v;
85 makeVariable(v); // make it a codegen variable
86 variable = v; // variable id now the same as v
87}
88
89template<class Base>
90inline void CodeHandler<Base>::makeVariable(CGB& variable) {
91 _independentVariables.push_back(makeNode(CGOpCode::Inv));
92 variable.makeVariable(*_independentVariables.back());
93}
94
95template<class Base>
97 return _independentVariables.size();
98}
99
100template<class Base>
102 return _varId;
103}
104
105template<class Base>
106inline size_t CodeHandler<Base>::getMaximumVariableID() const {
107 return _idCount;
108}
109
110template<class Base>
111inline bool CodeHandler<Base>::isVerbose() const {
112 return _verbose;
113}
114
115template<class Base>
116inline void CodeHandler<Base>::setVerbose(bool verbose) {
117 _verbose = verbose;
118}
119
120template<class Base>
121inline JobTimer* CodeHandler<Base>::getJobTimer() const {
122 return _jobTimer;
123}
124
125template<class Base>
126inline void CodeHandler<Base>::setJobTimer(JobTimer* jobTimer) {
127 _jobTimer = jobTimer;
128}
129
130template<class Base>
132 return _zeroDependents;
133}
134
135template<class Base>
136inline void CodeHandler<Base>::setZeroDependents(bool zeroDependents) {
137 _zeroDependents = zeroDependents;
138}
139
140template<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
152template<class Base>
153inline size_t CodeHandler<Base>::getOperationTreeVisitId() const {
154 return _idVisit;
155}
156
157template<class Base>
158inline void CodeHandler<Base>::startNewOperationTreeVisit() {
159 assert(_idVisit < (std::numeric_limits<size_t>::max)());
160
161 _lastVisit.adjustSize();
162 _idVisit++;
163}
164
165template<class Base>
166inline bool CodeHandler<Base>::isVisited(const Node& node) const {
167 size_t p = node.getHandlerPosition();
168 return p < _lastVisit.size() && _lastVisit[node] == _idVisit;
169}
170
171template<class Base>
172inline void CodeHandler<Base>::markVisited(const Node& node) {
173 _lastVisit.adjustSize(node);
174 _lastVisit[node] = _idVisit;
175}
176
177template<class Base>
178inline 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}
187template<class Base>
188inline const std::map<size_t, CGAbstractAtomicFun<Base>* >& CodeHandler<Base>::getAtomicFunctions() const {
189 return _atomicFunctions;
190}
191
192template<class Base>
194 return _atomicFunctionsMaxForward;
195}
196
197template<class Base>
199 return _atomicFunctionsMaxReverse;
200}
201
202template<class Base>
203inline const std::string* CodeHandler<Base>::getLoopName(size_t id) const {
204 return _loops.getLoopName(id);
205}
206
207template<class Base>
208inline const std::vector<typename CodeHandler<Base>::ScopePath>&
210 return _scopes;
211}
212
213template<class Base>
214void 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
223template<class Base>
224void 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
233template<class Base>
234void CodeHandler<Base>::generateCode(std::ostream& out,
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
243template<class Base>
244void CodeHandler<Base>::generateCode(std::ostream& out,
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}
254template<class Base>
255void 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
265template<class Base>
266void 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());
292 _atomicFunctionName2Index.clear();
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);
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 }
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);
396 dependentAdded2EvaluationQueue(arg);
397 }
398
402 if (_reuseIDs) {
403 reduceTemporaryVariables(dependent);
404 }
405
409 _variableDependencies.clear();
411 findVariableDependencies();
412 }
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,
440 _atomicFunctionsMaxForward, _atomicFunctionsMaxReverse,
441 _reuseIDs,
442 _loops.indexes, _loops.indexRandomPatterns,
443 _loops.dependentIndexPatterns, _loops.independentIndexPatterns,
444 _totalUseCount, _scope, *_auxIterationIndexOp,
445 _zeroDependents));
446
447 lang.generateSourceCode(out, std::move(_info));
448
452 _atomicFunctionName2Index.clear();
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
474template<class Base>
475size_t CodeHandler<Base>::getTemporaryVariableCount() const {
476 if (_idCount == 1)
477 return 0; // no code generated
478 else
479 return _idCount - _minTemporaryVarID;
480}
481
482template<class Base>
483size_t CodeHandler<Base>::getTemporaryArraySize() const {
484 return _idArrayCount - 1;
485}
486
487template<class Base>
488size_t CodeHandler<Base>::getTemporarySparseArraySize() const {
489 return _idSparseArrayCount - 1;
490}
491
492template<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();
506 _used = false;
507}
508
509template<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
523template<class Base>
525 return manageOperationNode(new Node(n));
526}
527
528template<class Base>
530 return manageOperationNode(new Node(this, op));
531}
532
533template<class Base>
534inline OperationNode<Base>* CodeHandler<Base>::makeNode(CGOpCode op,
535 const Arg& arg) {
536 return manageOperationNode(new Node(this, op, arg));
537}
538
539template<class Base>
540inline OperationNode<Base>* CodeHandler<Base>::makeNode(CGOpCode op,
541 std::vector<Arg>&& args) {
542 return manageOperationNode(new Node(this, op, std::move(args)));
543}
544
545template<class Base>
546inline OperationNode<Base>* CodeHandler<Base>::makeNode(CGOpCode op,
547 std::vector<size_t>&& info,
548 std::vector<Arg>&& args) {
549 return manageOperationNode(new Node(this, op, std::move(info), std::move(args)));
550}
551
552template<class Base>
553inline OperationNode<Base>* CodeHandler<Base>::makeNode(CGOpCode op,
554 const std::vector<size_t>& info,
555 const std::vector<Arg>& args) {
556 return manageOperationNode(new Node(this, op, info, args));
557}
558
559template<class Base>
560inline LoopStartOperationNode<Base>* CodeHandler<Base>::makeLoopStartNode(Node& indexDcl,
561 size_t iterationCount) {
562 auto* n = new LoopStartOperationNode<Base>(this, indexDcl, iterationCount);
563 manageOperationNode(n);
564 return n;
565}
566
567template<class Base>
568inline LoopStartOperationNode<Base>* CodeHandler<Base>::makeLoopStartNode(Node& indexDcl,
569 IndexOperationNode<Base>& iterCount) {
570 auto* n = new LoopStartOperationNode<Base>(this, indexDcl, iterCount);
571 manageOperationNode(n);
572 return n;
573}
574
575template<class Base>
576inline LoopEndOperationNode<Base>* CodeHandler<Base>::makeLoopEndNode(LoopStartOperationNode<Base>& loopStart,
577 const std::vector<Arg>& endArgs) {
578 auto* n = new LoopEndOperationNode<Base>(this, loopStart, endArgs);
579 manageOperationNode(n);
580 return n;
581}
582
583template<class Base>
584inline 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
592template<class Base>
593inline IndexOperationNode<Base>* CodeHandler<Base>::makeIndexNode(Node& indexDcl) {
594 auto* n = new IndexOperationNode<Base>(this, indexDcl);
595 manageOperationNode(n);
596 return n;
597}
598
599template<class Base>
600inline IndexOperationNode<Base>* CodeHandler<Base>::makeIndexNode(LoopStartOperationNode<Base>& loopStart) {
601 auto* n = new IndexOperationNode<Base>(this, loopStart);
602 manageOperationNode(n);
603 return n;
604}
605
606template<class Base>
607inline IndexOperationNode<Base>* CodeHandler<Base>::makeIndexNode(IndexAssignOperationNode<Base>& indexAssign) {
608 auto* n = new IndexOperationNode<Base>(this, indexAssign);
609 manageOperationNode(n);
610 return n;
611}
612
613template<class Base>
614inline IndexAssignOperationNode<Base>* CodeHandler<Base>::makeIndexAssignNode(Node& index,
615 IndexPattern& indexPattern,
616 IndexOperationNode<Base>& index1) {
617 auto* n = new IndexAssignOperationNode<Base>(this, index, indexPattern, index1);
618 manageOperationNode(n);
619 return n;
620}
621
622template<class Base>
624 IndexPattern& indexPattern,
626 IndexOperationNode<Base>* index2) {
627 auto* n = new IndexAssignOperationNode<Base>(this, index, indexPattern, index1, index2);
628 manageOperationNode(n);
629 return n;
631
632template<class Base>
633inline 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;
639
640template<class Base>
642 return _codeBlocks.size();
643}
644
645template<class Base>
646inline const std::vector<OperationNode<Base> *>& CodeHandler<Base>::getManagedNodes() const {
647 return _codeBlocks;
648}
649
650template<class Base>
651inline 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 *****************************************************************************/
676template<class Base>
677CG<Base> CodeHandler<Base>::createCG(const Arg& arg) {
678 return CGB(arg);
680
681/******************************************************************************
682 * Index patterns
683 *****************************************************************************/
684template<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));
699 }
700}
701
702/**************************************************************************
703 * Operation graph manipulation
704 *************************************************************************/
705template<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
715template<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
727template<class Base>
729 _managedVectors.insert(v);
730}
731
732template<class Base>
734 _managedVectors.erase(v);
735}
736
737template<class Base>
739
740 auto startAnalysis = [this](OperationStackData<Base>& stackEl,
741 OperationStack<Base>& stack) {
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 {
827 updateTemporaryVarInDiffScopes(code);
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
926template<class Base>
927inline bool CodeHandler<Base>::handleTemporaryVarInDiffScopes(Node& code,
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
939
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
982template<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
1067template<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
1150template<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
1173template<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
1193template<class Base>
1194inline void CodeHandler<Base>::updateVarScopeUsage(Node* node,
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
1224template<class Base>
1225inline 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
1248template<class Base>
1249inline size_t CodeHandler<Base>::findFirstDifferentScope(size_t color1,
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
1269template<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
1354template<class Base>
1355inline 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
1369template<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
1407template<class Base>
1408inline 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
1418template<class Base>
1419inline 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
1430template<class Base>
1431void CodeHandler<Base>::registerAtomicFunction(CGAbstractAtomicFun<Base>& atomic) {
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
1443template<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
1611template<class Base>
1612inline void CodeHandler<Base>::addToEvaluationQueue(Node& arg) {
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
1635template<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
1650 determineLastTempVarUsage(*node);
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
1715template<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
1741template<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
1808template<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,
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
1855template<class Base>
1856inline 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
1872template<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
1969template<class Base>
1971
1972 auto analyse = [this](SimpleOperationStackData<Base>& stackEl,
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
1988template<class Base>
1990 size_t newEvalOrder) {
1991
1992 auto analyse = [&](SimpleOperationStackData<Base>& stackEl,
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
2011template<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
2029template<class Base>
2031 Node& root) {
2032
2033 auto analyse = [&](SimpleOperationStackData<Base>& stackEl,
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
2051template<class Base>
2052inline bool CodeHandler<Base>::isIndependent(const Node& arg) const {
2053 return arg.getOperationType() == CGOpCode::Inv;
2054}
2055
2056template<class Base>
2057inline 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
2078template<class Base>
2079inline bool CodeHandler<Base>::isTemporaryArray(const Node& arg) {
2080 return arg.getOperationType() == CGOpCode::ArrayCreation;
2081}
2082
2083template<class Base>
2084inline bool CodeHandler<Base>::isTemporarySparseArray(const Node& arg) {
2085 return arg.getOperationType() == CGOpCode::SparseArrayCreation;
2086}
2087
2088template<class Base>
2089inline OperationNode<Base>* CodeHandler<Base>::getOperationFromAlias(Node& alias) {
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
2102template<class Base>
2103inline size_t CodeHandler<Base>::getEvaluationOrder(const Node& node) const {
2104 return _evaluationOrder[node];
2105}
2106
2107template<class Base>
2108inline void CodeHandler<Base>::setEvaluationOrder(Node& node,
2109 size_t order) {
2110 CPPADCG_ASSERT_UNKNOWN(order <= _variableOrder.size())
2111 _evaluationOrder[node] = order;
2112}
2113
2114template<class Base>
2115inline size_t CodeHandler<Base>::getLastUsageEvaluationOrder(const Node& node) const {
2116 return _lastUsageOrder[node];
2117}
2118
2119template<class Base>
2120inline void CodeHandler<Base>::setLastUsageEvaluationOrder(const Node& node,
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
2141template<class Base>
2142inline size_t CodeHandler<Base>::getTotalUsageCount(const Node& node) const {
2143 return _totalUseCount[node];
2144}
2145
2146template<class Base>
2147inline void CodeHandler<Base>::setTotalUsageCount(const Node& node,
2148 size_t cout) {
2149 _totalUseCount[node] = cout;
2150}
2151
2152template<class Base>
2153inline void CodeHandler<Base>::increaseTotalUsageCount(const Node& node) {
2154 _totalUseCount[node]++;
2155}
2156
2157template<class Base>
2158inline void CodeHandler<Base>::resetManagedNodes() {
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
size_t reserveArraySpace(const OperationNode< Base > &newArray)
size_t size() const noexcept
const std::string * getLoopName(size_t id) const
virtual bool requiresVariableDependencies() const =0
void setOperation(CGOpCode op, const std::vector< Argument< Base > > &arguments=std::vector< Argument< Base > >())
const std::vector< size_t > & getInfo() const
size_t getHandlerPosition() const
const std::vector< Argument< Base > > & getArguments() const
CGOpCode getOperationType() const
virtual void setTemporaryVariableID(size_t minTempID, size_t maxTempID, size_t maxTempArrayID, size_t maxTempSparseArrayID)=0