12966Swollman/* 250477Speter * Copyright 2011 Sven Verdoolaege. All rights reserved. 31590Srgrimes * 44699Sjkh * Redistribution and use in source and binary forms, with or without 534706Sbde * modification, are permitted provided that the following conditions 650634Speter * are met: 787809Smarkm * 81930Swollman * 1. Redistributions of source code must retain the above copyright 91930Swollman * notice, this list of conditions and the following disclaimer. 1038653Sgpalmer * 1196630Stjr * 2. Redistributions in binary form must reproduce the above 1238653Sgpalmer * copyright notice, this list of conditions and the following 1391706Sobrien * disclaimer in the documentation and/or other materials provided 1438653Sgpalmer * with the distribution. 1538653Sgpalmer * 1638653Sgpalmer * THIS SOFTWARE IS PROVIDED BY SVEN VERDOOLAEGE ''AS IS'' AND ANY 1757013Sobrien * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1878562Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 1938653Sgpalmer * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SVEN VERDOOLAEGE OR 2038653Sgpalmer * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 2138653Sgpalmer * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2238653Sgpalmer * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 2338653Sgpalmer * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2438653Sgpalmer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2538653Sgpalmer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2638653Sgpalmer * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2738653Sgpalmer * 2838653Sgpalmer * The views and conclusions contained in the software and documentation 2938653Sgpalmer * are those of the authors and should not be interpreted as 3038653Sgpalmer * representing official policies, either expressed or implied, of 3138653Sgpalmer * Sven Verdoolaege. 3238653Sgpalmer */ 3338653Sgpalmer 3438653Sgpalmer#include "isl_config.h" 3538653Sgpalmer 3695926Stjr#include <assert.h> 3738653Sgpalmer#include <iostream> 3838653Sgpalmer#include <llvm/Support/raw_ostream.h> 3938653Sgpalmer#include <llvm/Support/CommandLine.h> 4038653Sgpalmer#include <llvm/Support/Host.h> 4138653Sgpalmer#include <llvm/Support/ManagedStatic.h> 4240826Sjoerg#include <clang/AST/ASTContext.h> 4338653Sgpalmer#include <clang/AST/ASTConsumer.h> 4438653Sgpalmer#include <clang/Basic/FileSystemOptions.h> 4538653Sgpalmer#include <clang/Basic/FileManager.h> 4638653Sgpalmer#include <clang/Basic/TargetOptions.h> 4738653Sgpalmer#include <clang/Basic/TargetInfo.h> 4838653Sgpalmer#include <clang/Basic/Version.h> 4938653Sgpalmer#include <clang/Driver/Compilation.h> 5038653Sgpalmer#include <clang/Driver/Driver.h> 5138653Sgpalmer#include <clang/Driver/Tool.h> 5238653Sgpalmer#include <clang/Frontend/CompilerInstance.h> 5338653Sgpalmer#include <clang/Frontend/CompilerInvocation.h> 5441036Sdima#ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H 5563499Sps#include <clang/Basic/DiagnosticOptions.h> 5638653Sgpalmer#else 5738653Sgpalmer#include <clang/Frontend/DiagnosticOptions.h> 5838653Sgpalmer#endif 5948839Ssimokawa#include <clang/Frontend/TextDiagnosticPrinter.h> 6038653Sgpalmer#include <clang/Frontend/Utils.h> 6165627Snectar#include <clang/Lex/HeaderSearch.h> 6238653Sgpalmer#include <clang/Lex/Preprocessor.h> 6338653Sgpalmer#include <clang/Parse/ParseAST.h> 6438653Sgpalmer#include <clang/Sema/Sema.h> 6538653Sgpalmer 6638653Sgpalmer#include "extract_interface.h" 6738653Sgpalmer#include "python.h" 6838653Sgpalmer 6938653Sgpalmerusing namespace std; 7062813Speterusing namespace clang; 7138653Sgpalmerusing namespace clang::driver; 7238653Sgpalmer 7338653Sgpalmerstatic llvm::cl::opt<string> InputFilename(llvm::cl::Positional, 7438653Sgpalmer llvm::cl::Required, llvm::cl::desc("<input file>")); 7593619Sjakestatic llvm::cl::list<string> Includes("I", 7638653Sgpalmer llvm::cl::desc("Header search path"), 7738653Sgpalmer llvm::cl::value_desc("path"), llvm::cl::Prefix); 7838653Sgpalmer 7939614Sbdestatic const char *ResourceDir = CLANG_PREFIX"/lib/clang/"CLANG_VERSION_STRING; 8038653Sgpalmer 8160789Sps/* Does decl have an attribute of the following form? 8260789Sps * 8360789Sps * __attribute__((annotate("name"))) 8438653Sgpalmer */ 8538653Sgpalmerbool has_annotation(Decl *decl, const char *name) 8638653Sgpalmer{ 8738653Sgpalmer if (!decl->hasAttrs()) 8838653Sgpalmer return false; 8938653Sgpalmer 9038653Sgpalmer AttrVec attrs = decl->getAttrs(); 9138653Sgpalmer for (AttrVec::const_iterator i = attrs.begin() ; i != attrs.end(); ++i) { 9238653Sgpalmer const AnnotateAttr *ann = dyn_cast<AnnotateAttr>(*i); 9338653Sgpalmer if (!ann) 9438653Sgpalmer continue; 9538653Sgpalmer if (ann->getAnnotation().str() == name) 9638653Sgpalmer return true; 9738653Sgpalmer } 9838653Sgpalmer 9939614Sbde return false; 10038653Sgpalmer} 10138653Sgpalmer 10238653Sgpalmer/* Is decl marked as exported? 10338653Sgpalmer */ 10438653Sgpalmerstatic bool is_exported(Decl *decl) 10538653Sgpalmer{ 10639914Sdfr return has_annotation(decl, "isl_export"); 10738653Sgpalmer} 10838653Sgpalmer 10938653Sgpalmer/* Collect all types and functions that are annotated "isl_export" 11038653Sgpalmer * in "types" and "function". 11176273Sbrian * 11238653Sgpalmer * We currently only consider single declarations. 11338653Sgpalmer */ 11438653Sgpalmerstruct MyASTConsumer : public ASTConsumer { 11538653Sgpalmer set<RecordDecl *> types; 11638653Sgpalmer set<FunctionDecl *> functions; 11738653Sgpalmer 11838653Sgpalmer virtual HandleTopLevelDeclReturn HandleTopLevelDecl(DeclGroupRef D) { 11938653Sgpalmer Decl *decl; 12038653Sgpalmer 12138653Sgpalmer if (!D.isSingleDecl()) 12238653Sgpalmer return HandleTopLevelDeclContinue; 12338653Sgpalmer decl = D.getSingleDecl(); 12438653Sgpalmer if (!is_exported(decl)) 12538653Sgpalmer return HandleTopLevelDeclContinue; 12695332Sobrien switch (decl->getKind()) { 12738653Sgpalmer case Decl::Record: 12838653Sgpalmer types.insert(cast<RecordDecl>(decl)); 12938653Sgpalmer break; 13095332Sobrien case Decl::Function: 13138653Sgpalmer functions.insert(cast<FunctionDecl>(decl)); 13238653Sgpalmer break; 13338653Sgpalmer default: 13438653Sgpalmer break; 13538653Sgpalmer } 13638653Sgpalmer return HandleTopLevelDeclContinue; 13738653Sgpalmer } 13838653Sgpalmer}; 13938653Sgpalmer 14045701Sdes#ifdef USE_ARRAYREF 14138653Sgpalmer 14238653Sgpalmer#ifdef HAVE_CXXISPRODUCTION 14338653Sgpalmerstatic Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 14438653Sgpalmer{ 14541035Sdima return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 14638653Sgpalmer "", false, false, Diags); 14738653Sgpalmer} 14838653Sgpalmer#elif defined(HAVE_ISPRODUCTION) 14938653Sgpalmerstatic Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 15038653Sgpalmer{ 15138653Sgpalmer return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 15288277Smarkm "", false, Diags); 15338653Sgpalmer} 15438653Sgpalmer#else 15538653Sgpalmerstatic Driver *construct_driver(const char *binary, DiagnosticsEngine &Diags) 15638653Sgpalmer{ 15738653Sgpalmer return new Driver(binary, llvm::sys::getDefaultTargetTriple(), 15863437Ssheldonh "", Diags); 15939928Ssef} 16038653Sgpalmer#endif 16138653Sgpalmer 16238653Sgpalmer/* Create a CompilerInvocation object that stores the command line 16338653Sgpalmer * arguments constructed by the driver. 16438653Sgpalmer * The arguments are mainly useful for setting up the system include 16538653Sgpalmer * paths on newer clangs and on some platforms. 16638653Sgpalmer */ 16738653Sgpalmerstatic CompilerInvocation *construct_invocation(const char *filename, 16838653Sgpalmer DiagnosticsEngine &Diags) 16938653Sgpalmer{ 17062642Sn_hibma const char *binary = CLANG_PREFIX"/bin/clang"; 17138653Sgpalmer const llvm::OwningPtr<Driver> driver(construct_driver(binary, Diags)); 17238653Sgpalmer std::vector<const char *> Argv; 17338653Sgpalmer Argv.push_back(binary); 17438653Sgpalmer Argv.push_back(filename); 17538653Sgpalmer const llvm::OwningPtr<Compilation> compilation( 17638653Sgpalmer driver->BuildCompilation(llvm::ArrayRef<const char *>(Argv))); 17741062Sbde JobList &Jobs = compilation->getJobs(); 17838653Sgpalmer 17938653Sgpalmer Command *cmd = cast<Command>(*Jobs.begin()); 18038653Sgpalmer if (strcmp(cmd->getCreator().getName(), "clang")) 18138653Sgpalmer return NULL; 18238653Sgpalmer 18338653Sgpalmer const ArgStringList *args = &cmd->getArguments(); 18438653Sgpalmer 18538653Sgpalmer CompilerInvocation *invocation = new CompilerInvocation; 18638653Sgpalmer CompilerInvocation::CreateFromArgs(*invocation, args->data() + 1, 18738653Sgpalmer args->data() + args->size(), 18838653Sgpalmer Diags); 18938653Sgpalmer return invocation; 19038653Sgpalmer} 19138653Sgpalmer 19238653Sgpalmer#else 19338653Sgpalmer 19438653Sgpalmerstatic CompilerInvocation *construct_invocation(const char *filename, 19538653Sgpalmer DiagnosticsEngine &Diags) 1961590Srgrimes{ 19774813Sru return NULL; 19874813Sru} 19974813Sru 20039614Sbde#endif 20134554Sjb 20234554Sjb#ifdef HAVE_BASIC_DIAGNOSTICOPTIONS_H 20334554Sjb 20453935Speterstatic TextDiagnosticPrinter *construct_printer(void) 20553909Speter{ 20653935Speter return new TextDiagnosticPrinter(llvm::errs(), new DiagnosticOptions()); 20753909Speter} 20853909Speter 20953909Speter#else 21053909Speter 21186252Sgshapirostatic TextDiagnosticPrinter *construct_printer(void) 21286252Sgshapiro{ 21386252Sgshapiro DiagnosticOptions DO; 21486252Sgshapiro return new TextDiagnosticPrinter(llvm::errs(), DO); 21534554Sjb} 21636064Sjb 21738653Sgpalmer#endif 21894525Sru 21938653Sgpalmer#ifdef CREATETARGETINFO_TAKES_POINTER 22052406Sbp 22152702Sbpstatic TargetInfo *create_target_info(CompilerInstance *Clang, 22238653Sgpalmer DiagnosticsEngine &Diags) 22338653Sgpalmer{ 22438653Sgpalmer TargetOptions &TO = Clang->getTargetOpts(); 22538653Sgpalmer TO.Triple = llvm::sys::getDefaultTargetTriple(); 22687960Ssheldonh return TargetInfo::CreateTargetInfo(Diags, &TO); 22738653Sgpalmer} 22841035Sdima 22936064Sjb#else 23034554Sjb 23156279Sobrienstatic TargetInfo *create_target_info(CompilerInstance *Clang, 23256279Sobrien DiagnosticsEngine &Diags) 23356279Sobrien{ 23456279Sobrien TargetOptions &TO = Clang->getTargetOpts(); 23595763Sjake TO.Triple = llvm::sys::getDefaultTargetTriple(); 23695763Sjake return TargetInfo::CreateTargetInfo(Diags, TO); 23795763Sjake} 23895763Sjake 23994231Sobrien#endif 24094231Sobrien 24193932Speter#ifdef CREATEDIAGNOSTICS_TAKES_ARG 24293932Speter 24394231Sobrienstatic void create_diagnostics(CompilerInstance *Clang) 24494231Sobrien{ 24594231Sobrien Clang->createDiagnostics(0, NULL, construct_printer()); 24693932Speter} 24781878Speter 24881054Ssobomax#else 24981054Ssobomax 25081054Ssobomaxstatic void create_diagnostics(CompilerInstance *Clang) 2511590Srgrimes{ 252 Clang->createDiagnostics(construct_printer()); 253} 254 255#endif 256 257#ifdef ADDPATH_TAKES_4_ARGUMENTS 258 259void add_path(HeaderSearchOptions &HSO, string Path) 260{ 261 HSO.AddPath(Path, frontend::Angled, false, false); 262} 263 264#else 265 266void add_path(HeaderSearchOptions &HSO, string Path) 267{ 268 HSO.AddPath(Path, frontend::Angled, true, false, false); 269} 270 271#endif 272 273int main(int argc, char *argv[]) 274{ 275 llvm::cl::ParseCommandLineOptions(argc, argv); 276 277 CompilerInstance *Clang = new CompilerInstance(); 278 create_diagnostics(Clang); 279 DiagnosticsEngine &Diags = Clang->getDiagnostics(); 280 Diags.setSuppressSystemWarnings(true); 281 CompilerInvocation *invocation = 282 construct_invocation(InputFilename.c_str(), Diags); 283 if (invocation) 284 Clang->setInvocation(invocation); 285 Clang->createFileManager(); 286 Clang->createSourceManager(Clang->getFileManager()); 287 TargetInfo *target = create_target_info(Clang, Diags); 288 Clang->setTarget(target); 289 CompilerInvocation::setLangDefaults(Clang->getLangOpts(), IK_C, 290 LangStandard::lang_unspecified); 291 HeaderSearchOptions &HSO = Clang->getHeaderSearchOpts(); 292 LangOptions &LO = Clang->getLangOpts(); 293 PreprocessorOptions &PO = Clang->getPreprocessorOpts(); 294 HSO.ResourceDir = ResourceDir; 295 296 for (int i = 0; i < Includes.size(); ++i) 297 add_path(HSO, Includes[i]); 298 299 PO.addMacroDef("__isl_give=__attribute__((annotate(\"isl_give\")))"); 300 PO.addMacroDef("__isl_keep=__attribute__((annotate(\"isl_keep\")))"); 301 PO.addMacroDef("__isl_take=__attribute__((annotate(\"isl_take\")))"); 302 PO.addMacroDef("__isl_export=__attribute__((annotate(\"isl_export\")))"); 303 PO.addMacroDef("__isl_constructor=__attribute__((annotate(\"isl_constructor\"))) __attribute__((annotate(\"isl_export\")))"); 304 PO.addMacroDef("__isl_subclass(super)=__attribute__((annotate(\"isl_subclass(\" #super \")\"))) __attribute__((annotate(\"isl_export\")))"); 305 306 Clang->createPreprocessor(); 307 Preprocessor &PP = Clang->getPreprocessor(); 308 309 PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), LO); 310 311 const FileEntry *file = Clang->getFileManager().getFile(InputFilename); 312 assert(file); 313 Clang->getSourceManager().createMainFileID(file); 314 315 Clang->createASTContext(); 316 MyASTConsumer consumer; 317 Sema *sema = new Sema(PP, Clang->getASTContext(), consumer); 318 319 Diags.getClient()->BeginSourceFile(LO, &PP); 320 ParseAST(*sema); 321 Diags.getClient()->EndSourceFile(); 322 323 generate_python(consumer.types, consumer.functions); 324 325 delete sema; 326 delete Clang; 327 llvm::llvm_shutdown(); 328 329 return 0; 330} 331