ldc/gen/complex.cpp
David Nadlinger 8ff3a8060a Use llvm_unreachable instead of assert(0).
Also removed some unused functions.
2013-02-07 03:38:15 +01:00

486 lines
16 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//===-- complex.cpp -------------------------------------------------------===//
//
// LDC the LLVM D compiler
//
// This file is distributed under the BSD-style LDC license. See the LICENSE
// file for details.
//
//===----------------------------------------------------------------------===//
#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"
#include "gen/logger.h"
//////////////////////////////////////////////////////////////////////////////////////////
llvm::StructType* DtoComplexType(Type* type)
{
Type* t = type->toBasetype();
LLType* base = DtoComplexBaseType(t);
llvm::SmallVector<LLType*, 2> types;
types.push_back(base);
types.push_back(base);
return llvm::StructType::get(gIR->context(), types);
}
LLType* DtoComplexBaseType(Type* t)
{
switch (t->toBasetype()->ty) {
default: llvm_unreachable("Unexpected complex floating point type");
case Tcomplex32: return LLType::getFloatTy(gIR->context());
case Tcomplex64: return LLType::getDoubleTy(gIR->context());
case Tcomplex80:
if ((global.params.cpu == ARCHx86) || (global.params.cpu == ARCHx86_64))
return LLType::getX86_FP80Ty(gIR->context());
else if (global.params.cpu == ARCHppc || global.params.cpu == ARCHppc_64)
return LLType::getPPC_FP128Ty(gIR->context());
else
return LLType::getDoubleTy(gIR->context());
}
}
//////////////////////////////////////////////////////////////////////////////////////////
LLConstant* DtoConstComplex(Type* _ty, longdouble re, longdouble im)
{
Type* base = 0;
switch (_ty->toBasetype()->ty) {
default: llvm_unreachable("Unexpected complex floating point type");
case Tcomplex32: base = Type::tfloat32; break;
case Tcomplex64: base = Type::tfloat64; break;
case Tcomplex80: base = Type::tfloat80; break;
}
std::vector<LLConstant*> inits;
inits.push_back(DtoConstFP(base, re));
inits.push_back(DtoConstFP(base, im));
return llvm::ConstantStruct::get(DtoComplexType(_ty), inits);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoComplex(Loc& loc, Type* to, DValue* val)
{
LLType* complexTy = DtoType(to);
Type* baserety;
Type* baseimty;
switch (to->toBasetype()->ty) {
default: llvm_unreachable("Unexpected complex floating point type");
case Tcomplex32:
baserety = Type::tfloat32;
baseimty = Type::timaginary32;
break;
case Tcomplex64:
baserety = Type::tfloat64;
baseimty = Type::timaginary64;
break;
case Tcomplex80:
baserety = Type::tfloat80;
baseimty = Type::timaginary80;
break;
}
LLValue *re, *im;
DtoGetComplexParts(loc, to, val, re, im);
if(!re)
re = LLConstant::getNullValue(DtoType(baserety));
if(!im)
im = LLConstant::getNullValue(DtoType(baseimty));
LLValue* res = DtoAggrPair(complexTy, re, im);
return new DImValue(to, res);
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoComplexSet(LLValue* c, LLValue* re, LLValue* im)
{
DtoStore(re, DtoGEPi(c, 0, 0, "tmp"));
DtoStore(im, DtoGEPi(c, 0, 1, "tmp"));
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoGetComplexParts(Loc& loc, Type* to, DValue* val, DValue*& re, DValue*& im)
{
Type* baserety;
Type* baseimty;
switch (to->toBasetype()->ty) {
default: llvm_unreachable("Unexpected complex floating point type");
case Tcomplex32:
baserety = Type::tfloat32;
baseimty = Type::timaginary32;
break;
case Tcomplex64:
baserety = Type::tfloat64;
baseimty = Type::timaginary64;
break;
case Tcomplex80:
baserety = Type::tfloat80;
baseimty = Type::timaginary80;
break;
}
Type* t = val->getType()->toBasetype();
if (t->iscomplex()) {
DValue* v = DtoCastComplex(loc, val, to);
if (to->iscomplex()) {
if (v->isLVal()) {
LLValue *reVal = DtoGEP(v->getLVal(), DtoConstInt(0), DtoConstInt(0), ".re_part");
LLValue *imVal = DtoGEP(v->getLVal(), DtoConstInt(0), DtoConstInt(1), ".im_part");
re = new DVarValue(baserety, reVal);
im = new DVarValue(baseimty, imVal);
} else {
LLValue *reVal = gIR->ir->CreateExtractValue(v->getRVal(), 0, ".re_part");
LLValue *imVal = gIR->ir->CreateExtractValue(v->getRVal(), 1, ".im_part");
re = new DImValue(baserety, reVal);
im = new DImValue(baseimty, imVal);
}
} else
DtoGetComplexParts(loc, to, v, re, im);
}
else if (t->isimaginary()) {
re = NULL;
im = DtoCastFloat(loc, val, baseimty);
}
else if (t->isfloating()) {
re = DtoCastFloat(loc, val, baserety);
im = NULL;
}
else if (t->isintegral()) {
re = DtoCastInt(loc, val, baserety);
im = NULL;
}
else {
llvm_unreachable("Unexpected numeric type.");
}
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoGetComplexParts(Loc& loc, Type* to, DValue* val, LLValue*& re, LLValue*& im)
{
DValue *dre, *dim;
DtoGetComplexParts(loc, to, val, dre, dim);
re = dre ? dre->getRVal() : 0;
im = dim ? dim->getRVal() : 0;
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoComplexAdd(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im;
// lhs values
DtoGetComplexParts(loc, type, lhs, lhs_re, lhs_im);
// rhs values
DtoGetComplexParts(loc, type, rhs, rhs_re, rhs_im);
// add up
if(lhs_re && rhs_re)
res_re = gIR->ir->CreateFAdd(lhs_re, rhs_re, "tmp");
else if(lhs_re)
res_re = lhs_re;
else // either rhs_re or no re at all (then use any)
res_re = rhs_re;
if(lhs_im && rhs_im)
res_im = gIR->ir->CreateFAdd(lhs_im, rhs_im, "tmp");
else if(lhs_im)
res_im = lhs_im;
else // either rhs_im or no im at all (then use any)
res_im = rhs_im;
LLValue* res = DtoAggrPair(DtoType(type), res_re, res_im);
return new DImValue(type, res);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoComplexSub(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im;
// lhs values
DtoGetComplexParts(loc, type, lhs, lhs_re, lhs_im);
// rhs values
DtoGetComplexParts(loc, type, rhs, rhs_re, rhs_im);
// add up
if(lhs_re && rhs_re)
res_re = gIR->ir->CreateFSub(lhs_re, rhs_re, "tmp");
else if(lhs_re)
res_re = lhs_re;
else // either rhs_re or no re at all (then use any)
res_re = gIR->ir->CreateFNeg(rhs_re, "neg");
if(lhs_im && rhs_im)
res_im = gIR->ir->CreateFSub(lhs_im, rhs_im, "tmp");
else if(lhs_im)
res_im = lhs_im;
else // either rhs_im or no im at all (then use any)
res_im = gIR->ir->CreateFNeg(rhs_im, "neg");
LLValue* res = DtoAggrPair(DtoType(type), res_re, res_im);
return new DImValue(type, res);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoComplexMul(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im;
// lhs values
DtoGetComplexParts(loc, type, lhs, lhs_re, lhs_im);
// rhs values
DtoGetComplexParts(loc, type, rhs, rhs_re, rhs_im);
// mul up
llvm::Value *rere = NULL;
llvm::Value *reim = NULL;
llvm::Value *imre = NULL;
llvm::Value *imim = NULL;
if(lhs_re && rhs_re)
rere = gIR->ir->CreateFMul(lhs_re, rhs_re, "rere_mul");
if(lhs_re && rhs_im)
reim = gIR->ir->CreateFMul(lhs_re, rhs_im, "reim_mul");
if(lhs_im && rhs_re)
imre = gIR->ir->CreateFMul(lhs_im, rhs_re, "imre_mul");
if(lhs_im && rhs_im)
imim = gIR->ir->CreateFMul(lhs_im, rhs_im, "imim_mul");
if(rere && imim)
res_re = gIR->ir->CreateFSub(rere, imim, "rere_imim_sub");
else if(rere)
res_re = rere;
else if(imim)
res_re = gIR->ir->CreateFNeg(imim, "imim_neg");
else
res_re = lhs_re ? rhs_re : lhs_re; // null!
if(reim && imre)
res_im = gIR->ir->CreateFAdd(reim, imre, "reim_imre_add");
else if(reim)
res_im = reim;
else if(imre)
res_im = imre;
else
res_im = lhs_re ? rhs_im : lhs_re; // null!
LLValue* res = DtoAggrPair(DtoType(type), res_re, res_im);
return new DImValue(type, res);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoComplexDiv(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im;
// lhs values
DtoGetComplexParts(loc, type, lhs, lhs_re, lhs_im);
// rhs values
DtoGetComplexParts(loc, type, rhs, rhs_re, rhs_im);
// if divisor is only real, division is simple
if(rhs_re && !rhs_im) {
if(lhs_re)
res_re = gIR->ir->CreateFDiv(lhs_re, rhs_re, "re_divby_re");
else
res_re = lhs_re;
if(lhs_im)
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(!rhs_re && rhs_im) {
if(lhs_re)
res_im = gIR->ir->CreateFNeg(gIR->ir->CreateFDiv(lhs_re, rhs_im, "re_divby_im"), "neg");
else
res_im = lhs_re;
if(lhs_im)
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(lhs_re && lhs_im) {
tmp1 = gIR->ir->CreateFMul(lhs_re, rhs_re, "rere");
tmp2 = gIR->ir->CreateFMul(lhs_im, rhs_im, "imim");
res_re = gIR->ir->CreateFAdd(tmp1, tmp2, "rere_plus_imim");
tmp1 = gIR->ir->CreateFMul(lhs_re, rhs_im, "reim");
tmp2 = gIR->ir->CreateFMul(lhs_im, rhs_re, "imre");
res_im = gIR->ir->CreateFSub(tmp2, tmp1, "imre_sub_reim");
}
else if(lhs_re) {
res_re = gIR->ir->CreateFMul(lhs_re, rhs_re, "rere");
res_im = gIR->ir->CreateFMul(lhs_re, rhs_im, "reim");
res_im = gIR->ir->CreateFNeg(res_im);
}
else if(lhs_im) {
res_re = gIR->ir->CreateFMul(lhs_im, rhs_im, "imim");
res_im = gIR->ir->CreateFMul(lhs_im, rhs_re, "imre");
}
else
llvm_unreachable("lhs has neither real nor imaginary part");
tmp1 = gIR->ir->CreateFMul(rhs_re, rhs_re, "rhs_resq");
tmp2 = gIR->ir->CreateFMul(rhs_im, rhs_im, "rhs_imsq");
denom = gIR->ir->CreateFAdd(tmp1, tmp2, "denom");
res_re = gIR->ir->CreateFDiv(res_re, denom, "res_re");
res_im = gIR->ir->CreateFDiv(res_im, denom, "res_im");
}
LLValue* res = DtoAggrPair(DtoType(type), res_re, res_im);
return new DImValue(type, res);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoComplexRem(Loc& loc, Type* type, DValue* lhs, DValue* rhs)
{
llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im, *divisor;
// lhs values
DtoGetComplexParts(loc, type, lhs, lhs_re, lhs_im);
// rhs values
DtoGetComplexParts(loc, type, rhs, rhs_re, rhs_im);
// Divisor can be real or imaginary but not complex
assert((rhs_re != 0) ^ (rhs_im != 0));
divisor = rhs_re ? rhs_re : rhs_im;
res_re = lhs_re ? gIR->ir->CreateFRem(lhs_re, divisor, "tmp") : lhs_re;
res_im = lhs_re ? gIR->ir->CreateFRem(lhs_im, divisor, "tmp") : lhs_im;
LLValue* res = DtoAggrPair(DtoType(type), res_re, res_im);
return new DImValue(type, res);
}
//////////////////////////////////////////////////////////////////////////////////////////
DValue* DtoComplexNeg(Loc& loc, Type* type, DValue* val)
{
llvm::Value *a, *b, *re, *im;
// values
DtoGetComplexParts(loc, type, val, a, b);
// neg up
assert(a && b);
re = gIR->ir->CreateFNeg(a, "tmp");
im = gIR->ir->CreateFNeg(b, "tmp");
LLValue* res = DtoAggrPair(DtoType(type), re, im);
return new DImValue(type, res);
}
//////////////////////////////////////////////////////////////////////////////////////////
LLValue* DtoComplexEquals(Loc& loc, TOK op, DValue* lhs, DValue* rhs)
{
Type* type = lhs->getType();
DValue *lhs_re, *lhs_im, *rhs_re, *rhs_im;
// lhs values
DtoGetComplexParts(loc, type, lhs, lhs_re, lhs_im);
// rhs values
DtoGetComplexParts(loc, type, rhs, rhs_re, rhs_im);
// (l.re==r.re && l.im==r.im) or (l.re!=r.re || l.im!=r.im)
LLValue* b1 = DtoBinFloatsEquals(loc, lhs_re, rhs_re, op);
LLValue* b2 = DtoBinFloatsEquals(loc, lhs_im, rhs_im, op);
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 = _to->toBasetype();
Type* vty = val->getType()->toBasetype();
if (to->iscomplex()) {
if (vty->size() == to->size())
return val;
llvm::Value *re, *im;
DtoGetComplexParts(loc, val->getType(), val, re, im);
LLType* toty = DtoComplexBaseType(to);
if (to->size() < vty->size()) {
re = gIR->ir->CreateFPTrunc(re, toty, "tmp");
im = gIR->ir->CreateFPTrunc(im, toty, "tmp");
}
else {
re = gIR->ir->CreateFPExt(re, toty, "tmp");
im = gIR->ir->CreateFPExt(im, toty, "tmp");
}
LLValue* pair = DtoAggrPair(DtoType(_to), re, im);
return new DImValue(_to, pair);
}
else if (to->isimaginary()) {
// FIXME: this loads both values, even when we only need one
LLValue* v = val->getRVal();
LLValue* impart = gIR->ir->CreateExtractValue(v, 1, ".im_part");
Type *extractty;
switch (vty->ty) {
default: llvm_unreachable("Unexpected complex floating point type");
case Tcomplex32: extractty = Type::timaginary32; break;
case Tcomplex64: extractty = Type::timaginary64; break;
case Tcomplex80: extractty = Type::timaginary80; break;
}
DImValue* im = new DImValue(extractty, impart);
return DtoCastFloat(loc, im, to);
}
else if (to->ty == Tbool) {
return new DImValue(_to, DtoComplexEquals(loc, TOKnotequal, val, DtoNullValue(vty)));
}
else if (to->isfloating() || to->isintegral()) {
// FIXME: this loads both values, even when we only need one
LLValue* v = val->getRVal();
LLValue* repart = gIR->ir->CreateExtractValue(v, 0, ".re_part");
Type *extractty;
switch (vty->ty) {
default: llvm_unreachable("Unexpected complex floating point type");
case Tcomplex32: extractty = Type::tfloat32; break;
case Tcomplex64: extractty = Type::tfloat64; break;
case Tcomplex80: extractty = Type::tfloat80; break;
}
DImValue* re = new DImValue(extractty, repart);
return DtoCastFloat(loc, re, to);
}
else {
error(loc, "Don't know how to cast %s to %s", vty->toChars(), to->toChars());
fatal();
}
}