# HG changeset patch # User Christian Kamm # Date 1217429315 -7200 # Node ID 3c133dd1eda382eab3d6d4587a9ac7cc8eb41744 # Parent 11a8a45759a8b1dc465091b11d757265a57b3f9f Rework complex divison. diff -r 11a8a45759a8 -r 3c133dd1eda3 gen/complex.cpp --- a/gen/complex.cpp Wed Jul 30 10:45:20 2008 +0200 +++ b/gen/complex.cpp Wed Jul 30 16:48:35 2008 +0200 @@ -318,33 +318,76 @@ DValue* DtoComplexDiv(Loc& loc, Type* type, DValue* lhs, DValue* rhs) { - lhs = DtoComplex(loc, type, resolveLR(lhs, true)); - rhs = DtoComplex(loc, type, resolveLR(rhs, false)); + DValue* clhs = DtoComplex(loc, type, resolveLR(lhs, true)); + DValue* crhs = DtoComplex(loc, type, resolveLR(rhs, false)); - llvm::Value *a, *b, *c, *d; + llvm::Value *lhs_re, *lhs_im, *rhs_re, *rhs_im, *res_re, *res_im; // lhs values - DtoGetComplexParts(lhs, a, b); + DtoGetComplexParts(clhs, lhs_re, lhs_im); // rhs values - DtoGetComplexParts(rhs, c, d); + DtoGetComplexParts(crhs, rhs_re, rhs_im); - llvm::Value *tmp1, *tmp2, *denom, *re, *im; - - tmp1 = gIR->ir->CreateMul(c, c, "tmp"); - tmp2 = gIR->ir->CreateMul(d, d, "tmp"); - denom = gIR->ir->CreateAdd(tmp1, tmp2, "tmp"); + Type* lhstype = lhs->getType(); + Type* rhstype = rhs->getType(); - tmp1 = gIR->ir->CreateMul(a, c, "tmp"); - tmp2 = gIR->ir->CreateMul(b, d, "tmp"); - re = gIR->ir->CreateAdd(tmp1, tmp2, "tmp"); - re = gIR->ir->CreateFDiv(re, denom, "tmp"); + // 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; - tmp1 = gIR->ir->CreateMul(b, c, "tmp"); - tmp2 = gIR->ir->CreateMul(a, d, "tmp"); - im = gIR->ir->CreateSub(tmp1, tmp2, "tmp"); - im = gIR->ir->CreateFDiv(im, denom, "tmp"); + 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"); - return new DComplexValue(type, re, im); + 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); } //////////////////////////////////////////////////////////////////////////////////////////