mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-05 09:31:03 +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
97
gen/abi.cpp
97
gen/abi.cpp
|
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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},";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue