view gen/complex.cpp @ 454:283d113d4753

Added generation of the llvm 'sret' parameter attribute where applicable. Fixed some wrong argument handling code when setting parameter attributes. Updated the tango unittest script in the tango patch, does not work yet, all modules don't compile...
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Sat, 02 Aug 2008 02:54:57 +0200
parents cc40db549aea
children 672eb4893b55
line wrap: on
line source

#include "gen/llvm.h"

#include "mtype.h"
#include "declaration.h"

#include "gen/complex.h"
#include "gen/tollvm.h"
#include "gen/llvmhelpers.h"
#include "gen/irstate.h"
#include "gen/dvalue.h"

//////////////////////////////////////////////////////////////////////////////////////////

const llvm::StructType* DtoComplexType(Type* type)
{
    Type* t = DtoDType(type);

    const LLType* base = DtoComplexBaseType(t);

    std::vector<const LLType*> types;
    types.push_back(base);
    types.push_back(base);

    return llvm::StructType::get(types);
}

const LLType* DtoComplexBaseType(Type* t)
{
    TY ty = DtoDType(t)->ty;
    const LLType* base;
    if (ty == Tcomplex32) {
        return LLType::FloatTy;
    }
    else if (ty == Tcomplex64) {
        return LLType::DoubleTy;
    }
    else if (ty == Tcomplex80) {
        if (global.params.cpu == ARCHx86)
            return LLType::X86_FP80Ty;
        else
            return LLType::DoubleTy;
    }
    else {
        assert(0);
    }
}

//////////////////////////////////////////////////////////////////////////////////////////

LLConstant* DtoConstComplex(Type* ty, LLConstant* re, LLConstant* im)
{
    assert(0);
    const LLType* base = DtoComplexBaseType(ty);

    std::vector<LLConstant*> inits;
    inits.push_back(re);
    inits.push_back(im);

    const llvm::VectorType* vt = llvm::VectorType::get(base, 2);
    return llvm::ConstantVector::get(vt, inits);
}

LLConstant* DtoConstComplex(Type* _ty, long double re, long double im)
{
    TY ty = DtoDType(_ty)->ty;

    llvm::ConstantFP* fre;
    llvm::ConstantFP* fim;

    Type* base = 0;

    if (ty == Tcomplex32) {
        base = Type::tfloat32;
    }
    else if (ty == Tcomplex64) {
        base = Type::tfloat64;
    }
    else if (ty == Tcomplex80) {
        base = Type::tfloat80;
    }

    std::vector<LLConstant*> inits;
    inits.push_back(DtoConstFP(base, re));
    inits.push_back(DtoConstFP(base, im));

    return llvm::ConstantStruct::get(DtoComplexType(_ty), inits);
}

//////////////////////////////////////////////////////////////////////////////////////////

LLValue* DtoRealPart(DValue* val)
{
    assert(0);
    return gIR->ir->CreateExtractElement(val->getRVal(), DtoConstUint(0), "tmp");
}

//////////////////////////////////////////////////////////////////////////////////////////

