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 _CPP_INSTRUCTIONS_H 23 #define _CPP_INSTRUCTIONS_H 24 25 using namespace std; 26 27 #include "text_instructions.hh" 28 #include "type_manager.hh" 29 #include "struct_manager.hh" 30 31 class CPPInstVisitor : public TextInstVisitor { 32 private: 33 /* 34 Global functions names table as a static variable in the visitor 35 so that each function prototype is generated at most once in the module. 36 */ 37 static map<string, bool> gFunctionSymbolTable; 38 39 // Polymorphic math functions 40 map<string, string> gPolyMathLibTable; 41 cast2FAUSTFLOAT(const string & str)42 string cast2FAUSTFLOAT(const string& str) { return "FAUSTFLOAT(" + str + ")"; } 43 44 public: 45 using TextInstVisitor::visit; 46 CPPInstVisitor(std::ostream * out,int tab=0)47 CPPInstVisitor(std::ostream* out, int tab = 0) 48 : TextInstVisitor(out, "->", new CStringTypeManager(xfloat(), "*"), tab) 49 { 50 // Mark all math.h functions as generated... 51 gFunctionSymbolTable["abs"] = true; 52 53 gFunctionSymbolTable["max_i"] = true; 54 gFunctionSymbolTable["min_i"] = true; 55 56 // Float version 57 gFunctionSymbolTable["fabsf"] = true; 58 gFunctionSymbolTable["acosf"] = true; 59 gFunctionSymbolTable["asinf"] = true; 60 gFunctionSymbolTable["atanf"] = true; 61 gFunctionSymbolTable["atan2f"] = true; 62 gFunctionSymbolTable["ceilf"] = true; 63 gFunctionSymbolTable["cosf"] = true; 64 gFunctionSymbolTable["expf"] = true; 65 gFunctionSymbolTable["exp10f"] = true; 66 gFunctionSymbolTable["floorf"] = true; 67 gFunctionSymbolTable["fmodf"] = true; 68 gFunctionSymbolTable["logf"] = true; 69 gFunctionSymbolTable["log10f"] = true; 70 gFunctionSymbolTable["powf"] = true; 71 gFunctionSymbolTable["remainderf"] = true; 72 gFunctionSymbolTable["rintf"] = true; 73 gFunctionSymbolTable["roundf"] = true; 74 gFunctionSymbolTable["sinf"] = true; 75 gFunctionSymbolTable["sqrtf"] = true; 76 gFunctionSymbolTable["tanf"] = true; 77 78 // Double version 79 gFunctionSymbolTable["fabs"] = true; 80 gFunctionSymbolTable["acos"] = true; 81 gFunctionSymbolTable["asin"] = true; 82 gFunctionSymbolTable["atan"] = true; 83 gFunctionSymbolTable["atan2"] = true; 84 gFunctionSymbolTable["ceil"] = true; 85 gFunctionSymbolTable["cos"] = true; 86 gFunctionSymbolTable["exp"] = true; 87 gFunctionSymbolTable["exp10"] = true; 88 gFunctionSymbolTable["floor"] = true; 89 gFunctionSymbolTable["fmod"] = true; 90 gFunctionSymbolTable["log"] = true; 91 gFunctionSymbolTable["log10"] = true; 92 gFunctionSymbolTable["pow"] = true; 93 gFunctionSymbolTable["remainder"] = true; 94 gFunctionSymbolTable["rint"] = true; 95 gFunctionSymbolTable["round"] = true; 96 gFunctionSymbolTable["sin"] = true; 97 gFunctionSymbolTable["sqrt"] = true; 98 gFunctionSymbolTable["tan"] = true; 99 100 // Quad version 101 gFunctionSymbolTable["fabsl"] = true; 102 gFunctionSymbolTable["acosl"] = true; 103 gFunctionSymbolTable["asinl"] = true; 104 gFunctionSymbolTable["atanl"] = true; 105 gFunctionSymbolTable["atan2l"] = true; 106 gFunctionSymbolTable["ceill"] = true; 107 gFunctionSymbolTable["cosl"] = true; 108 gFunctionSymbolTable["expl"] = true; 109 gFunctionSymbolTable["exp10l"] = true; 110 gFunctionSymbolTable["floorl"] = true; 111 gFunctionSymbolTable["fmodl"] = true; 112 gFunctionSymbolTable["logl"] = true; 113 gFunctionSymbolTable["log10l"] = true; 114 gFunctionSymbolTable["powl"] = true; 115 gFunctionSymbolTable["remainderl"] = true; 116 gFunctionSymbolTable["rintl"] = true; 117 gFunctionSymbolTable["roundl"] = true; 118 gFunctionSymbolTable["sinl"] = true; 119 gFunctionSymbolTable["sqrtl"] = true; 120 gFunctionSymbolTable["tanl"] = true; 121 122 // Polymath mapping int version 123 gPolyMathLibTable["abs"] = "std::abs"; 124 gPolyMathLibTable["max_i"] = "std::max<int>"; 125 gPolyMathLibTable["min_i"] = "std::min<int>"; 126 127 // Polymath mapping float version 128 gPolyMathLibTable["max_f"] = "std::max<float>"; 129 gPolyMathLibTable["min_f"] = "std::min<float>"; 130 131 gPolyMathLibTable["fabsf"] = "std::fabs"; 132 gPolyMathLibTable["acosf"] = "std::acos"; 133 gPolyMathLibTable["asinf"] = "std::asin"; 134 gPolyMathLibTable["atanf"] = "std::atan"; 135 gPolyMathLibTable["atan2f"] = "std::atan2"; 136 gPolyMathLibTable["ceilf"] = "std::ceil"; 137 gPolyMathLibTable["cosf"] = "std::cos"; 138 gPolyMathLibTable["expf"] = "std::exp"; 139 gPolyMathLibTable["exp2f"] = "std::exp2"; 140 gPolyMathLibTable["exp10f"] = "exp10f"; 141 gPolyMathLibTable["floorf"] = "std::floor"; 142 gPolyMathLibTable["fmodf"] = "std::fmod"; 143 gPolyMathLibTable["logf"] = "std::log"; 144 gPolyMathLibTable["log2f"] = "std::log2"; 145 gPolyMathLibTable["log10f"] = "std::log10"; 146 gPolyMathLibTable["powf"] = "std::pow"; 147 gPolyMathLibTable["remainderf"] = "std::remainder"; 148 gPolyMathLibTable["rintf"] = "std::rint"; 149 gPolyMathLibTable["roundf"] = "std::round"; 150 gPolyMathLibTable["sinf"] = "std::sin"; 151 gPolyMathLibTable["sqrtf"] = "std::sqrt"; 152 gPolyMathLibTable["tanf"] = "std::tan"; 153 154 // Polymath mapping double version 155 gPolyMathLibTable["max_"] = "std::max<double>"; 156 gPolyMathLibTable["min_"] = "std::min<double>"; 157 158 gPolyMathLibTable["fabs"] = "std::fabs"; 159 gPolyMathLibTable["acos"] = "std::acos"; 160 gPolyMathLibTable["asin"] = "std::asin"; 161 gPolyMathLibTable["atan"] = "std::atan"; 162 gPolyMathLibTable["atan2"] = "std::atan2"; 163 gPolyMathLibTable["ceil"] = "std::ceil"; 164 gPolyMathLibTable["cos"] = "std::cos"; 165 gPolyMathLibTable["exp"] = "std::exp"; 166 gPolyMathLibTable["exp2"] = "std::exp2"; 167 gPolyMathLibTable["exp10"] = "exp10"; 168 gPolyMathLibTable["floor"] = "std::floor"; 169 gPolyMathLibTable["fmod"] = "std::fmod"; 170 gPolyMathLibTable["log"] = "std::log"; 171 gPolyMathLibTable["log2"] = "std::log2"; 172 gPolyMathLibTable["log10"] = "std::log10"; 173 gPolyMathLibTable["pow"] = "std::pow"; 174 gPolyMathLibTable["remainder"] = "std::remainder"; 175 gPolyMathLibTable["rint"] = "std::rint"; 176 gPolyMathLibTable["round"] = "std::round"; 177 gPolyMathLibTable["sin"] = "std::sin"; 178 gPolyMathLibTable["sqrt"] = "std::sqrt"; 179 gPolyMathLibTable["tan"] = "std::tan"; 180 181 // Polymath mapping quad version 182 gPolyMathLibTable["max_l"] = "std::max<quad>"; 183 gPolyMathLibTable["min_l"] = "std::min<quad>"; 184 185 gPolyMathLibTable["fabsl"] = "std::fabs"; 186 gPolyMathLibTable["acosl"] = "std::acos"; 187 gPolyMathLibTable["asinl"] = "std::asin"; 188 gPolyMathLibTable["atanl"] = "std::atan"; 189 gPolyMathLibTable["atan2l"] = "std::atan2"; 190 gPolyMathLibTable["ceill"] = "std::ceil"; 191 gPolyMathLibTable["cosl"] = "std::cos"; 192 gPolyMathLibTable["expl"] = "std::exp"; 193 gPolyMathLibTable["exp2l"] = "std::exp2"; 194 gPolyMathLibTable["exp10l"] = "exp10"; 195 gPolyMathLibTable["floorl"] = "std::floor"; 196 gPolyMathLibTable["fmodl"] = "std::fmod"; 197 gPolyMathLibTable["logl"] = "std::log"; 198 gPolyMathLibTable["log2l"] = "std::log2"; 199 gPolyMathLibTable["log10l"] = "std::log10"; 200 gPolyMathLibTable["powl"] = "std::pow"; 201 gPolyMathLibTable["remainderl"] = "std::remainder"; 202 gPolyMathLibTable["rintl"] = "std::rint"; 203 gPolyMathLibTable["roundl"] = "std::round"; 204 gPolyMathLibTable["sinl"] = "std::sin"; 205 gPolyMathLibTable["sqrtl"] = "std::sqrt"; 206 gPolyMathLibTable["tanl"] = "std::tan"; 207 } 208 ~CPPInstVisitor()209 virtual ~CPPInstVisitor() {} 210 visit(AddMetaDeclareInst * inst)211 virtual void visit(AddMetaDeclareInst* inst) 212 { 213 // Special case 214 if (inst->fZone == "0") { 215 *fOut << "ui_interface->declare(" << inst->fZone << ", " << quote(inst->fKey) << ", " << quote(inst->fValue) 216 << ")"; 217 } else { 218 *fOut << "ui_interface->declare(&" << inst->fZone << ", " << quote(inst->fKey) << ", " 219 << quote(inst->fValue) << ")"; 220 } 221 EndLine(); 222 } 223 visit(OpenboxInst * inst)224 virtual void visit(OpenboxInst* inst) 225 { 226 string name; 227 switch (inst->fOrient) { 228 case OpenboxInst::kVerticalBox: 229 name = "ui_interface->openVerticalBox("; 230 break; 231 case OpenboxInst::kHorizontalBox: 232 name = "ui_interface->openHorizontalBox("; 233 break; 234 case OpenboxInst::kTabBox: 235 name = "ui_interface->openTabBox("; 236 break; 237 } 238 *fOut << name << quote(inst->fName) << ")"; 239 EndLine(); 240 } 241 visit(CloseboxInst * inst)242 virtual void visit(CloseboxInst* inst) 243 { 244 *fOut << "ui_interface->closeBox();"; 245 tab(fTab, *fOut); 246 } 247 visit(AddButtonInst * inst)248 virtual void visit(AddButtonInst* inst) 249 { 250 if (inst->fType == AddButtonInst::kDefaultButton) { 251 *fOut << "ui_interface->addButton(" << quote(inst->fLabel) << ", &" << inst->fZone << ")"; 252 } else { 253 *fOut << "ui_interface->addCheckButton(" << quote(inst->fLabel) << ", &" << inst->fZone << ")"; 254 } 255 EndLine(); 256 } 257 visit(AddSliderInst * inst)258 virtual void visit(AddSliderInst* inst) 259 { 260 string name; 261 switch (inst->fType) { 262 case AddSliderInst::kHorizontal: 263 name = "ui_interface->addHorizontalSlider"; 264 break; 265 case AddSliderInst::kVertical: 266 name = "ui_interface->addVerticalSlider"; 267 break; 268 case AddSliderInst::kNumEntry: 269 name = "ui_interface->addNumEntry"; 270 break; 271 } 272 *fOut << name << "(" << quote(inst->fLabel) << ", " << "&" << inst->fZone << ", " 273 << cast2FAUSTFLOAT(checkReal(inst->fInit)) << ", " 274 << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", " 275 << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ", " 276 << cast2FAUSTFLOAT(checkReal(inst->fStep)) << ")"; 277 EndLine(); 278 } 279 visit(AddBargraphInst * inst)280 virtual void visit(AddBargraphInst* inst) 281 { 282 string name; 283 switch (inst->fType) { 284 case AddBargraphInst::kHorizontal: 285 name = "ui_interface->addHorizontalBargraph"; 286 break; 287 case AddBargraphInst::kVertical: 288 name = "ui_interface->addVerticalBargraph"; 289 break; 290 } 291 *fOut << name << "(" << quote(inst->fLabel) << ", &" << inst->fZone << ", " 292 << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", " 293 << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ")"; 294 EndLine(); 295 } 296 visit(AddSoundfileInst * inst)297 virtual void visit(AddSoundfileInst* inst) 298 { 299 *fOut << "ui_interface->addSoundfile(" << quote(inst->fLabel) << ", " << quote(inst->fURL) << ", &" 300 << inst->fSFZone << ")"; 301 EndLine(); 302 } 303 visit(DeclareVarInst * inst)304 virtual void visit(DeclareVarInst* inst) 305 { 306 if (inst->fAddress->getAccess() & Address::kConst) { 307 *fOut << "const "; 308 } 309 310 if (inst->fAddress->getAccess() & Address::kStaticStruct) { 311 *fOut << "static "; 312 } 313 314 if (inst->fAddress->getAccess() & Address::kVolatile) { 315 *fOut << "volatile "; 316 } 317 318 *fOut << fTypeManager->generateType(inst->fType, inst->fAddress->getName()); 319 if (inst->fValue) { 320 *fOut << " = "; 321 inst->fValue->accept(this); 322 } 323 EndLine(); 324 } 325 visit(DeclareFunInst * inst)326 virtual void visit(DeclareFunInst* inst) 327 { 328 // Already generated 329 if (gFunctionSymbolTable.find(inst->fName) != gFunctionSymbolTable.end()) { 330 return; 331 } else { 332 gFunctionSymbolTable[inst->fName] = true; 333 } 334 335 // Defined as macro in the architecture file... 336 if (checkMinMax(inst->fName)) { 337 return; 338 } 339 340 // Prototype arguments 341 if (inst->fType->fAttribute & FunTyped::kInline) { 342 *fOut << "inline "; 343 } 344 345 if (inst->fType->fAttribute & FunTyped::kVirtual) { 346 *fOut << "virtual "; 347 } 348 349 if (inst->fType->fAttribute & FunTyped::kLocal || inst->fType->fAttribute & FunTyped::kStatic) { 350 *fOut << "static "; 351 } 352 353 // Prototype 354 *fOut << fTypeManager->generateType(inst->fType->fResult, generateFunName(inst->fName)); 355 generateFunDefArgs(inst); 356 generateFunDefBody(inst); 357 } 358 visit(LoadVarAddressInst * inst)359 virtual void visit(LoadVarAddressInst* inst) 360 { 361 *fOut << "&"; 362 inst->fAddress->accept(this); 363 } 364 visit(BinopInst * inst)365 virtual void visit(BinopInst* inst) 366 { 367 // Special case for 'logical right-shift' 368 if (strcmp(gBinOpTable[inst->fOpcode]->fName, ">>>") == 0) { 369 TypingVisitor typing; 370 inst->fInst1->accept(&typing); 371 if (isInt64Type(typing.fCurType)) { 372 *fOut << "(int64_t(uint64_t("; 373 } else if (isInt32Type(typing.fCurType)) { 374 *fOut << "(int32_t(uint32_t("; 375 } else { 376 faustassert(false); 377 } 378 inst->fInst1->accept(this); 379 *fOut << ") >> "; 380 inst->fInst2->accept(this); 381 *fOut << "))w"; 382 } else { 383 TextInstVisitor::visit(inst); 384 } 385 } 386 visit(FixedPointNumInst * inst)387 virtual void visit(FixedPointNumInst* inst) { *fOut << "fixpoint_t(" << checkFloat(inst->fNum) << ")"; } 388 visit(FixedPointArrayNumInst * inst)389 virtual void visit(FixedPointArrayNumInst* inst) 390 { 391 char sep = '{'; 392 for (size_t i = 0; i < inst->fNumTable.size(); i++) { 393 *fOut << sep << "fixpoint_t(" << checkFloat(inst->fNumTable[i]) << ")"; 394 sep = ','; 395 } 396 *fOut << '}'; 397 } 398 visit(::CastInst * inst)399 virtual void visit(::CastInst* inst) 400 { 401 string type = fTypeManager->generateType(inst->fType); 402 if (endWith(type, "*")) { 403 *fOut << "static_cast<" << type << ">("; 404 inst->fInst->accept(this); 405 *fOut << ")"; 406 } else { 407 *fOut << type << "("; 408 inst->fInst->accept(this); 409 *fOut << ")"; 410 } 411 } 412 visit(BitcastInst * inst)413 virtual void visit(BitcastInst* inst) 414 { 415 switch (inst->fType->getType()) { 416 case Typed::kInt32: 417 *fOut << "*reinterpret_cast<int*>(&"; 418 inst->fInst->accept(this); 419 *fOut << ")"; 420 break; 421 case Typed::kInt64: 422 *fOut << "*reinterpret_cast<int64_t*>(&"; 423 inst->fInst->accept(this); 424 *fOut << ")"; 425 break; 426 case Typed::kFloat: 427 *fOut << "*reinterpret_cast<float*>(&"; 428 inst->fInst->accept(this); 429 *fOut << ")"; 430 break; 431 case Typed::kDouble: 432 *fOut << "*reinterpret_cast<double*>(&"; 433 inst->fInst->accept(this); 434 *fOut << ")"; 435 break; 436 default: 437 faustassert(false); 438 break; 439 } 440 } 441 visit(FunCallInst * inst)442 virtual void visit(FunCallInst* inst) 443 { 444 string name = gGlobal->getMathFunction(inst->fName); 445 name = (gPolyMathLibTable.find(name) != gPolyMathLibTable.end()) ? gPolyMathLibTable[name] : name; 446 generateFunCall(inst, name); 447 } 448 visit(ForLoopInst * inst)449 virtual void visit(ForLoopInst* inst) 450 { 451 // Don't generate empty loops... 452 if (inst->fCode->size() == 0) return; 453 454 if (gGlobal->gClang && !inst->fIsRecursive) { 455 *fOut << "#pragma clang loop vectorize(enable) interleave(enable)"; 456 tab(fTab, *fOut); 457 } 458 TextInstVisitor::visit(inst); 459 } 460 cleanup()461 static void cleanup() { gFunctionSymbolTable.clear(); } 462 }; 463 464 // Used for -os mode (TODO : does not work with 'soundfile') 465 class CPPInstVisitor1 : public CPPInstVisitor { 466 467 private: 468 469 StructInstVisitor fStructVisitor; 470 bool fZoneAddress; // If a zone address is currently written 471 bool fIndexedAddress; // If an indexed address is currently written 472 473 public: 474 CPPInstVisitor1(std::ostream * out,int tab=0)475 CPPInstVisitor1(std::ostream* out, int tab = 0) 476 :CPPInstVisitor(out, tab), fZoneAddress(false), fIndexedAddress(false) 477 {} 478 visit(AddSoundfileInst * inst)479 virtual void visit(AddSoundfileInst* inst) 480 { 481 // Not supported for now 482 throw faustexception("ERROR : AddSoundfileInst not supported for -os mode\n"); 483 } 484 visit(DeclareVarInst * inst)485 virtual void visit(DeclareVarInst* inst) 486 { 487 Address::AccessType access = inst->fAddress->getAccess(); 488 string name = inst->fAddress->getName(); 489 bool is_control = startWith(name, "fButton") 490 || startWith(name, "fCheckbox") 491 || startWith(name, "fVslider") 492 || startWith(name, "fHslider") 493 || startWith(name, "fEntry") 494 || startWith(name, "fVbargraph") 495 || startWith(name, "fHbargraph") 496 || name == "fSampleRate"; 497 if (((access & Address::kStruct) || (access & Address::kStaticStruct)) && !is_control) { 498 fStructVisitor.visit(inst); 499 } else { 500 CPPInstVisitor::visit(inst); 501 } 502 } 503 visit(NamedAddress * named)504 virtual void visit(NamedAddress* named) 505 { 506 Typed::VarType type; 507 if (fStructVisitor.hasField(named->fName, type)) { 508 // Zone address zone[id][index] are rewritten as zone[id+index] 509 fZoneAddress = true; 510 if (type == Typed::kInt32) { 511 *fOut << "iZone[" << fStructVisitor.getFieldIntOffset(named->fName)/sizeof(int); 512 } else { 513 *fOut << "fZone[" << fStructVisitor.getFieldRealOffset(named->fName)/ifloatsize(); 514 } 515 if (!fIndexedAddress) { *fOut << "]"; } 516 } else { 517 fZoneAddress = false; 518 *fOut << named->fName; 519 } 520 } 521 522 /* 523 Indexed address can actually be values in an array or fields in a struct type 524 */ visit(IndexedAddress * indexed)525 virtual void visit(IndexedAddress* indexed) 526 { 527 fIndexedAddress = true; 528 indexed->fAddress->accept(this); 529 DeclareStructTypeInst* struct_type = isStructType(indexed->getName()); 530 if (struct_type) { 531 Int32NumInst* field_index = static_cast<Int32NumInst*>(indexed->fIndex); 532 *fOut << "->" << struct_type->fType->getName(field_index->fNum); 533 } else { 534 // Zone address zone[id][index] are rewritten as zone[id+index] 535 if (fZoneAddress) { *fOut << "+"; } else { *fOut << "["; } 536 fIndexedAddress = false; 537 fZoneAddress = false; 538 indexed->fIndex->accept(this); 539 *fOut << "]"; 540 } 541 } 542 543 // Size is expressed in unit of the actual type (so 'int' or 'float/double') getIntZoneSize()544 int getIntZoneSize() { return fStructVisitor.getStructIntSize()/sizeof(int); } getRealZoneSize()545 int getRealZoneSize() { return fStructVisitor.getStructRealSize()/ifloatsize(); } 546 547 }; 548 549 class CPPVecInstVisitor : public CPPInstVisitor { 550 public: CPPVecInstVisitor(std::ostream * out,int tab=0)551 CPPVecInstVisitor(std::ostream* out, int tab = 0) : CPPInstVisitor(out, tab) {} 552 }; 553 554 #endif 555