starpu.c 49 KB

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