changeset 107:3efbcc81ba45 trunk

[svn r111] Fixed most problems with complex number support and added typeinfo for them. Added typeinfo ti_C. Did some changes to the way expressions that have both lvalue and rvalue LLVM values are handled.
author lindquist
date Tue, 20 Nov 2007 00:02:35 +0100
parents 5b5194b25f33
children 288fe1029e1f
files gen/complex.cpp gen/complex.h gen/dvalue.h gen/toir.cpp gen/tollvm.cpp llvmdc.kdevelop.filelist lphobos/build.sh lphobos/typeinfo1/ti_cdouble.d lphobos/typeinfo1/ti_cfloat.d lphobos/typeinfo1/ti_creal.d lphobos/typeinfo2/ti_AC.d lphobos/typeinfos1.d lphobos/typeinfos2.d test/complex3.d
diffstat 14 files changed, 442 insertions(+), 127 deletions(-) [+]
line wrap: on
line diff
--- a/gen/complex.cpp	Mon Nov 19 06:01:48 2007 +0100
+++ b/gen/complex.cpp	Tue Nov 20 00:02:35 2007 +0100
@@ -127,8 +127,7 @@
     TY ty = t->ty;
 
     if (val->isComplex() || t->iscomplex()) {
-        assert(DtoDType(to) == t);
-        return val;
+        return DtoCastComplex(val, to);
     }
 
     const llvm::Type* base = DtoComplexBaseType(to);
@@ -166,6 +165,21 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+void DtoGetComplexParts(DValue* c, llvm::Value*& re, llvm::Value*& im)
+{
+    // lhs values
+    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* DtoComplexAdd(Type* type, DValue* lhs, DValue* rhs)
 {
     lhs = DtoComplex(type, lhs);
@@ -174,24 +188,9 @@
     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"));
-    }
-
+    DtoGetComplexParts(lhs, a, b);
     // 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"));
-    }
+    DtoGetComplexParts(rhs, c, d);
 
     // add up
     re = gIR->ir->CreateAdd(a, c, "tmp");
@@ -210,24 +209,9 @@
     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"));
-    }
-
+    DtoGetComplexParts(lhs, a, b);
     // 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"));
-    }
+    DtoGetComplexParts(rhs, c, d);
 
     // add up
     re = gIR->ir->CreateSub(a, c, "tmp");
@@ -243,29 +227,14 @@
     lhs = DtoComplex(type, lhs);
     rhs = DtoComplex(type, rhs);
 
-    llvm::Value *a, *b, *c, *d, *re, *im;
+    llvm::Value *a, *b, *c, *d;
 
     // 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"));
-    }
-
+    DtoGetComplexParts(lhs, a, b);
     // 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"));
-    }
+    DtoGetComplexParts(rhs, c, d);
 
-    llvm::Value *tmp1, *tmp2;
+    llvm::Value *tmp1, *tmp2, *re, *im;
 
     tmp1 = gIR->ir->CreateMul(a, c, "tmp");
     tmp2 = gIR->ir->CreateMul(b, d, "tmp");
@@ -285,29 +254,14 @@
     lhs = DtoComplex(type, lhs);
     rhs = DtoComplex(type, rhs);
 
-    llvm::Value *a, *b, *c, *d, *re, *im;
+    llvm::Value *a, *b, *c, *d;
 
     // 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"));
-    }
-
+    DtoGetComplexParts(lhs, a, b);
     // 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"));
-    }
+    DtoGetComplexParts(rhs, c, d);
 
-    llvm::Value *tmp1, *tmp2, *denom;
+    llvm::Value *tmp1, *tmp2, *denom, *re, *im;
 
     tmp1 = gIR->ir->CreateMul(c, c, "tmp");
     tmp2 = gIR->ir->CreateMul(d, d, "tmp");
