starpu.c 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740
  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. #ifdef HAVE_C_FAMILY_C_COMMON_H
  25. # include <c-family/c-common.h>
  26. #elif HAVE_C_COMMON_H
  27. # include <c-common.h>
  28. #endif
  29. #ifdef HAVE_C_FAMILY_C_PRAGMA_H
  30. # include <c-family/c-pragma.h>
  31. #elif HAVE_C_PRAGMA_H
  32. # include <c-pragma.h>
  33. #endif
  34. #include <tm.h>
  35. #include <gimple.h>
  36. #include <tree-pass.h>
  37. #include <tree-flow.h>
  38. #include <cgraph.h>
  39. #include <gimple.h>
  40. #include <toplev.h>
  41. #include <stdio.h>
  42. /* Don't include the dreaded proprietary headers that we don't need anyway.
  43. In particular, this waives the obligation to reproduce their silly
  44. disclaimer. */
  45. #define STARPU_DONT_INCLUDE_CUDA_HEADERS
  46. #include <starpu.h> /* for `STARPU_CPU' & co. */
  47. /* The name of this plug-in. */
  48. static const char plugin_name[] = "starpu";
  49. /* Names of public attributes. */
  50. static const char task_attribute_name[] = "task";
  51. static const char task_implementation_attribute_name[] = "task_implementation";
  52. static const char heap_allocated_attribute_name[] = "heap_allocated";
  53. /* Names of attributes used internally. */
  54. static const char task_codelet_attribute_name[] = ".codelet";
  55. static const char task_implementation_list_attribute_name[] =
  56. ".task_implementation_list";
  57. static const char task_implementation_wrapper_attribute_name[] =
  58. ".task_implementation_wrapper";
  59. /* Names of data structures defined in <starpu.h>. */
  60. static const char codelet_struct_name[] = "starpu_codelet_gcc";
  61. /* Cached function declarations. */
  62. static tree unpack_fn;
  63. /* Forward declarations. */
  64. static tree build_codelet_declaration (tree task_decl);
  65. static tree build_task_body (const_tree task_decl);
  66. static tree build_pointer_lookup (tree pointer);
  67. static bool task_p (const_tree decl);
  68. static bool task_implementation_p (const_tree decl);
  69. static int task_implementation_target_to_int (const_tree target);
  70. /* Lookup the StarPU function NAME in the global scope and store the result
  71. in VAR (this can't be done from `lower_starpu'.) */
  72. #define LOOKUP_STARPU_FUNCTION(var, name) \
  73. if ((var) == NULL_TREE) \
  74. { \
  75. (var) = lookup_name (get_identifier (name)); \
  76. gcc_assert ((var) != NULL_TREE && TREE_CODE (var) == FUNCTION_DECL); \
  77. }
  78. /* Useful code backported from GCC 4.6. */
  79. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_ARRAY
  80. static tree
  81. build_call_expr_loc_array (location_t loc, tree fndecl, int n, tree *argarray)
  82. {
  83. tree fntype = TREE_TYPE (fndecl);
  84. tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
  85. return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
  86. }
  87. #endif
  88. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_VEC
  89. static tree
  90. build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
  91. {
  92. return build_call_expr_loc_array (loc, fndecl, VEC_length (tree, vec),
  93. VEC_address (tree, vec));
  94. }
  95. #endif
  96. /* Helpers. */
  97. /* Build a reference to the INDEXth element of ARRAY. `build_array_ref' is
  98. not exported, so we roll our own.
  99. FIXME: This version may not work for array types and doesn't do as much
  100. type-checking as `build_array_ref'. */
  101. static tree
  102. array_ref (tree array, size_t index)
  103. {
  104. gcc_assert (POINTER_TYPE_P (TREE_TYPE (array)));
  105. tree pointer_plus_offset =
  106. index > 0
  107. ? build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR,
  108. array,
  109. build_int_cstu (integer_type_node, index),
  110. 0)
  111. : array;
  112. gcc_assert (POINTER_TYPE_P (TREE_TYPE (pointer_plus_offset)));
  113. return build_indirect_ref (UNKNOWN_LOCATION,
  114. pointer_plus_offset,
  115. RO_ARRAY_INDEXING);
  116. }
  117. /* Like `build_constructor_from_list', but sort VALS according to their
  118. offset in struct TYPE. Inspired by `gnat_build_constructor'. */
  119. static tree
  120. build_constructor_from_unsorted_list (tree type, tree vals)
  121. {
  122. int compare_elmt_bitpos (const void *rt1, const void *rt2)
  123. {
  124. const constructor_elt *elmt1 = (constructor_elt *) rt1;
  125. const constructor_elt *elmt2 = (constructor_elt *) rt2;
  126. const_tree field1 = elmt1->index;
  127. const_tree field2 = elmt2->index;
  128. int ret
  129. = tree_int_cst_compare (bit_position (field1), bit_position (field2));
  130. return ret ? ret : (int) (DECL_UID (field1) - DECL_UID (field2));
  131. }
  132. tree t;
  133. VEC(constructor_elt,gc) *v = NULL;
  134. if (vals)
  135. {
  136. v = VEC_alloc (constructor_elt, gc, list_length (vals));
  137. for (t = vals; t; t = TREE_CHAIN (t))
  138. CONSTRUCTOR_APPEND_ELT (v, TREE_PURPOSE (t), TREE_VALUE (t));
  139. }
  140. /* Sort field initializers by field offset. */
  141. VEC_qsort (constructor_elt, v, compare_elmt_bitpos);
  142. return build_constructor (type, v);
  143. }
  144. /* Return true if LST holds the void type. */
  145. bool
  146. void_type_p (const_tree lst)
  147. {
  148. gcc_assert (TREE_CODE (lst) == TREE_LIST);
  149. return VOID_TYPE_P (TREE_VALUE (lst));
  150. }
  151. /* Debugging helpers. */
  152. static tree build_printf (const char *, ...)
  153. __attribute__ ((format (printf, 1, 2)));
  154. static tree
  155. build_printf (const char *fmt, ...)
  156. {
  157. tree call;
  158. char *str;
  159. va_list args;
  160. va_start (args, fmt);
  161. vasprintf (&str, fmt, args);
  162. call = build_call_expr (built_in_decls[BUILT_IN_PUTS], 1,
  163. build_string_literal (strlen (str) + 1, str));
  164. free (str);
  165. va_end (args);
  166. return call;
  167. }
  168. static tree
  169. build_hello_world (void)
  170. {
  171. return build_printf ("Hello, StarPU!");
  172. }
  173. /* List and vector utilities, à la SRFI-1. */
  174. static tree chain_trees (tree t, ...)
  175. __attribute__ ((sentinel));
  176. static tree
  177. chain_trees (tree t, ...)
  178. {
  179. va_list args;
  180. va_start (args, t);
  181. tree next, prev = t;
  182. for (prev = t, next = va_arg (args, tree);
  183. next != NULL_TREE;
  184. prev = next, next = va_arg (args, tree))
  185. TREE_CHAIN (prev) = next;
  186. va_end (args);
  187. return t;
  188. }
  189. static tree
  190. filter (bool (*pred) (const_tree), tree t)
  191. {
  192. tree result, lst;
  193. gcc_assert (TREE_CODE (t) == TREE_LIST);
  194. result = NULL_TREE;
  195. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  196. {
  197. if (pred (lst))
  198. result = tree_cons (TREE_PURPOSE (lst), TREE_VALUE (lst),
  199. result);
  200. }
  201. return nreverse (result);
  202. }
  203. static tree
  204. list_remove (bool (*pred) (const_tree), tree t)
  205. {
  206. bool opposite (const_tree t)
  207. {
  208. return !pred (t);
  209. }
  210. return filter (opposite, t);
  211. }
  212. /* Map FUNC over chain T. T does not have to be `TREE_LIST'; it can be a
  213. chain of arbitrary tree objects. */
  214. static tree
  215. map (tree (*func) (const_tree), tree t)
  216. {
  217. tree result, tail, lst;
  218. result = tail = NULL_TREE;
  219. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  220. {
  221. tree r = func (lst);
  222. if (tail != NULL_TREE)
  223. TREE_CHAIN (tail) = r;
  224. else
  225. result = r;
  226. tail = r;
  227. }
  228. return result;
  229. }
  230. static void
  231. for_each (void (*func) (tree), tree t)
  232. {
  233. tree lst;
  234. gcc_assert (TREE_CODE (t) == TREE_LIST);
  235. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  236. func (TREE_VALUE (lst));
  237. }
  238. /* Pragmas. */
  239. #define STARPU_PRAGMA_NAME_SPACE "starpu"
  240. static void
  241. handle_pragma_hello (struct cpp_reader *reader)
  242. {
  243. add_stmt (build_hello_world ());
  244. }
  245. /* Process `#pragma starpu initialize'.
  246. TODO: Parse and initialize some of the fields of `starpu_conf'. */
  247. static void
  248. handle_pragma_initialize (struct cpp_reader *reader)
  249. {
  250. static tree init_fn;
  251. LOOKUP_STARPU_FUNCTION (init_fn, "starpu_init");
  252. /* Call `starpu_init (NULL)'. */
  253. tree init = build_call_expr (init_fn, 1, build_zero_cst (ptr_type_node));
  254. add_stmt (init);
  255. }
  256. /* Process `#pragma starpu shutdown'. */
  257. static void
  258. handle_pragma_shutdown (struct cpp_reader *reader)
  259. {
  260. static tree shutdown_fn;
  261. LOOKUP_STARPU_FUNCTION (shutdown_fn, "starpu_shutdown");
  262. tree token;
  263. if (pragma_lex (&token) != CPP_EOF)
  264. error_at (cpp_peek_token (reader, 0)->src_loc,
  265. "junk after %<starpu shutdown%> pragma");
  266. else
  267. /* Call `starpu_shutdown ()'. */
  268. add_stmt (build_call_expr (shutdown_fn, 0));
  269. }
  270. static void
  271. handle_pragma_wait (struct cpp_reader *reader)
  272. {
  273. if (task_implementation_p (current_function_decl))
  274. {
  275. location_t loc;
  276. loc = cpp_peek_token (reader, 0)->src_loc;
  277. /* TODO: In the future we could generate a task for the continuation
  278. and have it depend on what's before here. */
  279. error_at (loc, "task implementation is not allowed to wait");
  280. }
  281. else
  282. {
  283. tree fndecl;
  284. fndecl = lookup_name (get_identifier ("starpu_task_wait_for_all"));
  285. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  286. add_stmt (build_call_expr (fndecl, 0));
  287. }
  288. }
  289. /* The minimal C expression parser. */
  290. extern int yyparse (location_t, const char *, tree *);
  291. extern int yydebug;
  292. /* Parse expressions from the CPP reader for PRAGMA, which is located at LOC.
  293. Return a TREE_LIST of C expressions. */
  294. static tree
  295. read_pragma_expressions (const char *pragma, location_t loc)
  296. {
  297. tree expr = NULL_TREE;
  298. if (yyparse (loc, pragma, &expr))
  299. /* Parse error or memory exhaustion. */
  300. expr = NULL_TREE;
  301. return expr;
  302. }
  303. /* Process `#pragma starpu register VAR [COUNT]' and emit the corresponding
  304. `starpu_vector_data_register' call. */
  305. static void
  306. handle_pragma_register (struct cpp_reader *reader)
  307. {
  308. tree args, ptr, count_arg;
  309. location_t loc;
  310. loc = cpp_peek_token (reader, 0)->src_loc;
  311. args = read_pragma_expressions ("register", loc);
  312. if (args == NULL_TREE)
  313. /* Parse error, presumably already handled by the parser. */
  314. return;
  315. /* First argument should be a pointer expression. */
  316. ptr = TREE_VALUE (args);
  317. args = TREE_CHAIN (args);
  318. if (ptr == error_mark_node)
  319. return;
  320. if (!POINTER_TYPE_P (TREE_TYPE (ptr))
  321. && TREE_CODE (TREE_TYPE (ptr)) != ARRAY_TYPE)
  322. {
  323. error_at (loc, "%qE is neither a pointer nor an array", ptr);
  324. return;
  325. }
  326. TREE_USED (ptr) = true;
  327. if (DECL_P (ptr))
  328. DECL_READ_P (ptr) = true;
  329. if (TREE_CODE (TREE_TYPE (ptr)) == ARRAY_TYPE
  330. && !DECL_EXTERNAL (ptr)
  331. && !TREE_STATIC (ptr)
  332. && !MAIN_NAME_P (DECL_NAME (current_function_decl)))
  333. warning_at (loc, 0, "using an on-stack array as a task input "
  334. "considered unsafe");
  335. /* Determine the number of elements in the vector. */
  336. tree count = NULL_TREE;
  337. if (TREE_CODE (TREE_TYPE (ptr)) == ARRAY_TYPE)
  338. {
  339. tree domain = TYPE_DOMAIN (TREE_TYPE (ptr));
  340. if (domain != NULL_TREE)
  341. {
  342. count = build_binary_op (loc, MINUS_EXPR,
  343. TYPE_MAX_VALUE (domain),
  344. TYPE_MIN_VALUE (domain),
  345. false);
  346. count = build_binary_op (loc, PLUS_EXPR,
  347. count,
  348. build_int_cstu (integer_type_node, 1),
  349. false);
  350. count = fold_convert (size_type_node, count);
  351. }
  352. }
  353. /* Second argument is optional but should be an integer. */
  354. count_arg = (args == NULL_TREE) ? NULL_TREE : TREE_VALUE (args);
  355. if (args != NULL_TREE)
  356. {
  357. args = TREE_CHAIN (args);
  358. TREE_CHAIN (count_arg) = NULL_TREE;
  359. }
  360. if (count_arg == NULL_TREE)
  361. {
  362. /* End of line reached: check whether the array size was
  363. determined. */
  364. if (count == NULL_TREE)
  365. {
  366. error_at (loc, "cannot determine size of array %qE", ptr);
  367. return;
  368. }
  369. }
  370. else if (count_arg == error_mark_node)
  371. /* COUNT_ARG could not be parsed and an error was already reported. */
  372. return;
  373. else if (!INTEGRAL_TYPE_P (TREE_TYPE (count_arg)))
  374. {
  375. error_at (loc, "%qE is not an integer", count_arg);
  376. return;
  377. }
  378. else
  379. {
  380. TREE_USED (count_arg) = true;
  381. if (DECL_P (count_arg))
  382. DECL_READ_P (count_arg) = true;
  383. if (count != NULL_TREE)
  384. {
  385. /* The number of elements of this array was already determined. */
  386. inform (loc,
  387. "element count can be omitted for bounded array %qE",
  388. ptr);
  389. if (count_arg != NULL_TREE)
  390. {
  391. if (TREE_CODE (count_arg) == INTEGER_CST)
  392. {
  393. if (!tree_int_cst_equal (count, count_arg))
  394. error_at (loc, "specified element count differs "
  395. "from actual size of array %qE",
  396. ptr);
  397. }
  398. else
  399. /* Using a variable to determine the array size whereas the
  400. array size is actually known statically. This looks like
  401. unreasonable code, so error out. */
  402. error_at (loc, "determining array size at run-time "
  403. "although array size is known at compile-time");
  404. }
  405. }
  406. else
  407. count = count_arg;
  408. }
  409. /* Any remaining args? */
  410. if (args != NULL_TREE)
  411. error_at (loc, "junk after %<starpu register%> pragma");
  412. /* If PTR is an array, take its address. */
  413. tree pointer =
  414. POINTER_TYPE_P (TREE_TYPE (ptr))
  415. ? ptr
  416. : build_addr (ptr, current_function_decl);
  417. /* Introduce a local variable to hold the handle. */
  418. tree handle_var = build_decl (loc, VAR_DECL, create_tmp_var_name (".handle"),
  419. ptr_type_node);
  420. DECL_CONTEXT (handle_var) = current_function_decl;
  421. DECL_ARTIFICIAL (handle_var) = true;
  422. DECL_INITIAL (handle_var) = NULL_TREE;
  423. tree register_fn =
  424. lookup_name (get_identifier ("starpu_vector_data_register"));
  425. /* Build `starpu_vector_data_register (&HANDLE_VAR, 0, POINTER,
  426. COUNT, sizeof *POINTER)' */
  427. tree call =
  428. build_call_expr (register_fn, 5,
  429. build_addr (handle_var, current_function_decl),
  430. build_zero_cst (uintptr_type_node), /* home node */
  431. pointer, count,
  432. size_in_bytes (TREE_TYPE (TREE_TYPE (ptr))));
  433. tree bind;
  434. bind = build3 (BIND_EXPR, void_type_node, handle_var, call,
  435. NULL_TREE);
  436. add_stmt (bind);
  437. }
  438. /* Process `#pragma starpu acquire VAR' and emit the corresponding
  439. `starpu_data_acquire' call. */
  440. static void
  441. handle_pragma_acquire (struct cpp_reader *reader)
  442. {
  443. static tree acquire_fn;
  444. LOOKUP_STARPU_FUNCTION (acquire_fn, "starpu_data_acquire");
  445. tree args, var;
  446. location_t loc;
  447. loc = cpp_peek_token (reader, 0)->src_loc;
  448. args = read_pragma_expressions ("acquire", loc);
  449. if (args == NULL_TREE)
  450. return;
  451. var = TREE_VALUE (args);
  452. if (var == error_mark_node)
  453. return;
  454. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  455. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  456. {
  457. error_at (loc, "%qE is neither a pointer nor an array", var);
  458. return;
  459. }
  460. else if (TREE_CHAIN (var) != NULL_TREE)
  461. error_at (loc, "junk after %<starpu acquire%> pragma");
  462. /* If VAR is an array, take its address. */
  463. tree pointer =
  464. POINTER_TYPE_P (TREE_TYPE (var))
  465. ? var
  466. : build_addr (var, current_function_decl);
  467. /* Call `starpu_data_acquire (starpu_data_lookup (ptr), STARPU_RW)'.
  468. TODO: Support modes other than RW. */
  469. add_stmt (build_call_expr (acquire_fn, 2,
  470. build_pointer_lookup (pointer),
  471. build_int_cst (integer_type_node, STARPU_RW)));
  472. }
  473. /* Process `#pragma starpu unregister VAR' and emit the corresponding
  474. `starpu_data_unregister' call. */
  475. static void
  476. handle_pragma_unregister (struct cpp_reader *reader)
  477. {
  478. static tree unregister_fn;
  479. LOOKUP_STARPU_FUNCTION (unregister_fn, "starpu_data_unregister");
  480. tree args, var;
  481. location_t loc;
  482. loc = cpp_peek_token (reader, 0)->src_loc;
  483. args = read_pragma_expressions ("unregister", loc);
  484. if (args == NULL_TREE)
  485. return;
  486. var = TREE_VALUE (args);
  487. if (var == error_mark_node)
  488. return;
  489. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  490. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  491. {
  492. error_at (loc, "%qE is neither a pointer nor an array", var);
  493. return;
  494. }
  495. else if (TREE_CHAIN (args) != NULL_TREE)
  496. error_at (loc, "junk after %<starpu unregister%> pragma");
  497. /* If VAR is an array, take its address. */
  498. tree pointer =
  499. POINTER_TYPE_P (TREE_TYPE (var))
  500. ? var
  501. : build_addr (var, current_function_decl);
  502. /* Call `starpu_data_unregister (starpu_data_lookup (ptr))'. */
  503. add_stmt (build_call_expr (unregister_fn, 1,
  504. build_pointer_lookup (pointer)));
  505. }
  506. static void
  507. register_pragmas (void *gcc_data, void *user_data)
  508. {
  509. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "hello",
  510. handle_pragma_hello);
  511. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "initialize",
  512. handle_pragma_initialize);
  513. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "wait",
  514. handle_pragma_wait);
  515. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "register",
  516. handle_pragma_register);
  517. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "acquire",
  518. handle_pragma_acquire);
  519. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "unregister",
  520. handle_pragma_unregister);
  521. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "shutdown",
  522. handle_pragma_shutdown);
  523. }
  524. /* Attributes. */
  525. /* Handle the `task' function attribute. */
  526. static tree
  527. handle_task_attribute (tree *node, tree name, tree args,
  528. int flags, bool *no_add_attrs)
  529. {
  530. tree fn;
  531. fn = *node;
  532. /* Get rid of the `task' attribute by default so that FN isn't further
  533. processed when it's erroneous. */
  534. *no_add_attrs = true;
  535. if (TREE_CODE (fn) != FUNCTION_DECL)
  536. error_at (DECL_SOURCE_LOCATION (fn),
  537. "%<task%> attribute only applies to functions");
  538. else
  539. {
  540. if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fn))))
  541. /* Raise an error but keep going to avoid spitting out too many
  542. errors at the user's face. */
  543. error_at (DECL_SOURCE_LOCATION (fn),
  544. "task return type must be %<void%>");
  545. /* This is a function declaration for something local to this
  546. translation unit, so add the `task' attribute to FN. */
  547. *no_add_attrs = false;
  548. /* Add an empty `task_implementation_list' attribute. */
  549. DECL_ATTRIBUTES (fn) =
  550. tree_cons (get_identifier (task_implementation_list_attribute_name),
  551. NULL_TREE,
  552. NULL_TREE);
  553. /* Push a declaration for the corresponding `struct starpu_codelet' object and
  554. add it as an attribute of FN. */
  555. tree cl = build_codelet_declaration (fn);
  556. DECL_ATTRIBUTES (fn) =
  557. tree_cons (get_identifier (task_codelet_attribute_name), cl,
  558. DECL_ATTRIBUTES (fn));
  559. pushdecl (cl);
  560. }
  561. /* Lookup & cache function declarations for later reuse. */
  562. LOOKUP_STARPU_FUNCTION (unpack_fn, "starpu_unpack_cl_args");
  563. return NULL_TREE;
  564. }
  565. /* Handle the `task_implementation (WHERE, TASK)' attribute. WHERE is a
  566. string constant ("cpu", "cuda", etc.), and TASK is the identifier of a
  567. function declared with the `task' attribute. */
  568. static tree
  569. handle_task_implementation_attribute (tree *node, tree name, tree args,
  570. int flags, bool *no_add_attrs)
  571. {
  572. location_t loc;
  573. tree fn, where, task_decl;
  574. /* FIXME:TODO: To change the order to (TASK, WHERE):
  575. tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
  576. tree cleanup_decl = lookup_name (cleanup_id);
  577. */
  578. fn = *node;
  579. where = TREE_VALUE (args);
  580. task_decl = TREE_VALUE (TREE_CHAIN (args));
  581. loc = DECL_SOURCE_LOCATION (fn);
  582. /* Get rid of the `task_implementation' attribute by default so that FN
  583. isn't further processed when it's erroneous. */
  584. *no_add_attrs = true;
  585. /* Mark FN as used to placate `-Wunused-function' when FN is erroneous
  586. anyway. */
  587. TREE_USED (fn) = true;
  588. if (TREE_CODE (fn) != FUNCTION_DECL)
  589. error_at (loc,
  590. "%<task_implementation%> attribute only applies to functions");
  591. else if (TREE_CODE (where) != STRING_CST)
  592. error_at (loc, "string constant expected "
  593. "as the first %<task_implementation%> argument");
  594. else if (TREE_CODE (task_decl) != FUNCTION_DECL)
  595. error_at (loc, "%qE is not a function", task_decl);
  596. else if (lookup_attribute (task_attribute_name,
  597. DECL_ATTRIBUTES (task_decl)) == NULL_TREE)
  598. error_at (loc, "function %qE lacks the %<task%> attribute",
  599. DECL_NAME (task_decl));
  600. else if (TYPE_CANONICAL (TREE_TYPE (fn))
  601. != TYPE_CANONICAL (TREE_TYPE (task_decl)))
  602. error_at (loc, "type differs from that of task %qE",
  603. DECL_NAME (task_decl));
  604. else
  605. {
  606. /* Add FN to the list of implementations of TASK_DECL. */
  607. tree attr, impls;
  608. attr = lookup_attribute (task_implementation_list_attribute_name,
  609. DECL_ATTRIBUTES (task_decl));
  610. impls = tree_cons (NULL_TREE, fn, TREE_VALUE (attr));
  611. TREE_VALUE (attr) = impls;
  612. TREE_USED (fn) = TREE_USED (task_decl);
  613. /* Check the `where' argument to raise a warning if needed. */
  614. if (task_implementation_target_to_int (where) == 0)
  615. warning_at (loc, 0,
  616. "unsupported target %E; task implementation won't be used",
  617. where);
  618. /* Keep the attribute. */
  619. *no_add_attrs = false;
  620. }
  621. return NULL_TREE;
  622. }
  623. /* Handle the `heap_allocated' attribute on variable *NODE. */
  624. static tree
  625. handle_heap_allocated_attribute (tree *node, tree name, tree args,
  626. int flags, bool *no_add_attrs)
  627. {
  628. location_t loc;
  629. tree var = *node;
  630. loc = DECL_SOURCE_LOCATION (var);
  631. if (DECL_EXTERNAL (var))
  632. error_at (loc, "attribute %<heap_allocated%> cannot be used "
  633. "on external declarations");
  634. else if (TREE_PUBLIC (var) || TREE_STATIC (var))
  635. {
  636. error_at (loc, "attribute %<heap_allocated%> cannot be used "
  637. "on global variables");
  638. TREE_TYPE (var) = error_mark_node;
  639. }
  640. else if (TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  641. {
  642. error_at (loc, "variable %qE must have an array type",
  643. DECL_NAME (var));
  644. TREE_TYPE (var) = error_mark_node;
  645. }
  646. else if (TYPE_SIZE (TREE_TYPE (var)) == NULL_TREE)
  647. {
  648. error_at (loc, "variable %qE has an incomplete array type",
  649. DECL_NAME (var));
  650. TREE_TYPE (var) = error_mark_node;
  651. }
  652. else
  653. {
  654. tree array_type = TREE_TYPE (var);
  655. tree pointer_type = build_pointer_type (array_type);
  656. TREE_TYPE (var) = pointer_type;
  657. DECL_SIZE (var) = TYPE_SIZE (pointer_type);
  658. DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (pointer_type);
  659. DECL_MODE (var) = TYPE_MODE (pointer_type);
  660. tree malloc_fn = lookup_name (get_identifier ("starpu_malloc"));
  661. gcc_assert (malloc_fn != NULL_TREE);
  662. add_stmt (build_call_expr (malloc_fn, 2,
  663. build_addr (var, current_function_decl),
  664. TYPE_SIZE_UNIT (array_type)));
  665. /* Add a destructor for VAR.
  666. TODO: Provide a way to disable this. */
  667. DECL_ATTRIBUTES (var) =
  668. tree_cons (get_identifier ("cleanup"),
  669. lookup_name (get_identifier ("_starpu_free_unref")),
  670. DECL_ATTRIBUTES (var));
  671. }
  672. return NULL_TREE;
  673. }
  674. /* Return the declaration of the `struct starpu_codelet' variable associated with
  675. TASK_DECL. */
  676. static tree
  677. task_codelet_declaration (const_tree task_decl)
  678. {
  679. tree cl_attr;
  680. cl_attr = lookup_attribute (task_codelet_attribute_name,
  681. DECL_ATTRIBUTES (task_decl));
  682. gcc_assert (cl_attr != NULL_TREE);
  683. return TREE_VALUE (cl_attr);
  684. }
  685. /* Return true if DECL is a task. */
  686. static bool
  687. task_p (const_tree decl)
  688. {
  689. return (TREE_CODE (decl) == FUNCTION_DECL &&
  690. lookup_attribute (task_attribute_name,
  691. DECL_ATTRIBUTES (decl)) != NULL_TREE);
  692. }
  693. /* Return true if DECL is a task implementation. */
  694. static bool
  695. task_implementation_p (const_tree decl)
  696. {
  697. return (TREE_CODE (decl) == FUNCTION_DECL &&
  698. lookup_attribute (task_implementation_attribute_name,
  699. DECL_ATTRIBUTES (decl)) != NULL_TREE);
  700. }
  701. /* Return the list of implementations of TASK_DECL. */
  702. static tree
  703. task_implementation_list (const_tree task_decl)
  704. {
  705. tree attr;
  706. attr = lookup_attribute (task_implementation_list_attribute_name,
  707. DECL_ATTRIBUTES (task_decl));
  708. return TREE_VALUE (attr);
  709. }
  710. /* Return the list of pointer parameter types of TASK_DECL. */
  711. static tree
  712. task_pointer_parameter_types (const_tree task_decl)
  713. {
  714. bool is_pointer (const_tree item)
  715. {
  716. return POINTER_TYPE_P (TREE_VALUE (item));
  717. }
  718. return filter (is_pointer, TYPE_ARG_TYPES (TREE_TYPE (task_decl)));
  719. }
  720. /* Return the StarPU integer constant corresponding to string TARGET. */
  721. static int
  722. task_implementation_target_to_int (const_tree target)
  723. {
  724. gcc_assert (TREE_CODE (target) == STRING_CST);
  725. int where_int;
  726. if (!strncmp (TREE_STRING_POINTER (target), "cpu",
  727. TREE_STRING_LENGTH (target)))
  728. where_int = STARPU_CPU;
  729. else if (!strncmp (TREE_STRING_POINTER (target), "opencl",
  730. TREE_STRING_LENGTH (target)))
  731. where_int = STARPU_OPENCL;
  732. else if (!strncmp (TREE_STRING_POINTER (target), "cuda",
  733. TREE_STRING_LENGTH (target)))
  734. where_int = STARPU_CUDA;
  735. else
  736. where_int = 0;
  737. return where_int;
  738. }
  739. /* Return a value indicating where TASK_IMPL should execute (`STARPU_CPU',
  740. `STARPU_CUDA', etc.). */
  741. static int
  742. task_implementation_where (const_tree task_impl)
  743. {
  744. tree impl_attr, args, where;
  745. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  746. impl_attr = lookup_attribute (task_implementation_attribute_name,
  747. DECL_ATTRIBUTES (task_impl));
  748. gcc_assert (impl_attr != NULL_TREE);
  749. args = TREE_VALUE (impl_attr);
  750. where = TREE_VALUE (args);
  751. return task_implementation_target_to_int (where);
  752. }
  753. /* Return the task implemented by TASK_IMPL. */
  754. static tree
  755. task_implementation_task (const_tree task_impl)
  756. {
  757. tree impl_attr, args;
  758. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  759. impl_attr = lookup_attribute (task_implementation_attribute_name,
  760. DECL_ATTRIBUTES (task_impl));
  761. gcc_assert (impl_attr != NULL_TREE);
  762. args = TREE_VALUE (impl_attr);
  763. return TREE_VALUE (TREE_CHAIN (args));
  764. }
  765. /* Return the FUNCTION_DECL of the wrapper generated for TASK_IMPL. */
  766. static tree
  767. task_implementation_wrapper (const_tree task_impl)
  768. {
  769. tree attr;
  770. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  771. attr = lookup_attribute (task_implementation_wrapper_attribute_name,
  772. DECL_ATTRIBUTES (task_impl));
  773. gcc_assert (attr != NULL_TREE);
  774. return TREE_VALUE (attr);
  775. }
  776. static void
  777. register_task_attributes (void *gcc_data, void *user_data)
  778. {
  779. static const struct attribute_spec task_attr =
  780. {
  781. task_attribute_name, 0, 0, true, false, false,
  782. handle_task_attribute
  783. };
  784. static const struct attribute_spec task_implementation_attr =
  785. {
  786. task_implementation_attribute_name, 2, 2, true, false, false,
  787. handle_task_implementation_attribute
  788. };
  789. static const struct attribute_spec heap_allocated_attr =
  790. {
  791. heap_allocated_attribute_name, 0, 0, true, false, false,
  792. handle_heap_allocated_attribute
  793. };
  794. register_attribute (&task_attr);
  795. register_attribute (&task_implementation_attr);
  796. register_attribute (&heap_allocated_attr);
  797. }
  798. /* Return the type of a codelet function, i.e.,
  799. `void (*) (void **, void *)'. */
  800. static tree
  801. build_codelet_wrapper_type (void)
  802. {
  803. tree void_ptr_ptr;
  804. void_ptr_ptr = build_pointer_type (ptr_type_node);
  805. return build_function_type_list (void_type_node,
  806. void_ptr_ptr, ptr_type_node,
  807. NULL_TREE);
  808. }
  809. /* Return an identifier for the wrapper of TASK_IMPL, a task
  810. implementation. */
  811. static tree
  812. build_codelet_wrapper_identifier (tree task_impl)
  813. {
  814. static const char suffix[] = ".task_implementation_wrapper";
  815. tree id;
  816. char *cl_name;
  817. const char *task_name;
  818. id = DECL_NAME (task_impl);
  819. task_name = IDENTIFIER_POINTER (id);
  820. cl_name = alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  821. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  822. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  823. return get_identifier (cl_name);
  824. }
  825. /* Return a function of type `void (*) (void **, void *)' that calls function
  826. TASK_IMPL, the FUNCTION_DECL of a task implementation whose prototype may
  827. be arbitrary. */
  828. static tree
  829. build_codelet_wrapper_definition (tree task_impl)
  830. {
  831. location_t loc;
  832. tree task_decl, decl;
  833. loc = DECL_SOURCE_LOCATION (task_impl);
  834. task_decl = task_implementation_task (task_impl);
  835. tree build_local_var (const_tree type)
  836. {
  837. tree var, t;
  838. const char *seed;
  839. t = TREE_VALUE (type);
  840. seed = POINTER_TYPE_P (t) ? "pointer_arg" : "scalar_arg";
  841. var = build_decl (loc, VAR_DECL, create_tmp_var_name (seed), t);
  842. DECL_CONTEXT (var) = decl;
  843. DECL_ARTIFICIAL (var) = true;
  844. return var;
  845. }
  846. /* Return the body of the wrapper, which unpacks `cl_args' and calls the
  847. user-defined task implementation. */
  848. tree build_body (tree wrapper_decl, tree vars)
  849. {
  850. tree stmts = NULL, call, v;
  851. VEC(tree, gc) *args;
  852. /* Build `var0 = STARPU_VECTOR_GET_PTR (buffers[0]); ...'. */
  853. size_t index = 0;
  854. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  855. {
  856. if (POINTER_TYPE_P (TREE_TYPE (v)))
  857. {
  858. /* Compute `void *VDESC = buffers[0];'. */
  859. tree vdesc = array_ref (DECL_ARGUMENTS (wrapper_decl), index);
  860. /* Below we assume (1) that pointer arguments are registered as
  861. StarPU vector handles, and (2) that the `ptr' field is at
  862. offset 0 of `struct starpu_vector_interface'. The latter allows us
  863. to use a simple pointer dereference instead of expanding
  864. `STARPU_VECTOR_GET_PTR'. */
  865. assert (offsetof (struct starpu_vector_interface, ptr) == 0);
  866. /* Compute `type *PTR = *(type **) VDESC;'. */
  867. tree ptr = build1 (INDIRECT_REF,
  868. build_pointer_type (TREE_TYPE (v)),
  869. vdesc);
  870. append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (v),
  871. v, ptr),
  872. &stmts);
  873. index++;
  874. }
  875. }
  876. /* Build `starpu_unpack_cl_args (cl_args, &var1, &var2, ...)'. */
  877. args = NULL;
  878. VEC_safe_push (tree, gc, args, TREE_CHAIN (DECL_ARGUMENTS (wrapper_decl)));
  879. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  880. {
  881. if (!POINTER_TYPE_P (TREE_TYPE (v)))
  882. VEC_safe_push (tree, gc, args, build_addr (v, wrapper_decl));
  883. }
  884. if (VEC_length (tree, args) > 1)
  885. {
  886. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fn, args);
  887. TREE_SIDE_EFFECTS (call) = 1;
  888. append_to_statement_list (call, &stmts);
  889. }
  890. /* Build `my_task_impl (var1, var2, ...)'. */
  891. args = NULL;
  892. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  893. VEC_safe_push (tree, gc, args, v);
  894. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, task_impl, args);
  895. TREE_SIDE_EFFECTS (call) = 1;
  896. append_to_statement_list (call, &stmts);
  897. tree bind;
  898. bind = build3 (BIND_EXPR, void_type_node, vars, stmts,
  899. DECL_INITIAL (wrapper_decl));
  900. TREE_TYPE (bind) = TREE_TYPE (TREE_TYPE (wrapper_decl));
  901. return bind;
  902. }
  903. /* Return the parameter list of the wrapper:
  904. `(void **BUFFERS, void *CL_ARGS)'. */
  905. tree build_parameters (tree wrapper_decl)
  906. {
  907. tree param1, param2;
  908. param1 = build_decl (loc, PARM_DECL,
  909. create_tmp_var_name ("buffers"),
  910. build_pointer_type (ptr_type_node));
  911. DECL_ARG_TYPE (param1) = ptr_type_node;
  912. DECL_CONTEXT (param1) = wrapper_decl;
  913. TREE_USED (param1) = true;
  914. param2 = build_decl (loc, PARM_DECL,
  915. create_tmp_var_name ("cl_args"),
  916. ptr_type_node);
  917. DECL_ARG_TYPE (param2) = ptr_type_node;
  918. DECL_CONTEXT (param2) = wrapper_decl;
  919. TREE_USED (param2) = true;
  920. return chainon (param1, param2);
  921. }
  922. tree wrapper_name, vars, result;
  923. wrapper_name = build_codelet_wrapper_identifier (task_impl);
  924. decl = build_decl (loc, FUNCTION_DECL, wrapper_name,
  925. build_codelet_wrapper_type ());
  926. vars = map (build_local_var,
  927. list_remove (void_type_p,
  928. TYPE_ARG_TYPES (TREE_TYPE (task_decl))));
  929. DECL_CONTEXT (decl) = NULL_TREE;
  930. DECL_ARGUMENTS (decl) = build_parameters (decl);
  931. result = build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  932. DECL_CONTEXT (result) = decl;
  933. DECL_ARTIFICIAL (result) = true;
  934. DECL_IGNORED_P (result) = true;
  935. DECL_RESULT (decl) = result;
  936. DECL_INITIAL (decl) = build_block (vars, NULL_TREE, decl, NULL_TREE);
  937. DECL_SAVED_TREE (decl) = build_body (decl, vars);
  938. TREE_PUBLIC (decl) = TREE_PUBLIC (task_impl);
  939. TREE_STATIC (decl) = true;
  940. TREE_USED (decl) = true;
  941. DECL_ARTIFICIAL (decl) = true;
  942. DECL_EXTERNAL (decl) = false;
  943. DECL_UNINLINABLE (decl) = true;
  944. rest_of_decl_compilation (decl, true, 0);
  945. struct function *prev_cfun = cfun;
  946. set_cfun (NULL);
  947. allocate_struct_function (decl, false);
  948. cfun->function_end_locus = DECL_SOURCE_LOCATION (task_impl);
  949. cgraph_finalize_function (decl, false);
  950. /* Mark DECL as needed so that it doesn't get removed by
  951. `cgraph_remove_unreachable_nodes' when it's not public. */
  952. cgraph_mark_needed_node (cgraph_get_node (decl));
  953. set_cfun (prev_cfun);
  954. return decl;
  955. }
  956. /* Define one wrapper function for each implementation of TASK. TASK should
  957. be the FUNCTION_DECL of a task. */
  958. static void
  959. define_codelet_wrappers (tree task)
  960. {
  961. void define (tree task_impl)
  962. {
  963. tree wrapper_def;
  964. wrapper_def = build_codelet_wrapper_definition (task_impl);
  965. DECL_ATTRIBUTES (task_impl) =
  966. tree_cons (get_identifier (task_implementation_wrapper_attribute_name),
  967. wrapper_def,
  968. DECL_ATTRIBUTES (task_impl));
  969. }
  970. for_each (define, task_implementation_list (task));
  971. }
  972. /* Return a NODE_IDENTIFIER for the variable holding the `struct starpu_codelet'
  973. structure associated with TASK_DECL. */
  974. static tree
  975. build_codelet_identifier (tree task_decl)
  976. {
  977. static const char suffix[] = ".codelet";
  978. tree id;
  979. char *cl_name;
  980. const char *task_name;
  981. id = DECL_NAME (task_decl);
  982. task_name = IDENTIFIER_POINTER (id);
  983. cl_name = alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  984. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  985. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  986. return get_identifier (cl_name);
  987. }
  988. static tree
  989. codelet_type (void)
  990. {
  991. /* XXX: Hack to allow the type declaration to be accessible at lower
  992. time. */
  993. static tree type_decl = NULL_TREE;
  994. if (type_decl == NULL_TREE)
  995. {
  996. /* Lookup the `struct starpu_codelet' struct type. This should succeed since
  997. we push <starpu.h> early on. */
  998. type_decl = lookup_name (get_identifier (codelet_struct_name));
  999. gcc_assert (type_decl != NULL_TREE && TREE_CODE (type_decl) == TYPE_DECL);
  1000. }
  1001. return TREE_TYPE (type_decl);
  1002. }
  1003. /* Return a VAR_DECL that declares a `struct starpu_codelet' structure for
  1004. TASK_DECL. */
  1005. static tree
  1006. build_codelet_declaration (tree task_decl)
  1007. {
  1008. tree name, cl_decl;
  1009. name = build_codelet_identifier (task_decl);
  1010. cl_decl = build_decl (DECL_SOURCE_LOCATION (task_decl),
  1011. VAR_DECL, name,
  1012. /* c_build_qualified_type (type, TYPE_QUAL_CONST) */
  1013. codelet_type ());
  1014. DECL_ARTIFICIAL (cl_decl) = true;
  1015. TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
  1016. TREE_STATIC (cl_decl) = false;
  1017. TREE_USED (cl_decl) = true;
  1018. DECL_EXTERNAL (cl_decl) = true;
  1019. DECL_CONTEXT (cl_decl) = NULL_TREE;
  1020. return cl_decl;
  1021. }
  1022. /* Return a `struct starpu_codelet' initializer for TASK_DECL. */
  1023. static tree
  1024. build_codelet_initializer (tree task_decl)
  1025. {
  1026. tree fields;
  1027. fields = TYPE_FIELDS (codelet_type ());
  1028. gcc_assert (TREE_CODE (fields) == FIELD_DECL);
  1029. tree lookup_field (const char *name)
  1030. {
  1031. tree fdecl, fname;
  1032. fname = get_identifier (name);
  1033. for (fdecl = fields;
  1034. fdecl != NULL_TREE;
  1035. fdecl = TREE_CHAIN (fdecl))
  1036. {
  1037. if (DECL_NAME (fdecl) == fname)
  1038. return fdecl;
  1039. }
  1040. /* Field NAME wasn't found. */
  1041. gcc_assert (false);
  1042. }
  1043. tree field_initializer (const char *name, tree value)
  1044. {
  1045. tree field, init;
  1046. field = lookup_field (name);
  1047. init = make_node (TREE_LIST);
  1048. TREE_PURPOSE (init) = field;
  1049. TREE_VALUE (init) = fold_convert (TREE_TYPE (field), value);
  1050. TREE_CHAIN (init) = NULL_TREE;
  1051. return init;
  1052. }
  1053. tree where_init (tree impls)
  1054. {
  1055. tree impl;
  1056. int where_int = 0;
  1057. for (impl = impls;
  1058. impl != NULL_TREE;
  1059. impl = TREE_CHAIN (impl))
  1060. {
  1061. tree impl_decl;
  1062. impl_decl = TREE_VALUE (impl);
  1063. gcc_assert (TREE_CODE (impl_decl) == FUNCTION_DECL);
  1064. printf (" `%s'\n", IDENTIFIER_POINTER (DECL_NAME (impl_decl)));
  1065. where_int |= task_implementation_where (impl_decl);
  1066. }
  1067. return build_int_cstu (integer_type_node, where_int);
  1068. }
  1069. tree implementation_pointer (tree impls, int where)
  1070. {
  1071. tree impl;
  1072. for (impl = impls;
  1073. impl != NULL_TREE;
  1074. impl = TREE_CHAIN (impl))
  1075. {
  1076. tree impl_decl;
  1077. impl_decl = TREE_VALUE (impl);
  1078. if (task_implementation_where (impl_decl) == where)
  1079. {
  1080. /* Return a pointer to the wrapper of IMPL_DECL. */
  1081. tree addr = build_addr (task_implementation_wrapper (impl_decl),
  1082. NULL_TREE);
  1083. return addr;
  1084. }
  1085. }
  1086. /* Default to a NULL pointer. */
  1087. return build_int_cstu (build_pointer_type (void_type_node), 0);
  1088. }
  1089. tree pointer_arg_count (void)
  1090. {
  1091. size_t len;
  1092. len = list_length (task_pointer_parameter_types (task_decl));
  1093. return build_int_cstu (integer_type_node, len);
  1094. }
  1095. printf ("implementations for `%s':\n",
  1096. IDENTIFIER_POINTER (DECL_NAME (task_decl)));
  1097. tree impls, inits;
  1098. impls = task_implementation_list (task_decl);
  1099. inits =
  1100. chain_trees (field_initializer ("where", where_init (impls)),
  1101. field_initializer ("nbuffers", pointer_arg_count ()),
  1102. field_initializer ("cpu_func",
  1103. implementation_pointer (impls, STARPU_CPU)),
  1104. field_initializer ("opencl_func",
  1105. implementation_pointer (impls,
  1106. STARPU_OPENCL)),
  1107. field_initializer ("cuda_func",
  1108. implementation_pointer (impls,
  1109. STARPU_CUDA)),
  1110. NULL_TREE);
  1111. return build_constructor_from_unsorted_list (codelet_type (), inits);
  1112. }
  1113. /* Return the VAR_DECL that defines a `struct starpu_codelet' structure for
  1114. TASK_DECL. The VAR_DECL is assumed to already exists, so it must not be
  1115. pushed again. */
  1116. static tree
  1117. declare_codelet (tree task_decl)
  1118. {
  1119. /* Retrieve the declaration of the `struct starpu_codelet' object. */
  1120. tree cl_decl;
  1121. cl_decl = lookup_name (build_codelet_identifier (task_decl));
  1122. gcc_assert (cl_decl != NULL_TREE && TREE_CODE (cl_decl) == VAR_DECL);
  1123. /* Turn the codelet declaration into a definition. */
  1124. TREE_TYPE (cl_decl) = codelet_type ();
  1125. TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
  1126. return cl_decl;
  1127. }
  1128. static void
  1129. handle_pre_genericize (void *gcc_data, void *user_data)
  1130. {
  1131. tree fn = (tree) gcc_data;
  1132. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  1133. if (task_p (fn) && TREE_STATIC (fn))
  1134. /* The user defined a body for task FN, which is forbidden. */
  1135. error_at (DECL_SOURCE_LOCATION (fn),
  1136. "task %qE must not have a body", DECL_NAME (fn));
  1137. else if (task_implementation_p (fn))
  1138. {
  1139. tree task = task_implementation_task (fn);
  1140. if (!TREE_STATIC (task))
  1141. {
  1142. /* TASK lacks a body. Declare its codelet, intantiate its codelet
  1143. wrappers, and its body in this compilation unit. */
  1144. tree build_parameter (const_tree lst)
  1145. {
  1146. tree param, type;
  1147. type = TREE_VALUE (lst);
  1148. param = build_decl (DECL_SOURCE_LOCATION (task), PARM_DECL,
  1149. create_tmp_var_name ("parameter"),
  1150. type);
  1151. DECL_ARG_TYPE (param) = type;
  1152. DECL_CONTEXT (param) = task;
  1153. return param;
  1154. }
  1155. /* Declare TASK's codelet. It cannot be defined yet because the
  1156. complete list of tasks isn't available at this point. */
  1157. declare_codelet (task);
  1158. /* Set the task's parameter list. */
  1159. DECL_ARGUMENTS (task) =
  1160. map (build_parameter,
  1161. list_remove (void_type_p,
  1162. TYPE_ARG_TYPES (TREE_TYPE (task))));
  1163. /* Build its body. */
  1164. DECL_SAVED_TREE (task) = build_task_body (task);
  1165. TREE_STATIC (task) = true;
  1166. DECL_EXTERNAL (task) = false;
  1167. DECL_INITIAL (task) = build_block (NULL_TREE, NULL_TREE, task, NULL_TREE);
  1168. DECL_RESULT (task) =
  1169. build_decl (DECL_SOURCE_LOCATION (task), RESULT_DECL,
  1170. NULL_TREE, void_type_node);
  1171. DECL_CONTEXT (DECL_RESULT (task)) = task;
  1172. /* Compile TASK's body. */
  1173. rest_of_decl_compilation (task, true, 0);
  1174. allocate_struct_function (task, false);
  1175. cgraph_finalize_function (task, false);
  1176. }
  1177. }
  1178. }
  1179. /* Build a "conversion" from a raw C pointer to its data handle. The
  1180. assumption is that the programmer should have already registered the
  1181. pointer by themselves. */
  1182. static tree
  1183. build_pointer_lookup (tree pointer)
  1184. {
  1185. #if 0
  1186. gimple emit_error_message (void)
  1187. {
  1188. static const char msg[] =
  1189. "starpu: task called with unregistered pointer, aborting\n";
  1190. return gimple_build_call (built_in_decls[BUILT_IN_PUTS], 1,
  1191. build_string_literal (strlen (msg) + 1, msg));
  1192. }
  1193. #endif
  1194. static tree data_lookup_fn;
  1195. LOOKUP_STARPU_FUNCTION (data_lookup_fn, "starpu_data_lookup");
  1196. return build_call_expr (data_lookup_fn, 1, pointer);
  1197. /* FIXME: Add `if (VAR == NULL) abort ();'. */
  1198. }
  1199. /* Build the body of TASK_DECL, which will call `starpu_insert_task'. */
  1200. static tree
  1201. build_task_body (const_tree task_decl)
  1202. {
  1203. VEC(tree, gc) *args = NULL;
  1204. tree p, params = DECL_ARGUMENTS (task_decl);
  1205. /* The first argument will be a pointer to the codelet. */
  1206. VEC_safe_push (tree, gc, args,
  1207. build_addr (task_codelet_declaration (task_decl),
  1208. current_function_decl));
  1209. for (p = params; p != NULL_TREE; p = TREE_CHAIN (p))
  1210. {
  1211. gcc_assert (TREE_CODE (p) == PARM_DECL);
  1212. tree type = TREE_TYPE (p);
  1213. if (POINTER_TYPE_P (type))
  1214. {
  1215. /* A pointer: the arguments will be:
  1216. `STARPU_RW, ptr' or similar. */
  1217. /* If TYPE points to a const-qualified type, then mark the data as
  1218. read-only; otherwise default to read-write.
  1219. FIXME: Add an attribute to specify write-only. */
  1220. int mode =
  1221. (TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
  1222. ? STARPU_R : STARPU_RW;
  1223. VEC_safe_push (tree, gc, args,
  1224. build_int_cst (integer_type_node, mode));
  1225. VEC_safe_push (tree, gc, args, build_pointer_lookup (p));
  1226. }
  1227. else
  1228. {
  1229. /* A scalar: the arguments will be:
  1230. `STARPU_VALUE, &scalar, sizeof (scalar)'. */
  1231. mark_addressable (p);
  1232. VEC_safe_push (tree, gc, args,
  1233. build_int_cst (integer_type_node, STARPU_VALUE));
  1234. VEC_safe_push (tree, gc, args,
  1235. build_addr (p, current_function_decl));
  1236. VEC_safe_push (tree, gc, args,
  1237. size_in_bytes (type));
  1238. }
  1239. }
  1240. /* Push the terminating zero. */
  1241. VEC_safe_push (tree, gc, args,
  1242. build_int_cst (integer_type_node, 0));
  1243. static tree insert_task_fn;
  1244. LOOKUP_STARPU_FUNCTION (insert_task_fn, "starpu_insert_task");
  1245. return build_call_expr_loc_vec (DECL_SOURCE_LOCATION (task_decl),
  1246. insert_task_fn, args);
  1247. }
  1248. static unsigned int
  1249. lower_starpu (void)
  1250. {
  1251. tree fndecl;
  1252. const struct cgraph_node *cgraph;
  1253. const struct cgraph_edge *callee;
  1254. fndecl = current_function_decl;
  1255. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  1256. if (task_p (fndecl))
  1257. {
  1258. /* Generate a `struct starpu_codelet' structure and a wrapper function for
  1259. each implementation of TASK_DECL. This cannot be done earlier
  1260. because we need to have a complete list of task implementations. */
  1261. define_codelet_wrappers (fndecl);
  1262. tree cl_def = task_codelet_declaration (fndecl);
  1263. DECL_INITIAL (cl_def) = build_codelet_initializer (fndecl);
  1264. TREE_STATIC (cl_def) = true;
  1265. DECL_EXTERNAL (cl_def) = false;
  1266. varpool_finalize_decl (cl_def);
  1267. }
  1268. /* This pass should occur after `build_cgraph_edges'. */
  1269. cgraph = cgraph_get_node (fndecl);
  1270. gcc_assert (cgraph != NULL);
  1271. if (MAIN_NAME_P (DECL_NAME (fndecl)))
  1272. {
  1273. /* Check whether FNDECL initializes StarPU and emit a warning if it
  1274. doesn't. */
  1275. bool initialized;
  1276. for (initialized = false, callee = cgraph->callees;
  1277. !initialized && callee != NULL;
  1278. callee = callee->next_callee)
  1279. {
  1280. initialized =
  1281. DECL_NAME (callee->callee->decl) == get_identifier ("starpu_init");
  1282. }
  1283. if (!initialized)
  1284. warning_at (DECL_SOURCE_LOCATION (fndecl), 0,
  1285. "%qE does not initialize StarPU", DECL_NAME (fndecl));
  1286. }
  1287. for (callee = cgraph->callees;
  1288. callee != NULL;
  1289. callee = callee->next_callee)
  1290. {
  1291. gcc_assert (callee->callee != NULL);
  1292. tree callee_decl;
  1293. callee_decl = callee->callee->decl;
  1294. if (lookup_attribute (task_attribute_name,
  1295. DECL_ATTRIBUTES (callee_decl)))
  1296. {
  1297. printf ("%s: `%s' calls task `%s'\n", __func__,
  1298. IDENTIFIER_POINTER (DECL_NAME (fndecl)),
  1299. IDENTIFIER_POINTER (DECL_NAME (callee_decl)));
  1300. /* TODO: Insert analysis to check whether the pointer arguments
  1301. need to be registered. */
  1302. }
  1303. }
  1304. return 0;
  1305. }
  1306. static struct opt_pass pass_lower_starpu =
  1307. {
  1308. .type = GIMPLE_PASS,
  1309. .name = "pass_lower_starpu",
  1310. .execute = lower_starpu,
  1311. /* The rest is zeroed. */
  1312. };
  1313. /* Initialization. */
  1314. static void
  1315. define_cpp_macros (void *gcc_data, void *user_data)
  1316. {
  1317. cpp_define (parse_in, "STARPU_GCC_PLUGIN=0");
  1318. cpp_push_include (parse_in, "starpu.h");
  1319. }
  1320. int
  1321. plugin_init (struct plugin_name_args *plugin_info,
  1322. struct plugin_gcc_version *version)
  1323. {
  1324. if (!plugin_default_version_check (version, &gcc_version))
  1325. return 1;
  1326. register_callback (plugin_name, PLUGIN_START_UNIT,
  1327. define_cpp_macros, NULL);
  1328. register_callback (plugin_name, PLUGIN_PRAGMAS,
  1329. register_pragmas, NULL);
  1330. register_callback (plugin_name, PLUGIN_ATTRIBUTES,
  1331. register_task_attributes, NULL);
  1332. register_callback (plugin_name, PLUGIN_PRE_GENERICIZE,
  1333. handle_pre_genericize, NULL);
  1334. /* Register our pass so that it happens after `build_cgraph_edges' has been
  1335. done. */
  1336. struct register_pass_info pass_info =
  1337. {
  1338. .pass = &pass_lower_starpu,
  1339. .reference_pass_name = "*build_cgraph_edges",
  1340. .ref_pass_instance_number = 1,
  1341. .pos_op = PASS_POS_INSERT_AFTER
  1342. };
  1343. register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP,
  1344. NULL, &pass_info);
  1345. return 0;
  1346. }