Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
calc2.cpp
Go to the documentation of this file.
1/*
2 @author herumi
3
4 tiny calculator 2
5 This program generates a function to calc the value of
6 polynomial given by user in run-time.
7 use boost::spirit::qi
8*/
9#ifdef _WIN32
10 #pragma warning(disable : 4127) // for boost(constant condition)
11 #pragma warning(disable : 4512) // for boost
12 #pragma warning(disable : 4819)
13#endif
14#include <boost/config/warning_disable.hpp>
15#include <boost/spirit/include/qi.hpp>
16#include <boost/spirit/include/phoenix_core.hpp>
17#include <boost/spirit/include/phoenix_container.hpp>
18#include <boost/spirit/include/phoenix_bind.hpp>
19#include <boost/timer.hpp>
20
21#include <stdio.h>
22#include <assert.h>
23#include <string>
24#include <vector>
25#define XBYAK_NO_OP_NAMES
26#include "xbyak/xbyak.h"
27
37
38struct Code {
40 double val_;
42 : op_(op)
43 , val_(0)
44 {
45 }
46 Code(double val)
47 : op_(OpImm)
48 , val_(val)
49 {
50 }
51};
52
53typedef std::vector<Code> CodeSet;
54
55struct Vm {
57 double operator()(double x) const
58 {
59 const size_t maxStack = 16;
60 double stack[maxStack];
61 double *p = stack;
62 CodeSet::const_iterator pc = code_.begin();
63
64 while (pc != code_.end()) {
65 switch (pc->op_) {
66 case OpVarX:
67 *p++ = x;
68 break;
69 case OpImm:
70 *p++ = pc->val_;
71 break;
72 case OpNeg:
73 p[-1] = -p[-1];
74 break;
75 case OpAdd:
76 --p;
77 p[-1] += p[0];
78 break;
79 case OpSub:
80 --p;
81 p[-1] -= p[0];
82 break;
83 case OpMul:
84 --p;
85 p[-1] *= p[0];
86 break;
87 case OpDiv:
88 --p;
89 p[-1] /= p[0];
90 break;
91 }
92 ++pc;
93 assert(p < stack + maxStack);
94 }
95 return p[-1];
96 }
97};
98
99class Jit : public Xbyak::CodeGenerator {
100private:
101 enum {
102 MAX_CONST_NUM = 32
103 };
104 MIE_ALIGN(16) double constTbl_[MAX_CONST_NUM];
105 Xbyak::uint64 negConst_;
106 size_t constTblPos_;
107#ifdef XBYAK32
108 const Xbyak::Reg32& varTbl_;
109 const Xbyak::Reg32& tbl_;
110#else
111 const Xbyak::Reg64& tbl_;
112#endif
113 int regIdx_;
114public:
115 /*
116 double jit(double x);
117 @note 32bit: x : [esp+4], return fp0
118 64bit: x [rcx](win), xmm0(gcc), return xmm0
119 */
121 : negConst_(Xbyak::uint64(1) << 63)
122 , constTblPos_(0)
123#ifdef XBYAK32
124 , varTbl_(eax)
125 , tbl_(edx)
126#elif defined(XBYAK64_WIN)
127 , tbl_(rcx)
128#else
129 , tbl_(rdi)
130#endif
131 , regIdx_(-1)
132 {
133#ifdef XBYAK32
134 lea(varTbl_, ptr [esp+4]);
135#else
136#ifdef XBYAK64_WIN
137 movaps(ptr [rsp + 8], xm6); // save xm6, xm7
138 movaps(ptr [rsp + 8 + 16], xm7);
139#endif
140 movaps(xm7, xm0); // save xm0
141#endif
142 mov(tbl_, (size_t)constTbl_);
143 }
144 void genPush(double n)
145 {
146 if (constTblPos_ >= MAX_CONST_NUM) throw;
147 constTbl_[constTblPos_] = n;
148 if (regIdx_ == 7) throw;
149 movsd(Xbyak::Xmm(++regIdx_), ptr[tbl_ + constTblPos_ * sizeof(double)]);
150 constTblPos_++;
151 }
152 void genVarX()
153 {
154#ifdef XBYAK32
155 if (regIdx_ == 7) throw;
156 movsd(Xbyak::Xmm(++regIdx_), ptr[varTbl_]);
157#else
158 if (regIdx_ == 6) throw;
159 movsd(Xbyak::Xmm(++regIdx_), xm7);
160#endif
161 }
162 void genAdd()
163 {
164 addsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
165 }
166 void genSub()
167 {
168 subsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
169 }
170 void genMul()
171 {
172 mulsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
173 }
174 void genDiv()
175 {
176 divsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--;
177 }
178 void genNeg()
179 {
180 xorpd(Xbyak::Xmm(regIdx_), ptr [tbl_ + MAX_CONST_NUM * sizeof(double)]);
181 }
182 void complete()
183 {
184#ifdef XBYAK32
185 sub(esp, 8);
186 movsd(ptr [esp], xm0);
187 fld(qword [esp]);
188 add(esp, 8);
189#else
190#ifdef XBYAK64_WIN
191 movaps(xm6, ptr [rsp + 8]);
192 movaps(xm7, ptr [rsp + 8 + 16]);
193#endif
194#endif
195 ret();
196 }
197};
198
199template<typename Iterator>
200struct Parser : boost::spirit::qi::grammar<Iterator, boost::spirit::ascii::space_type> {
201 boost::spirit::qi::rule<Iterator, boost::spirit::ascii::space_type> expression, term, factor;
204 : Parser::base_type(expression)
205 , code_(code)
206 {
207 namespace qi = boost::spirit::qi;
208 using namespace qi::labels;
209
210 using boost::phoenix::ref;
211 using boost::phoenix::push_back;
212
213 expression = term >> *(('+' > term[push_back(ref(code_), OpAdd)])
214 | ('-' > term[push_back(ref(code_), OpSub)]));
215
216 term = factor >> *(('*' > factor[push_back(ref(code_), OpMul)])
217 | ('/' > factor[push_back(ref(code_), OpDiv)]));
218
219 factor = qi::double_[push_back(ref(code_), _1)]
220 | qi::lit('x')[push_back(ref(code_), OpVarX)]
221 | ('(' > expression > ')')
222 | ('-' > factor[push_back(ref(code_), OpNeg)])
223 | ('+' > factor);
224 }
225};
226
227template<typename Iterator>
228struct ParserJit : boost::spirit::qi::grammar<Iterator, boost::spirit::ascii::space_type> {
229 boost::spirit::qi::rule<Iterator, boost::spirit::ascii::space_type> expression, term, factor;
232 : ParserJit::base_type(expression)
233 {
234 namespace qi = boost::spirit::qi;
235 using namespace qi::labels;
236
237 using boost::phoenix::ref;
238 using boost::phoenix::push_back;
239 using boost::phoenix::bind;
240
241 expression = term >> *(('+' > term[bind(&Jit::genAdd, ref(code_))])
242 | ('-' > term[bind(&Jit::genSub, ref(code_))]));
243
244 term = factor >> *(('*' > factor[bind(&Jit::genMul, ref(code_))])
245 | ('/' > factor[bind(&Jit::genDiv, ref(code_))]));
246
247 factor = qi::double_[bind(&Jit::genPush, ref(code_), _1)]
248 | qi::lit('x')[bind(&Jit::genVarX, ref(code_))]
249 | ('(' > expression > ')')
250 | ('-' > factor[bind(&Jit::genNeg, ref(code_))])
251 | ('+' > factor);
252 }
253};
254
255template<class Func>
256void Test(const char *msg, const Func& f)
257{
258 printf("%s:", msg);
259 boost::timer t;
260 double sum = 0;
261 for (double x = 0; x < 1000; x += 0.0001) {
262 sum += f(x);
263 }
264 printf("sum=%f, %fsec\n", sum, t.elapsed());
265}
266
267int main(int argc, char *argv[])
268{
269 if (argc < 2) {
270 fprintf(stderr, "input formula\n");
271 return 1;
272 }
273 const std::string str(argv[1]);
274
275 try {
276 Vm vm;
279
280 const std::string::const_iterator end = str.end();
281
282 std::string::const_iterator i = str.begin();
283 if (!phrase_parse(i, end, parser, boost::spirit::ascii::space) || i != end) {
284 puts("err 1");
285 return 1;
286 }
287 printf("ret=%f\n", vm(2.3));
288
289 i = str.begin();
290 if (!phrase_parse(i, end, parserJit, boost::spirit::ascii::space) || i != end) {
291 puts("err 2");
292 return 1;
293 }
294 parserJit.code_.complete();
295 double (*jit)(double) = parserJit.code_.getCode<double (*)(double)>();
296
297 Test("VM ", vm);
298 Test("JIT", jit);
299 } catch (...) {
300 fprintf(stderr, "err\n");
301 }
302}
const mie::Vuint & p
Definition bn.cpp:27
Operand
Definition calc2.cpp:28
@ OpVarX
Definition calc2.cpp:35
@ OpMul
Definition calc2.cpp:31
@ OpNeg
Definition calc2.cpp:33
@ OpSub
Definition calc2.cpp:30
@ OpDiv
Definition calc2.cpp:32
@ OpImm
Definition calc2.cpp:34
@ OpAdd
Definition calc2.cpp:29
std::vector< Code > CodeSet
Definition calc2.cpp:53
void Test(const char *msg, const Func &f)
Definition calc2.cpp:256
Definition calc2.cpp:99
void complete()
Definition calc2.cpp:182
void genAdd()
Definition calc2.cpp:162
Jit()
Definition calc2.cpp:120
void genVarX()
Definition calc2.cpp:152
void genPush(double n)
Definition calc2.cpp:144
void genMul()
Definition calc2.cpp:170
void genDiv()
Definition calc2.cpp:174
void genSub()
Definition calc2.cpp:166
void genNeg()
Definition calc2.cpp:178
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
void fld(const Address &addr)
Definition xbyak.h:237
const Reg32 esp
Definition xbyak.h:2087
const Reg32 eax
Definition xbyak.h:2087
const Xmm & xm0
Definition xbyak.h:2084
void add(const Operand &op, uint32 imm)
Definition xbyak.h:6
void sub(const Operand &op, uint32 imm)
Definition xbyak.h:746
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 AddressFrame qword
Definition xbyak.h:2090
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 lea(const Reg &reg, const Address &addr)
Definition xbyak.h:432
void xorpd(const Xmm &xmm, const Operand &op)
Definition xbyak.h:1281
void divsd(const Xmm &xmm, const Operand &op)
Definition xbyak.h:166
const AddressFrame ptr
Definition xbyak.h:2090
char ** argv
Definition xbyak.h:104
uint64_t uint64
Definition xbyak.h:117
Xbyak::uint64 uint64
Definition quantize.cpp:51
Definition bench.cpp:18
Code(Operand op)
Definition calc2.cpp:41
Operand op_
Definition calc2.cpp:39
double val_
Definition calc2.cpp:40
Code(double val)
Definition calc2.cpp:46
boost::spirit::qi::rule< Iterator, boost::spirit::ascii::space_type > term
Definition calc2.cpp:201
CodeSet & code_
Definition calc2.cpp:202
Parser(CodeSet &code)
Definition calc2.cpp:203
boost::spirit::qi::rule< Iterator, boost::spirit::ascii::space_type > expression
Definition calc2.cpp:201
boost::spirit::qi::rule< Iterator, boost::spirit::ascii::space_type > factor
Definition calc2.cpp:201
Jit code_
Definition calc2.cpp:230
boost::spirit::qi::rule< Iterator, boost::spirit::ascii::space_type > factor
Definition calc2.cpp:229
boost::spirit::qi::rule< Iterator, boost::spirit::ascii::space_type > expression
Definition calc2.cpp:229
ParserJit()
Definition calc2.cpp:231
boost::spirit::qi::rule< Iterator, boost::spirit::ascii::space_type > term
Definition calc2.cpp:229
Definition calc2.cpp:55
double operator()(double x) const
Definition calc2.cpp:57
CodeSet code_
Definition calc2.cpp:56
Xbyak ; JIT assembler for x86(IA32)/x64 by C++.
#define XBYAK32
Definition xbyak.h:88
CK_RV ret
#define MIE_ALIGN(x)
Definition zm.h:50