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 #include <math.h> 23 24 #include "Text.hh" 25 #include "floats.hh" 26 #include "ppsig.hh" 27 #include "sigtyperules.hh" 28 #include "xtended.hh" 29 30 /******************************************************************************************** 31 32 FTZ is a special primitive injected in recursive signals when the -ftz option is on. 33 The injected code allows to flush to zero denormalized number. This option should be used only 34 when it is not available on the CPU. 35 36 *********************************************************************************************/ 37 38 const char* FTZPattern[4][3] = { 39 {"???", "???", "???"}, // not a float 40 {"$0", "((fabsf($0)> FLT_MIN) ? $0 : 0.0f)", "((*(int*)&$0) & 0x7F800000) ? $0 : 0.0f"}, // float (1) 41 {"$0", "((fabs($0)> DBL_MIN) ? $0 : 0.0 )", "((*(long int*)&$0) & 0x7FF0000000000000) ? $0 : 0.0"}, // double (2) 42 {"$0", "((fabsl($0)> LDBL_MIN) ? $0 : 0.0L)", "((fabsl($0)>LDBL_MIN) ? $0 : 0.0L)"} // quad (3) 43 }; 44 45 class FtzPrim : public xtended { 46 private: 47 static int freshnum; // counter for fTempFTZxxx fresh variables 48 49 public: FtzPrim()50 FtzPrim() : xtended("ftz") {} 51 arity()52 virtual unsigned int arity() { return 1; } 53 needCache()54 virtual bool needCache() { return true; } 55 infereSigType(const vector<Type> & types)56 virtual Type infereSigType(const vector<Type>& types) 57 { 58 faustassert(types.size() == arity()); 59 return types[0]; 60 } 61 infereSigOrder(const vector<int> & args)62 virtual int infereSigOrder(const vector<int>& args) 63 { 64 faustassert(args.size() == arity()); 65 return args[0]; 66 } 67 computeSigOutput(const vector<Tree> & args)68 virtual Tree computeSigOutput(const vector<Tree>& args) 69 { 70 int i; 71 double r; 72 73 faustassert(args.size() == arity()); 74 75 if (isSigInt(args[0], &i)) { 76 return args[0]; 77 } else if (isSigReal(args[0], &r)) { 78 return args[0]; 79 } else { 80 return tree(symbol(), args[0]); 81 } 82 } 83 generateCode(CodeContainer * container,const list<ValueInst * > & args,::Type result,vector<::Type> const & types)84 virtual ValueInst* generateCode(CodeContainer* container, const list<ValueInst*>& args, ::Type result, 85 vector<::Type> const& types) 86 { 87 faustassert(args.size() == arity()); 88 faustassert(types.size() == arity()); 89 90 Type t = infereSigType(types); 91 if ((t->nature() == kReal) && (gGlobal->gFTZMode > 0)) { 92 switch (gGlobal->gFTZMode) { 93 case 1: { 94 // "fabs" function has to be declared 95 list<NamedTyped*> args_types; 96 args_types.push_back(InstBuilder::genNamedTyped("dummy", InstBuilder::genBasicTyped(itfloat()))); 97 FunTyped* fun_type = InstBuilder::genFunTyped(args_types, InstBuilder::genBasicTyped(itfloat())); 98 container->pushGlobalDeclare(InstBuilder::genDeclareFunInst(subst("fabs$0", isuffix()), fun_type)); 99 100 // we need to create a temporary variable to store the expression 101 string vname = gGlobal->getFreshID("fTempFTZ"); 102 container->addIncludeFile("<float.h>"); 103 container->pushComputeDSPMethod( 104 InstBuilder::genDecStackVar(vname, InstBuilder::genBasicTyped(itfloat()), *args.begin())); 105 ValueInst* real_min; 106 if (gGlobal->gFloatSize == 1) { 107 real_min = InstBuilder::genFloatNumInst(inummin()); 108 } else { 109 real_min = InstBuilder::genDoubleNumInst(inummin()); 110 } 111 112 list<ValueInst*> args_value; 113 args_value.push_back(InstBuilder::genLoadStackVar(vname)); 114 return InstBuilder::genSelect2Inst( 115 InstBuilder::genGreaterThan(InstBuilder::genFunCallInst(subst("fabs$0", isuffix()), args_value), 116 real_min), 117 InstBuilder::genLoadStackVar(vname), InstBuilder::genTypedZero(itfloat())); 118 } break; 119 120 case 2: { 121 // Bitcast based solution 122 string vname = gGlobal->getFreshID("fTempFTZ"); 123 container->pushComputeDSPMethod( 124 InstBuilder::genDecStackVar(vname, InstBuilder::genBasicTyped(itfloat()), *args.begin())); 125 switch (gGlobal->gFloatSize) { 126 case 1: 127 return InstBuilder::genSelect2Inst( 128 InstBuilder::genAnd(InstBuilder::genBitcastInst(InstBuilder::genLoadStackVar(vname), 129 InstBuilder::genInt32Typed()), 130 InstBuilder::genInt32NumInst(0x7F800000)), 131 InstBuilder::genLoadStackVar(vname), InstBuilder::genTypedZero(itfloat())); 132 case 2: 133 return InstBuilder::genSelect2Inst( 134 InstBuilder::genAnd( 135 InstBuilder::genBitcastInst(InstBuilder::genLoadStackVar(vname), 136 InstBuilder::genBasicTyped(Typed::kInt64)), 137 InstBuilder::genInt64NumInst(0x7FF0000000000000)), 138 InstBuilder::genLoadStackVar(vname), InstBuilder::genTypedZero(itfloat())); 139 default: 140 faustassert(false); 141 return *args.begin(); 142 } 143 } break; 144 145 default: 146 faustassert(false); 147 return *args.begin(); 148 } 149 150 } else { 151 // No ftz code for integer signals 152 return *args.begin(); 153 } 154 } 155 old_generateCode(Klass * klass,const vector<string> & args,const vector<::Type> & types)156 virtual string old_generateCode(Klass* klass, const vector<string>& args, const vector<::Type>& types) 157 { 158 faustassert(args.size() == arity()); 159 faustassert(types.size() == arity()); 160 161 Type t = infereSigType(types); 162 if ((t->nature() == kReal) && (gGlobal->gFTZMode > 0)) { 163 // we need to create a temporary variable to store the expression 164 string ctype = ifloat(); 165 string vname = subst("fTempFTZ$0", T(++freshnum)); 166 klass->addIncludeFile("<float.h>"); 167 klass->addExecCode(Statement("", subst("$0 $1 = $2;", ctype, vname, args[0]))); 168 return subst(FTZPattern[gGlobal->gFloatSize][gGlobal->gFTZMode], vname); 169 } else { 170 // No ftz code for integer signals 171 return args[0]; 172 } 173 } 174 generateLateq(Lateq * lateq,const vector<string> & args,const vector<::Type> & types)175 virtual string generateLateq(Lateq* lateq, const vector<string>& args, const vector<::Type>& types) 176 { 177 faustassert(args.size() == arity()); 178 faustassert(types.size() == arity()); 179 return args[0]; 180 } 181 }; 182 183 int FtzPrim::freshnum = 0; 184