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;
+}