Forgot new files that were supposed to be in last commit.

This commit is contained in:
Tomas Lindquist Olsen
2009-02-26 14:13:27 +01:00
parent 57a69e8177
commit 024946219a
3 changed files with 1099 additions and 0 deletions

225
gen/abi.cpp Normal file
View File

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

49
gen/abi.h Normal file
View File

@@ -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

825
gen/main.cpp Normal file
View File

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