@@ -330,29 +284,27 @@
 
 llvm::Value* DtoComplexEquals(TOK op, DValue* lhs, DValue* rhs)
 {
-    llvm::Value* lvec = lhs->getRVal();
-    llvm::Value* rvec = rhs->getRVal();
+    Type* type = lhs->getType();
+
+    lhs = DtoComplex(type, lhs);
+    rhs = DtoComplex(type, rhs);
+
+    llvm::Value *a, *b, *c, *d;
 
+    // lhs values
+    DtoGetComplexParts(lhs, a, b);
+    // rhs values
+    DtoGetComplexParts(rhs, c, d);
+
+    // select predicate
     llvm::FCmpInst::Predicate cmpop;
-    switch(op)
-    {
-    case TOKequal:
+    if (op == TOKequal)
         cmpop = llvm::FCmpInst::FCMP_OEQ;
-        break;
-    case TOKnotequal:
+    else
         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());
-
+    // (l.re==r.re && l.im==r.im)
+    llvm::Value* b1 = new llvm::FCmpInst(cmpop, a, c, "tmp", gIR->scopebb());
+    llvm::Value* b2 = new llvm::FCmpInst(cmpop, b, d, "tmp", gIR->scopebb());
     return gIR->ir->CreateAnd(b1,b2,"tmp");
 }
--- a/gen/complex.h	Mon Nov 19 06:01:48 2007 +0100
+++ b/gen/complex.h	Tue Nov 20 00:02:35 2007 +0100
@@ -17,6 +17,8 @@
 void DtoComplexAssign(llvm::Value* l, llvm::Value* r);
 void DtoComplexSet(llvm::Value* c, llvm::Value* re, llvm::Value* im);
 
+void DtoGetComplexParts(DValue* 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);
--- a/gen/dvalue.h	Mon Nov 19 06:01:48 2007 +0100
+++ b/gen/dvalue.h	Tue Nov 20 00:02:35 2007 +0100
@@ -31,7 +31,7 @@
 struct DFuncValue;
 struct DSliceValue;
 struct DArrayLenValue;
-struct DLValueCast;
+struct DLRValue;
 struct DComplexValue;
 
 // base class for d-values
@@ -51,8 +51,8 @@
     virtual DSliceValue* isSlice() { return NULL; }
     virtual DFuncValue* isFunc() { return NULL; }
     virtual DArrayLenValue* isArrayLen() { return NULL; }
-    virtual DLValueCast* isLValueCast() { return NULL; }
-    virtual DComplexValue* isComplex() { return NULL; };
+    virtual DComplexValue* isComplex() { return NULL; }
+    virtual DLRValue* isLRValue() { return NULL; }
 
     virtual bool inPlace() { return false; }
 
@@ -172,24 +172,28 @@
     virtual DFuncValue* isFunc() { return this; }
 };
 
