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