Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
calc.cpp
Go to the documentation of this file.
1/*
2 @author herumi
3
4 tiny calculator
5 This program generates a function to calc the value of
6 polynomial given by user in run-time.
7 use boost::spirit::classic
8 see calc2.cpp for new version of boost::spirit
9*/
10#include <stdio.h>
11#include <sstream>
12#include <map>
13#define XBYAK_NO_OP_NAMES
14#include "xbyak/xbyak.h"
15#ifdef _MSC_VER
16 #pragma warning(disable : 4127) // for boost(constant condition)
17 #pragma warning(disable : 4512) // for boost
18#endif
19#include <boost/spirit/include/classic_file_iterator.hpp>
20#include <boost/spirit/include/classic_core.hpp>
21#include <boost/bind.hpp>
22
26
27/*
28 JIT assemble of given polynomial for VC or gcc
29*/
31public:
32 typedef std::map<std::string, int> Map;
33private:
34 enum {
35 MAX_CONST_NUM = 32
36 };
37 double constTbl_[MAX_CONST_NUM];
38 size_t constTblPos_;
39 int regIdx_;
40 Map varMap_; // map var name to index
41#ifdef XBYAK32
42 const Xbyak::Reg32& valTbl_;
43 const Xbyak::Reg32& tbl_;
44#else
45 const Xbyak::Reg64& valTbl_;
46 const Xbyak::Reg64& tbl_;
47#endif
48public:
49 /*
50 @param y [out] the value of f(var)
51 @param var [in] table of input variables
52 func(double *y, const double var[]);
53 @note func does not return double to avoid difference of compiler
54 */
55 FuncGen(const std::vector<std::string>& varTbl)
56 : constTblPos_(0)
57 , regIdx_(-1)
58#ifdef XBYAK32
59 , valTbl_(eax)
60 , tbl_(edx)
61#elif defined(XBYAK64_WIN)
62 , valTbl_(rcx)
63 , tbl_(rdx)
64#else
65 , valTbl_(rdi)
66 , tbl_(rsi)
67#endif
68 {
69#ifdef XBYAK32
70 mov(valTbl_, ptr[esp+8]); // eax == varTbl
71 mov(tbl_, (size_t)constTbl_);
72#else
73#ifdef XBYAK64_WIN
74 movaps(ptr [rsp + 8], xm6); // save xm6, xm7
75 movaps(ptr [rsp + 8 + 16], xm7);
76#endif
77 mov(tbl_, (size_t)constTbl_);
78#endif
79 for (int i = 0, n = static_cast<int>(varTbl.size()); i < n; i++) {
80 varMap_[varTbl[i]] = i;
81 }
82 }
83 // use edx
84 void genPush(double n)
85 {
86 if (constTblPos_ >= MAX_CONST_NUM) throw;
87 constTbl_[constTblPos_] = n;
88 if (regIdx_ == 7) throw;
89 movsd(Xbyak::Xmm(++regIdx_), ptr[tbl_ + (int)(constTblPos_ * sizeof(double))]);
90 constTblPos_++;
91 }
92 // use eax
93 void genVal(const char *begin, const char *end)
94 {
95 std::string var(begin, end);
96 if (varMap_.find(var) == varMap_.end()) throw UNDEFINED_VARIABLE;
97 if (regIdx_ == 7) throw;
98 movsd(Xbyak::Xmm(++regIdx_), ptr[valTbl_ + varMap_[var] * sizeof(double)]);
99 }
100 void genAdd(const char*, const char*)
101 {
102 addsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
103 }
104 void genSub(const char*, const char*)
105 {
106 subsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
107 }
108 void genMul(const char*, const char*)
109 {
110 mulsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
111 }
112 void genDiv(const char*, const char*)
113 {
114 divsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
115 }
116 void complete()
117 {
118#ifdef XBYAK32
119 mov(eax, ptr [esp + 4]); // eax = valTbl
120 movsd(ptr [eax], xm0);
121#else
122#ifdef XBYAK64_WIN
123 movaps(xm6, ptr [rsp + 8]);
124 movaps(xm7, ptr [rsp + 8 + 16]);
125#endif
126#endif
127 ret();
128 }
129};
130
131struct Grammar : public boost::spirit::classic::grammar<Grammar> {
134 template<typename ScannerT>
135 struct definition {
136 boost::spirit::classic::rule<ScannerT> poly0, poly1, poly2, var;
137
138 definition(const Grammar& self)
139 {
140 using namespace boost;
141 using namespace boost::spirit::classic;
142
143 poly0 = poly1 >> *(('+' >> poly1)[bind(&FuncGen::genAdd, ref(self.f_), _1, _2)]
144 | ('-' >> poly1)[bind(&FuncGen::genSub, ref(self.f_), _1, _2)]);
145 poly1 = poly2 >> *(('*' >> poly2)[bind(&FuncGen::genMul, ref(self.f_), _1, _2)]
146 | ('/' >> poly2)[bind(&FuncGen::genDiv, ref(self.f_), _1, _2)]);
147 var = (+alpha_p)[bind(&FuncGen::genVal, ref(self.f_), _1, _2)];
148 poly2 = real_p[bind(&FuncGen::genPush, ref(self.f_), _1)]
149 | var
150 | '(' >> poly0 >> ')';
151 }
152 const boost::spirit::classic::rule<ScannerT>& start() const { return poly0; }
153 };
154};
155
156void put(const std::vector<double>& x)
157{
158 printf("%f", x[0]);
159 for (size_t i = 1, n = x.size(); i < n; i++) {
160 printf(", %f", x[i]);
161 }
162}
163
164int main(int argc, char *argv[])
165{
166 if (argc <= 2) {
167 fprintf(stderr, "calc \"var1 var2 ...\" \"function of var\"\n");
168 fprintf(stderr, "eg. calc x \"x*x\"\n");
169 fprintf(stderr, "eg. calc \"x y z\" \"x*x + y - z\"\n");
170 return 1;
171 }
172 const char *poly = argv[2];
173 try {
174 std::vector<std::string> varTbl;
175
176 // get varTbl from argv[1]
177 {
178 std::istringstream is(argv[1]);
179 int i = 0;
180 printf("varTbl = { ");
181 while (is) {
182 std::string var;
183 is >> var;
184 if (var.empty()) break;
185 printf("%s:%d, ", var.c_str(), i);
186 varTbl.push_back(var);
187 i++;
188 }
189 printf("}\n");
190 }
191 FuncGen funcGen(varTbl);
192 Grammar calc(funcGen);
193 boost::spirit::classic::parse_info<> r = parse(poly, calc, boost::spirit::classic::space_p);
194 if (!r.full) {
195 printf("err poly=%s\n", poly);
196 return 1;
197 }
198 funcGen.complete();
199 std::vector<double> valTbl;
200 valTbl.resize(varTbl.size());
201#ifdef XBYAK32
202 puts("32bit mode");
203 void (*func)(double *ret, const double *valTbl) = funcGen.getCode<void (*)(double *, const double*)>();
204#else
205 puts("64bit mode");
206 double (*func)(const double *valTbl) = funcGen.getCode<double (*)(const double*)>();
207#endif
208 for (int i = 0; i < 10; i++) {
209 for (size_t j = 0, n = valTbl.size(); j < n; j++) {
210 valTbl[j] = rand() % 7;
211 }
212 double y;
213#ifdef XBYAK32
214 func(&y, &valTbl[0]);
215#else
216 y = func(&valTbl[0]);
217#endif
218 printf("f("); put(valTbl); printf(")=%f\n", y);
219 }
220 } catch (std::exception& e) {
221 printf("ERR:%s\n", e.what());
222 } catch (Error err) {
223 printf("ERR:%d\n", err);
224 } catch (...) {
225 printf("unknown error\n");
226 }
227
228 return 0;
229}
const mie::Vuint & r
Definition bn.cpp:28
Error
Definition calc.cpp:23
@ UNDEFINED_VARIABLE
Definition calc.cpp:24
void genDiv(const char *, const char *)
Definition calc.cpp:112
void genPush(double n)
Definition calc.cpp:84
FuncGen(const std::vector< std::string > &varTbl)
Definition calc.cpp:55
void genMul(const char *, const char *)
Definition calc.cpp:108
void genAdd(const char *, const char *)
Definition calc.cpp:100
void genSub(const char *, const char *)
Definition calc.cpp:104
std::map< std::string, int > Map
Definition calc.cpp:32
void complete()
Definition calc.cpp:116
void genVal(const char *begin, const char *end)
Definition calc.cpp:93
const uint8 * getCode() const
Definition xbyak.h:905
const Xmm & xm6
Definition xbyak.h:2084
void subsd(const Xmm &xmm, const Operand &op)
Definition xbyak.h:750
const Xmm & xm7
Definition xbyak.h:2084
const Reg32 esp
Definition xbyak.h:2087
const Reg32 eax
Definition xbyak.h:2087
const Xmm & xm0
Definition xbyak.h:2084
void addsd(const Xmm &xmm, const Operand &op)
Definition xbyak.h:10
void movaps(const Address &addr, const Xmm &xmm)
Definition xbyak.h:450
const Reg32 edx
Definition xbyak.h:2087
void mov(const Operand &reg1, const Operand &reg2)
Definition xbyak.h:2210
void mulsd(const Xmm &xmm, const Operand &op)
Definition xbyak.h:500
void divsd(const Xmm &xmm, const Operand &op)
Definition xbyak.h:166
const AddressFrame ptr
Definition xbyak.h:2090
void put()
Definition gen_code.cpp:234
char ** argv
boost::spirit::classic::rule< ScannerT > poly0
Definition calc.cpp:136
boost::spirit::classic::rule< ScannerT > poly1
Definition calc.cpp:136
definition(const Grammar &self)
Definition calc.cpp:138
const boost::spirit::classic::rule< ScannerT > & start() const
Definition calc.cpp:152
boost::spirit::classic::rule< ScannerT > var
Definition calc.cpp:136
boost::spirit::classic::rule< ScannerT > poly2
Definition calc.cpp:136
FuncGen & f_
Definition calc.cpp:132
Grammar(FuncGen &f)
Definition calc.cpp:133
Xbyak ; JIT assembler for x86(IA32)/x64 by C++.
#define XBYAK32
Definition xbyak.h:88
CK_RV ret
uint16_t j