mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
Forgot new files that were supposed to be in last commit.
This commit is contained in:
225
gen/abi.cpp
Normal file
225
gen/abi.cpp
Normal 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
49
gen/abi.h
Normal 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
825
gen/main.cpp
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user