starpu.c 31 KB

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