changeset 104:4d1e9eb001e0 trunk

[svn r108] Now basic suppport for complex types. =,+,-,*,/ are supported.
author lindquist
date Mon, 19 Nov 2007 02:58:58 +0100
parents 855adfdb8d38
children 182b41f56b7f
files gen/binops.cpp gen/complex.cpp gen/complex.h gen/dvalue.h gen/toir.cpp gen/tollvm.cpp gen/tollvm.h llvmdc.kdevelop.filelist test/complex1.d test/complex2.d test/complex3.d
diffstat 11 files changed, 592 insertions(+), 392 deletions(-) [+]
line wrap: on
line diff
--- a/gen/binops.cpp	Sun Nov 18 08:25:07 2007 +0100
+++ b/gen/binops.cpp	Mon Nov 19 02:58:58 2007 +0100
@@ -3,26 +3,35 @@
 #include "declaration.h"
 
 #include "gen/irstate.h"
+#include "gen/tollvm.h"
 #include "gen/dvalue.h"
 
+//////////////////////////////////////////////////////////////////////////////
+
 DValue* DtoBinAdd(DValue* lhs, DValue* rhs)
 {
     llvm::Value* v = gIR->ir->CreateAdd(lhs->getRVal(), rhs->getRVal(), "tmp");
     return new DImValue( lhs->getType(), v );
 }
 
+//////////////////////////////////////////////////////////////////////////////
+
 DValue* DtoBinSub(DValue* lhs, DValue* rhs)
 {
     llvm::Value* v = gIR->ir->CreateSub(lhs->getRVal(), rhs->getRVal(), "tmp");
     return new DImValue( lhs->getType(), v );
 }
 
+//////////////////////////////////////////////////////////////////////////////
+
 DValue* DtoBinMul(DValue* lhs, DValue* rhs)
 {
     llvm::Value* v = gIR->ir->CreateMul(lhs->getRVal(), rhs->getRVal(), "tmp");
     return new DImValue( lhs->getType(), v );
 }
 
+//////////////////////////////////////////////////////////////////////////////
+
 DValue* DtoBinDiv(DValue* lhs, DValue* rhs)
 {
     Type* t = lhs->getType();
@@ -39,6 +48,8 @@
     return new DImValue( lhs->getType(), res );
 }
 