-// l-value cast d-value
-struct DLValueCast : DValue
+// l-value and r-value pair d-value
+struct DLRValue : DValue
 {
-    Type* type;
+    Type* ltype;
     llvm::Value* lval;
+    Type* rtype;
     llvm::Value* rval;
 
-    DLValueCast(Type* t, llvm::Value* l, llvm::Value* r) {
-        type = t;
+    DLRValue(Type* lt, llvm::Value* l, Type* rt, llvm::Value* r) {
+        ltype = lt;
         lval = l;
+        rtype = rt;
         rval = r;
     }
 
     virtual llvm::Value* getLVal() { assert(lval); return lval; }
     virtual llvm::Value* getRVal() { assert(rval); return rval; }
 
-    virtual Type* getType() { assert(type); return type; }
-    virtual DLValueCast* isLValueCast() { return this; }
+    Type* getLType() { return ltype; }
+    Type* getRType() { return rtype; }
+    virtual Type* getType() { return getRType(); }
+    virtual DLRValue* isLRValue() { return this; }
 };
 
 // complex number immediate d-value (much like slice)
--- a/gen/toir.cpp	Mon Nov 19 06:01:48 2007 +0100
+++ b/gen/toir.cpp	Tue Nov 20 00:02:35 2007 +0100
@@ -562,7 +562,7 @@
         res = new DImValue(type, gep);
     }
     else if (t->iscomplex()) {
-        res = DtoComplexAdd(type, l, r);
+        res = DtoComplexAdd(e1->type, l, r);
     }
     else {
         res = DtoBinAdd(l,r);
@@ -1056,17 +1056,17 @@
     DValue* u = e1->toElem(p);
     DValue* v = DtoCast(u, to);
 
-    if (v->isSlice())
+    if (v->isSlice()) {
+        assert(!gIR->topexp() || gIR->topexp()->e1 != this);
         return v;
-    else if (u->isLValueCast() || (u->isVar() && u->isVar()->lval))
-        return new DLValueCast(to, u->getLVal(), v->getRVal());
-    else if (gIR->topexp() && gIR->topexp()->e1 == this) {
-        llvm::Value* lval = u->getLVal();
-        llvm::Value* rval = v->getRVal();
-        Logger::cout() << "lval: " << *lval << "rval: " << *rval << '\n';
-        return new DLValueCast(to, lval, rval);
     }
 
+    else if (u->isLRValue() || (u->isVar() && u->isVar()->lval))
+        return new DLRValue(e1->type, u->getLVal(), to, v->getRVal());
+
+    else if (gIR->topexp() && gIR->topexp()->e1 == this)
+        return new DLRValue(e1->type, u->getLVal(), to, v->getRVal());
+
     return v;
 }
 
@@ -1193,7 +1193,7 @@
     llvm::Value* v = lv;
     if (DtoCanLoad(v))
         v = DtoLoad(v);
-    return new DLValueCast(type, lv, v);
+    return new DLRValue(e1->type, lv, type, v);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
--- a/gen/tollvm.cpp	Mon Nov 19 06:01:48 2007 +0100
+++ b/gen/tollvm.cpp	Tue Nov 20 00:02:35 2007 +0100
@@ -689,6 +689,10 @@
                 retval = new llvm::AllocaInst(DtoType(realtype), "tmpparam", gIR->topallocapoint());
                 DtoSetArray(retval, DtoArrayLen(sv), DtoArrayPtr(sv));
             }
+            else if (DComplexValue* cv = arg->isComplex()) {
+                retval = new llvm::AllocaInst(DtoType(realtype), "tmpparam", gIR->topallocapoint());
+                DtoComplexSet(retval, cv->re, cv->im);
+            }
             else {
                 retval = arg->getRVal();
             }
@@ -719,6 +723,14 @@
                     allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
                 }
             }
+            else if (realtype->iscomplex()) {
+                if (arg->isComplex()) {
+                    allocaInst = new llvm::AllocaInst(realtypell, "tmpparam", gIR->topallocapoint());
+                }
+                else {
+                    allocaInst = new llvm::AllocaInst(pty->getElementType(), "tmpparam", gIR->topallocapoint());
+                }
+            }
             else
             assert(0);
 
@@ -736,6 +748,9 @@
             if (sl->len) Logger::cout() << "len = " << *sl->len << '\n';
             assert(0);
         }
+        else if (DComplexValue* cl = arg->isComplex()) {
+            assert(0 && "complex in the wrong place");
+        }
         else {
             retval = arg->getRVal();
         }
