starpu.c 92 KB

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