- Fixed x86-32 C ABI for complex number return values.

- Removed unused code from the ABI class.
This commit is contained in:
Tomas Lindquist Olsen 2009-03-01 19:01:05 +01:00
parent 757601af09
commit 61dfb11bc5
7 changed files with 110 additions and 36 deletions

View file

@ -85,7 +85,65 @@ struct X87_complex_swap : ABIRetRewrite
}
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()
{
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();
// D only returns structs on the stack
if (tf->linkage == LINKd)
return (rt->ty == Tstruct);
}
bool passByRef(Type* t)
{
t = t->toBasetype();
return (t->ty == Tstruct || t->ty == Tsarray);
// other ABI's follow C, which is cdouble and creal returned on the stack
// as well as structs
else
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);
}
bool returnInArg(Type* t)
bool returnInArg(TypeFunction* tf)
{
Type* rt = t->toBasetype();
Type* rt = tf->next->toBasetype();
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.
}
bool returnInArg(Type* t)
bool returnInArg(TypeFunction* tf)
{
Type* rt = t->toBasetype();
Type* rt = tf->next->toBasetype();
return (rt->ty == Tstruct);
}
bool passByRef(Type* t)
{
t = t->toBasetype();
return (t->ty == Tstruct || t->ty == Tsarray);
}
};
//////////////////////////////////////////////////////////////////////////////

View file

@ -38,8 +38,7 @@ struct TargetABI
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;
virtual bool returnInArg(TypeFunction* t) = 0;
protected:
std::vector<ABIRetRewrite*> retOps;

View file

@ -79,7 +79,7 @@ const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, co
}
else
{
if (gABI->returnInArg(rt))
if (gABI->returnInArg(f))
{
rettype = getPtrToType(DtoType(rt));
actualRettype = LLType::VoidTy;

View file

@ -392,6 +392,8 @@ LLValue* DtoNestedContext(Loc loc, Dsymbol* sym)
// ASSIGNMENT HELPER (store this in that)
////////////////////////////////////////////////////////////////////////////////////////*/
// is this a good approach at all ?
void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
{
Logger::println("DtoAssign(...);\n");
@ -402,7 +404,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
if (t->ty == Tstruct) {
if (!t->equals(t2)) {
// TODO: fix this, use 'rhs' for something
// FIXME: use 'rhs' for something !?!
DtoAggrZeroInit(lhs->getLVal());
}
else {
@ -476,7 +478,7 @@ void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
DtoStore(r, l);
}
else if (t->iscomplex()) {
LLValue* dst;
LLValue *dst, *src;
if (DLRValue* lr = lhs->isLRValue()) {
dst = lr->getLVal();
rhs = DtoCastComplex(loc, rhs, lr->getLType());

View file

@ -175,6 +175,13 @@ static LLValue* x86_64_cfloatRetFixup(IRBuilderHelper b, LLValue* orig) {
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)
{
Logger::println("emitABIReturnAsmStmt(%s)", fdecl->mangle());
@ -204,8 +211,19 @@ void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
else if (rt->isfloating())
{
if (rt->iscomplex()) {
if (fdecl->linkage == LINKd) {
// 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 {
as->out_c = "={st},";
}

View file

@ -527,5 +527,10 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions*
call.setCallingConv(callconv);
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);
}

View file

@ -131,7 +131,10 @@ extern(C) cfloat cf_C()
{
version(X86)
{
asm { fld1; fld two_f; }
asm {
mov EAX, [one_f];
mov EDX, [two_f];
}
}
else version (X86_64)
{
@ -180,8 +183,8 @@ extern(C) cfloat cf2_C()
asm
{
naked;
fld1;
fld two_f;
mov EAX, [one_f];
mov EDX, [two_f];
ret;
}
}