Mercurial > projects > ldc
changeset 989:420ef073448d
Forgot new files that were supposed to be in last commit.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Thu, 26 Feb 2009 14:13:27 +0100 |
parents | 2667e3a145be |
children | 2137797748a8 |
files | gen/abi.cpp gen/abi.h gen/main.cpp |
diffstat | 3 files changed, 1099 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/abi.cpp Thu Feb 26 14:13:27 2009 +0100 @@ -0,0 +1,225 @@ +#include "gen/llvm.h" + +#include "mars.h" + +#include "gen/irstate.h" +#include "gen/llvmhelpers.h" +#include "gen/tollvm.h" +#include "gen/abi.h" + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +///////////////////// baseclass //////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// FIXME: Would be nice to come up a better and faster way to do this, right +// now I'm more worried about actually making this abstraction work at all ... +// It's definitely way overkill with the amount of return value rewrites we +// have right now, but I expect this to change with proper x86-64 abi support + +TargetABI::TargetABI() +{ +} + +llvm::Value* TargetABI::getRet(TypeFunction* tf, llvm::Value* io) +{ + if (ABIRetRewrite* r = findRetRewrite(tf)) + { + return r->get(io); + } + return io; +} + +llvm::Value* TargetABI::putRet(TypeFunction* tf, llvm::Value* io) +{ + if (ABIRetRewrite* r = findRetRewrite(tf)) + { + return r->put(io); + } + return io; +} + +const llvm::Type* TargetABI::getRetType(TypeFunction* tf, const llvm::Type* t) +{ + if (ABIRetRewrite* r = findRetRewrite(tf)) + { + return r->type(t); + } + return t; +} + +ABIRetRewrite * TargetABI::findRetRewrite(TypeFunction * tf) +{ + size_t n = retOps.size(); + if (n) + for (size_t i = 0; i < n; i++) + { + if (retOps[i]->test(tf)) + return retOps[i]; + } + return NULL; +} + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +///////////////////// X86 //////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +// simply swap of real/imag parts for proper x87 complex abi +struct X87_complex_swap : ABIRetRewrite +{ + LLValue* get(LLValue* v) + { + return DtoAggrPairSwap(v); + } + LLValue* put(LLValue* v) + { + return DtoAggrPairSwap(v); + } + const LLType* type(const LLType* t) + { + return t; + } + bool test(TypeFunction* tf) + { + return (tf->next->toBasetype()->iscomplex()); + } +}; + +////////////////////////////////////////////////////////////////////////////// + +struct X86TargetABI : TargetABI +{ + X86TargetABI() + { + retOps.push_back(new X87_complex_swap); + } + + bool returnInArg(Type* t) + { + Type* rt = t->toBasetype(); + return (rt->ty == Tstruct); + } + + bool passByRef(Type* t) + { + t = t->toBasetype(); + return (t->ty == Tstruct || t->ty == Tsarray); + } +}; + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +/////////////////// X86-64 ////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +struct X86_64_cfloat_rewrite : ABIRetRewrite +{ + // {double} -> {float,float} + LLValue* get(LLValue* in) + { + // extract double + LLValue* v = gIR->ir->CreateExtractValue(in, 0); + // cast to i64 + v = gIR->ir->CreateBitCast(v, LLType::Int64Ty); + + // extract real part + LLValue* rpart = gIR->ir->CreateTrunc(v, LLType::Int32Ty); + rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re"); + + // extract imag part + LLValue* ipart = gIR->ir->CreateLShr(v, LLConstantInt::get(LLType::Int64Ty, 32, false)); + ipart = gIR->ir->CreateTrunc(ipart, LLType::Int32Ty); + ipart = gIR->ir->CreateBitCast(ipart, LLType::FloatTy, ".im"); + + // return {float,float} aggr pair with same bits + return DtoAggrPair(rpart, ipart, ".final_cfloat"); + } + + // {float,float} -> {double} + LLValue* put(LLValue* v) + { + // extract real + LLValue* r = gIR->ir->CreateExtractValue(v, 0); + // cast to i32 + r = gIR->ir->CreateBitCast(r, LLType::Int32Ty); + // zext to i64 + r = gIR->ir->CreateZExt(r, LLType::Int64Ty); + + // extract imag + LLValue* i = gIR->ir->CreateExtractValue(v, 1); + // cast to i32 + i = gIR->ir->CreateBitCast(i, LLType::Int32Ty); + // zext to i64 + i = gIR->ir->CreateZExt(i, LLType::Int64Ty); + // shift up + i = gIR->ir->CreateShl(i, LLConstantInt::get(LLType::Int64Ty, 32, false)); + + // combine + v = gIR->ir->CreateOr(r, i); + + // cast to double + v = gIR->ir->CreateBitCast(v, LLType::DoubleTy); + + // return {double} + const LLType* t = LLStructType::get(LLType::DoubleTy, 0); + LLValue* undef = llvm::UndefValue::get(t); + return gIR->ir->CreateInsertValue(undef, v, 0); + } + + // {float,float} -> {double} + const LLType* type(const LLType* t) + { + return LLStructType::get(LLType::DoubleTy, 0); + } + + // test if rewrite applies to function + bool test(TypeFunction* tf) + { + return (tf->next->toBasetype() == Type::tcomplex32); + } +}; + +////////////////////////////////////////////////////////////////////////////// + +struct X86_64TargetABI : TargetABI +{ + X86_64TargetABI() + { + retOps.push_back(new X86_64_cfloat_rewrite); + } + + bool returnInArg(Type* t) + { + Type* rt = t->toBasetype(); + return (rt->ty == Tstruct); + } + + bool passByRef(Type* t) + { + t = t->toBasetype(); + return (t->ty == Tstruct || t->ty == Tsarray); + } +}; + +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////// + +TargetABI * TargetABI::getTarget() +{ + switch(global.params.cpu) + { + case ARCHx86: + return new X86TargetABI; + case ARCHx86_64: + return new X86_64TargetABI; + default: + return NULL; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/abi.h Thu Feb 26 14:13:27 2009 +0100 @@ -0,0 +1,49 @@ +#ifndef __LDC_GEN_ABI_H__ +#define __LDC_GEN_ABI_H__ + +#include <vector> + +struct Type; +namespace llvm +{ + class Type; + class Value; +} + +// return rewrite rule +struct ABIRetRewrite +{ + // get original value from rewritten one + virtual LLValue* get(LLValue* v) = 0; + + // rewrite original value + virtual LLValue* put(LLValue* v) = 0; + + // returns target type of this rewrite + virtual const LLType* type(const LLType* t) = 0; + + // test if rewrite applies + virtual bool test(TypeFunction* tf) = 0; +}; + + +// interface called by codegen +struct TargetABI +{ + static TargetABI* getTarget(); + + TargetABI(); + + const llvm::Type* getRetType(TypeFunction* tf, const llvm::Type* t); + llvm::Value* getRet(TypeFunction* tf, llvm::Value* v); + llvm::Value* putRet(TypeFunction* tf, llvm::Value* v); + + virtual bool returnInArg(Type* t) = 0; + virtual bool passByRef(Type* t) = 0; + +protected: + std::vector<ABIRetRewrite*> retOps; + ABIRetRewrite* findRetRewrite(TypeFunction* tf); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gen/main.cpp Thu Feb 26 14:13:27 2009 +0100 @@ -0,0 +1,825 @@ +// Pulled out of dmd/mars.c + +// some things are taken from llvm's llc tool +// which uses the llvm license + +#include "gen/llvm.h" +#include "llvm/Target/SubtargetFeature.h" +#include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetMachineRegistry.h" +#include "llvm/LinkAllVMCore.h" + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> +#include <limits.h> + +#if POSIX +#include <errno.h> +#elif _WIN32 +#include <windows.h> +#endif + +#include "mem.h" +#include "root.h" + +#include "mars.h" +#include "module.h" +#include "mtype.h" +#include "id.h" +#include "cond.h" + +#include "gen/logger.h" +#include "gen/linker.h" +#include "gen/irstate.h" + +#include "gen/cl_options.h" +#include "gen/cl_helpers.h" +using namespace opts; + +extern void getenv_setargv(const char *envvar, int *pargc, char** *pargv); +extern void backend_init(); +extern void backend_term(); + +static cl::opt<bool> noDefaultLib("nodefaultlib", + cl::desc("Don't add a default library for linking implicitly"), + cl::ZeroOrMore); + +static ArrayAdapter impPathsStore("I", global.params.imppath); +static cl::list<std::string, ArrayAdapter> importPaths("I", + cl::desc("Where to look for imports"), + cl::value_desc("path"), + cl::location(impPathsStore), + cl::Prefix); + +static ArrayAdapter defaultLibStore("defaultlib", global.params.defaultlibnames); +static cl::list<std::string, ArrayAdapter> defaultlibs("defaultlib", + cl::desc("Set default libraries for non-debug build"), + cl::value_desc("lib,..."), + cl::location(defaultLibStore), + cl::CommaSeparated); + +static ArrayAdapter debugLibStore("debuglib", global.params.debuglibnames); +static cl::list<std::string, ArrayAdapter> debuglibs("debuglib", + cl::desc("Set default libraries for debug build"), + cl::value_desc("lib,..."), + cl::location(debugLibStore), + cl::CommaSeparated); + +void printVersion() { + printf("LLVM D Compiler %s\nbased on DMD %s and %s\n%s\n%s\n", + global.ldc_version, global.version, global.llvm_version, global.copyright, global.written); + printf("D Language Documentation: http://www.digitalmars.com/d/1.0/index.html\n" + "LDC Homepage: http://www.dsource.org/projects/ldc\n"); +} + +// Helper function to handle -d-debug=* and -d-version=* +static void processVersions(std::vector<std::string>& list, char* type, + void (*setLevel)(unsigned), void (*addIdent)(const char*)) { + typedef std::vector<std::string>::iterator It; + + for(It I = list.begin(), E = list.end(); I != E; ++I) { + const char* value = I->c_str(); + if (isdigit(value[0])) { + errno = 0; + char* end; + long level = strtol(value, &end, 10); + if (*end || errno || level > INT_MAX) { + error("Invalid %s level: %s", type, I->c_str()); + } else { + setLevel((unsigned)level); + } + } else { + char* cstr = mem.strdup(value); + if (Lexer::isValidIdentifier(cstr)) { + addIdent(cstr); + continue; + } else { + error("Invalid %s identifier or level: '%s'", type, I->c_str()); + } + } + } +} + +// Helper function to handle -of, -od, etc. +static void initFromString(char*& dest, const cl::opt<std::string>& src) { + dest = 0; + if (src.getNumOccurrences() != 0) { + if (src.empty()) + error("Expected argument to '-%s'", src.ArgStr); + dest = mem.strdup(src.c_str()); + } +} + +int main(int argc, char** argv) +{ + Array files; + char *p, *ext; + Module *m; + int status = EXIT_SUCCESS; + + // Set some default values +#if _WIN32 + char buf[MAX_PATH]; + GetModuleFileName(NULL, buf, MAX_PATH); + global.params.argv0 = buf; +#else + global.params.argv0 = argv[0]; +#endif + global.params.useSwitchError = 1; + + global.params.linkswitches = new Array(); + global.params.libfiles = new Array(); + global.params.objfiles = new Array(); + global.params.ddocfiles = new Array(); + + // Set predefined version identifiers + VersionCondition::addPredefinedGlobalIdent("LLVM"); + VersionCondition::addPredefinedGlobalIdent("LDC"); + VersionCondition::addPredefinedGlobalIdent("all"); + + // read the inifile +#if DMDV2 + inifile(global.params.argv0, "ldc2.conf"); +#else + inifile(global.params.argv0, "ldc.conf"); +#endif + + // merge DFLAGS into argc/argv + getenv_setargv("DFLAGS", &argc, &argv); +#if 0 + for (int i = 0; i < argc; i++) + { + printf("argv[%d] = '%s'\n", i, argv[i]); + } +#endif + + // Handle fixed-up arguments! + cl::SetVersionPrinter(&printVersion); + cl::ParseCommandLineOptions(argc, argv, "LLVM-based D Compiler\n"); + + global.params.optimize = (global.params.optimizeLevel >= 0); + + // Negated options + global.params.link = !compileOnly; + global.params.obj = !dontWriteObj; + global.params.useInlineAsm = !noAsm; + + // String options: std::string --> char* + initFromString(global.params.objname, objectFile); + initFromString(global.params.objdir, objectDir); + + initFromString(global.params.docdir, ddocDir); + initFromString(global.params.docname, ddocFile); + global.params.doDocComments |= + global.params.docdir || global.params.docname; + +#ifdef _DH + initFromString(global.params.hdrdir, hdrDir); + initFromString(global.params.hdrname, hdrFile); + global.params.doHdrGeneration |= + global.params.hdrdir || global.params.hdrname; +#endif + + processVersions(debugArgs, "debug", + DebugCondition::setGlobalLevel, + DebugCondition::addGlobalIdent); + processVersions(versions, "version", + VersionCondition::setGlobalLevel, + VersionCondition::addGlobalIdent); + + global.params.output_o = + opts::output_o == cl::BOU_UNSET + ? OUTPUTFLAGdefault + : opts::output_o == cl::BOU_TRUE + ? OUTPUTFLAGset + : OUTPUTFLAGno; + global.params.output_bc = opts::output_bc ? OUTPUTFLAGset : OUTPUTFLAGno; + global.params.output_ll = opts::output_ll ? OUTPUTFLAGset : OUTPUTFLAGno; + global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno; + + if (global.params.run || !runargs.empty()) { + // FIXME: how to properly detect the presence of a PositionalEatsArgs + // option without parameters? We want to emit an error in that case... + // You'd think getNumOccurrences would do it, but it just returns the + // number of parameters) + // NOTE: Hacked around it by detecting -run in getenv_setargv(), where + // we're looking for it anyway, and pre-setting the flag... + global.params.run = true; + if (!runargs.empty()) { + files.push(mem.strdup(runargs[0].c_str())); + } else { + global.params.run = false; + error("Expected at least one argument to '-run'\n"); + } + } + + + files.reserve(fileList.size()); + typedef std::vector<std::string>::iterator It; + for(It I = fileList.begin(), E = fileList.end(); I != E; ++I) + if (!I->empty()) + files.push(mem.strdup(I->c_str())); + + if (global.errors) + { + fatal(); + } + if (files.dim == 0) + { + cl::PrintHelpMessage(); + return EXIT_FAILURE; + } + + Array* libs; + if (global.params.symdebug) + libs = global.params.debuglibnames; + else + libs = global.params.defaultlibnames; + + if (libs) + { + for (int i = 0; i < libs->dim; i++) + { + char *arg = (char *)mem.malloc(64); + strcpy(arg, "-l"); + strncat(arg, (char *)libs->data[i], 64); + global.params.linkswitches->push(arg); + } + } + else if (!noDefaultLib) + { + char *arg; + arg = (char *)mem.malloc(64); + strcpy(arg, "-lldc-runtime"); + global.params.linkswitches->push(arg); + arg = (char *)mem.malloc(64); + strcpy(arg, "-ltango-cc-tango"); + global.params.linkswitches->push(arg); + arg = (char *)mem.malloc(64); + strcpy(arg, "-ltango-gc-basic"); + global.params.linkswitches->push(arg); + // pass the runtime again to resolve issues + // with linking order + arg = (char *)mem.malloc(64); + strcpy(arg, "-lldc-runtime"); + global.params.linkswitches->push(arg); + } + + if (global.params.run) + quiet = 1; + + if (global.params.useUnitTests) + global.params.useAssert = 1; + + // LDC output determination + + // if we don't link, autodetect target from extension + if(!global.params.link && global.params.objname) { + ext = FileName::ext(global.params.objname); + bool autofound = false; + if (!ext) { + // keep things as they are + } else if (strcmp(ext, global.ll_ext) == 0) { + global.params.output_ll = OUTPUTFLAGset; + autofound = true; + } else if (strcmp(ext, global.bc_ext) == 0) { + global.params.output_bc = OUTPUTFLAGset; + autofound = true; + } else if (strcmp(ext, global.s_ext) == 0) { + global.params.output_s = OUTPUTFLAGset; + autofound = true; + } else if (strcmp(ext, global.obj_ext) == 0) { + global.params.output_o = OUTPUTFLAGset; + autofound = true; + } else { + // append dot, so forceExt won't change existing name even if it contains dots + size_t len = strlen(global.params.objname); + size_t extlen = strlen("."); + char* s = (char *)mem.malloc(len + 1 + extlen + 1); + memcpy(s, global.params.objname, len); + s[len] = '.'; + s[len+1+extlen] = 0; + global.params.objname = s; + + } + if(autofound && global.params.output_o == OUTPUTFLAGdefault) + global.params.output_o = OUTPUTFLAGno; + } + + // only link if possible + if (!global.params.obj || !global.params.output_o) + global.params.link = 0; + + if (global.params.link) + { + global.params.exefile = global.params.objname; + if (files.dim > 1) + global.params.objname = NULL; + } + else if (global.params.run) + { + error("flags conflict with -run"); + fatal(); + } + else + { + if (global.params.objname && files.dim > 1) + { + error("multiple source files, but only one .obj name"); + fatal(); + } + } + + // create a proper target + llvm::Module mod("dummy"); + + // did the user override the target triple? + if (mTargetTriple.empty()) + { + if (mArch != 0) + { + error("you must specify a target triple as well with -mtriple when using the -march option"); + fatal(); + } + global.params.targetTriple = DEFAULT_TARGET_TRIPLE; + } + else + { + global.params.targetTriple = mTargetTriple.c_str(); + } + + mod.setTargetTriple(global.params.targetTriple); + + // Allocate target machine. First, check whether the user has + // explicitly specified an architecture to compile for. + if (mArch == 0) + { + std::string Err; + mArch = llvm::TargetMachineRegistry::getClosestStaticTargetForModule(mod, Err); + if (mArch == 0) + { + error("failed to auto-select target '%s', please use the -march option"); + fatal(); + } + } + + // Package up features to be passed to target/subtarget + std::string FeaturesStr; + if (mCPU.size() || mAttrs.size()) + { + llvm::SubtargetFeatures Features; + Features.setCPU(mCPU); + for (unsigned i = 0; i != mAttrs.size(); ++i) + Features.AddFeature(mAttrs[i]); + FeaturesStr = Features.getString(); + } + + std::auto_ptr<llvm::TargetMachine> target(mArch->CtorFn(mod, FeaturesStr)); + assert(target.get() && "Could not allocate target machine!"); + gTargetMachine = target.get(); + gTargetData = gTargetMachine->getTargetData(); + + // get final data layout + std::string datalayout = gTargetData->getStringRepresentation(); + global.params.dataLayout = datalayout.c_str(); + + global.params.llvmArch = mArch->Name; + + if (strcmp(global.params.llvmArch,"x86")==0) { + VersionCondition::addPredefinedGlobalIdent("X86"); + global.params.isLE = true; + global.params.is64bit = false; + global.params.cpu = ARCHx86; + if (global.params.useInlineAsm) { + VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86"); + } + } + else if (strcmp(global.params.llvmArch,"x86-64")==0) { + VersionCondition::addPredefinedGlobalIdent("X86_64"); + global.params.isLE = true; + global.params.is64bit = true; + global.params.cpu = ARCHx86_64; + if (global.params.useInlineAsm) { + VersionCondition::addPredefinedGlobalIdent("LLVM_InlineAsm_X86_64"); + } + } + else if (strcmp(global.params.llvmArch,"ppc32")==0) { + VersionCondition::addPredefinedGlobalIdent("PPC"); + global.params.isLE = false; + global.params.is64bit = false; + global.params.cpu = ARCHppc; + } + else if (strcmp(global.params.llvmArch,"ppc64")==0) { + VersionCondition::addPredefinedGlobalIdent("PPC64"); + global.params.isLE = false; + global.params.is64bit = true; + global.params.cpu = ARCHppc_64; + } + else if (strcmp(global.params.llvmArch,"arm")==0) { + VersionCondition::addPredefinedGlobalIdent("ARM"); + global.params.isLE = true; + global.params.is64bit = false; + global.params.cpu = ARCHarm; + } + else if (strcmp(global.params.llvmArch,"thumb")==0) { + VersionCondition::addPredefinedGlobalIdent("Thumb"); + global.params.isLE = true; + global.params.is64bit = false; + global.params.cpu = ARCHthumb; + } + else { + error("invalid cpu architecture specified: %s", global.params.llvmArch); + fatal(); + } + + // endianness + if (global.params.isLE) { + VersionCondition::addPredefinedGlobalIdent("LittleEndian"); + } + else { + VersionCondition::addPredefinedGlobalIdent("BigEndian"); + } + + // a generic 64bit version + // why isn't this in D to begin with ? + if (global.params.is64bit) { + VersionCondition::addPredefinedGlobalIdent("LLVM64"); + } + + // parse the OS out of the target triple + // see http://gcc.gnu.org/install/specific.html for details + // also llvm's different SubTargets have useful information + std::string triple = global.params.targetTriple; + size_t npos = std::string::npos; + + // windows + // FIXME: win64 + if (triple.find("windows") != npos || triple.find("win32") != npos || triple.find("mingw") != npos) + { + global.params.os = OSWindows; + VersionCondition::addPredefinedGlobalIdent("Windows"); + VersionCondition::addPredefinedGlobalIdent("Win32"); + VersionCondition::addPredefinedGlobalIdent("mingw32"); + } + // FIXME: cygwin + else if (triple.find("cygwin") != npos) + { + error("CygWin is not yet supported"); + fatal(); + } + // linux + else if (triple.find("linux") != npos) + { + global.params.os = OSLinux; + VersionCondition::addPredefinedGlobalIdent("linux"); + VersionCondition::addPredefinedGlobalIdent("Posix"); + } + // darwin + else if (triple.find("-darwin") != npos) + { + global.params.os = OSMacOSX; + VersionCondition::addPredefinedGlobalIdent("OSX"); + VersionCondition::addPredefinedGlobalIdent("darwin"); + VersionCondition::addPredefinedGlobalIdent("Posix"); + } + // freebsd + else if (triple.find("-freebsd") != npos) + { + global.params.os = OSFreeBSD; + VersionCondition::addPredefinedGlobalIdent("freebsd"); + VersionCondition::addPredefinedGlobalIdent("Posix"); + } + // solaris + else if (triple.find("-solaris") != npos) + { + global.params.os = OSSolaris; + VersionCondition::addPredefinedGlobalIdent("solaris"); + VersionCondition::addPredefinedGlobalIdent("Posix"); + } + // unsupported + else + { + error("target triple '%s' is not supported", global.params.targetTriple); + fatal(); + } + + // added in 1.039 + if (global.params.doDocComments) + VersionCondition::addPredefinedGlobalIdent("D_Ddoc"); + + // Initialization + Type::init(); + Id::initialize(); + Module::init(); + initPrecedence(); + + backend_init(); + + //printf("%d source files\n",files.dim); + + // Build import search path + if (global.params.imppath) + { + for (int i = 0; i < global.params.imppath->dim; i++) + { + char *path = (char *)global.params.imppath->data[i]; + Array *a = FileName::splitPath(path); + + if (a) + { + if (!global.path) + global.path = new Array(); + global.path->append(a); + } + } + } + + // Build string import search path + if (global.params.fileImppath) + { + for (int i = 0; i < global.params.fileImppath->dim; i++) + { + char *path = (char *)global.params.fileImppath->data[i]; + Array *a = FileName::splitPath(path); + + if (a) + { + if (!global.filePath) + global.filePath = new Array(); + global.filePath->append(a); + } + } + } + + // Create Modules + Array modules; + modules.reserve(files.dim); + for (int i = 0; i < files.dim; i++) + { Identifier *id; + char *ext; + char *name; + + p = (char *) files.data[i]; + + p = FileName::name(p); // strip path + ext = FileName::ext(p); + if (ext) + { +#if POSIX + if (strcmp(ext, global.obj_ext) == 0 || + strcmp(ext, global.bc_ext) == 0) +#else + if (stricmp(ext, global.obj_ext) == 0 || + stricmp(ext, global.bc_ext) == 0) +#endif + { + global.params.objfiles->push(files.data[i]); + continue; + } + +#if POSIX + if (strcmp(ext, "a") == 0) +#elif __MINGW32__ + if (stricmp(ext, "a") == 0) +#else + if (stricmp(ext, "lib") == 0) +#endif + { + global.params.libfiles->push(files.data[i]); + continue; + } + + if (strcmp(ext, global.ddoc_ext) == 0) + { + global.params.ddocfiles->push(files.data[i]); + continue; + } + +#if !POSIX + if (stricmp(ext, "res") == 0) + { + global.params.resfile = (char *)files.data[i]; + continue; + } + + if (stricmp(ext, "def") == 0) + { + global.params.deffile = (char *)files.data[i]; + continue; + } + + if (stricmp(ext, "exe") == 0) + { + global.params.exefile = (char *)files.data[i]; + continue; + } +#endif + + if (stricmp(ext, global.mars_ext) == 0 || + stricmp(ext, global.hdr_ext) == 0 || + stricmp(ext, "htm") == 0 || + stricmp(ext, "html") == 0 || + stricmp(ext, "xhtml") == 0) + { + ext--; // skip onto '.' + assert(*ext == '.'); + name = (char *)mem.malloc((ext - p) + 1); + memcpy(name, p, ext - p); + name[ext - p] = 0; // strip extension + + if (name[0] == 0 || + strcmp(name, "..") == 0 || + strcmp(name, ".") == 0) + { + Linvalid: + error("invalid file name '%s'", (char *)files.data[i]); + fatal(); + } + } + else + { error("unrecognized file extension %s\n", ext); + fatal(); + } + } + else + { name = p; + if (!*name) + goto Linvalid; + } + + id = new Identifier(name, 0); + m = new Module((char *) files.data[i], id, global.params.doDocComments, global.params.doHdrGeneration); + modules.push(m); + } + + // Read files, parse them + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("parse %s\n", m->toChars()); + if (!Module::rootModule) + Module::rootModule = m; + m->importedFrom = m; + m->read(0); + m->parse(); + m->buildTargetFiles(); + m->deleteObjFile(); + if (m->isDocFile) + { + m->gendocfile(); + + // Remove m from list of modules + modules.remove(i); + i--; + } + } + if (global.errors) + fatal(); +#ifdef _DH + if (global.params.doHdrGeneration) + { + /* Generate 'header' import files. + * Since 'header' import files must be independent of command + * line switches and what else is imported, they are generated + * before any semantic analysis. + */ + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("import %s\n", m->toChars()); + m->genhdrfile(); + } + } + if (global.errors) + fatal(); +#endif + + // Do semantic analysis + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("semantic %s\n", m->toChars()); + m->semantic(); + } + if (global.errors) + fatal(); + + // Do pass 2 semantic analysis + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("semantic2 %s\n", m->toChars()); + m->semantic2(); + } + if (global.errors) + fatal(); + + // Do pass 3 semantic analysis + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("semantic3 %s\n", m->toChars()); + m->semantic3(); + } + if (global.errors) + fatal(); + +#if !IN_LLVM + // Scan for functions to inline + if (global.params.useInline) + { + /* The problem with useArrayBounds and useAssert is that the + * module being linked to may not have generated them, so if + * we inline functions from those modules, the symbols for them will + * not be found at link time. + */ + if (!global.params.useArrayBounds && !global.params.useAssert) + { +#endif + // Do pass 3 semantic analysis on all imported modules, + // since otherwise functions in them cannot be inlined + for (int i = 0; i < Module::amodules.dim; i++) + { + m = (Module *)Module::amodules.data[i]; + if (global.params.verbose) + printf("semantic3 %s\n", m->toChars()); + m->semantic3(); + } + if (global.errors) + fatal(); +#if !IN_LLVM + } + + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("inline scan %s\n", m->toChars()); + m->inlineScan(); + } + } +#endif + if (global.errors) + fatal(); + + // Generate output files + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + if (global.params.verbose) + printf("code %s\n", m->toChars()); + if (global.params.obj) + { + m->genobjfile(0); + global.params.objfiles->push(m->objfile->name->str); + } + if (global.errors) + m->deleteObjFile(); + else + { + if (global.params.doDocComments) + m->gendocfile(); + } + } + + backend_term(); + if (global.errors) + fatal(); + + if (!global.params.objfiles->dim) + { + if (global.params.link) + error("no object files to link"); + } + else + { + if (global.params.link) + //status = runLINK(); + linkObjToExecutable(global.params.argv0); + + if (global.params.run) + { + if (!status) + { + status = runExectuable(); + + /* Delete .obj files and .exe file + */ + for (int i = 0; i < modules.dim; i++) + { + m = (Module *)modules.data[i]; + m->deleteObjFile(); + } + deleteExecutable(); + } + } + } + + return status; +}