- 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) 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);
}
}; };
////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////

View file

@ -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;

View file

@ -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;

View file

@ -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());

View file

@ -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},";
} }

View file

@ -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);
} }

View file

@ -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;
} }
} }