starpu.c 95 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528
  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. #include <sys/mman.h>
  46. /* Don't include the dreaded proprietary headers that we don't need anyway.
  47. In particular, this waives the obligation to reproduce their silly
  48. disclaimer. */
  49. #define STARPU_DONT_INCLUDE_CUDA_HEADERS
  50. /* GCC 4.7 requires compilation with `g++', and C++ lacks a number of GNU C
  51. features, so work around that. */
  52. #ifdef __cplusplus
  53. /* G++ doesn't implement nested functions, so use C++11 lambdas instead. */
  54. # include <functional>
  55. # define local_define(ret, name, parms) auto name = [=]parms
  56. # define function_parm(ret, name, parms) std::function<ret parms> name
  57. /* G++ lacks designated initializers. */
  58. # define designated_field_init(name, value) value /* XXX: cross fingers */
  59. #else /* !__cplusplus */
  60. /* GNU C nested functions. */
  61. # define local_define(ret, name, parms) ret name parms
  62. # define function_parm(ret, name, parms) ret (*name) parms
  63. /* Designated field initializer. */
  64. # define designated_field_init(name, value) .name = value
  65. #endif /* !__cplusplus */
  66. /* C expression parser, possibly with C++ linkage. */
  67. extern int yyparse (location_t, const char *, tree *);
  68. extern int yydebug;
  69. /* This declaration is from `c-tree.h', but that header doesn't get
  70. installed. */
  71. extern tree xref_tag (enum tree_code, tree);
  72. #ifndef STRINGIFY
  73. # define STRINGIFY_(x) # x
  74. # define STRINGIFY(x) STRINGIFY_ (x)
  75. #endif
  76. #ifdef __cplusplus
  77. extern "C" {
  78. #endif
  79. /* Declared with `C' linkage in <gcc-plugin.h>. */
  80. int plugin_is_GPL_compatible;
  81. /* The name of this plug-in. */
  82. static const char plugin_name[] = "starpu";
  83. /* Whether to enable verbose output. */
  84. static bool verbose_output_p = false;
  85. /* Search path for OpenCL source files for the `opencl' pragma, as a
  86. `TREE_LIST'. */
  87. static tree opencl_include_dirs = NULL_TREE;
  88. /* Names of public attributes. */
  89. static const char task_attribute_name[] = "task";
  90. static const char task_implementation_attribute_name[] = "task_implementation";
  91. static const char output_attribute_name[] = "output";
  92. static const char heap_allocated_attribute_name[] = "heap_allocated";
  93. static const char registered_attribute_name[] = "registered";
  94. /* Names of attributes used internally. */
  95. static const char task_codelet_attribute_name[] = ".codelet";
  96. static const char task_implementation_list_attribute_name[] =
  97. ".task_implementation_list";
  98. static const char task_implementation_wrapper_attribute_name[] =
  99. ".task_implementation_wrapper";
  100. static const char heap_allocated_orig_type_attribute_name[] =
  101. ".heap_allocated_original_type";
  102. /* Names of data structures defined in <starpu.h>. */
  103. static const char codelet_struct_tag[] = "starpu_codelet";
  104. static const char opencl_program_struct_tag[] = "starpu_opencl_program";
  105. /* Cached function declarations. */
  106. static tree unpack_fn, data_lookup_fn;
  107. /* Targets supported by GCC-StarPU. */
  108. static int supported_targets = 0
  109. #ifdef STARPU_USE_CPU
  110. | STARPU_CPU
  111. #endif
  112. #ifdef STARPU_USE_CUDA
  113. | STARPU_CUDA
  114. #endif
  115. #ifdef STARPU_USE_OPENCL
  116. | STARPU_OPENCL
  117. #endif
  118. #ifdef STARPU_USE_GORDON
  119. | STARPU_GORDON
  120. #endif
  121. ;
  122. /* Forward declarations. */
  123. static tree build_function_arguments (tree fn);
  124. static tree build_codelet_declaration (tree task_decl);
  125. static tree build_cpu_codelet_identifier (const_tree task);
  126. static void define_task (tree task_decl);
  127. static tree build_pointer_lookup (tree pointer);
  128. static tree type_decl_for_struct_tag (const char *tag);
  129. static bool task_p (const_tree decl);
  130. static bool task_implementation_p (const_tree decl);
  131. static tree task_implementation_task (const_tree task_impl);
  132. static int task_implementation_where (const_tree task_impl);
  133. static bool implicit_cpu_task_implementation_p (const_tree fn);
  134. static int task_implementation_target_to_int (const_tree target);
  135. static bool heap_allocated_p (const_tree var_decl);
  136. static bool registered_p (const_tree var_decl);
  137. static tree declare_codelet (tree task_decl);
  138. /* Lookup the StarPU function NAME in the global scope and store the result
  139. in VAR (this can't be done from `lower_starpu'.) */
  140. #define LOOKUP_STARPU_FUNCTION(var, name) \
  141. if ((var) == NULL_TREE) \
  142. { \
  143. (var) = lookup_name (get_identifier (name)); \
  144. gcc_assert ((var) != NULL_TREE && TREE_CODE (var) == FUNCTION_DECL); \
  145. }
  146. /* Compile-time assertions. */
  147. #if STARPU_GNUC_PREREQ (4, 6)
  148. # define verify(cond, msg) _Static_assert ((cond), msg)
  149. #else
  150. # define verify(cond, msg) assert (cond);
  151. #endif
  152. /* Useful code backported from GCC 4.6. */
  153. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_ARRAY
  154. static tree
  155. build_call_expr_loc_array (location_t loc, tree fndecl, int n, tree *argarray)
  156. {
  157. tree fntype = TREE_TYPE (fndecl);
  158. tree fn = build1 (ADDR_EXPR, build_pointer_type (fntype), fndecl);
  159. return fold_builtin_call_array (loc, TREE_TYPE (fntype), fn, n, argarray);
  160. }
  161. #endif
  162. #if !HAVE_DECL_BUILD_CALL_EXPR_LOC_VEC
  163. static tree
  164. build_call_expr_loc_vec (location_t loc, tree fndecl, VEC(tree,gc) *vec)
  165. {
  166. return build_call_expr_loc_array (loc, fndecl, VEC_length (tree, vec),
  167. VEC_address (tree, vec));
  168. }
  169. #endif
  170. #if !HAVE_DECL_BUILD_ZERO_CST
  171. static tree
  172. build_zero_cst (tree type)
  173. {
  174. switch (TREE_CODE (type))
  175. {
  176. case INTEGER_TYPE: case ENUMERAL_TYPE: case BOOLEAN_TYPE:
  177. case POINTER_TYPE: case REFERENCE_TYPE:
  178. case OFFSET_TYPE:
  179. return build_int_cst (type, 0);
  180. default:
  181. abort ();
  182. }
  183. }
  184. #endif
  185. #ifndef VEC_qsort
  186. /* This macro is missing in GCC 4.5. */
  187. # define VEC_qsort(T,V,CMP) qsort(VEC_address (T,V), VEC_length(T,V), \
  188. sizeof (T), CMP)
  189. #endif
  190. #if !HAVE_DECL_BUILTIN_DECL_EXPLICIT
  191. /* This function was introduced in GCC 4.7 as a replacement for the
  192. `built_in_decls' array. */
  193. static inline tree
  194. builtin_decl_explicit (enum built_in_function fncode)
  195. {
  196. return built_in_decls[fncode];
  197. }
  198. #endif
  199. /* Helpers. */
  200. /* Return POINTER plus OFFSET, where OFFSET is in bytes. */
  201. static tree
  202. pointer_plus (tree pointer, size_t offset)
  203. {
  204. gcc_assert (POINTER_TYPE_P (TREE_TYPE (pointer)));
  205. if (offset == 0)
  206. return pointer;
  207. else
  208. return build_binary_op (UNKNOWN_LOCATION, PLUS_EXPR,
  209. pointer,
  210. build_int_cstu (integer_type_node, offset),
  211. false);
  212. }
  213. /* Build a reference to the INDEXth element of ARRAY. `build_array_ref' is
  214. not exported, so we roll our own.
  215. FIXME: This version may not work for array types and doesn't do as much
  216. type-checking as `build_array_ref'. */
  217. static tree
  218. array_ref (tree array, size_t index)
  219. {
  220. gcc_assert (POINTER_TYPE_P (TREE_TYPE (array)));
  221. return build_indirect_ref (UNKNOWN_LOCATION,
  222. pointer_plus (array, index),
  223. RO_ARRAY_INDEXING);
  224. }
  225. /* Return the number of elements of ARRAY_TYPE, or NULL_TREE if ARRAY_TYPE is
  226. an incomplete type. */
  227. static tree
  228. array_type_element_count (location_t loc, const_tree array_type)
  229. {
  230. gcc_assert (TREE_CODE (array_type) == ARRAY_TYPE);
  231. tree count, domain = TYPE_DOMAIN (array_type);
  232. if (domain != NULL_TREE)
  233. {
  234. count = build_binary_op (loc, MINUS_EXPR,
  235. TYPE_MAX_VALUE (domain),
  236. TYPE_MIN_VALUE (domain),
  237. false);
  238. count = build_binary_op (loc, PLUS_EXPR,
  239. count,
  240. build_int_cstu (integer_type_node, 1),
  241. false);
  242. count = fold_convert (size_type_node, count);
  243. }
  244. else
  245. count = NULL_TREE;
  246. return count;
  247. }
  248. /* Like `build_constructor_from_list', but sort VALS according to their
  249. offset in struct TYPE. Inspired by `gnat_build_constructor'. */
  250. static tree
  251. build_constructor_from_unsorted_list (tree type, tree vals)
  252. {
  253. local_define (int, compare_elmt_bitpos, (const void *rt1, const void *rt2))
  254. {
  255. const constructor_elt *elmt1 = (constructor_elt *) rt1;
  256. const constructor_elt *elmt2 = (constructor_elt *) rt2;
  257. const_tree field1 = elmt1->index;
  258. const_tree field2 = elmt2->index;
  259. int ret
  260. = tree_int_cst_compare (bit_position (field1), bit_position (field2));
  261. return ret ? ret : (int) (DECL_UID (field1) - DECL_UID (field2));
  262. };
  263. tree t;
  264. VEC(constructor_elt,gc) *v = NULL;
  265. if (vals)
  266. {
  267. v = VEC_alloc (constructor_elt, gc, list_length (vals));
  268. for (t = vals; t; t = TREE_CHAIN (t))
  269. CONSTRUCTOR_APPEND_ELT (v, TREE_PURPOSE (t), TREE_VALUE (t));
  270. }
  271. /* Sort field initializers by field offset. */
  272. VEC_qsort (constructor_elt, v, compare_elmt_bitpos);
  273. return build_constructor (type, v);
  274. }
  275. /* Return true if LST holds the void type. */
  276. bool
  277. void_type_p (const_tree lst)
  278. {
  279. gcc_assert (TREE_CODE (lst) == TREE_LIST);
  280. return VOID_TYPE_P (TREE_VALUE (lst));
  281. }
  282. /* Return true if LST holds a pointer type. */
  283. bool
  284. pointer_type_p (const_tree lst)
  285. {
  286. gcc_assert (TREE_CODE (lst) == TREE_LIST);
  287. return POINTER_TYPE_P (TREE_VALUE (lst));
  288. }
  289. /* Debugging helpers. */
  290. static tree build_printf (const char *, ...)
  291. __attribute__ ((format (printf, 1, 2)));
  292. static tree
  293. build_printf (const char *fmt, ...)
  294. {
  295. tree call;
  296. char *str;
  297. va_list args;
  298. va_start (args, fmt);
  299. vasprintf (&str, fmt, args);
  300. call = build_call_expr (builtin_decl_explicit (BUILT_IN_PUTS), 1,
  301. build_string_literal (strlen (str) + 1, str));
  302. free (str);
  303. va_end (args);
  304. return call;
  305. }
  306. static tree
  307. build_hello_world (void)
  308. {
  309. return build_printf ("Hello, StarPU!");
  310. }
  311. /* Given ERROR_VAR, an integer variable holding a StarPU error code, return
  312. statements that print out the error message returned by
  313. BUILD_ERROR_MESSAGE (ERROR_VAR) and abort. */
  314. static tree build_error_statements (location_t, tree,
  315. function_parm (tree, f, (tree)),
  316. const char *, ...)
  317. __attribute__ ((format (printf, 4, 5)));
  318. static tree
  319. build_error_statements (location_t loc, tree error_var,
  320. function_parm (tree, build_error_message, (tree)),
  321. const char *fmt, ...)
  322. {
  323. expanded_location xloc = expand_location (loc);
  324. tree print;
  325. char *str, *fmt_long;
  326. va_list args;
  327. va_start (args, fmt);
  328. /* Build a longer format. Since FMT itself contains % escapes, this needs
  329. to be done in two steps. */
  330. vasprintf (&str, fmt, args);
  331. if (error_var != NULL_TREE)
  332. {
  333. /* ERROR_VAR is an error code. */
  334. gcc_assert (TREE_CODE (error_var) == VAR_DECL
  335. && TREE_TYPE (error_var) == integer_type_node);
  336. asprintf (&fmt_long, "%s:%d: error: %s: %%s\n",
  337. xloc.file, xloc.line, str);
  338. print =
  339. build_call_expr (builtin_decl_explicit (BUILT_IN_PRINTF), 2,
  340. build_string_literal (strlen (fmt_long) + 1,
  341. fmt_long),
  342. build_error_message (error_var));
  343. }
  344. else
  345. {
  346. /* No error code provided. */
  347. asprintf (&fmt_long, "%s:%d: error: %s\n",
  348. xloc.file, xloc.line, str);
  349. print =
  350. build_call_expr (builtin_decl_explicit (BUILT_IN_PUTS), 1,
  351. build_string_literal (strlen (fmt_long) + 1,
  352. fmt_long));
  353. }
  354. free (fmt_long);
  355. free (str);
  356. va_end (args);
  357. tree stmts = NULL;
  358. append_to_statement_list (print, &stmts);
  359. append_to_statement_list (build_call_expr
  360. (builtin_decl_explicit (BUILT_IN_ABORT), 0),
  361. &stmts);
  362. return stmts;
  363. }
  364. /* Build an error string for the StarPU return value in ERROR_VAR. */
  365. static tree
  366. build_starpu_error_string (tree error_var)
  367. {
  368. static tree strerror_fn;
  369. LOOKUP_STARPU_FUNCTION (strerror_fn, "strerror");
  370. tree error_code =
  371. build1 (NEGATE_EXPR, TREE_TYPE (error_var), error_var);
  372. return build_call_expr (strerror_fn, 1, error_code);
  373. }
  374. /* List and vector utilities, à la SRFI-1. */
  375. static tree chain_trees (tree t, ...)
  376. __attribute__ ((sentinel));
  377. static tree
  378. chain_trees (tree t, ...)
  379. {
  380. va_list args;
  381. va_start (args, t);
  382. tree next, prev = t;
  383. for (prev = t, next = va_arg (args, tree);
  384. next != NULL_TREE;
  385. prev = next, next = va_arg (args, tree))
  386. TREE_CHAIN (prev) = next;
  387. va_end (args);
  388. return t;
  389. }
  390. static tree
  391. filter (function_parm (bool, pred, (const_tree)), tree t)
  392. {
  393. tree result, lst;
  394. gcc_assert (TREE_CODE (t) == TREE_LIST);
  395. result = NULL_TREE;
  396. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  397. {
  398. if (pred (lst))
  399. result = tree_cons (TREE_PURPOSE (lst), TREE_VALUE (lst),
  400. result);
  401. }
  402. return nreverse (result);
  403. }
  404. static tree
  405. list_remove (function_parm (bool, pred, (const_tree)), tree t)
  406. {
  407. local_define (bool, opposite, (const_tree t))
  408. {
  409. return !pred (t);
  410. };
  411. return filter (opposite, t);
  412. }
  413. /* Map FUNC over chain T. T does not have to be `TREE_LIST'; it can be a
  414. chain of arbitrary tree objects. */
  415. static tree
  416. map (function_parm (tree, func, (const_tree)), tree t)
  417. {
  418. tree result, tail, lst;
  419. result = tail = NULL_TREE;
  420. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  421. {
  422. tree r = func (lst);
  423. if (tail != NULL_TREE)
  424. TREE_CHAIN (tail) = r;
  425. else
  426. result = r;
  427. tail = r;
  428. }
  429. return result;
  430. }
  431. static void
  432. for_each (function_parm (void, func, (tree)), tree t)
  433. {
  434. tree lst;
  435. gcc_assert (TREE_CODE (t) == TREE_LIST);
  436. for (lst = t; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  437. func (TREE_VALUE (lst));
  438. }
  439. static size_t
  440. count (function_parm (bool, pred, (const_tree)), const_tree t)
  441. {
  442. size_t result;
  443. const_tree lst;
  444. for (lst = t, result = 0; lst != NULL_TREE; lst = TREE_CHAIN (lst))
  445. if (pred (lst))
  446. result++;
  447. return result;
  448. }
  449. /* Pragmas. */
  450. #define STARPU_PRAGMA_NAME_SPACE "starpu"
  451. static void
  452. handle_pragma_hello (struct cpp_reader *reader)
  453. {
  454. add_stmt (build_hello_world ());
  455. }
  456. /* Process `#pragma starpu initialize'.
  457. TODO: Parse and initialize some of the fields of `starpu_conf'. */
  458. static void
  459. handle_pragma_initialize (struct cpp_reader *reader)
  460. {
  461. static tree init_fn;
  462. LOOKUP_STARPU_FUNCTION (init_fn, "starpu_init");
  463. location_t loc = cpp_peek_token (reader, 0)->src_loc;
  464. /* Call `starpu_init (NULL)'. */
  465. tree init = build_call_expr (init_fn, 1, build_zero_cst (ptr_type_node));
  466. /* Introduce a local variable to hold the error code. */
  467. tree error_var = build_decl (loc, VAR_DECL,
  468. create_tmp_var_name (".initialize_error"),
  469. integer_type_node);
  470. DECL_CONTEXT (error_var) = current_function_decl;
  471. DECL_ARTIFICIAL (error_var) = true;
  472. tree assignment = build2 (INIT_EXPR, TREE_TYPE (error_var),
  473. error_var, init);
  474. tree cond = build3 (COND_EXPR, void_type_node,
  475. build2 (NE_EXPR, boolean_type_node,
  476. error_var, integer_zero_node),
  477. build_error_statements (loc, error_var,
  478. build_starpu_error_string,
  479. "failed to initialize StarPU"),
  480. NULL_TREE);
  481. tree stmts = NULL_TREE;
  482. append_to_statement_list (assignment, &stmts);
  483. append_to_statement_list (cond, &stmts);
  484. tree bind = build3 (BIND_EXPR, void_type_node, error_var, stmts,
  485. NULL_TREE);
  486. add_stmt (bind);
  487. }
  488. /* Process `#pragma starpu shutdown'. */
  489. static void
  490. handle_pragma_shutdown (struct cpp_reader *reader)
  491. {
  492. static tree shutdown_fn;
  493. LOOKUP_STARPU_FUNCTION (shutdown_fn, "starpu_shutdown");
  494. tree token;
  495. if (pragma_lex (&token) != CPP_EOF)
  496. error_at (cpp_peek_token (reader, 0)->src_loc,
  497. "junk after %<starpu shutdown%> pragma");
  498. else
  499. /* Call `starpu_shutdown ()'. */
  500. add_stmt (build_call_expr (shutdown_fn, 0));
  501. }
  502. static void
  503. handle_pragma_wait (struct cpp_reader *reader)
  504. {
  505. if (task_implementation_p (current_function_decl))
  506. {
  507. location_t loc;
  508. loc = cpp_peek_token (reader, 0)->src_loc;
  509. /* TODO: In the future we could generate a task for the continuation
  510. and have it depend on what's before here. */
  511. error_at (loc, "task implementation is not allowed to wait");
  512. }
  513. else
  514. {
  515. tree fndecl;
  516. fndecl = lookup_name (get_identifier ("starpu_task_wait_for_all"));
  517. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  518. add_stmt (build_call_expr (fndecl, 0));
  519. }
  520. }
  521. /* The minimal C expression parser. */
  522. /* Parse expressions from the CPP reader for PRAGMA, which is located at LOC.
  523. Return a TREE_LIST of C expressions. */
  524. static tree
  525. read_pragma_expressions (const char *pragma, location_t loc)
  526. {
  527. tree expr = NULL_TREE;
  528. if (yyparse (loc, pragma, &expr))
  529. /* Parse error or memory exhaustion. */
  530. expr = NULL_TREE;
  531. return expr;
  532. }
  533. /* Build a `starpu_vector_data_register' call for the COUNT elements pointed
  534. to by POINTER. */
  535. static tree
  536. build_data_register_call (location_t loc, tree pointer, tree count)
  537. {
  538. tree pointer_type = TREE_TYPE (pointer);
  539. gcc_assert ((TREE_CODE (pointer_type) == ARRAY_TYPE
  540. && TYPE_DOMAIN (pointer_type) != NULL_TREE)
  541. || POINTER_TYPE_P (pointer_type));
  542. gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (count)));
  543. static tree register_fn;
  544. LOOKUP_STARPU_FUNCTION (register_fn, "starpu_vector_data_register");
  545. /* Introduce a local variable to hold the handle. */
  546. tree handle_var = build_decl (loc, VAR_DECL, create_tmp_var_name (".handle"),
  547. ptr_type_node);
  548. DECL_CONTEXT (handle_var) = current_function_decl;
  549. DECL_ARTIFICIAL (handle_var) = true;
  550. DECL_INITIAL (handle_var) = NULL_TREE;
  551. /* If PTR is an array, take its address. */
  552. tree actual_pointer =
  553. POINTER_TYPE_P (pointer_type)
  554. ? pointer
  555. : build_addr (pointer, current_function_decl);
  556. /* Build `starpu_vector_data_register (&HANDLE_VAR, 0, POINTER,
  557. COUNT, sizeof *POINTER)' */
  558. tree call =
  559. build_call_expr (register_fn, 5,
  560. build_addr (handle_var, current_function_decl),
  561. build_zero_cst (uintptr_type_node), /* home node */
  562. actual_pointer, count,
  563. size_in_bytes (TREE_TYPE (pointer_type)));
  564. return build3 (BIND_EXPR, void_type_node, handle_var, call,
  565. NULL_TREE);
  566. }
  567. /* Return a `starpu_data_unregister' call for VAR. */
  568. static tree
  569. build_data_unregister_call (location_t loc, tree var)
  570. {
  571. static tree unregister_fn;
  572. LOOKUP_STARPU_FUNCTION (unregister_fn, "starpu_data_unregister");
  573. /* If VAR is an array, take its address. */
  574. tree pointer =
  575. POINTER_TYPE_P (TREE_TYPE (var))
  576. ? var
  577. : build_addr (var, current_function_decl);
  578. /* Call `starpu_data_unregister (starpu_data_lookup (ptr))'. */
  579. return build_call_expr (unregister_fn, 1,
  580. build_pointer_lookup (pointer));
  581. }
  582. /* Process `#pragma starpu register VAR [COUNT]' and emit the corresponding
  583. `starpu_vector_data_register' call. */
  584. static void
  585. handle_pragma_register (struct cpp_reader *reader)
  586. {
  587. tree args, ptr, count_arg;
  588. location_t loc;
  589. loc = cpp_peek_token (reader, 0)->src_loc;
  590. args = read_pragma_expressions ("register", loc);
  591. if (args == NULL_TREE)
  592. /* Parse error, presumably already handled by the parser. */
  593. return;
  594. /* First argument should be a pointer expression. */
  595. ptr = TREE_VALUE (args);
  596. args = TREE_CHAIN (args);
  597. if (ptr == error_mark_node)
  598. return;
  599. tree ptr_type;
  600. if (DECL_P (ptr))
  601. {
  602. tree heap_attr =
  603. lookup_attribute (heap_allocated_orig_type_attribute_name,
  604. DECL_ATTRIBUTES (ptr));
  605. if (heap_attr != NULL_TREE)
  606. /* PTR is `heap_allocated' so use its original array type to
  607. determine its size. */
  608. ptr_type = TREE_VALUE (heap_attr);
  609. else
  610. ptr_type = TREE_TYPE (ptr);
  611. }
  612. else
  613. ptr_type = TREE_TYPE (ptr);
  614. if (ptr_type == NULL_TREE)
  615. {
  616. /* PTR is a type-less thing, such as a STRING_CST. */
  617. error_at (loc, "invalid %<register%> argument");
  618. return;
  619. }
  620. if (!POINTER_TYPE_P (ptr_type)
  621. && TREE_CODE (ptr_type) != ARRAY_TYPE)
  622. {
  623. error_at (loc, "%qE is neither a pointer nor an array", ptr);
  624. return;
  625. }
  626. /* Since we implicitly use sizeof (*PTR), `void *' is not allowed. */
  627. if (VOID_TYPE_P (TREE_TYPE (ptr_type)))
  628. {
  629. error_at (loc, "pointers to %<void%> not allowed "
  630. "in %<register%> pragma");
  631. return;
  632. }
  633. TREE_USED (ptr) = true;
  634. #ifdef DECL_READ_P
  635. if (DECL_P (ptr))
  636. DECL_READ_P (ptr) = true;
  637. #endif
  638. if (TREE_CODE (ptr_type) == ARRAY_TYPE
  639. && !DECL_EXTERNAL (ptr)
  640. && !TREE_STATIC (ptr)
  641. && !(TREE_CODE (ptr) == VAR_DECL && heap_allocated_p (ptr))
  642. && !MAIN_NAME_P (DECL_NAME (current_function_decl)))
  643. warning_at (loc, 0, "using an on-stack array as a task input "
  644. "considered unsafe");
  645. /* Determine the number of elements in the vector. */
  646. tree count = NULL_TREE;
  647. if (TREE_CODE (ptr_type) == ARRAY_TYPE)
  648. count = array_type_element_count (loc, ptr_type);
  649. /* Second argument is optional but should be an integer. */
  650. count_arg = (args == NULL_TREE) ? NULL_TREE : TREE_VALUE (args);
  651. if (args != NULL_TREE)
  652. args = TREE_CHAIN (args);
  653. if (count_arg == NULL_TREE)
  654. {
  655. /* End of line reached: check whether the array size was
  656. determined. */
  657. if (count == NULL_TREE)
  658. {
  659. error_at (loc, "cannot determine size of array %qE", ptr);
  660. return;
  661. }
  662. }
  663. else if (count_arg == error_mark_node)
  664. /* COUNT_ARG could not be parsed and an error was already reported. */
  665. return;
  666. else if (!INTEGRAL_TYPE_P (TREE_TYPE (count_arg)))
  667. {
  668. error_at (loc, "%qE is not an integer", count_arg);
  669. return;
  670. }
  671. else
  672. {
  673. TREE_USED (count_arg) = true;
  674. #ifdef DECL_READ_P
  675. if (DECL_P (count_arg))
  676. DECL_READ_P (count_arg) = true;
  677. #endif
  678. if (count != NULL_TREE)
  679. {
  680. /* The number of elements of this array was already determined. */
  681. inform (loc,
  682. "element count can be omitted for bounded array %qE",
  683. ptr);
  684. if (count_arg != NULL_TREE)
  685. {
  686. if (TREE_CODE (count_arg) == INTEGER_CST)
  687. {
  688. if (!tree_int_cst_equal (count, count_arg))
  689. error_at (loc, "specified element count differs "
  690. "from actual size of array %qE",
  691. ptr);
  692. }
  693. else
  694. /* Using a variable to determine the array size whereas the
  695. array size is actually known statically. This looks like
  696. unreasonable code, so error out. */
  697. error_at (loc, "determining array size at run-time "
  698. "although array size is known at compile-time");
  699. }
  700. }
  701. else
  702. count = count_arg;
  703. }
  704. /* Any remaining args? */
  705. if (args != NULL_TREE)
  706. error_at (loc, "junk after %<starpu register%> pragma");
  707. /* Add a data register call. */
  708. add_stmt (build_data_register_call (loc, ptr, count));
  709. }
  710. /* Process `#pragma starpu acquire VAR' and emit the corresponding
  711. `starpu_data_acquire' call. */
  712. static void
  713. handle_pragma_acquire (struct cpp_reader *reader)
  714. {
  715. static tree acquire_fn;
  716. LOOKUP_STARPU_FUNCTION (acquire_fn, "starpu_data_acquire");
  717. tree args, var;
  718. location_t loc;
  719. loc = cpp_peek_token (reader, 0)->src_loc;
  720. args = read_pragma_expressions ("acquire", loc);
  721. if (args == NULL_TREE)
  722. return;
  723. var = TREE_VALUE (args);
  724. if (var == error_mark_node)
  725. return;
  726. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  727. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  728. {
  729. error_at (loc, "%qE is neither a pointer nor an array", var);
  730. return;
  731. }
  732. else if (TREE_CHAIN (args) != NULL_TREE)
  733. error_at (loc, "junk after %<starpu acquire%> pragma");
  734. /* If VAR is an array, take its address. */
  735. tree pointer =
  736. POINTER_TYPE_P (TREE_TYPE (var))
  737. ? var
  738. : build_addr (var, current_function_decl);
  739. /* Call `starpu_data_acquire (starpu_data_lookup (ptr), STARPU_RW)'.
  740. TODO: Support modes other than RW. */
  741. add_stmt (build_call_expr (acquire_fn, 2,
  742. build_pointer_lookup (pointer),
  743. build_int_cst (integer_type_node, STARPU_RW)));
  744. }
  745. /* Process `#pragma starpu release VAR' and emit the corresponding
  746. `starpu_data_release' call. */
  747. static void
  748. handle_pragma_release (struct cpp_reader *reader)
  749. {
  750. static tree release_fn;
  751. LOOKUP_STARPU_FUNCTION (release_fn, "starpu_data_release");
  752. tree args, var;
  753. location_t loc;
  754. loc = cpp_peek_token (reader, 0)->src_loc;
  755. args = read_pragma_expressions ("release", loc);
  756. if (args == NULL_TREE)
  757. return;
  758. var = TREE_VALUE (args);
  759. if (var == error_mark_node)
  760. return;
  761. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  762. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  763. {
  764. error_at (loc, "%qE is neither a pointer nor an array", var);
  765. return;
  766. }
  767. else if (TREE_CHAIN (args) != NULL_TREE)
  768. error_at (loc, "junk after %<starpu release%> pragma");
  769. /* If VAR is an array, take its address. */
  770. tree pointer =
  771. POINTER_TYPE_P (TREE_TYPE (var))
  772. ? var
  773. : build_addr (var, current_function_decl);
  774. /* Call `starpu_data_release (starpu_data_lookup (ptr))'. */
  775. add_stmt (build_call_expr (release_fn, 1,
  776. build_pointer_lookup (pointer)));
  777. }
  778. /* Process `#pragma starpu unregister VAR' and emit the corresponding
  779. `starpu_data_unregister' call. */
  780. static void
  781. handle_pragma_unregister (struct cpp_reader *reader)
  782. {
  783. tree args, var;
  784. location_t loc;
  785. loc = cpp_peek_token (reader, 0)->src_loc;
  786. args = read_pragma_expressions ("unregister", loc);
  787. if (args == NULL_TREE)
  788. return;
  789. var = TREE_VALUE (args);
  790. if (var == error_mark_node)
  791. return;
  792. else if (TREE_CODE (TREE_TYPE (var)) != POINTER_TYPE
  793. && TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  794. {
  795. error_at (loc, "%qE is neither a pointer nor an array", var);
  796. return;
  797. }
  798. else if (TREE_CHAIN (args) != NULL_TREE)
  799. error_at (loc, "junk after %<starpu unregister%> pragma");
  800. add_stmt (build_data_unregister_call (loc, var));
  801. }
  802. /* Return a private global string literal VAR_DECL, whose contents are the
  803. LEN bytes at CONTENTS. */
  804. static tree
  805. build_string_variable (location_t loc, const char *name_seed,
  806. const char *contents, size_t len)
  807. {
  808. tree decl;
  809. decl = build_decl (loc, VAR_DECL, create_tmp_var_name (name_seed),
  810. string_type_node);
  811. TREE_PUBLIC (decl) = false;
  812. TREE_STATIC (decl) = true;
  813. TREE_USED (decl) = true;
  814. DECL_INITIAL (decl) = /* XXX: off-by-one? */
  815. build_string_literal (len + 1, contents);
  816. DECL_ARTIFICIAL (decl) = true;
  817. return decl;
  818. }
  819. /* Return a VAR_DECL for a string variable containing the contents of FILE,
  820. which is looked for in each of the directories listed in SEARCH_PATH. If
  821. FILE could not be found, return NULL_TREE. */
  822. static tree
  823. build_variable_from_file_contents (location_t loc,
  824. const char *name_seed,
  825. const char *file,
  826. const_tree search_path)
  827. {
  828. gcc_assert (search_path != NULL_TREE
  829. && TREE_CODE (search_path) == TREE_LIST);
  830. int err, dir_fd;
  831. struct stat st;
  832. const_tree dirs;
  833. tree var = NULL_TREE;
  834. /* Look for FILE in each directory in SEARCH_PATH, and pick the first one
  835. that matches. */
  836. for (err = ENOENT, dir_fd = -1, dirs = search_path;
  837. (err != 0 || err == ENOENT) && dirs != NULL_TREE;
  838. dirs = TREE_CHAIN (dirs))
  839. {
  840. gcc_assert (TREE_VALUE (dirs) != NULL_TREE
  841. && TREE_CODE (TREE_VALUE (dirs)) == STRING_CST);
  842. dir_fd = open (TREE_STRING_POINTER (TREE_VALUE (dirs)),
  843. O_DIRECTORY | O_RDONLY);
  844. if (dir_fd < 0)
  845. err = ENOENT;
  846. else
  847. {
  848. err = fstatat (dir_fd, file, &st, 0);
  849. if (err != 0)
  850. close (dir_fd);
  851. else
  852. /* Leave DIRS unchanged so it can be referred to in diagnostics
  853. below. */
  854. break;
  855. }
  856. }
  857. if (err != 0 || dir_fd < 0)
  858. error_at (loc, "failed to access %qs: %m", file);
  859. else if (st.st_size == 0)
  860. {
  861. error_at (loc, "source file %qs is empty", file);
  862. close (dir_fd);
  863. }
  864. else
  865. {
  866. if (verbose_output_p)
  867. inform (loc, "found file %qs in %qs",
  868. file, TREE_STRING_POINTER (TREE_VALUE (dirs)));
  869. int fd;
  870. fd = openat (dir_fd, file, O_RDONLY);
  871. close (dir_fd);
  872. if (fd < 0)
  873. error_at (loc, "failed to open %qs: %m", file);
  874. else
  875. {
  876. void *contents;
  877. contents = mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
  878. if (contents == NULL)
  879. error_at (loc, "failed to map contents of %qs: %m", file);
  880. else
  881. {
  882. var = build_string_variable (loc, name_seed,
  883. (char *) contents, st.st_size);
  884. pushdecl (var);
  885. munmap (contents, st.st_size);
  886. }
  887. close (fd);
  888. }
  889. }
  890. return var;
  891. }
  892. /* Return the type corresponding to OPENCL_PROGRAM_STRUCT_TAG. */
  893. static tree
  894. opencl_program_type (void)
  895. {
  896. tree t = TREE_TYPE (type_decl_for_struct_tag (opencl_program_struct_tag));
  897. if (TYPE_SIZE (t) == NULL_TREE)
  898. {
  899. /* Incomplete type definition, for instance because <starpu_opencl.h>
  900. wasn't included. */
  901. error_at (UNKNOWN_LOCATION, "StarPU OpenCL support is lacking");
  902. t = error_mark_node;
  903. }
  904. return t;
  905. }
  906. static tree
  907. opencl_kernel_type (void)
  908. {
  909. tree t = lookup_name (get_identifier ("cl_kernel"));
  910. gcc_assert (t != NULL_TREE);
  911. if (TREE_CODE (t) == TYPE_DECL)
  912. t = TREE_TYPE (t);
  913. gcc_assert (TYPE_P (t));
  914. return t;
  915. }
  916. static tree
  917. opencl_command_queue_type (void)
  918. {
  919. tree t = lookup_name (get_identifier ("cl_command_queue"));
  920. gcc_assert (t != NULL_TREE);
  921. if (TREE_CODE (t) == TYPE_DECL)
  922. t = TREE_TYPE (t);
  923. gcc_assert (TYPE_P (t));
  924. return t;
  925. }
  926. static tree
  927. opencl_event_type (void)
  928. {
  929. tree t = lookup_name (get_identifier ("cl_event"));
  930. gcc_assert (t != NULL_TREE);
  931. if (TREE_CODE (t) == TYPE_DECL)
  932. t = TREE_TYPE (t);
  933. gcc_assert (TYPE_P (t));
  934. return t;
  935. }
  936. /* Return an expression that, given the OpenCL error code in ERROR_VAR,
  937. returns a string. */
  938. static tree
  939. build_opencl_error_string (tree error_var)
  940. {
  941. static tree clstrerror_fn;
  942. LOOKUP_STARPU_FUNCTION (clstrerror_fn, "starpu_opencl_error_string");
  943. return build_call_expr (clstrerror_fn, 1, error_var);
  944. }
  945. /* Return an error-checking `clSetKernelArg' call for argument ARG, at
  946. index IDX, of KERNEL. */
  947. static tree
  948. build_opencl_set_kernel_arg_call (location_t loc, tree fn,
  949. tree kernel, unsigned int idx,
  950. tree arg)
  951. {
  952. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
  953. && TREE_TYPE (kernel) == opencl_kernel_type ());
  954. static tree setkernarg_fn;
  955. LOOKUP_STARPU_FUNCTION (setkernarg_fn, "clSetKernelArg");
  956. tree call = build_call_expr (setkernarg_fn, 4, kernel,
  957. build_int_cst (integer_type_node, idx),
  958. size_in_bytes (TREE_TYPE (arg)),
  959. build_addr (arg, fn));
  960. tree error_var = build_decl (loc, VAR_DECL,
  961. create_tmp_var_name ("setkernelarg_error"),
  962. integer_type_node);
  963. DECL_ARTIFICIAL (error_var) = true;
  964. DECL_CONTEXT (error_var) = fn;
  965. tree assignment = build2 (INIT_EXPR, TREE_TYPE (error_var),
  966. error_var, call);
  967. /* Build `if (ERROR_VAR != 0) error ();'. */
  968. tree cond;
  969. cond = build3 (COND_EXPR, void_type_node,
  970. build2 (NE_EXPR, boolean_type_node,
  971. error_var, integer_zero_node),
  972. build_error_statements (loc, error_var,
  973. build_opencl_error_string,
  974. "failed to set OpenCL kernel "
  975. "argument %d", idx),
  976. NULL_TREE);
  977. tree stmts = NULL_TREE;
  978. append_to_statement_list (assignment, &stmts);
  979. append_to_statement_list (cond, &stmts);
  980. return build4 (TARGET_EXPR, void_type_node, error_var,
  981. stmts, NULL_TREE, NULL_TREE);
  982. }
  983. /* Return the sequence of `clSetKernelArg' calls for KERNEL. */
  984. static tree
  985. build_opencl_set_kernel_arg_calls (location_t loc, tree task_impl,
  986. tree kernel)
  987. {
  988. gcc_assert (task_implementation_p (task_impl));
  989. size_t n;
  990. tree arg, stmts = NULL_TREE;
  991. for (arg = DECL_ARGUMENTS (task_impl), n = 0;
  992. arg != NULL_TREE;
  993. arg = TREE_CHAIN (arg), n++)
  994. {
  995. tree call = build_opencl_set_kernel_arg_call (loc, task_impl,
  996. kernel, n, arg);
  997. append_to_statement_list (call, &stmts);
  998. }
  999. return stmts;
  1000. }
  1001. /* Define a body for TASK_IMPL that loads OpenCL source from FILE and calls
  1002. KERNEL. */
  1003. static void
  1004. define_opencl_task_implementation (location_t loc, tree task_impl,
  1005. const char *file, const_tree kernel,
  1006. tree groupsize)
  1007. {
  1008. gcc_assert (task_implementation_p (task_impl)
  1009. && task_implementation_where (task_impl) == STARPU_OPENCL);
  1010. gcc_assert (TREE_CODE (kernel) == STRING_CST);
  1011. gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (groupsize)));
  1012. local_define (tree, local_var, (tree type))
  1013. {
  1014. tree var = build_decl (loc, VAR_DECL,
  1015. create_tmp_var_name ("opencl_var"),
  1016. type);
  1017. DECL_ARTIFICIAL (var) = true;
  1018. DECL_CONTEXT (var) = task_impl;
  1019. return var;
  1020. };
  1021. if (!verbose_output_p)
  1022. /* No further warnings for this node. */
  1023. TREE_NO_WARNING (task_impl) = true;
  1024. static tree load_fn, load_kern_fn, enqueue_kern_fn, wid_fn, devid_fn, clfinish_fn,
  1025. collect_stats_fn, release_ev_fn;
  1026. if (load_fn == NULL_TREE)
  1027. {
  1028. load_fn =
  1029. lookup_name (get_identifier ("starpu_opencl_load_opencl_from_string"));
  1030. if (load_fn == NULL_TREE)
  1031. {
  1032. inform (loc, "no OpenCL support, task implementation %qE "
  1033. "not generated", DECL_NAME (task_impl));
  1034. return;
  1035. }
  1036. }
  1037. LOOKUP_STARPU_FUNCTION (load_kern_fn, "starpu_opencl_load_kernel");
  1038. LOOKUP_STARPU_FUNCTION (wid_fn, "starpu_worker_get_id");
  1039. LOOKUP_STARPU_FUNCTION (devid_fn, "starpu_worker_get_devid");
  1040. LOOKUP_STARPU_FUNCTION (enqueue_kern_fn, "clEnqueueNDRangeKernel");
  1041. LOOKUP_STARPU_FUNCTION (clfinish_fn, "clFinish");
  1042. LOOKUP_STARPU_FUNCTION (collect_stats_fn, "starpu_opencl_collect_stats");
  1043. LOOKUP_STARPU_FUNCTION (release_ev_fn, "clReleaseEvent");
  1044. if (verbose_output_p)
  1045. inform (loc, "defining %qE, with OpenCL kernel %qs from file %qs",
  1046. DECL_NAME (task_impl), TREE_STRING_POINTER (kernel), file);
  1047. tree source_var;
  1048. source_var = build_variable_from_file_contents (loc, "opencl_source",
  1049. file, opencl_include_dirs);
  1050. if (source_var != NULL_TREE)
  1051. {
  1052. /* Give TASK_IMPL an actual argument list. */
  1053. DECL_ARGUMENTS (task_impl) = build_function_arguments (task_impl);
  1054. tree prog_var, prog_loaded_var;
  1055. /* Global variable to hold the `starpu_opencl_program' object. */
  1056. prog_var = build_decl (loc, VAR_DECL,
  1057. create_tmp_var_name ("opencl_program"),
  1058. opencl_program_type ());
  1059. TREE_PUBLIC (prog_var) = false;
  1060. TREE_STATIC (prog_var) = true;
  1061. TREE_USED (prog_var) = true;
  1062. DECL_ARTIFICIAL (prog_var) = true;
  1063. pushdecl (prog_var);
  1064. /* Global variable indicating whether the program has already been
  1065. loaded. */
  1066. prog_loaded_var = build_decl (loc, VAR_DECL,
  1067. create_tmp_var_name ("opencl_prog_loaded"),
  1068. boolean_type_node);
  1069. TREE_PUBLIC (prog_loaded_var) = false;
  1070. TREE_STATIC (prog_loaded_var) = true;
  1071. TREE_USED (prog_loaded_var) = true;
  1072. DECL_ARTIFICIAL (prog_loaded_var) = true;
  1073. DECL_INITIAL (prog_loaded_var) = build_zero_cst (boolean_type_node);
  1074. pushdecl (prog_loaded_var);
  1075. /* Build `starpu_opencl_load_opencl_from_string (SOURCE_VAR,
  1076. &PROG_VAR, "")'. */
  1077. tree load = build_call_expr (load_fn, 3, source_var,
  1078. build_addr (prog_var, task_impl),
  1079. build_string_literal (1, ""));
  1080. tree load_stmts = NULL_TREE;
  1081. append_to_statement_list (load, &load_stmts);
  1082. append_to_statement_list (build2 (MODIFY_EXPR, boolean_type_node,
  1083. prog_loaded_var,
  1084. build_int_cst (boolean_type_node, 1)),
  1085. &load_stmts);
  1086. /* Build `if (!PROG_LOADED_VAR) { ...; PROG_LOADED_VAR = true; }'. */
  1087. tree load_cond = build3 (COND_EXPR, void_type_node,
  1088. prog_loaded_var,
  1089. NULL_TREE,
  1090. load_stmts);
  1091. /* Local variables. */
  1092. tree kernel_var, queue_var, event_var, group_size_var, ngroups_var,
  1093. error_var;
  1094. kernel_var = local_var (opencl_kernel_type ());
  1095. queue_var = local_var (opencl_command_queue_type ());
  1096. event_var = local_var (opencl_event_type ());
  1097. group_size_var = local_var (size_type_node);
  1098. ngroups_var = local_var (size_type_node);
  1099. error_var = local_var (integer_type_node);
  1100. /* Build `starpu_opencl_load_kernel (...)'.
  1101. TODO: Check return value. */
  1102. tree devid =
  1103. build_call_expr (devid_fn, 1, build_call_expr (wid_fn, 0));
  1104. tree load_kern = build_call_expr (load_kern_fn, 5,
  1105. build_addr (kernel_var, task_impl),
  1106. build_addr (queue_var, task_impl),
  1107. build_addr (prog_var, task_impl),
  1108. build_string_literal
  1109. (TREE_STRING_LENGTH (kernel) + 1,
  1110. TREE_STRING_POINTER (kernel)),
  1111. devid);
  1112. tree enqueue_kern =
  1113. build_call_expr (enqueue_kern_fn, 9,
  1114. queue_var, kernel_var,
  1115. build_int_cst (integer_type_node, 1),
  1116. null_pointer_node,
  1117. build_addr (group_size_var, task_impl),
  1118. build_addr (ngroups_var, task_impl),
  1119. integer_zero_node,
  1120. null_pointer_node,
  1121. build_addr (event_var, task_impl));
  1122. tree enqueue_err =
  1123. build2 (INIT_EXPR, TREE_TYPE (error_var), error_var, enqueue_kern);
  1124. tree enqueue_cond =
  1125. build3 (COND_EXPR, void_type_node,
  1126. build2 (NE_EXPR, boolean_type_node,
  1127. error_var, integer_zero_node),
  1128. build_error_statements (loc, error_var,
  1129. build_opencl_error_string,
  1130. "failed to enqueue kernel"),
  1131. NULL_TREE);
  1132. tree clfinish =
  1133. build_call_expr (clfinish_fn, 1, queue_var);
  1134. tree collect_stats =
  1135. build_call_expr (collect_stats_fn, 1, event_var);
  1136. tree release_ev =
  1137. build_call_expr (release_ev_fn, 1, event_var);
  1138. tree enqueue_stmts = NULL_TREE;
  1139. append_to_statement_list (enqueue_err, &enqueue_stmts);
  1140. append_to_statement_list (enqueue_cond, &enqueue_stmts);
  1141. /* TODO: Build `clFinish', `clReleaseEvent', & co. */
  1142. /* Put it all together. */
  1143. tree stmts = NULL_TREE;
  1144. append_to_statement_list (load_cond, &stmts);
  1145. append_to_statement_list (load_kern, &stmts);
  1146. append_to_statement_list (build_opencl_set_kernel_arg_calls (loc,
  1147. task_impl,
  1148. kernel_var),
  1149. &stmts);
  1150. /* TODO: Support user-provided values. */
  1151. append_to_statement_list (build2 (INIT_EXPR, TREE_TYPE (group_size_var),
  1152. group_size_var,
  1153. fold_convert (TREE_TYPE (group_size_var),
  1154. groupsize)),
  1155. &stmts);
  1156. append_to_statement_list (build2 (INIT_EXPR, TREE_TYPE (ngroups_var),
  1157. ngroups_var,
  1158. build_int_cst (TREE_TYPE (ngroups_var),
  1159. 1)),
  1160. &stmts);
  1161. append_to_statement_list (build4 (TARGET_EXPR, void_type_node,
  1162. error_var, enqueue_stmts,
  1163. NULL_TREE, NULL_TREE),
  1164. &stmts);
  1165. append_to_statement_list (clfinish, &stmts);
  1166. append_to_statement_list (collect_stats, &stmts);
  1167. append_to_statement_list (release_ev, &stmts);
  1168. /* Bind the local vars. */
  1169. tree vars = chain_trees (kernel_var, queue_var, event_var,
  1170. group_size_var, ngroups_var, NULL_TREE);
  1171. tree bind = build3 (BIND_EXPR, void_type_node, vars, stmts,
  1172. build_block (vars, NULL_TREE, task_impl, NULL_TREE));
  1173. TREE_USED (task_impl) = true;
  1174. TREE_STATIC (task_impl) = true;
  1175. DECL_EXTERNAL (task_impl) = false;
  1176. DECL_ARTIFICIAL (task_impl) = true;
  1177. DECL_SAVED_TREE (task_impl) = bind;
  1178. DECL_INITIAL (task_impl) = BIND_EXPR_BLOCK (bind);
  1179. DECL_RESULT (task_impl) =
  1180. build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  1181. /* Compile TASK_IMPL. */
  1182. rest_of_decl_compilation (task_impl, true, 0);
  1183. allocate_struct_function (task_impl, false);
  1184. cgraph_finalize_function (task_impl, false);
  1185. cgraph_mark_needed_node (cgraph_get_node (task_impl));
  1186. /* Generate a wrapper for TASK_IMPL, and possibly the body of its task.
  1187. This needs to be done explicitly here, because otherwise
  1188. `handle_pre_genericize' would never see TASK_IMPL's task. */
  1189. tree task = task_implementation_task (task_impl);
  1190. if (!TREE_STATIC (task))
  1191. {
  1192. declare_codelet (task);
  1193. define_task (task);
  1194. /* Compile TASK's body. */
  1195. rest_of_decl_compilation (task, true, 0);
  1196. allocate_struct_function (task, false);
  1197. cgraph_finalize_function (task, false);
  1198. cgraph_mark_needed_node (cgraph_get_node (task));
  1199. }
  1200. }
  1201. else
  1202. DECL_SAVED_TREE (task_impl) = error_mark_node;
  1203. return;
  1204. }
  1205. /* Handle the `opencl' pragma, which defines an OpenCL task
  1206. implementation. */
  1207. static void
  1208. handle_pragma_opencl (struct cpp_reader *reader)
  1209. {
  1210. tree args;
  1211. location_t loc;
  1212. loc = cpp_peek_token (reader, 0)->src_loc;
  1213. if (current_function_decl != NULL_TREE)
  1214. {
  1215. error_at (loc, "%<starpu opencl%> pragma can only be used "
  1216. "at the top-level");
  1217. return;
  1218. }
  1219. args = read_pragma_expressions ("opencl", loc);
  1220. if (args == NULL_TREE)
  1221. return;
  1222. /* TODO: Add "number of groups" arguments. */
  1223. if (list_length (args) < 4)
  1224. {
  1225. error_at (loc, "wrong number of arguments for %<starpu opencl%> pragma");
  1226. return;
  1227. }
  1228. if (task_implementation_p (TREE_VALUE (args)))
  1229. {
  1230. tree task_impl = TREE_VALUE (args);
  1231. if (task_implementation_where (task_impl) == STARPU_OPENCL)
  1232. {
  1233. args = TREE_CHAIN (args);
  1234. if (TREE_CODE (TREE_VALUE (args)) == STRING_CST)
  1235. {
  1236. tree file = TREE_VALUE (args);
  1237. args = TREE_CHAIN (args);
  1238. if (TREE_CODE (TREE_VALUE (args)) == STRING_CST)
  1239. {
  1240. tree kernel = TREE_VALUE (args);
  1241. args = TREE_CHAIN (args);
  1242. if (TREE_TYPE (TREE_VALUE (args)) != NULL_TREE &&
  1243. INTEGRAL_TYPE_P (TREE_TYPE (TREE_VALUE (args))))
  1244. {
  1245. tree groupsize = TREE_VALUE (args);
  1246. if (TREE_CHAIN (args) == NULL_TREE)
  1247. define_opencl_task_implementation (loc, task_impl,
  1248. TREE_STRING_POINTER (file),
  1249. kernel, groupsize);
  1250. else
  1251. error_at (loc, "junk after %<starpu opencl%> pragma");
  1252. }
  1253. else
  1254. error_at (loc, "%<groupsize%> argument must be an integral type");
  1255. }
  1256. else
  1257. error_at (loc, "%<kernel%> argument must be a string constant");
  1258. }
  1259. else
  1260. error_at (loc, "%<file%> argument must be a string constant");
  1261. }
  1262. else
  1263. error_at (loc, "%qE is not an OpenCL task implementation",
  1264. DECL_NAME (task_impl));
  1265. }
  1266. else
  1267. error_at (loc, "%qE is not a task implementation", TREE_VALUE (args));
  1268. }
  1269. /* Handle the `debug_tree' pragma (for debugging purposes.) */
  1270. static void
  1271. handle_pragma_debug_tree (struct cpp_reader *reader)
  1272. {
  1273. tree args, obj;
  1274. location_t loc;
  1275. loc = cpp_peek_token (reader, 0)->src_loc;
  1276. args = read_pragma_expressions ("debug_tree", loc);
  1277. if (args == NULL_TREE)
  1278. /* Parse error, presumably already handled by the parser. */
  1279. return;
  1280. obj = TREE_VALUE (args);
  1281. args = TREE_CHAIN (args);
  1282. if (obj == error_mark_node)
  1283. return;
  1284. if (args != NULL_TREE)
  1285. warning_at (loc, 0, "extraneous arguments ignored");
  1286. inform (loc, "debug_tree:");
  1287. debug_tree (obj);
  1288. printf ("\n");
  1289. }
  1290. /* Handle the `#pragma starpu add_target TARGET', which tells GCC-StarPU to
  1291. consider TARGET ("cpu", "opencl", etc.) as supported. This pragma is
  1292. undocumented and only meant to be used for testing purposes. */
  1293. static void
  1294. handle_pragma_add_target (struct cpp_reader *reader)
  1295. {
  1296. tree args, obj;
  1297. location_t loc;
  1298. loc = cpp_peek_token (reader, 0)->src_loc;
  1299. args = read_pragma_expressions ("add_target", loc);
  1300. if (args == NULL_TREE)
  1301. /* Parse error, presumably already handled by the parser. */
  1302. return;
  1303. obj = TREE_VALUE (args);
  1304. args = TREE_CHAIN (args);
  1305. if (obj == error_mark_node)
  1306. return;
  1307. if (args != NULL_TREE)
  1308. warning_at (loc, 0, "extraneous arguments ignored");
  1309. if (TREE_CODE (obj) == STRING_CST)
  1310. {
  1311. int new_target = task_implementation_target_to_int (obj);
  1312. if (obj == 0)
  1313. error_at (loc, "unsupported target %qE", obj);
  1314. else
  1315. supported_targets |= new_target;
  1316. }
  1317. else
  1318. error_at (loc, "expecting string literal");
  1319. }
  1320. static void
  1321. register_pragmas (void *gcc_data, void *user_data)
  1322. {
  1323. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "hello",
  1324. handle_pragma_hello);
  1325. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "debug_tree",
  1326. handle_pragma_debug_tree);
  1327. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "add_target",
  1328. handle_pragma_add_target);
  1329. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "initialize",
  1330. handle_pragma_initialize);
  1331. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "wait",
  1332. handle_pragma_wait);
  1333. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "register",
  1334. handle_pragma_register);
  1335. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "acquire",
  1336. handle_pragma_acquire);
  1337. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "release",
  1338. handle_pragma_release);
  1339. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "unregister",
  1340. handle_pragma_unregister);
  1341. c_register_pragma_with_expansion (STARPU_PRAGMA_NAME_SPACE, "opencl",
  1342. handle_pragma_opencl);
  1343. c_register_pragma (STARPU_PRAGMA_NAME_SPACE, "shutdown",
  1344. handle_pragma_shutdown);
  1345. }
  1346. /* Attributes. */
  1347. /* Turn FN into a task, and push its associated codelet declaration. */
  1348. static void
  1349. taskify_function (tree fn)
  1350. {
  1351. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  1352. /* Add a `task' attribute and an empty `task_implementation_list'
  1353. attribute. */
  1354. DECL_ATTRIBUTES (fn) =
  1355. tree_cons (get_identifier (task_implementation_list_attribute_name),
  1356. NULL_TREE,
  1357. tree_cons (get_identifier (task_attribute_name), NULL_TREE,
  1358. DECL_ATTRIBUTES (fn)));
  1359. /* Push a declaration for the corresponding `struct starpu_codelet' object and
  1360. add it as an attribute of FN. */
  1361. tree cl = build_codelet_declaration (fn);
  1362. DECL_ATTRIBUTES (fn) =
  1363. tree_cons (get_identifier (task_codelet_attribute_name), cl,
  1364. DECL_ATTRIBUTES (fn));
  1365. pushdecl (cl);
  1366. }
  1367. /* Handle the `task' function attribute. */
  1368. static tree
  1369. handle_task_attribute (tree *node, tree name, tree args,
  1370. int flags, bool *no_add_attrs)
  1371. {
  1372. tree fn;
  1373. fn = *node;
  1374. /* Get rid of the `task' attribute by default so that FN isn't further
  1375. processed when it's erroneous. */
  1376. *no_add_attrs = true;
  1377. if (TREE_CODE (fn) != FUNCTION_DECL)
  1378. error_at (DECL_SOURCE_LOCATION (fn),
  1379. "%<task%> attribute only applies to functions");
  1380. else
  1381. {
  1382. if (!VOID_TYPE_P (TREE_TYPE (TREE_TYPE (fn))))
  1383. /* Raise an error but keep going to avoid spitting out too many
  1384. errors at the user's face. */
  1385. error_at (DECL_SOURCE_LOCATION (fn),
  1386. "task return type must be %<void%>");
  1387. if (count (pointer_type_p, TYPE_ARG_TYPES (TREE_TYPE (fn)))
  1388. > STARPU_NMAXBUFS)
  1389. error_at (DECL_SOURCE_LOCATION (fn),
  1390. "maximum number of pointer parameters exceeded");
  1391. /* Turn FN into an actual task. */
  1392. taskify_function (fn);
  1393. }
  1394. /* Lookup & cache function declarations for later reuse. */
  1395. LOOKUP_STARPU_FUNCTION (unpack_fn, "starpu_codelet_unpack_args");
  1396. LOOKUP_STARPU_FUNCTION (data_lookup_fn, "starpu_data_lookup");
  1397. return NULL_TREE;
  1398. }
  1399. /* Diagnose use of C types that are either nonexistent or different in
  1400. OpenCL. */
  1401. static void
  1402. validate_opencl_argument_type (location_t loc, const_tree type)
  1403. {
  1404. /* When TYPE is a pointer type, get to the base element type. */
  1405. for (; POINTER_TYPE_P (type); type = TREE_TYPE (type));
  1406. if (!RECORD_OR_UNION_TYPE_P (type) && !VOID_TYPE_P (type))
  1407. {
  1408. tree decl = TYPE_NAME (type);
  1409. if (DECL_P (decl))
  1410. {
  1411. static const struct { const char *c; const char *cl; }
  1412. type_map[] =
  1413. {
  1414. /* Scalar types defined in OpenCL 1.2. See
  1415. <http://www.khronos.org/files/opencl-1-2-quick-reference-card.pdf>. */
  1416. { "char", "cl_char" },
  1417. { "signed char", "cl_char" },
  1418. { "unsigned char", "cl_uchar" },
  1419. { "uchar", "cl_uchar" },
  1420. { "short int", "cl_short" },
  1421. { "unsigned short", "cl_ushort" },
  1422. { "int", "cl_int" },
  1423. { "unsigned int", "cl_uint" },
  1424. { "uint", "cl_uint" },
  1425. { "long int", "cl_long" },
  1426. { "long unsigned int", "cl_ulong" },
  1427. { "ulong", "cl_ulong" },
  1428. { "float", "cl_float" },
  1429. { "double", "cl_double" },
  1430. { NULL, NULL }
  1431. };
  1432. const char *c_name = IDENTIFIER_POINTER (DECL_NAME (decl));
  1433. const char *cl_name =
  1434. ({
  1435. size_t i;
  1436. for (i = 0; type_map[i].c != NULL; i++)
  1437. {
  1438. if (strcmp (type_map[i].c, c_name) == 0)
  1439. break;
  1440. }
  1441. type_map[i].cl;
  1442. });
  1443. if (cl_name != NULL)
  1444. {
  1445. tree cl_type = lookup_name (get_identifier (cl_name));
  1446. if (cl_type != NULL_TREE)
  1447. {
  1448. if (DECL_P (cl_type))
  1449. cl_type = TREE_TYPE (cl_type);
  1450. if (!lang_hooks.types_compatible_p ((tree) type, cl_type))
  1451. {
  1452. tree st, sclt;
  1453. st = c_common_signed_type ((tree) type);
  1454. sclt = c_common_signed_type (cl_type);
  1455. if (st == sclt)
  1456. warning_at (loc, 0, "C type %qE differs in signedness "
  1457. "from the same-named OpenCL type",
  1458. DECL_NAME (decl));
  1459. else
  1460. /* TYPE should be avoided because the it differs from
  1461. CL_TYPE, and thus cannot be used safely in
  1462. `clSetKernelArg'. */
  1463. warning_at (loc, 0, "C type %qE differs from the "
  1464. "same-named OpenCL type",
  1465. DECL_NAME (decl));
  1466. }
  1467. }
  1468. /* Otherwise we can't conclude. It could be that <CL/cl.h>
  1469. wasn't included in the program, for instance. */
  1470. }
  1471. else
  1472. /* Recommend against use of `size_t', etc. */
  1473. warning_at (loc, 0, "%qE does not correspond to a known "
  1474. "OpenCL type", DECL_NAME (decl));
  1475. }
  1476. }
  1477. }
  1478. /* Add FN to the list of implementations of TASK_DECL. */
  1479. static void
  1480. add_task_implementation (tree task_decl, tree fn, const_tree where)
  1481. {
  1482. location_t loc;
  1483. tree attr, impls;
  1484. attr = lookup_attribute (task_implementation_list_attribute_name,
  1485. DECL_ATTRIBUTES (task_decl));
  1486. gcc_assert (attr != NULL_TREE);
  1487. gcc_assert (TREE_CODE (where) == STRING_CST);
  1488. loc = DECL_SOURCE_LOCATION (fn);
  1489. impls = tree_cons (NULL_TREE, fn, TREE_VALUE (attr));
  1490. TREE_VALUE (attr) = impls;
  1491. TREE_USED (fn) = true;
  1492. /* Check the `where' argument to raise a warning if needed. */
  1493. if (task_implementation_target_to_int (where) == 0)
  1494. warning_at (loc, 0,
  1495. "unsupported target %E; task implementation won't be used",
  1496. where);
  1497. else if (task_implementation_target_to_int (where) == STARPU_OPENCL)
  1498. {
  1499. local_define (void, validate, (tree t))
  1500. {
  1501. validate_opencl_argument_type (loc, t);
  1502. };
  1503. for_each (validate, TYPE_ARG_TYPES (TREE_TYPE (fn)));
  1504. }
  1505. }
  1506. /* Handle the `task_implementation (WHERE, TASK)' attribute. WHERE is a
  1507. string constant ("cpu", "cuda", etc.), and TASK is the identifier of a
  1508. function declared with the `task' attribute. */
  1509. static tree
  1510. handle_task_implementation_attribute (tree *node, tree name, tree args,
  1511. int flags, bool *no_add_attrs)
  1512. {
  1513. location_t loc;
  1514. tree fn, where, task_decl;
  1515. /* FIXME:TODO: To change the order to (TASK, WHERE):
  1516. tree cleanup_id = TREE_VALUE (TREE_VALUE (attr));
  1517. tree cleanup_decl = lookup_name (cleanup_id);
  1518. */
  1519. fn = *node;
  1520. where = TREE_VALUE (args);
  1521. task_decl = TREE_VALUE (TREE_CHAIN (args));
  1522. if (implicit_cpu_task_implementation_p (task_decl))
  1523. /* TASK_DECL is actually a CPU implementation. Implicit CPU task
  1524. implementations can lead to this situation, because the task is
  1525. renamed and modified to become a CPU implementation. */
  1526. task_decl = task_implementation_task (task_decl);
  1527. loc = DECL_SOURCE_LOCATION (fn);
  1528. /* Get rid of the `task_implementation' attribute by default so that FN
  1529. isn't further processed when it's erroneous. */
  1530. *no_add_attrs = true;
  1531. /* Mark FN as used to placate `-Wunused-function' when FN is erroneous
  1532. anyway. */
  1533. TREE_USED (fn) = true;
  1534. if (TREE_CODE (fn) != FUNCTION_DECL)
  1535. error_at (loc,
  1536. "%<task_implementation%> attribute only applies to functions");
  1537. else if (TREE_CODE (where) != STRING_CST)
  1538. error_at (loc, "string constant expected "
  1539. "as the first %<task_implementation%> argument");
  1540. else if (TREE_CODE (task_decl) != FUNCTION_DECL)
  1541. error_at (loc, "%qE is not a function", task_decl);
  1542. else if (lookup_attribute (task_attribute_name,
  1543. DECL_ATTRIBUTES (task_decl)) == NULL_TREE)
  1544. error_at (loc, "function %qE lacks the %<task%> attribute",
  1545. DECL_NAME (task_decl));
  1546. else if (TYPE_CANONICAL (TREE_TYPE (fn))
  1547. != TYPE_CANONICAL (TREE_TYPE (task_decl)))
  1548. error_at (loc, "type differs from that of task %qE",
  1549. DECL_NAME (task_decl));
  1550. else
  1551. {
  1552. /* Add FN to the list of implementations of TASK_DECL. */
  1553. add_task_implementation (task_decl, fn, where);
  1554. /* Keep the attribute. */
  1555. *no_add_attrs = false;
  1556. }
  1557. return NULL_TREE;
  1558. }
  1559. /* Return true when VAR is an automatic variable with complete array type;
  1560. otherwise, return false, and emit error messages mentioning ATTRIBUTE. */
  1561. static bool
  1562. automatic_array_variable_p (const char *attribute, tree var)
  1563. {
  1564. gcc_assert (TREE_CODE (var) == VAR_DECL);
  1565. location_t loc;
  1566. loc = DECL_SOURCE_LOCATION (var);
  1567. if (DECL_EXTERNAL (var))
  1568. error_at (loc, "attribute %qs cannot be used on external declarations",
  1569. attribute);
  1570. else if (TREE_PUBLIC (var) || TREE_STATIC (var))
  1571. {
  1572. error_at (loc, "attribute %qs cannot be used on global variables",
  1573. attribute);
  1574. TREE_TYPE (var) = error_mark_node;
  1575. }
  1576. else if (TREE_CODE (TREE_TYPE (var)) != ARRAY_TYPE)
  1577. {
  1578. error_at (loc, "variable %qE must have an array type",
  1579. DECL_NAME (var));
  1580. TREE_TYPE (var) = error_mark_node;
  1581. }
  1582. else if (TYPE_SIZE (TREE_TYPE (var)) == NULL_TREE)
  1583. {
  1584. error_at (loc, "variable %qE has an incomplete array type",
  1585. DECL_NAME (var));
  1586. TREE_TYPE (var) = error_mark_node;
  1587. }
  1588. else
  1589. return true;
  1590. return false;
  1591. }
  1592. /* Handle the `heap_allocated' attribute on variable *NODE. */
  1593. static tree
  1594. handle_heap_allocated_attribute (tree *node, tree name, tree args,
  1595. int flags, bool *no_add_attrs)
  1596. {
  1597. tree var = *node;
  1598. if (automatic_array_variable_p (heap_allocated_attribute_name, var))
  1599. {
  1600. /* Turn VAR into a pointer that feels like an array. This is what's
  1601. done for PARM_DECLs that have an array type. */
  1602. location_t loc = DECL_SOURCE_LOCATION (var);
  1603. tree array_type = TREE_TYPE (var);
  1604. tree element_type = TREE_TYPE (array_type);
  1605. tree pointer_type = build_pointer_type (element_type);
  1606. /* Keep a copy of VAR's original type. */
  1607. DECL_ATTRIBUTES (var) =
  1608. tree_cons (get_identifier (heap_allocated_orig_type_attribute_name),
  1609. array_type, DECL_ATTRIBUTES (var));
  1610. TREE_TYPE (var) = pointer_type;
  1611. DECL_SIZE (var) = TYPE_SIZE (pointer_type);
  1612. DECL_SIZE_UNIT (var) = TYPE_SIZE_UNIT (pointer_type);
  1613. DECL_ALIGN (var) = TYPE_ALIGN (pointer_type);
  1614. DECL_USER_ALIGN (var) = false;
  1615. DECL_MODE (var) = TYPE_MODE (pointer_type);
  1616. tree malloc_fn = lookup_name (get_identifier ("starpu_malloc"));
  1617. gcc_assert (malloc_fn != NULL_TREE);
  1618. tree alloc = build_call_expr (malloc_fn, 2,
  1619. build_addr (var, current_function_decl),
  1620. TYPE_SIZE_UNIT (array_type));
  1621. TREE_SIDE_EFFECTS (alloc) = true;
  1622. /* Add a destructor for VAR. Instead of consing the `cleanup'
  1623. attribute for VAR, directly use `push_cleanup'. This guarantees
  1624. that CLEANUP_ID is looked up in the right context, and allows us to
  1625. pass VAR directly to `starpu_free', instead of `&VAR'.
  1626. TODO: Provide a way to disable this. */
  1627. static tree cleanup_decl;
  1628. LOOKUP_STARPU_FUNCTION (cleanup_decl, "starpu_free");
  1629. if (registered_p (var))
  1630. {
  1631. /* A `registered' attribute has already been processed, and thus a
  1632. cleanup for it has been pushed. However, we want that cleanup
  1633. to appear before ours, and our allocation to appear before the
  1634. registration, so swap them. */
  1635. tree_stmt_iterator it;
  1636. tree parent, try_finally, registration;
  1637. #ifdef stmt_list_stack
  1638. # ifdef VEC_index /* 4.7 */
  1639. gcc_assert (VEC_length (tree, stmt_list_stack) > 1);
  1640. parent = VEC_index (tree, stmt_list_stack,
  1641. VEC_length (tree, stmt_list_stack) - 2);
  1642. # else
  1643. # error not ported to 4.8!
  1644. # endif
  1645. #else /* 4.6 and before */
  1646. parent = TREE_CHAIN (cur_stmt_list);
  1647. #endif
  1648. gcc_assert (parent != NULL_TREE
  1649. && TREE_CODE (parent) == STATEMENT_LIST);
  1650. it = tsi_last (parent);
  1651. try_finally = tsi_stmt (it);
  1652. gcc_assert (TREE_CODE (try_finally) == TRY_FINALLY_EXPR);
  1653. tsi_prev (&it);
  1654. registration =
  1655. build_data_register_call (loc, var,
  1656. array_type_element_count
  1657. (loc, array_type));
  1658. add_stmt (registration);
  1659. *tsi_stmt_ptr (it) = alloc;
  1660. push_cleanup (var, build_data_unregister_call (loc, var), false);
  1661. TREE_OPERAND (try_finally, 1) = build_call_expr (cleanup_decl, 1, var);
  1662. }
  1663. else
  1664. {
  1665. /* Push the allocation and cleanup in order. */
  1666. add_stmt (alloc);
  1667. push_cleanup (var, build_call_expr (cleanup_decl, 1, var), false);
  1668. }
  1669. /* Keep the attribute. */
  1670. *no_add_attrs = false;
  1671. }
  1672. return NULL_TREE;
  1673. }
  1674. /* Handle the `registered' attribute on variable *NODE. */
  1675. static tree
  1676. handle_registered_attribute (tree *node, tree name, tree args,
  1677. int flags, bool *no_add_attrs)
  1678. {
  1679. location_t loc;
  1680. tree var = *node;
  1681. loc = DECL_SOURCE_LOCATION (var);
  1682. bool heap_p = heap_allocated_p (var);
  1683. /* When VAR has the `heap_allocated' attribute, we know it has a complete
  1684. array type. */
  1685. if (heap_p
  1686. || automatic_array_variable_p (registered_attribute_name, var))
  1687. {
  1688. /* FIXME: This warning cannot be emitted here, because the
  1689. `heap_allocated' attribute may be processed later. */
  1690. /* if (!heap_p */
  1691. /* && !MAIN_NAME_P (DECL_NAME (current_function_decl))) */
  1692. /* warning_at (loc, 0, "using an on-stack array as a task input " */
  1693. /* "considered unsafe"); */
  1694. tree ptr_type, heap_attr =
  1695. lookup_attribute (heap_allocated_orig_type_attribute_name,
  1696. DECL_ATTRIBUTES (var));
  1697. if (heap_attr != NULL_TREE)
  1698. /* PTR is `heap_allocated' so use its original array type to
  1699. determine its size. */
  1700. ptr_type = TREE_VALUE (heap_attr);
  1701. else
  1702. ptr_type = TREE_TYPE (var);
  1703. tree count = array_type_element_count (loc, ptr_type);
  1704. add_stmt (build_data_register_call (loc, var, count));
  1705. push_cleanup (var,
  1706. build_data_unregister_call (DECL_SOURCE_LOCATION (var),
  1707. var),
  1708. false);
  1709. }
  1710. return NULL_TREE;
  1711. }
  1712. /* Handle the `output' attribute on type *NODE, which should be the type of a
  1713. PARM_DECL of a task or task implementation. */
  1714. static tree
  1715. handle_output_attribute (tree *node, tree name, tree args,
  1716. int flags, bool *no_add_attrs)
  1717. {
  1718. tree type = *node;
  1719. gcc_assert (TYPE_P (type));
  1720. if (!POINTER_TYPE_P (type) && TREE_CODE (type) != ARRAY_TYPE)
  1721. error ("%<output%> attribute not allowed for non-pointer types");
  1722. else
  1723. /* Keep the attribute. */
  1724. *no_add_attrs = false;
  1725. return NULL_TREE;
  1726. }
  1727. /* Return the declaration of the `struct starpu_codelet' variable associated with
  1728. TASK_DECL. */
  1729. static tree
  1730. task_codelet_declaration (const_tree task_decl)
  1731. {
  1732. tree cl_attr;
  1733. cl_attr = lookup_attribute (task_codelet_attribute_name,
  1734. DECL_ATTRIBUTES (task_decl));
  1735. gcc_assert (cl_attr != NULL_TREE);
  1736. return TREE_VALUE (cl_attr);
  1737. }
  1738. /* Return true if DECL is a task. */
  1739. static bool
  1740. task_p (const_tree decl)
  1741. {
  1742. return (TREE_CODE (decl) == FUNCTION_DECL &&
  1743. lookup_attribute (task_attribute_name,
  1744. DECL_ATTRIBUTES (decl)) != NULL_TREE);
  1745. }
  1746. /* Return true if DECL is a task implementation. */
  1747. static bool
  1748. task_implementation_p (const_tree decl)
  1749. {
  1750. return (TREE_CODE (decl) == FUNCTION_DECL &&
  1751. lookup_attribute (task_implementation_attribute_name,
  1752. DECL_ATTRIBUTES (decl)) != NULL_TREE);
  1753. }
  1754. /* Return the list of implementations of TASK_DECL. */
  1755. static tree
  1756. task_implementation_list (const_tree task_decl)
  1757. {
  1758. tree attr;
  1759. attr = lookup_attribute (task_implementation_list_attribute_name,
  1760. DECL_ATTRIBUTES (task_decl));
  1761. return TREE_VALUE (attr);
  1762. }
  1763. /* Return the list of pointer parameter types of TASK_DECL. */
  1764. static tree
  1765. task_pointer_parameter_types (const_tree task_decl)
  1766. {
  1767. return filter (pointer_type_p, TYPE_ARG_TYPES (TREE_TYPE (task_decl)));
  1768. }
  1769. /* Return the StarPU integer constant corresponding to string TARGET. */
  1770. static int
  1771. task_implementation_target_to_int (const_tree target)
  1772. {
  1773. gcc_assert (TREE_CODE (target) == STRING_CST);
  1774. int where_int;
  1775. if (!strncmp (TREE_STRING_POINTER (target), "cpu",
  1776. TREE_STRING_LENGTH (target)))
  1777. where_int = STARPU_CPU;
  1778. else if (!strncmp (TREE_STRING_POINTER (target), "opencl",
  1779. TREE_STRING_LENGTH (target)))
  1780. where_int = STARPU_OPENCL;
  1781. else if (!strncmp (TREE_STRING_POINTER (target), "cuda",
  1782. TREE_STRING_LENGTH (target)))
  1783. where_int = STARPU_CUDA;
  1784. else if (!strncmp (TREE_STRING_POINTER (target), "gordon",
  1785. TREE_STRING_LENGTH (target)))
  1786. where_int = STARPU_GORDON;
  1787. else
  1788. where_int = 0;
  1789. return where_int;
  1790. }
  1791. /* Return a value indicating where TASK_IMPL should execute (`STARPU_CPU',
  1792. `STARPU_CUDA', etc.). */
  1793. static int
  1794. task_implementation_where (const_tree task_impl)
  1795. {
  1796. tree impl_attr, args, where;
  1797. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  1798. impl_attr = lookup_attribute (task_implementation_attribute_name,
  1799. DECL_ATTRIBUTES (task_impl));
  1800. gcc_assert (impl_attr != NULL_TREE);
  1801. args = TREE_VALUE (impl_attr);
  1802. where = TREE_VALUE (args);
  1803. return task_implementation_target_to_int (where);
  1804. }
  1805. /* Return a bitwise-or of the supported targets of TASK_DECL. */
  1806. static int
  1807. task_where (const_tree task_decl)
  1808. {
  1809. gcc_assert (task_p (task_decl));
  1810. int where;
  1811. const_tree impl;
  1812. for (impl = task_implementation_list (task_decl), where = 0;
  1813. impl != NULL_TREE;
  1814. impl = TREE_CHAIN (impl))
  1815. where |= task_implementation_where (TREE_VALUE (impl));
  1816. return where;
  1817. }
  1818. /* Return the task implemented by TASK_IMPL. */
  1819. static tree
  1820. task_implementation_task (const_tree task_impl)
  1821. {
  1822. tree impl_attr, args, task;
  1823. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  1824. impl_attr = lookup_attribute (task_implementation_attribute_name,
  1825. DECL_ATTRIBUTES (task_impl));
  1826. gcc_assert (impl_attr != NULL_TREE);
  1827. args = TREE_VALUE (impl_attr);
  1828. task = TREE_VALUE (TREE_CHAIN (args));
  1829. if (task_implementation_p (task))
  1830. /* TASK is an implicit CPU task implementation, so return its real
  1831. task. */
  1832. return task_implementation_task (task);
  1833. return task;
  1834. }
  1835. /* Return the FUNCTION_DECL of the wrapper generated for TASK_IMPL. */
  1836. static tree
  1837. task_implementation_wrapper (const_tree task_impl)
  1838. {
  1839. tree attr;
  1840. gcc_assert (TREE_CODE (task_impl) == FUNCTION_DECL);
  1841. attr = lookup_attribute (task_implementation_wrapper_attribute_name,
  1842. DECL_ATTRIBUTES (task_impl));
  1843. gcc_assert (attr != NULL_TREE);
  1844. return TREE_VALUE (attr);
  1845. }
  1846. /* Return true when FN is an implicit CPU task implementation. */
  1847. static bool
  1848. implicit_cpu_task_implementation_p (const_tree fn)
  1849. {
  1850. if (task_implementation_p (fn)
  1851. && task_implementation_where (fn) == STARPU_CPU)
  1852. {
  1853. /* XXX: Hackish heuristic. */
  1854. const_tree cpu_id;
  1855. cpu_id = build_cpu_codelet_identifier (task_implementation_task (fn));
  1856. return cpu_id == DECL_NAME (fn);
  1857. }
  1858. return false;
  1859. }
  1860. /* Return true when VAR_DECL has the `heap_allocated' attribute. */
  1861. static bool
  1862. heap_allocated_p (const_tree var_decl)
  1863. {
  1864. gcc_assert (TREE_CODE (var_decl) == VAR_DECL);
  1865. return lookup_attribute (heap_allocated_attribute_name,
  1866. DECL_ATTRIBUTES (var_decl)) != NULL_TREE;
  1867. }
  1868. /* Return true when VAR_DECL has the `registered' attribute. */
  1869. static bool
  1870. registered_p (const_tree var_decl)
  1871. {
  1872. gcc_assert (TREE_CODE (var_decl) == VAR_DECL);
  1873. return lookup_attribute (registered_attribute_name,
  1874. DECL_ATTRIBUTES (var_decl)) != NULL_TREE;
  1875. }
  1876. /* Return true if TYPE is `output'-qualified. */
  1877. static bool
  1878. output_type_p (const_tree type)
  1879. {
  1880. return (lookup_attribute (output_attribute_name,
  1881. TYPE_ATTRIBUTES (type)) != NULL_TREE);
  1882. }
  1883. /* Return the access mode for POINTER, a PARM_DECL of a task. */
  1884. static enum starpu_access_mode
  1885. access_mode (const_tree type)
  1886. {
  1887. gcc_assert (POINTER_TYPE_P (type));
  1888. /* If TYPE points to a const-qualified type, then mark the data as
  1889. read-only; if is has the `output' attribute, then mark it as write-only;
  1890. otherwise default to read-write. */
  1891. return ((TYPE_QUALS (TREE_TYPE (type)) & TYPE_QUAL_CONST)
  1892. ? STARPU_R
  1893. : (output_type_p (type) ? STARPU_W : STARPU_RW));
  1894. }
  1895. static void
  1896. register_task_attributes (void *gcc_data, void *user_data)
  1897. {
  1898. static const struct attribute_spec task_attr =
  1899. {
  1900. task_attribute_name, 0, 0, true, false, false,
  1901. handle_task_attribute
  1902. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1903. , false
  1904. #endif
  1905. };
  1906. static const struct attribute_spec task_implementation_attr =
  1907. {
  1908. task_implementation_attribute_name, 2, 2, true, false, false,
  1909. handle_task_implementation_attribute
  1910. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1911. , false
  1912. #endif
  1913. };
  1914. static const struct attribute_spec heap_allocated_attr =
  1915. {
  1916. heap_allocated_attribute_name, 0, 0, true, false, false,
  1917. handle_heap_allocated_attribute
  1918. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1919. , false
  1920. #endif
  1921. };
  1922. static const struct attribute_spec registered_attr =
  1923. {
  1924. registered_attribute_name, 0, 0, true, false, false,
  1925. handle_registered_attribute
  1926. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1927. , false
  1928. #endif
  1929. };
  1930. static const struct attribute_spec output_attr =
  1931. {
  1932. output_attribute_name, 0, 0, true, true, false,
  1933. handle_output_attribute
  1934. #ifdef HAVE_ATTRIBUTE_SPEC_AFFECTS_TYPE_IDENTITY
  1935. , true /* affects type identity */
  1936. #endif
  1937. };
  1938. register_attribute (&task_attr);
  1939. register_attribute (&task_implementation_attr);
  1940. register_attribute (&heap_allocated_attr);
  1941. register_attribute (&registered_attr);
  1942. register_attribute (&output_attr);
  1943. }
  1944. /* Return the type of a codelet function, i.e.,
  1945. `void (*) (void **, void *)'. */
  1946. static tree
  1947. build_codelet_wrapper_type (void)
  1948. {
  1949. tree void_ptr_ptr;
  1950. void_ptr_ptr = build_pointer_type (ptr_type_node);
  1951. return build_function_type_list (void_type_node,
  1952. void_ptr_ptr, ptr_type_node,
  1953. NULL_TREE);
  1954. }
  1955. /* Return an identifier for the wrapper of TASK_IMPL, a task
  1956. implementation. */
  1957. static tree
  1958. build_codelet_wrapper_identifier (tree task_impl)
  1959. {
  1960. static const char suffix[] = ".task_implementation_wrapper";
  1961. tree id;
  1962. char *cl_name;
  1963. const char *task_name;
  1964. id = DECL_NAME (task_impl);
  1965. task_name = IDENTIFIER_POINTER (id);
  1966. cl_name = (char *) alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  1967. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  1968. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  1969. return get_identifier (cl_name);
  1970. }
  1971. /* Return a function of type `void (*) (void **, void *)' that calls function
  1972. TASK_IMPL, the FUNCTION_DECL of a task implementation whose prototype may
  1973. be arbitrary. */
  1974. static tree
  1975. build_codelet_wrapper_definition (tree task_impl)
  1976. {
  1977. location_t loc;
  1978. tree task_decl, wrapper_name, decl;
  1979. loc = DECL_SOURCE_LOCATION (task_impl);
  1980. task_decl = task_implementation_task (task_impl);
  1981. wrapper_name = build_codelet_wrapper_identifier (task_impl);
  1982. decl = build_decl (loc, FUNCTION_DECL, wrapper_name,
  1983. build_codelet_wrapper_type ());
  1984. local_define (tree, build_local_var, (const_tree type))
  1985. {
  1986. tree var, t;
  1987. const char *seed;
  1988. t = TREE_VALUE (type);
  1989. seed = POINTER_TYPE_P (t) ? "pointer_arg" : "scalar_arg";
  1990. var = build_decl (loc, VAR_DECL, create_tmp_var_name (seed), t);
  1991. DECL_CONTEXT (var) = decl;
  1992. DECL_ARTIFICIAL (var) = true;
  1993. return var;
  1994. };
  1995. /* Return the body of the wrapper, which unpacks `cl_args' and calls the
  1996. user-defined task implementation. */
  1997. local_define (tree, build_body, (tree wrapper_decl, tree vars))
  1998. {
  1999. bool opencl_p;
  2000. tree stmts = NULL, call, v;
  2001. VEC(tree, gc) *args;
  2002. opencl_p = (task_implementation_where (task_impl) == STARPU_OPENCL);
  2003. /* Build `var0 = STARPU_VECTOR_GET_PTR (buffers[0]); ...' or
  2004. `var0 = STARPU_VECTOR_GET_DEV_HANDLE (buffers[0])' for OpenCL. */
  2005. size_t index = 0;
  2006. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  2007. {
  2008. if (POINTER_TYPE_P (TREE_TYPE (v)))
  2009. {
  2010. /* Compute `void *VDESC = buffers[0];'. */
  2011. tree vdesc = array_ref (DECL_ARGUMENTS (wrapper_decl), index);
  2012. /* Use the right field, depending on OPENCL_P. */
  2013. size_t offset =
  2014. opencl_p
  2015. ? offsetof (struct starpu_vector_interface, dev_handle)
  2016. : offsetof (struct starpu_vector_interface, ptr);
  2017. gcc_assert (POINTER_TYPE_P (TREE_TYPE (vdesc)));
  2018. /* Compute `type *PTR = *(type **) VDESC;'. */
  2019. tree ptr =
  2020. build_indirect_ref (UNKNOWN_LOCATION,
  2021. fold_convert (build_pointer_type (TREE_TYPE (v)),
  2022. pointer_plus (vdesc, offset)),
  2023. RO_ARRAY_INDEXING);
  2024. append_to_statement_list (build2 (MODIFY_EXPR, TREE_TYPE (v),
  2025. v, ptr),
  2026. &stmts);
  2027. index++;
  2028. }
  2029. }
  2030. /* Build `starpu_codelet_unpack_args (cl_args, &var1, &var2, ...)'. */
  2031. args = NULL;
  2032. VEC_safe_push (tree, gc, args, TREE_CHAIN (DECL_ARGUMENTS (wrapper_decl)));
  2033. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  2034. {
  2035. if (!POINTER_TYPE_P (TREE_TYPE (v)))
  2036. VEC_safe_push (tree, gc, args, build_addr (v, wrapper_decl));
  2037. }
  2038. if (VEC_length (tree, args) > 1)
  2039. {
  2040. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, unpack_fn, args);
  2041. TREE_SIDE_EFFECTS (call) = 1;
  2042. append_to_statement_list (call, &stmts);
  2043. }
  2044. /* Build `my_task_impl (var1, var2, ...)'. */
  2045. args = NULL;
  2046. for (v = vars; v != NULL_TREE; v = TREE_CHAIN (v))
  2047. VEC_safe_push (tree, gc, args, v);
  2048. call = build_call_expr_loc_vec (UNKNOWN_LOCATION, task_impl, args);
  2049. TREE_SIDE_EFFECTS (call) = 1;
  2050. append_to_statement_list (call, &stmts);
  2051. tree bind;
  2052. bind = build3 (BIND_EXPR, void_type_node, vars, stmts,
  2053. DECL_INITIAL (wrapper_decl));
  2054. TREE_TYPE (bind) = TREE_TYPE (TREE_TYPE (wrapper_decl));
  2055. return bind;
  2056. };
  2057. /* Return the parameter list of the wrapper:
  2058. `(void **BUFFERS, void *CL_ARGS)'. */
  2059. local_define (tree, build_parameters, (tree wrapper_decl))
  2060. {
  2061. tree param1, param2;
  2062. param1 = build_decl (loc, PARM_DECL,
  2063. create_tmp_var_name ("buffers"),
  2064. build_pointer_type (ptr_type_node));
  2065. DECL_ARG_TYPE (param1) = ptr_type_node;
  2066. DECL_CONTEXT (param1) = wrapper_decl;
  2067. TREE_USED (param1) = true;
  2068. param2 = build_decl (loc, PARM_DECL,
  2069. create_tmp_var_name ("cl_args"),
  2070. ptr_type_node);
  2071. DECL_ARG_TYPE (param2) = ptr_type_node;
  2072. DECL_CONTEXT (param2) = wrapper_decl;
  2073. TREE_USED (param2) = true;
  2074. return chainon (param1, param2);
  2075. };
  2076. tree vars, result;
  2077. vars = map (build_local_var,
  2078. list_remove (void_type_p,
  2079. TYPE_ARG_TYPES (TREE_TYPE (task_decl))));
  2080. DECL_CONTEXT (decl) = NULL_TREE;
  2081. DECL_ARGUMENTS (decl) = build_parameters (decl);
  2082. result = build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  2083. DECL_CONTEXT (result) = decl;
  2084. DECL_ARTIFICIAL (result) = true;
  2085. DECL_IGNORED_P (result) = true;
  2086. DECL_RESULT (decl) = result;
  2087. DECL_INITIAL (decl) = build_block (vars, NULL_TREE, decl, NULL_TREE);
  2088. DECL_SAVED_TREE (decl) = build_body (decl, vars);
  2089. TREE_PUBLIC (decl) = TREE_PUBLIC (task_impl);
  2090. TREE_STATIC (decl) = true;
  2091. TREE_USED (decl) = true;
  2092. DECL_ARTIFICIAL (decl) = true;
  2093. DECL_EXTERNAL (decl) = false;
  2094. DECL_UNINLINABLE (decl) = true;
  2095. rest_of_decl_compilation (decl, true, 0);
  2096. struct function *prev_cfun = cfun;
  2097. set_cfun (NULL);
  2098. allocate_struct_function (decl, false);
  2099. cfun->function_end_locus = DECL_SOURCE_LOCATION (task_impl);
  2100. cgraph_finalize_function (decl, false);
  2101. /* Mark DECL as needed so that it doesn't get removed by
  2102. `cgraph_remove_unreachable_nodes' when it's not public. */
  2103. cgraph_mark_needed_node (cgraph_get_node (decl));
  2104. set_cfun (prev_cfun);
  2105. return decl;
  2106. }
  2107. /* Define one wrapper function for each implementation of TASK. TASK should
  2108. be the FUNCTION_DECL of a task. */
  2109. static void
  2110. define_codelet_wrappers (tree task)
  2111. {
  2112. local_define (void, define, (tree task_impl))
  2113. {
  2114. tree wrapper_def;
  2115. wrapper_def = build_codelet_wrapper_definition (task_impl);
  2116. DECL_ATTRIBUTES (task_impl) =
  2117. tree_cons (get_identifier (task_implementation_wrapper_attribute_name),
  2118. wrapper_def,
  2119. DECL_ATTRIBUTES (task_impl));
  2120. };
  2121. for_each (define, task_implementation_list (task));
  2122. }
  2123. /* Return a NODE_IDENTIFIER for the variable holding the `struct starpu_codelet'
  2124. structure associated with TASK_DECL. */
  2125. static tree
  2126. build_codelet_identifier (tree task_decl)
  2127. {
  2128. static const char suffix[] = ".codelet";
  2129. tree id;
  2130. char *cl_name;
  2131. const char *task_name;
  2132. id = DECL_NAME (task_decl);
  2133. task_name = IDENTIFIER_POINTER (id);
  2134. cl_name = (char *) alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  2135. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  2136. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  2137. return get_identifier (cl_name);
  2138. }
  2139. /* Return a TYPE_DECL for the RECORD_TYPE with tag name TAG. */
  2140. static tree
  2141. type_decl_for_struct_tag (const char *tag)
  2142. {
  2143. tree type_decl = xref_tag (RECORD_TYPE, get_identifier (tag));
  2144. gcc_assert (type_decl != NULL_TREE
  2145. && TREE_CODE (type_decl) == RECORD_TYPE);
  2146. /* `build_decl' expects a TYPE_DECL, so give it what it wants. */
  2147. type_decl = TYPE_STUB_DECL (type_decl);
  2148. gcc_assert (type_decl != NULL && TREE_CODE (type_decl) == TYPE_DECL);
  2149. return type_decl;
  2150. }
  2151. static tree
  2152. codelet_type (void)
  2153. {
  2154. /* XXX: Hack to allow the type declaration to be accessible at lower
  2155. time. */
  2156. static tree type_decl = NULL_TREE;
  2157. if (type_decl == NULL_TREE)
  2158. /* Lookup the `struct starpu_codelet' struct type. This should succeed since
  2159. we push <starpu.h> early on. */
  2160. type_decl = type_decl_for_struct_tag (codelet_struct_tag);
  2161. return TREE_TYPE (type_decl);
  2162. }
  2163. /* Return a VAR_DECL that declares a `struct starpu_codelet' structure for
  2164. TASK_DECL. */
  2165. static tree
  2166. build_codelet_declaration (tree task_decl)
  2167. {
  2168. tree name, cl_decl;
  2169. name = build_codelet_identifier (task_decl);
  2170. cl_decl = build_decl (DECL_SOURCE_LOCATION (task_decl),
  2171. VAR_DECL, name,
  2172. /* c_build_qualified_type (type, TYPE_QUAL_CONST) */
  2173. codelet_type ());
  2174. DECL_ARTIFICIAL (cl_decl) = true;
  2175. TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
  2176. TREE_STATIC (cl_decl) = false;
  2177. TREE_USED (cl_decl) = true;
  2178. DECL_EXTERNAL (cl_decl) = true;
  2179. DECL_CONTEXT (cl_decl) = NULL_TREE;
  2180. return cl_decl;
  2181. }
  2182. /* Return a `struct starpu_codelet' initializer for TASK_DECL. */
  2183. static tree
  2184. build_codelet_initializer (tree task_decl)
  2185. {
  2186. tree fields;
  2187. fields = TYPE_FIELDS (codelet_type ());
  2188. gcc_assert (TREE_CODE (fields) == FIELD_DECL);
  2189. local_define (tree, lookup_field, (const char *name))
  2190. {
  2191. tree fdecl, fname;
  2192. fname = get_identifier (name);
  2193. for (fdecl = fields;
  2194. fdecl != NULL_TREE;
  2195. fdecl = TREE_CHAIN (fdecl))
  2196. {
  2197. if (DECL_NAME (fdecl) == fname)
  2198. return fdecl;
  2199. }
  2200. /* Field NAME wasn't found. */
  2201. gcc_assert (false);
  2202. };
  2203. local_define (tree, field_initializer, (const char *name, tree value))
  2204. {
  2205. tree field, init;
  2206. field = lookup_field (name);
  2207. init = make_node (TREE_LIST);
  2208. TREE_PURPOSE (init) = field;
  2209. TREE_CHAIN (init) = NULL_TREE;
  2210. if (TREE_CODE (TREE_TYPE (value)) != ARRAY_TYPE)
  2211. TREE_VALUE (init) = fold_convert (TREE_TYPE (field), value);
  2212. else
  2213. TREE_VALUE (init) = value;
  2214. return init;
  2215. };
  2216. local_define (tree, codelet_name, ())
  2217. {
  2218. const char *name = IDENTIFIER_POINTER (DECL_NAME (task_decl));
  2219. return build_string_literal (strlen (name) + 1, name);
  2220. };
  2221. local_define (tree, where_init, (tree impls))
  2222. {
  2223. tree impl;
  2224. int where_int = 0;
  2225. for (impl = impls;
  2226. impl != NULL_TREE;
  2227. impl = TREE_CHAIN (impl))
  2228. {
  2229. tree impl_decl;
  2230. impl_decl = TREE_VALUE (impl);
  2231. gcc_assert (TREE_CODE (impl_decl) == FUNCTION_DECL);
  2232. if (verbose_output_p)
  2233. /* List the implementations of TASK_DECL. */
  2234. inform (DECL_SOURCE_LOCATION (impl_decl),
  2235. " %qE", DECL_NAME (impl_decl));
  2236. where_int |= task_implementation_where (impl_decl);
  2237. }
  2238. return build_int_cstu (integer_type_node, where_int);
  2239. };
  2240. local_define (tree, implementation_pointers, (tree impls, int where))
  2241. {
  2242. size_t len;
  2243. tree impl, pointers;
  2244. for (impl = impls, pointers = NULL_TREE, len = 0;
  2245. impl != NULL_TREE;
  2246. impl = TREE_CHAIN (impl))
  2247. {
  2248. tree impl_decl;
  2249. impl_decl = TREE_VALUE (impl);
  2250. if (task_implementation_where (impl_decl) == where)
  2251. {
  2252. /* Return a pointer to the wrapper of IMPL_DECL. */
  2253. tree addr = build_addr (task_implementation_wrapper (impl_decl),
  2254. NULL_TREE);
  2255. pointers = tree_cons (size_int (len), addr, pointers);
  2256. len++;
  2257. if (len > STARPU_MAXIMPLEMENTATIONS)
  2258. error_at (DECL_SOURCE_LOCATION (impl_decl),
  2259. "maximum number of per-target task implementations "
  2260. "exceeded");
  2261. }
  2262. }
  2263. /* POINTERS must be null-terminated. */
  2264. pointers = tree_cons (size_int (len), build_zero_cst (ptr_type_node),
  2265. pointers);
  2266. len++;
  2267. /* Return an array initializer. */
  2268. tree index_type = build_index_type (size_int (list_length (pointers)));
  2269. return build_constructor_from_list (build_array_type (ptr_type_node,
  2270. index_type),
  2271. nreverse (pointers));
  2272. };
  2273. local_define (tree, pointer_arg_count, (void))
  2274. {
  2275. size_t len;
  2276. len = list_length (task_pointer_parameter_types (task_decl));
  2277. return build_int_cstu (integer_type_node, len);
  2278. };
  2279. local_define (tree, access_mode_array, (void))
  2280. {
  2281. const_tree type;
  2282. tree modes;
  2283. size_t index;
  2284. for (type = task_pointer_parameter_types (task_decl),
  2285. modes = NULL_TREE, index = 0;
  2286. type != NULL_TREE && index < STARPU_NMAXBUFS;
  2287. type = TREE_CHAIN (type), index++)
  2288. {
  2289. tree value = build_int_cst (integer_type_node,
  2290. access_mode (TREE_VALUE (type)));
  2291. modes = tree_cons (size_int (index), value, modes);
  2292. }
  2293. tree index_type = build_index_type (size_int (list_length (modes)));
  2294. return build_constructor_from_list (build_array_type (integer_type_node,
  2295. index_type),
  2296. nreverse (modes));
  2297. };
  2298. if (verbose_output_p)
  2299. inform (DECL_SOURCE_LOCATION (task_decl),
  2300. "implementations for task %qE:", DECL_NAME (task_decl));
  2301. tree impls, inits;
  2302. impls = task_implementation_list (task_decl);
  2303. inits =
  2304. chain_trees (field_initializer ("name", codelet_name ()),
  2305. field_initializer ("where", where_init (impls)),
  2306. field_initializer ("nbuffers", pointer_arg_count ()),
  2307. field_initializer ("modes", access_mode_array ()),
  2308. field_initializer ("cpu_funcs",
  2309. implementation_pointers (impls,
  2310. STARPU_CPU)),
  2311. field_initializer ("opencl_funcs",
  2312. implementation_pointers (impls,
  2313. STARPU_OPENCL)),
  2314. field_initializer ("cuda_funcs",
  2315. implementation_pointers (impls,
  2316. STARPU_CUDA)),
  2317. NULL_TREE);
  2318. return build_constructor_from_unsorted_list (codelet_type (), inits);
  2319. }
  2320. /* Return the VAR_DECL that defines a `struct starpu_codelet' structure for
  2321. TASK_DECL. The VAR_DECL is assumed to already exists, so it must not be
  2322. pushed again. */
  2323. static tree
  2324. declare_codelet (tree task_decl)
  2325. {
  2326. /* Retrieve the declaration of the `struct starpu_codelet' object. */
  2327. tree cl_decl;
  2328. cl_decl = lookup_name (build_codelet_identifier (task_decl));
  2329. gcc_assert (cl_decl != NULL_TREE && TREE_CODE (cl_decl) == VAR_DECL);
  2330. /* Turn the codelet declaration into a definition. */
  2331. TREE_TYPE (cl_decl) = codelet_type ();
  2332. TREE_PUBLIC (cl_decl) = TREE_PUBLIC (task_decl);
  2333. return cl_decl;
  2334. }
  2335. /* Return the identifier for an automatically-generated CPU codelet of
  2336. TASK. */
  2337. static tree
  2338. build_cpu_codelet_identifier (const_tree task)
  2339. {
  2340. static const char suffix[] = ".cpu_implementation";
  2341. tree id;
  2342. char *cl_name;
  2343. const char *task_name;
  2344. id = DECL_NAME (task);
  2345. task_name = IDENTIFIER_POINTER (id);
  2346. cl_name = (char *) alloca (IDENTIFIER_LENGTH (id) + strlen (suffix) + 1);
  2347. memcpy (cl_name, task_name, IDENTIFIER_LENGTH (id));
  2348. strcpy (&cl_name[IDENTIFIER_LENGTH (id)], suffix);
  2349. return get_identifier (cl_name);
  2350. }
  2351. static void
  2352. handle_pre_genericize (void *gcc_data, void *user_data)
  2353. {
  2354. tree fn = (tree) gcc_data;
  2355. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL);
  2356. if (task_p (fn) && TREE_STATIC (fn))
  2357. {
  2358. /* The user defined a body for task FN, which we interpret as being the
  2359. body of an implicit CPU task implementation for FN. Thus, rename FN
  2360. and turn it into the "cpu" implementation of a task that we create
  2361. under FN's original name (this is easier than moving the body to a
  2362. different function, which would require traversing the body to
  2363. rewrite all references to FN to point to the new function.) Later,
  2364. `lower_starpu' rewrites calls to FN as calls to the newly created
  2365. task. */
  2366. tree task_name = DECL_NAME (fn);
  2367. tree cpu_impl = fn;
  2368. DECL_NAME (cpu_impl) = build_cpu_codelet_identifier (fn);
  2369. if (verbose_output_p)
  2370. inform (DECL_SOURCE_LOCATION (fn),
  2371. "implicit CPU implementation renamed from %qE to %qE",
  2372. task_name, DECL_NAME (cpu_impl));
  2373. tree task = build_decl (DECL_SOURCE_LOCATION (fn), FUNCTION_DECL,
  2374. task_name, TREE_TYPE (fn));
  2375. TREE_PUBLIC (task) = TREE_PUBLIC (fn);
  2376. TREE_PUBLIC (cpu_impl) = false;
  2377. taskify_function (task);
  2378. /* Inherit the task implementation list from FN. */
  2379. tree impls = lookup_attribute (task_implementation_list_attribute_name,
  2380. DECL_ATTRIBUTES (fn));
  2381. gcc_assert (impls != NULL_TREE);
  2382. impls = TREE_VALUE (impls);
  2383. DECL_ATTRIBUTES (task) =
  2384. tree_cons (get_identifier (task_implementation_list_attribute_name),
  2385. impls, DECL_ATTRIBUTES (task));
  2386. /* Make CPU_IMPL an implementation of FN. */
  2387. DECL_ATTRIBUTES (cpu_impl) =
  2388. tree_cons (get_identifier (task_implementation_attribute_name),
  2389. tree_cons (NULL_TREE, build_string (3, "cpu"),
  2390. tree_cons (NULL_TREE, task, NULL_TREE)),
  2391. NULL_TREE);
  2392. add_task_implementation (task, cpu_impl, build_string (3, "cpu"));
  2393. /* And now, process CPU_IMPL. */
  2394. }
  2395. if (task_implementation_p (fn))
  2396. {
  2397. tree task = task_implementation_task (fn);
  2398. if (!TREE_STATIC (task))
  2399. {
  2400. /* TASK lacks a body. Declare its codelet, intantiate its codelet
  2401. wrappers, and its body in this compilation unit. */
  2402. /* Declare TASK's codelet. It cannot be defined yet because the
  2403. complete list of tasks isn't available at this point. */
  2404. declare_codelet (task);
  2405. /* Build its body. */
  2406. current_function_decl = task;
  2407. define_task (task);
  2408. current_function_decl = fn;
  2409. /* Compile TASK's body. */
  2410. rest_of_decl_compilation (task, true, 0);
  2411. allocate_struct_function (task, false);
  2412. cgraph_finalize_function (task, false);
  2413. cgraph_mark_needed_node (cgraph_get_node (task));
  2414. }
  2415. }
  2416. }
  2417. /* Build a "conversion" from a raw C pointer to its data handle. The
  2418. assumption is that the programmer should have already registered the
  2419. pointer by themselves. */
  2420. static tree
  2421. build_pointer_lookup (tree pointer)
  2422. {
  2423. /* Make sure DATA_LOOKUP_FN is valid. */
  2424. LOOKUP_STARPU_FUNCTION (data_lookup_fn, "starpu_data_lookup");
  2425. location_t loc;
  2426. if (DECL_P (pointer))
  2427. loc = DECL_SOURCE_LOCATION (pointer);
  2428. else
  2429. loc = UNKNOWN_LOCATION;
  2430. /* Introduce a local variable to hold the handle. */
  2431. tree result_var = build_decl (loc, VAR_DECL,
  2432. create_tmp_var_name (".data_lookup_result"),
  2433. ptr_type_node);
  2434. DECL_CONTEXT (result_var) = current_function_decl;
  2435. DECL_ARTIFICIAL (result_var) = true;
  2436. DECL_SOURCE_LOCATION (result_var) = loc;
  2437. tree call = build_call_expr (data_lookup_fn, 1, pointer);
  2438. tree assignment = build2 (INIT_EXPR, TREE_TYPE (result_var),
  2439. result_var, call);
  2440. /* Build `if (RESULT_VAR == NULL) error ();'. */
  2441. tree cond = build3 (COND_EXPR, void_type_node,
  2442. build2 (EQ_EXPR, boolean_type_node,
  2443. result_var, null_pointer_node),
  2444. build_error_statements (loc, NULL_TREE,
  2445. build_starpu_error_string,
  2446. "attempt to use unregistered "
  2447. "pointer"),
  2448. NULL_TREE);
  2449. tree stmts = NULL;
  2450. append_to_statement_list (assignment, &stmts);
  2451. append_to_statement_list (cond, &stmts);
  2452. append_to_statement_list (result_var, &stmts);
  2453. return build4 (TARGET_EXPR, ptr_type_node, result_var, stmts, NULL_TREE, NULL_TREE);
  2454. }
  2455. /* Return a fresh argument list for FN. */
  2456. static tree
  2457. build_function_arguments (tree fn)
  2458. {
  2459. gcc_assert (TREE_CODE (fn) == FUNCTION_DECL
  2460. && DECL_ARGUMENTS (fn) == NULL_TREE);
  2461. local_define (tree, build_argument, (const_tree lst))
  2462. {
  2463. tree param, type;
  2464. type = TREE_VALUE (lst);
  2465. param = build_decl (DECL_SOURCE_LOCATION (fn), PARM_DECL,
  2466. create_tmp_var_name ("argument"),
  2467. type);
  2468. DECL_ARG_TYPE (param) = type;
  2469. DECL_CONTEXT (param) = fn;
  2470. return param;
  2471. };
  2472. return map (build_argument,
  2473. list_remove (void_type_p,
  2474. TYPE_ARG_TYPES (TREE_TYPE (fn))));
  2475. }
  2476. /* Build the body of TASK_DECL, which will call `starpu_insert_task'. */
  2477. static void
  2478. define_task (tree task_decl)
  2479. {
  2480. /* First of all, give TASK_DECL an argument list. */
  2481. DECL_ARGUMENTS (task_decl) = build_function_arguments (task_decl);
  2482. VEC(tree, gc) *args = NULL;
  2483. location_t loc = DECL_SOURCE_LOCATION (task_decl);
  2484. tree p, params = DECL_ARGUMENTS (task_decl);
  2485. /* The first argument will be a pointer to the codelet. */
  2486. VEC_safe_push (tree, gc, args,
  2487. build_addr (task_codelet_declaration (task_decl),
  2488. current_function_decl));
  2489. for (p = params; p != NULL_TREE; p = TREE_CHAIN (p))
  2490. {
  2491. gcc_assert (TREE_CODE (p) == PARM_DECL);
  2492. tree type = TREE_TYPE (p);
  2493. if (POINTER_TYPE_P (type))
  2494. {
  2495. /* A pointer: the arguments will be:
  2496. `STARPU_RW, ptr' or similar. */
  2497. VEC_safe_push (tree, gc, args,
  2498. build_int_cst (integer_type_node,
  2499. access_mode (type)));
  2500. VEC_safe_push (tree, gc, args, build_pointer_lookup (p));
  2501. }
  2502. else
  2503. {
  2504. /* A scalar: the arguments will be:
  2505. `STARPU_VALUE, &scalar, sizeof (scalar)'. */
  2506. mark_addressable (p);
  2507. VEC_safe_push (tree, gc, args,
  2508. build_int_cst (integer_type_node, STARPU_VALUE));
  2509. VEC_safe_push (tree, gc, args,
  2510. build_addr (p, current_function_decl));
  2511. VEC_safe_push (tree, gc, args,
  2512. size_in_bytes (type));
  2513. }
  2514. }
  2515. /* Push the terminating zero. */
  2516. VEC_safe_push (tree, gc, args,
  2517. build_int_cst (integer_type_node, 0));
  2518. /* Introduce a local variable to hold the error code. */
  2519. tree error_var = build_decl (loc, VAR_DECL,
  2520. create_tmp_var_name (".insert_task_error"),
  2521. integer_type_node);
  2522. DECL_CONTEXT (error_var) = task_decl;
  2523. DECL_ARTIFICIAL (error_var) = true;
  2524. /* Build this:
  2525. err = starpu_insert_task (...);
  2526. if (err != 0)
  2527. { printf ...; abort (); }
  2528. */
  2529. static tree insert_task_fn;
  2530. LOOKUP_STARPU_FUNCTION (insert_task_fn, "starpu_insert_task");
  2531. tree call = build_call_expr_loc_vec (loc, insert_task_fn, args);
  2532. tree assignment = build2 (INIT_EXPR, TREE_TYPE (error_var),
  2533. error_var, call);
  2534. tree name = DECL_NAME (task_decl);
  2535. tree cond = build3 (COND_EXPR, void_type_node,
  2536. build2 (NE_EXPR, boolean_type_node,
  2537. error_var, integer_zero_node),
  2538. build_error_statements (loc, error_var,
  2539. build_starpu_error_string,
  2540. "failed to insert task `%s'",
  2541. IDENTIFIER_POINTER (name)),
  2542. NULL_TREE);
  2543. tree stmts = NULL;
  2544. append_to_statement_list (assignment, &stmts);
  2545. append_to_statement_list (cond, &stmts);
  2546. tree bind = build3 (BIND_EXPR, void_type_node, error_var, stmts,
  2547. NULL_TREE);
  2548. /* Put it all together. */
  2549. DECL_SAVED_TREE (task_decl) = bind;
  2550. TREE_STATIC (task_decl) = true;
  2551. DECL_EXTERNAL (task_decl) = false;
  2552. DECL_ARTIFICIAL (task_decl) = true;
  2553. DECL_INITIAL (task_decl) =
  2554. build_block (error_var, NULL_TREE, task_decl, NULL_TREE);
  2555. DECL_RESULT (task_decl) =
  2556. build_decl (loc, RESULT_DECL, NULL_TREE, void_type_node);
  2557. DECL_CONTEXT (DECL_RESULT (task_decl)) = task_decl;
  2558. }
  2559. /* Raise warnings if TASK doesn't meet the basic criteria. */
  2560. static void
  2561. validate_task (tree task)
  2562. {
  2563. gcc_assert (task_p (task));
  2564. int where = task_where (task);
  2565. /* If TASK has no implementations, things will barf elsewhere anyway. */
  2566. if (task_implementation_list (task) != NULL_TREE)
  2567. if ((where & supported_targets) == 0)
  2568. error_at (DECL_SOURCE_LOCATION (task),
  2569. "none of the implementations of task %qE can be used",
  2570. DECL_NAME (task));
  2571. }
  2572. /* Raise an error when IMPL doesn't satisfy the constraints of a task
  2573. implementations, such as not invoking another task. */
  2574. static void
  2575. validate_task_implementation (tree impl)
  2576. {
  2577. gcc_assert (task_implementation_p (impl));
  2578. const struct cgraph_node *cgraph;
  2579. const struct cgraph_edge *callee;
  2580. cgraph = cgraph_get_node (impl);
  2581. /* When a definition of IMPL is available, check its callees. */
  2582. if (cgraph != NULL)
  2583. for (callee = cgraph->callees;
  2584. callee != NULL;
  2585. callee = callee->next_callee)
  2586. {
  2587. if (task_p (callee->callee->decl))
  2588. {
  2589. location_t loc;
  2590. loc = gimple_location (callee->call_stmt);
  2591. error_at (loc, "task %qE cannot be invoked from task implementation %qE",
  2592. DECL_NAME (callee->callee->decl),
  2593. DECL_NAME (impl));
  2594. }
  2595. }
  2596. }
  2597. static unsigned int
  2598. lower_starpu (void)
  2599. {
  2600. tree fndecl;
  2601. const struct cgraph_node *cgraph;
  2602. const struct cgraph_edge *callee;
  2603. fndecl = current_function_decl;
  2604. gcc_assert (TREE_CODE (fndecl) == FUNCTION_DECL);
  2605. if (task_p (fndecl))
  2606. {
  2607. /* Make sure the task and its implementations are valid. */
  2608. validate_task (fndecl);
  2609. for_each (validate_task_implementation,
  2610. task_implementation_list (fndecl));
  2611. /* Generate a `struct starpu_codelet' structure and a wrapper function for
  2612. each implementation of TASK_DECL. This cannot be done earlier
  2613. because we need to have a complete list of task implementations. */
  2614. define_codelet_wrappers (fndecl);
  2615. tree cl_def = task_codelet_declaration (fndecl);
  2616. DECL_INITIAL (cl_def) = build_codelet_initializer (fndecl);
  2617. TREE_STATIC (cl_def) = true;
  2618. DECL_EXTERNAL (cl_def) = false;
  2619. varpool_finalize_decl (cl_def);
  2620. }
  2621. /* This pass should occur after `build_cgraph_edges'. */
  2622. cgraph = cgraph_get_node (fndecl);
  2623. gcc_assert (cgraph != NULL);
  2624. if (MAIN_NAME_P (DECL_NAME (fndecl)))
  2625. {
  2626. /* Check whether FNDECL initializes StarPU and emit a warning if it
  2627. doesn't. */
  2628. bool initialized;
  2629. for (initialized = false, callee = cgraph->callees;
  2630. !initialized && callee != NULL;
  2631. callee = callee->next_callee)
  2632. {
  2633. initialized =
  2634. DECL_NAME (callee->callee->decl) == get_identifier ("starpu_init");
  2635. }
  2636. if (!initialized)
  2637. warning_at (DECL_SOURCE_LOCATION (fndecl), 0,
  2638. "%qE does not initialize StarPU", DECL_NAME (fndecl));
  2639. }
  2640. for (callee = cgraph->callees;
  2641. callee != NULL;
  2642. callee = callee->next_callee)
  2643. {
  2644. gcc_assert (callee->callee != NULL);
  2645. tree callee_decl, caller_decl;
  2646. callee_decl = callee->callee->decl;
  2647. caller_decl = callee->caller->decl;
  2648. if (implicit_cpu_task_implementation_p (callee_decl)
  2649. && !DECL_ARTIFICIAL (caller_decl))
  2650. {
  2651. /* Rewrite the call to point to the actual task beneath
  2652. CALLEE_DECL. */
  2653. callee_decl = task_implementation_task (callee_decl);
  2654. if (verbose_output_p)
  2655. inform (gimple_location (callee->call_stmt),
  2656. "call to %qE rewritten as a call to task %qE",
  2657. DECL_NAME (callee->callee->decl),
  2658. DECL_NAME (callee_decl));
  2659. gimple_call_set_fn (callee->call_stmt,
  2660. build_addr (callee_decl, callee->caller->decl));
  2661. }
  2662. if (task_p (callee_decl))
  2663. {
  2664. if (verbose_output_p)
  2665. inform (gimple_location (callee->call_stmt),
  2666. "%qE calls task %qE",
  2667. DECL_NAME (fndecl), DECL_NAME (callee_decl));
  2668. /* TODO: Insert analysis to check whether the pointer arguments
  2669. need to be registered. */
  2670. }
  2671. }
  2672. return 0;
  2673. }
  2674. static struct opt_pass pass_lower_starpu =
  2675. {
  2676. designated_field_init (type, GIMPLE_PASS),
  2677. designated_field_init (name, "pass_lower_starpu"),
  2678. designated_field_init (gate, NULL),
  2679. designated_field_init (execute, lower_starpu)
  2680. /* The rest is zeroed. */
  2681. };
  2682. /* Initialization. */
  2683. /* Directory where to look up <starpu.h> instead of `STARPU_INCLUDE_DIR'. */
  2684. static const char *include_dir;
  2685. static void
  2686. define_cpp_macros (void *gcc_data, void *user_data)
  2687. {
  2688. cpp_define (parse_in, "STARPU_GCC_PLUGIN=0");
  2689. if (include_dir)
  2690. {
  2691. /* Get the header from the user-specified directory. This is useful
  2692. when running the test suite, before StarPU is installed. */
  2693. char header[strlen (include_dir) + sizeof ("/starpu.h")];
  2694. strcpy (header, include_dir);
  2695. strcat (header, "/starpu.h");
  2696. cpp_push_include (parse_in, header);
  2697. }
  2698. else
  2699. cpp_push_include (parse_in, STARPU_INCLUDE_DIR "/starpu.h");
  2700. }
  2701. int
  2702. plugin_init (struct plugin_name_args *plugin_info,
  2703. struct plugin_gcc_version *version)
  2704. {
  2705. /* `plugin_default_version_check' happens to be stricter than necessary
  2706. (for instance, it fails when the `buildstamp' field of the plug-in
  2707. doesn't match that of GCC), so write our own check and make more relax
  2708. and more verbose. */
  2709. #define VERSION_CHECK(field) \
  2710. do \
  2711. { \
  2712. if (strcmp (gcc_version. field, version-> field) != 0) \
  2713. { \
  2714. error_at (UNKNOWN_LOCATION, "plug-in version check for `" \
  2715. STRINGIFY (field) "' failed: expected `%s', " \
  2716. "got `%s'", \
  2717. gcc_version. field, version-> field); \
  2718. return 1; \
  2719. } \
  2720. } \
  2721. while (0)
  2722. VERSION_CHECK (basever); /* e.g., "4.6.2" */
  2723. VERSION_CHECK (devphase);
  2724. VERSION_CHECK (revision);
  2725. VERSION_CHECK (configuration_arguments);
  2726. #undef VERSION_CHECK
  2727. register_callback (plugin_name, PLUGIN_START_UNIT,
  2728. define_cpp_macros, NULL);
  2729. register_callback (plugin_name, PLUGIN_PRAGMAS,
  2730. register_pragmas, NULL);
  2731. register_callback (plugin_name, PLUGIN_ATTRIBUTES,
  2732. register_task_attributes, NULL);
  2733. register_callback (plugin_name, PLUGIN_PRE_GENERICIZE,
  2734. handle_pre_genericize, NULL);
  2735. /* Register our pass so that it happens after `build_cgraph_edges' has been
  2736. done. */
  2737. struct register_pass_info pass_info =
  2738. {
  2739. designated_field_init (pass, &pass_lower_starpu),
  2740. designated_field_init (reference_pass_name, "*build_cgraph_edges"),
  2741. designated_field_init (ref_pass_instance_number, 1),
  2742. designated_field_init (pos_op, PASS_POS_INSERT_AFTER)
  2743. };
  2744. register_callback (plugin_name, PLUGIN_PASS_MANAGER_SETUP,
  2745. NULL, &pass_info);
  2746. include_dir = getenv ("STARPU_GCC_INCLUDE_DIR");
  2747. opencl_include_dirs = tree_cons (NULL_TREE, build_string (1, "."),
  2748. NULL_TREE);
  2749. int arg;
  2750. for (arg = 0; arg < plugin_info->argc; arg++)
  2751. {
  2752. if (strcmp (plugin_info->argv[arg].key, "include-dir") == 0)
  2753. {
  2754. if (plugin_info->argv[arg].value == NULL)
  2755. error_at (UNKNOWN_LOCATION, "missing directory name for option "
  2756. "%<-fplugin-arg-starpu-include-dir%>");
  2757. else
  2758. /* XXX: We assume that `value' has an infinite lifetime. */
  2759. include_dir = plugin_info->argv[arg].value;
  2760. }
  2761. else if (strcmp (plugin_info->argv[arg].key, "opencl-include-dir") == 0)
  2762. {
  2763. if (plugin_info->argv[arg].value == NULL)
  2764. error_at (UNKNOWN_LOCATION, "missing directory name for option "
  2765. "%<-fplugin-arg-starpu-opencl-include-dir%>");
  2766. else
  2767. {
  2768. tree dir = build_string (strlen (plugin_info->argv[arg].value),
  2769. plugin_info->argv[arg].value);
  2770. opencl_include_dirs = tree_cons (NULL_TREE, dir,
  2771. opencl_include_dirs);
  2772. }
  2773. }
  2774. else if (strcmp (plugin_info->argv[arg].key, "verbose") == 0)
  2775. verbose_output_p = true;
  2776. else
  2777. error_at (UNKNOWN_LOCATION, "invalid StarPU plug-in argument %qs",
  2778. plugin_info->argv[arg].key);
  2779. }
  2780. /* Keep the directories in the order in which they appear. */
  2781. opencl_include_dirs = nreverse (opencl_include_dirs);
  2782. return 0;
  2783. }
  2784. #ifdef __cplusplus
  2785. }
  2786. #endif