mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-12 02:43:14 +01:00
merge
This commit is contained in:
@@ -53,4 +53,45 @@ struct X87_complex_swap : ABIRewrite
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FIXME: try into eliminating the alloca or if at least check
|
||||
// if it gets optimized away
|
||||
|
||||
// convert byval struct
|
||||
// when
|
||||
struct X86_struct_to_register : ABIRewrite
|
||||
{
|
||||
// int -> struct
|
||||
LLValue* get(Type* dty, DValue* dv)
|
||||
{
|
||||
Logger::println("rewriting int -> struct");
|
||||
LLValue* mem = DtoAlloca(dty, ".int_to_struct");
|
||||
LLValue* v = dv->getRVal();
|
||||
DtoStore(v, DtoBitCast(mem, getPtrToType(v->getType())));
|
||||
return DtoLoad(mem);
|
||||
}
|
||||
// int -> struct (with dst lvalue given)
|
||||
void getL(Type* dty, DValue* dv, llvm::Value* lval)
|
||||
{
|
||||
Logger::println("rewriting int -> struct");
|
||||
LLValue* v = dv->getRVal();
|
||||
DtoStore(v, DtoBitCast(lval, getPtrToType(v->getType())));
|
||||
}
|
||||
// struct -> int
|
||||
LLValue* put(Type* dty, DValue* dv)
|
||||
{
|
||||
Logger::println("rewriting struct -> int");
|
||||
assert(dv->isLVal());
|
||||
LLValue* mem = dv->getLVal();
|
||||
const LLType* t = LLIntegerType::get(gIR->context(), dty->size()*8);
|
||||
return DtoLoad(DtoBitCast(mem, getPtrToType(t)));
|
||||
}
|
||||
const LLType* type(Type* t, const LLType*)
|
||||
{
|
||||
size_t sz = t->size()*8;
|
||||
return LLIntegerType::get(gIR->context(), sz);
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
/* TargetABI implementation for x86-64.
|
||||
* Written for LDC by Frits van Bommel in 2009.
|
||||
*
|
||||
* extern(D) follows no particular external ABI, but tries to be smart about
|
||||
* passing structs and returning them. It should probably be reviewed if the
|
||||
* way LLVM implements fastcc on this platform ever changes.
|
||||
* (Specifically, the number of return registers of various types is hardcoded)
|
||||
*
|
||||
*
|
||||
* extern(C) implements the C calling convention for x86-64, as found in
|
||||
* http://www.x86-64.org/documentation/abi-0.99.pdf
|
||||
*
|
||||
@@ -286,150 +280,6 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Implementation details for extern(D)
|
||||
namespace x86_64_D_cc {
|
||||
struct DRegCount {
|
||||
unsigned ints;
|
||||
unsigned sse;
|
||||
unsigned x87;
|
||||
|
||||
DRegCount(unsigned ints_, unsigned sse_, unsigned x87_)
|
||||
: ints(ints_), sse(sse_), x87(x87_) {}
|
||||
};
|
||||
|
||||
// Count the number of registers needed for a simple type.
|
||||
// (Not a struct or static array)
|
||||
DRegCount regsNeededForSimpleType(Type* t) {
|
||||
DRegCount r(0, 0, 0);
|
||||
switch(t->ty) {
|
||||
case Tstruct:
|
||||
case Tsarray:
|
||||
assert(0 && "Not a simple type!");
|
||||
// Return huge numbers if assertions are disabled, so it'll always get
|
||||
// bumped to memory.
|
||||
r.ints = r.sse = r.x87 = (unsigned)-1;
|
||||
break;
|
||||
|
||||
// Floats, doubles and such are passed in SSE registers
|
||||
case Tfloat32:
|
||||
case Tfloat64:
|
||||
case Timaginary32:
|
||||
case Timaginary64:
|
||||
r.sse = 1;
|
||||
break;
|
||||
|
||||
case Tcomplex32:
|
||||
case Tcomplex64:
|
||||
r.sse = 2;
|
||||
break;
|
||||
|
||||
// Reals, ireals and creals are passed in x87 registers
|
||||
case Tfloat80:
|
||||
case Timaginary80:
|
||||
r.x87 = 1;
|
||||
break;
|
||||
|
||||
case Tcomplex80:
|
||||
r.x87 = 2;
|
||||
break;
|
||||
|
||||
// Anything else is passed in one or two integer registers,
|
||||
// depending on its size.
|
||||
default: {
|
||||
int needed = (t->size() + 7) / 8;
|
||||
assert(needed <= 2);
|
||||
r.ints = needed;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Returns true if it's possible (and a good idea) to pass the struct in the
|
||||
// specified number of registers.
|
||||
// (May return false if it's a bad idea to pass the type in registers for
|
||||
// reasons other than it not fitting)
|
||||
// Note that if true is returned, 'left' is also modified to contain the
|
||||
// number of registers left. This property is used in the recursive case.
|
||||
// If false is returned, 'left' is garbage.
|
||||
bool shouldPassStructInRegs(TypeStruct* t, DRegCount& left) {
|
||||
// If it has unaligned fields, there's probably a reason for it,
|
||||
// so keep it in memory.
|
||||
if (hasUnalignedFields(t))
|
||||
return false;
|
||||
|
||||
Array* fields = &t->sym->fields;
|
||||
|
||||
if (fields->dim == 0)
|
||||
return false;
|
||||
|
||||
d_uns64 nextbyte = 0;
|
||||
for (d_uns64 i = 0; i < fields->dim; i++) {
|
||||
VarDeclaration* field = (VarDeclaration*) fields->data[i];
|
||||
|
||||
// This depends on ascending order of field offsets in structs
|
||||
// without overlapping fields.
|
||||
if (field->offset < nextbyte) {
|
||||
// Don't return unions (or structs containing them) in registers.
|
||||
return false;
|
||||
}
|
||||
nextbyte = field->offset + field->type->size();
|
||||
|
||||
switch (field->type->ty) {
|
||||
case Tstruct:
|
||||
if (!shouldPassStructInRegs((TypeStruct*) field->type, left))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case Tsarray:
|
||||
// Don't return static arrays in registers
|
||||
// (indexing registers doesn't work well)
|
||||
return false;
|
||||
|
||||
default: {
|
||||
DRegCount needed = regsNeededForSimpleType(field->type);
|
||||
if (needed.ints > left.ints || needed.sse > left.sse || needed.x87 > left.x87)
|
||||
return false;
|
||||
left.ints -= needed.ints;
|
||||
left.sse -= needed.sse;
|
||||
left.x87 -= needed.x87;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true if the struct fits in return registers in the x86-64 fastcc
|
||||
// calling convention.
|
||||
bool retStructInRegs(TypeStruct* st) {
|
||||
// 'fastcc' allows returns in up to two registers of each kind:
|
||||
DRegCount state(2, 2, 2);
|
||||
return shouldPassStructInRegs(st, state);
|
||||
}
|
||||
|
||||
// Heuristic for determining whether to pass a struct type directly or
|
||||
// bump it to memory.
|
||||
bool passStructTypeDirectly(TypeStruct* st) {
|
||||
// If the type fits in a reasonable number of registers,
|
||||
// pass it directly.
|
||||
// This does not necessarily mean it will actually be passed in
|
||||
// registers. For example, x87 registers are never actually used for
|
||||
// parameters.
|
||||
DRegCount state(2, 2, 2);
|
||||
return shouldPassStructInRegs(st, state);
|
||||
|
||||
// This doesn't work well: Since the register count can differ depending
|
||||
// on backend options, there's no way to be exact anyway.
|
||||
/*
|
||||
// Regular fastcc: 6 int, 8 sse, 0 x87
|
||||
// fastcc + tailcall: 5 int, 8 sse, 0 x87
|
||||
RegCount state(5, 8, 0);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -498,7 +348,7 @@ struct RegCount {
|
||||
struct X86_64TargetABI : TargetABI {
|
||||
X86_64_C_struct_rewrite struct_rewrite;
|
||||
X87_complex_swap swapComplex;
|
||||
RemoveStructPadding remove_padding;
|
||||
X86_struct_to_register structToReg;
|
||||
|
||||
void newFunctionType(TypeFunction* tf) {
|
||||
funcTypeStack.push_back(FuncTypeData(tf->linkage));
|
||||
@@ -538,7 +388,6 @@ private:
|
||||
return funcTypeStack.back().state;
|
||||
}
|
||||
|
||||
void fixup_D(IrFuncTyArg& arg);
|
||||
void fixup(IrFuncTyArg& arg);
|
||||
};
|
||||
|
||||
@@ -558,15 +407,8 @@ bool X86_64TargetABI::returnInArg(TypeFunction* tf) {
|
||||
if (tf->isref)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// All non-structs can be returned in registers.
|
||||
// FIXME: Update calling convention for static array returns
|
||||
if (rt->ty != Tstruct)
|
||||
return false;
|
||||
|
||||
// Try to figure out whether the struct fits in return registers
|
||||
// and whether it's a good idea to put it there.
|
||||
return !x86_64_D_cc::retStructInRegs((TypeStruct*) rt);
|
||||
return (rt->ty == Tstruct);
|
||||
} else {
|
||||
if (rt == Type::tvoid || keepUnchanged(rt))
|
||||
return false;
|
||||
@@ -586,11 +428,7 @@ bool X86_64TargetABI::returnInArg(TypeFunction* tf) {
|
||||
bool X86_64TargetABI::passByVal(Type* t) {
|
||||
t = t->toBasetype();
|
||||
if (linkage() == LINKd) {
|
||||
if (t->ty != Tstruct)
|
||||
return false;
|
||||
|
||||
// Try to be smart about which structs are passed in memory.
|
||||
return !x86_64_D_cc::passStructTypeDirectly((TypeStruct*) t);
|
||||
return t->toBasetype()->ty == Tstruct;
|
||||
} else {
|
||||
// This implements the C calling convention for x86-64.
|
||||
// It might not be correct for other calling conventions.
|
||||
@@ -649,20 +487,6 @@ bool X86_64TargetABI::passByVal(Type* t) {
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for rewriteFunctionType.
|
||||
// Structs passed or returned in registers are passed here
|
||||
// to get their padding removed (if necessary).
|
||||
void X86_64TargetABI::fixup_D(IrFuncTyArg& arg) {
|
||||
TypeStruct *type = (TypeStruct*)arg.type->toBasetype();
|
||||
assert(type->ty == Tstruct);
|
||||
if (type->alignsize() != 1) {
|
||||
// TODO: don't do this transformation if there's no padding
|
||||
LLType* abiTy = DtoUnpaddedStructType(type);
|
||||
assert(abiTy);
|
||||
arg.ltype = abiTy;
|
||||
arg.rewrite = &remove_padding;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function for rewriteFunctionType.
|
||||
// Return type and parameters are passed here (unless they're already in memory)
|
||||
@@ -682,12 +506,8 @@ void X86_64TargetABI::rewriteFunctionType(TypeFunction* tf) {
|
||||
Type* rt = fty.ret->type->toBasetype();
|
||||
|
||||
if (tf->linkage == LINKd) {
|
||||
if (!fty.arg_sret) {
|
||||
if (rt->ty == Tstruct && !fty.ret->byref) {
|
||||
Logger::println("x86-64 D ABI: Transforming return type");
|
||||
fixup_D(*fty.ret);
|
||||
}
|
||||
}
|
||||
|
||||
// RETURN VALUE
|
||||
|
||||
// complex {re,im} -> {im,re}
|
||||
if (rt->iscomplex())
|
||||
@@ -695,35 +515,102 @@ void X86_64TargetABI::rewriteFunctionType(TypeFunction* tf) {
|
||||
Logger::println("Rewriting complex return value");
|
||||
fty.ret->rewrite = &swapComplex;
|
||||
}
|
||||
|
||||
#if DMDV1
|
||||
if (fty.arg_this) {
|
||||
fty.arg_this->attrs |= llvm::Attribute::Nest;
|
||||
|
||||
// IMPLICIT PARAMETERS
|
||||
|
||||
int regcount = 6; // RDI,RSI,RDX,RCX,R8,R9
|
||||
int xmmcount = 8; // XMM0..XMM7
|
||||
|
||||
// mark this/nested params inreg
|
||||
if (fty.arg_this)
|
||||
{
|
||||
Logger::println("Putting 'this' in register");
|
||||
fty.arg_this->attrs = llvm::Attribute::InReg;
|
||||
--regcount;
|
||||
}
|
||||
if (fty.arg_nest) {
|
||||
fty.arg_nest->attrs |= llvm::Attribute::Nest;
|
||||
else if (fty.arg_nest)
|
||||
{
|
||||
Logger::println("Putting context ptr in register");
|
||||
fty.arg_nest->attrs = llvm::Attribute::InReg;
|
||||
--regcount;
|
||||
}
|
||||
else if (IrFuncTyArg* sret = fty.arg_sret)
|
||||
{
|
||||
Logger::println("Putting sret ptr in register");
|
||||
// sret and inreg are incompatible, but the ABI requires the
|
||||
// sret parameter to be in RDI in this situation...
|
||||
sret->attrs = (sret->attrs | llvm::Attribute::InReg)
|
||||
& ~llvm::Attribute::StructRet;
|
||||
--regcount;
|
||||
}
|
||||
#endif
|
||||
|
||||
Logger::println("x86-64 D ABI: Transforming arguments");
|
||||
LOG_SCOPE;
|
||||
|
||||
for (IrFuncTy::ArgIter I = fty.args.begin(), E = fty.args.end(); I != E; ++I) {
|
||||
for (IrFuncTy::ArgRIter I = fty.args.rbegin(), E = fty.args.rend(); I != E; ++I) {
|
||||
IrFuncTyArg& arg = **I;
|
||||
|
||||
if (Logger::enabled())
|
||||
Logger::cout() << "Arg: " << arg.type->toChars() << '\n';
|
||||
|
||||
// Arguments that are in memory are of no interest to us.
|
||||
if (arg.byref)
|
||||
continue;
|
||||
|
||||
Type* ty = arg.type->toBasetype();
|
||||
if (ty->ty == Tstruct)
|
||||
fixup_D(arg);
|
||||
|
||||
if (Logger::enabled())
|
||||
Logger::cout() << "New arg type: " << *arg.ltype << '\n';
|
||||
unsigned sz = ty->size();
|
||||
|
||||
if (ty->isfloating() && sz <= 8)
|
||||
{
|
||||
if (xmmcount > 0) {
|
||||
Logger::println("Putting float parameter in register");
|
||||
arg.attrs |= llvm::Attribute::InReg;
|
||||
--xmmcount;
|
||||
}
|
||||
}
|
||||
else if (regcount == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (arg.byref && !arg.isByVal())
|
||||
{
|
||||
Logger::println("Putting byref parameter in register");
|
||||
arg.attrs |= llvm::Attribute::InReg;
|
||||
--regcount;
|
||||
}
|
||||
else if (ty->ty == Tpointer)
|
||||
{
|
||||
Logger::println("Putting pointer parameter in register");
|
||||
arg.attrs |= llvm::Attribute::InReg;
|
||||
--regcount;
|
||||
}
|
||||
else if (ty->isintegral() && sz <= 8)
|
||||
{
|
||||
Logger::println("Putting integral parameter in register");
|
||||
arg.attrs |= llvm::Attribute::InReg;
|
||||
--regcount;
|
||||
}
|
||||
else if ((ty->ty == Tstruct || ty->ty == Tsarray) &&
|
||||
(sz == 1 || sz == 2 || sz == 4 || sz == 8))
|
||||
{
|
||||
if (ty->ty == Tstruct)
|
||||
{
|
||||
Logger::println("Putting struct in register");
|
||||
arg.rewrite = &structToReg;
|
||||
arg.ltype = structToReg.type(arg.type, arg.ltype);
|
||||
arg.byref = false;
|
||||
// erase previous attributes
|
||||
arg.attrs = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger::println("Putting static array in register");
|
||||
}
|
||||
arg.attrs |= llvm::Attribute::InReg;
|
||||
--regcount;
|
||||
}
|
||||
}
|
||||
|
||||
// EXPLICIT PARAMETERS
|
||||
|
||||
// reverse parameter order
|
||||
// for non variadics
|
||||
if (!fty.args.empty() && tf->varargs != 1)
|
||||
{
|
||||
fty.reverseParams = true;
|
||||
}
|
||||
} else {
|
||||
// TODO: See if this is correct for more than just extern(C).
|
||||
|
||||
42
gen/abi.cpp
42
gen/abi.cpp
@@ -13,6 +13,7 @@
|
||||
#include "gen/abi-generic.h"
|
||||
|
||||
#include "ir/irfunction.h"
|
||||
#include "ir/irfuncty.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -83,47 +84,6 @@ struct X86_cfloat_rewrite : ABIRewrite
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FIXME: try into eliminating the alloca or if at least check
|
||||
// if it gets optimized away
|
||||
|
||||
// convert byval struct
|
||||
// when
|
||||
struct X86_struct_to_register : ABIRewrite
|
||||
{
|
||||
// int -> struct
|
||||
LLValue* get(Type* dty, DValue* dv)
|
||||
{
|
||||
Logger::println("rewriting int -> struct");
|
||||
LLValue* mem = DtoAlloca(dty, ".int_to_struct");
|
||||
LLValue* v = dv->getRVal();
|
||||
DtoStore(v, DtoBitCast(mem, getPtrToType(v->getType())));
|
||||
return DtoLoad(mem);
|
||||
}
|
||||
// int -> struct (with dst lvalue given)
|
||||
void getL(Type* dty, DValue* dv, llvm::Value* lval)
|
||||
{
|
||||
Logger::println("rewriting int -> struct");
|
||||
LLValue* v = dv->getRVal();
|
||||
DtoStore(v, DtoBitCast(lval, getPtrToType(v->getType())));
|
||||
}
|
||||
// struct -> int
|
||||
LLValue* put(Type* dty, DValue* dv)
|
||||
{
|
||||
Logger::println("rewriting struct -> int");
|
||||
assert(dv->isLVal());
|
||||
LLValue* mem = dv->getLVal();
|
||||
const LLType* t = LLIntegerType::get(gIR->context(), dty->size()*8);
|
||||
return DtoLoad(DtoBitCast(mem, getPtrToType(t)));
|
||||
}
|
||||
const LLType* type(Type* t, const LLType*)
|
||||
{
|
||||
size_t sz = t->size()*8;
|
||||
return LLIntegerType::get(gIR->context(), sz);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct X86TargetABI : TargetABI
|
||||
{
|
||||
X87_complex_swap swapComplex;
|
||||
|
||||
@@ -1117,7 +1117,7 @@ LLValue* DtoArrayCompare(Loc& loc, TOK op, DValue* l, DValue* r)
|
||||
if (t->ty == Tchar)
|
||||
res = DtoArrayEqCmp_impl(loc, "_adCmpChar", l, r, false);
|
||||
else
|
||||
res = DtoArrayEqCmp_impl(loc, "_adCmp", l, r, true);
|
||||
res = DtoArrayEqCmp_impl(loc, _adCmp, l, r, true);
|
||||
res = gIR->ir->CreateICmp(cmpop, res, DtoConstInt(0), "tmp");
|
||||
}
|
||||
|
||||
|
||||
@@ -789,7 +789,7 @@ static void LLVM_D_BuildRuntimeModule()
|
||||
// int _adCmp(void[] a1, void[] a2, TypeInfo ti)
|
||||
{
|
||||
llvm::StringRef fname(_adEq);
|
||||
llvm::StringRef fname2("_adCmp");
|
||||
llvm::StringRef fname2(_adCmp);
|
||||
std::vector<const LLType*> types;
|
||||
types.push_back(rt_array(byteTy));
|
||||
types.push_back(rt_array(byteTy));
|
||||
|
||||
@@ -13,9 +13,11 @@ llvm::GlobalVariable* LLVM_D_GetRuntimeGlobal(llvm::Module* target, const char*
|
||||
#if DMDV1
|
||||
#define _d_allocclass "_d_allocclass"
|
||||
#define _adEq "_adEq"
|
||||
#define _adCmp "_adCmp"
|
||||
#else
|
||||
#define _d_allocclass "_d_newclass"
|
||||
#define _adEq "_adEq2"
|
||||
#define _adCmp "_adCmp2"
|
||||
#endif
|
||||
|
||||
#endif // LDC_GEN_RUNTIME_H_
|
||||
|
||||
@@ -522,9 +522,11 @@ static LLFunction* build_module_reference_and_ctor(LLConstant* moduleinfo)
|
||||
LLGlobalVariable* thismref = new LLGlobalVariable(*gIR->module, modulerefTy, false, LLGlobalValue::InternalLinkage, thismrefinit, thismrefname);
|
||||
|
||||
// make sure _Dmodule_ref is declared
|
||||
LLGlobalVariable* mref = gIR->module->getNamedGlobal("_Dmodule_ref");
|
||||
LLConstant* mref = gIR->module->getNamedGlobal("_Dmodule_ref");
|
||||
const LLType *modulerefPtrTy = getPtrToType(modulerefTy);
|
||||
if (!mref)
|
||||
mref = new LLGlobalVariable(*gIR->module, getPtrToType(modulerefTy), false, LLGlobalValue::ExternalLinkage, NULL, "_Dmodule_ref");
|
||||
mref = new LLGlobalVariable(*gIR->module, modulerefPtrTy, false, LLGlobalValue::ExternalLinkage, NULL, "_Dmodule_ref");
|
||||
mref = DtoBitCast(mref, getPtrToType(modulerefPtrTy));
|
||||
|
||||
// make the function insert this moduleinfo as the beginning of the _Dmodule_ref linked list
|
||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "moduleinfoCtorEntry", ctor);
|
||||
|
||||
@@ -70,6 +70,7 @@ struct IrFuncTy : IrBase
|
||||
// typedef llvm::SmallVector<IrFuncTyArg*, 4> ArgList;
|
||||
typedef std::vector<IrFuncTyArg*> ArgList;
|
||||
typedef ArgList::iterator ArgIter;
|
||||
typedef ArgList::reverse_iterator ArgRIter;
|
||||
ArgList args;
|
||||
|
||||
// C varargs
|
||||
|
||||
@@ -7,6 +7,7 @@ default:
|
||||
// 'switches' holds array of string that are appends to the command line
|
||||
// arguments before they are parsed.
|
||||
switches = [
|
||||
"-I@PROJECT_BINARY_DIR@/../import",
|
||||
"-I@RUNTIME_DIR@/import",
|
||||
"-I@RUNTIME_DIR@/src",
|
||||
"-L-L@PROJECT_BINARY_DIR@/../lib",
|
||||
|
||||
@@ -7,11 +7,12 @@ default:
|
||||
// 'switches' holds array of string that are appends to the command line
|
||||
// arguments before they are parsed.
|
||||
switches = [
|
||||
"-I@PROJECT_BINARY_DIR@/../import",
|
||||
"-I@RUNTIME_DIR@/import",
|
||||
"-I@RUNTIME_DIR@/src",
|
||||
"-I@PHOBOS2_DIR@/",
|
||||
"-L-L@PROJECT_BINARY_DIR@/../lib",
|
||||
"-defaultlib=phobos2",
|
||||
"-debuglib=phobos2"
|
||||
"-defaultlib=lphobos2",
|
||||
"-debuglib=lphobos2"
|
||||
];
|
||||
};
|
||||
|
||||
@@ -9,6 +9,10 @@ set(D_FLAGS -g -w -d CACHE STRING "runtime build flags, separated by ;")
|
||||
|
||||
if(BUILD_SHARED_LIBS)
|
||||
list(APPEND D_FLAGS -relocation-model=pic)
|
||||
set(D_LIBRARY_TYPE SHARED)
|
||||
else(BUILD_SHARED_LIBS)
|
||||
set(D_LIBRARY_TYPE STATIC)
|
||||
set(CXX_COMPILE_FLAGS " ")
|
||||
endif(BUILD_SHARED_LIBS)
|
||||
|
||||
# build tango for D1, druntime for D2
|
||||
@@ -81,12 +85,15 @@ elseif(D_VERSION EQUAL 2)
|
||||
${RUNTIME_DC_DIR}/arrayfloat.d
|
||||
${RUNTIME_DC_DIR}/arrayreal.d
|
||||
${RUNTIME_DC_DIR}/arrayshort.d
|
||||
${RUNTIME_DC_DIR}/critical_.d
|
||||
${RUNTIME_DC_DIR}/deh.d
|
||||
${RUNTIME_DC_DIR}/deh2.d
|
||||
${RUNTIME_DC_DIR}/llmath.d
|
||||
${RUNTIME_DC_DIR}/qsort2.d
|
||||
${RUNTIME_DC_DIR}/trace.d
|
||||
)
|
||||
file(GLOB DCRT_C ${RUNTIME_DC_DIR}/*.c)
|
||||
list(REMOVE_ITEM DCRT_C ${RUNTIME_DC_DIR}/deh.c ${RUNTIME_DC_DIR}/memory_osx.c)
|
||||
list(REMOVE_ITEM DCRT_C ${RUNTIME_DC_DIR}/deh.c ${RUNTIME_DC_DIR}/memory_osx.c ${RUNTIME_DC_DIR}/dylib_fixes.c)
|
||||
if(UNIX)
|
||||
file(GLOB_RECURSE CORE_D_SYS ${RUNTIME_DIR}/src/core/sys/posix/*.d)
|
||||
elseif(WIN32)
|
||||
@@ -94,15 +101,11 @@ elseif(D_VERSION EQUAL 2)
|
||||
elseif(APPLE)
|
||||
file(GLOB_RECURSE CORE_D_SYS ${RUNTIME_DIR}/src/core/sys/osx/*.d)
|
||||
endif(UNIX)
|
||||
list(APPEND CORE_D ${CORE_D_SYNC} ${CORE_D_SYS} ${CORE_D_STDC} ${LDC_D}
|
||||
${RUNTIME_DIR}/src/object_.d
|
||||
)
|
||||
list(APPEND CORE_D ${CORE_D_SYNC} ${CORE_D_SYS} ${CORE_D_STDC} )
|
||||
set(GENERATE_DI ${CORE_D})
|
||||
list(APPEND CORE_D ${LDC_D} ${RUNTIME_DIR}/src/object_.d)
|
||||
file(GLOB CORE_C ${RUNTIME_DIR}/src/core/stdc/*.c)
|
||||
|
||||
set(IGNORE_DI
|
||||
${RUNTIME_DIR}/src/object_.d
|
||||
)
|
||||
|
||||
if(PHOBOS2_DIR)
|
||||
file(GLOB PHOBOS2_D ${PHOBOS2_DIR}/std/*.d)
|
||||
file(GLOB PHOBOS2_D_MATH ${PHOBOS2_DIR}/std/internal/math/*.d)
|
||||
@@ -131,6 +134,9 @@ elseif(D_VERSION EQUAL 2)
|
||||
${PHOBOS2_DIR}/etc/c/zlib.d
|
||||
${PHOBOS2_DIR}/crc32.d
|
||||
)
|
||||
list(REMOVE_ITEM PHOBOS2_D
|
||||
${PHOBOS2_DIR}/std/intrinsic.d
|
||||
)
|
||||
set(CONFIG_NAME ${LDC_EXE}_phobos)
|
||||
else(PHOBOS2_DIR)
|
||||
set(CONFIG_NAME ${LDC_EXE})
|
||||
@@ -195,12 +201,13 @@ macro(dc INPUT_D OUTLIST_O OUTLIST_BC INCDIR MOREFLAGS PATH)
|
||||
list(APPEND ${OUTLIST_O} ${OUTPUT_O})
|
||||
list(APPEND ${OUTLIST_BC} ${OUTPUT_BC})
|
||||
|
||||
list(FIND IGNORE_DI "${INPUT_D}" INDEX)
|
||||
list(FIND GENERATE_DI "${INPUT_D}" INDEX)
|
||||
if (INDEX EQUAL -1)
|
||||
string(REGEX REPLACE "^src/" "druntime/" di_output ${output})
|
||||
set(DI_CMD -Hf=${CMAKE_BINARY_DIR}/import/${di_output}.di)
|
||||
set(DI_CMD "")
|
||||
else (INDEX EQUAL -1)
|
||||
list(REMOVE_AT IGNORE_DI ${INDEX})
|
||||
string(REGEX REPLACE "^src/" "" di_output ${output})
|
||||
set(DI_CMD -Hf=${CMAKE_BINARY_DIR}/import/${di_output}.di)
|
||||
list(REMOVE_AT GENERATE_DI ${INDEX})
|
||||
endif (INDEX EQUAL -1)
|
||||
|
||||
# Compile
|
||||
@@ -233,12 +240,12 @@ foreach(f ${DCRT_D})
|
||||
endforeach(f)
|
||||
|
||||
if(BUILD_SINGLE_LIB)
|
||||
add_library(${RUNTIME_AIO} ${CORE_O} ${CORE_C} ${GC_O} ${DCRT_O} ${DCRT_C})
|
||||
add_library(${RUNTIME_AIO} ${D_LIBRARY_TYPE} ${CORE_O} ${CORE_C} ${GC_O} ${DCRT_O} ${DCRT_C})
|
||||
set(LIBS ${RUNTIME_AIO})
|
||||
else(BUILD_SINGLE_LIB)
|
||||
add_library(${RUNTIME_CC} ${CORE_O} ${CORE_C})
|
||||
add_library(${RUNTIME_GC} ${GC_O})
|
||||
add_library(${RUNTIME_DC} ${DCRT_O} ${DCRT_C})
|
||||
add_library(${RUNTIME_CC} ${D_LIBRARY_TYPE} ${CORE_O} ${CORE_C})
|
||||
add_library(${RUNTIME_GC} ${D_LIBRARY_TYPE} ${GC_O})
|
||||
add_library(${RUNTIME_DC} ${D_LIBRARY_TYPE} ${DCRT_O} ${DCRT_C})
|
||||
set(LIBS
|
||||
${RUNTIME_CC}
|
||||
${RUNTIME_GC}
|
||||
@@ -289,12 +296,21 @@ if(PHOBOS2_DIR)
|
||||
dc(${f} PHOBOS2_O PHOBOS2_BC ${RUNTIME_DIR}/src/ "-I${PHOBOS2_DIR}" ${PHOBOS2_DIR})
|
||||
endforeach(f)
|
||||
|
||||
add_library(phobos2 ${ZLIB_C} ${PHOBOS2_O} ${CORE_O} ${CORE_C} ${GC_O} ${DCRT_O} ${DCRT_C})
|
||||
add_dependencies(phobos2 runtime)
|
||||
add_library(lphobos2 ${D_LIBRARY_TYPE}
|
||||
${ZLIB_C}
|
||||
${PHOBOS2_O}
|
||||
${CORE_O}
|
||||
${CORE_C}
|
||||
${GC_O}
|
||||
${DCRT_O}
|
||||
${DCRT_C}
|
||||
)
|
||||
add_dependencies(lphobos2 runtime)
|
||||
set_target_properties(
|
||||
phobos2 PROPERTIES
|
||||
lphobos2 PROPERTIES
|
||||
LINKER_LANGUAGE C
|
||||
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../lib
|
||||
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../lib
|
||||
)
|
||||
add_custom_target(phobos2 DEPENDS lphobos2)
|
||||
endif(PHOBOS2_DIR)
|
||||
|
||||
Reference in New Issue
Block a user