diff options
author | MITSUNARI Shigeo <[email protected]> | 2010-04-16 10:33:04 +0900 |
---|---|---|
committer | MITSUNARI Shigeo <[email protected]> | 2010-04-16 10:33:04 +0900 |
commit | cbb4ca2178c6bd391b48c130afececfdddc66836 (patch) | |
tree | 46c9cfe83e040443af60585e212d071f0f127ebc /sample/calc.cpp | |
download | xbyak-cbb4ca2178c6bd391b48c130afececfdddc66836.tar.gz xbyak-cbb4ca2178c6bd391b48c130afececfdddc66836.zip |
first commit
Diffstat (limited to 'sample/calc.cpp')
-rw-r--r-- | sample/calc.cpp | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/sample/calc.cpp b/sample/calc.cpp new file mode 100644 index 0000000..e4ecf6d --- /dev/null +++ b/sample/calc.cpp @@ -0,0 +1,226 @@ +/* + @author herumi + @date $Date: 2010/04/15 06:52:07 $ + + tiny calculator 2 + This program generates a function to calc the value of + polynomial given by user in run-time. + use boost::sprit + +*/ +#include <stdio.h> +#include <sstream> +#include <map> +#include "xbyak/xbyak.h" +#ifdef _WIN32 + #pragma warning(disable : 4127) // for boost(constant condition) + #pragma warning(disable : 4512) // for boost +#endif +//#include <boost/spirit/iterator/file_iterator.hpp> +//#include <boost/spirit/core.hpp> +#include <boost/spirit/include/classic_file_iterator.hpp> +#include <boost/spirit/include/classic_core.hpp> +#include <boost/bind.hpp> + +enum Error { + UNDEFINED_VARIABLE = 1 +}; + +/* + JIT assemble of given polynomial for VC or gcc +*/ +class FuncGen : public Xbyak::CodeGenerator { +public: + typedef std::map<std::string, int> Map; +private: + enum { + MAX_CONST_NUM = 32 + }; + double constTbl_[MAX_CONST_NUM]; + size_t constTblPos_; + int regIdx_; + Map varMap_; // map var name to index + const Xbyak::Reg32e& valTbl_; + const Xbyak::Reg32e& tbl_; +public: + /* + @param y [out] the value of f(var) + @param var [in] table of input variables + func(double *y, const double var[]); + @note func does not return double to avoid difference of compiler + */ + FuncGen(const std::vector<std::string>& varTbl) + : constTblPos_(0) + , regIdx_(-1) +#ifdef XBYAK32 + , valTbl_(eax) + , tbl_(edx) +#elif defined(XBYAK64_WIN) + , valTbl_(rcx) + , tbl_(rdx) +#else + , valTbl_(rdi) + , tbl_(rsi) +#endif + { +#ifdef XBYAK32 + mov(valTbl_, ptr[esp+8]); // eax == varTbl + mov(tbl_, (size_t)constTbl_); +#else +#ifdef XBYAK64_WIN + movaps(ptr [rsp + 8], xm6); // save xm6, xm7 + movaps(ptr [rsp + 8 + 16], xm7); +#endif + mov(tbl_, (size_t)constTbl_); +#endif + for (int i = 0, n = static_cast<int>(varTbl.size()); i < n; i++) { + varMap_[varTbl[i]] = i; + } + } + // use edx + void genPush(double n) + { + if (constTblPos_ >= MAX_CONST_NUM) throw; + constTbl_[constTblPos_] = n; + if (regIdx_ == 7) throw; + movsd(Xbyak::Xmm(++regIdx_), ptr[tbl_ + constTblPos_ * sizeof(double)]); + constTblPos_++; + } + // use eax + void genVal(const char *begin, const char *end) + { + std::string var(begin, end); + if (varMap_.find(var) == varMap_.end()) throw UNDEFINED_VARIABLE; + if (regIdx_ == 7) throw; + movsd(Xbyak::Xmm(++regIdx_), ptr[valTbl_ + varMap_[var] * sizeof(double)]); + } + void genAdd(const char*, const char*) + { + addsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--; + } + void genSub(const char*, const char*) + { + subsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--; + } + void genMul(const char*, const char*) + { + mulsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--; + } + void genDiv(const char*, const char*) + { + divsd(Xbyak::Xmm(regIdx_ - 1), Xbyak::Xmm(regIdx_)); regIdx_--; + } + void complete() + { +#ifdef XBYAK32 + mov(eax, ptr [esp + 4]); // eax = valTbl + movsd(ptr [eax], xm0); +#else +#ifdef XBYAK64_WIN + movaps(xm6, ptr [rsp + 8]); + movaps(xm7, ptr [rsp + 8 + 16]); +#endif +#endif + ret(); + } +}; + +struct Grammar : public boost::spirit::classic::grammar<Grammar> { + FuncGen& f_; + Grammar(FuncGen& f) : f_(f) { } + template<typename ScannerT> + struct definition { + boost::spirit::classic::rule<ScannerT> poly0, poly1, poly2, var; + + definition(const Grammar& self) + { + using namespace boost; + using namespace boost::spirit::classic; + + poly0 = poly1 >> *(('+' >> poly1)[bind(&FuncGen::genAdd, ref(self.f_), _1, _2)] + | ('-' >> poly1)[bind(&FuncGen::genSub, ref(self.f_), _1, _2)]); + poly1 = poly2 >> *(('*' >> poly2)[bind(&FuncGen::genMul, ref(self.f_), _1, _2)] + | ('/' >> poly2)[bind(&FuncGen::genDiv, ref(self.f_), _1, _2)]); + var = (+alpha_p)[bind(&FuncGen::genVal, ref(self.f_), _1, _2)]; + poly2 = real_p[bind(&FuncGen::genPush, ref(self.f_), _1)] + | var + | '(' >> poly0 >> ')'; + } + const boost::spirit::classic::rule<ScannerT>& start() const { return poly0; } + }; +}; + +void put(const std::vector<double>& x) +{ + printf("%f", x[0]); + for (size_t i = 1, n = x.size(); i < n; i++) { + printf(", %f", x[i]); + } +} + +int main(int argc, char *argv[]) +{ + if (argc <= 2) { + fprintf(stderr, "calc \"var1 var2 ...\" \"function of var\"\n"); + fprintf(stderr, "eg. calc x \"x*x\"\n"); + fprintf(stderr, "eg. calc \"x y z\" \"x*x + y - z\"\n"); + return 1; + } + const char *poly = argv[2]; + try { + std::vector<std::string> varTbl; + + // get varTbl from argv[1] + { + std::istringstream is(argv[1]); + int i = 0; + printf("varTbl = { "); + while (is) { + std::string var; + is >> var; + if (var.empty()) break; + printf("%s:%d, ", var.c_str(), i); + varTbl.push_back(var); + i++; + } + printf("}\n"); + } + FuncGen funcGen(varTbl); + Grammar calc(funcGen); + boost::spirit::classic::parse_info<> r = parse(poly, calc, boost::spirit::classic::space_p); + if (!r.full) { + printf("err poly=%s\n", poly); + return 1; + } + funcGen.complete(); + std::vector<double> valTbl; + valTbl.resize(varTbl.size()); +#ifdef XBYAK32 + puts("32bit mode"); + void (*func)(double *ret, const double *valTbl) = (void (*)(double *, const double*))funcGen.getCode(); +#else + puts("64bit mode"); + double (*func)(const double *valTbl) = (double (*)(const double*))funcGen.getCode(); +#endif + for (int i = 0; i < 10; i++) { + for (size_t j = 0, n = valTbl.size(); j < n; j++) { + valTbl[j] = rand() % 7; + } + double y; +#ifdef XBYAK32 + func(&y, &valTbl[0]); +#else + y = func(&valTbl[0]); +#endif + printf("f("); put(valTbl); printf(")=%f\n", y); + } + } catch (Xbyak::Error err) { + printf("ERR:%s(%d)\n", Xbyak::ConvertErrorToString(err), err); + } catch (Error err) { + printf("ERR:%d\n", err); + } catch (...) { + printf("unknown error\n"); + } + + return 0; +} |