1 #include "fpoptimizer/grammar.hh"
2 #include <algorithm>
3 #include <sstream>
4 #include <cmath>
5 #include <set>
6 
7 using namespace FPoptimizer_Grammar;
8 using namespace FUNCTIONPARSERTYPES;
9 
10 namespace
11 {
12     class TestFunction
13     {
14     public:
15         std::string fparser_test;
16         std::string cpp_test;
17     public:
TestFunction()18         TestFunction()
19             : fparser_test(),
20               cpp_test()
21         {
22         }
23 
TestFunction(const std::string & s)24         TestFunction(const std::string& s)
25             : fparser_test(s),
26               cpp_test(s)
27         {
28         }
29 
TestFunction(const std::string & fp,const std::string & cp)30         TestFunction(const std::string& fp, const std::string& cp)
31             : fparser_test(fp),
32               cpp_test(cp)
33         {
34         }
35 
36         struct TestInfo
37         {
38             const char* fp_pref, *cp_pref;
39             const char* fp_sep,  *cp_sep;
40             const char* fp_suff, *cp_suff;
41 
TestInfo__anon3315f6e20111::TestFunction::TestInfo42             explicit TestInfo(OPCODE opcode)
43             {
44                 fp_pref = cp_pref = "((";
45                 fp_sep = cp_sep = ",";
46                 fp_suff = cp_suff = "))";
47                 switch(opcode)
48                 {
49                     case cMul: fp_sep = cp_sep = ")*("; return;
50                     case cAdd: fp_sep = cp_sep = ")+("; return;
51                     case cSub: fp_sep = cp_sep = ")-("; return;
52                     case cDiv: fp_sep = cp_sep = ")/("; return;
53                     case cAnd: fp_sep = cp_sep = ")&("; return;
54                     case cOr:  fp_sep = cp_sep = ")|("; return;
55                     case cEqual:  fp_sep = ")=("; cp_sep = ")==("; return;
56                     case cNEqual:  fp_sep = cp_sep = ")!=("; return;
57                     case cLess:  fp_sep = cp_sep = ")<("; return;
58                     case cLessOrEq:  fp_sep = cp_sep = ")<=("; return;
59                     case cGreater:  fp_sep = cp_sep = ")>("; return;
60                     case cGreaterOrEq:  fp_sep = cp_sep = ")>=("; return;
61                     case cMod: fp_sep = ")%("; cp_pref = "(fmod("; cp_sep = ","; return;
62                     case cPow: fp_sep = ")^("; cp_pref =  "(pow("; cp_sep = ","; return;
63                     case cNeg: fp_pref = cp_pref =  "(-("; return;
64                     case cNot: fp_pref = cp_pref =  "(!("; return;
65                     case cNotNot: fp_pref = cp_pref =  "(!!("; return;
66                     case cInv: fp_pref = cp_pref = "(1/("; return;
67                     case cCot: fp_pref = "cot"; cp_pref = "(1/tan("; return;
68                     case cCsc: fp_pref = "csc"; cp_pref = "(1/sin("; return;
69                     case cSec: fp_pref = "sec"; cp_pref = "(1/cos("; return;
70                     case cInt: fp_pref = "int"; cp_pref = "(floor(0.5+("; return;
71                     #define op(opcode, fpcode, cpcode) \
72                         case opcode: \
73                             fp_pref = #fpcode "("; \
74                             cp_pref = #cpcode "("; \
75                             fp_suff = cp_suff = ")"; return
76                     op(cAbs,abs,abs);
77                     op(cAcos,acos,acos);
78                     op(cAcosh,acosh,fp_acosh);
79                     op(cAsin,asin,asin);
80                     op(cAsinh,asinh,fp_asinh);
81                     op(cAtan,atan,atan);
82                     op(cAtan2,atan2,atan2);
83                     op(cAtanh,atanh,fp_atanh);
84                     op(cCeil,ceil,ceil);
85                     op(cCos,cos,cos);
86                     op(cCosh,cosh,cosh);
87                     case cIf:
88                         fp_pref = "if((";
89                         return;
90                     op(cExp,exp,exp);
91                     op(cExp2,exp2,exp2);
92                     op(cFloor,floor,floor);
93                     op(cLog,log,log);
94                     op(cLog10,log10,log10);
95                     op(cLog2,log2,log2);
96                     op(cMax,max,max);
97                     op(cMin,min,min);
98                     op(cSin,sin,sin);
99                     op(cSinh,sinh,sinh);
100                     op(cSqrt,sqrt,sqrt);
101                     op(cTan,tan,tan);
102                     op(cTanh,tanh,tanh);
103                     op(cTrunc,trunc,trunc);
104                     #undef op
105                     case cImmed: return; // does not occur
106                     case cJump: return; // does not occur
107                     case cDup: return; // does not occur
108                     case cFetch: return; // does not occur
109                     case cPopNMov: return; // does not occur
110                     case cSqr: return; // does not occur
111                     case cRDiv: return; // does not occur
112                     case cRSub: return; // does not occur
113                     case cRSqrt: return; // does not occur (?)
114                     case cNop: return; // does not occur
115                     case VarBegin: return; // does not occur
116                 }
117             }
118         };
119     };
120 
121     class TestGenerator
122     {
123         std::map<unsigned, std::string> holders;
124     public:
CreateTest(const ParamSpec_ParamHolder & holder)125         TestFunction CreateTest(const ParamSpec_ParamHolder& holder)
126         {
127             std::map<unsigned, std::string>::const_iterator i = holders.find(holder.index);
128             if(i != holders.end()) return TestFunction( i->second );
129             std::string result;
130             if(holder.constraints & Constness_Const)
131             {
132             get_const_instead:;
133                 double value = 4.91;
134                 switch(ImmedConstraint_Value( holder.constraints & ValueMask) )
135                 {
136                     case Value_IsInteger: case Value_EvenInt:
137                         value = std::floor(value);
138                         break;
139                     case Value_OddInt:
140                         value = 3.0;
141                         break;
142                     case Value_Logical:
143                         value = 1.0;
144                     default: break;
145                 }
146                 if(holder.constraints & Oneness_One)
147                     value = 1.0;
148                 if(holder.constraints & Sign_Negative)
149                     value = -value;
150                 std::ostringstream r;
151                 r.precision(15);
152                 r << value;
153                 result = r.str();
154             }
155             else
156             {
157                 if(holder.constraints & OnenessMask) goto get_const_instead;
158                 static const char* const predefined[] =
159                 { "x", "y", "z", "sinh(x)" };
160                 result = predefined[(holder.index+4-2) % 4];
161                 // any expression evaluating to the given constraints
162                 switch(ImmedConstraint_Value( holder.constraints & ValueMask) )
163                 {
164                     case Value_IsInteger:
165                         result = "floor(" + result + ")";
166                         break;
167                     case Value_OddInt:
168                     case Value_EvenInt:
169                     case Value_NonInteger:
170                         goto get_const_instead;
171                     case Value_Logical:
172                         result = "(" + result + " < 3)";
173                         break;
174                 }
175                 switch(ImmedConstraint_Sign( holder.constraints & SignMask) )
176                 {
177                     case Sign_Positive:
178                         result = "abs(" + result + ")";
179                         break;
180                     case Sign_Negative:
181                         result = "(-cosh(" + result + "))";
182                         break;
183                 }
184             }
185             return TestFunction( holders[holder.index] = result );
186         }
187 
CreateTest(const ParamSpec_NumConstant & n)188         TestFunction CreateTest(const ParamSpec_NumConstant& n)
189         {
190             std::ostringstream s;
191             s.precision(15);
192             s << n.constvalue;
193             return TestFunction( s.str() );
194         }
195 
CreateTest(const ParamSpec_SubFunctionData & tree,unsigned constraints)196         TestFunction CreateTest(const ParamSpec_SubFunctionData& tree, unsigned constraints)
197         {
198             TestFunction::TestInfo info ( tree.subfunc_opcode );
199             std::vector<ParamSpec> params;
200             for(unsigned p=0; p<tree.param_count; ++p)
201                 params.push_back( ParamSpec_Extract(tree.param_list, p) );
202 
203             std::vector<TestFunction> result_params;
204             for(unsigned p=0; p<tree.param_count; ++p)
205             {
206                 const ParamSpec& param = params[p];
207                 switch(param.first)
208                 {
209                     case NumConstant:
210                     {
211                         const ParamSpec_NumConstant& n = *(const ParamSpec_NumConstant*)param.second;
212                         result_params.push_back( CreateTest( n ) );
213                         break;
214                     }
215                     case ParamHolder:
216                     {
217                         const ParamSpec_ParamHolder& n = *(const ParamSpec_ParamHolder*)param.second;
218                         result_params.push_back( CreateTest( n ) );
219                         break;
220                     }
221                     case SubFunction:
222                     {
223                         const ParamSpec_SubFunction& n = *(const ParamSpec_SubFunction*)param.second;
224                         result_params.push_back( CreateTest( n.data, n.constraints ) );
225                         break;
226                     }
227                 }
228             }
229             if(tree.restholder_index != 0)
230             {
231                 // add two random params
232                 if(constraints & Sign_Positive)
233                     result_params.push_back( TestFunction( "abs(q)" ) );
234                 else
235                 {
236                     result_params.push_back( TestFunction( "q" ) );
237                     result_params.push_back( TestFunction( "w" ) );
238                 }
239             }
240 
241             if(tree.match_type != PositionalParams)
242                 std::random_shuffle( result_params.begin(), result_params.end() );
243             TestFunction result;
244             result.fparser_test += info.fp_pref;
245             result.cpp_test     += info.cp_pref;
246             for(unsigned p=0; p<result_params.size(); ++p)
247             {
248                 if(tree.subfunc_opcode == cIf)
249                 {
250                     static const char* const fp_list[3] = { "", "),(", "),(" };
251                     static const char* const cp_list[3] = { "", ")?(", "):(" };
252                     info.fp_sep = fp_list[p];
253                     info.cp_sep = cp_list[p];
254                 }
255                 if(p > 0)
256                 {
257                     result.fparser_test += info.fp_sep;
258                     result.cpp_test     += info.cp_sep;
259                 }
260                 result.fparser_test += result_params[p].fparser_test;
261                 result.cpp_test     += result_params[p].cpp_test;
262             }
263             result.fparser_test += info.fp_suff;
264             result.cpp_test     += info.cp_suff;
265             return result;
266         }
267     };
268 }
269 
270 static std::set<const Rule*> Rules;
271 
FindRules(const Grammar & g)272 static void FindRules(const Grammar& g)
273 {
274     for(unsigned a=0; a<g.rule_count; ++a)
275         Rules.insert(&grammar_rules[g.rule_list[a]]);
276 }
277 
main()278 int main()
279 {
280     FindRules(grammar_optimize_round1);
281     FindRules(grammar_optimize_round2);
282     FindRules(grammar_optimize_round3);
283 
284     for(std::set<const Rule*>::const_iterator
285         i = Rules.begin();
286         i != Rules.end();
287         ++i)
288     {
289         const Rule& r = **i;
290 
291         if(r.logical_context)
292         {
293             // Skipping logical context rule
294             // FIXME: Instead, devise a test that utilizes logical context
295             continue;
296         }
297 
298         ParamSpec_SubFunctionData in_func = r.match_tree;
299         if(r.ruletype == ReplaceParams
300         && (in_func.subfunc_opcode == cAdd
301         || in_func.subfunc_opcode == cMul
302         || in_func.subfunc_opcode == cAnd
303         || in_func.subfunc_opcode == cOr))
304         {
305             in_func.restholder_index = 7;
306         }
307         TestGenerator gen;
308         TestFunction test = gen.CreateTest(in_func, 0);
309 
310         TestFunction repl;
311         if(r.ruletype == ReplaceParams)
312         {
313             ParamSpec_SubFunctionData repl_func =
314             { r.repl_param_count, r.repl_param_list,
315               r.match_tree.subfunc_opcode,
316               PositionalParams, in_func.restholder_index };
317             repl = gen.CreateTest(repl_func, 0);
318         }
319         else
320         {
321             ParamSpec p = ParamSpec_Extract(r.repl_param_list, 0);
322             if(p.first == SubFunction)
323                 repl = gen.CreateTest(*(const ParamSpec_SubFunctionData*)p.second, 0);
324             else if(p.first == ParamHolder)
325                 repl = gen.CreateTest(*(const ParamSpec_ParamHolder*)p.second);
326             else
327                 repl = gen.CreateTest(*(const ParamSpec_NumConstant*)p.second);
328         }
329         ParamSpec_SubFunction tmp = {r.match_tree,0,0};
330 
331         std::cout << "echo '---------NEW TEST-----------'\n";
332         std::cout << "echo 'Rule: ";
333         FPoptimizer_Grammar::DumpParam( ParamSpec(SubFunction, (const void*) &tmp) );
334         std::cout << "'\n";
335         if(r.ruletype == ProduceNewTree)
336         {
337             std::cout << "echo '  ->  ";
338             FPoptimizer_Grammar::DumpParam(
339                                         ParamSpec_Extract(r.repl_param_list, 0) );
340             std::cout << "'\n";
341         }
342         else
343         {
344             std::cout << "echo '  :   ";
345             FPoptimizer_Grammar::DumpParams(
346                                         r.repl_param_list, r.repl_param_count );
347             std::cout << "'\n";
348         }
349 
350         std::cout << "./functioninfo '" << test.fparser_test
351                   << "' '" << repl.fparser_test << "'\n";
352         /*
353         std::cout << test.fparser_test <<
354              "\n" << test.cpp_test <<
355              "\n\n";
356         */
357     }
358 }
359