take into account that unsigned iterators may wrap
[pet.git] / pet.cc
blob32aa4cd3da6e9faaca8b3771ab791c2dca966d4e
1 #include <stdlib.h>
2 #include <map>
3 #include <iostream>
4 #include <llvm/Support/raw_ostream.h>
5 #include <llvm/Support/ManagedStatic.h>
6 #include <llvm/Support/Host.h>
7 #include <clang/Basic/Version.h>
8 #include <clang/Basic/FileSystemOptions.h>
9 #include <clang/Basic/FileManager.h>
10 #include <clang/Basic/TargetOptions.h>
11 #include <clang/Basic/TargetInfo.h>
12 #include <clang/Frontend/CompilerInvocation.h>
13 #include <clang/Frontend/DiagnosticOptions.h>
14 #include <clang/Frontend/TextDiagnosticPrinter.h>
15 #include <clang/Frontend/HeaderSearchOptions.h>
16 #include <clang/Frontend/LangStandard.h>
17 #include <clang/Frontend/PreprocessorOptions.h>
18 #include <clang/Frontend/FrontendOptions.h>
19 #include <clang/Frontend/Utils.h>
20 #include <clang/Lex/HeaderSearch.h>
21 #include <clang/Lex/Preprocessor.h>
22 #include <clang/Lex/Pragma.h>
23 #include <clang/AST/ASTContext.h>
24 #include <clang/AST/ASTConsumer.h>
25 #include <clang/Sema/Sema.h>
26 #include <clang/Sema/SemaDiagnostic.h>
27 #include <clang/Parse/Parser.h>
28 #include <clang/Parse/ParseAST.h>
30 #include <isl/ctx.h>
31 #include <isl/constraint.h>
33 #include "scan.h"
35 #include "config.h"
37 #define ARRAY_SIZE(array) (sizeof(array)/sizeof(*array))
39 using namespace std;
40 using namespace clang;
42 /* Called if we found something we didn't expect in one of the pragmas.
43 * We'll provide more informative warnings later.
45 static void unsupported(Preprocessor &PP, SourceLocation loc)
47 Diagnostic &diag = PP.getDiagnostics();
48 unsigned id = diag.getCustomDiagID(Diagnostic::Warning, "unsupported");
49 DiagnosticBuilder B = diag.Report(loc, id);
52 /* Set the lower and upper bounds on the given dimension of "set"
53 * to "lb" and "ub".
55 static __isl_give isl_set *set_bounds(__isl_take isl_set *set,
56 enum isl_dim_type type, int pos, int lb, int ub)
58 isl_constraint *c;
60 c = isl_inequality_alloc(isl_set_get_dim(set));
61 isl_constraint_set_coefficient_si(c, type, pos, 1);
62 isl_constraint_set_constant_si(c, -lb);
63 set = isl_set_add_constraint(set, c);
65 c = isl_inequality_alloc(isl_set_get_dim(set));
66 isl_constraint_set_coefficient_si(c, type, pos, -1);
67 isl_constraint_set_constant_si(c, ub);
68 set = isl_set_add_constraint(set, c);
70 return set;
73 static int get_int(const char *s)
75 return s[0] == '"' ? atoi(s + 1) : atoi(s);
78 /* Handle pragmas of the form
80 * #pragma value_bounds identifier lower_bound upper_bound
82 * For each such pragma, add a mapping from the ValueDecl corresponding
83 * to "identifier" to a set { [i] : lower_bound <= i <= upper_bound }
84 * to the map value_bounds.
86 struct PragmaValueBoundsHandler : public PragmaHandler {
87 Sema &sema;
88 isl_ctx *ctx;
89 map<ValueDecl *, isl_set *> &value_bounds;
91 PragmaValueBoundsHandler(isl_ctx *ctx, Sema &sema,
92 map<ValueDecl *, isl_set *> &value_bounds) :
93 PragmaHandler("value_bounds"), ctx(ctx), sema(sema),
94 value_bounds(value_bounds) {}
96 virtual void HandlePragma(Preprocessor &PP,
97 PragmaIntroducerKind Introducer,
98 Token &ScopTok) {
99 isl_dim *dim;
100 isl_set *set;
101 IdentifierInfo *name;
102 Decl *decl;
103 ValueDecl *vd;
104 Token token;
105 int lb;
106 int ub;
108 PP.Lex(token);
109 if (token.isNot(tok::identifier)) {
110 unsupported(PP, token.getLocation());
111 return;
114 name = token.getIdentifierInfo();
115 decl = sema.LookupSingleName(sema.TUScope, name,
116 token.getLocation(), Sema::LookupOrdinaryName);
117 vd = decl ? cast_or_null<ValueDecl>(decl) : NULL;
118 if (!vd) {
119 unsupported(PP, token.getLocation());
120 return;
123 PP.Lex(token);
124 if (!token.isLiteral()) {
125 unsupported(PP, token.getLocation());
126 return;
129 lb = get_int(token.getLiteralData());
131 PP.Lex(token);
132 if (!token.isLiteral()) {
133 unsupported(PP, token.getLocation());
134 return;
137 ub = get_int(token.getLiteralData());
139 dim = isl_dim_set_alloc(ctx, 0, 1);
140 set = isl_set_universe(dim);
141 set = set_bounds(set, isl_dim_set, 0, lb, ub);
143 value_bounds[vd] = set;
147 /* Handle pragmas of the form
149 * #pragma parameter identifier lower_bound upper_bound
151 * For each such pragma, intersect the context with the set
152 * [identifier] -> { [] : lower_bound <= identifier <= upper_bound }
154 struct PragmaParameterHandler : public PragmaHandler {
155 Sema &sema;
156 isl_set *&context;
158 PragmaParameterHandler(Sema &sema, isl_set *&context) :
159 PragmaHandler("parameter"), sema(sema), context(context) {}
161 virtual void HandlePragma(Preprocessor &PP,
162 PragmaIntroducerKind Introducer,
163 Token &ScopTok) {
164 isl_id *id;
165 isl_ctx *ctx = isl_set_get_ctx(context);
166 isl_dim *dim;
167 isl_set *set;
168 IdentifierInfo *name;
169 Decl *decl;
170 ValueDecl *vd;
171 Token token;
172 int lb;
173 int ub;
175 PP.Lex(token);
176 if (token.isNot(tok::identifier)) {
177 unsupported(PP, token.getLocation());
178 return;
181 name = token.getIdentifierInfo();
182 decl = sema.LookupSingleName(sema.TUScope, name,
183 token.getLocation(), Sema::LookupOrdinaryName);
184 vd = decl ? cast_or_null<ValueDecl>(decl) : NULL;
185 if (!vd) {
186 unsupported(PP, token.getLocation());
187 return;
190 PP.Lex(token);
191 if (!token.isLiteral()) {
192 unsupported(PP, token.getLocation());
193 return;
196 lb = get_int(token.getLiteralData());
198 PP.Lex(token);
199 if (!token.isLiteral()) {
200 unsupported(PP, token.getLocation());
201 return;
204 ub = get_int(token.getLiteralData());
206 id = isl_id_alloc(ctx, vd->getName().str().c_str(), vd);
207 dim = isl_dim_set_alloc(ctx, 1, 0);
208 dim = isl_dim_set_dim_id(dim, isl_dim_param, 0, id);
210 set = isl_set_universe(dim);
212 set = set_bounds(set, isl_dim_param, 0, lb, ub);
214 context = isl_set_intersect(context, set);
218 /* Handle pragmas of the form
220 * #pragma scop
222 * In particular, store the current location in loc.start.
224 struct PragmaScopHandler : public PragmaHandler {
225 ScopLoc &loc;
227 PragmaScopHandler(ScopLoc &loc) : PragmaHandler("scop"), loc(loc) {}
229 virtual void HandlePragma(Preprocessor &PP,
230 PragmaIntroducerKind Introducer,
231 Token &ScopTok) {
232 SourceManager &SM = PP.getSourceManager();
233 loc.start = SM.getFileOffset(ScopTok.getLocation());
237 /* Handle pragmas of the form
239 * #pragma endscop
241 * In particular, store the current location in loc.end.
243 struct PragmaEndScopHandler : public PragmaHandler {
244 ScopLoc &loc;
246 PragmaEndScopHandler(ScopLoc &loc) :
247 PragmaHandler("endscop"), loc(loc) {}
249 virtual void HandlePragma(Preprocessor &PP,
250 PragmaIntroducerKind Introducer,
251 Token &EndScopTok) {
252 SourceManager &SM = PP.getSourceManager();
253 loc.end = SM.getFileOffset(EndScopTok.getLocation());
257 /* Extract a pet_scop from the appropriate function.
258 * If "function" is not NULL, then we only extract a pet_scop if the
259 * name of the function matches.
260 * If "autodetect" is false, then we only extract if we have seen
261 * scop and endscop pragmas and if these are situated inside the function
262 * body.
264 struct PetASTConsumer : public ASTConsumer {
265 Preprocessor &PP;
266 ScopLoc &loc;
267 const char *function;
268 bool autodetect;
269 isl_ctx *ctx;
270 struct pet_scop *scop;
272 PetASTConsumer(isl_ctx *ctx, Preprocessor &PP, ScopLoc &loc,
273 const char *function, bool autodetect) :
274 ctx(ctx), PP(PP), loc(loc), scop(NULL),
275 function(function), autodetect(autodetect) { }
277 virtual void HandleTopLevelDecl(DeclGroupRef dg) {
278 DeclGroupRef::iterator it;
280 if (scop)
281 return;
282 for (it = dg.begin(); it != dg.end(); ++it) {
283 FunctionDecl *fd = dyn_cast<clang::FunctionDecl>(*it);
284 if (!fd)
285 continue;
286 if (!fd->hasBody())
287 continue;
288 if (function &&
289 fd->getNameInfo().getAsString() != function)
290 continue;
291 if (autodetect) {
292 PetScan ps(ctx, PP, loc, 1);
293 scop = ps.scan(fd);
294 if (scop)
295 break;
296 else
297 continue;
299 if (!loc.end)
300 continue;
301 SourceManager &SM = PP.getSourceManager();
302 if (SM.getFileOffset(fd->getLocStart()) > loc.end)
303 continue;
304 if (SM.getFileOffset(fd->getLocEnd()) < loc.start)
305 continue;
306 PetScan ps(ctx, PP, loc, 0);
307 scop = ps.scan(fd);
308 break;
313 static const char *ResourceDir = CLANG_PREFIX"/lib/clang/"CLANG_VERSION_STRING;
315 static const char *implicit_functions[] = {
316 "min", "max", "ceild", "floord"
319 static bool is_implicit(const IdentifierInfo *ident)
321 const char *name = ident->getNameStart();
322 for (int i = 0; i < ARRAY_SIZE(implicit_functions); ++i)
323 if (!strcmp(name, implicit_functions[i]))
324 return true;
325 return false;
328 /* Ignore implicit function declaration warnings on
329 * "min", "max", "ceild" and "floord" as we detect and handle these
330 * in PetScan.
332 struct MyDiagnosticPrinter : public TextDiagnosticPrinter {
333 MyDiagnosticPrinter(const DiagnosticOptions &DO) :
334 TextDiagnosticPrinter(llvm::errs(), DO) {}
335 virtual void HandleDiagnostic(Diagnostic::Level level,
336 const DiagnosticInfo &info) {
337 if (info.getID() == diag::ext_implicit_function_decl &&
338 info.getNumArgs() == 1 &&
339 info.getArgKind(0) == Diagnostic::ak_identifierinfo &&
340 is_implicit(info.getArgIdentifier(0)))
341 /* ignore warning */;
342 else
343 TextDiagnosticPrinter::HandleDiagnostic(level, info);
347 /* Extract a pet_scop from the C source file called "filename".
348 * If "function" is not NULL, extract the pet_scop from the function
349 * with that name.
350 * If "autodetect" is set, extract any pet_scop we can find.
351 * Otherwise, extract the pet_scop from the region delimited
352 * by "scop" and "endscop" pragmas.
354 * We first set up the clang parser and then try to extract the
355 * pet_scop from the appropriate function in PetASTConsumer.
356 * If we have found a pet_scop, we add the context and value_bounds
357 * constraints specified through pragmas.
359 struct pet_scop *pet_scop_extract_from_C_source(isl_ctx *ctx,
360 const char *filename, const char *function, int autodetect)
362 isl_dim *dim;
363 isl_set *context;
364 map<ValueDecl *, isl_set *> value_bounds;
365 map<ValueDecl *, isl_set *>::iterator vb_it;
367 FileSystemOptions FO;
368 FileManager FM(FO);
369 const FileEntry *file = FM.getFile(filename);
370 if (!file)
371 isl_die(ctx, isl_error_unknown, "unable to open file",
372 return NULL);
374 llvm::IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
375 DiagnosticOptions DO;
376 Diagnostic Diags(DiagID, new MyDiagnosticPrinter(DO));
377 TargetOptions TO;
378 TO.Triple = llvm::sys::getHostTriple();
379 TargetInfo *target = TargetInfo::CreateTargetInfo(Diags, TO);
380 SourceManager SM(Diags, FM);
381 HeaderSearch HS(FM);
382 LangOptions LO;
383 CompilerInvocation::setLangDefaults(LO, IK_C,
384 LangStandard::lang_unspecified);
385 Preprocessor PP(Diags, LO, *target, SM, HS);
386 HeaderSearchOptions HSO;
387 PreprocessorOptions PPO;
388 FrontendOptions FEO;
389 HSO.ResourceDir = ResourceDir;
390 InitializePreprocessor(PP, PPO, HSO, FEO);
392 ScopLoc loc;
394 if (!autodetect) {
395 PP.AddPragmaHandler(new PragmaScopHandler(loc));
396 PP.AddPragmaHandler(new PragmaEndScopHandler(loc));
399 SM.createMainFileID(file);
401 ASTContext ast_context(LO, PP.getSourceManager(),
402 *target, PP.getIdentifierTable(), PP.getSelectorTable(),
403 PP.getBuiltinInfo(), 0);
404 PetASTConsumer consumer(ctx, PP, loc, function, autodetect);
405 Sema sema(PP, ast_context, consumer);
407 dim = isl_dim_set_alloc(ctx, 0, 0);
408 context = isl_set_universe(dim);
409 PP.AddPragmaHandler(new PragmaParameterHandler(sema, context));
410 PP.AddPragmaHandler(new PragmaValueBoundsHandler(ctx, sema, value_bounds));
412 Diags.getClient()->BeginSourceFile(LO, &PP);
413 ParseAST(sema);
414 Diags.getClient()->EndSourceFile();
416 delete target;
417 llvm::llvm_shutdown();
419 if (consumer.scop)
420 consumer.scop->context = isl_set_intersect(context,
421 consumer.scop->context);
422 else
423 isl_set_free(context);
425 if (consumer.scop) {
426 for (int i = 0; i < consumer.scop->n_array; ++i) {
427 isl_id *id;
428 ValueDecl *decl;
429 pet_array *array = consumer.scop->arrays[i];
431 id = isl_set_get_tuple_id(array->extent);
432 decl = (ValueDecl *)isl_id_get_user(id);
433 isl_id_free(id);
435 vb_it = value_bounds.find(decl);
436 if (vb_it != value_bounds.end())
437 array->value_bounds = isl_set_copy(vb_it->second);
441 for (vb_it = value_bounds.begin(); vb_it != value_bounds.end(); vb_it++)
442 isl_set_free(vb_it->second);
444 return consumer.scop;