starpu.c 72 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712
  1. /* GCC-StarPU
  2. Copyright (C) 2011, 2012 Institut National de Recherche en Informatique et Automatique
  3. GCC-StarPU is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation, either version 3 of the License, or
  6. (at your option) any later version.
  7. GCC-StarPU is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with GCC-StarPU. If not, see <http://www.gnu.org/licenses/>. */
  13. /* Use extensions of the GNU C Library. */
  14. #define _GNU_SOURCE 1
  15. #include <starpu-gcc-config.h>
  16. /* We must include starpu.h here, otherwise gcc will complain about a poisoned
  17. malloc in xmmintrin.h. */
  18. #include <starpu.h> /* for `STARPU_CPU' & co. */
  19. /* #define ENABLE_TREE_CHECKING 1 */
  20. #include <gcc-plugin.h>
  21. #include <plugin-version.h>
  22. #include <plugin.h>
  23. #include <cpplib.h>
  24. #include <tree.h>
  25. #include <tree-iterator.h>
  26. #include <langhooks.h>
  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 <gimple.h>
  39. #include <tree-pass.h>
  40. #include <tree-flow.h>
  41. #include <cgraph.h>
  42. #include <gimple.h>
  43. #include <toplev.h>
  44. #include <stdio.h>
  45. /* Don't include the dreaded proprietary headers that we don't need anyway.
  46. In particular, this waives the obligation to reproduce their silly
  47. disclaimer. */
  48. #define STARPU_DONT_INCLUDE_CUDA_HEADERS
  49. /* GCC 4.7 requires compilation with `g++', and C++ lacks a number of GNU C
  50. features, so work around that. */
  51. #ifdef __cplusplus
  52. /* G++ doesn't implement nested functions, so use C++11 lambdas instead. */
  53. # include <functional>
  54. # define local_define(ret, name, parms) auto name = [=]parms
  55. # define function_parm(ret, name, parms) std::function<ret parms> name
  56. /* G++ lacks designated initializers. */
  57. # define designated_field_init(name, value) value /* XXX: cross fingers */
  58. #else /* !__cplusplus */
  59. /* GNU C nested functions. */
  60. # define local_define(ret, name, parms) ret name parms
  61. # define function_parm(ret, name, parms) ret (*name) parms
  62. /* Designated field initializer. */
  63. # define designated_field_init(name, value) .name = value
  64. #endif /* !__cplusplus */
  65. /* C expression parser, possibly with C++ linkage. */
  66. extern int yyparse (location_t, const char *, tree *);
  67. extern int yydebug;
  68. /* This declaration is from `c-tree.h', but that header doesn't get
  69. installed. */
  70. extern tree xref_tag (enum tree_code, tree);
  71. #ifdef __cplusplus
  72. extern "C" {
  73. #endif
  74. /* Declared with `C' linkage in <gcc-plugin.h>. */
  75. int plugin_is_GPL_compatible;
  76. /* The name of this plug-in. */
  77. static const char plugin_name[] = "starpu";
  78. /* Whether to enable verbose output. */
  79. static bool verbose_output_p = false;
  80. /* Names of public attributes. */
  81. static const char task_attribute_name[] = "task";
  82. static const char task_implementation_attribute_name[] = "task_implementation";
  83. static const char output_attribute_name[] = "output";
  84. static const char heap_allocated_attribute_name[] = "heap_allocated";
  85. /* Names of attributes used internally. */
  86. static const char task_codelet_attribute_name[] = ".codelet";
  87. static const char task_implementation_list_attribute_name[] =
  88. ".task_implementation_list";
  89. static const char task_implementation_wrapper_attribute_name[] =
  90. ".task_implementation_wrapper";
  91. static const char heap_allocated_orig_type_attribute_name[] =
  92. ".heap_allocated_original_type";
  93. /* Names of data structures defined in <starpu.h>. */
  94. static const char codelet_struct_tag[] = "starpu_codelet";
  95. /* Cached function declarations. */
  96. static tree unpack_fn, data_lookup_fn;
  97. /* Forward declarations. */
  98. static tree build_codelet_declaration (tree task_decl);
  99. static tree build_cpu_codelet_identifier (const_tree task);
  100. static void define_task (tree task_decl);
  101. static tree build_pointer_lookup (tree pointer);
  102. static bool task_p (const_tree decl);
  103. static bool task_implementation_p (const_tree decl);
  104. static tree task_implementation_task (const_tree task_impl);
  105. static bool implicit_cpu_task_implementation_p (const_tree fn);
  106. static int task_implementation_target_to_int (const_tree target);
  107. static bool heap_allocated_p (const_tree var_decl);
  108. /* Lookup the StarPU function NAME in the global scope and store the result
  109. in VAR (this can't be done from `lower_starpu'.) */
  110. #define LOOKUP_STARPU_FUNCTION(var, name) \
  111. if ((var) == NULL_TREE) \
  112. { \
  113. (var) = lookup_name (get_identifier (name)); \
  114. gcc_assert ((var) != NULL_TREE && TREE_CODE (var) == FUNCTION_DECL); \
  115. }
  116. /* Compile-time assertions. */
  117. #if STARPU_GNUC_PREREQ (4, 6)
  118. # define verify(cond, msg) _Static_assert ((cond), msg)
  119. #else
  120. # define verify(cond, msg) assert (cond);
  121. #endif
  122. /* Useful code backported from GCC 4.6. */
  123. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_ARRAY
  124. static tree
  125. build_call_expr_loc_array (location_t loc, tree fndecl, int n, tree *argarray)
  126. {
  127. tree fntype = TREE_TYPE (fndecl);
  128. tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
  129. return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
  130. }
  131. #endif
  132. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_VEC
  133. static tree
  134. build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
  135. {
  136. return build_call_expr_loc_array (loc, fndecl, VEC_length (tree, vec),
  137. VEC_address (tree, vec));
  138. }
  139. #endif
  140. #if !HAVE_DECL_BUILD_ZERO_CST
  141. static tree
  142. build_zero_cst (tree type)
  143. {
  144. switch (TREE_CODE (type))
  145. {
  146. case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
  147. case POINTER_TYPE: case REFERENCE_TYPE:
  148. case OFFSET_TYPE:
  149. return build_int_cst (type, 0);
  150. default:
  151. abort ();
  152. }
  153. }
  154. #endif
  155. #ifndef VEC_qsort
  156. /* This macro is missing in GCC 4.5. */
  157. # define VEC_qsort(T,V,CMP) qsort(VEC_address (T,V), VEC_length(T,V), \
  158. sizeof (T), CMP)
  159. #endif
  160. #if !HAVE_DECL_BUILTIN_DECL_EXPLICIT
  161. /* This function was introduced in GCC 4.7 as a replacement for the
  162. `built_in_decls' array. */
  163. static inline tree
  164. builtin_decl_explicit (enum built_in_function fncode)
  165. {
  166. return built_in_decls[fncode];
  167. }
  168. #endif
  169. /* Helpers. */
  170. /* Return POINTER plus OFFSET, where OFFSET is in bytes. */
  171. static tree
  172. pointer_plus (tree pointer, size_t offset)
  173. {
  174. gcc_assert (POINTER_TYPE_P (TREE_TYPE (pointer)));
  175. if (offset == 0)
  176. return pointer;
  177. else
  178. return build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR,
  179. pointer,
  180. build_int_cstu (integer_type_node, offset),
  181. false);
  182. }
  183. /* Build a reference to the INDEXth element of ARRAY. `build_array_ref' is
  184. not exported, so we roll our own.
  185. FIXME: This version may not work for array types and doesn't do as much
  186. type-checking as `build_array_ref'. */
  187. static tree
  188. array_ref (tree array, size_t index)
  189. {
  190. gcc_assert (POINTER_TYPE_P (TREE_TYPE (array)));
  191. return build_indirect_ref (UNKNOWN_LOCATION,
  192. pointer_plus (array, index),
  193. RO_ARRAY_INDEXING);
  194. }
  195. /* Return the number of elements of ARRAY_TYPE, or NULL_TREE if ARRAY_TYPE is
  196. an incomplete type. */
  197. static tree
  198. array_type_element_count (location_t loc, const_tree array_type)
  199. {
  200. gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
  201. tree count, domain = TYPE_DOMAIN (array_type);
  202. if (domain != NULL_TREE)
  203. {
  204. count = build_binary_op (loc, MINUS_EXPR,
  205. TYPE_MAX_VALUE (domain),
  206. TYPE_MIN_VALUE (domain),
  207. false);
  208. count = build_binary_op (loc, PLUS_EXPR,
  209. count,
  210. build_int_cstu (integer_type_node, 1),
  211. false);
  212. count = fold_convert (size_type_node, count);
  213. }
  214. else
  215. count = NULL_TREE;
  216. return count;
  217. }
  218. /* Like `build_constructor_from_list', but sort VALS according to their
  219. offset in struct TYPE. Inspired by `gnat_build_constructor'. */
  220. static tree
  221. build_constructor_from_unsorted_list (tree type, tree vals)
  222. {
  223. local_define (int, compare_elmt_bitpos, (const void *rt1, const void *rt2))
  224. {
  225. const constructor_elt *elmt1 = (constructor_elt *) rt1;
  226. const constructor_elt *elmt2 = (constructor_elt *) rt2;
  227. const_tree field1 = elmt1->index;
  228. const_tree field2 = elmt2->index;
  229. int ret
  230. = tree_int_cst_compare (bit_position (field1), bit_position (field2));
  231. return ret ? ret : (int) (DECL_UID (field1) - DECL_UID (field2));
  232. };
  233. tree t;
  234. VEC(constructor_elt,gc) *v = NULL;
  235. if (vals)
  236. {
  237. v = VEC_alloc (constructor_elt, gc, list_length (vals));
  238. for (t = vals; t; t = TREE_CHAIN (t))
  239. CONSTRUCTOR_APPEND_ELT (v, TREE_PURPOSE (t), TREE_VALUE (t));
  240. }
  241. /* Sort field initializers by field offset. */
  242. VEC_qsort (constructor_elt, v, compare_elmt_bitpos);
  243. return build_constructor (type, v);
  244. }
  245. /* Return true if LST holds the void type. */
  246. bool
  247. void_type_p (const_tree lst)
  248. {
  249. gcc_assert (TREE_CODE (lst) == TREE_LIST);
  250. return VOID_TYPE_P (TREE_VALUE (lst));
  251. }
  252. /* Return true if LST holds a pointer type. */
  253. bool
  254. pointer_type_p (const_tree lst)
  255. {
  256. gcc_assert (TREE_CODE (lst) == TREE_LIST);
  257. return POINTER_TYPE_P (TREE_VALUE (lst));
  258. }
  259. /* Debugging helpers. */
  260. static tree build_printf (const char *, ...)
  261. __attribute__ ((format (printf, 1, 2)));
  262. static tree
  263. build_printf (const char *fmt, ...)
  264. {
  265. tree call;
  266. char *str;
  267. va_list args;
  268. va_start (args, fmt);
  269. vasprintf (&str, fmt, args);
  270. call = build_call_expr (builtin_decl_explicit (BUILT_IN_PUTS), 1,
  271. build_string_literal (strlen (str) + 1, str));
  272. free (str);
  273. va_end (args);
  274. return call;
  275. }
  276. static tree
  277. build_hello_world (void)
  278. {
  279. return build_printf ("Hello, StarPU!");
  280. }
  281. /* Given ERROR_VAR, an integer variable holding a StarPU error code, return
  282. statements that print out an error message and abort. */
  283. static tree build_error_statements (location_t, tree, const char *, ...)
  284. __attribute__ ((format (printf, 3, 4)));
  285. static tree
  286. build_error_statements (location_t loc, tree error_var, const char *fmt, ...)
  287. {
  288. expanded_location xloc = expand_location (loc);
  289. tree print;
  290. char *str, *fmt_long;
  291. va_list args;
  292. va_start (args, fmt);
  293. /* Build a longer format. Since FMT itself contains % escapes, this needs
  294. to be done in two steps. */
  295. vasprintf (&str, fmt, args);
  296. if (error_var != NULL_TREE)
  297. {
  298. /* ERROR_VAR is an error code. */
  299. static tree strerror_fn;
  300. LOOKUP_STARPU_FUNCTION (strerror_fn, "strerror");
  301. gcc_assert (TREE_CODE (error_var) == VAR_DECL
  302. && TREE_TYPE (error_var) == integer_type_node);
  303. asprintf (&fmt_long, "%s:%d: error: %s: %%s\n",
  304. xloc.file, xloc.line, str);
  305. tree error_code =
  306. build1 (NEGATE_EXPR, TREE_TYPE (error_var), error_var);
  307. print =
  308. build_call_expr (builtin_decl_explicit (BUILT_IN_PRINTF), 2,
  309. build_string_literal (strlen (fmt_long) + 1,
  310. fmt_long),
  311. build_call_expr (strerror_fn, 1, error_code));
  312. }
  313. else
  314. {
  315. /* No error code provided. */
  316. asprintf (&fmt_long, "%s:%d: error: %s\n",
  317. xloc.file, xloc.line, str);
  318. print =
  319. build_call_expr (builtin_decl_explicit (BUILT_IN_PUTS), 1,
  320. build_string_literal (strlen (fmt_long) + 1,
  321. fmt_long));
  322. }
  323. free (fmt_long);
  324. free (str);
  325. va_end (args);
  326. tree stmts = NULL;
  327. append_to_statement_list (print, &stmts);
  328. append_to_statement_list (build_call_expr
  329. (builtin_decl_explicit (BUILT_IN_ABORT), 0),
  330. &stmts);
  331. return stmts;
  332. }
  333. /* List and vector utilities, à la SRFI-1. */
  334. static tree chain_trees (tree t, ...)
  335. __attribute__ ((sentinel));
  336. static tree
  337. chain_trees (tree t, ...)
  338. {
  339. va_list args;
  340. va_start (args, t);
  341. tree next, prev = t;
  342. for (prev = t, next = va_arg (args, tree);
  343. next != NULL_TREE;
  344. prev = next, next = va_arg (args, tree))
  345. TREE_CHAIN (prev) = next;
  346. va_end (args);
  347. return t;
  348. }
  349. static tree
  350. filter (function_parm (bool, pred, (const_tree)), tree t)
  351. {
  352. tree result, lst;
  353. gcc_assert (TREE_CODE (t) == TREE_LIST);
  354. result = NULL_TREE;
  355. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  356. {
  357. if (pred (lst))
  358. result = tree_cons (TREE_PURPOSE (lst), TREE_VALUE (lst),
  359. result);
  360. }
  361. return nreverse (result);
  362. }
  363. static tree
  364. list_remove (function_parm (bool, pred, (const_tree)), tree t)
  365. {
  366. local_define (bool, opposite, (const_tree t))
  367. {
  368. return !pred (t);
  369. };
  370. return filter (opposite, t);
  371. }
  372. /* Map FUNC over chain T. T does not have to be `TREE_LIST'; it can be a
  373. chain of arbitrary tree objects. */
  374. static tree
  375. map (function_parm (tree, func, (const_tree)), tree t)
  376. {
  377. tree result, tail, lst;
  378. result = tail = NULL_TREE;
  379. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  380. {
  381. tree r = func (lst);
  382. if (tail != NULL_TREE)
  383. TREE_CHAIN (tail) = r;
  384. else
  385. result = r;
  386. tail = r;
  387. }
  388. return result;
  389. }
  390. static void
  391. for_each (function_parm (void, func, (tree)), tree t)
  392. {
  393. tree lst;
  394. gcc_assert (TREE_CODE (t) == TREE_LIST);
  395. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  396. func (TREE_VALUE (lst));
  397. }
  398. static size_t
  399. count (function_parm (bool, pred, (const_tree)), const_tree t)
  400. {
  401. size_t result;
  402. const_tree lst;
  403. for (lst = t, result = 0; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  404. if (pred (lst))
  405. result++;
  406. return result;
  407. }
  408. /* Pragmas. */
  409. #define STARPU_PRAGMA_NAME_SPACE "starpu"
  410. static void
  411. handle_pragma_hello (struct cpp_reader *reader)
  412. {
  413. add_stmt (build_hello_world ());
  414. }
  415. /* Process `#pragma starpu initialize'.
  416. TODO: Parse and initialize some of the fields of `starpu_conf'. */
  417. static void
  418. handle_pragma_initialize (struct cpp_reader *reader)
  419. {
  420. static tree init_fn;
  421. LOOKUP_STARPU_FUNCTION (init_fn, "starpu_init");
  422. location_t loc = cpp_peek_token (reader, 0)->src_loc;
  423. /* Call `starpu_init (NULL)'. */
  424. tree init = build_call_expr (init_fn, 1, build_zero_cst (ptr_type_node));
  425. /* Introduce a local variable to hold the error code. */
  426. tree error_var = build_decl (loc, VAR_DECL,
  427. create_tmp_var_name (".initialize_error"),
  428. integer_type_node);
  429. DECL_CONTEXT (error_var) = current_function_decl;
  430. DECL_ARTIFICIAL (error_var) = true;
  431. tree assignment = build2 (INIT_EXPR, TREE_TYPE (error_var),
  432. error_var, init);
  433. tree cond = build3 (COND_EXPR, void_type_node,
  434. build2 (NE_EXPR, boolean_type_node,
  435. error_var, integer_zero_node),
  436. build_error_statements (loc, error_var,
  437. "failed to initialize StarPU"),
  438. NULL_TREE);
  439. tree stmts = NULL_TREE;
  440. append_to_statement_list (assignment, &stmts);
  441. append_to_statement_list (cond, &stmts);
  442. tree bind = build3 (BIND_EXPR, void_type_node, error_var, stmts,
  443. NULL_TREE);
  444. add_stmt (bind);
  445. }
  446. /* Process `#pragma starpu shutdown'. */
  447. static void
  448. handle_pragma_shutdown (struct cpp_reader *reader)
  449. {
  450. static tree shutdown_fn;
  451. LOOKUP_STARPU_FUNCTION (shutdown_fn, "starpu_shutdown");
  452. tree token;
  453. if (pragma_lex (&token) != CPP_EOF)
  454. error_at (cpp_peek_token (reader, 0)->src_loc,
  455. "junk after %<starpu shutdown%> pragma");
  456. else
  457. /* Call `starpu_shutdown ()'. */
  458. add_stmt (build_call_expr (shutdown_fn, 0));
  459. }
  460. static void
  461. handle_pragma_wait (struct cpp_reader *reader)
  462. {
  463. if (task_implementation_p (current_function_decl))
  464. {
  465. location_t loc;
  466. loc = cpp_peek_token (reader, 0)->src_loc;
  467. /* TODO: In the future we could generate a task for the continuation
  468. and have it depend on what's before here. */
  469. error_at (loc, "task implementation is not allowed to wait");
  470. }
  471. else
  472. {
  473. tree fndecl;
  474. fndecl = lookup_name (get_identifier ("starpu_task_wait_for_all"));
  475. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  476. add_stmt (build_call_expr (fndecl, 0));
  477. }
  478. }
  479. /* The minimal C expression parser. */
  480. /* Parse expressions from the CPP reader for PRAGMA, which is located at LOC.
  481. Return a TREE_LIST of C expressions. */
  482. static tree
  483. read_pragma_expressions (const char *pragma, location_t loc)
  484. {
  485. tree expr = NULL_TREE;
  486. if (yyparse (loc, pragma, &expr))
  487. /* Parse error or memory exhaustion. */
  488. expr = NULL_TREE;
  489. return expr;
  490. }
  491. /* Build a `starpu_vector_data_register' call for the COUNT elements pointed
  492. to by POINTER. */
  493. static tree
  494. build_data_register_call (location_t loc, tree pointer, tree count)
  495. {
  496. tree pointer_type = TREE_TYPE (pointer);
  497. gcc_assert ((TREE_CODE (pointer_type) == ARRAY_TYPE
  498. && TYPE_DOMAIN (pointer_type) != NULL_TREE)
  499. || POINTER_TYPE_P (pointer_type));
  500. gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (count)));
  501. static tree register_fn;
  502. LOOKUP_STARPU_FUNCTION (register_fn, "starpu_vector_data_register");
  503. /* Introduce a local variable to hold the handle. */
  504. tree handle_var = build_decl (loc, VAR_DECL, create_tmp_var_name (".handle"),
  505. ptr_type_node);
  506. DECL_CONTEXT (handle_var) = current_function_decl;
  507. DECL_ARTIFICIAL (handle_var) = true;
  508. DECL_INITIAL (handle_var) = NULL_TREE;
  509. /* If PTR is an array, take its address. */
  510. tree actual_pointer =
  511. POINTER_TYPE_P (pointer_type)
  512. ? pointer
  513. : build_addr (pointer, current_function_decl);
  514. /* Build `starpu_vector_data_register (&HANDLE_VAR, 0, POINTER,
  515. COUNT, sizeof *POINTER)' */
  516. tree call =
  517. build_call_expr (register_fn, 5,
  518. build_addr (handle_var, current_function_decl),
  519. build_zero_cst (uintptr_type_node), /* home node */
  520. actual_pointer, count,
  521. size_in_bytes (TREE_TYPE (pointer_type)));
  522. return build3 (BIND_EXPR, void_type_node, handle_var, call,
  523. NULL_TREE);
  524. }
  525. /* Return a `starpu_data_unregister' call for VAR. */
  526. static tree
  527. build_data_unregister_call (location_t loc, tree var)
  528. {
  529. static tree unregister_fn;
  530. LOOKUP_STARPU_FUNCTION (unregister_fn, "starpu_data_unregister");
  531. /* If VAR is an array, take its address. */
  532. tree pointer =
  533. POINTER_TYPE_P (TREE_TYPE (var))
  534. ? var
  535. : build_addr (var, current_function_decl);
  536. /* Call `starpu_data_unregister (starpu_data_lookup (ptr))'. */
  537. return build_call_expr (unregister_fn, 1,
  538. build_pointer_lookup (pointer));
  539. }
  540. /* Process `#pragma starpu register VAR [COUNT]' and emit the corresponding
  541. `starpu_vector_data_register' call. */
  542. static void
  543. handle_pragma_register (struct cpp_reader *reader)
  544. {
  545. tree args, ptr, count_arg;
  546. location_t loc;
  547. loc = cpp_peek_token (reader, 0)->src_loc;
  548. args = read_pragma_expressions ("register", loc);
  549. if (args == NULL_TREE)
  550. /* Parse error, presumably already handled by the parser. */
  551. return;
  552. /* First argument should be a pointer expression. */
  553. ptr = TREE_VALUE (args);
  554. args = TREE_CHAIN (args);
  555. if (ptr == error_mark_node)
  556. return;
  557. tree ptr_type;
  558. if (DECL_P (ptr))
  559. {
  560. tree heap_attr =
  561. lookup_attribute (heap_allocated_orig_type_attribute_name,
  562. DECL_ATTRIBUTES (ptr));
  563. if (heap_attr != NULL_TREE)
  564. /* PTR is `heap_allocated' so use its original array type to
  565. determine its size. */
  566. ptr_type = TREE_VALUE (heap_attr);
  567. else
  568. ptr_type = TREE_TYPE (ptr);
  569. }
  570. else
  571. ptr_type = TREE_TYPE (ptr);
  572. if (!POINTER_TYPE_P (ptr_type)
  573. && TREE_CODE (ptr_type) != ARRAY_TYPE)
  574. {
  575. error_at (loc, "%qE is neither a pointer nor an array", ptr);
  576. return;
  577. }
  578. /* Since we implicitly use sizeof (*PTR), `void *' is not allowed. */
  579. if (VOID_TYPE_P (TREE_TYPE (ptr_type)))
  580. {
  581. error_at (loc, "pointers to %<void%> not allowed "
  582. "in %<register%> pragma");
  583. return;
  584. }
  585. TREE_USED (ptr) = true;
  586. #ifdef DECL_READ_P
  587. if (DECL_P (ptr))
  588. DECL_READ_P (ptr) = true;
  589. #endif
  590. if (TREE_CODE (ptr_type) == ARRAY_TYPE
  591. && !DECL_EXTERNAL (ptr)
  592. && !TREE_STATIC (ptr)
  593. && !(TREE_CODE (ptr) == VAR_DECL && heap_allocated_p (ptr))
  594. && !MAIN_NAME_P (DECL_NAME (current_function_decl)))
  595. warning_at (loc, 0, "using an on-stack array as a task input "
  596. "considered unsafe");
  597. /* Determine the number of elements in the vector. */
  598. tree count = NULL_TREE;
  599. if (TREE_CODE (ptr_type) == ARRAY_TYPE)
  600. count = array_type_element_count (loc, ptr_type);
  601. /* Second argument is optional but should be an integer. */
  602. count_arg = (args == NULL_TREE) ? NULL_TREE : TREE_VALUE (args);
  603. if (args != NULL_TREE)
  604. args = TREE_CHAIN (args);
  605. if (count_arg == NULL_TREE)
  606. {
  607. /* End of line reached: check whether the array size was
  608. determined. */
  609. if (count == NULL_TREE)
  610. {
  611. error_at (loc, "cannot determine size of array %qE", ptr);
  612. return;
  613. }
  614. }
  615. else if (count_arg == error_mark_node)
  616. /* COUNT_ARG could not be parsed and an error was already reported. */
  617. return;
  618. else if (!INTEGRAL_TYPE_P (TREE_TYPE (count_arg)))
  619. {
  620. error_at (loc, "%qE is not an integer", count_arg);
  621. return;
  622. }
  623. else
  624. {
  625. TREE_USED (count_arg) = true;
  626. #ifdef DECL_READ_P
  627. if (DECL_P (count_arg))
  628. DECL_READ_P (count_arg) = true;
  629. #endif
  630. if (count != NULL_TREE)
  631. {
  632. /* The number of elements of this array was already determined. */
  633. inform (loc,
  634. "element count can be omitted for bounded array %qE",
  635. ptr);
  636. if (count_arg != NULL_TREE)
  637. {
  638. if (TREE_CODE (count_arg) == INTEGER_CST)
  639. {
  640. if (!tree_int_cst_equal (count, count_arg))
  641. error_at (loc, "specified element count differs "
  642. "from actual size of array %qE",
  643. ptr);
  644. }
  645. else
  646. /* Using a variable to determine the array size whereas the
  647. array size is actually known statically. This looks like
  648. unreasonable code, so error out. */
  649. error_at (loc, "determining array size at run-time "
  650. "although array size is known at compile-time");
  651. }
  652. }
  653. else
  654. count = count_arg;
  655. }
  656. /* Any remaining args? */
  657. if (args != NULL_TREE)
  658. error_at (loc, "junk after %<starpu register%> pragma");
  659. /* Add a data register call. */
  660. add_stmt (build_data_register_call (loc, ptr, count));
  661. }
  662. /* Process `#pragma starpu acquire VAR' and emit the corresponding
  663. `starpu_data_acquire' call. */
  664. static void
  665. handle_pragma_acquire (struct cpp_reader *reader)
  666. {
  667. static tree acquire_fn;
  668. LOOKUP_STARPU_FUNCTION (acquire_fn, "starpu_data_acquire");
  669. tree args, var;
  670. location_t loc;
  671. loc = cpp_peek_token (reader, 0)->src_loc;
  672. args = read_pragma_expressions ("acquire", loc);
  673. if (args == NULL_TREE)
  674. return;
  675. var = TREE_VALUE (args);
  676. if (var == error_mark_node)
  677. return;
  678. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  679. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  680. {
  681. error_at (loc, "%qE is neither a pointer nor an array", var);
  682. return;
  683. }
  684. else if (TREE_CHAIN (args) != NULL_TREE)
  685. error_at (loc, "junk after %<starpu acquire%> pragma");
  686. /* If VAR is an array, take its address. */
  687. tree pointer =
  688. POINTER_TYPE_P (TREE_TYPE (var))
  689. ? var
  690. : build_addr (var, current_function_decl);
  691. /* Call `starpu_data_acquire (starpu_data_lookup (ptr), STARPU_RW)'.
  692. TODO: Support modes other than RW. */
  693. add_stmt (build_call_expr (acquire_fn, 2,
  694. build_pointer_lookup (pointer),
  695. build_int_cst (integer_type_node, STARPU_RW)));
  696. }
  697. /* Process `#pragma starpu release VAR' and emit the corresponding
  698. `starpu_data_release' call. */
  699. static void
  700. handle_pragma_release (struct cpp_reader *reader)
  701. {
  702. static tree release_fn;
  703. LOOKUP_STARPU_FUNCTION (release_fn, "starpu_data_release");
  704. tree args, var;
  705. location_t loc;
  706. loc = cpp_peek_token (reader, 0)->src_loc;
  707. args = read_pragma_expressions ("release", loc);
  708. if (args == NULL_TREE)
  709. return;
  710. var = TREE_VALUE (args);
  711. if (var == error_mark_node)
  712. return;
  713. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  714. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  715. {
  716. error_at (loc, "%qE is neither a pointer nor an array", var);
  717. return;
  718. }
  719. else if (TREE_CHAIN (args) != NULL_TREE)
  720. error_at (loc, "junk after %<starpu release%> pragma");
  721. /* If VAR is an array, take its address. */
  722. tree pointer =
  723. POINTER_TYPE_P (TREE_TYPE (var))
  724. ? var
  725. : build_addr (var, current_function_decl);
  726. /* Call `starpu_data_release (starpu_data_lookup (ptr))'. */
  727. add_stmt (build_call_expr (release_fn, 1,
  728. build_pointer_lookup (pointer)));
  729. }
  730. /* Process `#pragma starpu unregister VAR' and emit the corresponding
  731. `starpu_data_unregister' call. */
  732. static void
  733. handle_pragma_unregister (struct cpp_reader *reader)
  734. {
  735. tree args, var;
  736. location_t loc;
  737. loc = cpp_peek_token (reader, 0)->src_loc;
  738. args = read_pragma_expressions ("unregister", loc);
  739. if (args == NULL_TREE)
  740. return;
  741. var = TREE_VALUE (args);
  742. if (var == error_mark_node)
  743. return;
  744. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  745. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  746. {
  747. error_at (loc, "%qE is neither a pointer nor an array", var);
  748. return;
  749. }
  750. else if (TREE_CHAIN (args) != NULL_TREE)
  751. error_at (loc, "junk after %<starpu unregister%> pragma");
  752. add_stmt (build_data_unregister_call (loc, var));
  753. }
  754. /* Handle the `debug_tree' pragma (for debugging purposes.) */
  755. static void
  756. handle_pragma_debug_tree (struct cpp_reader *reader)
  757. {
  758. tree args, obj;
  759. location_t loc;
  760. loc = cpp_peek_token (reader, 0)->src_loc;
  761. args = read_pragma_expressions ("debug_tree", loc);
  762. if (args == NULL_TREE)
  763. /* Parse error, presumably already handled by the parser. */
  764. return;
  765. obj = TREE_VALUE (args);
  766. args = TREE_CHAIN (args);
  767. if (obj == error_mark_node)
  768. return;
  769. if (args != NULL_TREE)
  770. warning_at (loc, 0, "extraneous arguments ignored");
  771. inform (loc, "debug_tree:");
  772. debug_tree (obj);
  773. printf ("\n");
  774. }
  775. static void
  776. register_pragmas (void *gcc_data, void *user_data)
  777. {
  778. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "hello",
  779. handle_pragma_hello);
  780. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "debug_tree",
  781. handle_pragma_debug_tree);
  782. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "initialize",
  783. handle_pragma_initialize);
  784. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "wait",
  785. handle_pragma_wait);
  786. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "register",
  787. handle_pragma_register);
  788. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "acquire",
  789. handle_pragma_acquire);
  790. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "release",
  791. handle_pragma_release);
  792. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "unregister",
  793. handle_pragma_unregister);
  794. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "shutdown",
  795. handle_pragma_shutdown);
  796. }
  797. /* Attributes. */
  798. /* Turn FN into a task, and push its associated codelet declaration. */
  799. static void
  800. taskify_function (tree fn)
  801. {
  802. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  803. /* Add a `task' attribute and an empty `task_implementation_list'
  804. attribute. */
  805. DECL_ATTRIBUTES (fn) =
  806. tree_cons (get_identifier (task_implementation_list_attribute_name),
  807. NULL_TREE,
  808. tree_cons (get_identifier (task_attribute_name), NULL_TREE,
  809. DECL_ATTRIBUTES (fn)));
  810. /* Push a declaration for the corresponding `struct starpu_codelet' object and
  811. add it as an attribute of FN. */
  812. tree cl = build_codelet_declaration (fn);
  813. DECL_ATTRIBUTES (fn) =
  814. tree_cons (get_identifier (task_codelet_attribute_name), cl,
  815. DECL_ATTRIBUTES (fn));
  816. pushdecl (cl);
  817. }
  818. /* Handle the `task' function attribute. */
  819. static tree
  820. handle_task_attribute (tree *node, tree name, tree args,
  821. int flags, bool *no_add_attrs)
  822. {
  823. tree fn;
  824. fn = *node;
  825. /* Get rid of the `task' attribute by default so that FN isn't further
  826. processed when it's erroneous. */
  827. *no_add_attrs = true;
  828. if (TREE_CODE (fn) != FUNCTION_DECL)
  829. error_at (DECL_SOURCE_LOCATION (fn),
  830. "%<task%> attribute only applies to functions");
  831. else
  832. {
  833. if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fn))))
  834. /* Raise an error but keep going to avoid spitting out too many
  835. errors at the user's face. */
  836. error_at (DECL_SOURCE_LOCATION (fn),
  837. "task return type must be %<void%>");
  838. if (count (pointer_type_p, TYPE_ARG_TYPES (TREE_TYPE (fn)))
  839. > STARPU_NMAXBUFS)
  840. error_at (DECL_SOURCE_LOCATION (fn),
  841. "maximum number of pointer parameters exceeded");
  842. /* Turn FN into an actual task. */
  843. taskify_function (fn);
  844. }
  845. /* Lookup & cache function declarations for later reuse. */
  846. LOOKUP_STARPU_FUNCTION (unpack_fn, "starpu_codelet_unpack_args");
  847. LOOKUP_STARPU_FUNCTION (data_lookup_fn, "starpu_data_lookup");
  848. return NULL_TREE;
  849. }
  850. /* Diagnose use of C types that are either nonexistent or different in
  851. OpenCL. */
  852. static void
  853. validate_opencl_argument_type (location_t loc, const_tree type)
  854. {
  855. /* When TYPE is a pointer type, get to the base element type. */
  856. for (; POINTER_TYPE_P (type); type = TREE_TYPE (type));
  857. if (!RECORD_OR_UNION_TYPE_P (type) && !VOID_TYPE_P (type))
  858. {
  859. tree decl = TYPE_NAME (type);
  860. if (DECL_P (decl))
  861. {
  862. static const struct { const char *c; const char *cl; }
  863. type_map[] =
  864. {
  865. /* Scalar types defined in OpenCL 1.2. See
  866. <http://www.khronos.org/files/opencl-1-2-quick-reference-card.pdf>. */
  867. { "char", "cl_char" },
  868. { "signed char", "cl_char" },
  869. { "unsigned char", "cl_uchar" },
  870. { "uchar", "cl_uchar" },
  871. { "short int", "cl_short" },
  872. { "unsigned short", "cl_ushort" },
  873. { "int", "cl_int" },
  874. { "unsigned int", "cl_uint" },
  875. { "uint", "cl_uint" },
  876. { "long int", "cl_long" },
  877. { "long unsigned int", "cl_ulong" },
  878. { "ulong", "cl_ulong" },
  879. { "float", "cl_float" },
  880. { "double", "cl_double" },
  881. { NULL, NULL }
  882. };
  883. const char *c_name = IDENTIFIER_POINTER (DECL_NAME (decl));
  884. const char *cl_name =
  885. ({
  886. size_t i;
  887. for (i = 0; type_map[i].c != NULL; i++)
  888. {
  889. if (strcmp (type_map[i].c, c_name) == 0)
  890. break;
  891. }
  892. type_map[i].cl;
  893. });
  894. if (cl_name != NULL)
  895. {
  896. tree cl_type = lookup_name (get_identifier (cl_name));
  897. if (cl_type != NULL_TREE)
  898. {
  899. if (DECL_P (cl_type))
  900. cl_type = TREE_TYPE (cl_type);
  901. if (!lang_hooks.types_compatible_p ((tree) type, cl_type))
  902. {
  903. tree st, sclt;
  904. st = c_common_signed_type ((tree) type);
  905. sclt = c_common_signed_type (cl_type);
  906. if (st == sclt)
  907. warning_at (loc, 0, "C type %qE differs in signedness "
  908. "from the same-named OpenCL type",
  909. DECL_NAME (decl));
  910. else
  911. /* TYPE should be avoided because the it differs from
  912. CL_TYPE, and thus cannot be used safely in
  913. `clSetKernelArg'. */
  914. warning_at (loc, 0, "C type %qE differs from the "
  915. "same-named OpenCL type",
  916. DECL_NAME (decl));
  917. }
  918. }
  919. /* Otherwise we can't conclude. It could be that <CL/cl.h>
  920. wasn't included in the program, for instance. */
  921. }
  922. else
  923. /* Recommend against use of `size_t', etc. */
  924. warning_at (loc, 0, "%qE does not correspond to a known "
  925. "OpenCL type", DECL_NAME (decl));
  926. }
  927. }
  928. }
  929. /* Add FN to the list of implementations of TASK_DECL. */
  930. static void
  931. add_task_implementation (tree task_decl, tree fn, const_tree where)
  932. {
  933. location_t loc;
  934. tree attr, impls;
  935. attr = lookup_attribute (task_implementation_list_attribute_name,
  936. DECL_ATTRIBUTES (task_decl));
  937. gcc_assert (attr != NULL_TREE);
  938. gcc_assert (TREE_CODE (where) == STRING_CST);
  939. loc = DECL_SOURCE_LOCATION (fn);
  940. impls = tree_cons (NULL_TREE, fn, TREE_VALUE (attr));
  941. TREE_VALUE (attr) = impls;
  942. TREE_USED (fn) = true;
  943. /* Check the `where' argument to raise a warning if needed. */
  944. if (task_implementation_target_to_int (where) == 0)
  945. warning_at (loc, 0,
  946. "unsupported target %E; task implementation won't be used",
  947. where);
  948. else if (task_implementation_target_to_int (where) == STARPU_OPENCL)
  949. {
  950. local_define (void, validate, (tree t))
  951. {
  952. validate_opencl_argument_type (loc, t);
  953. };
  954. for_each (validate, TYPE_ARG_TYPES (TREE_TYPE (fn)));
  955. }
  956. }
  957. /* Handle the `task_implementation (WHERE, TASK)' attribute. WHERE is a
  958. string constant ("cpu", "cuda", etc.), and TASK is the identifier of a
  959. function declared with the `task' attribute. */
  960. static tree
  961. handle_task_implementation_attribute (tree *node, tree name, tree args,
  962. int flags, bool *no_add_attrs)
  963. {
  964. location_t loc;
  965. tree fn, where, task_decl;
  966. /* FIXME:TODO: To change the order to (TASK, WHERE):
  967. tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
  968. tree cleanup_decl = lookup_name (cleanup_id);
  969. */
  970. fn = *node;
  971. where = TREE_VALUE (args);
  972. task_decl = TREE_VALUE (TREE_CHAIN (args));
  973. if (implicit_cpu_task_implementation_p (task_decl))
  974. /* TASK_DECL is actually a CPU implementation. Implicit CPU task
  975. implementations can lead to this situation, because the task is
  976. renamed and modified to become a CPU implementation. */
  977. task_decl = task_implementation_task (task_decl);
  978. loc = DECL_SOURCE_LOCATION (fn);
  979. /* Get rid of the `task_implementation' attribute by default so that FN
  980. isn't further processed when it's erroneous. */
  981. *no_add_attrs = true;
  982. /* Mark FN as used to placate `-Wunused-function' when FN is erroneous
  983. anyway. */
  984. TREE_USED (fn) = true;
  985. if (TREE_CODE (fn) != FUNCTION_DECL)
  986. error_at (loc,
  987. "%<task_implementation%> attribute only applies to functions");
  988. else if (TREE_CODE (where) != STRING_CST)
  989. error_at (loc, "string constant expected "
  990. "as the first %<task_implementation%> argument");
  991. else if (TREE_CODE (task_decl) != FUNCTION_DECL)
  992. error_at (loc, "%qE is not a function", task_decl);
  993. else if (lookup_attribute (task_attribute_name,
  994. DECL_ATTRIBUTES (task_decl)) == NULL_TREE)
  995. error_at (loc, "function %qE lacks the %<task%> attribute",
  996. DECL_NAME (task_decl));
  997. else if (TYPE_CANONICAL (TREE_TYPE (fn))
  998. != TYPE_CANONICAL (TREE_TYPE (task_decl)))
  999. error_at (loc, "type differs from that of task %qE",
  1000. DECL_NAME (task_decl));
  1001. else
  1002. {
  1003. /* Add FN to the list of implementations of TASK_DECL. */
  1004. add_task_implementation (task_decl, fn, where);
  1005. /* Keep the attribute. */
  1006. *no_add_attrs = false;
  1007. }
  1008. return NULL_TREE;
  1009. }
  1010. /* Return true when VAR is an automatic variable with complete array type;
  1011. otherwise, return false, and emit error messages mentioning ATTRIBUTE. */
  1012. static bool
  1013. automatic_array_variable_p (const char *attribute, tree var)
  1014. {
  1015. gcc_assert (TREE_CODE (var) == VAR_DECL);
  1016. location_t loc;
  1017. loc = DECL_SOURCE_LOCATION (var);
  1018. if (DECL_EXTERNAL (var))
  1019. error_at (loc, "attribute %qs cannot be used on external declarations",
  1020. attribute);
  1021. else if (TREE_PUBLIC (var) || TREE_STATIC (var))
  1022. {
  1023. error_at (loc, "attribute %qs cannot be used on global variables",
  1024. attribute);
  1025. TREE_TYPE (var) = error_mark_node;
  1026. }
  1027. else if (TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  1028. {
  1029. error_at (loc, "variable %qE must have an array type",
  1030. DECL_NAME (var));
  1031. TREE_TYPE (var) = error_mark_node;
  1032. }
  1033. else if (TYPE_SIZE (TREE_TYPE (var)) == NULL_TREE)
  1034. {
  1035. error_at (loc, "variable %qE has an incomplete array type",
  1036. DECL_NAME (var));
  1037. TREE_TYPE (var) = error_mark_node;
  1038. }
  1039. else
  1040. return true;
  1041. return false;
  1042. }
  1043. /* Handle the `heap_allocated' attribute on variable *NODE. */
  1044. static tree
  1045. handle_heap_allocated_attribute (tree *node, tree name, tree args,
  1046. int flags, bool *no_add_attrs)
  1047. {
  1048. tree var = *node;
  1049. if (automatic_array_variable_p (heap_allocated_attribute_name, var))
  1050. {
  1051. /* Turn VAR into a pointer that feels like an array. This is what's
  1052. done for PARM_DECLs that have an array type. */
  1053. tree array_type = TREE_TYPE (var);
  1054. tree element_type = TREE_TYPE (array_type);
  1055. tree pointer_type = build_pointer_type (element_type);
  1056. /* Keep a copy of VAR's original type. */
  1057. DECL_ATTRIBUTES (var) =
  1058. tree_cons (get_identifier (heap_allocated_orig_type_attribute_name),
  1059. array_type, DECL_ATTRIBUTES (var));
  1060. TREE_TYPE (var) = pointer_type;
  1061. DECL_SIZE (var) = TYPE_SIZE (pointer_type);
  1062. DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (pointer_type);
  1063. DECL_ALIGN (var) = TYPE_ALIGN (pointer_type);
  1064. DECL_USER_ALIGN (var) = false;
  1065. DECL_MODE (var) = TYPE_MODE (pointer_type);
  1066. tree malloc_fn = lookup_name (get_identifier ("starpu_malloc"));
  1067. gcc_assert (malloc_fn != NULL_TREE);
  1068. tree alloc = build_call_expr (malloc_fn, 2,
  1069. build_addr (var, current_function_decl),
  1070. TYPE_SIZE_UNIT (array_type));
  1071. TREE_SIDE_EFFECTS (alloc) = true;
  1072. add_stmt (alloc);
  1073. /* Add a destructor for VAR. Instead of consing the `cleanup'
  1074. attribute for VAR, directly use `push_cleanup'. This guarantees
  1075. that CLEANUP_ID is looked up in the right context, and allows us to
  1076. pass VAR directly to `starpu_free', instead of `&VAR'.
  1077. TODO: Provide a way to disable this. */
  1078. static tree cleanup_decl;
  1079. LOOKUP_STARPU_FUNCTION (cleanup_decl, "starpu_free");
  1080. push_cleanup (var, build_call_expr (cleanup_decl, 1, var), false);
  1081. }
  1082. return NULL_TREE;
  1083. }
  1084. /* Handle the `output' attribute on type *NODE, which should be the type of a
  1085. PARM_DECL of a task or task implementation. */
  1086. static tree
  1087. handle_output_attribute (tree *node, tree name, tree args,
  1088. int flags, bool *no_add_attrs)
  1089. {
  1090. tree type = *node;
  1091. gcc_assert (TYPE_P (type));
  1092. if (!POINTER_TYPE_P (type) && TREE_CODE (type) != ARRAY_TYPE)
  1093. error ("%<output%> attribute not allowed for non-pointer types");
  1094. else
  1095. /* Keep the attribute. */
  1096. *no_add_attrs = false;
  1097. return NULL_TREE;
  1098. }
  1099. /* Return the declaration of the `struct starpu_codelet' variable associated with
  1100. TASK_DECL. */
  1101. static tree
  1102. task_codelet_declaration (const_tree task_decl)
  1103. {
  1104. tree cl_attr;
  1105. cl_attr = lookup_attribute (task_codelet_attribute_name,
  1106. DECL_ATTRIBUTES (task_decl));
  1107. gcc_assert (cl_attr != NULL_TREE);
  1108. return TREE_VALUE (cl_attr);
  1109. }
  1110. /* Return true if DECL is a task. */
  1111. static bool
  1112. task_p (const_tree decl)
  1113. {
  1114. return (TREE_CODE (decl) == FUNCTION_DECL &&
  1115. lookup_attribute (task_attribute_name,
  1116. DECL_ATTRIBUTES (decl)) != NULL_TREE);
  1117. }
  1118. /* Return true if DECL is a task implementation. */
  1119. static bool
  1120. task_implementation_p (const_tree decl)
  1121. {
  1122. return (TREE_CODE (decl) == FUNCTION_DECL &&
  1123. lookup_attribute (task_implementation_attribute_name,
  1124. DECL_ATTRIBUTES (decl)) != NULL_TREE);
  1125. }
  1126. /* Return the list of implementations of TASK_DECL. */
  1127. static tree
  1128. task_implementation_list (const_tree task_decl)
  1129. {
  1130. tree attr;
  1131. attr = lookup_attribute (task_implementation_list_attribute_name,
  1132. DECL_ATTRIBUTES (task_decl));
  1133. return TREE_VALUE (attr);
  1134. }
  1135. /* Return the list of pointer parameter types of TASK_DECL. */
  1136. static tree
  1137. task_pointer_parameter_types (const_tree task_decl)
  1138. {
  1139. return filter (pointer_type_p, TYPE_ARG_TYPES (TREE_TYPE (task_decl)));
  1140. }
  1141. /* Return the StarPU integer constant corresponding to string TARGET. */
  1142. static int
  1143. task_implementation_target_to_int (const_tree target)
  1144. {
  1145. gcc_assert (TREE_CODE (target) == STRING_CST);
  1146. int where_int;
  1147. if (!strncmp (TREE_STRING_POINTER (target), "cpu",
  1148. TREE_STRING_LENGTH (target)))
  1149. where_int = STARPU_CPU;
  1150. else if (!strncmp (TREE_STRING_POINTER (target), "opencl",
  1151. TREE_STRING_LENGTH (target)))
  1152. where_int = STARPU_OPENCL;
  1153. else if (!strncmp (TREE_STRING_POINTER (target), "cuda",
  1154. TREE_STRING_LENGTH (target)))
  1155. where_int = STARPU_CUDA;
  1156. else if (!strncmp (TREE_STRING_POINTER (target), "gordon",
  1157. TREE_STRING_LENGTH (target)))
  1158. where_int = STARPU_GORDON;
  1159. else
  1160. where_int = 0;
  1161. return where_int;
  1162. }
  1163. /* Return a value indicating where TASK_IMPL should execute (`STARPU_CPU',
  1164. `STARPU_CUDA', etc.). */
  1165. static int
  1166. task_implementation_where (const_tree task_impl)
  1167. {
  1168. tree impl_attr, args, where;
  1169. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  1170. impl_attr = lookup_attribute (task_implementation_attribute_name,
  1171. DECL_ATTRIBUTES (task_impl));
  1172. gcc_assert (impl_attr != NULL_TREE);
  1173. args = TREE_VALUE (impl_attr);
  1174. where = TREE_VALUE (args);
  1175. return task_implementation_target_to_int (where);
  1176. }
  1177. /* Return a bitwise-or of the supported targets of TASK_DECL. */
  1178. static int
  1179. task_where (const_tree task_decl)
  1180. {
  1181. gcc_assert (task_p (task_decl));
  1182. int where;
  1183. const_tree impl;
  1184. for (impl = task_implementation_list (task_decl), where = 0;
  1185. impl != NULL_TREE;
  1186. impl = TREE_CHAIN (impl))
  1187. where |= task_implementation_where (TREE_VALUE (impl));
  1188. return where;
  1189. }
  1190. /* Return the task implemented by TASK_IMPL. */
  1191. static tree
  1192. task_implementation_task (const_tree task_impl)
  1193. {
  1194. tree impl_attr, args, task;
  1195. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  1196. impl_attr = lookup_attribute (task_implementation_attribute_name,
  1197. DECL_ATTRIBUTES (task_impl));
  1198. gcc_assert (impl_attr != NULL_TREE);
  1199. args = TREE_VALUE (impl_attr);
  1200. task = TREE_VALUE (TREE_CHAIN (args));
  1201. if (task_implementation_p (task))
  1202. /* TASK is an implicit CPU task implementation, so return its real
  1203. task. */
  1204. return task_implementation_task (task);
  1205. return task;
  1206. }
  1207. /* Return the FUNCTION_DECL of the wrapper generated for TASK_IMPL. */
  1208. static tree
  1209. task_implementation_wrapper (const_tree task_impl)
  1210. {
  1211. tree attr;
  1212. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  1213. attr = lookup_attribute (task_implementation_wrapper_attribute_name,
  1214. DECL_ATTRIBUTES (task_impl));
  1215. gcc_assert (attr != NULL_TREE);
  1216. return TREE_VALUE (attr);
  1217. }
  1218. /* Return true when FN is an implicit CPU task implementation. */
  1219. static bool
  1220. implicit_cpu_task_implementation_p (const_tree fn)
  1221. {
  1222. if (task_implementation_p (fn)
  1223. && task_implementation_where (fn) == STARPU_CPU)
  1224. {
  1225. /* XXX: Hackish heuristic. */
  1226. const_tree cpu_id;
  1227. cpu_id = build_cpu_codelet_identifier (task_implementation_task (fn));
  1228. return cpu_id == DECL_NAME (fn);
  1229. }
  1230. return false;
  1231. }
  1232. /* Return true when VAR_DECL has the `heap_allocated' attribute. */
  1233. static bool
  1234. heap_allocated_p (const_tree var_decl)
  1235. {
  1236. gcc_assert (TREE_CODE (var_decl) == VAR_DECL);
  1237. return lookup_attribute (heap_allocated_attribute_name,
  1238. DECL_ATTRIBUTES (var_decl)) != NULL_TREE;
  1239. }
  1240. /* Return true if TYPE is `output'-qualified. */
  1241. static bool
  1242. output_type_p (const_tree type)
  1243. {
  1244. return (lookup_attribute (output_attribute_name,
  1245. TYPE_ATTRIBUTES (type)) != NULL_TREE);
  1246. }
  1247. /* Return the access mode for POINTER, a PARM_DECL of a task. */
  1248. static enum starpu_access_mode
  1249. access_mode (const_tree type)
  1250. {
  1251. gcc_assert (POINTER_TYPE_P (type));
  1252. /* If TYPE points to a const-qualified type, then mark the data as
  1253. read-only; if is has the `output' attribute, then mark it as write-only;
  1254. otherwise default to read-write. */
  1255. return ((TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
  1256. ? STARPU_R
  1257. : (output_type_p (type) ? STARPU_W : STARPU_RW));
  1258. }
  1259. static void
  1260. register_task_attributes (void *gcc_data, void *user_data)
  1261. {
  1262. static const struct attribute_spec task_attr =
  1263. {
  1264. task_attribute_name, 0, 0, true, false, false,
  1265. handle_task_attribute
  1266. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1267. , false
  1268. #endif
  1269. };
  1270. static const struct attribute_spec task_implementation_attr =
  1271. {
  1272. task_implementation_attribute_name, 2, 2, true, false, false,
  1273. handle_task_implementation_attribute
  1274. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1275. , false
  1276. #endif
  1277. };
  1278. static const struct attribute_spec heap_allocated_attr =
  1279. {
  1280. heap_allocated_attribute_name, 0, 0, true, false, false,
  1281. handle_heap_allocated_attribute
  1282. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1283. , false
  1284. #endif
  1285. };
  1286. static const struct attribute_spec output_attr =
  1287. {
  1288. output_attribute_name, 0, 0, true, true, false,
  1289. handle_output_attribute
  1290. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1291. , true /* affects type identity */
  1292. #endif
  1293. };
  1294. register_attribute (&task_attr);
  1295. register_attribute (&task_implementation_attr);
  1296. register_attribute (&heap_allocated_attr);
  1297. register_attribute (&output_attr);
  1298. }
  1299. /* Return the type of a codelet function, i.e.,
  1300. `void (*) (void **, void *)'. */
  1301. static tree
  1302. build_codelet_wrapper_type (void)
  1303. {
  1304. tree void_ptr_ptr;
  1305. void_ptr_ptr = build_pointer_type (ptr_type_node);
  1306. return build_function_type_list (void_type_node,
  1307. void_ptr_ptr, ptr_type_node,
  1308. NULL_TREE);
  1309. }
  1310. /* Return an identifier for the wrapper of TASK_IMPL, a task
  1311. implementation. */
  1312. static tree
  1313. build_codelet_wrapper_identifier (tree task_impl)
  1314. {
  1315. static const char suffix[] = ".task_implementation_wrapper";
  1316. tree id;
  1317. char *cl_name;
  1318. const char *task_name;
  1319. id = DECL_NAME (task_impl);
  1320. task_name = IDENTIFIER_POINTER (id);
  1321. cl_name = (char *) alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  1322. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  1323. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  1324. return get_identifier (cl_name);
  1325. }
  1326. /* Return a function of type `void (*) (void **, void *)' that calls function
  1327. TASK_IMPL, the FUNCTION_DECL of a task implementation whose prototype may
  1328. be arbitrary. */
  1329. static tree
  1330. build_codelet_wrapper_definition (tree task_impl)
  1331. {
  1332. location_t loc;
  1333. tree task_decl, wrapper_name, decl;
  1334. loc = DECL_SOURCE_LOCATION (task_impl);
  1335. task_decl = task_implementation_task (task_impl);
  1336. wrapper_name = build_codelet_wrapper_identifier (task_impl);
  1337. decl = build_decl (loc, FUNCTION_DECL, wrapper_name,
  1338. build_codelet_wrapper_type ());
  1339. local_define (tree, build_local_var, (const_tree type))
  1340. {
  1341. tree var, t;
  1342. const char *seed;
  1343. t = TREE_VALUE (type);
  1344. seed = POINTER_TYPE_P (t) ? "pointer_arg" : "scalar_arg";
  1345. var = build_decl (loc, VAR_DECL, create_tmp_var_name (seed), t);
  1346. DECL_CONTEXT (var) = decl;
  1347. DECL_ARTIFICIAL (var) = true;
  1348. return var;
  1349. };
  1350. /* Return the body of the wrapper, which unpacks `cl_args' and calls the
  1351. user-defined task implementation. */
  1352. local_define (tree, build_body, (tree wrapper_decl, tree vars))
  1353. {
  1354. bool opencl_p;
  1355. tree stmts = NULL, call, v;
  1356. VEC(tree, gc) *args;
  1357. opencl_p = (task_implementation_where (task_impl) == STARPU_OPENCL);
  1358. /* Build `var0 = STARPU_VECTOR_GET_PTR (buffers[0]); ...' or
  1359. `var0 = STARPU_VECTOR_GET_DEV_HANDLE (buffers[0])' for OpenCL. */
  1360. size_t index = 0;
  1361. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  1362. {
  1363. if (POINTER_TYPE_P (TREE_TYPE (v)))
  1364. {
  1365. /* Compute `void *VDESC = buffers[0];'. */
  1366. tree vdesc = array_ref (DECL_ARGUMENTS (wrapper_decl), index);
  1367. /* Use the right field, depending on OPENCL_P. */
  1368. size_t offset =
  1369. opencl_p
  1370. ? offsetof (struct starpu_vector_interface, dev_handle)
  1371. : offsetof (struct starpu_vector_interface, ptr);
  1372. gcc_assert (POINTER_TYPE_P (TREE_TYPE (vdesc)));
  1373. /* Compute `type *PTR = *(type **) VDESC;'. */
  1374. tree ptr =
  1375. build_indirect_ref (UNKNOWN_LOCATION,
  1376. fold_convert (build_pointer_type (TREE_TYPE (v)),
  1377. pointer_plus (vdesc, offset)),
  1378. RO_ARRAY_INDEXING);
  1379. append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (v),
  1380. v, ptr),
  1381. &stmts);
  1382. index++;
  1383. }
  1384. }
  1385. /* Build `starpu_codelet_unpack_args (cl_args, &var1, &var2, ...)'. */
  1386. args = NULL;
  1387. VEC_safe_push (tree, gc, args, TREE_CHAIN (DECL_ARGUMENTS (wrapper_decl)));
  1388. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  1389. {
  1390. if (!POINTER_TYPE_P (TREE_TYPE (v)))
  1391. VEC_safe_push (tree, gc, args, build_addr (v, wrapper_decl));
  1392. }
  1393. if (VEC_length (tree, args) > 1)
  1394. {
  1395. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fn, args);
  1396. TREE_SIDE_EFFECTS (call) = 1;
  1397. append_to_statement_list (call, &stmts);
  1398. }
  1399. /* Build `my_task_impl (var1, var2, ...)'. */
  1400. args = NULL;
  1401. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  1402. VEC_safe_push (tree, gc, args, v);
  1403. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, task_impl, args);
  1404. TREE_SIDE_EFFECTS (call) = 1;
  1405. append_to_statement_list (call, &stmts);
  1406. tree bind;
  1407. bind = build3 (BIND_EXPR, void_type_node, vars, stmts,
  1408. DECL_INITIAL (wrapper_decl));
  1409. TREE_TYPE (bind) = TREE_TYPE (TREE_TYPE (wrapper_decl));
  1410. return bind;
  1411. };
  1412. /* Return the parameter list of the wrapper:
  1413. `(void **BUFFERS, void *CL_ARGS)'. */
  1414. local_define (tree, build_parameters, (tree wrapper_decl))
  1415. {
  1416. tree param1, param2;
  1417. param1 = build_decl (loc, PARM_DECL,
  1418. create_tmp_var_name ("buffers"),
  1419. build_pointer_type (ptr_type_node));
  1420. DECL_ARG_TYPE (param1) = ptr_type_node;
  1421. DECL_CONTEXT (param1) = wrapper_decl;
  1422. TREE_USED (param1) = true;
  1423. param2 = build_decl (loc, PARM_DECL,
  1424. create_tmp_var_name ("cl_args"),
  1425. ptr_type_node);
  1426. DECL_ARG_TYPE (param2) = ptr_type_node;
  1427. DECL_CONTEXT (param2) = wrapper_decl;
  1428. TREE_USED (param2) = true;
  1429. return chainon (param1, param2);
  1430. };
  1431. tree vars, result;
  1432. vars = map (build_local_var,
  1433. list_remove (void_type_p,
  1434. TYPE_ARG_TYPES (TREE_TYPE (task_decl))));
  1435. DECL_CONTEXT (decl) = NULL_TREE;
  1436. DECL_ARGUMENTS (decl) = build_parameters (decl);
  1437. result = build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  1438. DECL_CONTEXT (result) = decl;
  1439. DECL_ARTIFICIAL (result) = true;
  1440. DECL_IGNORED_P (result) = true;
  1441. DECL_RESULT (decl) = result;
  1442. DECL_INITIAL (decl) = build_block (vars, NULL_TREE, decl, NULL_TREE);
  1443. DECL_SAVED_TREE (decl) = build_body (decl, vars);
  1444. TREE_PUBLIC (decl) = TREE_PUBLIC (task_impl);
  1445. TREE_STATIC (decl) = true;
  1446. TREE_USED (decl) = true;
  1447. DECL_ARTIFICIAL (decl) = true;
  1448. DECL_EXTERNAL (decl) = false;
  1449. DECL_UNINLINABLE (decl) = true;
  1450. rest_of_decl_compilation (decl, true, 0);
  1451. struct function *prev_cfun = cfun;
  1452. set_cfun (NULL);
  1453. allocate_struct_function (decl, false);
  1454. cfun->function_end_locus = DECL_SOURCE_LOCATION (task_impl);
  1455. cgraph_finalize_function (decl, false);
  1456. /* Mark DECL as needed so that it doesn't get removed by
  1457. `cgraph_remove_unreachable_nodes' when it's not public. */
  1458. cgraph_mark_needed_node (cgraph_get_node (decl));
  1459. set_cfun (prev_cfun);
  1460. return decl;
  1461. }
  1462. /* Define one wrapper function for each implementation of TASK. TASK should
  1463. be the FUNCTION_DECL of a task. */
  1464. static void
  1465. define_codelet_wrappers (tree task)
  1466. {
  1467. local_define (void, define, (tree task_impl))
  1468. {
  1469. tree wrapper_def;
  1470. wrapper_def = build_codelet_wrapper_definition (task_impl);
  1471. DECL_ATTRIBUTES (task_impl) =
  1472. tree_cons (get_identifier (task_implementation_wrapper_attribute_name),
  1473. wrapper_def,
  1474. DECL_ATTRIBUTES (task_impl));
  1475. };
  1476. for_each (define, task_implementation_list (task));
  1477. }
  1478. /* Return a NODE_IDENTIFIER for the variable holding the `struct starpu_codelet'
  1479. structure associated with TASK_DECL. */
  1480. static tree
  1481. build_codelet_identifier (tree task_decl)
  1482. {
  1483. static const char suffix[] = ".codelet";
  1484. tree id;
  1485. char *cl_name;
  1486. const char *task_name;
  1487. id = DECL_NAME (task_decl);
  1488. task_name = IDENTIFIER_POINTER (id);
  1489. cl_name = (char *) alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  1490. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  1491. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  1492. return get_identifier (cl_name);
  1493. }
  1494. static tree
  1495. codelet_type (void)
  1496. {
  1497. /* XXX: Hack to allow the type declaration to be accessible at lower
  1498. time. */
  1499. static tree type_decl = NULL_TREE;
  1500. if (type_decl == NULL_TREE)
  1501. {
  1502. /* Lookup the `struct starpu_codelet' struct type. This should succeed since
  1503. we push <starpu.h> early on. */
  1504. type_decl = xref_tag (RECORD_TYPE, get_identifier (codelet_struct_tag));
  1505. gcc_assert (type_decl != NULL_TREE
  1506. && TREE_CODE (type_decl) == RECORD_TYPE);
  1507. /* `build_decl' expects a TYPE_DECL, so give it what it wants. */
  1508. type_decl = TYPE_STUB_DECL (type_decl);
  1509. gcc_assert (type_decl != NULL && TREE_CODE (type_decl) == TYPE_DECL);
  1510. }
  1511. return TREE_TYPE (type_decl);
  1512. }
  1513. /* Return a VAR_DECL that declares a `struct starpu_codelet' structure for
  1514. TASK_DECL. */
  1515. static tree
  1516. build_codelet_declaration (tree task_decl)
  1517. {
  1518. tree name, cl_decl;
  1519. name = build_codelet_identifier (task_decl);
  1520. cl_decl = build_decl (DECL_SOURCE_LOCATION (task_decl),
  1521. VAR_DECL, name,
  1522. /* c_build_qualified_type (type, TYPE_QUAL_CONST) */
  1523. codelet_type ());
  1524. DECL_ARTIFICIAL (cl_decl) = true;
  1525. TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
  1526. TREE_STATIC (cl_decl) = false;
  1527. TREE_USED (cl_decl) = true;
  1528. DECL_EXTERNAL (cl_decl) = true;
  1529. DECL_CONTEXT (cl_decl) = NULL_TREE;
  1530. return cl_decl;
  1531. }
  1532. /* Return a `struct starpu_codelet' initializer for TASK_DECL. */
  1533. static tree
  1534. build_codelet_initializer (tree task_decl)
  1535. {
  1536. tree fields;
  1537. fields = TYPE_FIELDS (codelet_type ());
  1538. gcc_assert (TREE_CODE (fields) == FIELD_DECL);
  1539. local_define (tree, lookup_field, (const char *name))
  1540. {
  1541. tree fdecl, fname;
  1542. fname = get_identifier (name);
  1543. for (fdecl = fields;
  1544. fdecl != NULL_TREE;
  1545. fdecl = TREE_CHAIN (fdecl))
  1546. {
  1547. if (DECL_NAME (fdecl) == fname)
  1548. return fdecl;
  1549. }
  1550. /* Field NAME wasn't found. */
  1551. gcc_assert (false);
  1552. };
  1553. local_define (tree, field_initializer, (const char *name, tree value))
  1554. {
  1555. tree field, init;
  1556. field = lookup_field (name);
  1557. init = make_node (TREE_LIST);
  1558. TREE_PURPOSE (init) = field;
  1559. TREE_CHAIN (init) = NULL_TREE;
  1560. if (TREE_CODE (TREE_TYPE (value)) != ARRAY_TYPE)
  1561. TREE_VALUE (init) = fold_convert (TREE_TYPE (field), value);
  1562. else
  1563. TREE_VALUE (init) = value;
  1564. return init;
  1565. };
  1566. local_define (tree, codelet_name, ())
  1567. {
  1568. const char *name = IDENTIFIER_POINTER (DECL_NAME (task_decl));
  1569. return build_string_literal (strlen (name) + 1, name);
  1570. };
  1571. local_define (tree, where_init, (tree impls))
  1572. {
  1573. tree impl;
  1574. int where_int = 0;
  1575. for (impl = impls;
  1576. impl != NULL_TREE;
  1577. impl = TREE_CHAIN (impl))
  1578. {
  1579. tree impl_decl;
  1580. impl_decl = TREE_VALUE (impl);
  1581. gcc_assert (TREE_CODE (impl_decl) == FUNCTION_DECL);
  1582. if (verbose_output_p)
  1583. /* List the implementations of TASK_DECL. */
  1584. inform (DECL_SOURCE_LOCATION (impl_decl),
  1585. " %qE", DECL_NAME (impl_decl));
  1586. where_int |= task_implementation_where (impl_decl);
  1587. }
  1588. return build_int_cstu (integer_type_node, where_int);
  1589. };
  1590. local_define (tree, implementation_pointers, (tree impls, int where))
  1591. {
  1592. size_t len;
  1593. tree impl, pointers;
  1594. for (impl = impls, pointers = NULL_TREE, len = 0;
  1595. impl != NULL_TREE;
  1596. impl = TREE_CHAIN (impl))
  1597. {
  1598. tree impl_decl;
  1599. impl_decl = TREE_VALUE (impl);
  1600. if (task_implementation_where (impl_decl) == where)
  1601. {
  1602. /* Return a pointer to the wrapper of IMPL_DECL. */
  1603. tree addr = build_addr (task_implementation_wrapper (impl_decl),
  1604. NULL_TREE);
  1605. pointers = tree_cons (size_int (len), addr, pointers);
  1606. len++;
  1607. if (len > STARPU_MAXIMPLEMENTATIONS)
  1608. error_at (DECL_SOURCE_LOCATION (impl_decl),
  1609. "maximum number of per-target task implementations "
  1610. "exceeded");
  1611. }
  1612. }
  1613. /* POINTERS must be null-terminated. */
  1614. pointers = tree_cons (size_int (len), build_zero_cst (ptr_type_node),
  1615. pointers);
  1616. len++;
  1617. /* Return an array initializer. */
  1618. tree index_type = build_index_type (size_int (list_length (pointers)));
  1619. return build_constructor_from_list (build_array_type (ptr_type_node,
  1620. index_type),
  1621. nreverse (pointers));
  1622. };
  1623. local_define (tree, pointer_arg_count, (void))
  1624. {
  1625. size_t len;
  1626. len = list_length (task_pointer_parameter_types (task_decl));
  1627. return build_int_cstu (integer_type_node, len);
  1628. };
  1629. local_define (tree, access_mode_array, (void))
  1630. {
  1631. const_tree type;
  1632. tree modes;
  1633. size_t index;
  1634. for (type = task_pointer_parameter_types (task_decl),
  1635. modes = NULL_TREE, index = 0;
  1636. type != NULL_TREE && index < STARPU_NMAXBUFS;
  1637. type = TREE_CHAIN (type), index++)
  1638. {
  1639. tree value = build_int_cst (integer_type_node,
  1640. access_mode (TREE_VALUE (type)));
  1641. modes = tree_cons (size_int (index), value, modes);
  1642. }
  1643. tree index_type = build_index_type (size_int (list_length (modes)));
  1644. return build_constructor_from_list (build_array_type (integer_type_node,
  1645. index_type),
  1646. nreverse (modes));
  1647. };
  1648. if (verbose_output_p)
  1649. inform (DECL_SOURCE_LOCATION (task_decl),
  1650. "implementations for task %qE:", DECL_NAME (task_decl));
  1651. tree impls, inits;
  1652. impls = task_implementation_list (task_decl);
  1653. inits =
  1654. chain_trees (field_initializer ("name", codelet_name ()),
  1655. field_initializer ("where", where_init (impls)),
  1656. field_initializer ("nbuffers", pointer_arg_count ()),
  1657. field_initializer ("modes", access_mode_array ()),
  1658. field_initializer ("cpu_funcs",
  1659. implementation_pointers (impls,
  1660. STARPU_CPU)),
  1661. field_initializer ("opencl_funcs",
  1662. implementation_pointers (impls,
  1663. STARPU_OPENCL)),
  1664. field_initializer ("cuda_funcs",
  1665. implementation_pointers (impls,
  1666. STARPU_CUDA)),
  1667. NULL_TREE);
  1668. return build_constructor_from_unsorted_list (codelet_type (), inits);
  1669. }
  1670. /* Return the VAR_DECL that defines a `struct starpu_codelet' structure for
  1671. TASK_DECL. The VAR_DECL is assumed to already exists, so it must not be
  1672. pushed again. */
  1673. static tree
  1674. declare_codelet (tree task_decl)
  1675. {
  1676. /* Retrieve the declaration of the `struct starpu_codelet' object. */
  1677. tree cl_decl;
  1678. cl_decl = lookup_name (build_codelet_identifier (task_decl));
  1679. gcc_assert (cl_decl != NULL_TREE && TREE_CODE (cl_decl) == VAR_DECL);
  1680. /* Turn the codelet declaration into a definition. */
  1681. TREE_TYPE (cl_decl) = codelet_type ();
  1682. TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
  1683. return cl_decl;
  1684. }
  1685. /* Return the identifier for an automatically-generated CPU codelet of
  1686. TASK. */
  1687. static tree
  1688. build_cpu_codelet_identifier (const_tree task)
  1689. {
  1690. static const char suffix[] = ".cpu_implementation";
  1691. tree id;
  1692. char *cl_name;
  1693. const char *task_name;
  1694. id = DECL_NAME (task);
  1695. task_name = IDENTIFIER_POINTER (id);
  1696. cl_name = (char *) alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  1697. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  1698. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  1699. return get_identifier (cl_name);
  1700. }
  1701. static void
  1702. handle_pre_genericize (void *gcc_data, void *user_data)
  1703. {
  1704. tree fn = (tree) gcc_data;
  1705. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  1706. if (task_p (fn) && TREE_STATIC (fn))
  1707. {
  1708. /* The user defined a body for task FN, which we interpret as being the
  1709. body of an implicit CPU task implementation for FN. Thus, rename FN
  1710. and turn it into the "cpu" implementation of a task that we create
  1711. under FN's original name (this is easier than moving the body to a
  1712. different function, which would require traversing the body to
  1713. rewrite all references to FN to point to the new function.) Later,
  1714. `lower_starpu' rewrites calls to FN as calls to the newly created
  1715. task. */
  1716. tree task_name = DECL_NAME (fn);
  1717. tree cpu_impl = fn;
  1718. DECL_NAME (cpu_impl) = build_cpu_codelet_identifier (fn);
  1719. if (verbose_output_p)
  1720. inform (DECL_SOURCE_LOCATION (fn),
  1721. "implicit CPU implementation renamed from %qE to %qE",
  1722. task_name, DECL_NAME (cpu_impl));
  1723. tree task = build_decl (DECL_SOURCE_LOCATION (fn), FUNCTION_DECL,
  1724. task_name, TREE_TYPE (fn));
  1725. TREE_PUBLIC (task) = TREE_PUBLIC (fn);
  1726. TREE_PUBLIC (cpu_impl) = false;
  1727. taskify_function (task);
  1728. /* Inherit the task implementation list from FN. */
  1729. tree impls = lookup_attribute (task_implementation_list_attribute_name,
  1730. DECL_ATTRIBUTES (fn));
  1731. gcc_assert (impls != NULL_TREE);
  1732. impls = TREE_VALUE (impls);
  1733. DECL_ATTRIBUTES (task) =
  1734. tree_cons (get_identifier (task_implementation_list_attribute_name),
  1735. impls, DECL_ATTRIBUTES (task));
  1736. /* Make CPU_IMPL an implementation of FN. */
  1737. DECL_ATTRIBUTES (cpu_impl) =
  1738. tree_cons (get_identifier (task_implementation_attribute_name),
  1739. tree_cons (NULL_TREE, build_string (3, "cpu"),
  1740. tree_cons (NULL_TREE, task, NULL_TREE)),
  1741. NULL_TREE);
  1742. add_task_implementation (task, cpu_impl, build_string (3, "cpu"));
  1743. /* And now, process CPU_IMPL. */
  1744. }
  1745. if (task_implementation_p (fn))
  1746. {
  1747. tree task = task_implementation_task (fn);
  1748. if (!TREE_STATIC (task))
  1749. {
  1750. /* TASK lacks a body. Declare its codelet, intantiate its codelet
  1751. wrappers, and its body in this compilation unit. */
  1752. local_define (tree, build_parameter, (const_tree lst))
  1753. {
  1754. tree param, type;
  1755. type = TREE_VALUE (lst);
  1756. param = build_decl (DECL_SOURCE_LOCATION (task), PARM_DECL,
  1757. create_tmp_var_name ("parameter"),
  1758. type);
  1759. DECL_ARG_TYPE (param) = type;
  1760. DECL_CONTEXT (param) = task;
  1761. return param;
  1762. };
  1763. /* Declare TASK's codelet. It cannot be defined yet because the
  1764. complete list of tasks isn't available at this point. */
  1765. declare_codelet (task);
  1766. /* Set the task's parameter list. */
  1767. DECL_ARGUMENTS (task) =
  1768. map (build_parameter,
  1769. list_remove (void_type_p,
  1770. TYPE_ARG_TYPES (TREE_TYPE (task))));
  1771. /* Build its body. */
  1772. current_function_decl = task;
  1773. define_task (task);
  1774. current_function_decl = fn;
  1775. /* Compile TASK's body. */
  1776. rest_of_decl_compilation (task, true, 0);
  1777. allocate_struct_function (task, false);
  1778. cgraph_finalize_function (task, false);
  1779. cgraph_mark_needed_node (cgraph_get_node (task));
  1780. }
  1781. }
  1782. }
  1783. /* Build a "conversion" from a raw C pointer to its data handle. The
  1784. assumption is that the programmer should have already registered the
  1785. pointer by themselves. */
  1786. static tree
  1787. build_pointer_lookup (tree pointer)
  1788. {
  1789. /* Make sure DATA_LOOKUP_FN is valid. */
  1790. LOOKUP_STARPU_FUNCTION (data_lookup_fn, "starpu_data_lookup");
  1791. location_t loc;
  1792. if (DECL_P (pointer))
  1793. loc = DECL_SOURCE_LOCATION (pointer);
  1794. else
  1795. loc = UNKNOWN_LOCATION;
  1796. /* Introduce a local variable to hold the handle. */
  1797. tree result_var = build_decl (loc, VAR_DECL,
  1798. create_tmp_var_name (".data_lookup_result"),
  1799. ptr_type_node);
  1800. DECL_CONTEXT (result_var) = current_function_decl;
  1801. DECL_ARTIFICIAL (result_var) = true;
  1802. DECL_SOURCE_LOCATION (result_var) = loc;
  1803. tree call = build_call_expr (data_lookup_fn, 1, pointer);
  1804. tree assignment = build2 (INIT_EXPR, TREE_TYPE (result_var),
  1805. result_var, call);
  1806. /* Build `if (RESULT_VAR == NULL) error ();'. */
  1807. tree cond = build3 (COND_EXPR, void_type_node,
  1808. build2 (EQ_EXPR, boolean_type_node,
  1809. result_var, null_pointer_node),
  1810. build_error_statements (loc, NULL_TREE,
  1811. "attempt to use unregistered "
  1812. "pointer"),
  1813. NULL_TREE);
  1814. tree stmts = NULL;
  1815. append_to_statement_list (assignment, &stmts);
  1816. append_to_statement_list (cond, &stmts);
  1817. append_to_statement_list (result_var, &stmts);
  1818. return build4 (TARGET_EXPR, ptr_type_node, result_var, stmts, NULL_TREE, NULL_TREE);
  1819. }
  1820. /* Build the body of TASK_DECL, which will call `starpu_insert_task'. */
  1821. static void
  1822. define_task (tree task_decl)
  1823. {
  1824. VEC(tree, gc) *args = NULL;
  1825. location_t loc = DECL_SOURCE_LOCATION (task_decl);
  1826. tree p, params = DECL_ARGUMENTS (task_decl);
  1827. /* The first argument will be a pointer to the codelet. */
  1828. VEC_safe_push (tree, gc, args,
  1829. build_addr (task_codelet_declaration (task_decl),
  1830. current_function_decl));
  1831. for (p = params; p != NULL_TREE; p = TREE_CHAIN (p))
  1832. {
  1833. gcc_assert (TREE_CODE (p) == PARM_DECL);
  1834. tree type = TREE_TYPE (p);
  1835. if (POINTER_TYPE_P (type))
  1836. {
  1837. /* A pointer: the arguments will be:
  1838. `STARPU_RW, ptr' or similar. */
  1839. VEC_safe_push (tree, gc, args,
  1840. build_int_cst (integer_type_node,
  1841. access_mode (type)));
  1842. VEC_safe_push (tree, gc, args, build_pointer_lookup (p));
  1843. }
  1844. else
  1845. {
  1846. /* A scalar: the arguments will be:
  1847. `STARPU_VALUE, &scalar, sizeof (scalar)'. */
  1848. mark_addressable (p);
  1849. VEC_safe_push (tree, gc, args,
  1850. build_int_cst (integer_type_node, STARPU_VALUE));
  1851. VEC_safe_push (tree, gc, args,
  1852. build_addr (p, current_function_decl));
  1853. VEC_safe_push (tree, gc, args,
  1854. size_in_bytes (type));
  1855. }
  1856. }
  1857. /* Push the terminating zero. */
  1858. VEC_safe_push (tree, gc, args,
  1859. build_int_cst (integer_type_node, 0));
  1860. /* Introduce a local variable to hold the error code. */
  1861. tree error_var = build_decl (loc, VAR_DECL,
  1862. create_tmp_var_name (".insert_task_error"),
  1863. integer_type_node);
  1864. DECL_CONTEXT (error_var) = task_decl;
  1865. DECL_ARTIFICIAL (error_var) = true;
  1866. /* Build this:
  1867. err = starpu_insert_task (...);
  1868. if (err != 0)
  1869. { printf ...; abort (); }
  1870. */
  1871. static tree insert_task_fn;
  1872. LOOKUP_STARPU_FUNCTION (insert_task_fn, "starpu_insert_task");
  1873. tree call = build_call_expr_loc_vec (loc, insert_task_fn, args);
  1874. tree assignment = build2 (INIT_EXPR, TREE_TYPE (error_var),
  1875. error_var, call);
  1876. tree name = DECL_NAME (task_decl);
  1877. tree cond = build3 (COND_EXPR, void_type_node,
  1878. build2 (NE_EXPR, boolean_type_node,
  1879. error_var, integer_zero_node),
  1880. build_error_statements (loc, error_var,
  1881. "failed to insert task `%s'",
  1882. IDENTIFIER_POINTER (name)),
  1883. NULL_TREE);
  1884. tree stmts = NULL;
  1885. append_to_statement_list (assignment, &stmts);
  1886. append_to_statement_list (cond, &stmts);
  1887. tree bind = build3 (BIND_EXPR, void_type_node, error_var, stmts,
  1888. NULL_TREE);
  1889. /* Put it all together. */
  1890. DECL_SAVED_TREE (task_decl) = bind;
  1891. TREE_STATIC (task_decl) = true;
  1892. DECL_EXTERNAL (task_decl) = false;
  1893. DECL_ARTIFICIAL (task_decl) = true;
  1894. DECL_INITIAL (task_decl) =
  1895. build_block (error_var, NULL_TREE, task_decl, NULL_TREE);
  1896. DECL_RESULT (task_decl) =
  1897. build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  1898. DECL_CONTEXT (DECL_RESULT (task_decl)) = task_decl;
  1899. }
  1900. /* Raise warnings if TASK doesn't meet the basic criteria. */
  1901. static void
  1902. validate_task (tree task)
  1903. {
  1904. gcc_assert (task_p (task));
  1905. static const int supported = 0
  1906. #ifdef STARPU_USE_CPU
  1907. | STARPU_CPU
  1908. #endif
  1909. #ifdef STARPU_USE_CUDA
  1910. | STARPU_CUDA
  1911. #endif
  1912. #ifdef STARPU_USE_OPENCL
  1913. | STARPU_OPENCL
  1914. #endif
  1915. #ifdef STARPU_USE_GORDON
  1916. | STARPU_GORDON
  1917. #endif
  1918. ;
  1919. int where = task_where (task);
  1920. /* If TASK has no implementations, things will barf elsewhere anyway. */
  1921. if (task_implementation_list (task) != NULL_TREE)
  1922. if ((where & supported) == 0)
  1923. error_at (DECL_SOURCE_LOCATION (task),
  1924. "none of the implementations of task %qE can be used",
  1925. DECL_NAME (task));
  1926. }
  1927. /* Raise an error when IMPL doesn't satisfy the constraints of a task
  1928. implementations, such as not invoking another task. */
  1929. static void
  1930. validate_task_implementation (tree impl)
  1931. {
  1932. gcc_assert (task_implementation_p (impl));
  1933. const struct cgraph_node *cgraph;
  1934. const struct cgraph_edge *callee;
  1935. cgraph = cgraph_get_node (impl);
  1936. /* When a definition of IMPL is available, check its callees. */
  1937. if (cgraph != NULL)
  1938. for (callee = cgraph->callees;
  1939. callee != NULL;
  1940. callee = callee->next_callee)
  1941. {
  1942. if (task_p (callee->callee->decl))
  1943. {
  1944. location_t loc;
  1945. loc = gimple_location (callee->call_stmt);
  1946. error_at (loc, "task %qE cannot be invoked from task implementation %qE",
  1947. DECL_NAME (callee->callee->decl),
  1948. DECL_NAME (impl));
  1949. }
  1950. }
  1951. }
  1952. static unsigned int
  1953. lower_starpu (void)
  1954. {
  1955. tree fndecl;
  1956. const struct cgraph_node *cgraph;
  1957. const struct cgraph_edge *callee;
  1958. fndecl = current_function_decl;
  1959. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  1960. if (task_p (fndecl))
  1961. {
  1962. /* Make sure the task and its implementations are valid. */
  1963. validate_task (fndecl);
  1964. for_each (validate_task_implementation,
  1965. task_implementation_list (fndecl));
  1966. /* Generate a `struct starpu_codelet' structure and a wrapper function for
  1967. each implementation of TASK_DECL. This cannot be done earlier
  1968. because we need to have a complete list of task implementations. */
  1969. define_codelet_wrappers (fndecl);
  1970. tree cl_def = task_codelet_declaration (fndecl);
  1971. DECL_INITIAL (cl_def) = build_codelet_initializer (fndecl);
  1972. TREE_STATIC (cl_def) = true;
  1973. DECL_EXTERNAL (cl_def) = false;
  1974. varpool_finalize_decl (cl_def);
  1975. }
  1976. /* This pass should occur after `build_cgraph_edges'. */
  1977. cgraph = cgraph_get_node (fndecl);
  1978. gcc_assert (cgraph != NULL);
  1979. if (MAIN_NAME_P (DECL_NAME (fndecl)))
  1980. {
  1981. /* Check whether FNDECL initializes StarPU and emit a warning if it
  1982. doesn't. */
  1983. bool initialized;
  1984. for (initialized = false, callee = cgraph->callees;
  1985. !initialized && callee != NULL;
  1986. callee = callee->next_callee)
  1987. {
  1988. initialized =
  1989. DECL_NAME (callee->callee->decl) == get_identifier ("starpu_init");
  1990. }
  1991. if (!initialized)
  1992. warning_at (DECL_SOURCE_LOCATION (fndecl), 0,
  1993. "%qE does not initialize StarPU", DECL_NAME (fndecl));
  1994. }
  1995. for (callee = cgraph->callees;
  1996. callee != NULL;
  1997. callee = callee->next_callee)
  1998. {
  1999. gcc_assert (callee->callee != NULL);
  2000. tree callee_decl, caller_decl;
  2001. callee_decl = callee->callee->decl;
  2002. caller_decl = callee->caller->decl;
  2003. if (implicit_cpu_task_implementation_p (callee_decl)
  2004. && !DECL_ARTIFICIAL (caller_decl))
  2005. {
  2006. /* Rewrite the call to point to the actual task beneath
  2007. CALLEE_DECL. */
  2008. callee_decl = task_implementation_task (callee_decl);
  2009. if (verbose_output_p)
  2010. inform (gimple_location (callee->call_stmt),
  2011. "call to %qE rewritten as a call to task %qE",
  2012. DECL_NAME (callee->callee->decl),
  2013. DECL_NAME (callee_decl));
  2014. gimple_call_set_fn (callee->call_stmt,
  2015. build_addr (callee_decl, callee->caller->decl));
  2016. }
  2017. if (task_p (callee_decl))
  2018. {
  2019. if (verbose_output_p)
  2020. inform (gimple_location (callee->call_stmt),
  2021. "%qE calls task %qE",
  2022. DECL_NAME (fndecl), DECL_NAME (callee_decl));
  2023. /* TODO: Insert analysis to check whether the pointer arguments
  2024. need to be registered. */
  2025. }
  2026. }
  2027. return 0;
  2028. }
  2029. static struct opt_pass pass_lower_starpu =
  2030. {
  2031. designated_field_init (type, GIMPLE_PASS),
  2032. designated_field_init (name, "pass_lower_starpu"),
  2033. designated_field_init (gate, NULL),
  2034. designated_field_init (execute, lower_starpu)
  2035. /* The rest is zeroed. */
  2036. };
  2037. /* Initialization. */
  2038. /* Directory where to look up <starpu.h> instead of `STARPU_INCLUDE_DIR'. */
  2039. static const char *include_dir;
  2040. static void
  2041. define_cpp_macros (void *gcc_data, void *user_data)
  2042. {
  2043. cpp_define (parse_in, "STARPU_GCC_PLUGIN=0");
  2044. if (include_dir)
  2045. {
  2046. /* Get the header from the user-specified directory. This is useful
  2047. when running the test suite, before StarPU is installed. */
  2048. char header[strlen (include_dir) + sizeof ("/starpu.h")];
  2049. strcpy (header, include_dir);
  2050. strcat (header, "/starpu.h");
  2051. cpp_push_include (parse_in, header);
  2052. }
  2053. else
  2054. cpp_push_include (parse_in, STARPU_INCLUDE_DIR "/starpu.h");
  2055. }
  2056. int
  2057. plugin_init (struct plugin_name_args *plugin_info,
  2058. struct plugin_gcc_version *version)
  2059. {
  2060. if (!plugin_default_version_check (version, &gcc_version))
  2061. return 1;
  2062. register_callback (plugin_name, PLUGIN_START_UNIT,
  2063. define_cpp_macros, NULL);
  2064. register_callback (plugin_name, PLUGIN_PRAGMAS,
  2065. register_pragmas, NULL);
  2066. register_callback (plugin_name, PLUGIN_ATTRIBUTES,
  2067. register_task_attributes, NULL);
  2068. register_callback (plugin_name, PLUGIN_PRE_GENERICIZE,
  2069. handle_pre_genericize, NULL);
  2070. /* Register our pass so that it happens after `build_cgraph_edges' has been
  2071. done. */
  2072. struct register_pass_info pass_info =
  2073. {
  2074. designated_field_init (pass, &pass_lower_starpu),
  2075. designated_field_init (reference_pass_name, "*build_cgraph_edges"),
  2076. designated_field_init (ref_pass_instance_number, 1),
  2077. designated_field_init (pos_op, PASS_POS_INSERT_AFTER)
  2078. };
  2079. register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP,
  2080. NULL, &pass_info);
  2081. include_dir = getenv ("STARPU_GCC_INCLUDE_DIR");
  2082. int arg;
  2083. for (arg = 0; arg < plugin_info->argc; arg++)
  2084. {
  2085. if (strcmp (plugin_info->argv[arg].key, "include-dir") == 0)
  2086. {
  2087. if (plugin_info->argv[arg].value == NULL)
  2088. error_at (UNKNOWN_LOCATION, "missing directory name for option "
  2089. "%<-fplugin-arg-starpu-include-dir%>");
  2090. else
  2091. /* XXX: We assume that `value' has an infinite lifetime. */
  2092. include_dir = plugin_info->argv[arg].value;
  2093. }
  2094. else if (strcmp (plugin_info->argv[arg].key, "verbose") == 0)
  2095. verbose_output_p = true;
  2096. else
  2097. error_at (UNKNOWN_LOCATION, "invalid StarPU plug-in argument %qs",
  2098. plugin_info->argv[arg].key);
  2099. }
  2100. return 0;
  2101. }
  2102. #ifdef __cplusplus
  2103. }
  2104. #endif