starpu.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028
  1. /* GCC-StarPU
  2. Copyright (C) 2011 Institut National de Recherche en Informatique et Automatique
  3. GCC-StarPU is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. GCC-StarPU is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with GCC-StarPU. If not, see <http://www.gnu.org/licenses/>. */
  13. /* Use extensions of the GNU C Library. */
  14. #define _GNU_SOURCE 1
  15. #include <starpu-gcc-config.h>
  16. int plugin_is_GPL_compatible;
  17. /* #define ENABLE_TREE_CHECKING 1 */
  18. #include <gcc-plugin.h>
  19. #include <plugin-version.h>
  20. #include <plugin.h>
  21. #include <cpplib.h>
  22. #include <tree.h>
  23. #include <tree-iterator.h>
  24. #include <c-common.h>
  25. #include <c-pragma.h>
  26. #include <tm.h>
  27. #include <gimple.h>
  28. #include <tree-pass.h>
  29. #include <cgraph.h>
  30. #include <gimple.h>
  31. #include <toplev.h>
  32. #include <stdio.h>
  33. #include <starpu.h> /* for `STARPU_CPU' & co. */
  34. /* The name of this plug-in. */
  35. static const char plugin_name[] = "starpu";
  36. /* Names of public attributes. */
  37. static const char task_attribute_name[] = "task";
  38. static const char task_implementation_attribute_name[] = "task_implementation";
  39. /* Names of attributes used internally. */
  40. static const char task_codelet_attribute_name[] = ".codelet";
  41. static const char task_implementation_list_attribute_name[] =
  42. ".task_implementation_list";
  43. static const char task_implementation_wrapper_attribute_name[] =
  44. ".task_implementation_wrapper";
  45. /* Names of data structures defined in <starpu.h>. */
  46. static const char codelet_struct_name[] = "starpu_codelet";
  47. static const char task_struct_name[] = "starpu_task";
  48. /* The `starpu_insert_task' FUNCTION_DECL. */
  49. static tree insert_task_fn = NULL_TREE;
  50. /* Forward declarations. */
  51. static tree build_codelet_declaration (tree task_decl);
  52. /* Useful code backported from GCC 4.6. */
  53. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_ARRAY
  54. static tree
  55. build_call_expr_loc_array (location_t loc, tree fndecl, int n, tree *argarray)
  56. {
  57. tree fntype = TREE_TYPE (fndecl);
  58. tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
  59. return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
  60. }
  61. #endif
  62. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_VEC
  63. static tree
  64. build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
  65. {
  66. return build_call_expr_loc_array (loc, fndecl, VEC_length (tree, vec),
  67. VEC_address (tree, vec));
  68. }
  69. #endif
  70. /* Debugging helpers. */
  71. static tree build_printf (const char *, ...)
  72. __attribute__ ((format (printf, 1, 2)));
  73. static tree
  74. build_printf (const char *fmt, ...)
  75. {
  76. tree call;
  77. char *str;
  78. va_list args;
  79. va_start (args, fmt);
  80. vasprintf (&str, fmt, args);
  81. call = build_call_expr (built_in_decls[BUILT_IN_PUTS], 1,
  82. build_string_literal (strlen (str) + 1, str));
  83. free (str);
  84. va_end (args);
  85. return call;
  86. }
  87. static tree
  88. build_hello_world (void)
  89. {
  90. return build_printf ("Hello, StarPU!");
  91. }
  92. /* List and vector utilities, à la SRFI-1. */
  93. static tree chain_trees (tree t, ...)
  94. __attribute__ ((sentinel));
  95. static tree
  96. chain_trees (tree t, ...)
  97. {
  98. va_list args;
  99. va_start (args, t);
  100. tree next, prev = t;
  101. for (prev = t, next = va_arg (args, tree);
  102. next != NULL_TREE;
  103. prev = next, next = va_arg (args, tree))
  104. TREE_CHAIN (prev) = next;
  105. va_end (args);
  106. return t;
  107. }
  108. static tree
  109. filter (bool (*pred) (const_tree), tree t)
  110. {
  111. tree result, lst;
  112. gcc_assert (TREE_CODE (t) == TREE_LIST);
  113. result = NULL_TREE;
  114. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  115. {
  116. if (pred (lst))
  117. result = tree_cons (TREE_PURPOSE (lst), TREE_VALUE (lst),
  118. result);
  119. }
  120. return nreverse (result);
  121. }
  122. static void
  123. for_each (void (*func) (tree), tree t)
  124. {
  125. tree lst;
  126. gcc_assert (TREE_CODE (t) == TREE_LIST);
  127. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  128. func (TREE_VALUE (lst));
  129. }
  130. /* Pragmas. */
  131. #define STARPU_PRAGMA_NAME_SPACE "starpu"
  132. static void
  133. handle_pragma_hello (struct cpp_reader *reader)
  134. {
  135. add_stmt (build_hello_world ());
  136. }
  137. static void
  138. register_pragmas (void *gcc_data, void *user_data)
  139. {
  140. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "hello",
  141. handle_pragma_hello);
  142. }
  143. /* Attributes. */
  144. /* Handle the `task' function attribute. */
  145. static tree
  146. handle_task_attribute (tree *node, tree name, tree args,
  147. int flags, bool *no_add_attrs)
  148. {
  149. tree fn;
  150. fn = *node;
  151. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  152. /* This is a function declaration for something local to this
  153. translation unit, so add the `task' attribute to FN. */
  154. *no_add_attrs = false;
  155. /* Add an empty `task_implementation_list' attribute. */
  156. DECL_ATTRIBUTES (fn) =
  157. tree_cons (get_identifier (task_implementation_list_attribute_name),
  158. NULL_TREE,
  159. NULL_TREE);
  160. /* Push a declaration for the corresponding `starpu_codelet' object and add
  161. it as an attribute of FN. */
  162. tree cl = build_codelet_declaration (fn);
  163. DECL_ATTRIBUTES (fn) =
  164. tree_cons (get_identifier (task_codelet_attribute_name), cl,
  165. DECL_ATTRIBUTES (fn));
  166. pushdecl (cl);
  167. TREE_USED (fn) = true;
  168. if (insert_task_fn == NULL_TREE)
  169. {
  170. /* Lookup the TASK_CREATE_NAME in the global scope (this can't be done
  171. from `lower_starpu'.)
  172. XXX: Move it in a pass of its own. */
  173. insert_task_fn = lookup_name (get_identifier ("starpu_insert_task"));
  174. gcc_assert (insert_task_fn != NULL_TREE &&
  175. TREE_CODE (insert_task_fn) == FUNCTION_DECL);
  176. }
  177. return NULL_TREE;
  178. }
  179. /* Handle the `task_implementation (WHERE, TASK)' attribute. WHERE is a
  180. string constant ("cpu", "cuda", etc.), and TASK is the identifier of a
  181. function declared with the `task' attribute. */
  182. static tree
  183. handle_task_implementation_attribute (tree *node, tree name, tree args,
  184. int flags, bool *no_add_attrs)
  185. {
  186. tree fn, where, task_decl;
  187. /* FIXME: Use error nodes instead of `gcc_assert'. */
  188. /* FIXME:TODO: To change the order to (TASK, WHERE):
  189. tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
  190. tree cleanup_decl = lookup_name (cleanup_id);
  191. */
  192. fn = *node;
  193. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  194. where = TREE_VALUE (args);
  195. gcc_assert (TREE_CODE (where) == STRING_CST);
  196. task_decl = TREE_VALUE (TREE_CHAIN (args));
  197. gcc_assert (TREE_CODE (task_decl) == FUNCTION_DECL);
  198. gcc_assert (lookup_attribute (task_attribute_name,
  199. DECL_ATTRIBUTES (task_decl)));
  200. gcc_assert (TYPE_CANONICAL (TREE_TYPE (fn))
  201. == TYPE_CANONICAL (TREE_TYPE (task_decl))
  202. && TYPE_CANONICAL (TREE_TYPE (fn)) != NULL_TREE);
  203. /* Add FN to the list of implementations of TASK_DECL. */
  204. tree attr, impls;
  205. attr = lookup_attribute (task_implementation_list_attribute_name,
  206. DECL_ATTRIBUTES (task_decl));
  207. impls = tree_cons (NULL_TREE, fn, TREE_VALUE (attr));
  208. DECL_ATTRIBUTES (task_decl) =
  209. tree_cons (get_identifier (task_implementation_list_attribute_name),
  210. impls,
  211. remove_attribute (task_implementation_list_attribute_name,
  212. DECL_ATTRIBUTES (task_decl)));
  213. TREE_USED (fn) = true;
  214. /* Keep the attribute. */
  215. *no_add_attrs = false;
  216. return NULL_TREE;
  217. }
  218. /* Return the declaration of the `starpu_codelet' variable associated with
  219. TASK_DECL. */
  220. static tree
  221. task_codelet_declaration (const_tree task_decl)
  222. {
  223. tree cl_attr;
  224. cl_attr = lookup_attribute (task_codelet_attribute_name,
  225. DECL_ATTRIBUTES (task_decl));
  226. gcc_assert (cl_attr != NULL_TREE);
  227. return TREE_VALUE (cl_attr);
  228. }
  229. /* Return the list of implementations of TASK_DECL. */
  230. static tree
  231. task_implementation_list (const_tree task_decl)
  232. {
  233. tree attr;
  234. attr = lookup_attribute (task_implementation_list_attribute_name,
  235. DECL_ATTRIBUTES (task_decl));
  236. return TREE_VALUE (attr);
  237. }
  238. /* Return the list of scalar parameter types of TASK_DECL. */
  239. static tree
  240. task_scalar_parameter_types (const_tree task_decl)
  241. {
  242. bool is_scalar (const_tree item)
  243. {
  244. return (!POINTER_TYPE_P (TREE_VALUE (item))
  245. && !VOID_TYPE_P (TREE_VALUE (item)));
  246. }
  247. return filter (is_scalar, TYPE_ARG_TYPES (TREE_TYPE (task_decl)));
  248. }
  249. /* Return a value indicating where TASK_IMPL should execute (`STARPU_CPU',
  250. `STARPU_CUDA', etc.). */
  251. static int
  252. task_implementation_where (const_tree task_impl)
  253. {
  254. int where_int;
  255. tree impl_attr, args, where;
  256. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  257. impl_attr = lookup_attribute (task_implementation_attribute_name,
  258. DECL_ATTRIBUTES (task_impl));
  259. gcc_assert (impl_attr != NULL_TREE);
  260. args = TREE_VALUE (impl_attr);
  261. where = TREE_VALUE (args);
  262. if (!strncmp (TREE_STRING_POINTER (where), "cpu",
  263. TREE_STRING_LENGTH (where)))
  264. where_int = STARPU_CPU;
  265. else if (!strncmp (TREE_STRING_POINTER (where), "opencl",
  266. TREE_STRING_LENGTH (where)))
  267. where_int = STARPU_OPENCL;
  268. else if (!strncmp (TREE_STRING_POINTER (where), "cuda",
  269. TREE_STRING_LENGTH (where)))
  270. where_int = STARPU_CUDA;
  271. else
  272. /* FIXME: Error out? */
  273. where_int = 0;
  274. return where_int;
  275. }
  276. /* Return the task implemented by TASK_IMPL. */
  277. static tree
  278. task_implementation_task (const_tree task_impl)
  279. {
  280. tree impl_attr, args;
  281. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  282. impl_attr = lookup_attribute (task_implementation_attribute_name,
  283. DECL_ATTRIBUTES (task_impl));
  284. gcc_assert (impl_attr != NULL_TREE);
  285. args = TREE_VALUE (impl_attr);
  286. return TREE_VALUE (TREE_CHAIN (args));
  287. }
  288. /* Return the FUNCTION_DECL of the wrapper generated for TASK_IMPL. */
  289. static tree
  290. task_implementation_wrapper (const_tree task_impl)
  291. {
  292. tree attr;
  293. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  294. attr = lookup_attribute (task_implementation_wrapper_attribute_name,
  295. DECL_ATTRIBUTES (task_impl));
  296. gcc_assert (attr != NULL_TREE);
  297. return TREE_VALUE (attr);
  298. }
  299. static void
  300. register_task_attributes (void *gcc_data, void *user_data)
  301. {
  302. static const struct attribute_spec task_attr =
  303. {
  304. task_attribute_name, 0, 0, true, false, false,
  305. handle_task_attribute
  306. };
  307. static const struct attribute_spec task_implementation_attr =
  308. {
  309. task_implementation_attribute_name, 2, 2, true, false, false,
  310. handle_task_implementation_attribute
  311. };
  312. register_attribute (&task_attr);
  313. register_attribute (&task_implementation_attr);
  314. }
  315. /* Return the size in bytes of TYPE. */
  316. static tree
  317. sizeof_type (const_tree type)
  318. {
  319. size_t bits;
  320. bits = TREE_INT_CST_LOW (TYPE_SIZE (type));
  321. return build_int_cstu (size_type_node, bits / 8);
  322. }
  323. /* Return the type of a codelet function, i.e.,
  324. `void (*) (void **, void *)'. */
  325. static tree
  326. build_codelet_wrapper_type (void)
  327. {
  328. tree void_ptr, void_ptr_ptr;
  329. void_ptr = build_pointer_type (void_type_node);
  330. void_ptr_ptr = build_pointer_type (void_ptr);
  331. return build_function_type_list (void_type_node,
  332. void_ptr_ptr, void_ptr,
  333. NULL_TREE);
  334. }
  335. /* Return an identifier for the wrapper of TASK_IMPL, a task
  336. implementation. */
  337. static tree
  338. build_codelet_wrapper_identifier (tree task_impl)
  339. {
  340. static const char suffix[] = ".task_implementation_wrapper";
  341. tree id;
  342. char *cl_name;
  343. const char *task_name;
  344. id = DECL_NAME (task_impl);
  345. task_name = IDENTIFIER_POINTER (id);
  346. cl_name = alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  347. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  348. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  349. return get_identifier (cl_name);
  350. }
  351. /* Return a function of type `void (*) (void **, void *)' that calls function
  352. TASK_IMPL, the FUNCTION_DECL of a task implementation whose prototype may
  353. be arbitrary. */
  354. static tree
  355. build_codelet_wrapper_definition (tree task_impl)
  356. {
  357. location_t loc;
  358. tree task_decl;
  359. loc = DECL_SOURCE_LOCATION (task_impl);
  360. task_decl = task_implementation_task (task_impl);
  361. tree build_scalar_var_chain (tree wrapper_decl)
  362. {
  363. tree types, prev, vars = NULL_TREE;
  364. for (types = task_scalar_parameter_types (task_decl), prev = NULL_TREE;
  365. types != NULL_TREE;
  366. types = TREE_CHAIN (types))
  367. {
  368. tree var;
  369. var = build_decl (loc, VAR_DECL,
  370. create_tmp_var_name ("scalar_arg"),
  371. TREE_VALUE (types));
  372. DECL_CONTEXT (var) = wrapper_decl;
  373. if (prev != NULL_TREE)
  374. TREE_CHAIN (prev) = var;
  375. else
  376. vars = var;
  377. prev = var;
  378. }
  379. return vars;
  380. }
  381. /* Return the body of the wrapper, which unpacks `cl_args' and calls the
  382. user-defined task implementation. */
  383. tree build_body (tree wrapper_decl, tree vars)
  384. {
  385. tree stmts = NULL, call, unpack_fndecl, v;
  386. VEC(tree, gc) *args;
  387. unpack_fndecl = lookup_name (get_identifier ("starpu_unpack_cl_args"));
  388. gcc_assert (unpack_fndecl != NULL_TREE
  389. && TREE_CODE (unpack_fndecl) == FUNCTION_DECL);
  390. append_to_statement_list (build_printf ("entering task wrapper"), &stmts);
  391. /* Build `starpu_unpack_cl_args (cl_args, &var1, &var2, ...)'. */
  392. args = NULL;
  393. VEC_safe_push (tree, gc, args, TREE_CHAIN (DECL_ARGUMENTS (wrapper_decl)));
  394. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  395. VEC_safe_push (tree, gc, args, build_addr (v, wrapper_decl));
  396. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fndecl, args);
  397. append_to_statement_list (call, &stmts);
  398. /* Build `my_task_imply (var1, var2, ...)'. */
  399. args = NULL;
  400. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  401. VEC_safe_push (tree, gc, args, v);
  402. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, task_impl, args);
  403. append_to_statement_list (call, &stmts);
  404. append_to_statement_list (build_printf ("leaving task wrapper"), &stmts);
  405. tree bind;
  406. bind = build3 (BIND_EXPR, void_type_node, vars, stmts,
  407. DECL_INITIAL (wrapper_decl));
  408. TREE_TYPE (bind) = TREE_TYPE (TREE_TYPE (wrapper_decl));
  409. return bind;
  410. }
  411. /* Return the parameter list of the wrapper:
  412. `(void **BUFFERS, void *CL_ARGS)'. */
  413. tree build_parameters (void)
  414. {
  415. tree void_ptr, void_ptr_ptr;
  416. void_ptr = build_pointer_type (void_type_node);
  417. void_ptr_ptr = build_pointer_type (void_ptr);
  418. return chain_trees (build_decl (loc, PARM_DECL,
  419. create_tmp_var_name ("buffers"),
  420. void_ptr_ptr),
  421. build_decl (loc, PARM_DECL,
  422. create_tmp_var_name ("cl_args"),
  423. void_ptr),
  424. NULL_TREE);
  425. }
  426. tree decl, wrapper_name, vars, result;
  427. wrapper_name = build_codelet_wrapper_identifier (task_impl);
  428. decl = build_decl (loc, FUNCTION_DECL, wrapper_name,
  429. build_codelet_wrapper_type ());
  430. vars = build_scalar_var_chain (decl);
  431. DECL_CONTEXT (decl) = NULL_TREE;
  432. DECL_ARGUMENTS (decl) = build_parameters ();
  433. result = build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  434. DECL_ARTIFICIAL (result) = true;
  435. DECL_IGNORED_P (result) = true;
  436. DECL_RESULT (decl) = result;
  437. DECL_INITIAL (decl) = build_block (vars, NULL_TREE, decl, NULL_TREE);
  438. DECL_SAVED_TREE (decl) = build_body (decl, vars);
  439. TREE_PUBLIC (decl) = TREE_PUBLIC (task_impl);
  440. TREE_STATIC (decl) = true;
  441. TREE_USED (decl) = true;
  442. DECL_ARTIFICIAL (decl) = true;
  443. DECL_EXTERNAL (decl) = false;
  444. DECL_UNINLINABLE (decl) = true;
  445. rest_of_decl_compilation (decl, true, 0);
  446. struct function *prev_cfun = cfun;
  447. set_cfun (NULL);
  448. allocate_struct_function (decl, false);
  449. cfun->function_end_locus = DECL_SOURCE_LOCATION (task_impl);
  450. cgraph_finalize_function (decl, false);
  451. /* Mark DECL as needed so that it doesn't get removed by
  452. `cgraph_remove_unreachable_nodes' when it's not public. */
  453. cgraph_mark_needed_node (cgraph_get_node (decl));
  454. set_cfun (prev_cfun);
  455. return decl;
  456. }
  457. /* Define one wrapper function for each implementation of TASK. TASK should
  458. be the FUNCTION_DECL of a task. */
  459. static void
  460. define_codelet_wrappers (tree task)
  461. {
  462. void define (tree task_impl)
  463. {
  464. tree wrapper_def;
  465. wrapper_def = build_codelet_wrapper_definition (task_impl);
  466. DECL_ATTRIBUTES (task_impl) =
  467. tree_cons (get_identifier (task_implementation_wrapper_attribute_name),
  468. wrapper_def,
  469. DECL_ATTRIBUTES (task_impl));
  470. pushdecl (wrapper_def);
  471. }
  472. for_each (define, task_implementation_list (task));
  473. }
  474. /* Return a NODE_IDENTIFIER for the variable holding the `starpu_codelet'
  475. structure associated with TASK_DECL. */
  476. static tree
  477. build_codelet_identifier (tree task_decl)
  478. {
  479. static const char suffix[] = ".codelet";
  480. tree id;
  481. char *cl_name;
  482. const char *task_name;
  483. id = DECL_NAME (task_decl);
  484. task_name = IDENTIFIER_POINTER (id);
  485. cl_name = alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  486. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  487. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  488. return get_identifier (cl_name);
  489. }
  490. static tree
  491. codelet_type (void)
  492. {
  493. tree type_decl;
  494. /* Lookup the `starpu_codelet' struct type. This should succeed since we
  495. push <starpu.h> early on. */
  496. type_decl = lookup_name (get_identifier (codelet_struct_name));
  497. gcc_assert (type_decl != NULL_TREE && TREE_CODE (type_decl) == TYPE_DECL);
  498. return TREE_TYPE (type_decl);
  499. }
  500. /* Return a VAR_DECL that declares a `starpu_codelet' structure for
  501. TASK_DECL. */
  502. static tree
  503. build_codelet_declaration (tree task_decl)
  504. {
  505. tree name, cl_decl;
  506. name = build_codelet_identifier (task_decl);
  507. cl_decl = build_decl (DECL_SOURCE_LOCATION (task_decl),
  508. VAR_DECL, name,
  509. /* c_build_qualified_type (type, TYPE_QUAL_CONST) */
  510. codelet_type ());
  511. DECL_ARTIFICIAL (cl_decl) = true;
  512. TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
  513. TREE_STATIC (cl_decl) = false;
  514. TREE_USED (cl_decl) = true;
  515. DECL_EXTERNAL (cl_decl) = true;
  516. DECL_CONTEXT (cl_decl) = NULL_TREE;
  517. return cl_decl;
  518. }
  519. /* Return a `starpu_codelet' initializer for TASK_DECL. */
  520. static tree
  521. build_codelet_initializer (tree task_decl)
  522. {
  523. tree fields;
  524. fields = TYPE_FIELDS (codelet_type ());
  525. gcc_assert (TREE_CODE (fields) == FIELD_DECL);
  526. tree lookup_field (const char *name)
  527. {
  528. tree fdecl, fname;
  529. fname = get_identifier (name);
  530. for (fdecl = fields;
  531. fdecl != NULL_TREE;
  532. fdecl = TREE_CHAIN (fdecl))
  533. {
  534. if (DECL_NAME (fdecl) == fname)
  535. return fdecl;
  536. }
  537. /* Field NAME wasn't found. */
  538. gcc_assert (false);
  539. }
  540. tree field_initializer (const char *name, tree value)
  541. {
  542. tree field, init;
  543. field = lookup_field (name);
  544. init = make_node (TREE_LIST);
  545. TREE_PURPOSE (init) = field;
  546. TREE_VALUE (init) = fold_convert (TREE_TYPE (field), value);
  547. TREE_CHAIN (init) = NULL_TREE;
  548. return init;
  549. }
  550. tree where_init (tree impls)
  551. {
  552. tree impl;
  553. int where_int = 0;
  554. for (impl = impls;
  555. impl != NULL_TREE;
  556. impl = TREE_CHAIN (impl))
  557. {
  558. tree impl_decl;
  559. impl_decl = TREE_VALUE (impl);
  560. gcc_assert (TREE_CODE (impl_decl) == FUNCTION_DECL);
  561. printf (" `%s'\n", IDENTIFIER_POINTER (DECL_NAME (impl_decl)));
  562. where_int |= task_implementation_where (impl_decl);
  563. }
  564. return build_int_cstu (integer_type_node, where_int);
  565. }
  566. tree implementation_pointer (tree impls, int where)
  567. {
  568. tree impl;
  569. for (impl = impls;
  570. impl != NULL_TREE;
  571. impl = TREE_CHAIN (impl))
  572. {
  573. tree impl_decl;
  574. impl_decl = TREE_VALUE (impl);
  575. if (task_implementation_where (impl_decl) == where)
  576. {
  577. /* Return a pointer to the wrapper of IMPL_DECL. */
  578. tree addr = build_addr (task_implementation_wrapper (impl_decl),
  579. NULL_TREE);
  580. return addr;
  581. }
  582. }
  583. /* Default to a NULL pointer. */
  584. return build_int_cstu (build_pointer_type (void_type_node), 0);
  585. }
  586. printf ("implementations for `%s':\n",
  587. IDENTIFIER_POINTER (DECL_NAME (task_decl)));
  588. tree impls, inits;
  589. impls = task_implementation_list (task_decl);
  590. inits =
  591. chain_trees (field_initializer ("where", where_init (impls)),
  592. field_initializer ("cpu_func",
  593. implementation_pointer (impls, STARPU_CPU)),
  594. field_initializer ("opencl_func",
  595. implementation_pointer (impls,
  596. STARPU_OPENCL)),
  597. /* field_initializer ("cuda_func", */
  598. /* implementation_pointer (impls, */
  599. /* STARPU_CUDA)), */
  600. NULL_TREE);
  601. return build_constructor_from_list (codelet_type (), inits);
  602. }
  603. /* Return the VAR_DECL that defines a `starpu_codelet' structure for
  604. TASK_DECL. The VAR_DECL is assumed to already exists, so it must not be
  605. pushed again. */
  606. static tree
  607. define_codelet (tree task_decl)
  608. {
  609. /* Generate a wrapper function for each implementation of TASK_DECL that
  610. does all the packing/unpacking. */
  611. define_codelet_wrappers (task_decl);
  612. /* Retrieve the declaration of the `starpu_codelet' object. */
  613. tree cl_def;
  614. cl_def = lookup_name (build_codelet_identifier (task_decl));
  615. gcc_assert (cl_def != NULL_TREE && TREE_CODE (cl_def) == VAR_DECL);
  616. /* Turn the codelet declaration into a definition. */
  617. TREE_STATIC (cl_def) = true;
  618. DECL_EXTERNAL (cl_def) = false;
  619. DECL_INITIAL (cl_def) = build_codelet_initializer (task_decl);
  620. return cl_def;
  621. }
  622. /* Define the `starpu_codelet' structure for the task implemented by
  623. IMPL_DECL if we're in the right compilation unit, i.e., is IMPL_DECL is a
  624. "cpu" task implementation. */
  625. static void
  626. maybe_define_codelet (tree impl_decl)
  627. {
  628. if (task_implementation_where (impl_decl) == STARPU_CPU)
  629. /* IMPL_DECL is a "cpu" implementation of some task, so define the
  630. codelet structure in this compilation unit. */
  631. define_codelet (task_implementation_task (impl_decl));
  632. }
  633. static void
  634. handle_pre_genericize (void *gcc_data, void *user_data)
  635. {
  636. tree fndecl = (tree) gcc_data;
  637. gcc_assert (fndecl != NULL_TREE && TREE_CODE (fndecl) == FUNCTION_DECL);
  638. gcc_assert (lookup_name (DECL_NAME (fndecl)) == fndecl);
  639. if (lookup_attribute (task_implementation_attribute_name,
  640. DECL_ATTRIBUTES (fndecl)))
  641. maybe_define_codelet (fndecl);
  642. }
  643. /* Build a call to `starpu_insert_task' for TASK_DECL, which will replace
  644. CALL. */
  645. static gimple
  646. build_task_submission (tree task_decl, gimple call)
  647. {
  648. size_t n;
  649. VEC(tree, heap) *args = NULL;
  650. /* The first argument will be a pointer to the codelet. */
  651. VEC_safe_push (tree, heap, args,
  652. build_addr (task_codelet_declaration (task_decl),
  653. current_function_decl));
  654. for (n = 0; n < gimple_call_num_args (call); n++)
  655. {
  656. tree arg;
  657. arg = gimple_call_arg (call, n);
  658. if (POINTER_TYPE_P (TREE_TYPE (arg)))
  659. {
  660. /* A pointer: the arguments will be:
  661. `STARPU_RW, ptr' or similar. */
  662. gcc_assert (!"not implemented yet");
  663. }
  664. else
  665. {
  666. /* A scalar: the arguments will be:
  667. `STARPU_VALUE, &scalar, sizeof (scalar)'. */
  668. /* XXX: Currently the argument has to be a variable. */
  669. gcc_assert (TREE_CODE (arg) == VAR_DECL);
  670. VEC_safe_push (tree, heap, args,
  671. build_int_cst (integer_type_node, STARPU_VALUE));
  672. VEC_safe_push (tree, heap, args,
  673. build_addr (arg, current_function_decl));
  674. VEC_safe_push (tree, heap, args,
  675. sizeof_type (TREE_TYPE (arg)));
  676. }
  677. }
  678. /* Push the terminating zero. */
  679. VEC_safe_push (tree, heap, args,
  680. build_int_cst (integer_type_node, 0));
  681. return gimple_build_call_vec (insert_task_fn, args);
  682. }
  683. static unsigned int
  684. lower_starpu (void)
  685. {
  686. tree fndecl;
  687. const struct cgraph_node *cgraph;
  688. const struct cgraph_edge *callee;
  689. fndecl = current_function_decl;
  690. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  691. /* This pass should occur after `build_cgraph_edges'. */
  692. cgraph = cgraph_get_node (fndecl);
  693. gcc_assert (cgraph != NULL);
  694. printf ("%s: %s -> %p (callees: %p)\n", __func__,
  695. IDENTIFIER_POINTER (DECL_NAME (fndecl)),
  696. cgraph, cgraph ? cgraph->callees : NULL);
  697. for (callee = cgraph->callees;
  698. callee != NULL;
  699. callee = callee->next_callee)
  700. {
  701. gcc_assert (callee->callee != NULL);
  702. tree callee_decl;
  703. const char *callee_name;
  704. callee_decl = callee->callee->decl;
  705. callee_name = IDENTIFIER_POINTER (DECL_NAME (callee_decl));
  706. printf ("%s: callee `%s'\n", __func__, callee_name);
  707. if (lookup_attribute (task_attribute_name,
  708. DECL_ATTRIBUTES (callee_decl)))
  709. {
  710. printf ("%s: callee is a task\n", __func__);
  711. gimple call_site, submission;
  712. gimple_stmt_iterator gsi;
  713. call_site = callee->call_stmt;
  714. gsi = gsi_for_stmt (call_site);
  715. submission = build_task_submission (callee_decl, call_site);
  716. gsi_replace (&gsi, submission, true);
  717. gimple_set_block (submission, gimple_block (call_site));
  718. rebuild_cgraph_edges ();
  719. }
  720. }
  721. return 0;
  722. }
  723. static struct opt_pass pass_lower_starpu =
  724. {
  725. .type = GIMPLE_PASS,
  726. .name = "pass_lower_starpu",
  727. .execute = lower_starpu,
  728. /* The rest is zeroed. */
  729. };
  730. /* Initialization. */
  731. static void
  732. define_cpp_macros (void *gcc_data, void *user_data)
  733. {
  734. cpp_define (parse_in, "STARPU_GCC_PLUGIN=0");
  735. cpp_push_include (parse_in, "starpu.h");
  736. }
  737. int
  738. plugin_init (struct plugin_name_args *plugin_info,
  739. struct plugin_gcc_version *version)
  740. {
  741. if (!plugin_default_version_check (version, &gcc_version))
  742. return 1;
  743. register_callback (plugin_name, PLUGIN_START_UNIT,
  744. define_cpp_macros, NULL);
  745. register_callback (plugin_name, PLUGIN_PRAGMAS,
  746. register_pragmas, NULL);
  747. register_callback (plugin_name, PLUGIN_ATTRIBUTES,
  748. register_task_attributes, NULL);
  749. register_callback (plugin_name, PLUGIN_PRE_GENERICIZE,
  750. handle_pre_genericize, NULL);
  751. /* Register our pass so that it happens after `build_cgraph_edges' has been
  752. done. */
  753. struct register_pass_info pass_info =
  754. {
  755. .pass = &pass_lower_starpu,
  756. .reference_pass_name = "*build_cgraph_edges",
  757. .ref_pass_instance_number = 1,
  758. .pos_op = PASS_POS_INSERT_AFTER
  759. };
  760. register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP,
  761. NULL, &pass_info);
  762. return 0;
  763. }