Use clang's preprocessor, rather than forking a process to run cpp

on Mac/Linux (and not having a built-in preprocessor solution at all
on Windows.)  Fixes issue #32.
This commit is contained in:
Pete Couperus
2011-07-04 08:35:31 +01:00
committed by Matt Pharr
parent fe7717ab67
commit fac50ba454
3 changed files with 81 additions and 75 deletions

View File

@@ -2,9 +2,17 @@
# ispc Makefile
#
ARCH = $(shell uname)
ARCH_OS = $(shell uname)
ARCH_TYPE = $(shell arch)
CLANG=clang
CLANG_LIBS = -lclangFrontendTool -lclangFrontend -lclangDriver \
-lclangSerialization -lclangCodeGen -lclangParse -lclangSema \
-lclangStaticAnalyzerFrontend -lclangStaticAnalyzerCheckers \
-lclangStaticAnalyzerCore \
-lclangAnalysis -lclangIndex -lclangRewrite \
-lclangAST -lclangLex -lclangBasic
LLVM_LIBS=$(shell llvm-config --ldflags --libs) -lpthread -ldl
LLVM_CXXFLAGS=$(shell llvm-config --cppflags)
LLVM_VERSION_DEF=-DLLVM_$(shell llvm-config --version | sed s/\\./_/)
@@ -18,10 +26,14 @@ CXXFLAGS=-g3 $(LLVM_CXXFLAGS) -I. -Iobjs/ -Wall $(LLVM_VERSION_DEF) \
-DBUILD_DATE="\"$(BUILD_DATE)\"" -DBUILD_VERSION="\"$(BUILD_VERSION)\""
LDFLAGS=
ifeq ($(ARCH),Linux)
ifeq ($(ARCH_OS),Linux)
# try to link everything statically under Linux (including libstdc++) so
# that the binaries we generate will be portable across distributions...
LDFLAGS=-static -L/usr/lib/gcc/x86_64-linux-gnu/4.4
ifeq ($(ARCH_TYPE),x86_64)
LDFLAGS=-static -L/usr/lib/gcc/x86_64-linux-gnu/4.4
else
LDFLAGS=-L/usr/lib/gcc/i686-redhat-linux/4.6.0
endif
endif
LEX=flex
@@ -68,7 +80,7 @@ doxygen:
ispc: print_llvm_src dirs $(OBJS)
@echo Creating ispc executable
@$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(LLVM_LIBS)
@$(CXX) $(LDFLAGS) -o $@ $(OBJS) $(CLANG_LIBS) $(LLVM_LIBS)
ispc_test: dirs ispc_test.cpp
@echo Creating ispc_test executable

View File