LLValue* DtoImagPart(DValue* val)
{
    assert(0);
    return gIR->ir->CreateExtractElement(val->getRVal(), DtoConstUint(1), "tmp");
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoComplex(Loc& loc, Type* to, DValue* val)
{
    Type* t = DtoDType(val->getType());

    if (val->isComplex() || t->iscomplex()) {
        return DtoCastComplex(loc, val, to);
    }

    const LLType* base = DtoComplexBaseType(to);

    Type* baserety;
    Type* baseimty;
    TY ty = to->ty;
    if (ty == Tcomplex32) {
        baserety = Type::tfloat32;
        baseimty = Type::timaginary32;
    } else if (ty == Tcomplex64) {
        baserety = Type::tfloat64;
        baseimty = Type::timaginary64;
    } else if (ty == Tcomplex80) {
        baserety = Type::tfloat80;
        baseimty = Type::timaginary80;
    }

    if (t->isimaginary()) {
        return new DComplexValue(to, LLConstant::getNullValue(DtoType(baserety)), DtoCastFloat(loc, val, baseimty)->getRVal());
    }
    else if (t->isfloating()) {
        return new DComplexValue(to, DtoCastFloat(loc, val, baserety)->getRVal(), LLConstant::getNullValue(DtoType(baseimty)));
    }
    else if (t->isintegral()) {
        return new DComplexValue(to, DtoCastInt(loc, val, baserety)->getRVal(), LLConstant::getNullValue(DtoType(baseimty)));
    }
    assert(0);
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoComplexAssign(LLValue* l, LLValue* r)
{
    DtoStore(DtoLoad(DtoGEPi(r, 0,0, "tmp")), DtoGEPi(l,0,0,"tmp"));
    DtoStore(DtoLoad(DtoGEPi(r, 0,1, "tmp")), DtoGEPi(l,0,1,"tmp"));
}

void DtoComplexSet(LLValue* c, LLValue* re, LLValue* im)
{
    DtoStore(re, DtoGEPi(c,0,0,"tmp"));
    DtoStore(im, DtoGEPi(c,0,1,"tmp"));
}

//////////////////////////////////////////////////////////////////////////////////////////

void DtoGetComplexParts(DValue* c, LLValue*& re, LLValue*& im)
{
    // get LLValues
    if (DComplexValue* cx = c->isComplex()) {
        re = cx->re;
        im = cx->im;
    }
    else {
        re = DtoLoad(DtoGEPi(c->getRVal(),0,0,"tmp"));
        im = DtoLoad(DtoGEPi(c->getRVal(),0,1,"tmp"));
    }
}

DValue* resolveLR(DValue* val, bool getlval)
{
    if (DLRValue* lr = val->isLRValue()) {
        if (getlval)
            return lr->lvalue;
        else
            return lr->rvalue;
    }
    return val;
}

//////////////////////////////////////////////////////////////////////////////////////////

bool hasRe(Type* t)
{
    return 
        (t->ty != Timaginary32 && 
         t->ty != Timaginary64 &&
         t->ty != Timaginary80);
}

bool hasIm(Type* t)
{
    return 
        (t->ty == Timaginary32 || 
         t->ty == Timaginary64 ||
         t->ty == Timaginary80 ||
         t->ty == Tcomplex32 || 
         t->ty == Tcomplex64 ||
         t->ty == Tcomplex80);
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoComplexAdd(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
    DValue* clhs = DtoComplex(loc, type, resolveLR(lhs, true));
    DValue* crhs = DtoComplex(loc, type, resolveLR(rhs, false));

    llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im;

    // lhs values
    DtoGetComplexParts(clhs, lhs_re, lhs_im);
    // rhs values
    DtoGetComplexParts(crhs, rhs_re, rhs_im);

    // add up
    Type* lhstype = lhs->getType();
    Type* rhstype = rhs->getType();
    if(hasRe(lhstype) && hasRe(rhstype))
        res_re = gIR->ir->CreateAdd(lhs_re, rhs_re, "tmp");
    else if(hasRe(lhstype))
        res_re = lhs_re;
    else // either hasRe(rhstype) or no re at all (then use any)
        res_re = rhs_re;
    
    if(hasIm(lhstype) && hasIm(rhstype))
        res_im = gIR->ir->CreateAdd(lhs_im, rhs_im, "tmp");
    else if(hasIm(lhstype))
        res_im = lhs_im;
    else // either hasIm(rhstype) or no im at all (then use any)
        res_im = rhs_im;

    return new DComplexValue(type, res_re, res_im);
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoComplexSub(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
    DValue* clhs = DtoComplex(loc, type, resolveLR(lhs, true));
    DValue* crhs = DtoComplex(loc, type, resolveLR(rhs, false));

    llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im;

    // lhs values
    DtoGetComplexParts(clhs, lhs_re, lhs_im);
    // rhs values
    DtoGetComplexParts(crhs, rhs_re, rhs_im);

    // sub up
    Type* lhstype = lhs->getType();
    Type* rhstype = rhs->getType();
    if(hasRe(rhstype))
        res_re = gIR->ir->CreateSub(lhs_re, rhs_re, "tmp");
    else
        res_re = lhs_re;
    
    if(hasIm(rhstype))
        res_im = gIR->ir->CreateSub(lhs_im, rhs_im, "tmp");
    else
        res_im = lhs_im;

    return new DComplexValue(type, res_re, res_im);
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoComplexMul(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
    DValue* clhs = DtoComplex(loc, type, resolveLR(lhs, true));
    DValue* crhs = DtoComplex(loc, type, resolveLR(rhs, false));

    llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im;

    // lhs values
    DtoGetComplexParts(clhs, lhs_re, lhs_im);
    // rhs values
    DtoGetComplexParts(crhs, rhs_re, rhs_im);

    // mul up
    llvm::Value *rere = NULL;
    llvm::Value *reim = NULL;
    llvm::Value *imre = NULL;
    llvm::Value *imim = NULL;
    Type* lhstype = lhs->getType();
    Type* rhstype = rhs->getType();

    if(hasRe(lhstype) && hasRe(rhstype))
        rere = gIR->ir->CreateMul(lhs_re, rhs_re, "rere_mul");
    if(hasRe(lhstype) && hasIm(rhstype))
        reim = gIR->ir->CreateMul(lhs_re, rhs_im, "reim_mul");
    if(hasIm(lhstype) && hasRe(rhstype))
        imre = gIR->ir->CreateMul(lhs_im, rhs_re, "imre_mul");
    if(hasIm(lhstype) && hasIm(rhstype))
        imim = gIR->ir->CreateMul(lhs_im, rhs_im, "imim_mul");

    if(rere && imim)
        res_re = gIR->ir->CreateSub(rere, imim, "rere_imim_sub");
    else if(rere)
        res_re = rere;
    else if(imim)
        res_re = gIR->ir->CreateNeg(imim, "imim_neg");
    else
        res_re = hasRe(lhstype) ? rhs_re : lhs_re; // null!

    if(reim && imre)
        res_im = gIR->ir->CreateAdd(reim, imre, "reim_imre_add");
    else if(reim)
        res_im = reim;
    else if(imre)
        res_im = imre;
    else
        res_im = hasRe(lhstype) ? rhs_im : lhs_re; // null!

    return new DComplexValue(type, res_re, res_im);
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoComplexDiv(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
    DValue* clhs = DtoComplex(loc, type, resolveLR(lhs, true));
    DValue* crhs = DtoComplex(loc, type, resolveLR(rhs, false));

    llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im;

    // lhs values
    DtoGetComplexParts(clhs, lhs_re, lhs_im);
    // rhs values
    DtoGetComplexParts(crhs, rhs_re, rhs_im);

    Type* lhstype = lhs->getType();
    Type* rhstype = rhs->getType();

    // if divisor is only real, division is simple
    if(hasRe(rhstype) && !hasIm(rhstype)) {
        if(hasRe(lhstype))
            res_re = gIR->ir->CreateFDiv(lhs_re, rhs_re, "re_divby_re");
        else
            res_re = lhs_re;
        if(hasIm(lhstype))
            res_im = gIR->ir->CreateFDiv(lhs_im, rhs_re, "im_divby_re");
        else
            res_im = lhs_im;
    }
    // if divisor is only imaginary, division is simple too
    else if(!hasRe(rhstype) && hasIm(rhstype)) {
        if(hasRe(lhstype))
            res_im = gIR->ir->CreateNeg(gIR->ir->CreateFDiv(lhs_re, rhs_im, "re_divby_im"), "neg");
        else
            res_im = lhs_re;
        if(hasIm(lhstype))
            res_re = gIR->ir->CreateFDiv(lhs_im, rhs_im, "im_divby_im");
        else
            res_re = lhs_im;
    }
    // full division
    else {
        llvm::Value *tmp1, *tmp2, *denom;

        if(hasRe(lhstype) && hasIm(lhstype)) {
            tmp1 = gIR->ir->CreateMul(lhs_re, rhs_re, "rere");
            tmp2 = gIR->ir->CreateMul(lhs_im, rhs_im, "imim");
            res_re = gIR->ir->CreateAdd(tmp1, tmp2, "rere_plus_imim");

            tmp1 = gIR->ir->CreateMul(lhs_re, rhs_im, "reim");
            tmp2 = gIR->ir->CreateMul(lhs_im, rhs_re, "imre");
            res_im = gIR->ir->CreateSub(tmp2, tmp1, "imre_sub_reim");
        }
        else if(hasRe(lhstype)) {
            res_re = gIR->ir->CreateMul(lhs_re, rhs_re, "rere");

            res_im = gIR->ir->CreateMul(lhs_re, rhs_im, "reim");
            res_im = gIR->ir->CreateNeg(res_im);
        }
        else if(hasIm(lhstype)) {
            res_re = gIR->ir->CreateMul(lhs_im, rhs_im, "imim");
            res_im = gIR->ir->CreateMul(lhs_im, rhs_re, "imre");
        }
        else
            assert(0 && "lhs has neither real nor imaginary part");

        tmp1 = gIR->ir->CreateMul(rhs_re, rhs_re, "rhs_resq");
        tmp2 = gIR->ir->CreateMul(rhs_im, rhs_im, "rhs_imsq");
        denom = gIR->ir->CreateAdd(tmp1, tmp2, "denom");

        res_re = gIR->ir->CreateFDiv(res_re, denom, "res_re");
        res_im = gIR->ir->CreateFDiv(res_im, denom, "res_im");
    }

    return new DComplexValue(type, res_re, res_im);
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoComplexNeg(Loc& loc, Type* type, DValue* val)
{
    val = DtoComplex(loc, type, resolveLR(val, false));

    llvm::Value *a, *b, *re, *im;

    // values
    DtoGetComplexParts(val, a, b);

    // sub up
    re = gIR->ir->CreateNeg(a, "tmp");
    im = gIR->ir->CreateNeg(b, "tmp");

    return new DComplexValue(type, re, im);
}

//////////////////////////////////////////////////////////////////////////////////////////

LLValue* DtoComplexEquals(Loc& loc, TOK op, DValue* lhs, DValue* rhs)
{
    Type* type = lhs->getType();

    lhs = DtoComplex(loc, type, resolveLR(lhs, false));
    rhs = DtoComplex(loc, type, resolveLR(rhs, false));

    llvm::Value *a, *b, *c, *d;

    // lhs values
    DtoGetComplexParts(lhs, a, b);
    // rhs values
    DtoGetComplexParts(rhs, c, d);

    // select predicate
    llvm::FCmpInst::Predicate cmpop;
    if (op == TOKequal)
        cmpop = llvm::FCmpInst::FCMP_OEQ;
    else
        cmpop = llvm::FCmpInst::FCMP_UNE;

    // (l.re==r.re && l.im==r.im) or (l.re!=r.re || l.im!=r.im)
    LLValue* b1 = new llvm::FCmpInst(cmpop, a, c, "tmp", gIR->scopebb());
    LLValue* b2 = new llvm::FCmpInst(cmpop, b, d, "tmp", gIR->scopebb());

    if (op == TOKequal)
        return gIR->ir->CreateAnd(b1,b2,"tmp");
    else
        return gIR->ir->CreateOr(b1,b2,"tmp");
}

//////////////////////////////////////////////////////////////////////////////////////////

DValue* DtoCastComplex(Loc& loc, DValue* val, Type* _to)
{
    Type* to = DtoDType(_to);
    Type* vty = val->getType();
    if (to->iscomplex()) {
        if (vty->size() == to->size())
            return val;

        llvm::Value *re, *im;
        DtoGetComplexParts(val, re, im);
        const LLType* toty = DtoComplexBaseType(to);

        if (to->size() < vty->size()) {
            re = gIR->ir->CreateFPTrunc(re, toty, "tmp");
            im = gIR->ir->CreateFPTrunc(im, toty, "tmp");
        }
        else if (to->size() > vty->size()) {
            re = gIR->ir->CreateFPExt(re, toty, "tmp");
            im = gIR->ir->CreateFPExt(im, toty, "tmp");
        }
        else {
            return val;
        }

        if (val->isComplex())
            return new DComplexValue(_to, re, im);

        // unfortunately at this point, the cast value can show up as the lvalue for += and similar expressions.
        // so we need to give it storage, or fix the system that handles this stuff (DLRValue)
        LLValue* mem = new llvm::AllocaInst(DtoType(_to), "castcomplextmp", gIR->topallocapoint());
        DtoComplexSet(mem, re, im);
        return new DLRValue(val, new DImValue(_to, mem));
    }
    else if (to->isimaginary()) {
        if (val->isComplex())
            return new DImValue(to, val->isComplex()->im);
        LLValue* v = val->getRVal();
        DImValue* im = new DImValue(to, DtoLoad(DtoGEPi(v,0,1,"tmp")));
        return DtoCastFloat(loc, im, to);
    }
    else if (to->isfloating()) {
        if (val->isComplex())
            return new DImValue(to, val->isComplex()->re);
        LLValue* v = val->getRVal();
        DImValue* re = new DImValue(to, DtoLoad(DtoGEPi(v,0,0,"tmp")));
        return DtoCastFloat(loc, re, to);
    }
    else
    assert(0);
}