aboutsummaryrefslogtreecommitdiffhomepage
path: root/sample/calc.cpp
diff options
context:
space:
mode:
authorMITSUNARI Shigeo <[email protected]>2010-04-16 10:33:04 +0900
committerMITSUNARI Shigeo <[email protected]>2010-04-16 10:33:04 +0900
commitcbb4ca2178c6bd391b48c130afececfdddc66836 (patch)
tree46c9cfe83e040443af60585e212d071f0f127ebc /sample/calc.cpp
downloadxbyak-cbb4ca2178c6bd391b48c130afececfdddc66836.tar.gz
xbyak-cbb4ca2178c6bd391b48c130afececfdddc66836.zip
first commit
Diffstat (limited to 'sample/calc.cpp')
-rw-r--r--sample/calc.cpp226
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;
+}