starpu.c 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291
  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 <tree-flow.h>
  30. #include <cgraph.h>
  31. #include <gimple.h>
  32. #include <toplev.h>
  33. #include <stdio.h>
  34. #include <starpu.h> /* for `STARPU_CPU' & co. */
  35. /* The name of this plug-in. */
  36. static const char plugin_name[] = "starpu";
  37. /* Names of public attributes. */
  38. static const char task_attribute_name[] = "task";
  39. static const char task_implementation_attribute_name[] = "task_implementation";
  40. /* Names of attributes used internally. */
  41. static const char task_codelet_attribute_name[] = ".codelet";
  42. static const char task_implementation_list_attribute_name[] =
  43. ".task_implementation_list";
  44. static const char task_implementation_wrapper_attribute_name[] =
  45. ".task_implementation_wrapper";
  46. /* Names of data structures defined in <starpu.h>. */
  47. static const char codelet_struct_name[] = "starpu_codelet";
  48. static const char task_struct_name[] = "starpu_task";
  49. /* The `starpu_insert_task' and `starpu_data_lookup' FUNCTION_DECLs. */
  50. static tree insert_task_fn, data_lookup_fn;
  51. /* Forward declarations. */
  52. static tree build_codelet_declaration (tree task_decl);
  53. /* Useful code backported from GCC 4.6. */
  54. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_ARRAY
  55. static tree
  56. build_call_expr_loc_array (location_t loc, tree fndecl, int n, tree *argarray)
  57. {
  58. tree fntype = TREE_TYPE (fndecl);
  59. tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
  60. return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
  61. }
  62. #endif
  63. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_VEC
  64. static tree
  65. build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
  66. {
  67. return build_call_expr_loc_array (loc, fndecl, VEC_length (tree, vec),
  68. VEC_address (tree, vec));
  69. }
  70. #endif
  71. /* Helpers. */
  72. /* Build a reference to the INDEXth element of ARRAY. `build_array_ref' is
  73. not exported, so we roll our own. */
  74. static tree
  75. array_ref (tree array, size_t index)
  76. {
  77. gcc_assert (POINTER_TYPE_P (TREE_TYPE (array)));
  78. tree pointer_plus_offset =
  79. index > 0
  80. ? build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR,
  81. array,
  82. build_int_cstu (integer_type_node, index),
  83. 0)
  84. : array;
  85. gcc_assert (POINTER_TYPE_P (TREE_TYPE (pointer_plus_offset)));
  86. return build_indirect_ref (UNKNOWN_LOCATION,
  87. pointer_plus_offset,
  88. RO_ARRAY_INDEXING);
  89. }
  90. /* Like `build_constructor_from_list', but sort VALS according to their
  91. offset in struct TYPE. Inspired by `gnat_build_constructor'. */
  92. static tree
  93. build_constructor_from_unsorted_list (tree type, tree vals)
  94. {
  95. int compare_elmt_bitpos (const void *rt1, const void *rt2)
  96. {
  97. const constructor_elt *elmt1 = (constructor_elt *) rt1;
  98. const constructor_elt *elmt2 = (constructor_elt *) rt2;
  99. const_tree field1 = elmt1->index;
  100. const_tree field2 = elmt2->index;
  101. int ret
  102. = tree_int_cst_compare (bit_position (field1), bit_position (field2));
  103. return ret ? ret : (int) (DECL_UID (field1) - DECL_UID (field2));
  104. }
  105. tree t;
  106. VEC(constructor_elt,gc) *v = NULL;
  107. if (vals)
  108. {
  109. v = VEC_alloc (constructor_elt, gc, list_length (vals));
  110. for (t = vals; t; t = TREE_CHAIN (t))
  111. CONSTRUCTOR_APPEND_ELT (v, TREE_PURPOSE (t), TREE_VALUE (t));
  112. }
  113. /* Sort field initializers by field offset. */
  114. VEC_qsort (constructor_elt, v, compare_elmt_bitpos);
  115. return build_constructor (type, v);
  116. }
  117. /* Debugging helpers. */
  118. static tree build_printf (const char *, ...)
  119. __attribute__ ((format (printf, 1, 2)));
  120. static tree
  121. build_printf (const char *fmt, ...)
  122. {
  123. tree call;
  124. char *str;
  125. va_list args;
  126. va_start (args, fmt);
  127. vasprintf (&str, fmt, args);
  128. call = build_call_expr (built_in_decls[BUILT_IN_PUTS], 1,
  129. build_string_literal (strlen (str) + 1, str));
  130. free (str);
  131. va_end (args);
  132. return call;
  133. }
  134. static tree
  135. build_hello_world (void)
  136. {
  137. return build_printf ("Hello, StarPU!");
  138. }
  139. /* List and vector utilities, à la SRFI-1. */
  140. static tree chain_trees (tree t, ...)
  141. __attribute__ ((sentinel));
  142. static tree
  143. chain_trees (tree t, ...)
  144. {
  145. va_list args;
  146. va_start (args, t);
  147. tree next, prev = t;
  148. for (prev = t, next = va_arg (args, tree);
  149. next != NULL_TREE;
  150. prev = next, next = va_arg (args, tree))
  151. TREE_CHAIN (prev) = next;
  152. va_end (args);
  153. return t;
  154. }
  155. static tree
  156. filter (bool (*pred) (const_tree), tree t)
  157. {
  158. tree result, lst;
  159. gcc_assert (TREE_CODE (t) == TREE_LIST);
  160. result = NULL_TREE;
  161. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  162. {
  163. if (pred (lst))
  164. result = tree_cons (TREE_PURPOSE (lst), TREE_VALUE (lst),
  165. result);
  166. }
  167. return nreverse (result);
  168. }
  169. static void
  170. for_each (void (*func) (tree), tree t)
  171. {
  172. tree lst;
  173. gcc_assert (TREE_CODE (t) == TREE_LIST);
  174. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  175. func (TREE_VALUE (lst));
  176. }
  177. /* Pragmas. */
  178. #define STARPU_PRAGMA_NAME_SPACE "starpu"
  179. static void
  180. handle_pragma_hello (struct cpp_reader *reader)
  181. {
  182. add_stmt (build_hello_world ());
  183. }
  184. static void
  185. handle_pragma_wait (struct cpp_reader *reader)
  186. {
  187. tree fndecl;
  188. fndecl = lookup_name (get_identifier ("starpu_task_wait_for_all"));
  189. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  190. add_stmt (build_call_expr (fndecl, 0));
  191. }
  192. static void
  193. register_pragmas (void *gcc_data, void *user_data)
  194. {
  195. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "hello",
  196. handle_pragma_hello);
  197. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "wait",
  198. handle_pragma_wait);
  199. }
  200. /* Attributes. */
  201. /* Handle the `task' function attribute. */
  202. static tree
  203. handle_task_attribute (tree *node, tree name, tree args,
  204. int flags, bool *no_add_attrs)
  205. {
  206. tree fn;
  207. fn = *node;
  208. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  209. /* This is a function declaration for something local to this
  210. translation unit, so add the `task' attribute to FN. */
  211. *no_add_attrs = false;
  212. /* Add an empty `task_implementation_list' attribute. */
  213. DECL_ATTRIBUTES (fn) =
  214. tree_cons (get_identifier (task_implementation_list_attribute_name),
  215. NULL_TREE,
  216. NULL_TREE);
  217. /* Push a declaration for the corresponding `starpu_codelet' object and add
  218. it as an attribute of FN. */
  219. tree cl = build_codelet_declaration (fn);
  220. DECL_ATTRIBUTES (fn) =
  221. tree_cons (get_identifier (task_codelet_attribute_name), cl,
  222. DECL_ATTRIBUTES (fn));
  223. pushdecl (cl);
  224. TREE_USED (fn) = true;
  225. /* Lookup the useful StarPU functions in the global scope (this can't be
  226. done from `lower_starpu'.)
  227. XXX: Move it in a pass of its own. */
  228. #define LOOKUP_STARPU_FUNCTION(var, name) \
  229. if ((var) == NULL_TREE) \
  230. { \
  231. (var) = lookup_name (get_identifier (name)); \
  232. gcc_assert ((var) != NULL_TREE && TREE_CODE (var) == FUNCTION_DECL); \
  233. }
  234. LOOKUP_STARPU_FUNCTION (insert_task_fn, "starpu_insert_task");
  235. LOOKUP_STARPU_FUNCTION (data_lookup_fn, "starpu_data_lookup");
  236. #undef LOOKUP_STARPU_FUNCTION
  237. return NULL_TREE;
  238. }
  239. /* Handle the `task_implementation (WHERE, TASK)' attribute. WHERE is a
  240. string constant ("cpu", "cuda", etc.), and TASK is the identifier of a
  241. function declared with the `task' attribute. */
  242. static tree
  243. handle_task_implementation_attribute (tree *node, tree name, tree args,
  244. int flags, bool *no_add_attrs)
  245. {
  246. tree fn, where, task_decl;
  247. /* FIXME: Use error nodes instead of `gcc_assert'. */
  248. /* FIXME:TODO: To change the order to (TASK, WHERE):
  249. tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
  250. tree cleanup_decl = lookup_name (cleanup_id);
  251. */
  252. fn = *node;
  253. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  254. where = TREE_VALUE (args);
  255. gcc_assert (TREE_CODE (where) == STRING_CST);
  256. task_decl = TREE_VALUE (TREE_CHAIN (args));
  257. gcc_assert (TREE_CODE (task_decl) == FUNCTION_DECL);
  258. gcc_assert (lookup_attribute (task_attribute_name,
  259. DECL_ATTRIBUTES (task_decl)));
  260. gcc_assert (TYPE_CANONICAL (TREE_TYPE (fn))
  261. == TYPE_CANONICAL (TREE_TYPE (task_decl))
  262. && TYPE_CANONICAL (TREE_TYPE (fn)) != NULL_TREE);
  263. /* Add FN to the list of implementations of TASK_DECL. */
  264. tree attr, impls;
  265. attr = lookup_attribute (task_implementation_list_attribute_name,
  266. DECL_ATTRIBUTES (task_decl));
  267. impls = tree_cons (NULL_TREE, fn, TREE_VALUE (attr));
  268. DECL_ATTRIBUTES (task_decl) =
  269. tree_cons (get_identifier (task_implementation_list_attribute_name),
  270. impls,
  271. remove_attribute (task_implementation_list_attribute_name,
  272. DECL_ATTRIBUTES (task_decl)));
  273. TREE_USED (fn) = true;
  274. /* Keep the attribute. */
  275. *no_add_attrs = false;
  276. return NULL_TREE;
  277. }
  278. /* Return the declaration of the `starpu_codelet' variable associated with
  279. TASK_DECL. */
  280. static tree
  281. task_codelet_declaration (const_tree task_decl)
  282. {
  283. tree cl_attr;
  284. cl_attr = lookup_attribute (task_codelet_attribute_name,
  285. DECL_ATTRIBUTES (task_decl));
  286. gcc_assert (cl_attr != NULL_TREE);
  287. return TREE_VALUE (cl_attr);
  288. }
  289. /* Return the list of implementations of TASK_DECL. */
  290. static tree
  291. task_implementation_list (const_tree task_decl)
  292. {
  293. tree attr;
  294. attr = lookup_attribute (task_implementation_list_attribute_name,
  295. DECL_ATTRIBUTES (task_decl));
  296. return TREE_VALUE (attr);
  297. }
  298. /* Return the list of scalar parameter types of TASK_DECL. */
  299. static tree
  300. task_scalar_parameter_types (const_tree task_decl)
  301. {
  302. bool is_scalar (const_tree item)
  303. {
  304. return (!POINTER_TYPE_P (TREE_VALUE (item))
  305. && !VOID_TYPE_P (TREE_VALUE (item)));
  306. }
  307. return filter (is_scalar, TYPE_ARG_TYPES (TREE_TYPE (task_decl)));
  308. }
  309. /* Return the list of pointer parameter types of TASK_DECL. */
  310. static tree
  311. task_pointer_parameter_types (const_tree task_decl)
  312. {
  313. bool is_pointer (const_tree item)
  314. {
  315. return POINTER_TYPE_P (TREE_VALUE (item));
  316. }
  317. return filter (is_pointer, TYPE_ARG_TYPES (TREE_TYPE (task_decl)));
  318. }
  319. /* Return a value indicating where TASK_IMPL should execute (`STARPU_CPU',
  320. `STARPU_CUDA', etc.). */
  321. static int
  322. task_implementation_where (const_tree task_impl)
  323. {
  324. int where_int;
  325. tree impl_attr, args, where;
  326. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  327. impl_attr = lookup_attribute (task_implementation_attribute_name,
  328. DECL_ATTRIBUTES (task_impl));
  329. gcc_assert (impl_attr != NULL_TREE);
  330. args = TREE_VALUE (impl_attr);
  331. where = TREE_VALUE (args);
  332. if (!strncmp (TREE_STRING_POINTER (where), "cpu",
  333. TREE_STRING_LENGTH (where)))
  334. where_int = STARPU_CPU;
  335. else if (!strncmp (TREE_STRING_POINTER (where), "opencl",
  336. TREE_STRING_LENGTH (where)))
  337. where_int = STARPU_OPENCL;
  338. else if (!strncmp (TREE_STRING_POINTER (where), "cuda",
  339. TREE_STRING_LENGTH (where)))
  340. where_int = STARPU_CUDA;
  341. else
  342. /* FIXME: Error out? */
  343. where_int = 0;
  344. return where_int;
  345. }
  346. /* Return the task implemented by TASK_IMPL. */
  347. static tree
  348. task_implementation_task (const_tree task_impl)
  349. {
  350. tree impl_attr, args;
  351. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  352. impl_attr = lookup_attribute (task_implementation_attribute_name,
  353. DECL_ATTRIBUTES (task_impl));
  354. gcc_assert (impl_attr != NULL_TREE);
  355. args = TREE_VALUE (impl_attr);
  356. return TREE_VALUE (TREE_CHAIN (args));
  357. }
  358. /* Return the FUNCTION_DECL of the wrapper generated for TASK_IMPL. */
  359. static tree
  360. task_implementation_wrapper (const_tree task_impl)
  361. {
  362. tree attr;
  363. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  364. attr = lookup_attribute (task_implementation_wrapper_attribute_name,
  365. DECL_ATTRIBUTES (task_impl));
  366. gcc_assert (attr != NULL_TREE);
  367. return TREE_VALUE (attr);
  368. }
  369. static void
  370. register_task_attributes (void *gcc_data, void *user_data)
  371. {
  372. static const struct attribute_spec task_attr =
  373. {
  374. task_attribute_name, 0, 0, true, false, false,
  375. handle_task_attribute
  376. };
  377. static const struct attribute_spec task_implementation_attr =
  378. {
  379. task_implementation_attribute_name, 2, 2, true, false, false,
  380. handle_task_implementation_attribute
  381. };
  382. register_attribute (&task_attr);
  383. register_attribute (&task_implementation_attr);
  384. }
  385. /* Return the type of a codelet function, i.e.,
  386. `void (*) (void **, void *)'. */
  387. static tree
  388. build_codelet_wrapper_type (void)
  389. {
  390. tree void_ptr_ptr;
  391. void_ptr_ptr = build_pointer_type (ptr_type_node);
  392. return build_function_type_list (void_type_node,
  393. void_ptr_ptr, ptr_type_node,
  394. NULL_TREE);
  395. }
  396. /* Return an identifier for the wrapper of TASK_IMPL, a task
  397. implementation. */
  398. static tree
  399. build_codelet_wrapper_identifier (tree task_impl)
  400. {
  401. static const char suffix[] = ".task_implementation_wrapper";
  402. tree id;
  403. char *cl_name;
  404. const char *task_name;
  405. id = DECL_NAME (task_impl);
  406. task_name = IDENTIFIER_POINTER (id);
  407. cl_name = alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  408. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  409. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  410. return get_identifier (cl_name);
  411. }
  412. /* Return a function of type `void (*) (void **, void *)' that calls function
  413. TASK_IMPL, the FUNCTION_DECL of a task implementation whose prototype may
  414. be arbitrary. */
  415. static tree
  416. build_codelet_wrapper_definition (tree task_impl)
  417. {
  418. location_t loc;
  419. tree task_decl;
  420. loc = DECL_SOURCE_LOCATION (task_impl);
  421. task_decl = task_implementation_task (task_impl);
  422. tree build_var_chain (tree type_list, const char *seed, tree wrapper_decl)
  423. {
  424. tree types, prev, vars = NULL_TREE;
  425. for (types = type_list, prev = NULL_TREE;
  426. types != NULL_TREE;
  427. types = TREE_CHAIN (types))
  428. {
  429. tree var;
  430. var = build_decl (loc, VAR_DECL,
  431. create_tmp_var_name (seed),
  432. TREE_VALUE (types));
  433. DECL_CONTEXT (var) = wrapper_decl;
  434. DECL_ARTIFICIAL (var) = true;
  435. if (prev != NULL_TREE)
  436. TREE_CHAIN (prev) = var;
  437. else
  438. vars = var;
  439. prev = var;
  440. }
  441. return vars;
  442. }
  443. /* Return the body of the wrapper, which unpacks `cl_args' and calls the
  444. user-defined task implementation. */
  445. tree build_body (tree wrapper_decl, tree vars)
  446. {
  447. tree stmts = NULL, call, unpack_fndecl, v;
  448. VEC(tree, gc) *args;
  449. unpack_fndecl = lookup_name (get_identifier ("starpu_unpack_cl_args"));
  450. gcc_assert (unpack_fndecl != NULL_TREE
  451. && TREE_CODE (unpack_fndecl) == FUNCTION_DECL);
  452. /* Build `var0 = STARPU_VECTOR_GET_PTR (buffers[0]); ...'. */
  453. size_t index = 0;
  454. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  455. {
  456. if (POINTER_TYPE_P (TREE_TYPE (v)))
  457. {
  458. /* Compute `void *VDESC = buffers[0];'. */
  459. tree vdesc = array_ref (DECL_ARGUMENTS (wrapper_decl), index);
  460. /* Below we assume (1) that pointer arguments are registered as
  461. StarPU vector handles, and (2) that the `ptr' field is at
  462. offset 0 of `starpu_vector_interface_s'. The latter allows us
  463. to use a simple pointer dereference instead of expanding
  464. `STARPU_VECTOR_GET_PTR'. */
  465. assert (offsetof (struct starpu_vector_interface_s, ptr) == 0);
  466. /* Compute `type *PTR = *(type **) VDESC;'. */
  467. tree ptr = build1 (INDIRECT_REF,
  468. build_pointer_type (TREE_TYPE (v)),
  469. vdesc);
  470. append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (v),
  471. v, ptr),
  472. &stmts);
  473. index++;
  474. }
  475. }
  476. /* Build `starpu_unpack_cl_args (cl_args, &var1, &var2, ...)'. */
  477. args = NULL;
  478. VEC_safe_push (tree, gc, args, TREE_CHAIN (DECL_ARGUMENTS (wrapper_decl)));
  479. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  480. {
  481. if (!POINTER_TYPE_P (TREE_TYPE (v)))
  482. VEC_safe_push (tree, gc, args, build_addr (v, wrapper_decl));
  483. }
  484. if (VEC_length (tree, args) > 1)
  485. {
  486. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fndecl, args);
  487. TREE_SIDE_EFFECTS (call) = 1;
  488. append_to_statement_list (call, &stmts);
  489. }
  490. /* Build `my_task_impl (var1, var2, ...)'. */
  491. args = NULL;
  492. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  493. VEC_safe_push (tree, gc, args, v);
  494. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, task_impl, args);
  495. TREE_SIDE_EFFECTS (call) = 1;
  496. append_to_statement_list (call, &stmts);
  497. tree bind;
  498. bind = build3 (BIND_EXPR, void_type_node, vars, stmts,
  499. DECL_INITIAL (wrapper_decl));
  500. TREE_TYPE (bind) = TREE_TYPE (TREE_TYPE (wrapper_decl));
  501. return bind;
  502. }
  503. /* Return the parameter list of the wrapper:
  504. `(void **BUFFERS, void *CL_ARGS)'. */
  505. tree build_parameters (tree wrapper_decl)
  506. {
  507. tree param1, param2;
  508. param1 = build_decl (loc, PARM_DECL,
  509. create_tmp_var_name ("buffers"),
  510. build_pointer_type (ptr_type_node));
  511. DECL_ARG_TYPE (param1) = ptr_type_node;
  512. DECL_CONTEXT (param1) = wrapper_decl;
  513. TREE_USED (param1) = true;
  514. param2 = build_decl (loc, PARM_DECL,
  515. create_tmp_var_name ("cl_args"),
  516. ptr_type_node);
  517. DECL_ARG_TYPE (param2) = ptr_type_node;
  518. DECL_CONTEXT (param2) = wrapper_decl;
  519. TREE_USED (param2) = true;
  520. return chainon (param1, param2);
  521. }
  522. tree decl, wrapper_name, vars, result;
  523. wrapper_name = build_codelet_wrapper_identifier (task_impl);
  524. decl = build_decl (loc, FUNCTION_DECL, wrapper_name,
  525. build_codelet_wrapper_type ());
  526. /* FIXME: This won't work if scalar and pointer params are
  527. interspersed. */
  528. vars = chainon (build_var_chain (task_scalar_parameter_types (task_decl),
  529. "scalar_arg", decl),
  530. build_var_chain (task_pointer_parameter_types (task_decl),
  531. "pointer_arg", decl));
  532. DECL_CONTEXT (decl) = NULL_TREE;
  533. DECL_ARGUMENTS (decl) = build_parameters (decl);
  534. result = build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  535. DECL_CONTEXT (result) = decl;
  536. DECL_ARTIFICIAL (result) = true;
  537. DECL_IGNORED_P (result) = true;
  538. DECL_RESULT (decl) = result;
  539. DECL_INITIAL (decl) = build_block (vars, NULL_TREE, decl, NULL_TREE);
  540. DECL_SAVED_TREE (decl) = build_body (decl, vars);
  541. TREE_PUBLIC (decl) = TREE_PUBLIC (task_impl);
  542. TREE_STATIC (decl) = true;
  543. TREE_USED (decl) = true;
  544. DECL_ARTIFICIAL (decl) = true;
  545. DECL_EXTERNAL (decl) = false;
  546. DECL_UNINLINABLE (decl) = true;
  547. rest_of_decl_compilation (decl, true, 0);
  548. struct function *prev_cfun = cfun;
  549. set_cfun (NULL);
  550. allocate_struct_function (decl, false);
  551. cfun->function_end_locus = DECL_SOURCE_LOCATION (task_impl);
  552. cgraph_finalize_function (decl, false);
  553. /* Mark DECL as needed so that it doesn't get removed by
  554. `cgraph_remove_unreachable_nodes' when it's not public. */
  555. cgraph_mark_needed_node (cgraph_get_node (decl));
  556. set_cfun (prev_cfun);
  557. return decl;
  558. }
  559. /* Define one wrapper function for each implementation of TASK. TASK should
  560. be the FUNCTION_DECL of a task. */
  561. static void
  562. define_codelet_wrappers (tree task)
  563. {
  564. void define (tree task_impl)
  565. {
  566. tree wrapper_def;
  567. wrapper_def = build_codelet_wrapper_definition (task_impl);
  568. DECL_ATTRIBUTES (task_impl) =
  569. tree_cons (get_identifier (task_implementation_wrapper_attribute_name),
  570. wrapper_def,
  571. DECL_ATTRIBUTES (task_impl));
  572. pushdecl (wrapper_def);
  573. }
  574. for_each (define, task_implementation_list (task));
  575. }
  576. /* Return a NODE_IDENTIFIER for the variable holding the `starpu_codelet'
  577. structure associated with TASK_DECL. */
  578. static tree
  579. build_codelet_identifier (tree task_decl)
  580. {
  581. static const char suffix[] = ".codelet";
  582. tree id;
  583. char *cl_name;
  584. const char *task_name;
  585. id = DECL_NAME (task_decl);
  586. task_name = IDENTIFIER_POINTER (id);
  587. cl_name = alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  588. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  589. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  590. return get_identifier (cl_name);
  591. }
  592. static tree
  593. codelet_type (void)
  594. {
  595. tree type_decl;
  596. /* Lookup the `starpu_codelet' struct type. This should succeed since we
  597. push <starpu.h> early on. */
  598. type_decl = lookup_name (get_identifier (codelet_struct_name));
  599. gcc_assert (type_decl != NULL_TREE && TREE_CODE (type_decl) == TYPE_DECL);
  600. return TREE_TYPE (type_decl);
  601. }
  602. /* Return a VAR_DECL that declares a `starpu_codelet' structure for
  603. TASK_DECL. */
  604. static tree
  605. build_codelet_declaration (tree task_decl)
  606. {
  607. tree name, cl_decl;
  608. name = build_codelet_identifier (task_decl);
  609. cl_decl = build_decl (DECL_SOURCE_LOCATION (task_decl),
  610. VAR_DECL, name,
  611. /* c_build_qualified_type (type, TYPE_QUAL_CONST) */
  612. codelet_type ());
  613. DECL_ARTIFICIAL (cl_decl) = true;
  614. TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
  615. TREE_STATIC (cl_decl) = false;
  616. TREE_USED (cl_decl) = true;
  617. DECL_EXTERNAL (cl_decl) = true;
  618. DECL_CONTEXT (cl_decl) = NULL_TREE;
  619. return cl_decl;
  620. }
  621. /* Return a `starpu_codelet' initializer for TASK_DECL. */
  622. static tree
  623. build_codelet_initializer (tree task_decl)
  624. {
  625. tree fields;
  626. fields = TYPE_FIELDS (codelet_type ());
  627. gcc_assert (TREE_CODE (fields) == FIELD_DECL);
  628. tree lookup_field (const char *name)
  629. {
  630. tree fdecl, fname;
  631. fname = get_identifier (name);
  632. for (fdecl = fields;
  633. fdecl != NULL_TREE;
  634. fdecl = TREE_CHAIN (fdecl))
  635. {
  636. if (DECL_NAME (fdecl) == fname)
  637. return fdecl;
  638. }
  639. /* Field NAME wasn't found. */
  640. gcc_assert (false);
  641. }
  642. tree field_initializer (const char *name, tree value)
  643. {
  644. tree field, init;
  645. field = lookup_field (name);
  646. init = make_node (TREE_LIST);
  647. TREE_PURPOSE (init) = field;
  648. TREE_VALUE (init) = fold_convert (TREE_TYPE (field), value);
  649. TREE_CHAIN (init) = NULL_TREE;
  650. return init;
  651. }
  652. tree where_init (tree impls)
  653. {
  654. tree impl;
  655. int where_int = 0;
  656. for (impl = impls;
  657. impl != NULL_TREE;
  658. impl = TREE_CHAIN (impl))
  659. {
  660. tree impl_decl;
  661. impl_decl = TREE_VALUE (impl);
  662. gcc_assert (TREE_CODE (impl_decl) == FUNCTION_DECL);
  663. printf (" `%s'\n", IDENTIFIER_POINTER (DECL_NAME (impl_decl)));
  664. where_int |= task_implementation_where (impl_decl);
  665. }
  666. return build_int_cstu (integer_type_node, where_int);
  667. }
  668. tree implementation_pointer (tree impls, int where)
  669. {
  670. tree impl;
  671. for (impl = impls;
  672. impl != NULL_TREE;
  673. impl = TREE_CHAIN (impl))
  674. {
  675. tree impl_decl;
  676. impl_decl = TREE_VALUE (impl);
  677. if (task_implementation_where (impl_decl) == where)
  678. {
  679. /* Return a pointer to the wrapper of IMPL_DECL. */
  680. tree addr = build_addr (task_implementation_wrapper (impl_decl),
  681. NULL_TREE);
  682. return addr;
  683. }
  684. }
  685. /* Default to a NULL pointer. */
  686. return build_int_cstu (build_pointer_type (void_type_node), 0);
  687. }
  688. tree pointer_arg_count (void)
  689. {
  690. size_t len;
  691. len = list_length (task_pointer_parameter_types (task_decl));
  692. return build_int_cstu (integer_type_node, len);
  693. }
  694. printf ("implementations for `%s':\n",
  695. IDENTIFIER_POINTER (DECL_NAME (task_decl)));
  696. tree impls, inits;
  697. impls = task_implementation_list (task_decl);
  698. inits =
  699. chain_trees (field_initializer ("where", where_init (impls)),
  700. field_initializer ("nbuffers", pointer_arg_count ()),
  701. field_initializer ("cpu_func",
  702. implementation_pointer (impls, STARPU_CPU)),
  703. field_initializer ("opencl_func",
  704. implementation_pointer (impls,
  705. STARPU_OPENCL)),
  706. field_initializer ("cuda_func",
  707. implementation_pointer (impls,
  708. STARPU_CUDA)),
  709. NULL_TREE);
  710. return build_constructor_from_unsorted_list (codelet_type (), inits);
  711. }
  712. /* Return the VAR_DECL that defines a `starpu_codelet' structure for
  713. TASK_DECL. The VAR_DECL is assumed to already exists, so it must not be
  714. pushed again. */
  715. static tree
  716. define_codelet (tree task_decl)
  717. {
  718. /* Generate a wrapper function for each implementation of TASK_DECL that
  719. does all the packing/unpacking. */
  720. define_codelet_wrappers (task_decl);
  721. /* Retrieve the declaration of the `starpu_codelet' object. */
  722. tree cl_def;
  723. cl_def = lookup_name (build_codelet_identifier (task_decl));
  724. gcc_assert (cl_def != NULL_TREE && TREE_CODE (cl_def) == VAR_DECL);
  725. /* Turn the codelet declaration into a definition. */
  726. TREE_PUBLIC (cl_def) = TREE_PUBLIC (task_decl);
  727. TREE_STATIC (cl_def) = true;
  728. DECL_EXTERNAL (cl_def) = false;
  729. DECL_INITIAL (cl_def) = build_codelet_initializer (task_decl);
  730. return cl_def;
  731. }
  732. /* Define the `starpu_codelet' structure for the task implemented by
  733. IMPL_DECL if we're in the right compilation unit, i.e., is IMPL_DECL is a
  734. "cpu" task implementation. */
  735. static void
  736. maybe_define_codelet (tree impl_decl)
  737. {
  738. if (task_implementation_where (impl_decl) == STARPU_CPU)
  739. /* IMPL_DECL is a "cpu" implementation of some task, so define the
  740. codelet structure in this compilation unit. */
  741. define_codelet (task_implementation_task (impl_decl));
  742. }
  743. static void
  744. handle_pre_genericize (void *gcc_data, void *user_data)
  745. {
  746. tree fndecl = (tree) gcc_data;
  747. gcc_assert (fndecl != NULL_TREE && TREE_CODE (fndecl) == FUNCTION_DECL);
  748. gcc_assert (lookup_name (DECL_NAME (fndecl)) == fndecl);
  749. if (lookup_attribute (task_implementation_attribute_name,
  750. DECL_ATTRIBUTES (fndecl)))
  751. maybe_define_codelet (fndecl);
  752. }
  753. /* Build a "conversion" from a raw C pointer to its data handle. The
  754. assumption is that the programmer should have already registered the
  755. pointer by themselves. */
  756. static tree
  757. build_pointer_lookup (tree pointer, gimple_seq *body)
  758. {
  759. gimple emit_error_message (void)
  760. {
  761. static const char msg[] =
  762. "starpu: task called with unregistered pointer, aborting\n";
  763. return gimple_build_call (built_in_decls[BUILT_IN_PUTS], 1,
  764. build_string_literal (strlen (msg) + 1, msg));
  765. }
  766. tree var;
  767. var = create_tmp_var (ptr_type_node, ".handle-arg");
  768. mark_addressable (var);
  769. /* Initialize VAR with `starpu_data_lookup (POINTER)'. */
  770. gimple_seq init = NULL;
  771. tree modify = build2 (MODIFY_EXPR, ptr_type_node, var,
  772. build_call_expr (data_lookup_fn, 1, pointer));
  773. force_gimple_operand (modify, &init, true, var);
  774. gimple_seq_add_seq (body, init);
  775. /* FIXME: Add `if (VAR == NULL) abort ();'. */
  776. #if 0
  777. tree abort_label = create_artificial_label (UNKNOWN_LOCATION);
  778. tree success_label = create_artificial_label (UNKNOWN_LOCATION);
  779. gimple cond = gimple_build_cond (EQ_EXPR,
  780. var, build_zero_cst (ptr_type_node),
  781. abort_label, success_label);
  782. gimple_seq_add_stmt (body, cond);
  783. gimplify_seq_add_stmt (body, gimple_build_label (abort_label));
  784. gimple_seq_add_stmt (body, emit_error_message ());
  785. gimple_seq_add_stmt (body,
  786. gimple_build_call (built_in_decls[BUILT_IN_ABORT], 0));
  787. gimplify_seq_add_stmt (body, gimple_build_label (success_label));
  788. rebuild_cgraph_edges ();
  789. #endif
  790. return var;
  791. }
  792. /* Build a call to `starpu_insert_task' for TASK_DECL, which will replace
  793. CALL. */
  794. static gimple_seq
  795. build_task_submission (tree task_decl, gimple call)
  796. {
  797. /* Return a chain of local variables that need to be introduced. Variables
  798. are introduced for each argument that is either a scalar constant or a
  799. non-addressable variable---e.g., a `char' variable allocated in a
  800. register. Populate BODY with the initial assignments to these
  801. variables. */
  802. /* FIXME: We should also introduce local variables to mimic implicit
  803. integer type conversion---e.g., when the formal parameter type is `char'
  804. and the function is called with a `long' variable. */
  805. tree local_vars (gimple_seq *body)
  806. {
  807. size_t n;
  808. tree vars = NULL_TREE;
  809. tree arg_types = TYPE_ARG_TYPES (TREE_TYPE (task_decl));
  810. for (n = 0;
  811. n < gimple_call_num_args (call);
  812. n++, arg_types = TREE_CHAIN (arg_types))
  813. {
  814. tree arg, type;
  815. /* Initially ARG_TYPES should be a list of N type nodes. */
  816. gcc_assert (TREE_CODE (arg_types) == TREE_LIST);
  817. type = TREE_VALUE (arg_types);
  818. gcc_assert (type != NULL_TREE);
  819. arg = gimple_call_arg (call, n);
  820. if ((!POINTER_TYPE_P (TREE_TYPE (arg))
  821. && TREE_CONSTANT (arg)
  822. && TREE_CODE (arg) != VAR_DECL
  823. && TREE_CODE (arg) != ADDR_EXPR)
  824. || is_gimple_non_addressable (arg))
  825. {
  826. /* ARG is a scalar constant or a non-addressable variable.
  827. Introduce a variable to hold it. */
  828. tree var =
  829. create_tmp_var (type,
  830. is_gimple_non_addressable (arg)
  831. ? ".non-addressable-arg"
  832. : ".literal-arg");
  833. mark_addressable (var);
  834. /* Initialize VAR. */
  835. tree init_value = fold_convert (type, arg);
  836. gimple_seq init = NULL;
  837. tree modify = build2 (MODIFY_EXPR, type, var, init_value);
  838. force_gimple_operand (modify, &init, true, var);
  839. gimple_seq_add_seq (body, init);
  840. if (vars != NULL_TREE)
  841. chainon (vars, var);
  842. else
  843. vars = var;
  844. }
  845. }
  846. return vars;
  847. }
  848. size_t n;
  849. VEC(tree, heap) *args = NULL;
  850. tree vars;
  851. gimple_seq body = NULL;
  852. vars = local_vars (&body);
  853. /* The first argument will be a pointer to the codelet. */
  854. VEC_safe_push (tree, heap, args,
  855. build_addr (task_codelet_declaration (task_decl),
  856. current_function_decl));
  857. for (n = 0; n < gimple_call_num_args (call); n++)
  858. {
  859. tree arg;
  860. arg = gimple_call_arg (call, n);
  861. if (POINTER_TYPE_P (TREE_TYPE (arg)))
  862. {
  863. /* A pointer: the arguments will be:
  864. `STARPU_RW, ptr' or similar. */
  865. gcc_assert (TREE_CODE (arg) == VAR_DECL
  866. || TREE_CODE (arg) == ADDR_EXPR);
  867. VEC_safe_push (tree, heap, args,
  868. build_int_cst (integer_type_node, STARPU_RW));
  869. VEC_safe_push (tree, heap, args, build_pointer_lookup (arg, &body));
  870. }
  871. else
  872. {
  873. /* A scalar: the arguments will be:
  874. `STARPU_VALUE, &scalar, sizeof (scalar)'. */
  875. if (is_gimple_non_addressable (arg) || TREE_CONSTANT (arg))
  876. {
  877. /* Use the local variable we introduced to hold ARG's
  878. value. */
  879. arg = vars;
  880. vars = TREE_CHAIN (vars);
  881. }
  882. gcc_assert (TREE_CODE (arg) == VAR_DECL);
  883. gcc_assert (TREE_ADDRESSABLE (arg));
  884. VEC_safe_push (tree, heap, args,
  885. build_int_cst (integer_type_node, STARPU_VALUE));
  886. VEC_safe_push (tree, heap, args,
  887. build_addr (arg, current_function_decl));
  888. VEC_safe_push (tree, heap, args,
  889. size_in_bytes (TREE_TYPE (arg)));
  890. }
  891. }
  892. /* Push the terminating zero. */
  893. VEC_safe_push (tree, heap, args,
  894. build_int_cst (integer_type_node, 0));
  895. gimple_seq_add_stmt (&body, gimple_build_call_vec (insert_task_fn, args));
  896. return body;
  897. }
  898. static unsigned int
  899. lower_starpu (void)
  900. {
  901. tree fndecl;
  902. const struct cgraph_node *cgraph;
  903. const struct cgraph_edge *callee;
  904. fndecl = current_function_decl;
  905. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  906. /* This pass should occur after `build_cgraph_edges'. */
  907. cgraph = cgraph_get_node (fndecl);
  908. gcc_assert (cgraph != NULL);
  909. for (callee = cgraph->callees;
  910. callee != NULL;
  911. callee = callee->next_callee)
  912. {
  913. gcc_assert (callee->callee != NULL);
  914. tree callee_decl;
  915. callee_decl = callee->callee->decl;
  916. if (lookup_attribute (task_attribute_name,
  917. DECL_ATTRIBUTES (callee_decl)))
  918. {
  919. printf ("%s: `%s' calls task `%s'\n", __func__,
  920. IDENTIFIER_POINTER (DECL_NAME (fndecl)),
  921. IDENTIFIER_POINTER (DECL_NAME (callee_decl)));
  922. gimple call_site;
  923. gimple_seq submission;
  924. gimple_stmt_iterator gsi;
  925. call_site = callee->call_stmt;
  926. gsi = gsi_for_stmt (call_site);
  927. submission = build_task_submission (callee_decl, call_site);
  928. gsi_remove (&gsi, true);
  929. gsi_insert_seq_before (&gsi, submission, GSI_SAME_STMT);
  930. rebuild_cgraph_edges ();
  931. }
  932. }
  933. return 0;
  934. }
  935. static struct opt_pass pass_lower_starpu =
  936. {
  937. .type = GIMPLE_PASS,
  938. .name = "pass_lower_starpu",
  939. .execute = lower_starpu,
  940. /* The rest is zeroed. */
  941. };
  942. /* Initialization. */
  943. static void
  944. define_cpp_macros (void *gcc_data, void *user_data)
  945. {
  946. cpp_define (parse_in, "STARPU_GCC_PLUGIN=0");
  947. cpp_push_include (parse_in, "starpu.h");
  948. }
  949. int
  950. plugin_init (struct plugin_name_args *plugin_info,
  951. struct plugin_gcc_version *version)
  952. {
  953. if (!plugin_default_version_check (version, &gcc_version))
  954. return 1;
  955. register_callback (plugin_name, PLUGIN_START_UNIT,
  956. define_cpp_macros, NULL);
  957. register_callback (plugin_name, PLUGIN_PRAGMAS,
  958. register_pragmas, NULL);
  959. register_callback (plugin_name, PLUGIN_ATTRIBUTES,
  960. register_task_attributes, NULL);
  961. register_callback (plugin_name, PLUGIN_PRE_GENERICIZE,
  962. handle_pre_genericize, NULL);
  963. /* Register our pass so that it happens after `build_cgraph_edges' has been
  964. done. */
  965. struct register_pass_info pass_info =
  966. {
  967. .pass = &pass_lower_starpu,
  968. .reference_pass_name = "*build_cgraph_edges",
  969. .ref_pass_instance_number = 1,
  970. .pos_op = PASS_POS_INSERT_AFTER
  971. };
  972. register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP,
  973. NULL, &pass_info);
  974. return 0;
  975. }