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 _DLANG_INSTRUCTIONS_H 23 #define _DLANG_INSTRUCTIONS_H 24 25 using namespace std; 26 27 #include "text_instructions.hh" 28 #include "type_manager.hh" 29 30 class DLangInstVisitor : public TextInstVisitor { 31 private: 32 /* 33 Global functions names table as a static variable in the visitor 34 so that each function prototype is generated at most once in the module. 35 */ 36 static map<string, bool> gFunctionSymbolTable; 37 38 // Polymorphic math functions 39 map<string, string> gPolyMathLibTable; 40 cast2FAUSTFLOAT(const string & str)41 string cast2FAUSTFLOAT(const string& str) { return "cast(FAUSTFLOAT)" + str; } 42 43 public: 44 using TextInstVisitor::visit; 45 DLangInstVisitor(std::ostream * out,int tab=0)46 DLangInstVisitor(std::ostream* out, int tab = 0) : TextInstVisitor(out, ".", xfloat(), "*", tab) 47 { 48 // Set 64 bits types 49 fTypeManager->fTypeDirectTable[Typed::kInt64] = "long"; 50 fTypeManager->fTypeDirectTable[Typed::kInt64_ptr] = "long*"; 51 fTypeManager->fTypeDirectTable[Typed::kInt64_vec] = "vector<long>"; 52 53 // Int version 54 gPolyMathLibTable["abs"] = "std.math.abs"; 55 gPolyMathLibTable["max_i"] = "max"; 56 gPolyMathLibTable["min_i"] = "min"; 57 gPolyMathLibTable["rint"] = "round"; 58 59 // Float version 60 gPolyMathLibTable["fabsf"] = "fabs"; 61 gPolyMathLibTable["acosf"] = "acos"; 62 gPolyMathLibTable["asinf"] = "asin"; 63 gPolyMathLibTable["atanf"] = "atan"; 64 gPolyMathLibTable["atan2f"] = "atan2"; 65 gPolyMathLibTable["ceilf"] = "ceil"; 66 gPolyMathLibTable["cosf"] = "cos"; 67 gPolyMathLibTable["coshf"] = "cosh"; 68 gPolyMathLibTable["expf"] = "exp"; 69 gPolyMathLibTable["floorf"] = "floor"; 70 gPolyMathLibTable["fmodf"] = "fmod"; 71 gPolyMathLibTable["logf"] = "log"; 72 gPolyMathLibTable["log10f"] = "log10"; 73 gPolyMathLibTable["max_f"] = "fmax"; 74 gPolyMathLibTable["min_f"] = "fmin"; 75 gPolyMathLibTable["powf"] = "pow"; 76 gPolyMathLibTable["remainderf"] = "remainder"; 77 gPolyMathLibTable["roundf"] = "round"; 78 gPolyMathLibTable["sinf"] = "sin"; 79 gPolyMathLibTable["sinhf"] = "sinh"; 80 gPolyMathLibTable["sqrtf"] = "sqrt"; 81 gPolyMathLibTable["tanf"] = "tan"; 82 gPolyMathLibTable["tanhf"] = "tanh"; 83 84 // Hyperbolic 85 gPolyMathLibTable["acoshf"] = "acosh"; 86 gPolyMathLibTable["asinhf"] = "asinh"; 87 gPolyMathLibTable["atanhf"] = "atanh"; 88 gPolyMathLibTable["coshf"] = "cosh"; 89 gPolyMathLibTable["sinhf"] = "sinh"; 90 gPolyMathLibTable["tanhf"] = "tanh"; 91 92 gPolyMathLibTable["isnanf"] = "isNaN"; 93 gPolyMathLibTable["isinff"] = "isInfinity"; 94 gPolyMathLibTable["copysignf"] = "copysign"; 95 96 // Double version 97 gPolyMathLibTable["fabs"] = "fabs"; 98 gPolyMathLibTable["acos"] = "acos"; 99 gPolyMathLibTable["asin"] = "asin"; 100 gPolyMathLibTable["atan"] = "atan"; 101 gPolyMathLibTable["atan2"] = "atan2"; 102 gPolyMathLibTable["ceil"] = "ceil"; 103 gPolyMathLibTable["cos"] = "cos"; 104 gPolyMathLibTable["cosh"] = "cosh"; 105 gPolyMathLibTable["exp"] = "exp"; 106 gPolyMathLibTable["floor"] = "floor"; 107 gPolyMathLibTable["fmod"] = "fmod"; 108 gPolyMathLibTable["log"] = "log"; 109 gPolyMathLibTable["log10"] = "log10"; 110 gPolyMathLibTable["max_"] = "fmax"; 111 gPolyMathLibTable["min_"] = "fmin"; 112 gPolyMathLibTable["pow"] = "pow"; 113 gPolyMathLibTable["remainder"] = "remainder"; 114 gPolyMathLibTable["round"] = "round"; 115 gPolyMathLibTable["sin"] = "sin"; 116 gPolyMathLibTable["sinh"] = "sinh"; 117 gPolyMathLibTable["sqrt"] = "sqrt"; 118 gPolyMathLibTable["tan"] = "tan"; 119 gPolyMathLibTable["tanh"] = "tanh"; 120 121 // Hyperbolic 122 gPolyMathLibTable["acosh"] = "acosh"; 123 gPolyMathLibTable["asinh"] = "asinh"; 124 gPolyMathLibTable["atanh"] = "atanh"; 125 gPolyMathLibTable["cosh"] = "cosh"; 126 gPolyMathLibTable["sinh"] = "sinh"; 127 gPolyMathLibTable["tanh"] = "tanh"; 128 129 gPolyMathLibTable["isnan"] = "isNaN"; 130 gPolyMathLibTable["isinf"] = "isInfinity"; 131 gPolyMathLibTable["copysign"] = "copysign"; 132 } 133 ~DLangInstVisitor()134 virtual ~DLangInstVisitor() {} 135 visit(AddMetaDeclareInst * inst)136 virtual void visit(AddMetaDeclareInst* inst) 137 { 138 // Special case 139 if (inst->fZone == "0") { 140 *fOut << "uiInterface.declare(" << inst->fZone << ", " << quote(inst->fKey) << ", " << quote(inst->fValue) 141 << ")"; 142 } else { 143 *fOut << "uiInterface.declare(&" << inst->fZone << ", " << quote(inst->fKey) << ", " 144 << quote(inst->fValue) << ")"; 145 } 146 EndLine(); 147 } 148 visit(OpenboxInst * inst)149 virtual void visit(OpenboxInst* inst) 150 { 151 string name; 152 switch (inst->fOrient) { 153 case OpenboxInst::kVerticalBox: 154 name = "uiInterface.openVerticalBox("; 155 break; 156 case OpenboxInst::kHorizontalBox: 157 name = "uiInterface.openHorizontalBox("; 158 break; 159 case OpenboxInst::kTabBox: 160 name = "uiInterface.openTabBox("; 161 break; 162 } 163 *fOut << name << quote(inst->fName) << ")"; 164 EndLine(); 165 } 166 visit(CloseboxInst * inst)167 virtual void visit(CloseboxInst* inst) 168 { 169 *fOut << "uiInterface.closeBox();"; 170 tab(fTab, *fOut); 171 } 172 visit(AddButtonInst * inst)173 virtual void visit(AddButtonInst* inst) 174 { 175 if (inst->fType == AddButtonInst::kDefaultButton) { 176 *fOut << "uiInterface.addButton(" << quote(inst->fLabel) << ", &" << inst->fZone << ")"; 177 } else { 178 *fOut << "uiInterface.addCheckButton(" << quote(inst->fLabel) << ", &" << inst->fZone << ")"; 179 } 180 EndLine(); 181 } 182 visit(AddSliderInst * inst)183 virtual void visit(AddSliderInst* inst) 184 { 185 string name; 186 switch (inst->fType) { 187 case AddSliderInst::kHorizontal: 188 name = "uiInterface.addHorizontalSlider"; 189 break; 190 case AddSliderInst::kVertical: 191 name = "uiInterface.addVerticalSlider"; 192 break; 193 case AddSliderInst::kNumEntry: 194 name = "uiInterface.addNumEntry"; 195 break; 196 } 197 *fOut << name << "(" << quote(inst->fLabel) << ", " << "&" << inst->fZone << ", " 198 << cast2FAUSTFLOAT(checkReal(inst->fInit)) << ", " 199 << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", " 200 << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ", " 201 << cast2FAUSTFLOAT(checkReal(inst->fStep)) << ")"; 202 EndLine(); 203 } 204 visit(AddBargraphInst * inst)205 virtual void visit(AddBargraphInst* inst) 206 { 207 string name; 208 switch (inst->fType) { 209 case AddBargraphInst::kHorizontal: 210 name = "uiInterface.addHorizontalBargraph"; 211 break; 212 case AddBargraphInst::kVertical: 213 name = "uiInterface.addVerticalBargraph"; 214 break; 215 } 216 *fOut << name << "(" << quote(inst->fLabel) << ", &" << inst->fZone << ", " 217 << cast2FAUSTFLOAT(checkReal(inst->fMin)) << ", " 218 << cast2FAUSTFLOAT(checkReal(inst->fMax)) << ")"; 219 EndLine(); 220 } 221 visit(AddSoundfileInst * inst)222 virtual void visit(AddSoundfileInst* inst) 223 { 224 *fOut << "uiInterface.addSoundfile(" << quote(inst->fLabel) << ", " << quote(inst->fURL) << ", &" 225 << inst->fSFZone << ")"; 226 EndLine(); 227 } 228 visit(DeclareVarInst * inst)229 virtual void visit(DeclareVarInst* inst) 230 { 231 if (inst->fAddress->getAccess() & Address::kConst) { 232 *fOut << "const "; 233 } 234 235 if (inst->fAddress->getAccess() & Address::kStaticStruct) { 236 *fOut << "__gshared "; 237 } 238 239 if (inst->fAddress->getAccess() & Address::kVolatile) { 240 *fOut << "volatile "; 241 } 242 ArrayTyped* array_typed = dynamic_cast<ArrayTyped*>(inst->fType); 243 if (array_typed && array_typed->fSize > 1) { 244 string type = fTypeManager->fTypeDirectTable[array_typed->fType->getType()]; 245 if (inst->fValue) { 246 *fOut << type << "[] " << inst->fAddress->getName() << " = "; 247 inst->fValue->accept(this); 248 } else { 249 *fOut << type << "[" << array_typed->fSize << "] " << inst->fAddress->getName(); 250 } 251 } else { 252 *fOut << fTypeManager->generateType(inst->fType, inst->fAddress->getName()); 253 if (inst->fValue) { 254 *fOut << " = "; 255 inst->fValue->accept(this); 256 } 257 } 258 EndLine(); 259 } 260 visit(DeclareFunInst * inst)261 virtual void visit(DeclareFunInst* inst) 262 { 263 // Already generated 264 if (gFunctionSymbolTable.find(inst->fName) != gFunctionSymbolTable.end()) { 265 return; 266 } else { 267 gFunctionSymbolTable[inst->fName] = true; 268 } 269 270 // Dont declare Math library functions, they are already defined in std.math 271 if (gPolyMathLibTable.find(inst->fName) != gPolyMathLibTable.end()) { 272 return; 273 } 274 275 // Defined as macro in the architecture file... 276 if (checkMinMax(inst->fName)) { 277 return; 278 } 279 280 // Prototype arguments 281 if (inst->fType->fAttribute & FunTyped::kInline) { 282 *fOut << "inline "; 283 } 284 285 if (inst->fType->fAttribute & FunTyped::kLocal || inst->fType->fAttribute & FunTyped::kStatic) { 286 *fOut << "static "; 287 } 288 289 // Prototype 290 // Special case: member function `init` renamed to `initialize` so it doesnt conflict with D `.init` property. 291 *fOut << fTypeManager->generateType(inst->fType->fResult, generateFunName(inst->fName == "init" ? "initialize" : inst->fName)); 292 generateFunDefArgs(inst); 293 generateFunDefBody(inst); 294 } 295 generateFunDefBody(DeclareFunInst * inst)296 virtual void generateFunDefBody(DeclareFunInst* inst) 297 { 298 if (inst->fCode->fCode.size() == 0) { 299 *fOut << ") nothrow @nogc;" << endl; // Pure prototype 300 } else { 301 // Function body 302 *fOut << ") nothrow @nogc {"; 303 fTab++; 304 tab(fTab, *fOut); 305 inst->fCode->accept(this); 306 fTab--; 307 back(1, *fOut); 308 *fOut << "}"; 309 tab(fTab, *fOut); 310 } 311 } 312 visit(LoadVarAddressInst * inst)313 virtual void visit(LoadVarAddressInst* inst) 314 { 315 *fOut << "&"; 316 inst->fAddress->accept(this); 317 } 318 visit(BinopInst * inst)319 virtual void visit(BinopInst* inst) 320 { 321 // Special case for 'logical right-shift' 322 if (strcmp(gBinOpTable[inst->fOpcode]->fName, ">>>") == 0) { 323 TypingVisitor typing; 324 inst->fInst1->accept(&typing); 325 if (isInt64Type(typing.fCurType)) { 326 *fOut << "(cast(long)(cast(ulong)"; 327 } else if (isInt32Type(typing.fCurType)) { 328 *fOut << "(cast(int)(cast(uint)"; 329 } else { 330 faustassert(false); 331 } 332 inst->fInst1->accept(this); 333 *fOut << " >> "; 334 inst->fInst2->accept(this); 335 *fOut << "))"; 336 } else { 337 TextInstVisitor::visit(inst); 338 } 339 } 340 visit(::CastInst * inst)341 virtual void visit(::CastInst* inst) 342 { 343 string type = fTypeManager->generateType(inst->fType); 344 *fOut << "cast(" << type << ")"; 345 inst->fInst->accept(this); 346 } 347 348 /* 349 Indexed adresses can actually be values in an array or fields in a struct type 350 */ visit(IndexedAddress * indexed)351 virtual void visit(IndexedAddress* indexed) 352 { 353 indexed->fAddress->accept(this); 354 DeclareStructTypeInst* struct_type = isStructType(indexed->getName()); 355 if (struct_type) { 356 Int32NumInst* field_index = static_cast<Int32NumInst*>(indexed->fIndex); 357 *fOut << "." << struct_type->fType->getName(field_index->fNum); 358 } else { 359 *fOut << "["; 360 indexed->fIndex->accept(this); 361 *fOut << "]"; 362 } 363 } 364 visit(BitcastInst * inst)365 virtual void visit(BitcastInst* inst) { faustassert(false); } 366 visit(FunCallInst * inst)367 virtual void visit(FunCallInst* inst) 368 { 369 string name = gGlobal->getMathFunction(inst->fName); 370 name = (gPolyMathLibTable.find(name) != gPolyMathLibTable.end()) ? gPolyMathLibTable[name] : name; 371 generateFunCall(inst, name); 372 } 373 visit(FloatArrayNumInst * inst)374 virtual void visit(FloatArrayNumInst* inst) 375 { 376 char sep = '['; 377 for (size_t i = 0; i < inst->fNumTable.size(); i++) { 378 *fOut << sep << checkFloat(inst->fNumTable[i]); 379 sep = ','; 380 } 381 *fOut << ']'; 382 } 383 visit(Int32ArrayNumInst * inst)384 virtual void visit(Int32ArrayNumInst* inst) 385 { 386 char sep = '['; 387 for (size_t i = 0; i < inst->fNumTable.size(); i++) { 388 *fOut << sep << inst->fNumTable[i]; 389 sep = ','; 390 } 391 *fOut << ']'; 392 } 393 visit(DoubleArrayNumInst * inst)394 virtual void visit(DoubleArrayNumInst* inst) 395 { 396 char sep = '['; 397 for (size_t i = 0; i < inst->fNumTable.size(); i++) { 398 *fOut << sep << checkDouble(inst->fNumTable[i]); 399 sep = ','; 400 } 401 *fOut << ']'; 402 } 403 cleanup()404 static void cleanup() { gFunctionSymbolTable.clear(); } 405 }; 406 407 #endif 408