mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-02-16 20:03:14 +01:00
Forgot new files that were supposed to be in last commit.
This commit is contained in:
225
gen/abi.cpp
Normal file
225
gen/abi.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
#include "gen/llvm.h"
|
||||
|
||||
#include "mars.h"
|
||||
|
||||
#include "gen/irstate.h"
|
||||
#include "gen/llvmhelpers.h"
|
||||
#include "gen/tollvm.h"
|
||||
#include "gen/abi.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////// baseclass ////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FIXME: Would be nice to come up a better and faster way to do this, right
|
||||
// now I'm more worried about actually making this abstraction work at all ...
|
||||
// It's definitely way overkill with the amount of return value rewrites we
|
||||
// have right now, but I expect this to change with proper x86-64 abi support
|
||||
|
||||
TargetABI::TargetABI()
|
||||
{
|
||||
}
|
||||
|
||||
llvm::Value* TargetABI::getRet(TypeFunction* tf, llvm::Value* io)
|
||||
{
|
||||
if (ABIRetRewrite* r = findRetRewrite(tf))
|
||||
{
|
||||
return r->get(io);
|
||||
}
|
||||
return io;
|
||||
}
|
||||
|
||||
llvm::Value* TargetABI::putRet(TypeFunction* tf, llvm::Value* io)
|
||||
{
|
||||
if (ABIRetRewrite* r = findRetRewrite(tf))
|
||||
{
|
||||
return r->put(io);
|
||||
}
|
||||
return io;
|
||||
}
|
||||
|
||||
const llvm::Type* TargetABI::getRetType(TypeFunction* tf, const llvm::Type* t)
|
||||
{
|
||||
if (ABIRetRewrite* r = findRetRewrite(tf))
|
||||
{
|
||||
return r->type(t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
ABIRetRewrite * TargetABI::findRetRewrite(TypeFunction * tf)
|
||||
{
|
||||
size_t n = retOps.size();
|
||||
if (n)
|
||||
for (size_t i = 0; i < n; i++)
|
||||
{
|
||||
if (retOps[i]->test(tf))
|
||||
return retOps[i];
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
///////////////////// X86 ////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// simply swap of real/imag parts for proper x87 complex abi
|
||||
struct X87_complex_swap : ABIRetRewrite
|
||||
{
|
||||
LLValue* get(LLValue* v)
|
||||
{
|
||||
return DtoAggrPairSwap(v);
|
||||
}
|
||||
LLValue* put(LLValue* v)
|
||||
{
|
||||
return DtoAggrPairSwap(v);
|
||||
}
|
||||
const LLType* type(const LLType* t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
bool test(TypeFunction* tf)
|
||||
{
|
||||
return (tf->next->toBasetype()->iscomplex());
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct X86TargetABI : TargetABI
|
||||
{
|
||||
X86TargetABI()
|
||||
{
|
||||
retOps.push_back(new X87_complex_swap);
|
||||
}
|
||||
|
||||
bool returnInArg(Type* t)
|
||||
{
|
||||
Type* rt = t->toBasetype();
|
||||
return (rt->ty == Tstruct);
|
||||
}
|
||||
|
||||
bool passByRef(Type* t)
|
||||
{
|
||||
t = t->toBasetype();
|
||||
return (t->ty == Tstruct || t->ty == Tsarray);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////// X86-64 //////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct X86_64_cfloat_rewrite : ABIRetRewrite
|
||||
{
|
||||
// {double} -> {float,float}
|
||||
LLValue* get(LLValue* in)
|
||||
{
|
||||
// extract double
|
||||
LLValue* v = gIR->ir->CreateExtractValue(in, 0);
|
||||
// cast to i64
|
||||
v = gIR->ir->CreateBitCast(v, LLType::Int64Ty);
|
||||
|
||||
// extract real part
|
||||
LLValue* rpart = gIR->ir->CreateTrunc(v, LLType::Int32Ty);
|
||||
rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re");
|
||||
|
||||
// extract imag part
|
||||
LLValue* ipart = gIR->ir->CreateLShr(v, 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} -> {double}
|
||||
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
|
||||
v = gIR->ir->CreateOr(r, i);
|
||||
|
||||
// cast to double
|
||||
v = gIR->ir->CreateBitCast(v, LLType::DoubleTy);
|
||||
|
||||
// return {double}
|
||||
const LLType* t = LLStructType::get(LLType::DoubleTy, 0);
|
||||
LLValue* undef = llvm::UndefValue::get(t);
|
||||
return gIR->ir->CreateInsertValue(undef, v, 0);
|
||||
}
|
||||
|
||||
// {float,float} -> {double}
|
||||
const LLType* type(const LLType* t)
|
||||
{
|
||||
return LLStructType::get(LLType::DoubleTy, 0);
|
||||
}
|
||||
|
||||
// test if rewrite applies to function
|
||||
bool test(TypeFunction* tf)
|
||||
{
|
||||
return (tf->next->toBasetype() == Type::tcomplex32);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
struct X86_64TargetABI : TargetABI
|
||||
{
|
||||
X86_64TargetABI()
|
||||
{
|
||||
retOps.push_back(new X86_64_cfloat_rewrite);
|
||||
}
|
||||
|
||||
bool returnInArg(Type* t)
|
||||
{
|
||||
Type* rt = t->toBasetype();
|
||||
return (rt->ty == Tstruct);
|
||||
}
|
||||
|
||||
bool passByRef(Type* t)
|
||||
{
|
||||
t = t->toBasetype();
|
||||
return (t->ty == Tstruct || t->ty == Tsarray);
|
||||
}
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
TargetABI * TargetABI::getTarget()
|
||||
{
|
||||
switch(global.params.cpu)
|
||||
{
|
||||
case ARCHx86:
|
||||
return new X86TargetABI;
|
||||
case ARCHx86_64:
|
||||
return new X86_64TargetABI;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user