starpu.c 70 KB

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