mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-11-03 15:47:26 +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
|
#endif
|
||||||
|
|||||||
+92
-205
@@ -1,12 +1,6 @@
|
|||||||
/* TargetABI implementation for x86-64.
|
/* TargetABI implementation for x86-64.
|
||||||
* Written for LDC by Frits van Bommel in 2009.
|
* 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
|
* extern(C) implements the C calling convention for x86-64, as found in
|
||||||
* http://www.x86-64.org/documentation/abi-0.99.pdf
|
* 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 {
|
struct X86_64TargetABI : TargetABI {
|
||||||
X86_64_C_struct_rewrite struct_rewrite;
|
X86_64_C_struct_rewrite struct_rewrite;
|
||||||
X87_complex_swap swapComplex;
|
X87_complex_swap swapComplex;
|
||||||
RemoveStructPadding remove_padding;
|
X86_struct_to_register structToReg;
|
||||||
|
|
||||||
void newFunctionType(TypeFunction* tf) {
|
void newFunctionType(TypeFunction* tf) {
|
||||||
funcTypeStack.push_back(FuncTypeData(tf->linkage));
|
funcTypeStack.push_back(FuncTypeData(tf->linkage));
|
||||||
@@ -538,7 +388,6 @@ private:
|
|||||||
return funcTypeStack.back().state;
|
return funcTypeStack.back().state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixup_D(IrFuncTyArg& arg);
|
|
||||||
void fixup(IrFuncTyArg& arg);
|
void fixup(IrFuncTyArg& arg);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -558,15 +407,8 @@ bool X86_64TargetABI::returnInArg(TypeFunction* tf) {
|
|||||||
if (tf->isref)
|
if (tf->isref)
|
||||||
return false;
|
return false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// All non-structs can be returned in registers.
|
// All non-structs can be returned in registers.
|
||||||
// FIXME: Update calling convention for static array returns
|
return (rt->ty == Tstruct);
|
||||||
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);
|
|
||||||
} else {
|
} else {
|
||||||
if (rt == Type::tvoid || keepUnchanged(rt))
|
if (rt == Type::tvoid || keepUnchanged(rt))
|
||||||
return false;
|
return false;
|
||||||
@@ -586,11 +428,7 @@ bool X86_64TargetABI::returnInArg(TypeFunction* tf) {
|
|||||||
bool X86_64TargetABI::passByVal(Type* t) {
|
bool X86_64TargetABI::passByVal(Type* t) {
|
||||||
t = t->toBasetype();
|
t = t->toBasetype();
|
||||||
if (linkage() == LINKd) {
|
if (linkage() == LINKd) {
|
||||||
if (t->ty != Tstruct)
|
return t->toBasetype()->ty == Tstruct;
|
||||||
return false;
|
|
||||||
|
|
||||||
// Try to be smart about which structs are passed in memory.
|
|
||||||
return !x86_64_D_cc::passStructTypeDirectly((TypeStruct*) t);
|
|
||||||
} else {
|
} else {
|
||||||
// This implements the C calling convention for x86-64.
|
// This implements the C calling convention for x86-64.
|
||||||
// It might not be correct for other calling conventions.
|
// 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.
|
// Helper function for rewriteFunctionType.
|
||||||
// Return type and parameters are passed here (unless they're already in memory)
|
// 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();
|
Type* rt = fty.ret->type->toBasetype();
|
||||||
|
|
||||||
if (tf->linkage == LINKd) {
|
if (tf->linkage == LINKd) {
|
||||||
if (!fty.arg_sret) {
|
|
||||||
if (rt->ty == Tstruct && !fty.ret->byref) {
|
// RETURN VALUE
|
||||||
Logger::println("x86-64 D ABI: Transforming return type");
|
|
||||||
fixup_D(*fty.ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// complex {re,im} -> {im,re}
|
// complex {re,im} -> {im,re}
|
||||||
if (rt->iscomplex())
|
if (rt->iscomplex())
|
||||||
@@ -695,35 +515,102 @@ void X86_64TargetABI::rewriteFunctionType(TypeFunction* tf) {
|
|||||||
Logger::println("Rewriting complex return value");
|
Logger::println("Rewriting complex return value");
|
||||||
fty.ret->rewrite = &swapComplex;
|
fty.ret->rewrite = &swapComplex;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if DMDV1
|
// IMPLICIT PARAMETERS
|
||||||
if (fty.arg_this) {
|
|
||||||
fty.arg_this->attrs |= llvm::Attribute::Nest;
|
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) {
|
else if (fty.arg_nest)
|
||||||
fty.arg_nest->attrs |= llvm::Attribute::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");
|
Logger::println("x86-64 D ABI: Transforming arguments");
|
||||||
LOG_SCOPE;
|
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;
|
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();
|
Type* ty = arg.type->toBasetype();
|
||||||
if (ty->ty == Tstruct)
|
unsigned sz = ty->size();
|
||||||
fixup_D(arg);
|
|
||||||
|
if (ty->isfloating() && sz <= 8)
|
||||||
if (Logger::enabled())
|
{
|
||||||
Logger::cout() << "New arg type: " << *arg.ltype << '\n';
|
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 {
|
} else {
|
||||||
// TODO: See if this is correct for more than just extern(C).
|
// TODO: See if this is correct for more than just extern(C).
|
||||||
|
|||||||
+1
-41
@@ -13,6 +13,7 @@
|
|||||||
#include "gen/abi-generic.h"
|
#include "gen/abi-generic.h"
|
||||||
|
|
||||||
#include "ir/irfunction.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
|
struct X86TargetABI : TargetABI
|
||||||
{
|
{
|
||||||
X87_complex_swap swapComplex;
|
X87_complex_swap swapComplex;
|
||||||
|
|||||||
+1
-1
@@ -1117,7 +1117,7 @@ LLValue* DtoArrayCompare(Loc& loc, TOK op, DValue* l, DValue* r)
|
|||||||
if (t->ty == Tchar)
|
if (t->ty == Tchar)
|
||||||
res = DtoArrayEqCmp_impl(loc, "_adCmpChar", l, r, false);
|
res = DtoArrayEqCmp_impl(loc, "_adCmpChar", l, r, false);
|
||||||
else
|
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");
|
res = gIR->ir->CreateICmp(cmpop, res, DtoConstInt(0), "tmp");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -789,7 +789,7 @@ static void LLVM_D_BuildRuntimeModule()
|
|||||||
// int _adCmp(void[] a1, void[] a2, TypeInfo ti)
|
// int _adCmp(void[] a1, void[] a2, TypeInfo ti)
|
||||||
{
|
{
|
||||||
llvm::StringRef fname(_adEq);
|
llvm::StringRef fname(_adEq);
|
||||||
llvm::StringRef fname2("_adCmp");
|
llvm::StringRef fname2(_adCmp);
|
||||||
std::vector<const LLType*> types;
|
std::vector<const LLType*> types;
|
||||||
types.push_back(rt_array(byteTy));
|
types.push_back(rt_array(byteTy));
|
||||||
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
|
#if DMDV1
|
||||||
#define _d_allocclass "_d_allocclass"
|
#define _d_allocclass "_d_allocclass"
|
||||||
#define _adEq "_adEq"
|
#define _adEq "_adEq"
|
||||||
|
#define _adCmp "_adCmp"
|
||||||
#else
|
#else
|
||||||
#define _d_allocclass "_d_newclass"
|
#define _d_allocclass "_d_newclass"
|
||||||
#define _adEq "_adEq2"
|
#define _adEq "_adEq2"
|
||||||
|
#define _adCmp "_adCmp2"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // LDC_GEN_RUNTIME_H_
|
#endif // LDC_GEN_RUNTIME_H_
|
||||||
|
|||||||
+4
-2
@@ -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);
|
LLGlobalVariable* thismref = new LLGlobalVariable(*gIR->module, modulerefTy, false, LLGlobalValue::InternalLinkage, thismrefinit, thismrefname);
|
||||||
|
|
||||||
// make sure _Dmodule_ref is declared
|
// 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)
|
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
|
// 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);
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "moduleinfoCtorEntry", ctor);
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ struct IrFuncTy : IrBase
|
|||||||
// typedef llvm::SmallVector<IrFuncTyArg*, 4> ArgList;
|
// typedef llvm::SmallVector<IrFuncTyArg*, 4> ArgList;
|
||||||
typedef std::vector<IrFuncTyArg*> ArgList;
|
typedef std::vector<IrFuncTyArg*> ArgList;
|
||||||
typedef ArgList::iterator ArgIter;
|
typedef ArgList::iterator ArgIter;
|
||||||
|
typedef ArgList::reverse_iterator ArgRIter;
|
||||||
ArgList args;
|
ArgList args;
|
||||||
|
|
||||||
// C varargs
|
// C varargs
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ default:
|
|||||||
// 'switches' holds array of string that are appends to the command line
|
// 'switches' holds array of string that are appends to the command line
|
||||||
// arguments before they are parsed.
|
// arguments before they are parsed.
|
||||||
switches = [
|
switches = [
|
||||||
|
"-I@PROJECT_BINARY_DIR@/../import",
|
||||||
"-I@RUNTIME_DIR@/import",
|
"-I@RUNTIME_DIR@/import",
|
||||||
"-I@RUNTIME_DIR@/src",
|
"-I@RUNTIME_DIR@/src",
|
||||||
"-L-L@PROJECT_BINARY_DIR@/../lib",
|
"-L-L@PROJECT_BINARY_DIR@/../lib",
|
||||||
|
|||||||
+3
-2
@@ -7,11 +7,12 @@ default:
|
|||||||
// 'switches' holds array of string that are appends to the command line
|
// 'switches' holds array of string that are appends to the command line
|
||||||
// arguments before they are parsed.
|
// arguments before they are parsed.
|
||||||
switches = [
|
switches = [
|
||||||
|
"-I@PROJECT_BINARY_DIR@/../import",
|
||||||
"-I@RUNTIME_DIR@/import",
|
"-I@RUNTIME_DIR@/import",
|
||||||
"-I@RUNTIME_DIR@/src",
|
"-I@RUNTIME_DIR@/src",
|
||||||
"-I@PHOBOS2_DIR@/",
|
"-I@PHOBOS2_DIR@/",
|
||||||
"-L-L@PROJECT_BINARY_DIR@/../lib",
|
"-L-L@PROJECT_BINARY_DIR@/../lib",
|
||||||
"-defaultlib=phobos2",
|
"-defaultlib=lphobos2",
|
||||||
"-debuglib=phobos2"
|
"-debuglib=lphobos2"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|||||||
+35
-19
@@ -9,6 +9,10 @@ set(D_FLAGS -g -w -d CACHE STRING "runtime build flags, separated by ;")
|
|||||||
|
|
||||||
if(BUILD_SHARED_LIBS)
|
if(BUILD_SHARED_LIBS)
|
||||||
list(APPEND D_FLAGS -relocation-model=pic)
|
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)
|
endif(BUILD_SHARED_LIBS)
|
||||||
|
|
||||||
# build tango for D1, druntime for D2
|
# build tango for D1, druntime for D2
|
||||||
@@ -81,12 +85,15 @@ elseif(D_VERSION EQUAL 2)
|
|||||||
${RUNTIME_DC_DIR}/arrayfloat.d
|
${RUNTIME_DC_DIR}/arrayfloat.d
|
||||||
${RUNTIME_DC_DIR}/arrayreal.d
|
${RUNTIME_DC_DIR}/arrayreal.d
|
||||||
${RUNTIME_DC_DIR}/arrayshort.d
|
${RUNTIME_DC_DIR}/arrayshort.d
|
||||||
|
${RUNTIME_DC_DIR}/critical_.d
|
||||||
${RUNTIME_DC_DIR}/deh.d
|
${RUNTIME_DC_DIR}/deh.d
|
||||||
${RUNTIME_DC_DIR}/deh2.d
|
${RUNTIME_DC_DIR}/deh2.d
|
||||||
|
${RUNTIME_DC_DIR}/llmath.d
|
||||||
|
${RUNTIME_DC_DIR}/qsort2.d
|
||||||
${RUNTIME_DC_DIR}/trace.d
|
${RUNTIME_DC_DIR}/trace.d
|
||||||
)
|
)
|
||||||
file(GLOB DCRT_C ${RUNTIME_DC_DIR}/*.c)
|
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)
|
if(UNIX)
|
||||||
file(GLOB_RECURSE CORE_D_SYS ${RUNTIME_DIR}/src/core/sys/posix/*.d)
|
file(GLOB_RECURSE CORE_D_SYS ${RUNTIME_DIR}/src/core/sys/posix/*.d)
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
@@ -94,15 +101,11 @@ elseif(D_VERSION EQUAL 2)
|
|||||||
elseif(APPLE)
|
elseif(APPLE)
|
||||||
file(GLOB_RECURSE CORE_D_SYS ${RUNTIME_DIR}/src/core/sys/osx/*.d)
|
file(GLOB_RECURSE CORE_D_SYS ${RUNTIME_DIR}/src/core/sys/osx/*.d)
|
||||||
endif(UNIX)
|
endif(UNIX)
|
||||||
list(APPEND CORE_D ${CORE_D_SYNC} ${CORE_D_SYS} ${CORE_D_STDC} ${LDC_D}
|
list(APPEND CORE_D ${CORE_D_SYNC} ${CORE_D_SYS} ${CORE_D_STDC} )
|
||||||
${RUNTIME_DIR}/src/object_.d
|
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)
|
file(GLOB CORE_C ${RUNTIME_DIR}/src/core/stdc/*.c)
|
||||||
|
|
||||||
set(IGNORE_DI
|
|
||||||
${RUNTIME_DIR}/src/object_.d
|
|
||||||
)
|
|
||||||
|
|
||||||
if(PHOBOS2_DIR)
|
if(PHOBOS2_DIR)
|
||||||
file(GLOB PHOBOS2_D ${PHOBOS2_DIR}/std/*.d)
|
file(GLOB PHOBOS2_D ${PHOBOS2_DIR}/std/*.d)
|
||||||
file(GLOB PHOBOS2_D_MATH ${PHOBOS2_DIR}/std/internal/math/*.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}/etc/c/zlib.d
|
||||||
${PHOBOS2_DIR}/crc32.d
|
${PHOBOS2_DIR}/crc32.d
|
||||||
)
|
)
|
||||||
|
list(REMOVE_ITEM PHOBOS2_D
|
||||||
|
${PHOBOS2_DIR}/std/intrinsic.d
|
||||||
|
)
|
||||||
set(CONFIG_NAME ${LDC_EXE}_phobos)
|
set(CONFIG_NAME ${LDC_EXE}_phobos)
|
||||||
else(PHOBOS2_DIR)
|
else(PHOBOS2_DIR)
|
||||||
set(CONFIG_NAME ${LDC_EXE})
|
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_O} ${OUTPUT_O})
|
||||||
list(APPEND ${OUTLIST_BC} ${OUTPUT_BC})
|
list(APPEND ${OUTLIST_BC} ${OUTPUT_BC})
|
||||||
|
|
||||||
list(FIND IGNORE_DI "${INPUT_D}" INDEX)
|
list(FIND GENERATE_DI "${INPUT_D}" INDEX)
|
||||||
if (INDEX EQUAL -1)
|
if (INDEX EQUAL -1)
|
||||||
string(REGEX REPLACE "^src/" "druntime/" di_output ${output})
|
set(DI_CMD "")
|
||||||
set(DI_CMD -Hf=${CMAKE_BINARY_DIR}/import/${di_output}.di)
|
|
||||||
else (INDEX EQUAL -1)
|
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)
|
endif (INDEX EQUAL -1)
|
||||||
|
|
||||||
# Compile
|
# Compile
|
||||||
@@ -233,12 +240,12 @@ foreach(f ${DCRT_D})
|
|||||||
endforeach(f)
|
endforeach(f)
|
||||||
|
|
||||||
if(BUILD_SINGLE_LIB)
|
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})
|
set(LIBS ${RUNTIME_AIO})
|
||||||
else(BUILD_SINGLE_LIB)
|
else(BUILD_SINGLE_LIB)
|
||||||
add_library(${RUNTIME_CC} ${CORE_O} ${CORE_C})
|
add_library(${RUNTIME_CC} ${D_LIBRARY_TYPE} ${CORE_O} ${CORE_C})
|
||||||
add_library(${RUNTIME_GC} ${GC_O})
|
add_library(${RUNTIME_GC} ${D_LIBRARY_TYPE} ${GC_O})
|
||||||
add_library(${RUNTIME_DC} ${DCRT_O} ${DCRT_C})
|
add_library(${RUNTIME_DC} ${D_LIBRARY_TYPE} ${DCRT_O} ${DCRT_C})
|
||||||
set(LIBS
|
set(LIBS
|
||||||
${RUNTIME_CC}
|
${RUNTIME_CC}
|
||||||
${RUNTIME_GC}
|
${RUNTIME_GC}
|
||||||
@@ -289,12 +296,21 @@ if(PHOBOS2_DIR)
|
|||||||
dc(${f} PHOBOS2_O PHOBOS2_BC ${RUNTIME_DIR}/src/ "-I${PHOBOS2_DIR}" ${PHOBOS2_DIR})
|
dc(${f} PHOBOS2_O PHOBOS2_BC ${RUNTIME_DIR}/src/ "-I${PHOBOS2_DIR}" ${PHOBOS2_DIR})
|
||||||
endforeach(f)
|
endforeach(f)
|
||||||
|
|
||||||
add_library(phobos2 ${ZLIB_C} ${PHOBOS2_O} ${CORE_O} ${CORE_C} ${GC_O} ${DCRT_O} ${DCRT_C})
|
add_library(lphobos2 ${D_LIBRARY_TYPE}
|
||||||
add_dependencies(phobos2 runtime)
|
${ZLIB_C}
|
||||||
|
${PHOBOS2_O}
|
||||||
|
${CORE_O}
|
||||||
|
${CORE_C}
|
||||||
|
${GC_O}
|
||||||
|
${DCRT_O}
|
||||||
|
${DCRT_C}
|
||||||
|
)
|
||||||
|
add_dependencies(lphobos2 runtime)
|
||||||
set_target_properties(
|
set_target_properties(
|
||||||
phobos2 PROPERTIES
|
lphobos2 PROPERTIES
|
||||||
LINKER_LANGUAGE C
|
LINKER_LANGUAGE C
|
||||||
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../lib
|
ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../lib
|
||||||
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../lib
|
LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/../lib
|
||||||
)
|
)
|
||||||
|
add_custom_target(phobos2 DEPENDS lphobos2)
|
||||||
endif(PHOBOS2_DIR)
|
endif(PHOBOS2_DIR)
|
||||||
|
|||||||
Reference in New Issue
Block a user