view gen/abi.cpp @ 989:420ef073448d

Forgot new files that were supposed to be in last commit.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Thu, 26 Feb 2009 14:13:27 +0100
parents
children 223a679053dd
line wrap: on
line source

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