starpu.c 27 KB

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