1 /************************************************************************
2  ************************************************************************
3     FAUST compiler
4     Copyright (C) 2003-2018 GRAME, Centre National de Creation Musicale
5     ---------------------------------------------------------------------
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  ************************************************************************
20  ************************************************************************/
21 
22 #ifndef interpreter_dsp_aux_pe_h
23 #define interpreter_dsp_aux_pe_h
24 
25 #include "interpreter_dsp_aux.h"
26 
27 // Specialization using partial evaluation: making controllers constant and optimizing the code.
28 
29 template <class REAL, int TRACE>
30 class interpreter_dsp_aux_pe : public interpreter_dsp_aux<REAL, TRACE> {
31     protected:
32         FBCBlockInstruction<REAL>* fStaticInitBlock;
33         FBCBlockInstruction<REAL>* fInitBlock;
34         FBCBlockInstruction<REAL>* fResetUIBlock;
35         FBCBlockInstruction<REAL>* fClearBlock;
36         FBCBlockInstruction<REAL>* fComputeBlock;
37         FBCBlockInstruction<REAL>* fComputeDSPBlock;
38 
39         std::map<int, int>  fIntMap;
40         std::map<int, REAL> fRealMap;
41 
42     public:
interpreter_dsp_aux_pe(interpreter_dsp_factory_aux<REAL,TRACE> * factory)43         interpreter_dsp_aux_pe(interpreter_dsp_factory_aux<REAL, TRACE>* factory)
44         {
45             std::cout << "interpreter_dsp_aux_pe\n";
46             /*
47              if (this->fFactory->getMemoryManager()) {
48              this->fInputs  = static_cast<T**>(this->fFactory->allocate(sizeof(T*) * this->fFactory->fNumInputs));
49              this->fOutputs = static_cast<T**>(this->fFactory->allocate(sizeof(T*) * this->fFactory->fNumOutputs));
50              } else {
51              this->fInputs  = new T*[this->fFactory->fNumInputs];
52              this->fOutputs = new T*[this->fFactory->fNumOutputs];
53              }
54              */
55 
56             /*
57              fFactory->fStaticInitBlock->write(&std::cout, false);
58              fFactory->fInitBlock->write(&std::cout, false);
59              fFactory->fResetUIBlock->write(&std::cout, false);
60              fFactory->fClearBlock->write(&std::cout, false);
61              fFactory->fComputeBlock->write(&std::cout, false);
62              fFactory->fComputeDSPBlock->write(&std::cout, false);
63              std::cout << "size " << fFactory->fComputeDSPBlock->size() << std::endl;
64              */
65 
66             this->fFactory     = factory;
67             this->fFBCExecutor = factory->createFBCExecutor();
68 
69             fStaticInitBlock = nullptr;
70             fInitBlock       = nullptr;
71             fResetUIBlock    = nullptr;
72             fClearBlock      = nullptr;
73             fComputeBlock    = nullptr;
74             fComputeDSPBlock = nullptr;
75         }
76 
~interpreter_dsp_aux_pe()77         virtual ~interpreter_dsp_aux_pe()
78         {
79             /*
80              if (this->fFactory->getMemoryManager()) {
81              this->fFactory->destroy(this->fInputs);
82              this->fFactory->destroy(this->fOutputs);
83              } else {
84              delete[] this->fInputs;
85              delete[] this->fOutputs;
86              }
87              */
88 
89             delete this->fStaticInitBlock;
90             delete this->fInitBlock;
91             delete this->fResetUIBlock;
92             delete this->fClearBlock;
93             delete this->fComputeBlock;
94             delete this->fComputeDSPBlock;
95         }
96 
instanceConstants(int sample_rate)97         virtual void instanceConstants(int sample_rate)
98         {
99             // Store sample_rate in specialization fIntMap
100             fIntMap[this->fFactory->fSROffset] = sample_rate;
101 
102             // Store sample_rate in 'fSampleate' variable at correct offset in fIntHeap
103             this->fFBCExecutor->setIntValue(this->fFactory->fSROffset, sample_rate);
104 
105             // Execute state init instructions
106             this->fFBCExecutor->ExecuteBlock(this->fFactory->fInitBlock);
107         }
108 
init(int sample_rate)109         virtual void init(int sample_rate)
110         {
111             this->fInitialized = true;
112 
113             // Store sample_rate in specialization fIntMap
114             fIntMap[this->fFactory->fSROffset] = sample_rate;
115 
116             // Store sample_rate in 'fSampleRate' variable at correct offset in fIntHeap
117             this->fFBCExecutor->setIntValue(this->fFactory->fSROffset, sample_rate);
118 
119             this->classInit(sample_rate);
120             this->instanceInit(sample_rate);
121 
122             // Propagate constant values stored in the code into the heap
123             this->fStaticInitBlock =
124             FBCInstructionOptimizer<T>::specialize2Heap(this->fFactory->fStaticInitBlock->copy(), fIntMap, fRealMap);
125             this->fInitBlock =
126             FBCInstructionOptimizer<T>::specialize2Heap(this->fFactory->fInitBlock->copy(), fIntMap, fRealMap);
127             this->fResetUIBlock =
128             FBCInstructionOptimizer<T>::specialize2Heap(this->fFactory->fResetUIBlock->copy(), fIntMap, fRealMap);
129             this->fClearBlock =
130             FBCInstructionOptimizer<T>::specialize2Heap(this->fFactory->fClearBlock->copy(), fIntMap, fRealMap);
131 
132             // Suppress IOTA from fIntMap since we don't want specialization to use it
133             if (fIntMap.find(this->fFactory->fIOTAOffset) != fIntMap.end()) {
134                 fIntMap.erase(fIntMap.find(this->fFactory->fIOTAOffset));
135             }
136 
137             // Freeze all controllers
138             this->fFactory->fUserInterfaceBlock->freezeDefaultValues(fRealMap);
139 
140             // To test : unfreeze "freg, gate, gain" controllers
141             std::map<std::string, int>& map = this->fFactory->fUserInterfaceBlock->getPathMap();
142             for (auto& it : map) {
143                 if ((it.first.find("freq") != std::string::npos) || (it.first.find("gate") != std::string::npos) ||
144                     (it.first.find("gain") != std::string::npos)) {
145                     this->fFactory->fUserInterfaceBlock->unFreezeValue(fRealMap, it.first);
146                 }
147             }
148             // Keep button on
149             // this->fFactory->fUserInterfaceBlock->unFreezeValue(fRealMap, FBCInstruction::kAddButton);
150 
151             // Specialization by partial evaluation
152             this->fComputeBlock =
153             FBCInstructionOptimizer<T>::specialize(this->fFactory->fComputeBlock->copy(), fIntMap, fRealMap);
154 
155         #ifdef MACHINE
156             // LLVM JIT only works on unoptimized FBC
157             this->fComputeDSPBlock = this->fFactory->fComputeDSPBlock->copy();
158         #else
159             this->fComputeDSPBlock =
160             FBCInstructionOptimizer<T>::optimizeBlock(this->fFactory->fComputeDSPBlock->copy(), 1, 4);
161         #endif
162 
163             // To test C++ generation
164             // this->fComputeDSPBlock = this->fFactory->fComputeDSPBlock->copy();
165 
166             this->fComputeDSPBlock = FBCInstructionOptimizer<T>::specialize(this->fComputeDSPBlock, fIntMap, fRealMap);
167 
168         #ifndef MACHINE
169             // // LLVM JIT only works on unoptimized FBC
170             this->fComputeBlock    = FBCInstructionOptimizer<T>::optimizeBlock(this->fComputeBlock, 5, 6);
171             this->fComputeDSPBlock = FBCInstructionOptimizer<T>::optimizeBlock(this->fComputeDSPBlock, 5, 6);
172         #endif
173 
174             /*
175              this->fStaticInitBlock->write(&std::cout, false);
176              this->fInitBlock->write(&std::cout, false);
177              this->fResetUIBlock->write(&std::cout, false);
178              this->fClearBlock->write(&std::cout, false);
179              this->fComputeBlock->write(&std::cout, false);
180              this->fComputeDSPBlock->write(&std::cout, false);
181              */
182             /*
183              #ifdef MACHINE
184              FBCCPPGenerator<T> cpp_generator(this->fFactory);
185              cpp_generator.generateCode(std::cout, this->fComputeBlock, this->fComputeDSPBlock);
186              #endif
187              */
188         }
189 
compute(int count,FAUSTFLOAT ** inputs_aux,FAUSTFLOAT ** outputs_aux)190         virtual void compute(int count, FAUSTFLOAT** inputs_aux, FAUSTFLOAT** outputs_aux)
191         {
192             if (count == 0) return;  // Beware: compiled loop don't work with an index of 0
193 
194             if (TRACE > 0 && !this->fInitialized) {
195                 std::cout << "======== DSP is not initialized ! ========" << std::endl;
196             } else {
197                 // std::cout << "compute " << count << std::endl;
198                 T** inputs  = reinterpret_cast<T**>(inputs_aux);
199                 T** outputs = reinterpret_cast<T**>(outputs_aux);
200 
201                 // Prepare in/out buffers
202                 for (int i = 0; i < this->fFactory->fNumInputs; i++) {
203                     this->fFBCExecutor->setInput(i, inputs[i]);
204                 }
205                 for (int i = 0; i < this->fFactory->fNumOutputs; i++) {
206                     this->fFBCExecutor->setOutput(i, outputs[i]);
207                 }
208 
209                 // Set count in 'count' variable at the correct offset in fIntHeap
210                 this->fFBCExecutor->setIntValue(this->fFactory->fCountOffset, count);
211 
212                 // Executes the specialized 'control' block
213                 this->fFBCExecutor->ExecuteBlock(this->fComputeBlock);
214 
215                 // Executes the specialized 'DSP' block
216         #ifdef MACHINE
217                 this->fFBCExecutor->ExecuteBlock(this->fComputeDSPBlock, true);
218         #else
219                 this->fFBCExecutor->ExecuteBlock(this->fComputeDSPBlock);
220         #endif
221             }
222         }
223 };
224 
225 #endif
226