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); }
LLValue* DtoAggrPairSwap(LLValue* aggr) { Logger::println("swapping aggr pair"); LLValue* r = gIR->ir->CreateExtractValue(aggr, 0); LLValue* i = gIR->ir->CreateExtractValue(aggr, 1); return DtoAggrPair(i, r, "swapped"); }
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); } 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); } 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* 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(); } }
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); }
LLValue* DtoAggrPair(LLValue* V1, LLValue* V2, const char* name) { llvm::SmallVector<LLType*, 2> types; types.push_back(V1->getType()); types.push_back(V2->getType()); LLType* t = LLStructType::get(gIR->context(), types); return DtoAggrPair(t, V1, V2, name); }
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); im = gIR->ir->CreateFNeg(b); LLValue *res = DtoAggrPair(DtoType(type), re, 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 = nullptr; llvm::Value *reim = nullptr; llvm::Value *imre = nullptr; llvm::Value *imim = nullptr; 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); }
// i64 -> {float,float} LLValue* get(Type*, DValue* dv) { LLValue* in = dv->getRVal(); // extract real part LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::getInt32Ty(gIR->context())); rpart = gIR->ir->CreateBitCast(rpart, LLType::getFloatTy(gIR->context()), ".re"); // extract imag part LLValue* ipart = gIR->ir->CreateLShr(in, LLConstantInt::get(LLType::getInt64Ty(gIR->context()), 32, false)); ipart = gIR->ir->CreateTrunc(ipart, LLType::getInt32Ty(gIR->context())); ipart = gIR->ir->CreateBitCast(ipart, LLType::getFloatTy(gIR->context()), ".im"); // return {float,float} aggr pair with same bits return DtoAggrPair(rpart, ipart, ".final_cfloat"); }
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) : lhs_re; res_im = lhs_re ? gIR->ir->CreateFRem(lhs_im, divisor) : lhs_im; LLValue *res = DtoAggrPair(DtoType(type), res_re, res_im); return new DImValue(type, res); }
LLValue* DtoAggrPair(LLValue* V1, LLValue* V2, const char* name) { LLType *types[] = { V1->getType(), V2->getType() }; LLType *t = LLStructType::get(gIR->context(), types, false); return DtoAggrPair(t, V1, V2, name); }
DSliceValue::DSliceValue(Type *t, LLValue *length, LLValue *ptr) : DValue(t, DtoAggrPair(length, ptr)) {}
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 assert(0 && "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); }
LLValue* DSliceValue::getRVal() { assert(len); assert(ptr); return DtoAggrPair(len, ptr); }