add pet_scop_print_original
[pet.git] / pet.cc
blob825cb1224152136ae78fd7eb495ab0992bcf2a73
1 /*
2 * Copyright 2011 Leiden University. All rights reserved.
3 * Copyright 2012 Ecole Normale Superieure. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following
14 * disclaimer in the documentation and/or other materials provided
15 * with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * The views and conclusions contained in the software and documentation
30 * are those of the authors and should not be interpreted as
31 * representing official policies, either expressed or implied, of
32 * Leiden University.
33 */
35 #include "config.h"
37 #include <stdlib.h>
38 #include <map>
39 #include <iostream>
40 #include <llvm/Support/raw_ostream.h>
41 #include <llvm/Support/ManagedStatic.h>
42 #include <llvm/Support/Host.h>
43 #include <clang/Basic/Version.h>
44 #include <clang/Basic/FileSystemOptions.h>
45 #include <clang/Basic/FileManager.h>
46 #include <clang/Basic/TargetOptions.h>
47 #include <clang/Basic/TargetInfo.h>
48 #include <clang/Driver/Compilation.h>
49 #include <clang/Driver/Driver.h>
50 #include <clang/Driver/Tool.h>
51 #include <clang/Frontend/CompilerInstance.h>
52 #include <clang/Frontend/CompilerInvocation.h>
53 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
54 #include <clang/Basic/DiagnosticOptions.h>
55 #else
56 #include <clang/Frontend/DiagnosticOptions.h>
57 #endif
58 #include <clang/Frontend/TextDiagnosticPrinter.h>
59 #ifdef HAVE_LEX_HEADERSEARCHOPTIONS_H
60 #include <clang/Lex/HeaderSearchOptions.h>
61 #else
62 #include <clang/Frontend/HeaderSearchOptions.h>
63 #endif
64 #include <clang/Frontend/LangStandard.h>
65 #ifdef HAVE_LEX_PREPROCESSOROPTIONS_H
66 #include <clang/Lex/PreprocessorOptions.h>
67 #else
68 #include <clang/Frontend/PreprocessorOptions.h>
69 #endif
70 #include <clang/Frontend/FrontendOptions.h>
71 #include <clang/Frontend/Utils.h>
72 #include <clang/Lex/HeaderSearch.h>
73 #include <clang/Lex/Preprocessor.h>
74 #include <clang/Lex/Pragma.h>
75 #include <clang/AST/ASTContext.h>
76 #include <clang/AST/ASTConsumer.h>
77 #include <clang/Sema/Sema.h>
78 #include <clang/Sema/SemaDiagnostic.h>
79 #include <clang/Parse/Parser.h>
80 #include <clang/Parse/ParseAST.h>
82 #include <isl/ctx.h>
83 #include <isl/constraint.h>
85 #include <pet.h>
87 #include "options.h"
88 #include "scan.h"
89 #include "print.h"
91 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
93 using namespace std;
94 using namespace clang;
95 using namespace clang::driver;
97 /* Called if we found something we didn't expect in one of the pragmas.
98 * We'll provide more informative warnings later.
100 static void unsupported(Preprocessor &PP, SourceLocation loc)
102 DiagnosticsEngine &diag = PP.getDiagnostics();
103 unsigned id = diag.getCustomDiagID(DiagnosticsEngine::Warning,
104 "unsupported");
105 DiagnosticBuilder B = diag.Report(loc, id);
108 static int get_int(const char *s)
110 return s[0] == '"' ? atoi(s + 1) : atoi(s);
113 static ValueDecl *get_value_decl(Sema &sema, Token &token)
115 IdentifierInfo *name;
116 Decl *decl;
118 if (token.isNot(tok::identifier))
119 return NULL;
121 name = token.getIdentifierInfo();
122 decl = sema.LookupSingleName(sema.TUScope, name,
123 token.getLocation(), Sema::LookupOrdinaryName);
124 return decl ? cast_or_null<ValueDecl>(decl) : NULL;
127 /* Handle pragmas of the form
129 * #pragma value_bounds identifier lower_bound upper_bound
131 * For each such pragma, add a mapping
132 * { identifier[] -> [i] : lower_bound <= i <= upper_bound }
133 * to value_bounds.
135 struct PragmaValueBoundsHandler : public PragmaHandler {
136 Sema &sema;
137 isl_ctx *ctx;
138 isl_union_map *value_bounds;
140 PragmaValueBoundsHandler(isl_ctx *ctx, Sema &sema) :
141 PragmaHandler("value_bounds"), ctx(ctx), sema(sema) {
142 isl_space *space = isl_space_params_alloc(ctx, 0);
143 value_bounds = isl_union_map_empty(space);
146 ~PragmaValueBoundsHandler() {
147 isl_union_map_free(value_bounds);
150 virtual void HandlePragma(Preprocessor &PP,
151 PragmaIntroducerKind Introducer,
152 Token &ScopTok) {
153 isl_id *id;
154 isl_space *dim;
155 isl_map *map;
156 ValueDecl *vd;
157 Token token;
158 int lb;
159 int ub;
161 PP.Lex(token);
162 vd = get_value_decl(sema, token);
163 if (!vd) {
164 unsupported(PP, token.getLocation());
165 return;
168 PP.Lex(token);
169 if (!token.isLiteral()) {
170 unsupported(PP, token.getLocation());
171 return;
174 lb = get_int(token.getLiteralData());
176 PP.Lex(token);
177 if (!token.isLiteral()) {
178 unsupported(PP, token.getLocation());
179 return;
182 ub = get_int(token.getLiteralData());
184 dim = isl_space_alloc(ctx, 0, 0, 1);
185 map = isl_map_universe(dim);
186 map = isl_map_lower_bound_si(map, isl_dim_out, 0, lb);
187 map = isl_map_upper_bound_si(map, isl_dim_out, 0, ub);
188 id = isl_id_alloc(ctx, vd->getName().str().c_str(), vd);
189 map = isl_map_set_tuple_id(map, isl_dim_in, id);
191 value_bounds = isl_union_map_add_map(value_bounds, map);
195 /* Given a variable declaration, check if it has an integer initializer
196 * and if so, add a parameter corresponding to the variable to "value"
197 * with its value fixed to the integer initializer and return the result.
199 static __isl_give isl_set *extract_initialization(__isl_take isl_set *value,
200 ValueDecl *decl)
202 VarDecl *vd;
203 Expr *expr;
204 IntegerLiteral *il;
205 isl_val *v;
206 isl_ctx *ctx;
207 isl_id *id;
208 isl_space *space;
209 isl_set *set;
211 vd = cast<VarDecl>(decl);
212 if (!vd)
213 return value;
214 if (!vd->getType()->isIntegerType())
215 return value;
216 expr = vd->getInit();
217 if (!expr)
218 return value;
219 il = cast<IntegerLiteral>(expr);
220 if (!il)
221 return value;
223 ctx = isl_set_get_ctx(value);
224 id = isl_id_alloc(ctx, vd->getName().str().c_str(), vd);
225 space = isl_space_params_alloc(ctx, 1);
226 space = isl_space_set_dim_id(space, isl_dim_param, 0, id);
227 set = isl_set_universe(space);
229 v = PetScan::extract_int(ctx, il);
230 set = isl_set_fix_val(set, isl_dim_param, 0, v);
232 return isl_set_intersect(value, set);
235 /* Handle pragmas of the form
237 * #pragma parameter identifier lower_bound
238 * and
239 * #pragma parameter identifier lower_bound upper_bound
241 * For each such pragma, intersect the context with the set
242 * [identifier] -> { [] : lower_bound <= identifier <= upper_bound }
244 struct PragmaParameterHandler : public PragmaHandler {
245 Sema &sema;
246 isl_set *&context;
247 isl_set *&context_value;
249 PragmaParameterHandler(Sema &sema, isl_set *&context,
250 isl_set *&context_value) :
251 PragmaHandler("parameter"), sema(sema), context(context),
252 context_value(context_value) {}
254 virtual void HandlePragma(Preprocessor &PP,
255 PragmaIntroducerKind Introducer,
256 Token &ScopTok) {
257 isl_id *id;
258 isl_ctx *ctx = isl_set_get_ctx(context);
259 isl_space *dim;
260 isl_set *set;
261 ValueDecl *vd;
262 Token token;
263 int lb;
264 int ub;
265 bool has_ub = false;
267 PP.Lex(token);
268 vd = get_value_decl(sema, token);
269 if (!vd) {
270 unsupported(PP, token.getLocation());
271 return;
274 PP.Lex(token);
275 if (!token.isLiteral()) {
276 unsupported(PP, token.getLocation());
277 return;
280 lb = get_int(token.getLiteralData());
282 PP.Lex(token);
283 if (token.isLiteral()) {
284 has_ub = true;
285 ub = get_int(token.getLiteralData());
286 } else if (token.isNot(tok::eod)) {
287 unsupported(PP, token.getLocation());
288 return;
291 id = isl_id_alloc(ctx, vd->getName().str().c_str(), vd);
292 dim = isl_space_params_alloc(ctx, 1);
293 dim = isl_space_set_dim_id(dim, isl_dim_param, 0, id);
295 set = isl_set_universe(dim);
297 set = isl_set_lower_bound_si(set, isl_dim_param, 0, lb);
298 if (has_ub)
299 set = isl_set_upper_bound_si(set, isl_dim_param, 0, ub);
301 context = isl_set_intersect(context, set);
303 context_value = extract_initialization(context_value, vd);
307 #ifdef HAVE_TRANSLATELINECOL
309 /* Return a SourceLocation for line "line", column "col" of file "FID".
311 SourceLocation translateLineCol(SourceManager &SM, FileID FID, unsigned line,
312 unsigned col)
314 return SM.translateLineCol(FID, line, col);
317 #else
319 /* Return a SourceLocation for line "line", column "col" of file "FID".
321 SourceLocation translateLineCol(SourceManager &SM, FileID FID, unsigned line,
322 unsigned col)
324 return SM.getLocation(SM.getFileEntryForID(FID), line, col);
327 #endif
329 /* Handle pragmas of the form
331 * #pragma scop
333 * In particular, store the location of the line containing
334 * the pragma in loc.start.
336 struct PragmaScopHandler : public PragmaHandler {
337 ScopLoc &loc;
339 PragmaScopHandler(ScopLoc &loc) : PragmaHandler("scop"), loc(loc) {}
341 virtual void HandlePragma(Preprocessor &PP,
342 PragmaIntroducerKind Introducer,
343 Token &ScopTok) {
344 SourceManager &SM = PP.getSourceManager();
345 SourceLocation sloc = ScopTok.getLocation();
346 int line = SM.getExpansionLineNumber(sloc);
347 sloc = translateLineCol(SM, SM.getFileID(sloc), line, 1);
348 loc.start = SM.getFileOffset(sloc);
352 /* Handle pragmas of the form
354 * #pragma endscop
356 * In particular, store the location of the line following the one containing
357 * the pragma in loc.end.
359 struct PragmaEndScopHandler : public PragmaHandler {
360 ScopLoc &loc;
362 PragmaEndScopHandler(ScopLoc &loc) :
363 PragmaHandler("endscop"), loc(loc) {}
365 virtual void HandlePragma(Preprocessor &PP,
366 PragmaIntroducerKind Introducer,
367 Token &EndScopTok) {
368 SourceManager &SM = PP.getSourceManager();
369 SourceLocation sloc = EndScopTok.getLocation();
370 int line = SM.getExpansionLineNumber(sloc);
371 sloc = translateLineCol(SM, SM.getFileID(sloc), line + 1, 1);
372 loc.end = SM.getFileOffset(sloc);
376 /* Handle pragmas of the form
378 * #pragma live-out identifier, identifier, ...
380 * Each identifier on the line is stored in live_out.
382 struct PragmaLiveOutHandler : public PragmaHandler {
383 Sema &sema;
384 set<ValueDecl *> &live_out;
386 PragmaLiveOutHandler(Sema &sema, set<ValueDecl *> &live_out) :
387 PragmaHandler("live"), sema(sema), live_out(live_out) {}
389 virtual void HandlePragma(Preprocessor &PP,
390 PragmaIntroducerKind Introducer,
391 Token &ScopTok) {
392 Token token;
394 PP.Lex(token);
395 if (token.isNot(tok::minus))
396 return;
397 PP.Lex(token);
398 if (token.isNot(tok::identifier) ||
399 !token.getIdentifierInfo()->isStr("out"))
400 return;
402 PP.Lex(token);
403 while (token.isNot(tok::eod)) {
404 ValueDecl *vd;
406 vd = get_value_decl(sema, token);
407 if (!vd) {
408 unsupported(PP, token.getLocation());
409 return;
411 live_out.insert(vd);
412 PP.Lex(token);
413 if (token.is(tok::comma))
414 PP.Lex(token);
419 /* For each array in "scop", set its value_bounds property
420 * based on the infofrmation in "value_bounds" and
421 * mark it as live_out if it appears in "live_out".
423 static void update_arrays(struct pet_scop *scop,
424 __isl_take isl_union_map *value_bounds, set<ValueDecl *> &live_out)
426 set<ValueDecl *>::iterator lo_it;
427 isl_ctx *ctx = isl_union_map_get_ctx(value_bounds);
429 if (!scop) {
430 isl_union_map_free(value_bounds);
431 return;
434 for (int i = 0; i < scop->n_array; ++i) {
435 isl_id *id;
436 isl_space *space;
437 isl_map *bounds;
438 ValueDecl *decl;
439 pet_array *array = scop->arrays[i];
441 id = isl_set_get_tuple_id(array->extent);
442 decl = (ValueDecl *)isl_id_get_user(id);
444 space = isl_space_alloc(ctx, 0, 0, 1);
445 space = isl_space_set_tuple_id(space, isl_dim_in, id);
447 bounds = isl_union_map_extract_map(value_bounds, space);
448 if (!isl_map_plain_is_empty(bounds))
449 array->value_bounds = isl_map_range(bounds);
450 else
451 isl_map_free(bounds);
453 lo_it = live_out.find(decl);
454 if (lo_it != live_out.end())
455 array->live_out = 1;
458 isl_union_map_free(value_bounds);
461 /* Extract a pet_scop (if any) from each appropriate function.
462 * Each detected scop is passed to "fn".
463 * If "function" is not NULL, then we only extract a pet_scop if the
464 * name of the function matches.
465 * If "autodetect" is false, then we only extract if we have seen
466 * scop and endscop pragmas and if these are situated inside the function
467 * body.
469 struct PetASTConsumer : public ASTConsumer {
470 Preprocessor &PP;
471 ASTContext &ast_context;
472 DiagnosticsEngine &diags;
473 ScopLoc &loc;
474 const char *function;
475 pet_options *options;
476 isl_ctx *ctx;
477 isl_set *context;
478 isl_set *context_value;
479 set<ValueDecl *> live_out;
480 PragmaValueBoundsHandler *vb_handler;
481 int (*fn)(struct pet_scop *scop, void *user);
482 void *user;
483 bool error;
485 PetASTConsumer(isl_ctx *ctx, Preprocessor &PP, ASTContext &ast_context,
486 DiagnosticsEngine &diags, ScopLoc &loc, const char *function,
487 pet_options *options,
488 int (*fn)(struct pet_scop *scop, void *user), void *user) :
489 ctx(ctx), PP(PP), ast_context(ast_context), diags(diags),
490 loc(loc), function(function), options(options),
491 vb_handler(NULL), fn(fn), user(user), error(false)
493 isl_space *space;
494 space = isl_space_params_alloc(ctx, 0);
495 context = isl_set_universe(isl_space_copy(space));
496 context_value = isl_set_universe(space);
499 ~PetASTConsumer() {
500 isl_set_free(context);
501 isl_set_free(context_value);
504 void handle_value_bounds(Sema *sema) {
505 vb_handler = new PragmaValueBoundsHandler(ctx, *sema);
506 PP.AddPragmaHandler(vb_handler);
509 __isl_give isl_union_map *get_value_bounds() {
510 return isl_union_map_copy(vb_handler->value_bounds);
513 /* Pass "scop" to "fn" after performing some postprocessing.
514 * In particular, add the context and value_bounds constraints
515 * speficied through pragmas, add reference identifiers and
516 * reset user pointers on parameters and tuple ids.
518 void call_fn(pet_scop *scop) {
519 if (!scop)
520 return;
521 if (diags.hasErrorOccurred()) {
522 pet_scop_free(scop);
523 return;
525 scop->context = isl_set_intersect(scop->context,
526 isl_set_copy(context));
527 scop->context_value = isl_set_intersect(scop->context_value,
528 isl_set_copy(context_value));
530 update_arrays(scop, get_value_bounds(), live_out);
532 scop = pet_scop_add_ref_ids(scop);
533 scop = pet_scop_anonymize(scop);
535 if (fn(scop, user) < 0)
536 error = true;
539 virtual HandleTopLevelDeclReturn HandleTopLevelDecl(DeclGroupRef dg) {
540 DeclGroupRef::iterator it;
542 if (error)
543 return HandleTopLevelDeclContinue;
545 for (it = dg.begin(); it != dg.end(); ++it) {
546 pet_scop *scop;
547 isl_union_map *vb = vb_handler->value_bounds;
548 FunctionDecl *fd = dyn_cast<clang::FunctionDecl>(*it);
549 if (!fd)
550 continue;
551 if (!fd->hasBody())
552 continue;
553 if (function &&
554 fd->getNameInfo().getAsString() != function)
555 continue;
556 if (options->autodetect) {
557 PetScan ps(PP, ast_context, loc, options,
558 isl_union_map_copy(vb));
559 scop = ps.scan(fd);
560 call_fn(scop);
561 continue;
563 if (!loc.end)
564 continue;
565 SourceManager &SM = PP.getSourceManager();
566 if (SM.getFileOffset(fd->getLocStart()) > loc.end)
567 continue;
568 if (SM.getFileOffset(fd->getLocEnd()) < loc.start)
569 continue;
570 PetScan ps(PP, ast_context, loc, options,
571 isl_union_map_copy(vb));
572 scop = ps.scan(fd);
573 call_fn(scop);
576 return HandleTopLevelDeclContinue;
580 static const char *ResourceDir = CLANG_PREFIX"/lib/clang/"CLANG_VERSION_STRING;
582 static const char *implicit_functions[] = {
583 "min", "max", "ceild", "floord"
586 static bool is_implicit(const IdentifierInfo *ident)
588 const char *name = ident->getNameStart();
589 for (int i = 0; i < ARRAY_SIZE(implicit_functions); ++i)
590 if (!strcmp(name, implicit_functions[i]))
591 return true;
592 return false;
595 /* Ignore implicit function declaration warnings on
596 * "min", "max", "ceild" and "floord" as we detect and handle these
597 * in PetScan.
599 struct MyDiagnosticPrinter : public TextDiagnosticPrinter {
600 const DiagnosticOptions *DiagOpts;
601 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
602 MyDiagnosticPrinter(DiagnosticOptions *DO) :
603 TextDiagnosticPrinter(llvm::errs(), DO) {}
604 virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
605 return new MyDiagnosticPrinter(&Diags.getDiagnosticOptions());
607 #else
608 MyDiagnosticPrinter(const DiagnosticOptions &DO) :
609 DiagOpts(&DO), TextDiagnosticPrinter(llvm::errs(), DO) {}
610 virtual DiagnosticConsumer *clone(DiagnosticsEngine &Diags) const {
611 return new MyDiagnosticPrinter(*DiagOpts);
613 #endif
614 virtual void HandleDiagnostic(DiagnosticsEngine::Level level,
615 const DiagnosticInfo &info) {
616 if (info.getID() == diag::ext_implicit_function_decl &&
617 info.getNumArgs() == 1 &&
618 info.getArgKind(0) == DiagnosticsEngine::ak_identifierinfo &&
619 is_implicit(info.getArgIdentifier(0)))
620 /* ignore warning */;
621 else
622 TextDiagnosticPrinter::HandleDiagnostic(level, info);
626 #ifdef USE_ARRAYREF
628 #ifdef HAVE_CXXISPRODUCTION
629 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
631 return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
632 "", false, false, Diags);
634 #elif defined(HAVE_ISPRODUCTION)
635 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
637 return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
638 "", false, Diags);
640 #else
641 static Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags)
643 return new Driver(binary, llvm::sys::getDefaultTargetTriple(),
644 "", Diags);
646 #endif
648 /* Create a CompilerInvocation object that stores the command line
649 * arguments constructed by the driver.
650 * The arguments are mainly useful for setting up the system include
651 * paths on newer clangs and on some platforms.
653 static CompilerInvocation *construct_invocation(const char *filename,
654 DiagnosticsEngine &Diags)
656 const char *binary = CLANG_PREFIX"/bin/clang";
657 const llvm::OwningPtr<Driver> driver(construct_driver(binary, Diags));
658 std::vector<const char *> Argv;
659 Argv.push_back(binary);
660 Argv.push_back(filename);
661 const llvm::OwningPtr<Compilation> compilation(
662 driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv)));
663 JobList &Jobs = compilation->getJobs();
664 if (Jobs.size() < 1)
665 return NULL;
667 Command *cmd = cast<Command>(*Jobs.begin());
668 if (strcmp(cmd->getCreator().getName(), "clang"))
669 return NULL;
671 const ArgStringList *args = &cmd->getArguments();
673 CompilerInvocation *invocation = new CompilerInvocation;
674 CompilerInvocation::CreateFromArgs(*invocation, args->data() + 1,
675 args->data() + args->size(),
676 Diags);
677 return invocation;
680 #else
682 static CompilerInvocation *construct_invocation(const char *filename,
683 DiagnosticsEngine &Diags)
685 return NULL;
688 #endif
690 #ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H
692 static MyDiagnosticPrinter *construct_printer(CompilerInstance *Clang)
694 return new MyDiagnosticPrinter(new DiagnosticOptions());
697 #else
699 static MyDiagnosticPrinter *construct_printer(CompilerInstance *Clang)
701 return new MyDiagnosticPrinter(Clang->getDiagnosticOpts());
704 #endif
706 #ifdef CREATETARGETINFO_TAKES_POINTER
708 static TargetInfo *create_target_info(CompilerInstance *Clang,
709 DiagnosticsEngine &Diags)
711 TargetOptions &TO = Clang->getTargetOpts();
712 TO.Triple = llvm::sys::getDefaultTargetTriple();
713 return TargetInfo::CreateTargetInfo(Diags, &TO);
716 #else
718 static TargetInfo *create_target_info(CompilerInstance *Clang,
719 DiagnosticsEngine &Diags)
721 TargetOptions &TO = Clang->getTargetOpts();
722 TO.Triple = llvm::sys::getDefaultTargetTriple();
723 return TargetInfo::CreateTargetInfo(Diags, TO);
726 #endif
728 #ifdef CREATEDIAGNOSTICS_TAKES_ARG
730 static void create_diagnostics(CompilerInstance *Clang)
732 Clang->createDiagnostics(0, NULL);
735 #else
737 static void create_diagnostics(CompilerInstance *Clang)
739 Clang->createDiagnostics();
742 #endif
744 #ifdef ADDPATH_TAKES_4_ARGUMENTS
746 void add_path(HeaderSearchOptions &HSO, string Path)
748 HSO.AddPath(Path, frontend::Angled, false, false);
751 #else
753 void add_path(HeaderSearchOptions &HSO, string Path)
755 HSO.AddPath(Path, frontend::Angled, true, false, false);
758 #endif
760 /* Extract a pet_scop from each function in the C source file called "filename".
761 * Each detected scop is passed to "fn".
762 * If "function" is not NULL, only extract a pet_scop from the function
763 * with that name.
764 * If "autodetect" is set, extract any pet_scop we can find.
765 * Otherwise, extract the pet_scop from the region delimited
766 * by "scop" and "endscop" pragmas.
768 * We first set up the clang parser and then try to extract the
769 * pet_scop from the appropriate function(s) in PetASTConsumer.
771 static int foreach_scop_in_C_source(isl_ctx *ctx,
772 const char *filename, const char *function, pet_options *options,
773 int (*fn)(struct pet_scop *scop, void *user), void *user)
775 CompilerInstance *Clang = new CompilerInstance();
776 create_diagnostics(Clang);
777 DiagnosticsEngine &Diags = Clang->getDiagnostics();
778 Diags.setSuppressSystemWarnings(true);
779 CompilerInvocation *invocation = construct_invocation(filename, Diags);
780 if (invocation)
781 Clang->setInvocation(invocation);
782 Diags.setClient(construct_printer(Clang));
783 Clang->createFileManager();
784 Clang->createSourceManager(Clang->getFileManager());
785 TargetInfo *target = create_target_info(Clang, Diags);
786 Clang->setTarget(target);
787 CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C,
788 LangStandard::lang_unspecified);
789 HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts();
790 HSO.ResourceDir = ResourceDir;
791 for (int i = 0; i < options->n_path; ++i)
792 add_path(HSO, options->paths[i]);
793 PreprocessorOptions &PO = Clang->getPreprocessorOpts();
794 for (int i = 0; i < options->n_define; ++i)
795 PO.addMacroDef(options->defines[i]);
796 Clang->createPreprocessor();
797 Preprocessor &PP = Clang->getPreprocessor();
799 ScopLoc loc;
801 const FileEntry *file = Clang->getFileManager().getFile(filename);
802 if (!file)
803 isl_die(ctx, isl_error_unknown, "unable to open file",
804 do { delete Clang; return -1; } while (0));
805 Clang->getSourceManager().createMainFileID(file);
807 Clang->createASTContext();
808 PetASTConsumer consumer(ctx, PP, Clang->getASTContext(), Diags,
809 loc, function, options, fn, user);
810 Sema *sema = new Sema(PP, Clang->getASTContext(), consumer);
812 if (!options->autodetect) {
813 PP.AddPragmaHandler(new PragmaScopHandler(loc));
814 PP.AddPragmaHandler(new PragmaEndScopHandler(loc));
815 PP.AddPragmaHandler(new PragmaLiveOutHandler(*sema,
816 consumer.live_out));
819 PP.AddPragmaHandler(new PragmaParameterHandler(*sema, consumer.context,
820 consumer.context_value));
821 consumer.handle_value_bounds(sema);
823 Diags.getClient()->BeginSourceFile(Clang->getLangOpts(), &PP);
824 ParseAST(*sema);
825 Diags.getClient()->EndSourceFile();
827 delete sema;
828 delete Clang;
830 return consumer.error ? -1 : 0;
833 /* Extract a pet_scop from each function in the C source file called "filename".
834 * Each detected scop is passed to "fn".
836 * This wrapper around foreach_scop_in_C_source is mainly used to ensure
837 * that all objects on the stack (of that function) are destroyed before we
838 * call llvm_shutdown.
840 static int pet_foreach_scop_in_C_source(isl_ctx *ctx,
841 const char *filename, const char *function,
842 int (*fn)(struct pet_scop *scop, void *user), void *user)
844 int r;
845 pet_options *options;
846 bool allocated = false;
848 options = isl_ctx_peek_pet_options(ctx);
849 if (!options) {
850 options = pet_options_new_with_defaults();
851 allocated = true;
854 r = foreach_scop_in_C_source(ctx, filename, function, options,
855 fn, user);
856 llvm::llvm_shutdown();
858 if (allocated)
859 pet_options_free(options);
861 return r;
864 /* Store "scop" into the address pointed to by "user".
865 * Return -1 to indicate that we are not interested in any further scops.
866 * This function should therefore not be called a second call
867 * so in principle there is no need to check if we have already set *user.
869 static int set_first_scop(pet_scop *scop, void *user)
871 pet_scop **p = (pet_scop **) user;
873 if (!*p)
874 *p = scop;
875 else
876 pet_scop_free(scop);
878 return -1;
881 /* Extract a pet_scop from the C source file called "filename".
882 * If "function" is not NULL, extract the pet_scop from the function
883 * with that name.
885 * We start extracting scops from every function and then abort
886 * as soon as we have extracted one scop.
888 struct pet_scop *pet_scop_extract_from_C_source(isl_ctx *ctx,
889 const char *filename, const char *function)
891 pet_scop *scop = NULL;
893 pet_foreach_scop_in_C_source(ctx, filename, function,
894 &set_first_scop, &scop);
896 return scop;
899 /* Internal data structure for pet_transform_C_source
901 * transform is the function that should be called to print a scop
902 * in is the input source file
903 * out is the output source file
904 * end is the offset of the end of the previous scop (zero if we have not
905 * found any scop yet)
906 * p is a printer that prints to out.
908 struct pet_transform_data {
909 __isl_give isl_printer *(*transform)(__isl_take isl_printer *p,
910 struct pet_scop *scop, void *user);
911 void *user;
913 FILE *in;
914 FILE *out;
915 unsigned end;
916 isl_printer *p;
919 /* This function is called each time a scop is detected.
921 * We first copy the input text code from the end of the previous scop
922 * until the start of "scop" and then print the scop itself through
923 * a call to data->transform.
924 * Finally, we keep track of the end of "scop" so that we can
925 * continue copying when we find the next scop.
927 * Before calling data->transform, we store a pointer to the original
928 * input file in the extended scop in case the user wants to call
929 * pet_scop_print_original from the callback.
931 static int pet_transform(struct pet_scop *scop, void *user)
933 struct pet_transform_data *data = (struct pet_transform_data *) user;
935 if (copy(data->in, data->out, data->end, scop->start) < 0)
936 goto error;
937 data->end = scop->end;
938 scop = pet_scop_set_input_file(scop, data->in);
939 data->p = data->transform(data->p, scop, data->user);
940 if (!data->p)
941 return -1;
942 return 0;
943 error:
944 pet_scop_free(scop);
945 return -1;
948 /* Transform the C source file "input" by rewriting each scop
949 * (at most one per function) through a call to "transform".
950 * The transformed C code is written to "output".
952 * For each scop we find, we first copy the input text code
953 * from the end of the previous scop (or the beginning of the file
954 * in case of the first scop) until the start of the scop
955 * and then print the scop itself through a call to "transform".
956 * At the end we copy everything from the end of the final scop
957 * until the end of the input file to "output".
959 int pet_transform_C_source(isl_ctx *ctx, const char *input, FILE *out,
960 __isl_give isl_printer *(*transform)(__isl_take isl_printer *p,
961 struct pet_scop *scop, void *user), void *user)
963 struct pet_transform_data data;
964 int r;
966 data.in = stdin;
967 data.out = out;
968 if (input && strcmp(input, "-")) {
969 data.in = fopen(input, "r");
970 if (!data.in)
971 isl_die(ctx, isl_error_unknown, "unable to open file",
972 return -1);
975 data.p = isl_printer_to_file(ctx, data.out);
976 data.p = isl_printer_set_output_format(data.p, ISL_FORMAT_C);
978 data.transform = transform;
979 data.user = user;
980 data.end = 0;
981 r = pet_foreach_scop_in_C_source(ctx, input, NULL,
982 &pet_transform, &data);
984 isl_printer_free(data.p);
985 if (!data.p)
986 r = -1;
987 if (r == 0 && copy(data.in, data.out, data.end, -1) < 0)
988 r = -1;
990 if (data.in != stdin)
991 fclose(data.in);
993 return r;