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 _FIR_INTERPRETER_BYTECODE_H
23 #define _FIR_INTERPRETER_BYTECODE_H
24
25 #include <math.h>
26 #include <iostream>
27 #include <string>
28 #include <vector>
29
30 #include "exception.hh"
31 #include "faust/gui/PathBuilder.h"
32 #include "fbc_opcode.hh"
33
quote1(std::string str)34 static inline std::string quote1(std::string str)
35 {
36 return "\"" + str + "\"";
37 }
38
unquote1(const std::string & str)39 static inline std::string unquote1(const std::string& str)
40 {
41 return (str[0] == '"') ? str.substr(1, str.size() - 2) : str;
42 }
43
44 // Bytecode definition
45
46 template <class REAL>
47 struct FBCBlockInstruction;
48
49 template <class REAL>
50 struct FBCBasicInstruction : public FBCInstruction {
51 std::string fName;
52 Opcode fOpcode;
53 int fIntValue;
54 REAL fRealValue;
55 int fOffset1;
56 int fOffset2;
57
58 FBCBlockInstruction<REAL>* fBranch1;
59 FBCBlockInstruction<REAL>* fBranch2;
60
FBCBasicInstructionFBCBasicInstruction61 FBCBasicInstruction(Opcode opcode, const std::string& name, int val_int, REAL val_real, int off1, int off2,
62 FBCBlockInstruction<REAL>* branch1, FBCBlockInstruction<REAL>* branch2)
63 : fName(""),
64 fOpcode(opcode),
65 fIntValue(val_int),
66 fRealValue(val_real),
67 fOffset1(off1),
68 fOffset2(off2),
69 fBranch1(branch1),
70 fBranch2(branch2)
71 {
72 }
73
FBCBasicInstructionFBCBasicInstruction74 FBCBasicInstruction(Opcode opcode, int val_int, REAL val_real)
75 : fName(""),
76 fOpcode(opcode),
77 fIntValue(val_int),
78 fRealValue(val_real),
79 fOffset1(-1),
80 fOffset2(-1),
81 fBranch1(nullptr),
82 fBranch2(nullptr)
83 {
84 }
85
FBCBasicInstructionFBCBasicInstruction86 FBCBasicInstruction(Opcode opcode, int val_int, REAL val_real, int off1, int off2)
87 : fName(""),
88 fOpcode(opcode),
89 fIntValue(val_int),
90 fRealValue(val_real),
91 fOffset1(off1),
92 fOffset2(off2),
93 fBranch1(nullptr),
94 fBranch2(nullptr)
95 {
96 }
97
FBCBasicInstructionFBCBasicInstruction98 FBCBasicInstruction(Opcode opcode, const std::string& name, int val_int, REAL val_real, int off1, int off2)
99 : fName(name),
100 fOpcode(opcode),
101 fIntValue(val_int),
102 fRealValue(val_real),
103 fOffset1(off1),
104 fOffset2(off2),
105 fBranch1(nullptr),
106 fBranch2(nullptr)
107 {
108 }
109
FBCBasicInstructionFBCBasicInstruction110 FBCBasicInstruction(Opcode opcode)
111 : fName(""),
112 fOpcode(opcode),
113 fIntValue(0),
114 fRealValue(0),
115 fOffset1(-1),
116 fOffset2(-1),
117 fBranch1(nullptr),
118 fBranch2(nullptr)
119 {
120 }
121
FBCBasicInstructionFBCBasicInstruction122 FBCBasicInstruction()
123 : fName(""),
124 fOpcode(FBCInstruction::kNop),
125 fIntValue(0),
126 fRealValue(0),
127 fOffset1(-1),
128 fOffset2(-1),
129 fBranch1(nullptr),
130 fBranch2(nullptr)
131 {
132 }
133
getBranch1FBCBasicInstruction134 FBCBlockInstruction<REAL>* getBranch1() { return (fOpcode == kCondBranch) ? nullptr : fBranch1; }
getBranch2FBCBasicInstruction135 FBCBlockInstruction<REAL>* getBranch2() { return fBranch2; }
136
~FBCBasicInstructionFBCBasicInstruction137 virtual ~FBCBasicInstruction()
138 {
139 delete getBranch1();
140 delete getBranch2();
141 }
142
sizeFBCBasicInstruction143 int size()
144 {
145 int branches =
146 std::max(((getBranch1()) ? getBranch1()->size() : 0), ((getBranch2()) ? getBranch2()->size() : 0));
147 return (branches > 0) ? branches : 1;
148 }
149
writeFBCBasicInstruction150 virtual void write(std::ostream* out, bool binary = false, bool small = false, bool recurse = true)
151 {
152 if (small) {
153 *out << "o " << fOpcode << " k "
154 << " i " << fIntValue << " r " << fRealValue << " o " << fOffset1 << " o " << fOffset2 << std::endl;
155 } else {
156 *out << "opcode " << fOpcode << " " << gFBCInstructionTable[fOpcode] << " int " << fIntValue << " real "
157 << fRealValue << " offset1 " << fOffset1 << " offset2 " << fOffset2;
158 if (this->fName != "") {
159 *out << " name " << this->fName;
160 }
161 *out << std::endl;
162 }
163 // If select/if/loop : write branches
164 if (recurse && getBranch1()) {
165 getBranch1()->write(out, binary, small, recurse);
166 }
167 if (recurse && getBranch2()) {
168 getBranch2()->write(out, binary, small, recurse);
169 }
170 }
171
copyFBCBasicInstruction172 virtual FBCBasicInstruction<REAL>* copy()
173 {
174 return new FBCBasicInstruction<REAL>(fOpcode, fName, fIntValue, fRealValue, fOffset1, fOffset2,
175 ((getBranch1()) ? getBranch1()->copy() : nullptr),
176 ((getBranch2()) ? getBranch2()->copy() : nullptr));
177 }
178 };
179
180 template <class REAL>
181 struct FIRBlockStoreRealInstruction : public FBCBasicInstruction<REAL> {
182 std::vector<REAL> fNumTable;
183
FIRBlockStoreRealInstructionFIRBlockStoreRealInstruction184 FIRBlockStoreRealInstruction(FBCInstruction::Opcode opcode, int offset1, int offset2,
185 const std::vector<REAL>& numtable)
186 {
187 this->fOpcode = opcode;
188 this->fIntValue = 0;
189 this->fRealValue = 0;
190 this->fOffset1 = offset1;
191 this->fOffset2 = offset2;
192 this->fBranch1 = nullptr;
193 this->fBranch2 = nullptr;
194 this->fNumTable = numtable;
195 }
196
copyFIRBlockStoreRealInstruction197 virtual FIRBlockStoreRealInstruction<REAL>* copy()
198 {
199 return new FIRBlockStoreRealInstruction<REAL>(this->fOpcode, this->fOffset1, this->fOffset2, this->fNumTable);
200 }
201
writeFIRBlockStoreRealInstruction202 virtual void write(std::ostream* out, bool binary = false, bool small = false, bool recurse = true)
203 {
204 if (small) {
205 *out << "o " << this->fOpcode << " k "
206 << " o " << this->fOffset1 << " o " << this->fOffset2 << " s " << this->fNumTable.size() << std::endl;
207 } else {
208 *out << "opcode " << this->fOpcode << " " << gFBCInstructionTable[this->fOpcode] << " offset1 "
209 << this->fOffset1 << " offset2 " << this->fOffset2 << " size " << this->fNumTable.size();
210 if (this->fName != "") {
211 *out << " name " << this->fName;
212 }
213 *out << std::endl;
214 }
215 for (size_t i = 0; i < fNumTable.size(); i++) {
216 *out << this->fNumTable[i] << " ";
217 }
218 *out << std::endl;
219 }
220 };
221
222 template <class REAL>
223 struct FIRBlockStoreIntInstruction : public FBCBasicInstruction<REAL> {
224 std::vector<int> fNumTable;
225
FIRBlockStoreIntInstructionFIRBlockStoreIntInstruction226 FIRBlockStoreIntInstruction(FBCInstruction::Opcode opcode, int offset1, int offset2,
227 const std::vector<int>& numtable)
228 {
229 this->fOpcode = opcode;
230 this->fIntValue = 0;
231 this->fRealValue = 0;
232 this->fOffset1 = offset1;
233 this->fOffset2 = offset2;
234 this->fBranch1 = nullptr;
235 this->fBranch2 = nullptr;
236 this->fNumTable = numtable;
237 }
238
copyFIRBlockStoreIntInstruction239 virtual FIRBlockStoreIntInstruction<REAL>* copy()
240 {
241 return new FIRBlockStoreIntInstruction<REAL>(this->fOpcode, this->fOffset1, this->fOffset2, this->fNumTable);
242 }
243
writeFIRBlockStoreIntInstruction244 virtual void write(std::ostream* out, bool binary = false, bool small = false, bool recurse = true)
245 {
246 if (small) {
247 *out << "o " << this->fOpcode << " k "
248 << " o " << this->fOffset1 << " o " << this->fOffset2 << " s " << this->fNumTable.size() << std::endl;
249 } else {
250 *out << "opcode " << this->fOpcode << " " << gFBCInstructionTable[this->fOpcode] << " offset1 "
251 << this->fOffset1 << " offset2 " << this->fOffset2 << " size " << this->fNumTable.size();
252 if (this->fName != "") {
253 *out << " name " << this->fName;
254 }
255 *out << std::endl;
256 }
257 for (size_t i = 0; i < fNumTable.size(); i++) {
258 *out << this->fNumTable[i] << " ";
259 }
260 *out << std::endl;
261 }
262 };
263
264 template <class REAL>
265 struct FIRUserInterfaceInstruction : public FBCInstruction {
266 Opcode fOpcode;
267 int fOffset;
268 std::string fLabel;
269 std::string fKey;
270 std::string fValue;
271 REAL fInit;
272 REAL fMin;
273 REAL fMax;
274 REAL fStep;
275
FIRUserInterfaceInstructionFIRUserInterfaceInstruction276 FIRUserInterfaceInstruction(Opcode opcode, int offset, const std::string& label, const std::string& key,
277 const std::string& value, REAL init, REAL min, REAL max, REAL step)
278 : fOpcode(opcode),
279 fOffset(offset),
280 fLabel(label),
281 fKey(key),
282 fValue(value),
283 fInit(init),
284 fMin(min),
285 fMax(max),
286 fStep(step)
287 {
288 }
289
FIRUserInterfaceInstructionFIRUserInterfaceInstruction290 FIRUserInterfaceInstruction(Opcode opcode, int offset, const std::string& label, REAL init, REAL min, REAL max, REAL step)
291 : fOpcode(opcode), fOffset(offset), fLabel(label), fInit(init), fMin(min), fMax(max), fStep(step)
292 {
293 }
294
FIRUserInterfaceInstructionFIRUserInterfaceInstruction295 FIRUserInterfaceInstruction(Opcode opcode)
296 : fOpcode(opcode), fOffset(-1), fLabel(""), fKey(""), fValue(""), fInit(0), fMin(0), fMax(0), fStep(0)
297 {
298 }
299
FIRUserInterfaceInstructionFIRUserInterfaceInstruction300 FIRUserInterfaceInstruction(Opcode opcode, const std::string& label)
301 : fOpcode(opcode), fOffset(-1), fLabel(label), fKey(""), fValue(""), fInit(0), fMin(0), fMax(0), fStep(0)
302 {
303 }
304
FIRUserInterfaceInstructionFIRUserInterfaceInstruction305 FIRUserInterfaceInstruction(Opcode opcode, int offset, const std::string& label)
306 : fOpcode(opcode), fOffset(offset), fLabel(label), fKey(""), fValue(""), fInit(0), fMin(0), fMax(0), fStep(0)
307 {
308 }
309
FIRUserInterfaceInstructionFIRUserInterfaceInstruction310 FIRUserInterfaceInstruction(Opcode opcode, int offset, const std::string& label, REAL min, REAL max)
311 : fOpcode(opcode),
312 fOffset(offset),
313 fLabel(label),
314 fKey(""),
315 fValue(""),
316 fInit(0),
317 fMin(min),
318 fMax(max),
319 fStep(0)
320 {
321 }
322
FIRUserInterfaceInstructionFIRUserInterfaceInstruction323 FIRUserInterfaceInstruction(Opcode opcode, int offset, const std::string& key, const std::string& value)
324 : fOpcode(opcode), fOffset(offset), fLabel(""), fKey(key), fValue(value), fInit(0), fMin(0), fMax(0), fStep(0)
325 {
326 }
327
~FIRUserInterfaceInstructionFIRUserInterfaceInstruction328 virtual ~FIRUserInterfaceInstruction() {}
329
writeFIRUserInterfaceInstruction330 virtual void write(std::ostream* out, bool binary = false, bool small = false, bool recurse = true)
331 {
332 if (small) {
333 *out << "o " << fOpcode << " k "
334 << " o " << fOffset << " l " << quote1(fLabel) << " k " << quote1(fKey) << " v " << quote1(fValue)
335 << " i " << fInit << " m " << fMin << " m " << fMax << " s " << fStep << std::endl;
336 } else {
337 *out << "opcode " << fOpcode << " " << gFBCInstructionTable[fOpcode] << " offset " << fOffset << " label "
338 << quote1(fLabel) << " key " << quote1(fKey) << " value " << quote1(fValue) << " init " << fInit
339 << " min " << fMin << " max " << fMax << " step " << fStep << std::endl;
340 }
341 }
342 };
343
344 struct FIRMetaInstruction : public FBCInstruction {
345 std::string fKey;
346 std::string fValue;
347
FIRMetaInstructionFIRMetaInstruction348 FIRMetaInstruction(const std::string& key, const std::string& value) : fKey(key), fValue(value) {}
349
~FIRMetaInstructionFIRMetaInstruction350 virtual ~FIRMetaInstruction() {}
351
writeFIRMetaInstruction352 virtual void write(std::ostream* out, bool binary = false, bool small = false, bool recurse = true)
353 {
354 if (small) {
355 *out << "m"
356 << " k " << quote1(fKey) << " v " << quote1(fValue) << std::endl;
357 } else {
358 *out << "meta"
359 << " key " << quote1(fKey) << " value " << quote1(fValue) << std::endl;
360 }
361 }
362 };
363
364 #define InstructionIT typename std::vector<FBCBasicInstruction<REAL>*>::iterator
365 #define UIInstructionIT typename std::vector<FIRUserInterfaceInstruction<REAL>*>::iterator
366 #define MetaInstructionIT std::vector<FIRMetaInstruction*>::iterator
367
368 template <class REAL>
369 struct FIRUserInterfaceBlockInstruction : public FBCInstruction {
370 std::vector<FIRUserInterfaceInstruction<REAL>*> fInstructions;
371 std::map<std::string, int> fPathMap;
372
FIRUserInterfaceBlockInstructionFIRUserInterfaceBlockInstruction373 FIRUserInterfaceBlockInstruction() {}
374
~FIRUserInterfaceBlockInstructionFIRUserInterfaceBlockInstruction375 virtual ~FIRUserInterfaceBlockInstruction()
376 {
377 for (const auto& it : fInstructions) {
378 delete it;
379 }
380 }
381
pushFIRUserInterfaceBlockInstruction382 void push(FIRUserInterfaceInstruction<REAL>* inst)
383 {
384 if (inst) fInstructions.push_back(inst);
385 }
386
writeFIRUserInterfaceBlockInstruction387 virtual void write(std::ostream* out, bool binary = false, bool small = false, bool recurse = true)
388 {
389 *out << "block_size " << fInstructions.size() << std::endl;
390 for (const auto& it : fInstructions) {
391 it->write(out, binary, small, recurse);
392 }
393 }
394
getPathMapFIRUserInterfaceBlockInstruction395 std::map<std::string, int>& getPathMap()
396 {
397 // Build the [path, offset] map
398 PathBuilder path_builder;
399
400 for (const auto& it : fInstructions) {
401 switch (it->fOpcode) {
402 case FBCInstruction::kOpenVerticalBox:
403 path_builder.pushLabel(it->fLabel);
404 break;
405
406 case FBCInstruction::kOpenHorizontalBox:
407 path_builder.pushLabel(it->fLabel);
408 break;
409
410 case FBCInstruction::kOpenTabBox:
411 path_builder.pushLabel(it->fLabel);
412 break;
413
414 case FBCInstruction::kCloseBox:
415 path_builder.popLabel();
416 break;
417
418 case FBCInstruction::kAddButton:
419 case FBCInstruction::kAddCheckButton:
420 case FBCInstruction::kAddHorizontalSlider:
421 case FBCInstruction::kAddVerticalSlider:
422 case FBCInstruction::kAddNumEntry:
423 fPathMap[path_builder.buildPath(it->fLabel)] = it->fOffset;
424 break;
425
426 default:
427 break;
428 }
429 }
430
431 return fPathMap;
432 }
433
freezeDefaultValuesFIRUserInterfaceBlockInstruction434 void freezeDefaultValues(std::map<int, REAL>& real_map)
435 {
436 for (const auto& it : fInstructions) {
437 if (it->fOpcode == FBCInstruction::kAddButton
438 || it->fOpcode == FBCInstruction::kAddCheckButton
439 || it->fOpcode == FBCInstruction::kAddHorizontalSlider
440 || it->fOpcode == FBCInstruction::kAddVerticalSlider
441 || it->fOpcode == FBCInstruction::kAddNumEntry) {
442 real_map[it->fOffset] = it->fInit;
443 }
444 }
445 }
446
unFreezeValueFIRUserInterfaceBlockInstruction447 void unFreezeValue(std::map<int, REAL>& real_map, FBCInstruction::Opcode opcode)
448 {
449 for (const auto& it : fInstructions) {
450 if ((it->fOpcode == opcode) && real_map.find(it->fOffset) != real_map.end()) {
451 real_map.erase(real_map.find(it->fOffset));
452 }
453 }
454 }
455
unFreezeValueFIRUserInterfaceBlockInstruction456 void unFreezeValue(std::map<int, REAL>& real_map, const std::string& path)
457 {
458 if (fPathMap.find(path) != fPathMap.end()) {
459 real_map.erase(real_map.find(fPathMap[path]));
460 }
461 }
462
unFreezeValueFIRUserInterfaceBlockInstruction463 void unFreezeValue(std::map<int, REAL>& real_map)
464 {
465 for (const auto& it : fInstructions) {
466 if (real_map.find(it->fOffset) != real_map.end()) {
467 real_map.erase(real_map.find(it->fOffset));
468 }
469 }
470 }
471 };
472
473 struct FIRMetaBlockInstruction : public FBCInstruction {
474 std::vector<FIRMetaInstruction*> fInstructions;
475
~FIRMetaBlockInstructionFIRMetaBlockInstruction476 virtual ~FIRMetaBlockInstruction()
477 {
478 for (const auto& it : fInstructions) {
479 delete it;
480 }
481 }
482
pushFIRMetaBlockInstruction483 void push(FIRMetaInstruction* inst)
484 {
485 if (inst) fInstructions.push_back(inst);
486 }
487
writeFIRMetaBlockInstruction488 virtual void write(std::ostream* out, bool binary = false, bool small = false, bool recurse = true)
489 {
490 *out << "block_size " << fInstructions.size() << std::endl;
491 for (const auto& it : fInstructions) {
492 it->write(out, binary, small, recurse);
493 }
494 }
495 };
496
497 template <class REAL>
498 struct FBCBlockInstruction : public FBCInstruction {
499 std::vector<FBCBasicInstruction<REAL>*> fInstructions;
500
~FBCBlockInstructionFBCBlockInstruction501 virtual ~FBCBlockInstruction()
502 {
503 for (const auto& it : fInstructions) {
504 delete it;
505 }
506 }
507
508 // Check block coherency
checkFBCBlockInstruction509 void check()
510 {
511 faustassert(fInstructions.back()->fOpcode == FBCInstruction::kReturn);
512 }
513
pushFBCBlockInstruction514 void push(FBCBasicInstruction<REAL>* inst)
515 {
516 if (inst) fInstructions.push_back(inst);
517 }
518
mergeFBCBlockInstruction519 void merge(FBCBlockInstruction<REAL>* block)
520 {
521 for (const auto& it : block->fInstructions) {
522 if (it->fOpcode != FBCInstruction::kReturn) { // kReturn must be removed...
523 fInstructions.push_back(it);
524 }
525 }
526 }
527
writeFBCBlockInstruction528 virtual void write(std::ostream* out, bool binary = false, bool small = false, bool recurse = true)
529 {
530 *out << "block_size " << fInstructions.size() << std::endl;
531 for (const auto& it : fInstructions) {
532 it->write(out, binary, small, recurse);
533 }
534 }
535
stackMoveFBCBlockInstruction536 void stackMove(int& int_index, int& real_index)
537 {
538 std::cout << "FBCBlockInstruction::stackMove" << std::endl;
539 int tmp_int_index = 0;
540 int tmp_real_index = 0;
541 for (const auto& it : fInstructions) {
542 it->stackMove(tmp_int_index, tmp_real_index);
543 it->write(&std::cout);
544 std::cout << "int_stack_index " << tmp_int_index << " real_stack_index " << tmp_real_index << std::endl;
545 faustassert(tmp_int_index >= 0 && tmp_real_index >= 0);
546 int_index = std::max(int_index, tmp_int_index);
547 real_index = std::max(real_index, tmp_real_index);
548 }
549 }
550
copyFBCBlockInstruction551 virtual FBCBlockInstruction<REAL>* copy()
552 {
553 FBCBlockInstruction<REAL>* block = new FBCBlockInstruction<REAL>();
554 for (const auto& it : fInstructions) {
555 FBCBasicInstruction<REAL>* inst_copy = it->copy();
556 if (it->fOpcode == kCondBranch) { // Special case for loops
557 inst_copy->fBranch1 = block;
558 }
559 block->push(inst_copy);
560 }
561 return block;
562 }
563
sizeFBCBlockInstruction564 int size()
565 {
566 int size = 0;
567 for (const auto& it : fInstructions) {
568 size += it->size();
569 }
570 return size;
571 }
572
isRealInstFBCBlockInstruction573 bool isRealInst() { return isRealType(fInstructions.back()->fOpcode); }
574 };
575
576 #endif
577