mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-06 10:57:35 +03:00
- Fixed x86-32 C ABI for complex number return values.
- Removed unused code from the ABI class.
This commit is contained in:
parent
757601af09
commit
61dfb11bc5
7 changed files with 110 additions and 36 deletions
99
gen/abi.cpp
99
gen/abi.cpp
|
@ -85,7 +85,65 @@ struct X87_complex_swap : ABIRetRewrite
|
||||||
}
|
}
|
||||||
bool test(TypeFunction* tf)
|
bool test(TypeFunction* tf)
|
||||||
{
|
{
|
||||||
return (tf->next->toBasetype()->iscomplex());
|
// extern(D) && is(T:creal)
|
||||||
|
return (tf->linkage == LINKd && tf->next->toBasetype()->iscomplex());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct X86_cfloat_rewrite : ABIRetRewrite
|
||||||
|
{
|
||||||
|
// i64 -> {float,float}
|
||||||
|
LLValue* get(LLValue* in)
|
||||||
|
{
|
||||||
|
// extract real part
|
||||||
|
LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty);
|
||||||
|
rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re");
|
||||||
|
|
||||||
|
// extract imag part
|
||||||
|
LLValue* ipart = gIR->ir->CreateLShr(in, 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} -> i64
|
||||||
|
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 and return
|
||||||
|
return v = gIR->ir->CreateOr(r, i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// {float,float} -> i64
|
||||||
|
const LLType* type(const LLType* t)
|
||||||
|
{
|
||||||
|
return LLType::Int64Ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
// test if rewrite applies to function
|
||||||
|
bool test(TypeFunction* tf)
|
||||||
|
{
|
||||||
|
return (tf->linkage != LINKd)
|
||||||
|
&& (tf->next->toBasetype() == Type::tcomplex32);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,18 +154,19 @@ struct X86TargetABI : TargetABI
|
||||||
X86TargetABI()
|
X86TargetABI()
|
||||||
{
|
{
|
||||||
retOps.push_back(new X87_complex_swap);
|
retOps.push_back(new X87_complex_swap);
|
||||||
|
retOps.push_back(new X86_cfloat_rewrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool returnInArg(Type* t)
|
bool returnInArg(TypeFunction* tf)
|
||||||
{
|
{
|
||||||
Type* rt = t->toBasetype();
|
Type* rt = tf->next->toBasetype();
|
||||||
return (rt->ty == Tstruct);
|
// D only returns structs on the stack
|
||||||
}
|
if (tf->linkage == LINKd)
|
||||||
|
return (rt->ty == Tstruct);
|
||||||
bool passByRef(Type* t)
|
// other ABI's follow C, which is cdouble and creal returned on the stack
|
||||||
{
|
// as well as structs
|
||||||
t = t->toBasetype();
|
else
|
||||||
return (t->ty == Tstruct || t->ty == Tsarray);
|
return (rt->ty == Tstruct || rt->ty == Tcomplex64 || rt->ty == Tcomplex80);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -194,17 +253,11 @@ struct X86_64TargetABI : TargetABI
|
||||||
retOps.push_back(new X86_64_cfloat_rewrite);
|
retOps.push_back(new X86_64_cfloat_rewrite);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool returnInArg(Type* t)
|
bool returnInArg(TypeFunction* tf)
|
||||||
{
|
{
|
||||||
Type* rt = t->toBasetype();
|
Type* rt = tf->next->toBasetype();
|
||||||
return (rt->ty == Tstruct);
|
return (rt->ty == Tstruct);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool passByRef(Type* t)
|
|
||||||
{
|
|
||||||
t = t->toBasetype();
|
|
||||||
return (t->ty == Tstruct || t->ty == Tsarray);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -221,17 +274,11 @@ struct UnknownTargetABI : TargetABI
|
||||||
// Don't push anything into retOps, assume defaults will be fine.
|
// Don't push anything into retOps, assume defaults will be fine.
|
||||||
}
|
}
|
||||||
|
|
||||||
bool returnInArg(Type* t)
|
bool returnInArg(TypeFunction* tf)
|
||||||
{
|
{
|
||||||
Type* rt = t->toBasetype();
|
Type* rt = tf->next->toBasetype();
|
||||||
return (rt->ty == Tstruct);
|
return (rt->ty == Tstruct);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool passByRef(Type* t)
|
|
||||||
{
|
|
||||||
t = t->toBasetype();
|
|
||||||
return (t->ty == Tstruct || t->ty == Tsarray);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
|
@ -38,8 +38,7 @@ struct TargetABI
|
||||||
llvm::Value* getRet(TypeFunction* tf, llvm::Value* v);
|
llvm::Value* getRet(TypeFunction* tf, llvm::Value* v);
|
||||||
llvm::Value* putRet(TypeFunction* tf, llvm::Value* v);
|
llvm::Value* putRet(TypeFunction* tf, llvm::Value* v);
|
||||||
|
|
||||||
virtual bool returnInArg(Type* t) = 0;
|
virtual bool returnInArg(TypeFunction* t) = 0;
|
||||||
virtual bool passByRef(Type* t) = 0;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<ABIRetRewrite*> retOps;
|
std::vector<ABIRetRewrite*> retOps;
|
||||||
|
|
|
@ -79,7 +79,7 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (gABI->returnInArg(rt))
|
if (gABI->returnInArg(f))
|
||||||
{
|
{
|
||||||
rettype = getPtrToType(DtoType(rt));
|
rettype = getPtrToType(DtoType(rt));
|
||||||
actualRettype = LLType::VoidTy;
|
actualRettype = LLType::VoidTy;
|
||||||
|
|
|
@ -392,6 +392,8 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
|
||||||
// ASSIGNMENT HELPER (store this in that)
|
// ASSIGNMENT HELPER (store this in that)
|
||||||
////////////////////////////////////////////////////////////////////////////////////////*/
|
////////////////////////////////////////////////////////////////////////////////////////*/
|
||||||
|
|
||||||
|
// is this a good approach at all ?
|
||||||
|
|
||||||
void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
|
void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
|
||||||
{
|
{
|
||||||
Logger::println("DtoAssign(...);\n");
|
Logger::println("DtoAssign(...);\n");
|
||||||
|
@ -402,7 +404,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
|
||||||
|
|
||||||
if (t->ty == Tstruct) {
|
if (t->ty == Tstruct) {
|
||||||
if (!t->equals(t2)) {
|
if (!t->equals(t2)) {
|
||||||
// TODO: fix this, use 'rhs' for something
|
// FIXME: use 'rhs' for something !?!
|
||||||
DtoAggrZeroInit(lhs->getLVal());
|
DtoAggrZeroInit(lhs->getLVal());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -476,7 +478,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
|
||||||
DtoStore(r, l);
|
DtoStore(r, l);
|
||||||
}
|
}
|
||||||
else if (t->iscomplex()) {
|
else if (t->iscomplex()) {
|
||||||
LLValue* dst;
|
LLValue *dst, *src;
|
||||||
if (DLRValue* lr = lhs->isLRValue()) {
|
if (DLRValue* lr = lhs->isLRValue()) {
|
||||||
dst = lr->getLVal();
|
dst = lr->getLVal();
|
||||||
rhs = DtoCastComplex(loc, rhs, lr->getLType());
|
rhs = DtoCastComplex(loc, rhs, lr->getLType());
|
||||||
|
|
|
@ -175,6 +175,13 @@ static LLValue* x86_64_cfloatRetFixup(IRBuilderHelper b, LLValue* orig) {
|
||||||
return b->CreateInsertValue(undef, orig, 0, "asm.ret");
|
return b->CreateInsertValue(undef, orig, 0, "asm.ret");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LLValue* x86_cfloatRetFixup(IRBuilderHelper b, LLValue* orig) {
|
||||||
|
assert(orig->getType() == LLType::DoubleTy);
|
||||||
|
LLType* retty = LLStructType::get(LLType::DoubleTy, NULL);
|
||||||
|
LLValue* undef = llvm::UndefValue::get(retty);
|
||||||
|
return b->CreateInsertValue(undef, orig, 0, "asm.ret");
|
||||||
|
}
|
||||||
|
|
||||||
void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
|
void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
|
||||||
{
|
{
|
||||||
Logger::println("emitABIReturnAsmStmt(%s)", fdecl->mangle());
|
Logger::println("emitABIReturnAsmStmt(%s)", fdecl->mangle());
|
||||||
|
@ -204,8 +211,19 @@ void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
|
||||||
else if (rt->isfloating())
|
else if (rt->isfloating())
|
||||||
{
|
{
|
||||||
if (rt->iscomplex()) {
|
if (rt->iscomplex()) {
|
||||||
as->out_c = "={st},={st(1)},";
|
if (fdecl->linkage == LINKd) {
|
||||||
asmblock->retn = 2;
|
// extern(D) always returns on the FPU stack
|
||||||
|
as->out_c = "={st},={st(1)},";
|
||||||
|
asmblock->retn = 2;
|
||||||
|
} else if (rt->ty == Tcomplex32) {
|
||||||
|
// extern(C) cfloat is return as i64
|
||||||
|
as->out_c = "=A,";
|
||||||
|
asmblock->retty = LLType::Int64Ty;
|
||||||
|
} else {
|
||||||
|
// cdouble and creal extern(C) are returned in pointer
|
||||||
|
// don't add anything!
|
||||||
|
return;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
as->out_c = "={st},";
|
as->out_c = "={st},";
|
||||||
}
|
}
|
||||||
|
|
|
@ -527,5 +527,10 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
|
||||||
call.setCallingConv(callconv);
|
call.setCallingConv(callconv);
|
||||||
call.setAttributes(attrlist);
|
call.setAttributes(attrlist);
|
||||||
|
|
||||||
|
// if we are returning through a pointer arg
|
||||||
|
// make sure we provide a lvalue back!
|
||||||
|
if (retinptr)
|
||||||
|
return new DVarValue(resulttype, retllval);
|
||||||
|
|
||||||
return new DImValue(resulttype, retllval);
|
return new DImValue(resulttype, retllval);
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,10 @@ extern(C) cfloat cf_C()
|
||||||
{
|
{
|
||||||
version(X86)
|
version(X86)
|
||||||
{
|
{
|
||||||
asm { fld1; fld two_f; }
|
asm {
|
||||||
|
mov EAX, [one_f];
|
||||||
|
mov EDX, [two_f];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else version (X86_64)
|
else version (X86_64)
|
||||||
{
|
{
|
||||||
|
@ -180,8 +183,8 @@ extern(C) cfloat cf2_C()
|
||||||
asm
|
asm
|
||||||
{
|
{
|
||||||
naked;
|
naked;
|
||||||
fld1;
|
mov EAX, [one_f];
|
||||||
fld two_f;
|
mov EDX, [two_f];
|
||||||
ret;
|
ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue