starpu.c 88 KB

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