2 * Copyright 2011 Leiden University. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following
13 * disclaimer in the documentation and/or other materials provided
14 * with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY LEIDEN UNIVERSITY ''AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL LEIDEN UNIVERSITY OR
20 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 * The views and conclusions contained in the software and documentation
29 * are those of the authors and should not be interpreted as
30 * representing official policies, either expressed or implied, of
37 #include <llvm/Support/raw_ostream.h>
38 #include <llvm/Support/ManagedStatic.h>
39 #include <llvm/Support/Host.h>
40 #include <clang/Basic/Version.h>
41 #include <clang/Basic/FileSystemOptions.h>
42 #include <clang/Basic/FileManager.h>
43 #include <clang/Basic/TargetOptions.h>
44 #include <clang/Basic/TargetInfo.h>
45 #include <clang/Driver/Compilation.h>
46 #include <clang/Driver/Driver.h>
47 #include <clang/Driver/Tool.h>
48 #include <clang/Frontend/CompilerInstance.h>
49 #include <clang/Frontend/CompilerInvocation.h>
50 #include <clang/Frontend/DiagnosticOptions.h>
51 #include <clang/Frontend/TextDiagnosticPrinter.h>
52 #include <clang/Frontend/HeaderSearchOptions.h>
53 #include <clang/Frontend/LangStandard.h>
54 #include <clang/Frontend/PreprocessorOptions.h>
55 #include <clang/Frontend/FrontendOptions.h>
56 #include <clang/Frontend/Utils.h>
57 #include <clang/Lex/HeaderSearch.h>
58 #include <clang/Lex/Preprocessor.h>
59 #include <clang/Lex/Pragma.h>
60 #include <clang/AST/ASTContext.h>
61 #include <clang/AST/ASTConsumer.h>
62 #include <clang/Sema/Sema.h>
63 #include <clang/Sema/SemaDiagnostic.h>
64 #include <clang/Parse/Parser.h>
65 #include <clang/Parse/ParseAST.h>
68 #include <isl/constraint.h>
75 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
78 using namespace clang
;
79 using namespace clang::driver
;
81 /* Called if we found something we didn't expect in one of the pragmas.
82 * We'll provide more informative warnings later.
84 static void unsupported(Preprocessor
&PP
, SourceLocation loc
)
86 DiagnosticsEngine
&diag
= PP
.getDiagnostics();
87 unsigned id
= diag
.getCustomDiagID(DiagnosticsEngine::Warning
,
89 DiagnosticBuilder B
= diag
.Report(loc
, id
);
92 static int get_int(const char *s
)
94 return s
[0] == '"' ? atoi(s
+ 1) : atoi(s
);
97 static ValueDecl
*get_value_decl(Sema
&sema
, Token
&token
)
102 if (token
.isNot(tok::identifier
))
105 name
= token
.getIdentifierInfo();
106 decl
= sema
.LookupSingleName(sema
.TUScope
, name
,
107 token
.getLocation(), Sema::LookupOrdinaryName
);
108 return decl
? cast_or_null
<ValueDecl
>(decl
) : NULL
;
111 /* Handle pragmas of the form
113 * #pragma value_bounds identifier lower_bound upper_bound
115 * For each such pragma, add a mapping from the ValueDecl corresponding
116 * to "identifier" to a set { [i] : lower_bound <= i <= upper_bound }
117 * to the map value_bounds.
119 struct PragmaValueBoundsHandler
: public PragmaHandler
{
122 map
<ValueDecl
*, isl_set
*> &value_bounds
;
124 PragmaValueBoundsHandler(isl_ctx
*ctx
, Sema
&sema
,
125 map
<ValueDecl
*, isl_set
*> &value_bounds
) :
126 PragmaHandler("value_bounds"), ctx(ctx
), sema(sema
),
127 value_bounds(value_bounds
) {}
129 virtual void HandlePragma(Preprocessor
&PP
,
130 PragmaIntroducerKind Introducer
,
140 vd
= get_value_decl(sema
, token
);
142 unsupported(PP
, token
.getLocation());
147 if (!token
.isLiteral()) {
148 unsupported(PP
, token
.getLocation());
152 lb
= get_int(token
.getLiteralData());
155 if (!token
.isLiteral()) {
156 unsupported(PP
, token
.getLocation());
160 ub
= get_int(token
.getLiteralData());
162 dim
= isl_space_set_alloc(ctx
, 0, 1);
163 set
= isl_set_universe(dim
);
164 set
= isl_set_lower_bound_si(set
, isl_dim_set
, 0, lb
);
165 set
= isl_set_upper_bound_si(set
, isl_dim_set
, 0, ub
);
167 value_bounds
[vd
] = set
;
171 /* Given a variable declaration, check if it has an integer initializer
172 * and if so, add a parameter corresponding to the variable to "value"
173 * with its value fixed to the integer initializer and return the result.
175 static __isl_give isl_set
*extract_initialization(__isl_take isl_set
*value
,
187 vd
= cast
<VarDecl
>(decl
);
190 if (!vd
->getType()->isIntegerType())
192 expr
= vd
->getInit();
195 il
= cast
<IntegerLiteral
>(expr
);
199 ctx
= isl_set_get_ctx(value
);
200 id
= isl_id_alloc(ctx
, vd
->getName().str().c_str(), vd
);
201 space
= isl_space_params_alloc(ctx
, 1);
202 space
= isl_space_set_dim_id(space
, isl_dim_param
, 0, id
);
203 set
= isl_set_universe(space
);
206 PetScan::extract_int(il
, &v
);
207 set
= isl_set_fix(set
, isl_dim_param
, 0, v
);
210 return isl_set_intersect(value
, set
);
213 /* Handle pragmas of the form
215 * #pragma parameter identifier lower_bound
217 * #pragma parameter identifier lower_bound upper_bound
219 * For each such pragma, intersect the context with the set
220 * [identifier] -> { [] : lower_bound <= identifier <= upper_bound }
222 struct PragmaParameterHandler
: public PragmaHandler
{
225 isl_set
*&context_value
;
227 PragmaParameterHandler(Sema
&sema
, isl_set
*&context
,
228 isl_set
*&context_value
) :
229 PragmaHandler("parameter"), sema(sema
), context(context
),
230 context_value(context_value
) {}
232 virtual void HandlePragma(Preprocessor
&PP
,
233 PragmaIntroducerKind Introducer
,
236 isl_ctx
*ctx
= isl_set_get_ctx(context
);
246 vd
= get_value_decl(sema
, token
);
248 unsupported(PP
, token
.getLocation());
253 if (!token
.isLiteral()) {
254 unsupported(PP
, token
.getLocation());
258 lb
= get_int(token
.getLiteralData());
261 if (token
.isLiteral()) {
263 ub
= get_int(token
.getLiteralData());
264 } else if (token
.isNot(tok::eod
)) {
265 unsupported(PP
, token
.getLocation());
269 id
= isl_id_alloc(ctx
, vd
->getName().str().c_str(), vd
);
270 dim
= isl_space_params_alloc(ctx
, 1);
271 dim
= isl_space_set_dim_id(dim
, isl_dim_param
, 0, id
);
273 set
= isl_set_universe(dim
);
275 set
= isl_set_lower_bound_si(set
, isl_dim_param
, 0, lb
);
277 set
= isl_set_upper_bound_si(set
, isl_dim_param
, 0, ub
);
279 context
= isl_set_intersect(context
, set
);
281 context_value
= extract_initialization(context_value
, vd
);
285 /* Handle pragmas of the form
289 * In particular, store the current location in loc.start.
291 struct PragmaScopHandler
: public PragmaHandler
{
294 PragmaScopHandler(ScopLoc
&loc
) : PragmaHandler("scop"), loc(loc
) {}
296 virtual void HandlePragma(Preprocessor
&PP
,
297 PragmaIntroducerKind Introducer
,
299 SourceManager
&SM
= PP
.getSourceManager();
300 loc
.start
= SM
.getFileOffset(ScopTok
.getLocation());
304 /* Handle pragmas of the form
308 * In particular, store the current location in loc.end.
310 struct PragmaEndScopHandler
: public PragmaHandler
{
313 PragmaEndScopHandler(ScopLoc
&loc
) :
314 PragmaHandler("endscop"), loc(loc
) {}
316 virtual void HandlePragma(Preprocessor
&PP
,
317 PragmaIntroducerKind Introducer
,
319 SourceManager
&SM
= PP
.getSourceManager();
320 loc
.end
= SM
.getFileOffset(EndScopTok
.getLocation());
324 /* Handle pragmas of the form
326 * #pragma live-out identifier, identifier, ...
328 * Each identifier on the line is stored in live_out.
330 struct PragmaLiveOutHandler
: public PragmaHandler
{
332 set
<ValueDecl
*> &live_out
;
334 PragmaLiveOutHandler(Sema
&sema
, set
<ValueDecl
*> &live_out
) :
335 PragmaHandler("live"), sema(sema
), live_out(live_out
) {}
337 virtual void HandlePragma(Preprocessor
&PP
,
338 PragmaIntroducerKind Introducer
,
343 if (token
.isNot(tok::minus
))
346 if (token
.isNot(tok::identifier
) ||
347 !token
.getIdentifierInfo()->isStr("out"))
351 while (token
.isNot(tok::eod
)) {
354 vd
= get_value_decl(sema
, token
);
356 unsupported(PP
, token
.getLocation());
361 if (token
.is(tok::comma
))
367 /* Extract a pet_scop from the appropriate function.
368 * If "function" is not NULL, then we only extract a pet_scop if the
369 * name of the function matches.
370 * If "autodetect" is false, then we only extract if we have seen
371 * scop and endscop pragmas and if these are situated inside the function
374 struct PetASTConsumer
: public ASTConsumer
{
376 ASTContext
&ast_context
;
378 const char *function
;
381 struct pet_scop
*scop
;
383 PetASTConsumer(isl_ctx
*ctx
, Preprocessor
&PP
, ASTContext
&ast_context
,
384 ScopLoc
&loc
, const char *function
, bool autodetect
) :
385 ctx(ctx
), PP(PP
), ast_context(ast_context
), loc(loc
),
386 scop(NULL
), function(function
), autodetect(autodetect
) { }
388 virtual void HandleTopLevelDecl(DeclGroupRef dg
) {
389 DeclGroupRef::iterator it
;
393 for (it
= dg
.begin(); it
!= dg
.end(); ++it
) {
394 FunctionDecl
*fd
= dyn_cast
<clang::FunctionDecl
>(*it
);
400 fd
->getNameInfo().getAsString() != function
)
403 PetScan
ps(ctx
, PP
, ast_context
, loc
, 1);
412 SourceManager
&SM
= PP
.getSourceManager();
413 if (SM
.getFileOffset(fd
->getLocStart()) > loc
.end
)
415 if (SM
.getFileOffset(fd
->getLocEnd()) < loc
.start
)
417 PetScan
ps(ctx
, PP
, ast_context
, loc
, 0);
424 static const char *ResourceDir
= CLANG_PREFIX
"/lib/clang/"CLANG_VERSION_STRING
;
426 static const char *implicit_functions
[] = {
427 "min", "max", "ceild", "floord"
430 static bool is_implicit(const IdentifierInfo
*ident
)
432 const char *name
= ident
->getNameStart();
433 for (int i
= 0; i
< ARRAY_SIZE(implicit_functions
); ++i
)
434 if (!strcmp(name
, implicit_functions
[i
]))
439 /* Ignore implicit function declaration warnings on
440 * "min", "max", "ceild" and "floord" as we detect and handle these
443 * The cloned field keeps track of whether the clone method
444 * has ever been called. Newer clangs (by default) clone
445 * the DiagnosticConsumer passed to createDiagnostics and
446 * then take ownership of the clone, which means that
447 * the original has to be deleted by the calling code.
449 struct MyDiagnosticPrinter
: public TextDiagnosticPrinter
{
450 const DiagnosticOptions
*DiagOpts
;
452 MyDiagnosticPrinter(const DiagnosticOptions
&DO
) :
453 DiagOpts(&DO
), TextDiagnosticPrinter(llvm::errs(), DO
) {}
454 virtual DiagnosticConsumer
*clone(DiagnosticsEngine
&Diags
) const {
456 return new MyDiagnosticPrinter(*DiagOpts
);
458 virtual void HandleDiagnostic(DiagnosticsEngine::Level level
,
459 const DiagnosticInfo
&info
) {
460 if (info
.getID() == diag::ext_implicit_function_decl
&&
461 info
.getNumArgs() == 1 &&
462 info
.getArgKind(0) == DiagnosticsEngine::ak_identifierinfo
&&
463 is_implicit(info
.getArgIdentifier(0)))
464 /* ignore warning */;
466 TextDiagnosticPrinter::HandleDiagnostic(level
, info
);
470 bool MyDiagnosticPrinter::cloned
= false;
472 static void update_arrays(struct pet_scop
*scop
,
473 map
<ValueDecl
*, isl_set
*> &value_bounds
,
474 set
<ValueDecl
*> &live_out
)
476 map
<ValueDecl
*, isl_set
*>::iterator vb_it
;
477 set
<ValueDecl
*>::iterator lo_it
;
482 for (int i
= 0; i
< scop
->n_array
; ++i
) {
485 pet_array
*array
= scop
->arrays
[i
];
487 id
= isl_set_get_tuple_id(array
->extent
);
488 decl
= (ValueDecl
*)isl_id_get_user(id
);
491 vb_it
= value_bounds
.find(decl
);
492 if (vb_it
!= value_bounds
.end())
493 array
->value_bounds
= isl_set_copy(vb_it
->second
);
495 lo_it
= live_out
.find(decl
);
496 if (lo_it
!= live_out
.end())
503 #ifdef HAVE_CXXISPRODUCTION
504 static Driver
*construct_driver(const char *binary
, DiagnosticsEngine
&Diags
)
506 return new Driver(binary
, llvm::sys::getDefaultTargetTriple(),
507 "", false, false, Diags
);
510 static Driver
*construct_driver(const char *binary
, DiagnosticsEngine
&Diags
)
512 return new Driver(binary
, llvm::sys::getDefaultTargetTriple(),
517 /* Create a CompilerInvocation object that stores the command line
518 * arguments constructed by the driver.
519 * The arguments are mainly useful for setting up the system include
520 * paths on newer clangs and on some platforms.
522 static CompilerInvocation
*construct_invocation(const char *filename
,
523 DiagnosticsEngine
&Diags
)
525 const char *binary
= CLANG_PREFIX
"/bin/clang";
526 const llvm::OwningPtr
<Driver
> driver(construct_driver(binary
, Diags
));
527 std::vector
<const char *> Argv
;
528 Argv
.push_back(binary
);
529 Argv
.push_back(filename
);
530 const llvm::OwningPtr
<Compilation
> compilation(
531 driver
->BuildCompilation(llvm::ArrayRef
<const char *>(Argv
)));
532 JobList
&Jobs
= compilation
->getJobs();
536 Command
*cmd
= cast
<Command
>(*Jobs
.begin());
537 if (strcmp(cmd
->getCreator().getName(), "clang"))
540 const ArgStringList
*args
= &cmd
->getArguments();
542 CompilerInvocation
*invocation
= new CompilerInvocation
;
543 CompilerInvocation::CreateFromArgs(*invocation
, args
->data() + 1,
544 args
->data() + args
->size(),
551 static CompilerInvocation
*construct_invocation(const char *filename
,
552 DiagnosticsEngine
&Diags
)
559 /* Extract a pet_scop from the C source file called "filename".
560 * If "function" is not NULL, extract the pet_scop from the function
562 * If "autodetect" is set, extract any pet_scop we can find.
563 * Otherwise, extract the pet_scop from the region delimited
564 * by "scop" and "endscop" pragmas.
566 * We first set up the clang parser and then try to extract the
567 * pet_scop from the appropriate function in PetASTConsumer.
568 * If we have found a pet_scop, we add the context and value_bounds
569 * constraints specified through pragmas.
571 static struct pet_scop
*scop_extract_from_C_source(isl_ctx
*ctx
,
572 const char *filename
, const char *function
, pet_options
*options
)
576 isl_set
*context_value
;
577 set
<ValueDecl
*> live_out
;
578 map
<ValueDecl
*, isl_set
*> value_bounds
;
579 map
<ValueDecl
*, isl_set
*>::iterator vb_it
;
581 CompilerInstance
*Clang
= new CompilerInstance();
582 DiagnosticOptions DO
;
583 MyDiagnosticPrinter
*printer
= new MyDiagnosticPrinter(DO
);
584 Clang
->createDiagnostics(0, NULL
, printer
);
587 DiagnosticsEngine
&Diags
= Clang
->getDiagnostics();
588 Diags
.setSuppressSystemWarnings(true);
589 CompilerInvocation
*invocation
= construct_invocation(filename
, Diags
);
591 Clang
->setInvocation(invocation
);
592 Clang
->createFileManager();
593 Clang
->createSourceManager(Clang
->getFileManager());
595 TO
.Triple
= llvm::sys::getDefaultTargetTriple();
596 TargetInfo
*target
= TargetInfo::CreateTargetInfo(Diags
, TO
);
597 Clang
->setTarget(target
);
598 CompilerInvocation::setLangDefaults(Clang
->getLangOpts(), IK_C
,
599 LangStandard::lang_unspecified
);
600 HeaderSearchOptions
&HSO
= Clang
->getHeaderSearchOpts();
601 HSO
.ResourceDir
= ResourceDir
;
602 for (int i
= 0; i
< options
->n_path
; ++i
)
603 HSO
.AddPath(options
->paths
[i
],
604 frontend::Angled
, true, false, false);
605 PreprocessorOptions
&PO
= Clang
->getPreprocessorOpts();
606 for (int i
= 0; i
< options
->n_define
; ++i
)
607 PO
.addMacroDef(options
->defines
[i
]);
608 Clang
->createPreprocessor();
609 Preprocessor
&PP
= Clang
->getPreprocessor();
613 const FileEntry
*file
= Clang
->getFileManager().getFile(filename
);
615 isl_die(ctx
, isl_error_unknown
, "unable to open file",
616 do { delete Clang
; return NULL
; } while (0));
617 Clang
->getSourceManager().createMainFileID(file
);
619 Clang
->createASTContext();
620 PetASTConsumer
consumer(ctx
, PP
, Clang
->getASTContext(),
621 loc
, function
, options
->autodetect
);
622 Sema
*sema
= new Sema(PP
, Clang
->getASTContext(), consumer
);
624 if (!options
->autodetect
) {
625 PP
.AddPragmaHandler(new PragmaScopHandler(loc
));
626 PP
.AddPragmaHandler(new PragmaEndScopHandler(loc
));
627 PP
.AddPragmaHandler(new PragmaLiveOutHandler(*sema
, live_out
));
630 dim
= isl_space_params_alloc(ctx
, 0);
631 context
= isl_set_universe(isl_space_copy(dim
));
632 context_value
= isl_set_universe(dim
);
633 PP
.AddPragmaHandler(new PragmaParameterHandler(*sema
, context
,
635 PP
.AddPragmaHandler(new PragmaValueBoundsHandler(ctx
, *sema
, value_bounds
));
637 Diags
.getClient()->BeginSourceFile(Clang
->getLangOpts(), &PP
);
639 Diags
.getClient()->EndSourceFile();
645 consumer
.scop
->context
= isl_set_intersect(context
,
646 consumer
.scop
->context
);
647 consumer
.scop
->context_value
= isl_set_intersect(context_value
,
648 consumer
.scop
->context_value
);
650 isl_set_free(context
);
651 isl_set_free(context_value
);
654 update_arrays(consumer
.scop
, value_bounds
, live_out
);
656 for (vb_it
= value_bounds
.begin(); vb_it
!= value_bounds
.end(); vb_it
++)
657 isl_set_free(vb_it
->second
);
659 return consumer
.scop
;
662 struct pet_scop
*pet_scop_extract_from_C_source(isl_ctx
*ctx
,
663 const char *filename
, const char *function
)
666 pet_options
*options
;
667 bool allocated
= false;
669 options
= isl_ctx_peek_pet_options(ctx
);
671 options
= pet_options_new_with_defaults();
675 scop
= scop_extract_from_C_source(ctx
, filename
, function
, options
);
676 llvm::llvm_shutdown();
679 pet_options_free(options
);