meta_kernel.hpp 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054
  1. //---------------------------------------------------------------------------//
  2. // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
  3. //
  4. // Distributed under the Boost Software License, Version 1.0
  5. // See accompanying file LICENSE_1_0.txt or copy at
  6. // http://www.boost.org/LICENSE_1_0.txt
  7. //
  8. // See http://boostorg.github.com/compute for more information.
  9. //---------------------------------------------------------------------------//
  10. #ifndef BOOST_COMPUTE_DETAIL_META_KERNEL_HPP
  11. #define BOOST_COMPUTE_DETAIL_META_KERNEL_HPP
  12. #include <set>
  13. #include <string>
  14. #include <vector>
  15. #include <iomanip>
  16. #include <sstream>
  17. #include <utility>
  18. #include <boost/tuple/tuple.hpp>
  19. #include <boost/type_traits.hpp>
  20. #include <boost/lexical_cast.hpp>
  21. #include <boost/static_assert.hpp>
  22. #include <boost/algorithm/string/find.hpp>
  23. #include <boost/preprocessor/repetition.hpp>
  24. #include <boost/compute/kernel.hpp>
  25. #include <boost/compute/closure.hpp>
  26. #include <boost/compute/function.hpp>
  27. #include <boost/compute/functional.hpp>
  28. #include <boost/compute/type_traits.hpp>
  29. #include <boost/compute/command_queue.hpp>
  30. #include <boost/compute/image/image2d.hpp>
  31. #include <boost/compute/image/image_sampler.hpp>
  32. #include <boost/compute/memory_object.hpp>
  33. #include <boost/compute/detail/device_ptr.hpp>
  34. #include <boost/compute/detail/sha1.hpp>
  35. #include <boost/compute/utility/program_cache.hpp>
  36. namespace boost {
  37. namespace compute {
  38. namespace detail {
  39. template<class T>
  40. class meta_kernel_variable
  41. {
  42. public:
  43. typedef T result_type;
  44. meta_kernel_variable(const std::string &name)
  45. : m_name(name)
  46. {
  47. }
  48. meta_kernel_variable(const meta_kernel_variable &other)
  49. : m_name(other.m_name)
  50. {
  51. }
  52. meta_kernel_variable& operator=(const meta_kernel_variable &other)
  53. {
  54. if(this != &other){
  55. m_name = other.m_name;
  56. }
  57. return *this;
  58. }
  59. ~meta_kernel_variable()
  60. {
  61. }
  62. std::string name() const
  63. {
  64. return m_name;
  65. }
  66. private:
  67. std::string m_name;
  68. };
  69. template<class T>
  70. class meta_kernel_literal
  71. {
  72. public:
  73. typedef T result_type;
  74. meta_kernel_literal(const T &value)
  75. : m_value(value)
  76. {
  77. }
  78. meta_kernel_literal(const meta_kernel_literal &other)
  79. : m_value(other.m_value)
  80. {
  81. }
  82. meta_kernel_literal& operator=(const meta_kernel_literal &other)
  83. {
  84. if(this != &other){
  85. m_value = other.m_value;
  86. }
  87. return *this;
  88. }
  89. ~meta_kernel_literal()
  90. {
  91. }
  92. const T& value() const
  93. {
  94. return m_value;
  95. }
  96. private:
  97. T m_value;
  98. };
  99. struct meta_kernel_stored_arg
  100. {
  101. meta_kernel_stored_arg()
  102. : m_size(0),
  103. m_value(0)
  104. {
  105. }
  106. meta_kernel_stored_arg(const meta_kernel_stored_arg &other)
  107. : m_size(0),
  108. m_value(0)
  109. {
  110. set_value(other.m_size, other.m_value);
  111. }
  112. meta_kernel_stored_arg& operator=(const meta_kernel_stored_arg &other)
  113. {
  114. if(this != &other){
  115. set_value(other.m_size, other.m_value);
  116. }
  117. return *this;
  118. }
  119. template<class T>
  120. meta_kernel_stored_arg(const T &value)
  121. : m_size(0),
  122. m_value(0)
  123. {
  124. set_value(value);
  125. }
  126. ~meta_kernel_stored_arg()
  127. {
  128. if(m_value){
  129. std::free(m_value);
  130. }
  131. }
  132. void set_value(size_t size, const void *value)
  133. {
  134. if(m_value){
  135. std::free(m_value);
  136. }
  137. m_size = size;
  138. if(value){
  139. m_value = std::malloc(size);
  140. std::memcpy(m_value, value, size);
  141. }
  142. else {
  143. m_value = 0;
  144. }
  145. }
  146. template<class T>
  147. void set_value(const T &value)
  148. {
  149. set_value(sizeof(T), boost::addressof(value));
  150. }
  151. size_t m_size;
  152. void *m_value;
  153. };
  154. struct meta_kernel_buffer_info
  155. {
  156. meta_kernel_buffer_info(const buffer &buffer,
  157. const std::string &id,
  158. memory_object::address_space addr_space,
  159. size_t i)
  160. : m_mem(buffer.get()),
  161. identifier(id),
  162. address_space(addr_space),
  163. index(i)
  164. {
  165. }
  166. cl_mem m_mem;
  167. std::string identifier;
  168. memory_object::address_space address_space;
  169. size_t index;
  170. };
  171. class meta_kernel;
  172. template<class Type>
  173. struct inject_type_impl
  174. {
  175. void operator()(meta_kernel &)
  176. {
  177. // default implementation does nothing
  178. }
  179. };
  180. #define BOOST_COMPUTE_META_KERNEL_DECLARE_SCALAR_TYPE_STREAM_OPERATOR(type) \
  181. meta_kernel& operator<<(const type &x) \
  182. { \
  183. m_source << x; \
  184. return *this; \
  185. }
  186. #define BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(type) \
  187. meta_kernel& operator<<(const type &x) \
  188. { \
  189. m_source << "(" << type_name<type>() << ")"; \
  190. m_source << "("; \
  191. for(size_t i = 0; i < vector_size<type>::value; i++){ \
  192. *this << lit(x[i]); \
  193. \
  194. if(i != vector_size<type>::value - 1){ \
  195. m_source << ","; \
  196. } \
  197. } \
  198. m_source << ")"; \
  199. return *this; \
  200. }
  201. #define BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(type) \
  202. BOOST_COMPUTE_META_KERNEL_DECLARE_SCALAR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(type, _)) \
  203. BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(BOOST_PP_CAT(type, 2), _)) \
  204. BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(BOOST_PP_CAT(type, 4), _)) \
  205. BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(BOOST_PP_CAT(type, 8), _)) \
  206. BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(BOOST_PP_CAT(BOOST_PP_CAT(type, 16), _))
  207. class meta_kernel
  208. {
  209. public:
  210. template<class T>
  211. class argument
  212. {
  213. public:
  214. argument(const std::string &name, size_t index)
  215. : m_name(name),
  216. m_index(index)
  217. {
  218. }
  219. const std::string &name() const
  220. {
  221. return m_name;
  222. }
  223. size_t index() const
  224. {
  225. return m_index;
  226. }
  227. private:
  228. std::string m_name;
  229. size_t m_index;
  230. };
  231. explicit meta_kernel(const std::string &name)
  232. : m_name(name)
  233. {
  234. }
  235. meta_kernel(const meta_kernel &other)
  236. {
  237. m_source.str(other.m_source.str());
  238. }
  239. meta_kernel& operator=(const meta_kernel &other)
  240. {
  241. if(this != &other){
  242. m_source.str(other.m_source.str());
  243. }
  244. return *this;
  245. }
  246. ~meta_kernel()
  247. {
  248. }
  249. std::string name() const
  250. {
  251. return m_name;
  252. }
  253. std::string source() const
  254. {
  255. std::stringstream stream;
  256. // add pragmas
  257. if(!m_pragmas.empty()){
  258. stream << m_pragmas << "\n";
  259. }
  260. // add macros
  261. stream << "#define boost_pair_type(t1, t2) _pair_ ## t1 ## _ ## t2 ## _t\n";
  262. stream << "#define boost_pair_get(x, n) (n == 0 ? x.first ## x.second)\n";
  263. stream << "#define boost_make_pair(t1, x, t2, y) (boost_pair_type(t1, t2)) { x, y }\n";
  264. stream << "#define boost_tuple_get(x, n) (x.v ## n)\n";
  265. // add type declaration source
  266. stream << m_type_declaration_source.str() << "\n";
  267. // add external function source
  268. stream << m_external_function_source.str() << "\n";
  269. // add kernel source
  270. stream << "__kernel void " << m_name
  271. << "(" << boost::join(m_args, ", ") << ")\n"
  272. << "{\n" << m_source.str() << "\n}\n";
  273. return stream.str();
  274. }
  275. kernel compile(const context &context, const std::string &options = std::string())
  276. {
  277. // generate the program source
  278. std::string source = this->source();
  279. // generate cache key
  280. std::string cache_key = "__boost_meta_kernel_" +
  281. static_cast<std::string>(detail::sha1(source));
  282. // load program cache
  283. boost::shared_ptr<program_cache> cache =
  284. program_cache::get_global_cache(context);
  285. // load (or build) program from cache
  286. ::boost::compute::program program =
  287. cache->get_or_build(cache_key, options, source, context);
  288. // create kernel
  289. ::boost::compute::kernel kernel = program.create_kernel(name());
  290. // bind stored args
  291. for(size_t i = 0; i < m_stored_args.size(); i++){
  292. const detail::meta_kernel_stored_arg &arg = m_stored_args[i];
  293. if(arg.m_size != 0){
  294. kernel.set_arg(i, arg.m_size, arg.m_value);
  295. }
  296. }
  297. // bind buffer args
  298. for(size_t i = 0; i < m_stored_buffers.size(); i++){
  299. const detail::meta_kernel_buffer_info &bi = m_stored_buffers[i];
  300. kernel.set_arg(bi.index, bi.m_mem);
  301. }
  302. return kernel;
  303. }
  304. template<class T>
  305. size_t add_arg(const std::string &name)
  306. {
  307. std::stringstream stream;
  308. stream << type<T>() << " " << name;
  309. // add argument to list
  310. m_args.push_back(stream.str());
  311. // return index
  312. return m_args.size() - 1;
  313. }
  314. template<class T>
  315. size_t add_arg(memory_object::address_space address_space,
  316. const std::string &name)
  317. {
  318. return add_arg_with_qualifiers<T>(address_space_prefix(address_space), name);
  319. }
  320. template<class T>
  321. void set_arg(size_t index, const T &value)
  322. {
  323. if(index >= m_stored_args.size()){
  324. m_stored_args.resize(index + 1);
  325. }
  326. m_stored_args[index] = detail::meta_kernel_stored_arg(value);
  327. }
  328. void set_arg(size_t index, const memory_object &mem)
  329. {
  330. set_arg<cl_mem>(index, mem.get());
  331. }
  332. void set_arg(size_t index, const image_sampler &sampler)
  333. {
  334. set_arg<cl_sampler>(index, cl_sampler(sampler));
  335. }
  336. template<class T>
  337. size_t add_set_arg(const std::string &name, const T &value)
  338. {
  339. size_t index = add_arg<T>(name);
  340. set_arg<T>(index, value);
  341. return index;
  342. }
  343. void add_extension_pragma(const std::string &extension,
  344. const std::string &value = "enable")
  345. {
  346. m_pragmas += "#pragma OPENCL EXTENSION " + extension + " : " + value + "\n";
  347. }
  348. void add_extension_pragma(const std::string &extension,
  349. const std::string &value) const
  350. {
  351. return const_cast<meta_kernel *>(this)->add_extension_pragma(extension, value);
  352. }
  353. template<class T>
  354. std::string type() const
  355. {
  356. std::stringstream stream;
  357. // const qualifier
  358. if(boost::is_const<T>::value){
  359. stream << "const ";
  360. }
  361. // volatile qualifier
  362. if(boost::is_volatile<T>::value){
  363. stream << "volatile ";
  364. }
  365. // type
  366. typedef
  367. typename boost::remove_cv<
  368. typename boost::remove_pointer<T>::type
  369. >::type Type;
  370. stream << type_name<Type>();
  371. // pointer
  372. if(boost::is_pointer<T>::value){
  373. stream << "*";
  374. }
  375. // inject type pragmas and/or definitions
  376. inject_type<Type>();
  377. return stream.str();
  378. }
  379. template<class T>
  380. std::string decl(const std::string &name) const
  381. {
  382. return type<T>() + " " + name;
  383. }
  384. template<class T, class Expr>
  385. std::string decl(const std::string &name, const Expr &init) const
  386. {
  387. meta_kernel tmp((std::string()));
  388. tmp << tmp.decl<T>(name) << " = " << init;
  389. return tmp.m_source.str();
  390. }
  391. template<class T>
  392. detail::meta_kernel_variable<T> var(const std::string &name) const
  393. {
  394. type<T>();
  395. return make_var<T>(name);
  396. }
  397. template<class T>
  398. detail::meta_kernel_literal<T> lit(const T &value) const
  399. {
  400. type<T>();
  401. return detail::meta_kernel_literal<T>(value);
  402. }
  403. template<class T>
  404. detail::meta_kernel_variable<T> expr(const std::string &expr) const
  405. {
  406. type<T>();
  407. return detail::meta_kernel_variable<T>(expr);
  408. }
  409. // define stream operators for scalar and vector types
  410. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(char)
  411. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(uchar)
  412. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(short)
  413. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(ushort)
  414. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(int)
  415. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(uint)
  416. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(long)
  417. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(ulong)
  418. BOOST_COMPUTE_META_KERNEL_DECLARE_TYPE_STREAM_OPERATORS(double)
  419. // define stream operators for float scalar and vector types
  420. meta_kernel& operator<<(const float &x)
  421. {
  422. m_source << std::showpoint << x << 'f';
  423. return *this;
  424. }
  425. BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(float2_)
  426. BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(float4_)
  427. BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(float8_)
  428. BOOST_COMPUTE_META_KERNEL_DECLARE_VECTOR_TYPE_STREAM_OPERATOR(float16_)
  429. // define stream operators for variable types
  430. template<class T>
  431. meta_kernel& operator<<(const meta_kernel_variable<T> &variable)
  432. {
  433. return *this << variable.name();
  434. }
  435. // define stream operators for literal types
  436. template<class T>
  437. meta_kernel& operator<<(const meta_kernel_literal<T> &literal)
  438. {
  439. return *this << literal.value();
  440. }
  441. meta_kernel& operator<<(const meta_kernel_literal<bool> &literal)
  442. {
  443. return *this << (literal.value() ? "true" : "false");
  444. }
  445. meta_kernel& operator<<(const meta_kernel_literal<char> &literal)
  446. {
  447. const char c = literal.value();
  448. switch(c){
  449. // control characters
  450. case '\0':
  451. return *this << "'\\0'";
  452. case '\a':
  453. return *this << "'\\a'";
  454. case '\b':
  455. return *this << "'\\b'";
  456. case '\t':
  457. return *this << "'\\t'";
  458. case '\n':
  459. return *this << "'\\n'";
  460. case '\v':
  461. return *this << "'\\v'";
  462. case '\f':
  463. return *this << "'\\f'";
  464. case '\r':
  465. return *this << "'\\r'";
  466. // characters which need escaping
  467. case '\"':
  468. case '\'':
  469. case '\?':
  470. case '\\':
  471. return *this << "'\\" << c << "'";
  472. // all other characters
  473. default:
  474. return *this << "'" << c << "'";
  475. }
  476. }
  477. meta_kernel& operator<<(const meta_kernel_literal<signed char> &literal)
  478. {
  479. return *this << lit<char>(literal.value());
  480. }
  481. meta_kernel& operator<<(const meta_kernel_literal<unsigned char> &literal)
  482. {
  483. return *this << uint_(literal.value());
  484. }
  485. // define stream operators for strings
  486. meta_kernel& operator<<(char ch)
  487. {
  488. m_source << ch;
  489. return *this;
  490. }
  491. meta_kernel& operator<<(const char *string)
  492. {
  493. m_source << string;
  494. return *this;
  495. }
  496. meta_kernel& operator<<(const std::string &string)
  497. {
  498. m_source << string;
  499. return *this;
  500. }
  501. template<class T>
  502. static detail::meta_kernel_variable<T> make_var(const std::string &name)
  503. {
  504. return detail::meta_kernel_variable<T>(name);
  505. }
  506. template<class T>
  507. static detail::meta_kernel_literal<T> make_lit(const T &value)
  508. {
  509. return detail::meta_kernel_literal<T>(value);
  510. }
  511. template<class T>
  512. static detail::meta_kernel_variable<T> make_expr(const std::string &expr)
  513. {
  514. return detail::meta_kernel_variable<T>(expr);
  515. }
  516. event exec(command_queue &queue)
  517. {
  518. return exec_1d(queue, 0, 1);
  519. }
  520. event exec_1d(command_queue &queue,
  521. size_t global_work_offset,
  522. size_t global_work_size)
  523. {
  524. const context &context = queue.get_context();
  525. ::boost::compute::kernel kernel = compile(context);
  526. return queue.enqueue_1d_range_kernel(
  527. kernel,
  528. global_work_offset,
  529. global_work_size,
  530. 0
  531. );
  532. }
  533. event exec_1d(command_queue &queue,
  534. size_t global_work_offset,
  535. size_t global_work_size,
  536. size_t local_work_size)
  537. {
  538. const context &context = queue.get_context();
  539. ::boost::compute::kernel kernel = compile(context);
  540. return queue.enqueue_1d_range_kernel(
  541. kernel,
  542. global_work_offset,
  543. global_work_size,
  544. local_work_size
  545. );
  546. }
  547. template<class T>
  548. std::string get_buffer_identifier(const buffer &buffer,
  549. const memory_object::address_space address_space =
  550. memory_object::global_memory)
  551. {
  552. // check if we've already seen buffer
  553. for(size_t i = 0; i < m_stored_buffers.size(); i++){
  554. const detail::meta_kernel_buffer_info &bi = m_stored_buffers[i];
  555. if(bi.m_mem == buffer.get() &&
  556. bi.address_space == address_space){
  557. return bi.identifier;
  558. }
  559. }
  560. // create a new binding
  561. std::string identifier =
  562. "_buf" + lexical_cast<std::string>(m_stored_buffers.size());
  563. size_t index = add_arg<T *>(address_space, identifier);
  564. // store new buffer info
  565. m_stored_buffers.push_back(
  566. detail::meta_kernel_buffer_info(buffer, identifier, address_space, index));
  567. return identifier;
  568. }
  569. std::string get_image_identifier(const char *qualifiers, const image2d &image)
  570. {
  571. size_t index = add_arg_with_qualifiers<image2d>(qualifiers, "image");
  572. set_arg(index, image);
  573. return "image";
  574. }
  575. std::string get_sampler_identifier(bool normalized_coords,
  576. cl_addressing_mode addressing_mode,
  577. cl_filter_mode filter_mode)
  578. {
  579. (void) normalized_coords;
  580. (void) addressing_mode;
  581. (void) filter_mode;
  582. m_pragmas += "const sampler_t sampler = CLK_NORMALIZED_COORDS_FALSE |\n"
  583. " CLK_ADDRESS_NONE |\n"
  584. " CLK_FILTER_NEAREST;\n";
  585. return "sampler";
  586. }
  587. template<class Expr>
  588. static std::string expr_to_string(const Expr &expr)
  589. {
  590. meta_kernel tmp((std::string()));
  591. tmp << expr;
  592. return tmp.m_source.str();
  593. }
  594. template<class Predicate>
  595. detail::invoked_function<bool, boost::tuple<Predicate> > if_(Predicate pred) const
  596. {
  597. return detail::invoked_function<bool, boost::tuple<Predicate> >(
  598. "if", std::string(), boost::make_tuple(pred)
  599. );
  600. }
  601. template<class Predicate>
  602. detail::invoked_function<bool, boost::tuple<Predicate> > else_if_(Predicate pred) const
  603. {
  604. return detail::invoked_function<bool, boost::tuple<Predicate> >(
  605. "else if", std::string(), boost::make_tuple(pred)
  606. );
  607. }
  608. detail::meta_kernel_variable<cl_uint> get_global_id(size_t dim) const
  609. {
  610. return expr<cl_uint>("get_global_id(" + lexical_cast<std::string>(dim) + ")");
  611. }
  612. void add_function(const std::string &name, const std::string &source)
  613. {
  614. if(m_external_function_names.count(name)){
  615. return;
  616. }
  617. m_external_function_names.insert(name);
  618. m_external_function_source << source << "\n";
  619. }
  620. void add_function(const std::string &name,
  621. const std::string &source,
  622. const std::map<std::string, std::string> &definitions)
  623. {
  624. typedef std::map<std::string, std::string>::const_iterator iter;
  625. std::stringstream s;
  626. // add #define's
  627. for(iter i = definitions.begin(); i != definitions.end(); i++){
  628. s << "#define " << i->first;
  629. if(!i->second.empty()){
  630. s << " " << i->second;
  631. }
  632. s << "\n";
  633. }
  634. s << source << "\n";
  635. // add #undef's
  636. for(iter i = definitions.begin(); i != definitions.end(); i++){
  637. s << "#undef " << i->first << "\n";
  638. }
  639. add_function(name, s.str());
  640. }
  641. template<class Type>
  642. void add_type_declaration(const std::string &declaration)
  643. {
  644. const char *name = type_name<Type>();
  645. // check if the type has already been declared
  646. std::string source = m_type_declaration_source.str();
  647. if(source.find(name) != std::string::npos){
  648. return;
  649. }
  650. m_type_declaration_source << declaration;
  651. }
  652. template<class Type>
  653. void inject_type() const
  654. {
  655. inject_type_impl<Type>()(const_cast<meta_kernel &>(*this));
  656. }
  657. // the insert_function_call() method inserts a call to a function with
  658. // the given name tuple of argument values.
  659. template<class ArgTuple>
  660. void insert_function_call(const std::string &name, const ArgTuple &args)
  661. {
  662. *this << name << '(';
  663. insert_function_call_args(args);
  664. *this << ')';
  665. }
  666. // the insert_function_call_args() method takes a tuple of argument values
  667. // and inserts them into the source string with a comma in-between each.
  668. // this is useful for creating function calls given a tuple of values.
  669. void insert_function_call_args(const boost::tuple<>&)
  670. {
  671. }
  672. #define BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARG_TYPE(z, n, unused) \
  673. inject_type<BOOST_PP_CAT(T, n)>();
  674. #define BOOST_COMPUTE_META_KERNEL_STREAM_FUNCTION_ARG(z, n, unused) \
  675. << boost::get<BOOST_PP_DEC(n)>(args) << ", "
  676. #define BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARGS(z, n, unused) \
  677. template<BOOST_PP_ENUM_PARAMS(n, class T)> \
  678. void insert_function_call_args( \
  679. const boost::tuple<BOOST_PP_ENUM_PARAMS(n, T)> &args \
  680. ) \
  681. { \
  682. BOOST_PP_REPEAT_FROM_TO( \
  683. 0, n, BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARG_TYPE, ~ \
  684. ) \
  685. *this \
  686. BOOST_PP_REPEAT_FROM_TO( \
  687. 1, n, BOOST_COMPUTE_META_KERNEL_STREAM_FUNCTION_ARG, ~ \
  688. ) \
  689. << boost::get<BOOST_PP_DEC(n)>(args); \
  690. }
  691. BOOST_PP_REPEAT_FROM_TO(
  692. 1, BOOST_COMPUTE_MAX_ARITY, BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARGS, ~
  693. )
  694. #undef BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARG_TYPE
  695. #undef BOOST_COMPUTE_META_KERNEL_STREAM_FUNCTION_ARG
  696. #undef BOOST_COMPUTE_META_KERNEL_INSERT_FUNCTION_ARGS
  697. static const char* address_space_prefix(const memory_object::address_space value)
  698. {
  699. switch(value){
  700. case memory_object::global_memory: return "__global";
  701. case memory_object::local_memory: return "__local";
  702. case memory_object::private_memory: return "__private";
  703. case memory_object::constant_memory: return "__constant";
  704. };
  705. return 0; // unreachable
  706. }
  707. private:
  708. template<class T>
  709. size_t add_arg_with_qualifiers(const char *qualifiers, const std::string &name)
  710. {
  711. size_t index = add_arg<T>(name);
  712. // update argument type declaration with qualifiers
  713. std::stringstream s;
  714. s << qualifiers << " " << m_args[index];
  715. m_args[index] = s.str();
  716. return index;
  717. }
  718. private:
  719. std::string m_name;
  720. std::stringstream m_source;
  721. std::stringstream m_external_function_source;
  722. std::stringstream m_type_declaration_source;
  723. std::set<std::string> m_external_function_names;
  724. std::vector<std::string> m_args;
  725. std::string m_pragmas;
  726. std::vector<detail::meta_kernel_stored_arg> m_stored_args;
  727. std::vector<detail::meta_kernel_buffer_info> m_stored_buffers;
  728. };
  729. template<class ResultType, class ArgTuple>
  730. inline meta_kernel&
  731. operator<<(meta_kernel &kernel, const invoked_function<ResultType, ArgTuple> &expr)
  732. {
  733. if(!expr.source().empty()){
  734. kernel.add_function(expr.name(), expr.source(), expr.definitions());
  735. }
  736. kernel.insert_function_call(expr.name(), expr.args());
  737. return kernel;
  738. }
  739. template<class ResultType, class ArgTuple, class CaptureTuple>
  740. inline meta_kernel&
  741. operator<<(meta_kernel &kernel,
  742. const invoked_closure<ResultType, ArgTuple, CaptureTuple> &expr)
  743. {
  744. if(!expr.source().empty()){
  745. kernel.add_function(expr.name(), expr.source(), expr.definitions());
  746. }
  747. kernel << expr.name() << '(';
  748. kernel.insert_function_call_args(expr.args());
  749. kernel << ", ";
  750. kernel.insert_function_call_args(expr.capture());
  751. kernel << ')';
  752. return kernel;
  753. }
  754. template<class Arg1, class Arg2, class Result>
  755. inline meta_kernel& operator<<(meta_kernel &kernel,
  756. const invoked_binary_operator<Arg1,
  757. Arg2,
  758. Result> &expr)
  759. {
  760. return kernel << "((" << expr.arg1() << ")"
  761. << expr.op()
  762. << "(" << expr.arg2() << "))";
  763. }
  764. template<class T, class IndexExpr>
  765. inline meta_kernel& operator<<(meta_kernel &kernel,
  766. const detail::device_ptr_index_expr<T, IndexExpr> &expr)
  767. {
  768. if(expr.m_index == 0){
  769. return kernel <<
  770. kernel.get_buffer_identifier<T>(expr.m_buffer) <<
  771. '[' << expr.m_expr << ']';
  772. }
  773. else {
  774. return kernel <<
  775. kernel.get_buffer_identifier<T>(expr.m_buffer) <<
  776. '[' << expr.m_index << "+(" << expr.m_expr << ")]";
  777. }
  778. }
  779. template<class T1, class T2, class IndexExpr>
  780. inline meta_kernel& operator<<(meta_kernel &kernel,
  781. const detail::device_ptr_index_expr<std::pair<T1, T2>, IndexExpr> &expr)
  782. {
  783. typedef std::pair<T1, T2> T;
  784. if(expr.m_index == 0){
  785. return kernel <<
  786. kernel.get_buffer_identifier<T>(expr.m_buffer) <<
  787. '[' << expr.m_expr << ']';
  788. }
  789. else {
  790. return kernel <<
  791. kernel.get_buffer_identifier<T>(expr.m_buffer) <<
  792. '[' << expr.m_index << "+(" << expr.m_expr << ")]";
  793. }
  794. }
  795. template<class Predicate, class Arg>
  796. inline meta_kernel& operator<<(meta_kernel &kernel,
  797. const invoked_unary_negate_function<Predicate,
  798. Arg> &expr)
  799. {
  800. return kernel << "!(" << expr.pred()(expr.expr()) << ')';
  801. }
  802. template<class Predicate, class Arg1, class Arg2>
  803. inline meta_kernel& operator<<(meta_kernel &kernel,
  804. const invoked_binary_negate_function<Predicate,
  805. Arg1,
  806. Arg2> &expr)
  807. {
  808. return kernel << "!(" << expr.pred()(expr.expr1(), expr.expr2()) << ')';
  809. }
  810. // get<N>() for vector types
  811. template<size_t N, class Arg, class T>
  812. inline meta_kernel& operator<<(meta_kernel &kernel,
  813. const invoked_get<N, Arg, T> &expr)
  814. {
  815. BOOST_STATIC_ASSERT(N < 16);
  816. if(N < 10){
  817. return kernel << expr.m_arg << ".s" << uint_(N);
  818. }
  819. else if(N < 16){
  820. #ifdef _MSC_VER
  821. # pragma warning(push)
  822. # pragma warning(disable: 4307)
  823. #endif
  824. return kernel << expr.m_arg << ".s" << char('a' + (N - 10));
  825. #ifdef _MSC_VER
  826. # pragma warning(pop)
  827. #endif
  828. }
  829. return kernel;
  830. }
  831. template<class T, class Arg>
  832. inline meta_kernel& operator<<(meta_kernel &kernel,
  833. const invoked_field<T, Arg> &expr)
  834. {
  835. return kernel << expr.m_arg << "." << expr.m_field;
  836. }
  837. template<class T, class Arg>
  838. inline meta_kernel& operator<<(meta_kernel &k,
  839. const invoked_as<T, Arg> &expr)
  840. {
  841. return k << "as_" << type_name<T>() << "(" << expr.m_arg << ")";
  842. }
  843. template<class T, class Arg>
  844. inline meta_kernel& operator<<(meta_kernel &k,
  845. const invoked_convert<T, Arg> &expr)
  846. {
  847. return k << "convert_" << type_name<T>() << "(" << expr.m_arg << ")";
  848. }
  849. template<class T, class Arg>
  850. inline meta_kernel& operator<<(meta_kernel &k,
  851. const invoked_identity<T, Arg> &expr)
  852. {
  853. return k << expr.m_arg;
  854. }
  855. template<>
  856. struct inject_type_impl<double_>
  857. {
  858. void operator()(meta_kernel &kernel)
  859. {
  860. kernel.add_extension_pragma("cl_khr_fp64", "enable");
  861. }
  862. };
  863. template<class Scalar, size_t N>
  864. struct inject_type_impl<vector_type<Scalar, N> >
  865. {
  866. void operator()(meta_kernel &kernel)
  867. {
  868. kernel.inject_type<Scalar>();
  869. }
  870. };
  871. } // end detail namespace
  872. } // end compute namespace
  873. } // end boost namespace
  874. #endif // BOOST_COMPUTE_DETAIL_META_KERNEL_HPP