@@ -895,19 +910,27 @@
     }
     else if (t->iscomplex()) {
         assert(!lhs->isComplex());
-        if (DComplexValue* cx = rhs->isComplex()) {
-            DtoComplexSet(lhs->getRVal(), cx->re, cx->im);
+
+        llvm::Value* dst;
+        if (DLRValue* lr = lhs->isLRValue()) {
+            dst = lr->getLVal();
+            rhs = DtoCastComplex(rhs, lr->getLType());
         }
         else {
-            DtoComplexAssign(lhs->getRVal(), rhs->getRVal());
+            dst = lhs->getRVal();
         }
+
+        if (DComplexValue* cx = rhs->isComplex())
+            DtoComplexSet(dst, cx->re, cx->im);
+        else
+            DtoComplexAssign(dst, rhs->getRVal());
     }
     else {
         llvm::Value* r = rhs->getRVal();
         llvm::Value* l = lhs->getLVal();
         Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
         const llvm::Type* lit = l->getType()->getContainedType(0);
-        if (r->getType() != lit) {
+        if (r->getType() != lit) { // :(
             r = DtoBitCast(r, lit);
             Logger::cout() << "really assign\nlhs: " << *l << "rhs: " << *r << '\n';
         }
@@ -982,6 +1005,7 @@
         rval = new llvm::PtrToIntInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
     }
     else {
+        Logger::println("invalid cast from '%s' to '%s'", val->getType()->toChars(), to->toChars());
         assert(0);
     }
 
@@ -1040,16 +1064,48 @@
 DValue* DtoCastComplex(DValue* val, Type* _to)
 {
     Type* to = DtoDType(_to);
-    llvm::Value* v = val->getRVal();
+    Type* vty = val->getType();
     if (to->iscomplex()) {
-        assert(0);
+        if (vty->size() == to->size())
+            return val;
+
+        llvm::Value *re, *im;
+        DtoGetComplexParts(val, re, im);
+        const llvm::Type* 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)
+        llvm::Value* mem = new llvm::AllocaInst(DtoType(_to), "castcomplextmp", gIR->topallocapoint());
+        DtoComplexSet(mem, re, im);
+        return new DLRValue(val->getType(), val->getRVal(), _to, mem);
     }
     else if (to->isimaginary()) {
-        DImValue* im = new DImValue(to, gIR->ir->CreateExtractElement(v, DtoConstUint(1), "im"));
+        if (val->isComplex())
+            return new DImValue(to, val->isComplex()->im);
+        llvm::Value* v = val->getRVal();
+        DImValue* im = new DImValue(to, DtoLoad(DtoGEPi(v,0,1,"tmp")));
         return DtoCastFloat(im, to);
     }
     else if (to->isfloating()) {
-        DImValue* re = new DImValue(to, gIR->ir->CreateExtractElement(v, DtoConstUint(0), "re"));
+        if (val->isComplex())
+            return new DImValue(to, val->isComplex()->re);
+        llvm::Value* v = val->getRVal();
+        DImValue* re = new DImValue(to, DtoLoad(DtoGEPi(v,0,0,"tmp")));
         return DtoCastFloat(re, to);
     }
     else
--- a/llvmdc.kdevelop.filelist	Mon Nov 19 06:01:48 2007 +0100
+++ b/llvmdc.kdevelop.filelist	Tue Nov 20 00:02:35 2007 +0100
@@ -132,7 +132,6 @@
 gen/tollvm.h
 gen/toobj.cpp
 gen/typeinf.h
-gen/typeinfo12.d
 gen/typinf.cpp
 lphobos
 lphobos/crc32.d
@@ -193,7 +192,10 @@
 lphobos/std/utf.d
 lphobos/typeinfo1
 lphobos/typeinfo1/ti_byte.d
+lphobos/typeinfo1/ti_cdouble.d
+lphobos/typeinfo1/ti_cfloat.d
 lphobos/typeinfo1/ti_char.d
+lphobos/typeinfo1/ti_creal.d
 lphobos/typeinfo1/ti_dchar.d
 lphobos/typeinfo1/ti_delegate.d
 lphobos/typeinfo1/ti_double.d
@@ -213,6 +215,7 @@
 lphobos/typeinfo1/ti_void.d
 lphobos/typeinfo1/ti_wchar.d
 lphobos/typeinfo2
+lphobos/typeinfo2/ti_AC.d
 lphobos/typeinfo2/ti_Adouble.d
 lphobos/typeinfo2/ti_Afloat.d
 lphobos/typeinfo2/ti_Ag.d
@@ -220,6 +223,7 @@
 lphobos/typeinfo2/ti_Along.d
 lphobos/typeinfo2/ti_Areal.d
 lphobos/typeinfo2/ti_Ashort.d
+lphobos/typeinfo2/ti_C.d
 lphobos/typeinfos1.d
 lphobos/typeinfos2.d
 runalltests.d
@@ -304,8 +308,8 @@
 test/bug63.d
 test/bug64.d
 test/bug66.d
-test/bug69.d
 test/bug7.d
+test/bug70.d
 test/bug8.d
 test/bug9.d
 test/c.d
--- a/lphobos/build.sh	Mon Nov 19 06:01:48 2007 +0100
+++ b/lphobos/build.sh	Tue Nov 20 00:02:35 2007 +0100
@@ -20,7 +20,7 @@
 
 
 echo "compiling typeinfo 1"
-rebuild typeinfos1.d -c -oqobj -dc=llvmdc-posix || exit 1
+rebuild typeinfos1.d -c -oqobj -dc=llvmdc-posix -v || exit 1
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo1.*.bc` ../lib/llvmdcore.bc || exit 1
 
 echo "compiling typeinfo 2"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/typeinfo1/ti_cdouble.d	Tue Nov 20 00:02:35 2007 +0100
@@ -0,0 +1,67 @@
+
+// cdouble
+
+module std.typeinfo.ti_cdouble;
+
+class TypeInfo_r : TypeInfo
+{
+    char[] toString() { return "cdouble"; }
+
+    hash_t getHash(void *p)
+    {
+	return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+	       (cast(uint *)p)[2] + (cast(uint *)p)[3];
+    }
+
+    static int _equals(cdouble f1, cdouble f2)
+    {
+	return f1 == f2;
+    }
+
+    static int _compare(cdouble f1, cdouble f2)
+    {   int result;
+
+	if (f1.re < f2.re)
+	    result = -1;
+	else if (f1.re > f2.re)
+	    result = 1;
+	else if (f1.im < f2.im)
+	    result = -1;
+	else if (f1.im > f2.im)
+	    result = 1;
+	else
+	    result = 0;
+        return result;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    size_t tsize()
+    {
+	return cdouble.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	cdouble t;
+
+	t = *cast(cdouble *)p1;
+	*cast(cdouble *)p1 = *cast(cdouble *)p2;
+	*cast(cdouble *)p2 = t;
+    }
+
+    void[] init()
+    {	static cdouble r;
+
+	return (cast(cdouble *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/typeinfo1/ti_cfloat.d	Tue Nov 20 00:02:35 2007 +0100
@@ -0,0 +1,66 @@
+
+// cfloat
+
+module std.typeinfo.ti_cfloat;
+
+class TypeInfo_q : TypeInfo
+{
+    char[] toString() { return "cfloat"; }
+
+    hash_t getHash(void *p)
+    {
+	return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static int _equals(cfloat f1, cfloat f2)
+    {
+	return f1 == f2;
+    }
+
+    static int _compare(cfloat f1, cfloat f2)
+    {   int result;
+
+	if (f1.re < f2.re)
+	    result = -1;
+	else if (f1.re > f2.re)
+	    result = 1;
+	else if (f1.im < f2.im)
+	    result = -1;
+	else if (f1.im > f2.im)
+	    result = 1;
+	else
+	    result = 0;
+        return result;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    size_t tsize()
+    {
+	return cfloat.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	cfloat t;
+
+	t = *cast(cfloat *)p1;
+	*cast(cfloat *)p1 = *cast(cfloat *)p2;
+	*cast(cfloat *)p2 = t;
+    }
+
+    void[] init()
+    {	static cfloat r;
+
+	return (cast(cfloat *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/typeinfo1/ti_creal.d	Tue Nov 20 00:02:35 2007 +0100
@@ -0,0 +1,68 @@
+
+// creal
+
+module std.typeinfo.ti_creal;
+
+class TypeInfo_c : TypeInfo
+{
+    char[] toString() { return "creal"; }
+
+    hash_t getHash(void *p)
+    {
+	return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+	       (cast(uint *)p)[2] + (cast(uint *)p)[3] +
+	       (cast(uint *)p)[4];
+    }
+
+    static int _equals(creal f1, creal f2)
+    {
+	return f1 == f2;
+    }
+
+    static int _compare(creal f1, creal f2)
+    {   int result;
+
+	if (f1.re < f2.re)
+	    result = -1;
+	else if (f1.re > f2.re)
+	    result = 1;
+	else if (f1.im < f2.im)
+	    result = -1;
+	else if (f1.im > f2.im)
+	    result = 1;
+	else
+	    result = 0;
+        return result;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	return _equals(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	return _compare(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    size_t tsize()
+    {
+	return creal.sizeof;
+    }
+
+    void swap(void *p1, void *p2)
+    {
+	creal t;
+
+	t = *cast(creal *)p1;
+	*cast(creal *)p1 = *cast(creal *)p2;
+	*cast(creal *)p2 = t;
+    }
+
+    void[] init()
+    {	static creal r;
+
+	return (cast(creal *)&r)[0 .. 1];
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/typeinfo2/ti_AC.d	Tue Nov 20 00:02:35 2007 +0100
@@ -0,0 +1,92 @@
+module std.typeinfo.ti_AC;
+
+// Object[]
+
+class TypeInfo_AC : TypeInfo
+{
+    hash_t getHash(void *p)
+    {	Object[] s = *cast(Object[]*)p;
+	hash_t hash = 0;
+
+	foreach (Object o; s)
+	{
+	    if (o)
+		hash += o.toHash();
+	}
+	return hash;
+    }
+
+    int equals(void *p1, void *p2)
+    {
+	Object[] s1 = *cast(Object[]*)p1;
+	Object[] s2 = *cast(Object[]*)p2;
+
+	if (s1.length == s2.length)
+	{
+	    for (size_t u = 0; u < s1.length; u++)
+	    {	Object o1 = s1[u];
+		Object o2 = s2[u];
+
+		// Do not pass null's to Object.opEquals()
+		if (o1 is o2 ||
+		    (!(o1 is null) && !(o2 is null) && o1.opEquals(o2)))
+		    continue;
+		return 0;
+	    }
+	    return 1;
+	}
+	return 0;
+    }
+
+    int compare(void *p1, void *p2)
+    {
+	Object[] s1 = *cast(Object[]*)p1;
+	Object[] s2 = *cast(Object[]*)p2;
+	int c;
+
+	c = cast(int)s1.length - cast(int)s2.length;
+	if (c == 0)
+	{
+	    for (size_t u = 0; u < s1.length; u++)
+	    {	Object o1 = s1[u];
+		Object o2 = s2[u];
+
+		if (o1 is o2)
+		    continue;
+
+		// Regard null references as always being "less than"
+		if (o1)
+		{
+		    if (!o2)
+		    {	c = 1;
+			break;
+		    }
+		    c = o1.opCmp(o2);
+		    if (c)
+			break;
+		}
+		else
+		{   c = -1;
+		    break;
+		}
+	    }
+	}
+	return c;
+    }
+
+    size_t tsize()
+    {
+	return (Object[]).sizeof;
+    }
+
+    uint flags()
+    {
+	return 1;
+    }
+
+    TypeInfo next()
+    {
+	return typeid(Object);
+    }
+}
+
--- a/lphobos/typeinfos1.d	Mon Nov 19 06:01:48 2007 +0100
+++ b/lphobos/typeinfos1.d	Tue Nov 20 00:02:35 2007 +0100
@@ -2,13 +2,16 @@
 
 import
 typeinfo1.ti_byte,
+typeinfo1.ti_cdouble,
+typeinfo1.ti_cfloat,
 typeinfo1.ti_char,
+typeinfo1.ti_creal,
+typeinfo1.ti_dchar,
 typeinfo1.ti_delegate,
-typeinfo1.ti_dchar,
 typeinfo1.ti_double,
 typeinfo1.ti_float,
+typeinfo1.ti_idouble,
 typeinfo1.ti_ifloat,
-typeinfo1.ti_idouble,
 typeinfo1.ti_int,
 typeinfo1.ti_ireal,
 typeinfo1.ti_long,
--- a/lphobos/typeinfos2.d	Mon Nov 19 06:01:48 2007 +0100
+++ b/lphobos/typeinfos2.d	Tue Nov 20 00:02:35 2007 +0100
@@ -1,6 +1,7 @@
 module typeinfos2;
 
 import
+//typeinfo2.to_AC,
 typeinfo2.ti_Adouble,
 typeinfo2.ti_Afloat,
 typeinfo2.ti_Ag,
--- a/test/complex3.d	Mon Nov 19 06:01:48 2007 +0100
+++ b/test/complex3.d	Tue Nov 20 00:02:35 2007 +0100
@@ -4,6 +4,6 @@
 {
     cfloat c1 = 1f + 0i;
     cfloat c2 = 0f + 0i;
-    //c2 += 1f + 0i;
+    c2 += 1f + 0i;
     //assert(c1 == c2);
 }