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