1
0

NaiveIRGenerator.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. #include "NaiveIRGenerator.h"
  2. #include <omp.h>
  3. using mnd::NaiveIRGenerator;
  4. template class mnd::NaiveIRGenerator<float>;
  5. template class mnd::NaiveIRGenerator<double>;
  6. template class mnd::NaiveIRGenerator<mnd::DoubleDouble>;
  7. template class mnd::NaiveIRGenerator<mnd::QuadDouble>;
  8. namespace mnd::eval
  9. {
  10. using namespace mnd;
  11. using namespace mnd::ir;
  12. template<typename T>
  13. struct ToEvalVisitor
  14. {
  15. EvalStruct<T>& es;
  16. std::unique_ptr<EvalNode> visit(ir::Node* f)
  17. {
  18. std::any& nodeData = getNodeData(f);
  19. if (EvalNode** en = std::any_cast<EvalNode*>(&nodeData)) {
  20. size_t tmpStore;
  21. if (Store* s = std::get_if<Store>(*en)) {
  22. tmpStore = s->index;
  23. }
  24. else {
  25. tmpStore = createTemp();
  26. EvalNode store = Store{ tmpStore, std::make_unique<EvalNode>(std::move(**en)) };
  27. **en = std::move(store);
  28. }
  29. auto l = std::make_unique<EvalNode>(Load{ tmpStore });
  30. setNodeData(f, l.get());
  31. return l;
  32. }
  33. EvalNode n = std::visit(*this, *f);
  34. auto r = std::make_unique<EvalNode>(std::move(n));
  35. setNodeData(f, r.get());
  36. return r;
  37. }
  38. std::any& getNodeData(ir::Node* n)
  39. {
  40. return std::visit([](auto& x) -> std::any& { return x.nodeData; }, *n);
  41. }
  42. void setNodeData(ir::Node* n, EvalNode* en)
  43. {
  44. std::visit([en](auto& x) { x.nodeData = en; }, *n);
  45. }
  46. size_t createTemp(void)
  47. {
  48. es.temporaries.push_back(0);
  49. es.variables.push_back(&es.temporaries[es.temporaries.size() - 1]);
  50. return es.variables.size() - 1;
  51. }
  52. size_t createConstant(mnd::Real& value)
  53. {
  54. es.temporaries.push_back(mnd::convert<T>(value));
  55. es.variables.push_back(&es.temporaries[es.temporaries.size() - 1]);
  56. return es.variables.size() - 1;
  57. }
  58. size_t createVariable(std::string& value)
  59. {
  60. es.variables.push_back(nullptr);
  61. es.variableNames.emplace(value, es.variables.size() - 1);
  62. return es.variables.size() - 1;
  63. }
  64. EvalNode operator()(ir::Constant& x) {
  65. return Load{ createConstant(x.value) };
  66. }
  67. EvalNode operator()(ir::Variable& x) {
  68. return Load{ createVariable(x.name) };
  69. }
  70. EvalNode operator()(ir::Addition& x) {
  71. auto left = visit(x.left);
  72. return Add{ std::move(left), visit(x.right) };
  73. }
  74. EvalNode operator()(ir::Subtraction& x) {
  75. auto left = visit(x.left);
  76. return Sub{ std::move(left), visit(x.right) };
  77. }
  78. EvalNode operator()(ir::Multiplication& x) {
  79. auto left = visit(x.left);
  80. return Mul{ std::move(left), visit(x.right) };
  81. }
  82. EvalNode operator()(ir::Division& x) {
  83. auto left = visit(x.left);
  84. return Div{ std::move(left), visit(x.right) };
  85. }
  86. EvalNode operator()(ir::Negation& x) {
  87. return Neg{ visit(x.value) };
  88. }
  89. EvalNode operator()(ir::Atan2& x) {
  90. auto left = visit(x.left);
  91. return Atan2{ std::move(left), visit(x.right) };
  92. }
  93. EvalNode operator()(ir::Pow& x) {
  94. auto left = visit(x.left);
  95. return Pow{ std::move(left), visit(x.right) };
  96. }
  97. EvalNode operator()(ir::Cos& x) {
  98. return Cos{ visit(x.value) };
  99. }
  100. EvalNode operator()(ir::Sin& x) {
  101. return Sin{ visit(x.value) };
  102. }
  103. EvalNode operator()(ir::Exp& x) {
  104. return Exp{ visit(x.value) };
  105. }
  106. EvalNode operator()(ir::Ln& x) {
  107. return Ln{ visit(x.value) };
  108. }
  109. };
  110. template<typename T>
  111. struct EvalVisitor
  112. {
  113. mnd::eval::EvalStruct<T>& es;
  114. T visit(const EvalNode& en) {
  115. return std::visit(*this, en);
  116. }
  117. T operator()(const Load& x) {
  118. return *es.variables[x.index];
  119. }
  120. T operator()(const Store& x) {
  121. T r = visit(*x.v);
  122. *es.variables[x.index] = r;
  123. return r;
  124. }
  125. T operator()(const Add& x) {
  126. return visit(*x.a) + visit(*x.b);
  127. }
  128. T operator()(const Sub& x) {
  129. return visit(*x.a) - visit(*x.b);
  130. }
  131. T operator()(const Mul& x) {
  132. return visit(*x.a) * visit(*x.b);
  133. }
  134. T operator()(const Div& x) {
  135. return visit(*x.a) / visit(*x.b);
  136. }
  137. T operator()(const Neg& x) {
  138. return -visit(*x.a);
  139. }
  140. T operator()(const Atan2& x) {
  141. return mnd::atan2(visit(*x.a), visit(*x.b));
  142. }
  143. T operator()(const Pow& x) {
  144. return mnd::pow(visit(*x.a), visit(*x.b));
  145. }
  146. T operator()(const Cos& x) {
  147. return mnd::cos(visit(*x.a));
  148. }
  149. T operator()(const Sin& x) {
  150. return mnd::sin(visit(*x.a));
  151. }
  152. T operator()(const Exp& x) {
  153. return mnd::exp(visit(*x.a));
  154. }
  155. T operator()(const Ln& x) {
  156. return mnd::log(visit(*x.a));
  157. }
  158. };
  159. }
  160. template<typename T>
  161. NaiveIRGenerator<T>::NaiveIRGenerator(const mnd::ir::Formula& irf,
  162. mnd::Precision prec) :
  163. mnd::MandelGenerator{ prec },
  164. form{ irf }
  165. {
  166. eval::ToEvalVisitor<T> tev{ es };
  167. newz_re = tev.visit(irf.newA);
  168. newz_im = tev.visit(irf.newB);
  169. start_re = tev.visit(irf.startA);
  170. start_im = tev.visit(irf.startB);
  171. }
  172. template<typename T>
  173. void NaiveIRGenerator<T>::generate(const mnd::MandelInfo& info, float* data)
  174. {
  175. const MandelViewport& view = info.view;
  176. const bool parallel = true;
  177. T viewx = mnd::convert<T>(view.x);
  178. T viewy = mnd::convert<T>(view.y);
  179. T wpp = mnd::convert<T>(view.width / info.bWidth);
  180. T hpp = mnd::convert<T>(view.height / info.bHeight);
  181. #if defined(_OPENMP)
  182. if constexpr (parallel)
  183. omp_set_num_threads(omp_get_num_procs());
  184. # pragma omp parallel for schedule(static, 1) if (parallel)
  185. #endif
  186. for (long j = 0; j < info.bHeight; j++) {
  187. T y = viewy + T(double(j)) * hpp;
  188. for (long i = 0; i < info.bWidth; i++) {
  189. T x = viewx + T(double(i)) * wpp;
  190. T a;
  191. T b;
  192. es.prepare(&a, &b, &x, &y);
  193. eval::EvalVisitor<T> visitor{ es };
  194. a = visitor.visit(*start_re);
  195. b = visitor.visit(*start_im);
  196. int k = 0;
  197. for (k = 0; k < info.maxIter; k++) {
  198. T newA = visitor.visit(*newz_re);
  199. T newB = visitor.visit(*newz_im);
  200. a = newA;
  201. b = newB;
  202. if (a * a + b * b >= 16.0)
  203. break;
  204. }
  205. data[i + j * info.bWidth] = float(k);
  206. }
  207. }
  208. }