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