starpu.c 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800
  1. /* GCC-StarPU
  2. Copyright (C) 2011, 2012 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. /* We must include starpu.h here, otherwise gcc will complain about a poisoned
  17. malloc in xmmintrin.h. */
  18. #include <starpu.h> /* for `STARPU_CPU' & co. */
  19. /* #define ENABLE_TREE_CHECKING 1 */
  20. #include <gcc-plugin.h>
  21. #include <plugin-version.h>
  22. #include <plugin.h>
  23. #include <cpplib.h>
  24. #include <tree.h>
  25. #include <tree-iterator.h>
  26. #include <flags.h> /* for `optimize' */
  27. #ifdef HAVE_C_FAMILY_C_COMMON_H
  28. # include <c-family/c-common.h>
  29. #elif HAVE_C_COMMON_H
  30. # include <c-common.h>
  31. #endif
  32. #ifdef HAVE_C_FAMILY_C_PRAGMA_H
  33. # include <c-family/c-pragma.h>
  34. #elif HAVE_C_PRAGMA_H
  35. # include <c-pragma.h>
  36. #endif
  37. #include <tm.h>
  38. #include <tree-pass.h>
  39. #include <tree-flow.h>
  40. #include <cgraph.h>
  41. #include <gimple.h>
  42. #include <toplev.h>
  43. #include <stdio.h>
  44. #include <starpu-gcc/utils.h>
  45. #include <starpu-gcc/tasks.h>
  46. #include <starpu-gcc/warn-unregistered.h>
  47. #include <starpu-gcc/opencl.h>
  48. /* Don't include the dreaded proprietary headers that we don't need anyway.
  49. In particular, this waives the obligation to reproduce their silly
  50. disclaimer. */
  51. #define STARPU_DONT_INCLUDE_CUDA_HEADERS
  52. #ifndef STRINGIFY
  53. # define STRINGIFY_(x) # x
  54. # define STRINGIFY(x) STRINGIFY_ (x)
  55. #endif
  56. #ifdef __cplusplus
  57. extern "C" {
  58. #endif
  59. /* Declared with `C' linkage in <gcc-plugin.h>. */
  60. int plugin_is_GPL_compatible;
  61. /* The name of this plug-in. */
  62. static const char plugin_name[] = "starpu";
  63. /* Names of public attributes. */
  64. static const char heap_allocated_attribute_name[] = "heap_allocated";
  65. static const char registered_attribute_name[] = "registered";
  66. /* Names of attributes used internally. */
  67. static const char heap_allocated_orig_type_attribute_name[] =
  68. ".heap_allocated_original_type";
  69. /* Cached function declarations. */
  70. static tree unpack_fn;
  71. /* Targets supported by GCC-StarPU. */
  72. static int supported_targets = 0
  73. #ifdef STARPU_USE_CPU
  74. | STARPU_CPU
  75. #endif
  76. #ifdef STARPU_USE_CUDA
  77. | STARPU_CUDA
  78. #endif
  79. #ifdef STARPU_USE_OPENCL
  80. | STARPU_OPENCL
  81. #endif
  82. #ifdef STARPU_USE_GORDON
  83. | STARPU_GORDON
  84. #endif
  85. ;
  86. /* Forward declarations. */
  87. static tree build_cpu_codelet_identifier (const_tree task);
  88. static bool implicit_cpu_task_implementation_p (const_tree fn);
  89. static bool heap_allocated_p (const_tree var_decl);
  90. static bool registered_p (const_tree var_decl);
  91. /* Compile-time assertions. */
  92. #if STARPU_GNUC_PREREQ (4, 6)
  93. # define verify(cond, msg) _Static_assert ((cond), msg)
  94. #else
  95. # define verify(cond, msg) assert (cond);
  96. #endif
  97. /* Helpers. */
  98. /* Return POINTER plus OFFSET, where OFFSET is in bytes. */
  99. static tree
  100. pointer_plus (tree pointer, size_t offset)
  101. {
  102. gcc_assert (POINTER_TYPE_P (TREE_TYPE (pointer)));
  103. if (offset == 0)
  104. return pointer;
  105. else
  106. return build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR,
  107. pointer,
  108. build_int_cstu (integer_type_node, offset),
  109. false);
  110. }
  111. /* Build a reference to the INDEXth element of ARRAY. `build_array_ref' is
  112. not exported, so we roll our own.
  113. FIXME: This version may not work for array types and doesn't do as much
  114. type-checking as `build_array_ref'. */
  115. static tree
  116. array_ref (tree array, size_t index)
  117. {
  118. gcc_assert (POINTER_TYPE_P (TREE_TYPE (array)));
  119. return build_indirect_ref (UNKNOWN_LOCATION,
  120. pointer_plus (array, index),
  121. RO_ARRAY_INDEXING);
  122. }
  123. /* Return the number of elements of ARRAY_TYPE, or NULL_TREE if ARRAY_TYPE is
  124. an incomplete type. */
  125. static tree
  126. array_type_element_count (location_t loc, const_tree array_type)
  127. {
  128. gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
  129. tree count, domain = TYPE_DOMAIN (array_type);
  130. if (domain != NULL_TREE)
  131. {
  132. count = build_binary_op (loc, MINUS_EXPR,
  133. TYPE_MAX_VALUE (domain),
  134. TYPE_MIN_VALUE (domain),
  135. false);
  136. count = build_binary_op (loc, PLUS_EXPR,
  137. count,
  138. build_int_cstu (integer_type_node, 1),
  139. false);
  140. count = fold_convert (size_type_node, count);
  141. }
  142. else
  143. count = NULL_TREE;
  144. return count;
  145. }
  146. /* Debugging helpers. */
  147. static tree build_printf (const char *, ...)
  148. __attribute__ ((format (printf, 1, 2)));
  149. static tree
  150. build_printf (const char *fmt, ...)
  151. {
  152. tree call;
  153. char *str;
  154. va_list args;
  155. va_start (args, fmt);
  156. vasprintf (&str, fmt, args);
  157. call = build_call_expr (builtin_decl_explicit (BUILT_IN_PUTS), 1,
  158. build_string_literal (strlen (str) + 1, str));
  159. free (str);
  160. va_end (args);
  161. return call;
  162. }
  163. static tree
  164. build_hello_world (void)
  165. {
  166. return build_printf ("Hello, StarPU!");
  167. }
  168. /* Pragmas. */
  169. #define STARPU_PRAGMA_NAME_SPACE "starpu"
  170. static void
  171. handle_pragma_hello (struct cpp_reader *reader)
  172. {
  173. add_stmt (build_hello_world ());
  174. }
  175. /* Process `#pragma starpu initialize'.
  176. TODO: Parse and initialize some of the fields of `starpu_conf'. */
  177. static void
  178. handle_pragma_initialize (struct cpp_reader *reader)
  179. {
  180. static tree init_fn;
  181. LOOKUP_STARPU_FUNCTION (init_fn, "starpu_init");
  182. location_t loc = cpp_peek_token (reader, 0)->src_loc;
  183. /* Call `starpu_init (NULL)'. */
  184. tree init = build_call_expr (init_fn, 1, build_zero_cst (ptr_type_node));
  185. /* Introduce a local variable to hold the error code. */
  186. tree error_var = build_decl (loc, VAR_DECL,
  187. create_tmp_var_name (".initialize_error"),
  188. integer_type_node);
  189. DECL_CONTEXT (error_var) = current_function_decl;
  190. DECL_ARTIFICIAL (error_var) = true;
  191. tree assignment = build2 (INIT_EXPR, TREE_TYPE (error_var),
  192. error_var, init);
  193. tree cond = build3 (COND_EXPR, void_type_node,
  194. build2 (NE_EXPR, boolean_type_node,
  195. error_var, integer_zero_node),
  196. build_error_statements (loc, error_var,
  197. build_starpu_error_string,
  198. "failed to initialize StarPU"),
  199. NULL_TREE);
  200. tree stmts = NULL_TREE;
  201. append_to_statement_list (assignment, &stmts);
  202. append_to_statement_list (cond, &stmts);
  203. tree bind = build3 (BIND_EXPR, void_type_node, error_var, stmts,
  204. NULL_TREE);
  205. add_stmt (bind);
  206. }
  207. /* Process `#pragma starpu shutdown'. */
  208. static void
  209. handle_pragma_shutdown (struct cpp_reader *reader)
  210. {
  211. static tree shutdown_fn;
  212. LOOKUP_STARPU_FUNCTION (shutdown_fn, "starpu_shutdown");
  213. tree token;
  214. if (pragma_lex (&token) != CPP_EOF)
  215. error_at (cpp_peek_token (reader, 0)->src_loc,
  216. "junk after %<starpu shutdown%> pragma");
  217. else
  218. /* Call `starpu_shutdown ()'. */
  219. add_stmt (build_call_expr (shutdown_fn, 0));
  220. }
  221. static void
  222. handle_pragma_wait (struct cpp_reader *reader)
  223. {
  224. if (task_implementation_p (current_function_decl))
  225. {
  226. location_t loc;
  227. loc = cpp_peek_token (reader, 0)->src_loc;
  228. /* TODO: In the future we could generate a task for the continuation
  229. and have it depend on what's before here. */
  230. error_at (loc, "task implementation is not allowed to wait");
  231. }
  232. else
  233. {
  234. tree fndecl;
  235. fndecl = lookup_name (get_identifier ("starpu_task_wait_for_all"));
  236. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  237. add_stmt (build_call_expr (fndecl, 0));
  238. }
  239. }
  240. /* Build a `starpu_vector_data_register' call for the COUNT elements pointed
  241. to by POINTER. */
  242. static tree
  243. build_data_register_call (location_t loc, tree pointer, tree count)
  244. {
  245. tree pointer_type = TREE_TYPE (pointer);
  246. gcc_assert ((TREE_CODE (pointer_type) == ARRAY_TYPE
  247. && TYPE_DOMAIN (pointer_type) != NULL_TREE)
  248. || POINTER_TYPE_P (pointer_type));
  249. gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (count)));
  250. static tree register_fn;
  251. LOOKUP_STARPU_FUNCTION (register_fn, "starpu_vector_data_register");
  252. /* Introduce a local variable to hold the handle. */
  253. tree handle_var = build_decl (loc, VAR_DECL, create_tmp_var_name (".handle"),
  254. ptr_type_node);
  255. DECL_CONTEXT (handle_var) = current_function_decl;
  256. DECL_ARTIFICIAL (handle_var) = true;
  257. DECL_INITIAL (handle_var) = NULL_TREE;
  258. /* If PTR is an array, take its address. */
  259. tree actual_pointer =
  260. POINTER_TYPE_P (pointer_type)
  261. ? pointer
  262. : build_addr (pointer, current_function_decl);
  263. /* Build `starpu_vector_data_register (&HANDLE_VAR, 0, POINTER,
  264. COUNT, sizeof *POINTER)' */
  265. tree call =
  266. build_call_expr (register_fn, 5,
  267. build_addr (handle_var, current_function_decl),
  268. build_zero_cst (uintptr_type_node), /* home node */
  269. actual_pointer, count,
  270. size_in_bytes (TREE_TYPE (pointer_type)));
  271. return build3 (BIND_EXPR, void_type_node, handle_var, call,
  272. NULL_TREE);
  273. }
  274. /* Return a `starpu_data_unregister' call for VAR. */
  275. static tree
  276. build_data_unregister_call (location_t loc, tree var)
  277. {
  278. static tree unregister_fn;
  279. LOOKUP_STARPU_FUNCTION (unregister_fn, "starpu_data_unregister");
  280. /* If VAR is an array, take its address. */
  281. tree pointer =
  282. POINTER_TYPE_P (TREE_TYPE (var))
  283. ? var
  284. : build_addr (var, current_function_decl);
  285. /* Call `starpu_data_unregister (starpu_data_lookup (ptr))'. */
  286. return build_call_expr (unregister_fn, 1,
  287. build_pointer_lookup (pointer));
  288. }
  289. /* Process `#pragma starpu register VAR [COUNT]' and emit the corresponding
  290. `starpu_vector_data_register' call. */
  291. static void
  292. handle_pragma_register (struct cpp_reader *reader)
  293. {
  294. tree args, ptr, count_arg;
  295. location_t loc;
  296. loc = cpp_peek_token (reader, 0)->src_loc;
  297. args = read_pragma_expressions ("register", loc);
  298. if (args == NULL_TREE)
  299. /* Parse error, presumably already handled by the parser. */
  300. return;
  301. /* First argument should be a pointer expression. */
  302. ptr = TREE_VALUE (args);
  303. args = TREE_CHAIN (args);
  304. if (ptr == error_mark_node)
  305. return;
  306. tree ptr_type;
  307. if (DECL_P (ptr))
  308. {
  309. tree heap_attr =
  310. lookup_attribute (heap_allocated_orig_type_attribute_name,
  311. DECL_ATTRIBUTES (ptr));
  312. if (heap_attr != NULL_TREE)
  313. /* PTR is `heap_allocated' so use its original array type to
  314. determine its size. */
  315. ptr_type = TREE_VALUE (heap_attr);
  316. else
  317. ptr_type = TREE_TYPE (ptr);
  318. }
  319. else
  320. ptr_type = TREE_TYPE (ptr);
  321. if (ptr_type == NULL_TREE)
  322. {
  323. /* PTR is a type-less thing, such as a STRING_CST. */
  324. error_at (loc, "invalid %<register%> argument");
  325. return;
  326. }
  327. if (!POINTER_TYPE_P (ptr_type)
  328. && TREE_CODE (ptr_type) != ARRAY_TYPE)
  329. {
  330. error_at (loc, "%qE is neither a pointer nor an array", ptr);
  331. return;
  332. }
  333. /* Since we implicitly use sizeof (*PTR), `void *' is not allowed. */
  334. if (VOID_TYPE_P (TREE_TYPE (ptr_type)))
  335. {
  336. error_at (loc, "pointers to %<void%> not allowed "
  337. "in %<register%> pragma");
  338. return;
  339. }
  340. TREE_USED (ptr) = true;
  341. #ifdef DECL_READ_P
  342. if (DECL_P (ptr))
  343. DECL_READ_P (ptr) = true;
  344. #endif
  345. if (TREE_CODE (ptr_type) == ARRAY_TYPE
  346. && !DECL_EXTERNAL (ptr)
  347. && !TREE_STATIC (ptr)
  348. && !(TREE_CODE (ptr) == VAR_DECL && heap_allocated_p (ptr))
  349. && !MAIN_NAME_P (DECL_NAME (current_function_decl)))
  350. warning_at (loc, 0, "using an on-stack array as a task input "
  351. "considered unsafe");
  352. /* Determine the number of elements in the vector. */
  353. tree count = NULL_TREE;
  354. if (TREE_CODE (ptr_type) == ARRAY_TYPE)
  355. count = array_type_element_count (loc, ptr_type);
  356. /* Second argument is optional but should be an integer. */
  357. count_arg = (args == NULL_TREE) ? NULL_TREE : TREE_VALUE (args);
  358. if (args != NULL_TREE)
  359. args = TREE_CHAIN (args);
  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. #ifdef DECL_READ_P
  382. if (DECL_P (count_arg))
  383. DECL_READ_P (count_arg) = true;
  384. #endif
  385. if (count != NULL_TREE)
  386. {
  387. /* The number of elements of this array was already determined. */
  388. inform (loc,
  389. "element count can be omitted for bounded array %qE",
  390. ptr);
  391. if (count_arg != NULL_TREE)
  392. {
  393. if (TREE_CODE (count_arg) == INTEGER_CST)
  394. {
  395. if (!tree_int_cst_equal (count, count_arg))
  396. error_at (loc, "specified element count differs "
  397. "from actual size of array %qE",
  398. ptr);
  399. }
  400. else
  401. /* Using a variable to determine the array size whereas the
  402. array size is actually known statically. This looks like
  403. unreasonable code, so error out. */
  404. error_at (loc, "determining array size at run-time "
  405. "although array size is known at compile-time");
  406. }
  407. }
  408. else
  409. count = count_arg;
  410. }
  411. /* Any remaining args? */
  412. if (args != NULL_TREE)
  413. error_at (loc, "junk after %<starpu register%> pragma");
  414. /* Add a data register call. */
  415. add_stmt (build_data_register_call (loc, ptr, count));
  416. }
  417. /* Process `#pragma starpu acquire VAR' and emit the corresponding
  418. `starpu_data_acquire' call. */
  419. static void
  420. handle_pragma_acquire (struct cpp_reader *reader)
  421. {
  422. static tree acquire_fn;
  423. LOOKUP_STARPU_FUNCTION (acquire_fn, "starpu_data_acquire");
  424. tree args, var;
  425. location_t loc;
  426. loc = cpp_peek_token (reader, 0)->src_loc;
  427. args = read_pragma_expressions ("acquire", loc);
  428. if (args == NULL_TREE)
  429. return;
  430. var = TREE_VALUE (args);
  431. if (var == error_mark_node)
  432. return;
  433. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  434. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  435. {
  436. error_at (loc, "%qE is neither a pointer nor an array", var);
  437. return;
  438. }
  439. else if (TREE_CHAIN (args) != NULL_TREE)
  440. error_at (loc, "junk after %<starpu acquire%> pragma");
  441. /* If VAR is an array, take its address. */
  442. tree pointer =
  443. POINTER_TYPE_P (TREE_TYPE (var))
  444. ? var
  445. : build_addr (var, current_function_decl);
  446. /* Call `starpu_data_acquire (starpu_data_lookup (ptr), STARPU_RW)'.
  447. TODO: Support modes other than RW. */
  448. add_stmt (build_call_expr (acquire_fn, 2,
  449. build_pointer_lookup (pointer),
  450. build_int_cst (integer_type_node, STARPU_RW)));
  451. }
  452. /* Process `#pragma starpu release VAR' and emit the corresponding
  453. `starpu_data_release' call. */
  454. static void
  455. handle_pragma_release (struct cpp_reader *reader)
  456. {
  457. static tree release_fn;
  458. LOOKUP_STARPU_FUNCTION (release_fn, "starpu_data_release");
  459. tree args, var;
  460. location_t loc;
  461. loc = cpp_peek_token (reader, 0)->src_loc;
  462. args = read_pragma_expressions ("release", loc);
  463. if (args == NULL_TREE)
  464. return;
  465. var = TREE_VALUE (args);
  466. if (var == error_mark_node)
  467. return;
  468. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  469. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  470. {
  471. error_at (loc, "%qE is neither a pointer nor an array", var);
  472. return;
  473. }
  474. else if (TREE_CHAIN (args) != NULL_TREE)
  475. error_at (loc, "junk after %<starpu release%> pragma");
  476. /* If VAR is an array, take its address. */
  477. tree pointer =
  478. POINTER_TYPE_P (TREE_TYPE (var))
  479. ? var
  480. : build_addr (var, current_function_decl);
  481. /* Call `starpu_data_release (starpu_data_lookup (ptr))'. */
  482. add_stmt (build_call_expr (release_fn, 1,
  483. build_pointer_lookup (pointer)));
  484. }
  485. /* Process `#pragma starpu unregister VAR' and emit the corresponding
  486. `starpu_data_unregister' call. */
  487. static void
  488. handle_pragma_unregister (struct cpp_reader *reader)
  489. {
  490. tree args, var;
  491. location_t loc;
  492. loc = cpp_peek_token (reader, 0)->src_loc;
  493. args = read_pragma_expressions ("unregister", loc);
  494. if (args == NULL_TREE)
  495. return;
  496. var = TREE_VALUE (args);
  497. if (var == error_mark_node)
  498. return;
  499. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  500. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  501. {
  502. error_at (loc, "%qE is neither a pointer nor an array", var);
  503. return;
  504. }
  505. else if (TREE_CHAIN (args) != NULL_TREE)
  506. error_at (loc, "junk after %<starpu unregister%> pragma");
  507. add_stmt (build_data_unregister_call (loc, var));
  508. }
  509. /* Handle the `debug_tree' pragma (for debugging purposes.) */
  510. static void
  511. handle_pragma_debug_tree (struct cpp_reader *reader)
  512. {
  513. tree args, obj;
  514. location_t loc;
  515. loc = cpp_peek_token (reader, 0)->src_loc;
  516. args = read_pragma_expressions ("debug_tree", loc);
  517. if (args == NULL_TREE)
  518. /* Parse error, presumably already handled by the parser. */
  519. return;
  520. obj = TREE_VALUE (args);
  521. args = TREE_CHAIN (args);
  522. if (obj == error_mark_node)
  523. return;
  524. if (args != NULL_TREE)
  525. warning_at (loc, 0, "extraneous arguments ignored");
  526. inform (loc, "debug_tree:");
  527. debug_tree (obj);
  528. printf ("\n");
  529. }
  530. /* Handle the `#pragma starpu add_target TARGET', which tells GCC-StarPU to
  531. consider TARGET ("cpu", "opencl", etc.) as supported. This pragma is
  532. undocumented and only meant to be used for testing purposes. */
  533. static void
  534. handle_pragma_add_target (struct cpp_reader *reader)
  535. {
  536. tree args, obj;
  537. location_t loc;
  538. loc = cpp_peek_token (reader, 0)->src_loc;
  539. args = read_pragma_expressions ("add_target", loc);
  540. if (args == NULL_TREE)
  541. /* Parse error, presumably already handled by the parser. */
  542. return;
  543. obj = TREE_VALUE (args);
  544. args = TREE_CHAIN (args);
  545. if (obj == error_mark_node)
  546. return;
  547. if (args != NULL_TREE)
  548. warning_at (loc, 0, "extraneous arguments ignored");
  549. if (TREE_CODE (obj) == STRING_CST)
  550. {
  551. int new_target = task_implementation_target_to_int (obj);
  552. if (obj == 0)
  553. error_at (loc, "unsupported target %qE", obj);
  554. else
  555. supported_targets |= new_target;
  556. }
  557. else
  558. error_at (loc, "expecting string literal");
  559. }
  560. static void
  561. register_pragmas (void *gcc_data, void *user_data)
  562. {
  563. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "hello",
  564. handle_pragma_hello);
  565. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "debug_tree",
  566. handle_pragma_debug_tree);
  567. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "add_target",
  568. handle_pragma_add_target);
  569. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "initialize",
  570. handle_pragma_initialize);
  571. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "wait",
  572. handle_pragma_wait);
  573. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "register",
  574. handle_pragma_register);
  575. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "acquire",
  576. handle_pragma_acquire);
  577. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "release",
  578. handle_pragma_release);
  579. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "unregister",
  580. handle_pragma_unregister);
  581. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "opencl",
  582. handle_pragma_opencl);
  583. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "shutdown",
  584. handle_pragma_shutdown);
  585. }
  586. /* Attributes. */
  587. /* Handle the `task' function attribute. */
  588. static tree
  589. handle_task_attribute (tree *node, tree name, tree args,
  590. int flags, bool *no_add_attrs)
  591. {
  592. tree fn;
  593. fn = *node;
  594. /* Get rid of the `task' attribute by default so that FN isn't further
  595. processed when it's erroneous. */
  596. *no_add_attrs = true;
  597. if (TREE_CODE (fn) != FUNCTION_DECL)
  598. error_at (DECL_SOURCE_LOCATION (fn),
  599. "%<task%> attribute only applies to functions");
  600. else
  601. {
  602. if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fn))))
  603. /* Raise an error but keep going to avoid spitting out too many
  604. errors at the user's face. */
  605. error_at (DECL_SOURCE_LOCATION (fn),
  606. "task return type must be %<void%>");
  607. if (count (pointer_type_p, TYPE_ARG_TYPES (TREE_TYPE (fn)))
  608. > STARPU_NMAXBUFS)
  609. error_at (DECL_SOURCE_LOCATION (fn),
  610. "maximum number of pointer parameters exceeded");
  611. /* Turn FN into an actual task. */
  612. taskify_function (fn);
  613. }
  614. /* Lookup & cache function declarations for later reuse. */
  615. LOOKUP_STARPU_FUNCTION (unpack_fn, "starpu_codelet_unpack_args");
  616. return NULL_TREE;
  617. }
  618. /* Handle the `task_implementation (WHERE, TASK)' attribute. WHERE is a
  619. string constant ("cpu", "cuda", etc.), and TASK is the identifier of a
  620. function declared with the `task' attribute. */
  621. static tree
  622. handle_task_implementation_attribute (tree *node, tree name, tree args,
  623. int flags, bool *no_add_attrs)
  624. {
  625. location_t loc;
  626. tree fn, where, task_decl;
  627. /* FIXME:TODO: To change the order to (TASK, WHERE):
  628. tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
  629. tree cleanup_decl = lookup_name (cleanup_id);
  630. */
  631. fn = *node;
  632. where = TREE_VALUE (args);
  633. task_decl = TREE_VALUE (TREE_CHAIN (args));
  634. if (implicit_cpu_task_implementation_p (task_decl))
  635. /* TASK_DECL is actually a CPU implementation. Implicit CPU task
  636. implementations can lead to this situation, because the task is
  637. renamed and modified to become a CPU implementation. */
  638. task_decl = task_implementation_task (task_decl);
  639. loc = DECL_SOURCE_LOCATION (fn);
  640. /* Get rid of the `task_implementation' attribute by default so that FN
  641. isn't further processed when it's erroneous. */
  642. *no_add_attrs = true;
  643. /* Mark FN as used to placate `-Wunused-function' when FN is erroneous
  644. anyway. */
  645. TREE_USED (fn) = true;
  646. if (TREE_CODE (fn) != FUNCTION_DECL)
  647. error_at (loc,
  648. "%<task_implementation%> attribute only applies to functions");
  649. else if (TREE_CODE (where) != STRING_CST)
  650. error_at (loc, "string constant expected "
  651. "as the first %<task_implementation%> argument");
  652. else if (TREE_CODE (task_decl) != FUNCTION_DECL)
  653. error_at (loc, "%qE is not a function", task_decl);
  654. else if (lookup_attribute (task_attribute_name,
  655. DECL_ATTRIBUTES (task_decl)) == NULL_TREE)
  656. error_at (loc, "function %qE lacks the %<task%> attribute",
  657. DECL_NAME (task_decl));
  658. else if (TYPE_CANONICAL (TREE_TYPE (fn))
  659. != TYPE_CANONICAL (TREE_TYPE (task_decl)))
  660. error_at (loc, "type differs from that of task %qE",
  661. DECL_NAME (task_decl));
  662. else
  663. {
  664. /* Add FN to the list of implementations of TASK_DECL. */
  665. add_task_implementation (task_decl, fn, where);
  666. /* Keep the attribute. */
  667. *no_add_attrs = false;
  668. }
  669. return NULL_TREE;
  670. }
  671. /* Return true when VAR is an automatic variable with complete array type;
  672. otherwise, return false, and emit error messages mentioning ATTRIBUTE. */
  673. static bool
  674. automatic_array_variable_p (const char *attribute, tree var)
  675. {
  676. gcc_assert (TREE_CODE (var) == VAR_DECL);
  677. location_t loc;
  678. loc = DECL_SOURCE_LOCATION (var);
  679. if (DECL_EXTERNAL (var))
  680. error_at (loc, "attribute %qs cannot be used on external declarations",
  681. attribute);
  682. else if (TREE_PUBLIC (var) || TREE_STATIC (var))
  683. {
  684. error_at (loc, "attribute %qs cannot be used on global variables",
  685. attribute);
  686. TREE_TYPE (var) = error_mark_node;
  687. }
  688. else if (TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  689. {
  690. error_at (loc, "variable %qE must have an array type",
  691. DECL_NAME (var));
  692. TREE_TYPE (var) = error_mark_node;
  693. }
  694. else if (TYPE_SIZE (TREE_TYPE (var)) == NULL_TREE)
  695. {
  696. error_at (loc, "variable %qE has an incomplete array type",
  697. DECL_NAME (var));
  698. TREE_TYPE (var) = error_mark_node;
  699. }
  700. else
  701. return true;
  702. return false;
  703. }
  704. /* Handle the `heap_allocated' attribute on variable *NODE. */
  705. static tree
  706. handle_heap_allocated_attribute (tree *node, tree name, tree args,
  707. int flags, bool *no_add_attrs)
  708. {
  709. tree var = *node;
  710. if (automatic_array_variable_p (heap_allocated_attribute_name, var))
  711. {
  712. /* Turn VAR into a pointer that feels like an array. This is what's
  713. done for PARM_DECLs that have an array type. */
  714. location_t loc = DECL_SOURCE_LOCATION (var);
  715. tree array_type = TREE_TYPE (var);
  716. tree element_type = TREE_TYPE (array_type);
  717. tree pointer_type = build_pointer_type (element_type);
  718. /* Keep a copy of VAR's original type. */
  719. DECL_ATTRIBUTES (var) =
  720. tree_cons (get_identifier (heap_allocated_orig_type_attribute_name),
  721. array_type, DECL_ATTRIBUTES (var));
  722. TREE_TYPE (var) = pointer_type;
  723. DECL_SIZE (var) = TYPE_SIZE (pointer_type);
  724. DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (pointer_type);
  725. DECL_ALIGN (var) = TYPE_ALIGN (pointer_type);
  726. DECL_USER_ALIGN (var) = false;
  727. DECL_MODE (var) = TYPE_MODE (pointer_type);
  728. tree malloc_fn = lookup_name (get_identifier ("starpu_malloc"));
  729. gcc_assert (malloc_fn != NULL_TREE);
  730. tree alloc = build_call_expr (malloc_fn, 2,
  731. build_addr (var, current_function_decl),
  732. TYPE_SIZE_UNIT (array_type));
  733. TREE_SIDE_EFFECTS (alloc) = true;
  734. /* Add a destructor for VAR. Instead of consing the `cleanup'
  735. attribute for VAR, directly use `push_cleanup'. This guarantees
  736. that CLEANUP_ID is looked up in the right context, and allows us to
  737. pass VAR directly to `starpu_free', instead of `&VAR'.
  738. TODO: Provide a way to disable this. */
  739. static tree cleanup_decl;
  740. LOOKUP_STARPU_FUNCTION (cleanup_decl, "starpu_free");
  741. if (registered_p (var))
  742. {
  743. /* A `registered' attribute has already been processed, and thus a
  744. cleanup for it has been pushed. However, we want that cleanup
  745. to appear before ours, and our allocation to appear before the
  746. registration, so swap them. */
  747. tree_stmt_iterator it;
  748. tree parent, try_finally, registration;
  749. #ifdef stmt_list_stack
  750. # ifdef VEC_index /* 4.7 */
  751. gcc_assert (VEC_length (tree, stmt_list_stack) > 1);
  752. parent = VEC_index (tree, stmt_list_stack,
  753. VEC_length (tree, stmt_list_stack) - 2);
  754. # else
  755. # error not ported to 4.8!
  756. # endif
  757. #else /* 4.6 and before */
  758. parent = TREE_CHAIN (cur_stmt_list);
  759. #endif
  760. gcc_assert (parent != NULL_TREE
  761. && TREE_CODE (parent) == STATEMENT_LIST);
  762. it = tsi_last (parent);
  763. try_finally = tsi_stmt (it);
  764. gcc_assert (TREE_CODE (try_finally) == TRY_FINALLY_EXPR);
  765. tsi_prev (&it);
  766. registration =
  767. build_data_register_call (loc, var,
  768. array_type_element_count
  769. (loc, array_type));
  770. add_stmt (registration);
  771. *tsi_stmt_ptr (it) = alloc;
  772. push_cleanup (var, build_data_unregister_call (loc, var), false);
  773. TREE_OPERAND (try_finally, 1) = build_call_expr (cleanup_decl, 1, var);
  774. }
  775. else
  776. {
  777. /* Push the allocation and cleanup in order. */
  778. add_stmt (alloc);
  779. push_cleanup (var, build_call_expr (cleanup_decl, 1, var), false);
  780. }
  781. /* Keep the attribute. */
  782. *no_add_attrs = false;
  783. }
  784. return NULL_TREE;
  785. }
  786. /* Handle the `registered' attribute on variable *NODE. */
  787. static tree
  788. handle_registered_attribute (tree *node, tree name, tree args,
  789. int flags, bool *no_add_attrs)
  790. {
  791. location_t loc;
  792. tree var = *node;
  793. loc = DECL_SOURCE_LOCATION (var);
  794. bool heap_p = heap_allocated_p (var);
  795. /* When VAR has the `heap_allocated' attribute, we know it has a complete
  796. array type. */
  797. if (heap_p
  798. || automatic_array_variable_p (registered_attribute_name, var))
  799. {
  800. /* FIXME: This warning cannot be emitted here, because the
  801. `heap_allocated' attribute may be processed later. */
  802. /* if (!heap_p */
  803. /* && !MAIN_NAME_P (DECL_NAME (current_function_decl))) */
  804. /* warning_at (loc, 0, "using an on-stack array as a task input " */
  805. /* "considered unsafe"); */
  806. tree ptr_type, heap_attr =
  807. lookup_attribute (heap_allocated_orig_type_attribute_name,
  808. DECL_ATTRIBUTES (var));
  809. if (heap_attr != NULL_TREE)
  810. /* PTR is `heap_allocated' so use its original array type to
  811. determine its size. */
  812. ptr_type = TREE_VALUE (heap_attr);
  813. else
  814. ptr_type = TREE_TYPE (var);
  815. tree count = array_type_element_count (loc, ptr_type);
  816. add_stmt (build_data_register_call (loc, var, count));
  817. push_cleanup (var,
  818. build_data_unregister_call (DECL_SOURCE_LOCATION (var),
  819. var),
  820. false);
  821. }
  822. return NULL_TREE;
  823. }
  824. /* Handle the `output' attribute on type *NODE, which should be the type of a
  825. PARM_DECL of a task or task implementation. */
  826. static tree
  827. handle_output_attribute (tree *node, tree name, tree args,
  828. int flags, bool *no_add_attrs)
  829. {
  830. tree type = *node;
  831. gcc_assert (TYPE_P (type));
  832. if (!POINTER_TYPE_P (type) && TREE_CODE (type) != ARRAY_TYPE)
  833. error ("%<output%> attribute not allowed for non-pointer types");
  834. else
  835. /* Keep the attribute. */
  836. *no_add_attrs = false;
  837. return NULL_TREE;
  838. }
  839. /* Return true when FN is an implicit CPU task implementation. */
  840. static bool
  841. implicit_cpu_task_implementation_p (const_tree fn)
  842. {
  843. if (task_implementation_p (fn)
  844. && task_implementation_where (fn) == STARPU_CPU)
  845. {
  846. /* XXX: Hackish heuristic. */
  847. const_tree cpu_id;
  848. cpu_id = build_cpu_codelet_identifier (task_implementation_task (fn));
  849. return cpu_id == DECL_NAME (fn);
  850. }
  851. return false;
  852. }
  853. /* Return true when VAR_DECL has the `heap_allocated' attribute. */
  854. static bool
  855. heap_allocated_p (const_tree var_decl)
  856. {
  857. gcc_assert (TREE_CODE (var_decl) == VAR_DECL);
  858. return lookup_attribute (heap_allocated_attribute_name,
  859. DECL_ATTRIBUTES (var_decl)) != NULL_TREE;
  860. }
  861. /* Return true when VAR_DECL has the `registered' attribute. */
  862. static bool
  863. registered_p (const_tree var_decl)
  864. {
  865. gcc_assert (TREE_CODE (var_decl) == VAR_DECL);
  866. return lookup_attribute (registered_attribute_name,
  867. DECL_ATTRIBUTES (var_decl)) != NULL_TREE;
  868. }
  869. static void
  870. register_task_attributes (void *gcc_data, void *user_data)
  871. {
  872. static const struct attribute_spec task_attr =
  873. {
  874. task_attribute_name, 0, 0, true, false, false,
  875. handle_task_attribute
  876. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  877. , false
  878. #endif
  879. };
  880. static const struct attribute_spec task_implementation_attr =
  881. {
  882. task_implementation_attribute_name, 2, 2, true, false, false,
  883. handle_task_implementation_attribute
  884. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  885. , false
  886. #endif
  887. };
  888. static const struct attribute_spec heap_allocated_attr =
  889. {
  890. heap_allocated_attribute_name, 0, 0, true, false, false,
  891. handle_heap_allocated_attribute
  892. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  893. , false
  894. #endif
  895. };
  896. static const struct attribute_spec registered_attr =
  897. {
  898. registered_attribute_name, 0, 0, true, false, false,
  899. handle_registered_attribute
  900. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  901. , false
  902. #endif
  903. };
  904. static const struct attribute_spec output_attr =
  905. {
  906. output_attribute_name, 0, 0, true, true, false,
  907. handle_output_attribute
  908. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  909. , true /* affects type identity */
  910. #endif
  911. };
  912. register_attribute (&task_attr);
  913. register_attribute (&task_implementation_attr);
  914. register_attribute (&heap_allocated_attr);
  915. register_attribute (&registered_attr);
  916. register_attribute (&output_attr);
  917. }
  918. /* Return the type of a codelet function, i.e.,
  919. `void (*) (void **, void *)'. */
  920. static tree
  921. build_codelet_wrapper_type (void)
  922. {
  923. tree void_ptr_ptr;
  924. void_ptr_ptr = build_pointer_type (ptr_type_node);
  925. return build_function_type_list (void_type_node,
  926. void_ptr_ptr, ptr_type_node,
  927. NULL_TREE);
  928. }
  929. /* Return an identifier for the wrapper of TASK_IMPL, a task
  930. implementation. */
  931. static tree
  932. build_codelet_wrapper_identifier (tree task_impl)
  933. {
  934. static const char suffix[] = ".task_implementation_wrapper";
  935. tree id;
  936. char *cl_name;
  937. const char *task_name;
  938. id = DECL_NAME (task_impl);
  939. task_name = IDENTIFIER_POINTER (id);
  940. cl_name = (char *) alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  941. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  942. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  943. return get_identifier (cl_name);
  944. }
  945. /* Return a function of type `void (*) (void **, void *)' that calls function
  946. TASK_IMPL, the FUNCTION_DECL of a task implementation whose prototype may
  947. be arbitrary. */
  948. static tree
  949. build_codelet_wrapper_definition (tree task_impl)
  950. {
  951. location_t loc;
  952. tree task_decl, wrapper_name, decl;
  953. loc = DECL_SOURCE_LOCATION (task_impl);
  954. task_decl = task_implementation_task (task_impl);
  955. wrapper_name = build_codelet_wrapper_identifier (task_impl);
  956. decl = build_decl (loc, FUNCTION_DECL, wrapper_name,
  957. build_codelet_wrapper_type ());
  958. local_define (tree, build_local_var, (const_tree type))
  959. {
  960. tree var, t;
  961. const char *seed;
  962. t = TREE_VALUE (type);
  963. seed = POINTER_TYPE_P (t) ? "pointer_arg" : "scalar_arg";
  964. var = build_decl (loc, VAR_DECL, create_tmp_var_name (seed), t);
  965. DECL_CONTEXT (var) = decl;
  966. DECL_ARTIFICIAL (var) = true;
  967. return var;
  968. };
  969. /* Return the body of the wrapper, which unpacks `cl_args' and calls the
  970. user-defined task implementation. */
  971. local_define (tree, build_body, (tree wrapper_decl, tree vars))
  972. {
  973. bool opencl_p;
  974. tree stmts = NULL, call, v;
  975. VEC(tree, gc) *args;
  976. opencl_p = (task_implementation_where (task_impl) == STARPU_OPENCL);
  977. /* Build `var0 = STARPU_VECTOR_GET_PTR (buffers[0]); ...' or
  978. `var0 = STARPU_VECTOR_GET_DEV_HANDLE (buffers[0])' for OpenCL. */
  979. size_t index = 0;
  980. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  981. {
  982. if (POINTER_TYPE_P (TREE_TYPE (v)))
  983. {
  984. /* Compute `void *VDESC = buffers[0];'. */
  985. tree vdesc = array_ref (DECL_ARGUMENTS (wrapper_decl), index);
  986. /* Use the right field, depending on OPENCL_P. */
  987. size_t offset =
  988. opencl_p
  989. ? offsetof (struct starpu_vector_interface, dev_handle)
  990. : offsetof (struct starpu_vector_interface, ptr);
  991. gcc_assert (POINTER_TYPE_P (TREE_TYPE (vdesc)));
  992. /* Compute `type *PTR = *(type **) VDESC;'. */
  993. tree ptr =
  994. build_indirect_ref (UNKNOWN_LOCATION,
  995. fold_convert (build_pointer_type (TREE_TYPE (v)),
  996. pointer_plus (vdesc, offset)),
  997. RO_ARRAY_INDEXING);
  998. append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (v),
  999. v, ptr),
  1000. &stmts);
  1001. index++;
  1002. }
  1003. }
  1004. /* Build `starpu_codelet_unpack_args (cl_args, &var1, &var2, ...)'. */
  1005. args = NULL;
  1006. VEC_safe_push (tree, gc, args, TREE_CHAIN (DECL_ARGUMENTS (wrapper_decl)));
  1007. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  1008. {
  1009. if (!POINTER_TYPE_P (TREE_TYPE (v)))
  1010. VEC_safe_push (tree, gc, args, build_addr (v, wrapper_decl));
  1011. }
  1012. if (VEC_length (tree, args) > 1)
  1013. {
  1014. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fn, args);
  1015. TREE_SIDE_EFFECTS (call) = 1;
  1016. append_to_statement_list (call, &stmts);
  1017. }
  1018. /* Build `my_task_impl (var1, var2, ...)'. */
  1019. args = NULL;
  1020. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  1021. VEC_safe_push (tree, gc, args, v);
  1022. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, task_impl, args);
  1023. TREE_SIDE_EFFECTS (call) = 1;
  1024. append_to_statement_list (call, &stmts);
  1025. tree bind;
  1026. bind = build3 (BIND_EXPR, void_type_node, vars, stmts,
  1027. DECL_INITIAL (wrapper_decl));
  1028. TREE_TYPE (bind) = TREE_TYPE (TREE_TYPE (wrapper_decl));
  1029. return bind;
  1030. };
  1031. /* Return the parameter list of the wrapper:
  1032. `(void **BUFFERS, void *CL_ARGS)'. */
  1033. local_define (tree, build_parameters, (tree wrapper_decl))
  1034. {
  1035. tree param1, param2;
  1036. param1 = build_decl (loc, PARM_DECL,
  1037. create_tmp_var_name ("buffers"),
  1038. build_pointer_type (ptr_type_node));
  1039. DECL_ARG_TYPE (param1) = ptr_type_node;
  1040. DECL_CONTEXT (param1) = wrapper_decl;
  1041. TREE_USED (param1) = true;
  1042. param2 = build_decl (loc, PARM_DECL,
  1043. create_tmp_var_name ("cl_args"),
  1044. ptr_type_node);
  1045. DECL_ARG_TYPE (param2) = ptr_type_node;
  1046. DECL_CONTEXT (param2) = wrapper_decl;
  1047. TREE_USED (param2) = true;
  1048. return chainon (param1, param2);
  1049. };
  1050. tree vars, result;
  1051. vars = map (build_local_var,
  1052. list_remove (void_type_p,
  1053. TYPE_ARG_TYPES (TREE_TYPE (task_decl))));
  1054. DECL_CONTEXT (decl) = NULL_TREE;
  1055. DECL_ARGUMENTS (decl) = build_parameters (decl);
  1056. result = build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  1057. DECL_CONTEXT (result) = decl;
  1058. DECL_ARTIFICIAL (result) = true;
  1059. DECL_IGNORED_P (result) = true;
  1060. DECL_RESULT (decl) = result;
  1061. DECL_INITIAL (decl) = build_block (vars, NULL_TREE, decl, NULL_TREE);
  1062. DECL_SAVED_TREE (decl) = build_body (decl, vars);
  1063. TREE_PUBLIC (decl) = TREE_PUBLIC (task_impl);
  1064. TREE_STATIC (decl) = true;
  1065. TREE_USED (decl) = true;
  1066. DECL_ARTIFICIAL (decl) = true;
  1067. DECL_EXTERNAL (decl) = false;
  1068. DECL_UNINLINABLE (decl) = true;
  1069. rest_of_decl_compilation (decl, true, 0);
  1070. struct function *prev_cfun = cfun;
  1071. set_cfun (NULL);
  1072. allocate_struct_function (decl, false);
  1073. cfun->function_end_locus = DECL_SOURCE_LOCATION (task_impl);
  1074. cgraph_finalize_function (decl, false);
  1075. /* Mark DECL as needed so that it doesn't get removed by
  1076. `cgraph_remove_unreachable_nodes' when it's not public. */
  1077. cgraph_mark_needed_node (cgraph_get_node (decl));
  1078. set_cfun (prev_cfun);
  1079. return decl;
  1080. }
  1081. /* Define one wrapper function for each implementation of TASK. TASK should
  1082. be the FUNCTION_DECL of a task. */
  1083. static void
  1084. define_codelet_wrappers (tree task)
  1085. {
  1086. local_define (void, define, (tree task_impl))
  1087. {
  1088. tree wrapper_def;
  1089. wrapper_def = build_codelet_wrapper_definition (task_impl);
  1090. DECL_ATTRIBUTES (task_impl) =
  1091. tree_cons (get_identifier (task_implementation_wrapper_attribute_name),
  1092. wrapper_def,
  1093. DECL_ATTRIBUTES (task_impl));
  1094. };
  1095. for_each (define, task_implementation_list (task));
  1096. }
  1097. /* Return the identifier for an automatically-generated CPU codelet of
  1098. TASK. */
  1099. static tree
  1100. build_cpu_codelet_identifier (const_tree task)
  1101. {
  1102. static const char suffix[] = ".cpu_implementation";
  1103. tree id;
  1104. char *cl_name;
  1105. const char *task_name;
  1106. id = DECL_NAME (task);
  1107. task_name = IDENTIFIER_POINTER (id);
  1108. cl_name = (char *) alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  1109. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  1110. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  1111. return get_identifier (cl_name);
  1112. }
  1113. static void
  1114. handle_pre_genericize (void *gcc_data, void *user_data)
  1115. {
  1116. tree fn = (tree) gcc_data;
  1117. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  1118. if (task_p (fn) && TREE_STATIC (fn))
  1119. {
  1120. /* The user defined a body for task FN, which we interpret as being the
  1121. body of an implicit CPU task implementation for FN. Thus, rename FN
  1122. and turn it into the "cpu" implementation of a task that we create
  1123. under FN's original name (this is easier than moving the body to a
  1124. different function, which would require traversing the body to
  1125. rewrite all references to FN to point to the new function.) Later,
  1126. `lower_starpu' rewrites calls to FN as calls to the newly created
  1127. task. */
  1128. tree task_name = DECL_NAME (fn);
  1129. tree cpu_impl = fn;
  1130. DECL_NAME (cpu_impl) = build_cpu_codelet_identifier (fn);
  1131. if (verbose_output_p)
  1132. inform (DECL_SOURCE_LOCATION (fn),
  1133. "implicit CPU implementation renamed from %qE to %qE",
  1134. task_name, DECL_NAME (cpu_impl));
  1135. tree task = build_decl (DECL_SOURCE_LOCATION (fn), FUNCTION_DECL,
  1136. task_name, TREE_TYPE (fn));
  1137. TREE_PUBLIC (task) = TREE_PUBLIC (fn);
  1138. TREE_PUBLIC (cpu_impl) = false;
  1139. taskify_function (task);
  1140. /* Inherit the task implementation list from FN. */
  1141. tree impls = lookup_attribute (task_implementation_list_attribute_name,
  1142. DECL_ATTRIBUTES (fn));
  1143. gcc_assert (impls != NULL_TREE);
  1144. impls = TREE_VALUE (impls);
  1145. DECL_ATTRIBUTES (task) =
  1146. tree_cons (get_identifier (task_implementation_list_attribute_name),
  1147. impls, DECL_ATTRIBUTES (task));
  1148. /* Make CPU_IMPL an implementation of FN. */
  1149. DECL_ATTRIBUTES (cpu_impl) =
  1150. tree_cons (get_identifier (task_implementation_attribute_name),
  1151. tree_cons (NULL_TREE, build_string (3, "cpu"),
  1152. tree_cons (NULL_TREE, task, NULL_TREE)),
  1153. NULL_TREE);
  1154. add_task_implementation (task, cpu_impl, build_string (3, "cpu"));
  1155. /* And now, process CPU_IMPL. */
  1156. }
  1157. if (task_implementation_p (fn))
  1158. {
  1159. tree task = task_implementation_task (fn);
  1160. if (!TREE_STATIC (task))
  1161. {
  1162. /* TASK lacks a body. Declare its codelet, intantiate its codelet
  1163. wrappers, and its body in this compilation unit. */
  1164. /* Declare TASK's codelet. It cannot be defined yet because the
  1165. complete list of tasks isn't available at this point. */
  1166. declare_codelet (task);
  1167. /* Build its body. */
  1168. current_function_decl = task;
  1169. define_task (task);
  1170. current_function_decl = fn;
  1171. /* Compile TASK's body. */
  1172. rest_of_decl_compilation (task, true, 0);
  1173. allocate_struct_function (task, false);
  1174. cgraph_finalize_function (task, false);
  1175. cgraph_mark_needed_node (cgraph_get_node (task));
  1176. }
  1177. }
  1178. }
  1179. /* Raise warnings if TASK doesn't meet the basic criteria. */
  1180. static void
  1181. validate_task (tree task)
  1182. {
  1183. gcc_assert (task_p (task));
  1184. int where = task_where (task);
  1185. /* If TASK has no implementations, things will barf elsewhere anyway. */
  1186. if (task_implementation_list (task) != NULL_TREE)
  1187. if ((where & supported_targets) == 0)
  1188. error_at (DECL_SOURCE_LOCATION (task),
  1189. "none of the implementations of task %qE can be used",
  1190. DECL_NAME (task));
  1191. }
  1192. /* Raise an error when IMPL doesn't satisfy the constraints of a task
  1193. implementations, such as not invoking another task. */
  1194. static void
  1195. validate_task_implementation (tree impl)
  1196. {
  1197. gcc_assert (task_implementation_p (impl));
  1198. const struct cgraph_node *cgraph;
  1199. const struct cgraph_edge *callee;
  1200. cgraph = cgraph_get_node (impl);
  1201. /* When a definition of IMPL is available, check its callees. */
  1202. if (cgraph != NULL)
  1203. for (callee = cgraph->callees;
  1204. callee != NULL;
  1205. callee = callee->next_callee)
  1206. {
  1207. if (task_p (callee->callee->decl))
  1208. {
  1209. location_t loc;
  1210. loc = gimple_location (callee->call_stmt);
  1211. error_at (loc, "task %qE cannot be invoked from task implementation %qE",
  1212. DECL_NAME (callee->callee->decl),
  1213. DECL_NAME (impl));
  1214. }
  1215. }
  1216. }
  1217. static unsigned int
  1218. lower_starpu (void)
  1219. {
  1220. tree fndecl;
  1221. const struct cgraph_node *cgraph;
  1222. const struct cgraph_edge *callee;
  1223. fndecl = current_function_decl;
  1224. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  1225. if (task_p (fndecl))
  1226. {
  1227. /* Make sure the task and its implementations are valid. */
  1228. validate_task (fndecl);
  1229. for_each (validate_task_implementation,
  1230. task_implementation_list (fndecl));
  1231. /* Generate a `struct starpu_codelet' structure and a wrapper function for
  1232. each implementation of TASK_DECL. This cannot be done earlier
  1233. because we need to have a complete list of task implementations. */
  1234. define_codelet_wrappers (fndecl);
  1235. tree cl_def = task_codelet_declaration (fndecl);
  1236. DECL_INITIAL (cl_def) = build_codelet_initializer (fndecl);
  1237. TREE_STATIC (cl_def) = true;
  1238. DECL_EXTERNAL (cl_def) = false;
  1239. varpool_finalize_decl (cl_def);
  1240. }
  1241. /* This pass should occur after `build_cgraph_edges'. */
  1242. cgraph = cgraph_get_node (fndecl);
  1243. gcc_assert (cgraph != NULL);
  1244. if (MAIN_NAME_P (DECL_NAME (fndecl)))
  1245. {
  1246. /* Check whether FNDECL initializes StarPU and emit a warning if it
  1247. doesn't. */
  1248. bool initialized;
  1249. for (initialized = false, callee = cgraph->callees;
  1250. !initialized && callee != NULL;
  1251. callee = callee->next_callee)
  1252. {
  1253. initialized =
  1254. DECL_NAME (callee->callee->decl) == get_identifier ("starpu_init");
  1255. }
  1256. if (!initialized)
  1257. warning_at (DECL_SOURCE_LOCATION (fndecl), 0,
  1258. "%qE does not initialize StarPU", DECL_NAME (fndecl));
  1259. }
  1260. for (callee = cgraph->callees;
  1261. callee != NULL;
  1262. callee = callee->next_callee)
  1263. {
  1264. gcc_assert (callee->callee != NULL);
  1265. tree callee_decl, caller_decl;
  1266. callee_decl = callee->callee->decl;
  1267. caller_decl = callee->caller->decl;
  1268. if (implicit_cpu_task_implementation_p (callee_decl)
  1269. && !DECL_ARTIFICIAL (caller_decl))
  1270. {
  1271. /* Rewrite the call to point to the actual task beneath
  1272. CALLEE_DECL. */
  1273. callee_decl = task_implementation_task (callee_decl);
  1274. if (verbose_output_p)
  1275. inform (gimple_location (callee->call_stmt),
  1276. "call to %qE rewritten as a call to task %qE",
  1277. DECL_NAME (callee->callee->decl),
  1278. DECL_NAME (callee_decl));
  1279. gimple_call_set_fn (callee->call_stmt,
  1280. build_addr (callee_decl, callee->caller->decl));
  1281. }
  1282. if (task_p (callee_decl))
  1283. {
  1284. if (verbose_output_p)
  1285. inform (gimple_location (callee->call_stmt),
  1286. "%qE calls task %qE",
  1287. DECL_NAME (fndecl), DECL_NAME (callee_decl));
  1288. }
  1289. }
  1290. return 0;
  1291. }
  1292. static struct opt_pass pass_lower_starpu =
  1293. {
  1294. designated_field_init (type, GIMPLE_PASS),
  1295. designated_field_init (name, "lower_starpu"),
  1296. designated_field_init (gate, NULL),
  1297. designated_field_init (execute, lower_starpu),
  1298. /* The rest is zeroed. */
  1299. };
  1300. /* Initialization. */
  1301. /* Directory where to look up <starpu.h> instead of `STARPU_INCLUDE_DIR'. */
  1302. static const char *include_dir;
  1303. static void
  1304. define_cpp_macros (void *gcc_data, void *user_data)
  1305. {
  1306. cpp_define (parse_in, "STARPU_GCC_PLUGIN=0");
  1307. if (include_dir)
  1308. {
  1309. /* Get the header from the user-specified directory. This is useful
  1310. when running the test suite, before StarPU is installed. */
  1311. char header[strlen (include_dir) + sizeof ("/starpu.h")];
  1312. strcpy (header, include_dir);
  1313. strcat (header, "/starpu.h");
  1314. cpp_push_include (parse_in, header);
  1315. }
  1316. else
  1317. cpp_push_include (parse_in, STARPU_INCLUDE_DIR "/starpu.h");
  1318. }
  1319. int
  1320. plugin_init (struct plugin_name_args *plugin_info,
  1321. struct plugin_gcc_version *version)
  1322. {
  1323. /* `plugin_default_version_check' happens to be stricter than necessary
  1324. (for instance, it fails when the `buildstamp' field of the plug-in
  1325. doesn't match that of GCC), so write our own check and make more relax
  1326. and more verbose. */
  1327. #define VERSION_CHECK(field) \
  1328. do \
  1329. { \
  1330. if (strcmp (gcc_version. field, version-> field) != 0) \
  1331. { \
  1332. error_at (UNKNOWN_LOCATION, "plug-in version check for `" \
  1333. STRINGIFY (field) "' failed: expected `%s', " \
  1334. "got `%s'", \
  1335. gcc_version. field, version-> field); \
  1336. return 1; \
  1337. } \
  1338. } \
  1339. while (0)
  1340. VERSION_CHECK (basever); /* e.g., "4.6.2" */
  1341. VERSION_CHECK (devphase);
  1342. VERSION_CHECK (revision);
  1343. VERSION_CHECK (configuration_arguments);
  1344. #undef VERSION_CHECK
  1345. register_callback (plugin_name, PLUGIN_START_UNIT,
  1346. define_cpp_macros, NULL);
  1347. register_callback (plugin_name, PLUGIN_PRAGMAS,
  1348. register_pragmas, NULL);
  1349. register_callback (plugin_name, PLUGIN_ATTRIBUTES,
  1350. register_task_attributes, NULL);
  1351. register_callback (plugin_name, PLUGIN_PRE_GENERICIZE,
  1352. handle_pre_genericize, NULL);
  1353. /* Register our pass so that it happens after `build_cgraph_edges' has been
  1354. done. */
  1355. struct register_pass_info pass_info =
  1356. {
  1357. designated_field_init (pass, &pass_lower_starpu),
  1358. designated_field_init (reference_pass_name, "*build_cgraph_edges"),
  1359. designated_field_init (ref_pass_instance_number, 1),
  1360. designated_field_init (pos_op, PASS_POS_INSERT_AFTER)
  1361. };
  1362. register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP,
  1363. NULL, &pass_info);
  1364. #if HAVE_DECL_PTR_DEREFS_MAY_ALIAS_P
  1365. /* This warning pass is only available when `ptr_derefs_may_alias_p' is
  1366. available, with GCC >= 4.6. */
  1367. struct register_pass_info pass_info2 =
  1368. {
  1369. designated_field_init (pass, &pass_warn_starpu_unregistered),
  1370. designated_field_init (reference_pass_name, "ssa"),
  1371. designated_field_init (ref_pass_instance_number, 1),
  1372. designated_field_init (pos_op, PASS_POS_INSERT_AFTER)
  1373. };
  1374. if (optimize)
  1375. /* Using `TODO_rebuild_alias' allows us to have more accurate aliasing
  1376. info. However, `TODO_rebuild_alias' cannot be used when optimizations
  1377. are turned off. See <http://gcc.gnu.org/ml/gcc/2012-10/msg00104.html>
  1378. for details. */
  1379. pass_warn_starpu_unregistered.todo_flags_start = TODO_rebuild_alias;
  1380. register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP,
  1381. NULL, &pass_info2);
  1382. #endif
  1383. include_dir = getenv ("STARPU_GCC_INCLUDE_DIR");
  1384. opencl_include_dirs = tree_cons (NULL_TREE, build_string (1, "."),
  1385. NULL_TREE);
  1386. int arg;
  1387. for (arg = 0; arg < plugin_info->argc; arg++)
  1388. {
  1389. if (strcmp (plugin_info->argv[arg].key, "include-dir") == 0)
  1390. {
  1391. if (plugin_info->argv[arg].value == NULL)
  1392. error_at (UNKNOWN_LOCATION, "missing directory name for option "
  1393. "%<-fplugin-arg-starpu-include-dir%>");
  1394. else
  1395. /* XXX: We assume that `value' has an infinite lifetime. */
  1396. include_dir = plugin_info->argv[arg].value;
  1397. }
  1398. else if (strcmp (plugin_info->argv[arg].key, "opencl-include-dir") == 0)
  1399. {
  1400. if (plugin_info->argv[arg].value == NULL)
  1401. error_at (UNKNOWN_LOCATION, "missing directory name for option "
  1402. "%<-fplugin-arg-starpu-opencl-include-dir%>");
  1403. else
  1404. {
  1405. tree dir = build_string (strlen (plugin_info->argv[arg].value),
  1406. plugin_info->argv[arg].value);
  1407. opencl_include_dirs = tree_cons (NULL_TREE, dir,
  1408. opencl_include_dirs);
  1409. }
  1410. }
  1411. else if (strcmp (plugin_info->argv[arg].key, "verbose") == 0)
  1412. verbose_output_p = true;
  1413. else
  1414. error_at (UNKNOWN_LOCATION, "invalid StarPU plug-in argument %qs",
  1415. plugin_info->argv[arg].key);
  1416. }
  1417. /* Keep the directories in the order in which they appear. */
  1418. opencl_include_dirs = nreverse (opencl_include_dirs);
  1419. return 0;
  1420. }
  1421. #ifdef __cplusplus
  1422. }
  1423. #endif