@@ -70,6 +70,7 @@
#include <llvm/Instructions.h>
#include <llvm/Intrinsics.h>
#include <llvm/Support/FormattedStream.h>
#include <llvm/Support/FileUtilities.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Target/TargetRegistry.h>
#include <llvm/Target/TargetSelect.h>
@@ -79,6 +80,9 @@
#include <llvm/PassManager.h>
#include <llvm/Analysis/Verifier.h>
#include <llvm/Support/CFG.h>
#include <clang/Frontend/CompilerInstance.h>
#include <clang/Frontend/Utils.h>
#include <clang/Basic/TargetInfo.h>
#ifndef LLVM_2_8
#include <llvm/Support/ToolOutputFile.h>
#include <llvm/Support/Host.h>
@@ -133,8 +137,9 @@ extern FILE *yyin;
extern int yyparse();
typedef struct yy_buffer_state *YY_BUFFER_STATE;
extern void yy_switch_to_buffer(YY_BUFFER_STATE);
extern YY_BUFFER_STATE yy_scan_string(const char *);
extern YY_BUFFER_STATE yy_create_buffer(FILE *, int);
extern void yy_delete_buffer(YY_BUFFER_STATE);
int
Module::CompileFile() {
@@ -146,63 +151,17 @@ Module::CompileFile() {
bool runPreprocessor = g->runCPP;
// We currently require that the user run the preprocessor by hand on
// windows and pipe the result to ispc.
// FIXME: It'd be nice to run cl.exe for them to do this, if it's available
// in the PATH...
#ifdef ISPC_IS_WINDOWS
runPreprocessor = false;
#endif // ISPC_IS_WINDOWS
// The FILE handle that we'll point the parser at. This may end up
// being stdin, an opened file on disk, or the piped output from the
// preprocessor.
FILE *f;
if (runPreprocessor) {
// Before we run the preprocessor, make sure that file exists and
// we can read it since otherwise we get a pretty obscure/unhelpful
// error message from cpp
if (filename) {
f = fopen(filename, "r");
if (f == NULL) {
perror(filename);
return 1;
}
fclose(f);
}
// Go ahead and construct a command string to run the preprocessor.
// First, concatentate all of the -D statements from the original
// ispc command line so that we can pass them along to cpp.
std::string cppDefs;
for (unsigned int i = 0; i < g->cppArgs.size(); ++i) {
cppDefs += g->cppArgs[i];
cppDefs += ' ';
}
#ifdef ISPC_IS_WINDOWS
// For now, this code should never be reached
FATAL("Need to implement code to run the preprocessor for windows");
#else // ISPC_IS_WINDOWS
char *cmd = NULL;
if (asprintf(&cmd, "/usr/bin/cpp -DISPC=1 -DPI=3.1415926536 %s %s",
cppDefs.c_str(), filename ? filename : "-") == -1) {
fprintf(stderr, "Unable to allocate memory in asprintf()?!\n");
exit(1);
}
f = popen(cmd, "r");
free(cmd);
if (f == NULL) {
perror(filename ? filename : "<stdin>");
return 1;
}
#endif // ISPC_IS_WINDOWS
std::string buffer;
llvm::raw_string_ostream os(buffer);
execPreprocessor(filename, &os);
YY_BUFFER_STATE strbuf = yy_scan_string(os.str().c_str());
yyparse();
yy_delete_buffer(strbuf);
}
else {
// No preprocessor, just open up the file if it's not stdin..
FILE* f = NULL;
if (filename == NULL)
f = stdin;
else {
@@ -212,24 +171,11 @@ Module::CompileFile() {
return 1;
}
}
}
// Here is where the magic happens: parse the file, build the AST, etc.
// This in turn will lead to calls back to Module::AddFunction(),
// etc...
yyin = f;
yy_switch_to_buffer(yy_create_buffer(yyin, 4096));
yyparse();
if (runPreprocessor) {
#ifdef ISPC_IS_WINDOWS
FATAL("need to implement this for windows as well");
#else
pclose(f);
#endif // ISPC_IS_WINDOWS
}
else
yyin = f;
yy_switch_to_buffer(yy_create_buffer(yyin, 4096));
yyparse();
fclose(f);
}
if (errorCount == 0)
Optimize(module, g->opt.level);
@@ -1430,3 +1376,44 @@ Module::writeHeader(const char *fn) {
fclose(f);
return true;
}
void
Module::execPreprocessor(const char* infilename, llvm::raw_string_ostream* ostream) const
{
clang::CompilerInstance inst;
std::string error;
inst.createFileManager();
inst.createDiagnostics(0, NULL);
clang::TargetOptions& options = inst.getTargetOpts();
llvm::Triple triple(module->getTargetTriple());
if (triple.getTriple().empty())
triple.setTriple(llvm::sys::getHostTriple());
options.Triple = triple.getTriple();
clang::TargetInfo* target
= clang::TargetInfo::CreateTargetInfo(inst.getDiagnostics(), options);
inst.setTarget(target);
inst.createSourceManager(inst.getFileManager());
inst.InitializeSourceManager(infilename);
clang::PreprocessorOptions& opts = inst.getPreprocessorOpts();
//Add defs for ISPC and PI
opts.addMacroDef("ISPC");
opts.addMacroDef("PI=3.1415926535");
for (unsigned int i = 0; i < g->cppArgs.size(); ++i) {
//Sanity Check, should really begin with -D
if (g->cppArgs[i].substr(0,2) == "-D") {
opts.addMacroDef(g->cppArgs[i].substr(2));
}
}
inst.createPreprocessor();
clang::DoPrintPreprocessedInput(inst.getPreprocessor(),
ostream, inst.getPreprocessorOutputOpts());
}

View File

@@ -41,6 +41,11 @@
#include "ispc.h"
namespace llvm
{
class raw_string_ostream;
}
class Module {
public:
/** The name of the source file being compiled should be passed as the
@@ -108,6 +113,8 @@ private:
bool writeHeader(const char *filename);
bool writeObjectFileOrAssembly(OutputType outputType, const char *filename);
void execPreprocessor(const char *infilename, llvm::raw_string_ostream* ostream) const;
};
#endif // ISPC_MODULE_H