+//////////////////////////////////////////////////////////////////////////////
+
 DValue* DtoBinRem(DValue* lhs, DValue* rhs)
 {
     Type* t = lhs->getType();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/complex.cpp	Mon Nov 19 02:58:58 2007 +0100
@@ -0,0 +1,358 @@
+#include "gen/llvm.h"
+
+#include "mtype.h"
+#include "declaration.h"
+
+#include "gen/complex.h"
+#include "gen/tollvm.h"
+#include "gen/irstate.h"
+#include "gen/dvalue.h"
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+const llvm::StructType* DtoComplexType(Type* type)
+{
+    Type* t = DtoDType(type);
+
+    const llvm::Type* base = DtoComplexBaseType(t);
+
+    std::vector<const llvm::Type*> types;
+    types.push_back(base);
+    types.push_back(base);
+
+    return llvm::StructType::get(types);
+}
+
+const llvm::Type* DtoComplexBaseType(Type* t)
+{
+    TY ty = DtoDType(t)->ty;
+    const llvm::Type* base;
+    if (ty == Tcomplex32) {
+        return llvm::Type::FloatTy;
+    }
+    else if (ty == Tcomplex64 || ty == Tcomplex80) {
+        return llvm::Type::DoubleTy;
+    }
+    else {
+        assert(0);
+    }
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Constant* DtoConstComplex(Type* ty, llvm::Constant* re, llvm::Constant* im)
+{
+    assert(0);
+    const llvm::Type* base = DtoComplexBaseType(ty);
+
+    std::vector<llvm::Constant*> inits;
+    inits.push_back(re);
+    inits.push_back(im);
+
+    const llvm::VectorType* vt = llvm::VectorType::get(base, 2);
+    return llvm::ConstantVector::get(vt, inits);
+}
+
+llvm::Constant* DtoConstComplex(Type* _ty, long double re, long double im)
+{
+    TY ty = DtoDType(_ty)->ty;
+
+    llvm::ConstantFP* fre;
+    llvm::ConstantFP* fim;
+
+    const llvm::Type* base;
+
+    if (ty == Tcomplex32) {
+        fre = DtoConstFP(Type::tfloat32, re);
+        fim = DtoConstFP(Type::tfloat32, im);
+        base = llvm::Type::FloatTy;
+    }
+    else if (ty == Tcomplex64 || ty == Tcomplex80) {
+        fre = DtoConstFP(Type::tfloat64, re);
+        fim = DtoConstFP(Type::tfloat64, im);
+        base = llvm::Type::DoubleTy;
+    }
+    else
+    assert(0);
+
+    std::vector<llvm::Constant*> inits;
+    inits.push_back(fre);
+    inits.push_back(fim);
+    return llvm::ConstantStruct::get(DtoComplexType(_ty), inits);
+}
+
+llvm::Constant* DtoUndefComplex(Type* _ty)
+{
+    assert(0);
+    TY ty = DtoDType(_ty)->ty;
+    const llvm::Type* base;
+    if (ty == Tcomplex32) {
+        base = llvm::Type::FloatTy;
+    }
+    else if (ty == Tcomplex64 || ty == Tcomplex80) {
+        base = llvm::Type::DoubleTy;
+    }
+    else
+    assert(0);
+
+    std::vector<llvm::Constant*> inits;
+    inits.push_back(llvm::UndefValue::get(base));
+    inits.push_back(llvm::UndefValue::get(base));
+
+    const llvm::VectorType* vt = llvm::VectorType::get(base, 2);
+    return llvm::ConstantVector::get(vt, inits);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoRealPart(DValue* val)
+{
+    assert(0);
+    return gIR->ir->CreateExtractElement(val->getRVal(), DtoConstUint(0), "tmp");
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoImagPart(DValue* val)
+{
+    assert(0);
+    return gIR->ir->CreateExtractElement(val->getRVal(), DtoConstUint(1), "tmp");
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoComplex(Type* to, DValue* val)
+{
+    Type* t = DtoDType(val->getType());
+    TY ty = t->ty;
+
+    if (val->isComplex() || t->iscomplex()) {
+        assert(DtoDType(to) == t);
+        return val;
+    }
+
+    const llvm::Type* base = DtoComplexBaseType(to);
+
+    llvm::Constant* undef = llvm::UndefValue::get(base);
+    llvm::Constant* zero;
+    if (ty == Tfloat32 || ty == Timaginary32 || ty == Tcomplex32)
+        zero = llvm::ConstantFP::get(llvm::Type::FloatTy, float(0));
+    else if (ty == Tfloat64 || ty == Timaginary64 || ty == Tcomplex64 || ty == Tfloat80 || ty == Timaginary80 || ty == Tcomplex80)
+        zero = llvm::ConstantFP::get(llvm::Type::DoubleTy, double(0));
+
+    if (t->isimaginary()) {
+        return new DComplexValue(to, zero, val->getRVal());
+    }
+    else if (t->isfloating()) {
+        return new DComplexValue(to, val->getRVal(), zero);
+    }
+    else
+    assert(0);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+void DtoComplexAssign(llvm::Value* l, llvm::Value* 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(llvm::Value* c, llvm::Value* re, llvm::Value* im)
+{
+    DtoStore(re, DtoGEPi(c,0,0,"tmp"));
+    DtoStore(im, DtoGEPi(c,0,1,"tmp"));
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoComplexAdd(Type* type, DValue* lhs, DValue* rhs)
+{
+    lhs = DtoComplex(type, lhs);
+    rhs = DtoComplex(type, rhs);
+
+    llvm::Value *a, *b, *c, *d, *re, *im;
+
+    // lhs values
+    if (DComplexValue* cx = lhs->isComplex()) {
+        a = cx->re;
+        b = cx->im;
+    }
+    else {
+        a = DtoLoad(DtoGEPi(lhs->getRVal(),0,0,"tmp"));
+        b = DtoLoad(DtoGEPi(lhs->getRVal(),0,1,"tmp"));
+    }
+
+    // rhs values
+    if (DComplexValue* cx = rhs->isComplex()) {
+        c = cx->re;
+        d = cx->im;
+    }
+    else {
+        c = DtoLoad(DtoGEPi(rhs->getRVal(),0,0,"tmp"));
+        d = DtoLoad(DtoGEPi(rhs->getRVal(),0,1,"tmp"));
+    }
+
+    // add up
+    re = gIR->ir->CreateAdd(a, c, "tmp");
+    im = gIR->ir->CreateAdd(b, d, "tmp");
+
+    return new DComplexValue(type, re, im);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoComplexSub(Type* type, DValue* lhs, DValue* rhs)
+{
+    lhs = DtoComplex(type, lhs);
+    rhs = DtoComplex(type, rhs);
+
+    llvm::Value *a, *b, *c, *d, *re, *im;
+
+    // lhs values
+    if (DComplexValue* cx = lhs->isComplex()) {
+        a = cx->re;
+        b = cx->im;
+    }
+    else {
+        a = DtoLoad(DtoGEPi(lhs->getRVal(),0,0,"tmp"));
+        b = DtoLoad(DtoGEPi(lhs->getRVal(),0,1,"tmp"));
+    }
+
+    // rhs values
+    if (DComplexValue* cx = rhs->isComplex()) {
+        c = cx->re;
+        d = cx->im;
+    }
+    else {
+        c = DtoLoad(DtoGEPi(rhs->getRVal(),0,0,"tmp"));
+        d = DtoLoad(DtoGEPi(rhs->getRVal(),0,1,"tmp"));
+    }
+
+    // add up
+    re = gIR->ir->CreateSub(a, c, "tmp");
+    im = gIR->ir->CreateSub(b, d, "tmp");
+
+    return new DComplexValue(type, re, im);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoComplexMul(Type* type, DValue* lhs, DValue* rhs)
+{
+    lhs = DtoComplex(type, lhs);
+    rhs = DtoComplex(type, rhs);
+
+    llvm::Value *a, *b, *c, *d, *re, *im;
+
+    // lhs values
+    if (DComplexValue* cx = lhs->isComplex()) {
+        a = cx->re;
+        b = cx->im;
+    }
+    else {
+        a = DtoLoad(DtoGEPi(lhs->getRVal(),0,0,"tmp"));
+        b = DtoLoad(DtoGEPi(lhs->getRVal(),0,1,"tmp"));
+    }
+
+    // rhs values
+    if (DComplexValue* cx = rhs->isComplex()) {
+        c = cx->re;
+        d = cx->im;
+    }
+    else {
+        c = DtoLoad(DtoGEPi(rhs->getRVal(),0,0,"tmp"));
+        d = DtoLoad(DtoGEPi(rhs->getRVal(),0,1,"tmp"));
+    }
+
+    llvm::Value *tmp1, *tmp2;
+
+    tmp1 = gIR->ir->CreateMul(a, c, "tmp");
+    tmp2 = gIR->ir->CreateMul(b, d, "tmp");
+    re = gIR->ir->CreateSub(tmp1, tmp2, "tmp");
+
+    tmp1 = gIR->ir->CreateMul(b, c, "tmp");
+    tmp2 = gIR->ir->CreateMul(a, d, "tmp");
+    im = gIR->ir->CreateAdd(tmp1, tmp2, "tmp");
+
+    return new DComplexValue(type, re, im);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoComplexDiv(Type* type, DValue* lhs, DValue* rhs)
+{
+    lhs = DtoComplex(type, lhs);
+    rhs = DtoComplex(type, rhs);
+
+    llvm::Value *a, *b, *c, *d, *re, *im;
+
+    // lhs values
+    if (DComplexValue* cx = lhs->isComplex()) {
+        a = cx->re;
+        b = cx->im;
+    }
+    else {
+        a = DtoLoad(DtoGEPi(lhs->getRVal(),0,0,"tmp"));
+        b = DtoLoad(DtoGEPi(lhs->getRVal(),0,1,"tmp"));
+    }
+
+    // rhs values
+    if (DComplexValue* cx = rhs->isComplex()) {
+        c = cx->re;
+        d = cx->im;
+    }
+    else {
+        c = DtoLoad(DtoGEPi(rhs->getRVal(),0,0,"tmp"));
+        d = DtoLoad(DtoGEPi(rhs->getRVal(),0,1,"tmp"));
+    }
+
+    llvm::Value *tmp1, *tmp2, *denom;
+
+    tmp1 = gIR->ir->CreateMul(c, c, "tmp");
+    tmp2 = gIR->ir->CreateMul(d, d, "tmp");
+    denom = gIR->ir->CreateAdd(tmp1, tmp2, "tmp");
+
+    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");
+
+    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");
+
+    return new DComplexValue(type, re, im);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* DtoComplexEquals(TOK op, DValue* lhs, DValue* rhs)
+{
+    llvm::Value* lvec = lhs->getRVal();
+    llvm::Value* rvec = rhs->getRVal();
+
+    llvm::FCmpInst::Predicate cmpop;
+    switch(op)
+    {
+    case TOKequal:
+        cmpop = llvm::FCmpInst::FCMP_OEQ;
+        break;
+    case TOKnotequal:
+        cmpop = llvm::FCmpInst::FCMP_UNE;
+        break;
+    default:
+        assert(0);
+    }
+
+    llvm::Value* l1 = gIR->ir->CreateExtractElement(lvec, DtoConstUint(0), "re");
+    llvm::Value* r1 = gIR->ir->CreateExtractElement(rvec, DtoConstUint(0), "re");
+    llvm::Value* b1 = new llvm::FCmpInst(cmpop, l1, r1, "tmp", gIR->scopebb());
+
+    llvm::Value* l2 = gIR->ir->CreateExtractElement(lvec, DtoConstUint(1), "im");
+    llvm::Value* r2 = gIR->ir->CreateExtractElement(rvec, DtoConstUint(1), "im");
+    llvm::Value* b2 = new llvm::FCmpInst(cmpop, l2, r2, "tmp", gIR->scopebb());
+
+    return gIR->ir->CreateAnd(b1,b2,"tmp");
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gen/complex.h	Mon Nov 19 02:58:58 2007 +0100
@@ -0,0 +1,27 @@
+#ifndef LLVMDC_GEN_COMPLEX_H
+#define LLVMDC_GEN_COMPLEX_H
+
+const llvm::StructType* DtoComplexType(Type* t);
+const llvm::Type* DtoComplexBaseType(Type* t);
+
+llvm::Constant* DtoConstComplex(Type* t, llvm::Constant* re, llvm::Constant* im);
+llvm::Constant* DtoConstComplex(Type* t, long double re, long double im);
+llvm::Constant* DtoUndefComplex(Type* _ty);
+
+llvm::Constant* DtoComplexShuffleMask(unsigned a, unsigned b);
+
+llvm::Value* DtoRealPart(DValue* val);
+llvm::Value* DtoImagPart(DValue* val);
+DValue* DtoComplex(Type* to, DValue* val);
+
+void DtoComplexAssign(llvm::Value* l, llvm::Value* r);
+void DtoComplexSet(llvm::Value* c, llvm::Value* re, llvm::Value* im);
+
+DValue* DtoComplexAdd(Type* type, DValue* lhs, DValue* rhs);
+DValue* DtoComplexSub(Type* type, DValue* lhs, DValue* rhs);
+DValue* DtoComplexMul(Type* type, DValue* lhs, DValue* rhs);
+DValue* DtoComplexDiv(Type* type, DValue* lhs, DValue* rhs);
+
+llvm::Value* DtoComplexEquals(TOK op, DValue* lhs, DValue* rhs);
+
+#endif // LLVMDC_GEN_COMPLEX_H
--- a/gen/dvalue.h	Sun Nov 18 08:25:07 2007 +0100
+++ b/gen/dvalue.h	Mon Nov 19 02:58:58 2007 +0100
@@ -32,6 +32,7 @@
 struct DSliceValue;
 struct DArrayLenValue;
 struct DLValueCast;
+struct DComplexValue;
 
 // base class for d-values
 struct DValue : Object
@@ -51,6 +52,7 @@
     virtual DFuncValue* isFunc() { return NULL; }
     virtual DArrayLenValue* isArrayLen() { return NULL; }
     virtual DLValueCast* isLValueCast() { return NULL; }
+    virtual DComplexValue* isComplex() { return NULL; };
 
     virtual bool inPlace() { return false; }
 
@@ -190,4 +192,21 @@
     virtual DLValueCast* isLValueCast() { return this; }
 };
 
+// complex number immediate d-value (much like slice)
+struct DComplexValue : DValue
+{
+    Type* type;
+    llvm::Value* re;
+    llvm::Value* im;
+
+    DComplexValue(Type* t, llvm::Value* r, llvm::Value* i) {
+        type = t;
+        re = r;
+        im = i;
+    }
+
+    virtual Type* getType() { assert(type); return type; }
+    virtual DComplexValue* isComplex() { return this; }
+};
+
 #endif // LLVMDC_GEN_DVALUE_H
--- a/gen/toir.cpp	Sun Nov 18 08:25:07 2007 +0100
+++ b/gen/toir.cpp	Mon Nov 19 02:58:58 2007 +0100
@@ -28,7 +28,7 @@
 #include "gen/structs.h"
 #include "gen/classes.h"
 #include "gen/typeinf.h"
-
+#include "gen/complex.h"
 #include "gen/dvalue.h"
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -291,13 +291,7 @@
     Logger::print("RealExp::toConstElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
     Type* t = DtoDType(type);
-    const llvm::Type* fty = DtoType(t);
-    if (t->ty == Tfloat32 || t->ty == Timaginary32)
-        return llvm::ConstantFP::get(fty,float(value));
-    else if (t->ty == Tfloat64 || t->ty == Timaginary64 || t->ty == Tfloat80 || t->ty == Timaginary80)
-        return llvm::ConstantFP::get(fty,double(value));
-    assert(0);
-    return NULL;
+    return DtoConstFP(t, value);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -334,7 +328,18 @@
 {
     Logger::print("ComplexExp::toElem(): %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
-    assert(0 && "no complex yet");
+    llvm::Constant* c = toConstElem(p);
+
+    if (c->isNullValue()) {
+        Type* t = DtoDType(type);
+        if (t->ty == Tcomplex32)
+            c = DtoConstFP(Type::tfloat32, 0);
+        else
+            c = DtoConstFP(Type::tfloat64, 0);
+        return new DComplexValue(type, c, c);
+    }
+
+    return new DComplexValue(type, c->getOperand(0), c->getOperand(1));
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -343,7 +348,7 @@
 {
     Logger::print("ComplexExp::toConstElem(): %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
-    assert(0 && "no complex yet");
+    return DtoConstComplex(type, value.re, value.im);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -484,164 +489,6 @@
     }
 
     return l;
-
-    /*
-    if (l->type == DValue::ARRAYLEN)
-    {
-        DtoResizeDynArray(l->mem, r->getValue());
-        delete r;
-        delete l;
-        return 0;
-    }
-
-    Type* e1type = DtoDType(e1->type);
-    Type* e2type = DtoDType(e2->type);
-    TY e1ty = e1type->ty;
-    TY e2ty = e2type->ty;
-
-    DValue* e = new DValue(this);
-    e->type = DValue::VAR;
-
-    // struct
-    if (e1ty == Tstruct) {
-        e->mem = l->mem;
-        // struct + struct
-        if (e2ty == Tstruct) {
-            // struct literals do the assignment themselvs (in place)
-            if (!r->inplace) {
-                DtoStructCopy(l->mem,r->getValue());
-            }
-            else {
-                e->inplace = true;
-            }
-        }
-        // struct + const int
-        else if (e2type->isintegral()){
-            IntegerExp* iexp = (IntegerExp*)e2;
-            assert(iexp->value == 0 && "Only integral struct initializer allowed is zero");
-            DtoStructZeroInit(l->mem);
-        }
-        // :x
-        else
-        assert(0 && "struct = unknown");
-    }
-    else if (e1ty == Tsarray) {
-        assert(0 && "static array not supported");
-    }
-    else if (e1ty == Tarray) {
-        if (e2type->isscalar() || e2type->ty == Tclass){
-            if (l->type == DValue::SLICE) {
-                DtoArrayInit(l->mem, l->arg, r->getValue());
-            }
-            else {
-                DtoArrayInit(l->mem, r->getValue());
-            }
-        }
-        else if (e2ty == Tarray) {
-            //new llvm::StoreInst(r->val,l->val,p->scopebb());
-            if (r->type == DValue::NUL) {
-                llvm::Constant* c = llvm::cast<llvm::Constant>(r->val);
-                assert(c->isNullValue());
-                DtoNullArray(l->mem);
-                e->mem = l->mem;
-            }
-            else if (r->type == DValue::SLICE) {
-                if (l->type == DValue::SLICE) {
-                    DtoArrayCopy(l,r);
-                    e->type = DValue::SLICE;
-                    e->mem = l->mem;
-                    e->arg = l->arg;
-                }
-                else {
-                    DtoSetArray(l->mem,r->arg,r->mem);
-                    e->mem = l->mem;
-                }
-            }
-            else {
-                // new expressions write directly to the array reference
-                // so do string literals
-                e->mem = l->mem;
-                if (!r->inplace) {
-                    assert(r->mem);
-                    DtoArrayAssign(l->mem, r->mem);
-                }
-                else {
-                    e->inplace = true;
-                }
-            }
-        }
-        else
-        assert(0);
-    }
-    else if (e1ty == Tpointer) {
-        e->mem = l->mem;
-        if (e2ty == Tpointer) {
-            llvm::Value* v = r->field ? r->mem : r->getValue();
-            Logger::cout() << "*=*: " << *v << ", " << *l->mem << '\n';
-            new llvm::StoreInst(v, l->mem, p->scopebb());
-        }
-        else
-        assert(0);
-    }
-    else if (e1ty == Tclass) {
-        if (e2ty == Tclass) {
-            llvm::Value* tmp = r->getValue();
-            Logger::cout() << "tmp: " << *tmp << " ||| " << *l->mem << '\n';
-            // assignment to this in constructor special case
-            if (l->isthis) {
-                FuncDeclaration* fdecl = p->func().decl;
-                // respecify the this param
-                if (!llvm::isa<llvm::AllocaInst>(fdecl->llvmThisVar))
-                    fdecl->llvmThisVar = new llvm::AllocaInst(tmp->getType(), "newthis", p->topallocapoint());
-                new llvm::StoreInst(tmp, fdecl->llvmThisVar, p->scopebb());
-                e->mem = fdecl->llvmThisVar;
-            }
-            // regular class ref -> class ref assignment
-            else {
-                new llvm::StoreInst(tmp, l->mem, p->scopebb());
-                e->mem = l->mem;
-            }
-        }
-        else
-        assert(0);
-    }
-    else if (e1ty == Tdelegate) {
-        Logger::println("Assigning to delegate");
-        if (e2ty == Tdelegate) {
-            if (r->type == DValue::NUL) {
-                llvm::Constant* c = llvm::cast<llvm::Constant>(r->val);
-                if (c->isNullValue()) {
-                    DtoNullDelegate(l->mem);
-                    e->mem = l->mem;
-                }
-                else
-                assert(0);
-            }
-            else if (r->inplace) {
-                // do nothing
-                e->inplace = true;
-                e->mem = l->mem;
-            }
-            else {
-                DtoDelegateCopy(l->mem, r->getValue());
-                e->mem = l->mem;
-            }
-        }
-        else
-        assert(0);
-    }
-    // !struct && !array && !pointer && !class
-    else {
-        Logger::cout() << *l->mem << '\n';
-        new llvm::StoreInst(r->getValue(),l->mem,p->scopebb());
-        e->mem = l->mem;
-    }
-
-    delete r;
-    delete l;
-
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -682,8 +529,14 @@
             llvm::Value* v = new llvm::GetElementPtrInst(l->getRVal(), r->getRVal(), "tmp", p->scopebb());
             return new DImValue(type, v);
         }
+        else if (t->iscomplex()) {
+            return DtoComplexAdd(type, l, r);
+        }
         assert(0);
     }
+    else if (t->iscomplex()) {
+        return DtoComplexAdd(type, l, r);
+    }
     else {
         return DtoBinAdd(l,r);
     }
@@ -701,39 +554,22 @@
     DValue* r = e2->toElem(p);
     p->exps.pop_back();
 
+    Type* t = DtoDType(type);
+
     DValue* res;
     if (DtoDType(e1->type)->ty == Tpointer) {
         llvm::Value* gep = new llvm::GetElementPtrInst(l->getRVal(),r->getRVal(),"tmp",p->scopebb());
         res = new DImValue(type, gep);
     }
+    else if (t->iscomplex()) {
+        res = DtoComplexAdd(type, l, r);
+    }
     else {
         res = DtoBinAdd(l,r);
     }
     DtoAssign(l, res);
 
     return l;
-
-    /*
-
-    Type* e1type = DtoDType(e1->type);
-
-    DValue* e = new DValue(this);
-    llvm::Value* val = 0;
-    if (e1type->ty == Tpointer) {
-        val = e->mem = new llvm::GetElementPtrInst(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    }
-    else {
-        val = e->val = llvm::BinaryOperator::createAdd(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    }
-
-    assert(l->mem);
-    new llvm::StoreInst(val,l->mem,p->scopebb());
-    e->type = DValue::VAR;
-
-    delete l;
-    delete r;
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -746,6 +582,8 @@
     DValue* l = e1->toElem(p);
     DValue* r = e2->toElem(p);
 
+    Type* t = DtoDType(type);
+
     if (DtoDType(e1->type)->ty == Tpointer) {
         llvm::Value* lv = l->getRVal();
         llvm::Value* rv = r->getRVal();
@@ -759,34 +597,12 @@
             diff = p->ir->CreateIntToPtr(diff, DtoType(type));
         return new DImValue(type, diff);
     }
+    else if (t->iscomplex()) {
+        return DtoComplexSub(type, l, r);
+    }
     else {
         return DtoBinSub(l,r);
     }
-
-    /*
-    llvm::Value* left = l->getValue();
-    if (isaPointer(left->getType()))
-        left = new llvm::PtrToIntInst(left,DtoSize_t(),"tmp",p->scopebb());
-
-    llvm::Value* right = r->getValue();
-    if (isaPointer(right->getType()))
-        right = new llvm::PtrToIntInst(right,DtoSize_t(),"tmp",p->scopebb());
-
-    e->val = llvm::BinaryOperator::createSub(left,right,"tmp",p->scopebb());
-    e->type = DValue::VAL;
-
-    const llvm::Type* totype = DtoType(type);
-    if (e->val->getType() != totype) {
-        assert(0);
-        assert(isaPointer(e->val->getType()));
-        assert(llvm::isa<llvm::IntegerType>(totype));
-        e->val = new llvm::IntToPtrInst(e->val,totype,"tmp",p->scopebb());
-    }
-
-    delete l;
-    delete r;
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -799,6 +615,8 @@
     DValue* l = e1->toElem(p);
     DValue* r = e2->toElem(p);
 
+    Type* t = DtoDType(type);
+
     DValue* res;
     if (DtoDType(e1->type)->ty == Tpointer) {
         llvm::Value* tmp = r->getRVal();
@@ -807,212 +625,113 @@
         tmp = new llvm::GetElementPtrInst(l->getRVal(),tmp,"tmp",p->scopebb());
         res = new DImValue(type, tmp);
     }
+    else if (t->iscomplex()) {
+        res = DtoComplexSub(type, l, r);
+    }
     else {
         res = DtoBinSub(l,r);
     }
     DtoAssign(l, res);
 
     return l;
-
-    /*
-
-    Type* e1type = DtoDType(e1->type);
-
-    llvm::Value* tmp = 0;
-    if (e1type->ty == Tpointer) {
-        tmp = r->getValue();
-        llvm::Value* zero = llvm::ConstantInt::get(tmp->getType(),0,false);
-        tmp = llvm::BinaryOperator::createSub(zero,tmp,"tmp",p->scopebb());
-        tmp = new llvm::GetElementPtrInst(l->getValue(),tmp,"tmp",p->scopebb());
-    }
-    else {
-        tmp = llvm::BinaryOperator::createSub(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    }
-
-    assert(l->mem);
-    new llvm::StoreInst(tmp, l->mem, p->scopebb());
-
-    delete l;
-    delete r;
-
-    DValue* e = new DValue(this);
-    e->val = tmp;
-    e->type = DValue::VAR;
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 DValue* MulExp::toElem(IRState* p)
 {
-    Logger::print("MulExp::toElem: %s\n", toChars());
+    Logger::print("MulExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
     DValue* l = e1->toElem(p);
     DValue* r = e2->toElem(p);
 
-    return DtoBinMul(l,r);
-    /*
-    if (l->dvalue && r->dvalue) {
-        Logger::println("DVALUE PATH");
-        e->dvalue = DtoBinMul(l->dvalue, r->dvalue);
-        e->val = e->dvalue->getRVal();
+    if (type->iscomplex()) {
+        return DtoComplexMul(type, l, r);
     }
-    else {
-        llvm::Value* vl = l->getValue();
-        llvm::Value* vr = r->getValue();
-        Logger::cout() << "mul: " << *vl << ", " << *vr << '\n';
-        e->val = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb());
-        e->dvalue = new DImValue(type, e->val);
-    }
-    e->type = DValue::VAL;
-    delete l;
-    delete r;
-    return e;
-    */
+
+    return DtoBinMul(l,r);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 DValue* MulAssignExp::toElem(IRState* p)
 {
-    Logger::print("MulAssignExp::toElem: %s\n", toChars());
+    Logger::print("MulAssignExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
     DValue* l = e1->toElem(p);
     DValue* r = e2->toElem(p);
 
-    DValue* res = DtoBinMul(l,r);
+    DValue* res;
+    if (type->iscomplex()) {
+        res = DtoComplexMul(type, l, r);
+    }
+    else {
+        res = DtoBinMul(l,r);
+    }
     DtoAssign(l, res);
 
     return l;
-
-    /*
-    llvm::Value* vl = l->getValue();
-    llvm::Value* vr = r->getValue();
-    Logger::cout() << "mulassign: " << *vl << ", " << *vr << '\n';
-    llvm::Value* tmp = llvm::BinaryOperator::createMul(vl,vr,"tmp",p->scopebb());
-
-    assert(l->mem);
-    new llvm::StoreInst(tmp,l->mem,p->scopebb());
-
-    delete l;
-    delete r;
-
-    DValue* e = new DValue(this);
-    e->val = tmp;
-    e->type = DValue::VAR;
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 DValue* DivExp::toElem(IRState* p)
 {
-    Logger::print("DivExp::toElem: %s\n", toChars());
+    Logger::print("DivExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
     DValue* l = e1->toElem(p);
     DValue* r = e2->toElem(p);
 
+    if (type->iscomplex()) {
+        return DtoComplexDiv(type, l, r);
+    }
+
     return DtoBinDiv(l, r);
-    /*
-
-    Type* t = DtoDType(type);
-
-    if (t->isunsigned())
-        e->val = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else if (t->isintegral())
-        e->val = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else if (t->isfloating())
-        e->val = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else
-        assert(0);
-    e->type = DValue::VAL;
-    delete l;
-    delete r;
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 DValue* DivAssignExp::toElem(IRState* p)
 {
-    Logger::print("DivAssignExp::toElem: %s\n", toChars());
+    Logger::print("DivAssignExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
     DValue* l = e1->toElem(p);
     DValue* r = e2->toElem(p);
 
-    DValue* res = DtoBinDiv(l,r);
+    DValue* res;
+    if (type->iscomplex()) {
+        res = DtoComplexDiv(type, l, r);
+    }
+    else {
+        res = DtoBinDiv(l,r);
+    }
     DtoAssign(l, res);
 
     return l;
-
-    /*
-
-    Type* t = DtoDType(type);
-
-    llvm::Value* tmp;
-    if (t->isunsigned())
-        tmp = llvm::BinaryOperator::createUDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else if (t->isintegral())
-        tmp = llvm::BinaryOperator::createSDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else if (t->isfloating())
-        tmp = llvm::BinaryOperator::createFDiv(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else
-        assert(0);
-
-    assert(l->mem);
-    new llvm::StoreInst(tmp,l->mem,p->scopebb());
-
-    delete l;
-    delete r;
-
-    DValue* e = new DValue(this);
-    e->val = tmp;
-    e->type = DValue::VAR;
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 DValue* ModExp::toElem(IRState* p)
 {
-    Logger::print("ModExp::toElem: %s\n", toChars());
+    Logger::print("ModExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
     DValue* l = e1->toElem(p);
     DValue* r = e2->toElem(p);
 
     return DtoBinRem(l, r);
-    /*
-    Type* t = DtoDType(type);
-
-    if (t->isunsigned())
-        e->val = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else if (t->isintegral())
-        e->val = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else if (t->isfloating())
-        e->val = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else
-        assert(0);
-    e->type = DValue::VAL;
-    delete l;
-    delete r;
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 DValue* ModAssignExp::toElem(IRState* p)
 {
-    Logger::print("ModAssignExp::toElem: %s\n", toChars());
+    Logger::print("ModAssignExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
     DValue* l = e1->toElem(p);
@@ -1022,39 +741,13 @@
     DtoAssign(l, res);
 
     return l;
-
-    /*
-
-    Type* t = DtoDType(type);
-
-    llvm::Value* tmp;
-    if (t->isunsigned())
-        tmp = llvm::BinaryOperator::createURem(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else if (t->isintegral())
-        tmp = llvm::BinaryOperator::createSRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else if (t->isfloating())
-        tmp = llvm::BinaryOperator::createFRem(l->getValue(),r->getValue(),"tmp",p->scopebb());
-    else
-        assert(0);
-
-    assert(l->mem);
-    new llvm::StoreInst(tmp,l->mem,p->scopebb());
-
-    delete l;
-    delete r;
-
-    DValue* e = new DValue(this);
-    e->val = tmp;
-    e->type = DValue::VAR;
-    return e;
-    */
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
 DValue* CallExp::toElem(IRState* p)
 {
-    Logger::print("CallExp::toElem: %s\n", toChars());
+    Logger::print("CallExp::toElem: %s | %s\n", toChars(), type->toChars());
     LOG_SCOPE;
 
     DValue* fn = e1->toElem(p);
@@ -1880,6 +1573,11 @@
         }
         eval = new llvm::ICmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb());
     }
+    else if (t->iscomplex())
+    {
+        Logger::println("complex");
+        eval = DtoComplexEquals(op, l, r);
+    }
     else if (t->isfloating())
     {
         Logger::println("floating");
@@ -2439,9 +2137,9 @@
     if (t->isintegral())
         zero = llvm::ConstantInt::get(val->getType(), 0, true);
     else if (t->isfloating()) {
-        if (t->ty == Tfloat32)
+        if (t->ty == Tfloat32 || t->ty == Timaginary32)
             zero = llvm::ConstantFP::get(val->getType(), float(0));
-        else if (t->ty == Tfloat64 || t->ty == Tfloat80)
+        else if (t->ty == Tfloat64 || t->ty == Tfloat80 || t->ty == Timaginary64 || t->ty == Timaginary80)
             zero = llvm::ConstantFP::get(val->getType(), double(0));
         else
         assert(0);
--- a/gen/tollvm.cpp	Sun Nov 18 08:25:07 2007 +0100
+++ b/gen/tollvm.cpp	Mon Nov 19 02:58:58 2007 +0100
@@ -18,11 +18,13 @@
 #include "gen/structs.h"
 #include "gen/classes.h"
 #include "gen/typeinf.h"
+#include "gen/complex.h"
 
 bool DtoIsPassedByRef(Type* type)
 {
-    TY t = DtoDType(type)->ty;
-    return (t == Tstruct || t == Tarray || t == Tdelegate || t == Tsarray);
+    Type* typ = DtoDType(type);
+    TY t = typ->ty;
+    return (t == Tstruct || t == Tarray || t == Tdelegate || t == Tsarray || typ->iscomplex());
 }
 
 Type* DtoDType(Type* t)
@@ -72,10 +74,9 @@
 
     // complex
     case Tcomplex32:
-        return DtoComplexType(llvm::Type::FloatTy);
     case Tcomplex64:
     case Tcomplex80:
-        return DtoComplexType(llvm::Type::DoubleTy);
+        return DtoComplexType(t);
 
     // pointers
     case Tpointer: {
@@ -196,16 +197,6 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-const llvm::StructType* DtoComplexType(const llvm::Type* base)
-{
-    std::vector<const llvm::Type*> types;
-    types.push_back(base);
-    types.push_back(base);
-    return llvm::StructType::get(types);
-}
-
-//////////////////////////////////////////////////////////////////////////////////////////
-
 static llvm::Function* LLVM_DeclareMemIntrinsic(const char* name, int bits, bool set=false)
 {
     assert(bits == 32 || bits == 64);
@@ -902,6 +893,15 @@
             DtoStore(rhs->getRVal(), lhs->getLVal());
         }
     }
+    else if (t->iscomplex()) {
+        assert(!lhs->isComplex());
+        if (DComplexValue* cx = rhs->isComplex()) {
+            DtoComplexSet(lhs->getRVal(), cx->re, cx->im);
+        }
+        else {
+            DtoComplexAssign(lhs->getRVal(), rhs->getRVal());
+        }
+    }
     else {
         llvm::Value* r = rhs->getRVal();
         llvm::Value* l = lhs->getLVal();
@@ -990,6 +990,9 @@
 
 DValue* DtoCastFloat(DValue* val, Type* to)
 {
+    if (val->getType() == to)
+        return val;
+
     const llvm::Type* tolltype = DtoType(to);
 
     Type* totype = DtoDType(to);
@@ -1001,7 +1004,11 @@
 
     llvm::Value* rval;
 
-    if (totype->isfloating()) {
+    if (totype->iscomplex()) {
+        assert(0);
+        //return new DImValue(to, DtoComplex(to, val));
+    }
+    else if (totype->isfloating()) {
         if ((fromtype->ty == Tfloat80 || fromtype->ty == Tfloat64) && (totype->ty == Tfloat80 || totype->ty == Tfloat64)) {
             rval = val->getRVal();
         }
@@ -1030,6 +1037,25 @@
     return new DImValue(to, rval);
 }
 
+DValue* DtoCastComplex(DValue* val, Type* _to)
+{
+    Type* to = DtoDType(_to);
+    llvm::Value* v = val->getRVal();
+    if (to->iscomplex()) {
+        assert(0);
+    }
+    else if (to->isimaginary()) {
+        DImValue* im = new DImValue(to, gIR->ir->CreateExtractElement(v, DtoConstUint(1), "im"));
+        return DtoCastFloat(im, to);
+    }
+    else if (to->isfloating()) {
+        DImValue* re = new DImValue(to, gIR->ir->CreateExtractElement(v, DtoConstUint(0), "re"));
+        return DtoCastFloat(re, to);
+    }
+    else
+    assert(0);
+}
+
 DValue* DtoCastClass(DValue* val, Type* _to)
 {
     const llvm::Type* tolltype = DtoType(_to);
@@ -1045,6 +1071,9 @@
     if (fromtype->isintegral()) {
         return DtoCastInt(val, to);
     }
+    else if (fromtype->iscomplex()) {
+        return DtoCastComplex(val, to);
+    }
     else if (fromtype->isfloating()) {
         return DtoCastFloat(val, to);
     }
@@ -1081,6 +1110,16 @@
     return llvm::ConstantInt::get(llvm::Type::Int1Ty, b, false);
 }
 
+llvm::ConstantFP* DtoConstFP(Type* t, long double value)
+{
+    TY ty = DtoDType(t)->ty;
+    if (ty == Tfloat32 || ty == Timaginary32)
+        return llvm::ConstantFP::get(llvm::Type::FloatTy, float(value));
+    else if (ty == Tfloat64 || ty == Timaginary64 || ty == Tfloat80 || ty == Timaginary80)
+        return llvm::ConstantFP::get(llvm::Type::DoubleTy, double(value));
+}
+
+
 //////////////////////////////////////////////////////////////////////////////////////////
 
 llvm::Constant* DtoConstString(const char* str)
@@ -1165,6 +1204,8 @@
     return false;
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+
 llvm::Value* DtoBitCast(llvm::Value* v, const llvm::Type* t)
 {
     if (v->getType() == t)
@@ -1172,6 +1213,8 @@
     return gIR->ir->CreateBitCast(v, t, "tmp");
 }
 
+//////////////////////////////////////////////////////////////////////////////////////////
+
 const llvm::PointerType* isaPointer(llvm::Value* v)
 {
     return llvm::dyn_cast<llvm::PointerType>(v->getType());
--- a/gen/tollvm.h	Sun Nov 18 08:25:07 2007 +0100
+++ b/gen/tollvm.h	Mon Nov 19 02:58:58 2007 +0100
@@ -22,8 +22,6 @@
 
 const llvm::Type* DtoSize_t();
 
-const llvm::StructType* DtoComplexType(const llvm::Type* base);
-
 llvm::Constant* DtoConstInitializer(Type* type, Initializer* init);
 llvm::Constant* DtoConstFieldInitializer(Type* type, Initializer* init);
 DValue* DtoInitializer(Initializer* init);
@@ -50,6 +48,8 @@
 llvm::ConstantInt* DtoConstSize_t(size_t);
 llvm::ConstantInt* DtoConstUint(unsigned i);
 llvm::ConstantInt* DtoConstInt(int i);
+llvm::ConstantFP* DtoConstFP(Type* t, long double value);
+
 llvm::Constant* DtoConstString(const char*);
 llvm::Constant* DtoConstStringPtr(const char* str, const char* section = 0);
 llvm::Constant* DtoConstBool(bool);
@@ -98,6 +98,7 @@
 DValue* DtoCastInt(DValue* val, Type* to);
 DValue* DtoCastPtr(DValue* val, Type* to);
 DValue* DtoCastFloat(DValue* val, Type* to);
+DValue* DtoCastComplex(DValue* val, Type* to);
 DValue* DtoCastClass(DValue* val, Type* to);
 DValue* DtoCast(DValue* val, Type* to);
 
--- a/llvmdc.kdevelop.filelist	Sun Nov 18 08:25:07 2007 +0100
+++ b/llvmdc.kdevelop.filelist	Mon Nov 19 02:58:58 2007 +0100
@@ -105,6 +105,8 @@
 gen/binops.cpp
 gen/classes.cpp
 gen/classes.h
+gen/complex.cpp
+gen/complex.h
 gen/dvalue.cpp
 gen/dvalue.h
 gen/dwarftypes.cpp
@@ -142,6 +144,7 @@
 lphobos/internal/aApplyR.d
 lphobos/internal/adi.d
 lphobos/internal/arrays.d
+lphobos/internal/cmath2.d
 lphobos/internal/contract.d
 lphobos/internal/mem.d
 lphobos/internal/moduleinit.d
@@ -317,6 +320,8 @@
 test/classinfo2.d
 test/comma.d
 test/complex1.d
+test/complex2.d
+test/complex3.d
 test/cond.d
 test/cond1.d
 test/condexp.d
--- a/test/complex1.d	Sun Nov 18 08:25:07 2007 +0100
+++ b/test/complex1.d	Mon Nov 19 02:58:58 2007 +0100
@@ -2,5 +2,20 @@
 
 void main()
 {
-    cfloat c1;
+    cfloat cf1 = 3f + 0i;
+    cfloat cf2 = 4f + 1i;
+    cfloat cf3 = func();
+    auto c1 = cf1 + cf2;
+    auto c2 = cf2 - cf3;
+    {
+    auto c3 = cf1 * cf3;
+    {
+    auto c4 = cf2 / cf3;
+    }
+    }
 }
+
+cfloat func()
+{
+    return 3f + 1i;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/complex2.d	Mon Nov 19 02:58:58 2007 +0100
@@ -0,0 +1,14 @@
+module complex2;
+
+void main()
+{
+    cdouble c = 3.0 + 0i;
+    cdouble d = 2.0 + 0i;
+    {
+        cdouble c1 = c + 3.0;
+        cdouble c2 = c - 3.0i;
+    }
+    {
+        cdouble c1 = c / 2.0;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/complex3.d	Mon Nov 19 02:58:58 2007 +0100
@@ -0,0 +1,9 @@
+module complex3;
+
+void main()
+{
+    cfloat c1 = 1f + 0i;
+    cfloat c2 = 0f + 0i;
+    //c2 += 1f + 0i;
+    //assert(c1 == c2);
+}