starpu.c 49 KB

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