Index: src/common/core/thread.d
===================================================================
--- src/common/core/thread.d	(revision 166)
+++ src/common/core/thread.d	(working copy)
@@ -333,8 +333,52 @@
         }
         body
         {
-            version( D_InlineAsm_X86 )
+            version(LDC)
             {
+                version(X86)
+                {
+                    uint eax,ecx,edx,ebx,ebp,esi,edi;
+                    asm
+                    {
+                        mov eax[EBP], EAX      ;
+                        mov ecx[EBP], ECX      ;
+                        mov edx[EBP], EDX      ;
+                        mov ebx[EBP], EBX      ;
+                        mov ebp[EBP], EBP      ;
+                        mov esi[EBP], ESI      ;
+                        mov edi[EBP], EDI      ;
+                    }
+                }
+                else version (X86_64)
+                {
+                    ulong rax,rbx,rcx,rdx,rbp,rsi,rdi,rsp,r8,r9,r10,r11,r12,r13,r14,r15;
+                    asm
+                    {
+                        movq rax[RBP], RAX        ;
+                        movq rbx[RBP], RBX        ;
+                        movq rcx[RBP], RCX        ;
+                        movq rdx[RBP], RDX        ;
+                        movq rbp[RBP], RBP        ;
+                        movq rsi[RBP], RSI        ;
+                        movq rdi[RBP], RDI        ;
+                        movq rsp[RBP], RSP        ;
+                        movq  r8[RBP], R8         ;
+                        movq  r9[RBP], R9         ;
+                        movq r10[RBP], R10        ;
+                        movq r11[RBP], R11        ;
+                        movq r12[RBP], R12        ;
+                        movq r13[RBP], R13        ;
+                        movq r14[RBP], R14        ;
+                        movq r15[RBP], R15        ;
+                    }
+                }
+                else
+                {
+                    static assert( false, "Architecture not supported." );
+                }
+            }
+	    else version( D_InlineAsm_X86 )
+            {
                 asm
                 {
                     pushad;
@@ -386,7 +430,11 @@
                 }
             }
 
-            version( D_InlineAsm_X86 )
+	    version(LDC)
+	    {
+		    // Nothing to pop
+	    }
+	    else version( D_InlineAsm_X86 )
             {
                 asm
                 {
Index: src/build-ldc.sh
===================================================================
--- src/build-ldc.sh	(revision 0)
+++ src/build-ldc.sh	(revision 0)
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+cd `dirname $0`
+
+GC=basic
+CC=gcc
+CFLAGS="-g -c"
+DC=ldmd2
+DFLAGS="-g -d -c -debug -I`pwd`/compiler/ldc"
+
+echo Cleaning...
+find . -name \*.o | xargs rm
+rm *.a
+
+compile()
+{
+	echo Compiling files in $1
+	opwd=`pwd`
+	cd $1
+	for f in `find . -name \*.d`; do
+		echo Compiling file: ${1}/${f}
+		$DC $DFLAGS -of${f%.*}.o $f
+	done
+	cd $opwd
+}
+
+compile_c()
+{
+	echo Compiling file: $1
+	$CC $CFLAGS $1 -o${1%.*}.o
+}
+
+link()
+{
+	echo Linking $1
+	ar rsv $1 `find . -name \*.o`
+}
+
+compile compiler/ldc
+compile common
+compile gc/$GC
+
+echo Compiling C files
+compile_c compiler/ldc/monitor.c
+compile_c compiler/ldc/critical.c
+compile_c common/core/stdc/errno.c
+
+link libdruntime-ldc.a

Property changes on: src/build-ldc.sh
___________________________________________________________________
Added: svn:executable
   + *

Index: src/gc/basic/gcx.d
===================================================================
--- src/gc/basic/gcx.d	(revision 166)
+++ src/gc/basic/gcx.d	(working copy)
@@ -1,3021 +0,0 @@
-/**
- * Contains the garbage collector implementation.
- *
- * Copyright: Copyright Digital Mars 2001 - 2009.
- * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
- * Authors:   Walter Bright, David Friedman, Sean Kelly
- *
- *          Copyright Digital Mars 2001 - 2009.
- * Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- */
-module gc.gcx;
-
-// D Programming Language Garbage Collector implementation
-
-/************** Debugging ***************************/
-
-//debug = PRINTF;               // turn on printf's
-//debug = COLLECT_PRINTF;       // turn on printf's
-//debug = THREADINVARIANT;      // check thread integrity
-//debug = LOGGING;              // log allocations / frees
-//debug = MEMSTOMP;             // stomp on memory
-//debug = SENTINEL;             // add underrun/overrrun protection
-//debug = PTRCHECK;             // more pointer checking
-//debug = PTRCHECK2;            // thorough but slow pointer checking
-
-/*************** Configuration *********************/
-
-version = STACKGROWSDOWN;       // growing the stack means subtracting from the stack pointer
-                                // (use for Intel X86 CPUs)
-                                // else growing the stack means adding to the stack pointer
-version = MULTI_THREADED;       // produce multithreaded version
-
-/***************************************************/
-
-private import gc.gcbits;
-private import gc.gcstats;
-private import gc.gcalloc;
-
-private import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
-private import core.stdc.string;
-
-debug (PRINTF) import core.stdc.stdio : printf;
-debug (COLLECT_PRINTF) import core.stdc.stdio : printf;
-debug private import core.stdc.stdio;
-
-private
-{
-    enum USE_CACHE = true;
-
-    enum BlkAttr : uint
-    {
-        FINALIZE = 0b0000_0001,
-        NO_SCAN  = 0b0000_0010,
-        NO_MOVE  = 0b0000_0100,
-        ALL_BITS = 0b1111_1111
-    }
-
-    struct BlkInfo
-    {
-        void*  base;
-        size_t size;
-        uint   attr;
-    }
-
-    extern (C) void* rt_stackBottom();
-    extern (C) void* rt_stackTop();
-
-    extern (C) void rt_finalize( void* p, bool det = true );
-
-    version (MULTI_THREADED)
-    {
-        extern (C) bool thread_needLock();
-        extern (C) void thread_suspendAll();
-        extern (C) void thread_resumeAll();
-
-        alias void delegate( void*, void* ) scanFn;
-        extern (C) void thread_scanAll( scanFn fn, void* curStackTop = null );
-    }
-
-    extern (C) void onOutOfMemoryError();
-
-    enum
-    {
-        OPFAIL = ~cast(size_t)0
-    }
-}
-
-
-alias GC gc_t;
-
-
-/* ======================= Leak Detector =========================== */
-
-
-debug (LOGGING)
-{
-    struct Log
-    {
-        void*  p;
-        size_t size;
-        size_t line;
-        char*  file;
-        void*  parent;
-
-        void print()
-        {
-            printf("    p = %x, size = %d, parent = %x ", p, size, parent);
-            if (file)
-            {
-                printf("%s(%u)", file, line);
-            }
-            printf("\n");
-        }
-    }
-
-
-    struct LogArray
-    {
-        size_t dim;
-        size_t allocdim;
-        Log *data;
-
-        void Dtor()
-        {
-            if (data)
-                cstdlib.free(data);
-            data = null;
-        }
-
-        void reserve(size_t nentries)
-        {
-            assert(dim <= allocdim);
-            if (allocdim - dim < nentries)
-            {
-                allocdim = (dim + nentries) * 2;
-                assert(dim + nentries <= allocdim);
-                if (!data)
-                {
-                    data = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
-                    if (!data && allocdim)
-                        onOutOfMemoryError();
-                }
-                else
-                {   Log *newdata;
-
-                    newdata = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
-                    if (!newdata && allocdim)
-                        onOutOfMemoryError();
-                    memcpy(newdata, data, dim * Log.sizeof);
-                    cstdlib.free(data);
-                    data = newdata;
-                }
-            }
-        }
-
-
-        void push(Log log)
-        {
-            reserve(1);
-            data[dim++] = log;
-        }
-
-        void remove(size_t i)
-        {
-            memmove(data + i, data + i + 1, (dim - i) * Log.sizeof);
-            dim--;
-        }
-
-
-        size_t find(void *p)
-        {
-            for (size_t i = 0; i < dim; i++)
-            {
-                if (data[i].p == p)
-                    return i;
-            }
-            return OPFAIL; // not found
-        }
-
-
-        void copy(LogArray *from)
-        {
-            reserve(from.dim - dim);
-            assert(from.dim <= allocdim);
-            memcpy(data, from.data, from.dim * Log.sizeof);
-            dim = from.dim;
-        }
-    }
-}
-
-
-/* ============================ GC =============================== */
-
-
-class GCLock { }                // just a dummy so we can get a global lock
-
-
-const uint GCVERSION = 1;       // increment every time we change interface
-                                // to GC.
-
-class GC
-{
-    // For passing to debug code (not thread safe)
-    __gshared size_t line;
-    __gshared char*  file;
-
-    uint gcversion = GCVERSION;
-
-    Gcx *gcx;                   // implementation
-    __gshared ClassInfo gcLock;    // global lock
-
-
-    void initialize()
-    {
-        gcLock = GCLock.classinfo;
-        gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof);
-        if (!gcx)
-            onOutOfMemoryError();
-        gcx.initialize();
-        setStackBottom(rt_stackBottom());
-    }
-
-
-    void Dtor()
-    {
-        version (linux)
-        {
-            //debug(PRINTF) printf("Thread %x ", pthread_self());
-            //debug(PRINTF) printf("GC.Dtor()\n");
-        }
-
-        if (gcx)
-        {
-            gcx.Dtor();
-            cstdlib.free(gcx);
-            gcx = null;
-        }
-    }
-
-
-    invariant()
-    {
-        if (gcx)
-        {
-            gcx.thread_Invariant();
-        }
-    }
-
-
-    /**
-     *
-     */
-    void enable()
-    {
-        if (!thread_needLock())
-        {
-            assert(gcx.disabled > 0);
-            gcx.disabled--;
-        }
-        else synchronized (gcLock)
-        {
-            assert(gcx.disabled > 0);
-            gcx.disabled--;
-        }
-    }
-
-
-    /**
-     *
-     */
-    void disable()
-    {
-        if (!thread_needLock())
-        {
-            gcx.disabled++;
-        }
-        else synchronized (gcLock)
-        {
-            gcx.disabled++;
-        }
-    }
-
-
-    /**
-     *
-     */
-    uint getAttr(void* p)
-    {
-        if (!p)
-        {
-            return 0;
-        }
-
-        uint go()
-        {
-            Pool* pool = gcx.findPool(p);
-            uint  oldb = 0;
-
-            if (pool)
-            {
-                auto biti = cast(size_t)(p - pool.baseAddr) / 16;
-
-                oldb = gcx.getBits(pool, biti);
-            }
-            return oldb;
-        }
-
-        if (!thread_needLock())
-        {
-            return go();
-        }
-        else synchronized (gcLock)
-        {
-            return go();
-        }
-    }
-
-
-    /**
-     *
-     */
-    uint setAttr(void* p, uint mask)
-    {
-        if (!p)
-        {
-            return 0;
-        }
-
-        uint go()
-        {
-            Pool* pool = gcx.findPool(p);
-            uint  oldb = 0;
-
-            if (pool)
-            {
-                auto biti = cast(size_t)(p - pool.baseAddr) / 16;
-
-                oldb = gcx.getBits(pool, biti);
-                gcx.setBits(pool, biti, mask);
-            }
-            return oldb;
-        }
-
-        if (!thread_needLock())
-        {
-            return go();
-        }
-        else synchronized (gcLock)
-        {
-            return go();
-        }
-    }
-
-
-    /**
-     *
-     */
-    uint clrAttr(void* p, uint mask)
-    {
-        if (!p)
-        {
-            return 0;
-        }
-
-        uint go()
-        {
-            Pool* pool = gcx.findPool(p);
-            uint  oldb = 0;
-
-            if (pool)
-            {
-                auto biti = cast(size_t)(p - pool.baseAddr) / 16;
-
-                oldb = gcx.getBits(pool, biti);
-                gcx.clrBits(pool, biti, mask);
-            }
-            return oldb;
-        }
-
-        if (!thread_needLock())
-        {
-            return go();
-        }
-        else synchronized (gcLock)
-        {
-            return go();
-        }
-    }
-
-
-    /**
-     *
-     */
-    void *malloc(size_t size, uint bits = 0)
-    {
-        if (!size)
-        {
-            return null;
-        }
-
-        // Since a finalizer could launch a new thread, we always need to lock
-        // when collecting.  The safest way to do this is to simply always lock
-        // when allocating.
-        synchronized (gcLock)
-        {
-            return mallocNoSync(size, bits);
-        }
-    }
-
-
-    //
-    //
-    //
-    private void *mallocNoSync(size_t size, uint bits = 0)
-    {
-        assert(size != 0);
-
-        void *p = null;
-        Bins bin;
-
-        //debug(PRINTF) printf("GC::malloc(size = %d, gcx = %p)\n", size, gcx);
-        assert(gcx);
-        //debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self());
-
-        size += SENTINEL_EXTRA;
-
-        // Compute size bin
-        // Cache previous binsize lookup - Dave Fladebo.
-        __gshared size_t lastsize = -1;
-        __gshared Bins lastbin;
-        if (size == lastsize)
-            bin = lastbin;
-        else
-        {
-            bin = gcx.findBin(size);
-            lastsize = size;
-            lastbin = bin;
-        }
-
-        if (bin < B_PAGE)
-        {
-            int  state     = gcx.disabled ? 1 : 0;
-            bool collected = false;
-
-            while (!gcx.bucket[bin] && !gcx.allocPage(bin))
-            {
-                switch (state)
-                {
-                case 0:
-                    gcx.fullcollectshell();
-                    collected = true;
-                    state = 1;
-                    continue;
-                case 1:
-                    gcx.newPool(1);
-                    state = 2;
-                    continue;
-                case 2:
-                    if (collected)
-                        onOutOfMemoryError();
-                    state = 0;
-                    continue;
-                default:
-                    assert(false);
-                }
-            }
-            p = gcx.bucket[bin];
-
-            // Return next item from free list
-            gcx.bucket[bin] = (cast(List*)p).next;
-            if( !(bits & BlkAttr.NO_SCAN) )
-                memset(p + size, 0, binsize[bin] - size);
-            //debug(PRINTF) printf("\tmalloc => %x\n", p);
-            debug (MEMSTOMP) memset(p, 0xF0, size);
-        }
-        else
-        {
-            p = gcx.bigAlloc(size);
-            if (!p)
-                onOutOfMemoryError();
-        }
-        size -= SENTINEL_EXTRA;
-        p = sentinel_add(p);
-        sentinel_init(p, size);
-        gcx.log_malloc(p, size);
-
-        if (bits)
-        {
-            Pool *pool = gcx.findPool(p);
-            assert(pool);
-
-            gcx.setBits(pool, cast(size_t)(p - pool.baseAddr) / 16, bits);
-        }
-        return p;
-    }
-
-
-    /**
-     *
-     */
-    void *calloc(size_t size, uint bits = 0)
-    {
-        if (!size)
-        {
-            return null;
-        }
-
-        // Since a finalizer could launch a new thread, we always need to lock
-        // when collecting.  The safest way to do this is to simply always lock
-        // when allocating.
-        synchronized (gcLock)
-        {
-            return callocNoSync(size, bits);
-        }
-    }
-
-
-    //
-    //
-    //
-    private void *callocNoSync(size_t size, uint bits = 0)
-    {
-        assert(size != 0);
-
-        //debug(PRINTF) printf("calloc: %x len %d\n", p, len);
-        void *p = mallocNoSync(size, bits);
-        memset(p, 0, size);
-        return p;
-    }
-
-
-    /**
-     *
-     */
-    void *realloc(void *p, size_t size, uint bits = 0)
-    {
-        // Since a finalizer could launch a new thread, we always need to lock
-        // when collecting.  The safest way to do this is to simply always lock
-        // when allocating.
-        synchronized (gcLock)
-        {
-            return reallocNoSync(p, size, bits);
-        }
-    }
-
-
-    //
-    //
-    //
-    private void *reallocNoSync(void *p, size_t size, uint bits = 0)
-    {
-        if (!size)
-        {   if (p)
-            {   freeNoSync(p);
-                p = null;
-            }
-        }
-        else if (!p)
-        {
-            p = mallocNoSync(size, bits);
-        }
-        else
-        {   void *p2;
-            size_t psize;
-
-            //debug(PRINTF) printf("GC::realloc(p = %x, size = %u)\n", p, size);
-            version (SENTINEL)
-            {
-                sentinel_Invariant(p);
-                psize = *sentinel_size(p);
-                if (psize != size)
-                {
-                    if (psize)
-                    {
-                        Pool *pool = gcx.findPool(p);
-
-                        if (pool)
-                        {
-                            auto biti = cast(size_t)(p - pool.baseAddr) / 16;
-
-                            if (bits)
-                            {
-                                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
-                                gcx.setBits(pool, biti, bits);
-                            }
-                            else
-                            {
-                                bits = gcx.getBits(pool, biti);
-                            }
-                        }
-                    }
-                    p2 = mallocNoSync(size, bits);
-                    if (psize < size)
-                        size = psize;
-                    //debug(PRINTF) printf("\tcopying %d bytes\n",size);
-                    memcpy(p2, p, size);
-                    p = p2;
-                }
-            }
-            else
-            {
-                psize = gcx.findSize(p);        // find allocated size
-                if (psize >= PAGESIZE && size >= PAGESIZE)
-                {
-                    auto psz = psize / PAGESIZE;
-                    auto newsz = (size + PAGESIZE - 1) / PAGESIZE;
-                    if (newsz == psz)
-                        return p;
-
-                    auto pool = gcx.findPool(p);
-                    auto pagenum = (p - pool.baseAddr) / PAGESIZE;
-
-                    if (newsz < psz)
-                    {   // Shrink in place
-                        synchronized (gcLock)
-                        {
-                            debug (MEMSTOMP) memset(p + size, 0xF2, psize - size);
-                            pool.freePages(pagenum + newsz, psz - newsz);
-                        }
-                        return p;
-                    }
-                    else if (pagenum + newsz <= pool.npages)
-                    {
-                        // Attempt to expand in place
-                        synchronized (gcLock)
-                        {
-                            for (size_t i = pagenum + psz; 1;)
-                            {
-                                if (i == pagenum + newsz)
-                                {
-                                    debug (MEMSTOMP) memset(p + psize, 0xF0, size - psize);
-                                    memset(&pool.pagetable[pagenum + psz], B_PAGEPLUS, newsz - psz);
-                                    return p;
-                                }
-                                if (i == pool.ncommitted)
-                                {
-                                    auto u = pool.extendPages(pagenum + newsz - pool.ncommitted);
-                                    if (u == OPFAIL)
-                                        break;
-                                    i = pagenum + newsz;
-                                    continue;
-                                }
-                                if (pool.pagetable[i] != B_FREE)
-                                    break;
-                                i++;
-                            }
-                        }
-                    }
-                }
-                if (psize < size ||             // if new size is bigger
-                    psize > size * 2)           // or less than half
-                {
-                    if (psize)
-                    {
-                        Pool *pool = gcx.findPool(p);
-
-                        if (pool)
-                        {
-                            auto biti = cast(size_t)(p - pool.baseAddr) / 16;
-
-                            if (bits)
-                            {
-                                gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
-                                gcx.setBits(pool, biti, bits);
-                            }
-                            else
-                            {
-                                bits = gcx.getBits(pool, biti);
-                            }
-                        }
-                    }
-                    p2 = mallocNoSync(size, bits);
-                    if (psize < size)
-                        size = psize;
-                    //debug(PRINTF) printf("\tcopying %d bytes\n",size);
-                    memcpy(p2, p, size);
-                    p = p2;
-                }
-            }
-        }
-        return p;
-    }
-
-
-    /**
-     * Attempt to in-place enlarge the memory block pointed to by p by at least
-     * minbytes beyond its current capacity, up to a maximum of maxsize.  This
-     * does not attempt to move the memory block (like realloc() does).
-     *
-     * Returns:
-     *  0 if could not extend p,
-     *  total size of entire memory block if successful.
-     */
-    size_t extend(void* p, size_t minsize, size_t maxsize)
-    {
-        if (!thread_needLock())
-        {
-            return extendNoSync(p, minsize, maxsize);
-        }
-        else synchronized (gcLock)
-        {
-            return extendNoSync(p, minsize, maxsize);
-        }
-    }
-
-
-    //
-    //
-    //
-    private size_t extendNoSync(void* p, size_t minsize, size_t maxsize)
-    in
-    {
-        assert( minsize <= maxsize );
-    }
-    body
-    {
-        //debug(PRINTF) printf("GC::extend(p = %x, minsize = %u, maxsize = %u)\n", p, minsize, maxsize);
-        version (SENTINEL)
-        {
-            return 0;
-        }
-        auto psize = gcx.findSize(p);   // find allocated size
-        if (psize < PAGESIZE)
-            return 0;                   // cannot extend buckets
-
-        auto psz = psize / PAGESIZE;
-        auto minsz = (minsize + PAGESIZE - 1) / PAGESIZE;
-        auto maxsz = (maxsize + PAGESIZE - 1) / PAGESIZE;
-
-        auto pool = gcx.findPool(p);
-        auto pagenum = (p - pool.baseAddr) / PAGESIZE;
-
-        size_t sz;
-        for (sz = 0; sz < maxsz; sz++)
-        {
-            auto i = pagenum + psz + sz;
-            if (i == pool.ncommitted)
-                break;
-            if (pool.pagetable[i] != B_FREE)
-            {   if (sz < minsz)
-                    return 0;
-                break;
-            }
-        }
-        if (sz >= minsz)
-        {
-        }
-        else if (pagenum + psz + sz == pool.ncommitted)
-        {
-            auto u = pool.extendPages(minsz - sz);
-            if (u == OPFAIL)
-                return 0;
-            sz = minsz;
-        }
-        else
-            return 0;
-        debug (MEMSTOMP) memset(p + psize, 0xF0, (psz + sz) * PAGESIZE - psize);
-        memset(pool.pagetable + pagenum + psz, B_PAGEPLUS, sz);
-        if (p == gcx.cached_size_key)
-            gcx.cached_size_val = (psz + sz) * PAGESIZE;
-        if (p == gcx.cached_info_key)
-            gcx.cached_info_val.size = (psz + sz) * PAGESIZE;
-        return (psz + sz) * PAGESIZE;
-    }
-
-
-    /**
-     *
-     */
-    size_t reserve(size_t size)
-    {
-        if (!size)
-        {
-            return 0;
-        }
-
-        if (!thread_needLock())
-        {
-            return reserveNoSync(size);
-        }
-        else synchronized (gcLock)
-        {
-            return reserveNoSync(size);
-        }
-    }
-
-
-    //
-    //
-    //
-    private size_t reserveNoSync(size_t size)
-    {
-        assert(size != 0);
-        assert(gcx);
-
-        return gcx.reserve(size);
-    }
-
-
-    /**
-     *
-     */
-    void free(void *p)
-    {
-        if (!p)
-        {
-            return;
-        }
-
-        if (!thread_needLock())
-        {
-            return freeNoSync(p);
-        }
-        else synchronized (gcLock)
-        {
-            return freeNoSync(p);
-        }
-    }
-
-
-    //
-    //
-    //
-    private void freeNoSync(void *p)
-    {
-        assert (p);
-
-        Pool*  pool;
-        size_t pagenum;
-        Bins   bin;
-        size_t biti;
-
-        // Find which page it is in
-        pool = gcx.findPool(p);
-        if (!pool)                              // if not one of ours
-            return;                             // ignore
-        sentinel_Invariant(p);
-        p = sentinel_sub(p);
-        pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
-        biti = cast(size_t)(p - pool.baseAddr) / 16;
-        gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
-
-        bin = cast(Bins)pool.pagetable[pagenum];
-        if (bin == B_PAGE)              // if large alloc
-        {   size_t npages;
-            size_t n;
-
-            // Free pages
-            npages = 1;
-            n = pagenum;
-            while (++n < pool.ncommitted && pool.pagetable[n] == B_PAGEPLUS)
-                npages++;
-            debug (MEMSTOMP) memset(p, 0xF2, npages * PAGESIZE);
-            pool.freePages(pagenum, npages);
-        }
-        else
-        {   // Add to free list
-            List *list = cast(List*)p;
-
-            debug (MEMSTOMP) memset(p, 0xF2, binsize[bin]);
-
-            list.next = gcx.bucket[bin];
-            gcx.bucket[bin] = list;
-        }
-        gcx.log_free(sentinel_add(p));
-    }
-
-
-    /**
-     * Determine the base address of the block containing p.  If p is not a gc
-     * allocated pointer, return null.
-     */
-    void* addrOf(void *p)
-    {
-        if (!p)
-        {
-            return null;
-        }
-
-        if (!thread_needLock())
-        {
-            return addrOfNoSync(p);
-        }
-        else synchronized (gcLock)
-        {
-            return addrOfNoSync(p);
-        }
-    }
-
-
-    //
-    //
-    //
-    void* addrOfNoSync(void *p)
-    {
-        if (!p)
-        {
-            return null;
-        }
-
-        return gcx.findBase(p);
-    }
-
-
-    /**
-     * Determine the allocated size of pointer p.  If p is an interior pointer
-     * or not a gc allocated pointer, return 0.
-     */
-    size_t sizeOf(void *p)
-    {
-        if (!p)
-        {
-            return 0;
-        }
-
-        if (!thread_needLock())
-        {
-            return sizeOfNoSync(p);
-        }
-        else synchronized (gcLock)
-        {
-            return sizeOfNoSync(p);
-        }
-    }
-
-
-    //
-    //
-    //
-    private size_t sizeOfNoSync(void *p)
-    {
-        assert (p);
-
-        version (SENTINEL)
-        {
-            p = sentinel_sub(p);
-            size_t size = gcx.findSize(p);
-
-            // Check for interior pointer
-            // This depends on:
-            // 1) size is a power of 2 for less than PAGESIZE values
-            // 2) base of memory pool is aligned on PAGESIZE boundary
-            if (cast(size_t)p & (size - 1) & (PAGESIZE - 1))
-                size = 0;
-            return size ? size - SENTINEL_EXTRA : 0;
-        }
-        else
-        {
-            size_t size = gcx.findSize(p);
-
-            // Check for interior pointer
-            // This depends on:
-            // 1) size is a power of 2 for less than PAGESIZE values
-            // 2) base of memory pool is aligned on PAGESIZE boundary
-            if (cast(size_t)p & (size - 1) & (PAGESIZE - 1))
-                return 0;
-            return size;
-        }
-    }
-
-
-    /**
-     * Determine the base address of the block containing p.  If p is not a gc
-     * allocated pointer, return null.
-     */
-    BlkInfo query(void *p)
-    {
-        if (!p)
-        {
-            BlkInfo i;
-            return  i;
-        }
-
-        if (!thread_needLock())
-        {
-            return queryNoSync(p);
-        }
-        else synchronized (gcLock)
-        {
-            return queryNoSync(p);
-        }
-    }
-
-
-    //
-    //
-    //
-    BlkInfo queryNoSync(void *p)
-    {
-        assert(p);
-
-        return gcx.getInfo(p);
-    }
-
-
-    /**
-     * Verify that pointer p:
-     *  1) belongs to this memory pool
-     *  2) points to the start of an allocated piece of memory
-     *  3) is not on a free list
-     */
-    void check(void *p)
-    {
-        if (!p)
-        {
-            return;
-        }
-
-        if (!thread_needLock())
-        {
-            checkNoSync(p);
-        }
-        else synchronized (gcLock)
-        {
-            checkNoSync(p);
-        }
-    }
-
-
-    //
-    //
-    //
-    private void checkNoSync(void *p)
-    {
-        assert(p);
-
-        sentinel_Invariant(p);
-        debug (PTRCHECK)
-        {
-            Pool*  pool;
-            size_t pagenum;
-            Bins   bin;
-            size_t size;
-
-            p = sentinel_sub(p);
-            pool = gcx.findPool(p);
-            assert(pool);
-            pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
-            bin = cast(Bins)pool.pagetable[pagenum];
-            assert(bin <= B_PAGE);
-            size = binsize[bin];
-            assert((cast(size_t)p & (size - 1)) == 0);
-
-            debug (PTRCHECK2)
-            {
-                if (bin < B_PAGE)
-                {
-                    // Check that p is not on a free list
-                    List *list;
-
-                    for (list = gcx.bucket[bin]; list; list = list.next)
-                    {
-                        assert(cast(void*)list != p);
-                    }
-                }
-            }
-        }
-    }
-
-
-    //
-    //
-    //
-    private void setStackBottom(void *p)
-    {
-        version (STACKGROWSDOWN)
-        {
-            //p = (void *)((uint *)p + 4);
-            if (p > gcx.stackBottom)
-            {
-                //debug(PRINTF) printf("setStackBottom(%x)\n", p);
-                gcx.stackBottom = p;
-            }
-        }
-        else
-        {
-            //p = (void *)((uint *)p - 4);
-            if (p < gcx.stackBottom)
-            {
-                //debug(PRINTF) printf("setStackBottom(%x)\n", p);
-                gcx.stackBottom = cast(char*)p;
-            }
-        }
-    }
-
-
-    /**
-     * add p to list of roots
-     */
-    void addRoot(void *p)
-    {
-        if (!p)
-        {
-            return;
-        }
-
-        if (!thread_needLock())
-        {
-            gcx.addRoot(p);
-        }
-        else synchronized (gcLock)
-        {
-            gcx.addRoot(p);
-        }
-    }
-
-
-    /**
-     * remove p from list of roots
-     */
-    void removeRoot(void *p)
-    {
-        if (!p)
-        {
-            return;
-        }
-
-        if (!thread_needLock())
-        {
-            gcx.removeRoot(p);
-        }
-        else synchronized (gcLock)
-        {
-            gcx.removeRoot(p);
-        }
-    }
-
-
-    /**
-     *
-     */
-    int delegate(int delegate(inout void*)) rootIter()
-    {
-        if (!thread_needLock())
-        {
-            return &gcx.rootIter;
-        }
-        else synchronized (gcLock)
-        {
-            return &gcx.rootIter;
-        }
-    }
-
-
-    /**
-     * add range to scan for roots
-     */
-    void addRange(void *p, size_t sz)
-    {
-        if (!p || !sz)
-        {
-            return;
-        }
-
-        //debug(PRINTF) printf("+GC.addRange(pbot = x%x, ptop = x%x)\n", pbot, ptop);
-        if (!thread_needLock())
-        {
-            gcx.addRange(p, p + sz);
-        }
-        else synchronized (gcLock)
-        {
-            gcx.addRange(p, p + sz);
-        }
-        //debug(PRINTF) printf("-GC.addRange()\n");
-    }
-
-
-    /**
-     * remove range
-     */
-    void removeRange(void *p)
-    {
-        if (!p)
-        {
-            return;
-        }
-
-        if (!thread_needLock())
-        {
-            gcx.removeRange(p);
-        }
-        else synchronized (gcLock)
-        {
-            gcx.removeRange(p);
-        }
-    }
-
-
-    /**
-     *
-     */
-    int delegate(int delegate(inout Range)) rangeIter()
-    {
-        if (!thread_needLock())
-        {
-            return &gcx.rangeIter;
-        }
-        else synchronized (gcLock)
-        {
-            return &gcx.rangeIter;
-        }
-    }
-
-
-    /**
-     * do full garbage collection
-     */
-    void fullCollect()
-    {
-        debug(PRINTF) printf("GC.fullCollect()\n");
-
-        // Since a finalizer could launch a new thread, we always need to lock
-        // when collecting.
-        synchronized (gcLock)
-        {
-            gcx.fullcollectshell();
-        }
-
-        version (none)
-        {
-            GCStats stats;
-
-            getStats(stats);
-            debug(PRINTF) printf("poolsize = %x, usedsize = %x, freelistsize = %x\n",
-                    stats.poolsize, stats.usedsize, stats.freelistsize);
-        }
-
-        gcx.log_collect();
-    }
-
-
-    /**
-     * do full garbage collection ignoring roots
-     */
-    void fullCollectNoStack()
-    {
-        // Since a finalizer could launch a new thread, we always need to lock
-        // when collecting.
-        synchronized (gcLock)
-        {
-            gcx.noStack++;
-            gcx.fullcollectshell();
-            gcx.noStack--;
-        }
-    }
-
-
-    /**
-     * minimize free space usage
-     */
-    void minimize()
-    {
-        if (!thread_needLock())
-        {
-            gcx.minimize();
-        }
-        else synchronized (gcLock)
-        {
-            gcx.minimize();
-        }
-    }
-
-
-    /**
-     * Retrieve statistics about garbage collection.
-     * Useful for debugging and tuning.
-     */
-    void getStats(out GCStats stats)
-    {
-        if (!thread_needLock())
-        {
-            getStatsNoSync(stats);
-        }
-        else synchronized (gcLock)
-        {
-            getStatsNoSync(stats);
-        }
-    }
-
-
-    //
-    //
-    //
-    private void getStatsNoSync(out GCStats stats)
-    {
-        size_t psize = 0;
-        size_t usize = 0;
-        size_t flsize = 0;
-
-        size_t n;
-        size_t bsize = 0;
-
-        //debug(PRINTF) printf("getStats()\n");
-        memset(&stats, 0, GCStats.sizeof);
-
-        for (n = 0; n < gcx.npools; n++)
-        {   Pool *pool = gcx.pooltable[n];
-
-            psize += pool.ncommitted * PAGESIZE;
-            for (size_t j = 0; j < pool.ncommitted; j++)
-            {
-                Bins bin = cast(Bins)pool.pagetable[j];
-                if (bin == B_FREE)
-                    stats.freeblocks++;
-                else if (bin == B_PAGE)
-                    stats.pageblocks++;
-                else if (bin < B_PAGE)
-                    bsize += PAGESIZE;
-            }
-        }
-
-        for (n = 0; n < B_PAGE; n++)
-        {
-            //debug(PRINTF) printf("bin %d\n", n);
-            for (List *list = gcx.bucket[n]; list; list = list.next)
-            {
-                //debug(PRINTF) printf("\tlist %x\n", list);
-                flsize += binsize[n];
-            }
-        }
-
-        usize = bsize - flsize;
-
-        stats.poolsize = psize;
-        stats.usedsize = bsize - flsize;
-        stats.freelistsize = flsize;
-    }
-}
-
-
-/* ============================ Gcx =============================== */
-
-enum
-{   PAGESIZE =    4096,
-    COMMITSIZE = (4096*16),
-    POOLSIZE =   (4096*256),
-}
-
-
-enum
-{
-    B_16,
-    B_32,
-    B_64,
-    B_128,
-    B_256,
-    B_512,
-    B_1024,
-    B_2048,
-    B_PAGE,             // start of large alloc
-    B_PAGEPLUS,         // continuation of large alloc
-    B_FREE,             // free page
-    B_UNCOMMITTED,      // memory not committed for this page
-    B_MAX
-}
-
-
-alias ubyte Bins;
-
-
-struct List
-{
-    List *next;
-}
-
-
-struct Range
-{
-    void *pbot;
-    void *ptop;
-}
-
-
-immutable uint binsize[B_MAX] = [ 16,32,64,128,256,512,1024,2048,4096 ];
-immutable uint notbinsize[B_MAX] = [ ~(16u-1),~(32u-1),~(64u-1),~(128u-1),~(256u-1),
-                                ~(512u-1),~(1024u-1),~(2048u-1),~(4096u-1) ];
-
-/* ============================ Gcx =============================== */
-
-
-struct Gcx
-{
-    debug (THREADINVARIANT)
-    {
-        pthread_t self;
-        void thread_Invariant()
-        {
-            if (self != pthread_self())
-                printf("thread_Invariant(): gcx = %x, self = %x, pthread_self() = %x\n", this, self, pthread_self());
-            assert(self == pthread_self());
-        }
-    }
-    else
-    {
-        void thread_Invariant() { }
-    }
-    
-    void *cached_size_key;
-    size_t cached_size_val;
-    
-    void *cached_info_key;
-    BlkInfo cached_info_val;
-
-    size_t nroots;
-    size_t rootdim;
-    void **roots;
-
-    size_t nranges;
-    size_t rangedim;
-    Range *ranges;
-
-    uint noStack;       // !=0 means don't scan stack
-    uint log;           // turn on logging
-    uint anychanges;
-    void *stackBottom;
-    uint inited;
-    int disabled;       // turn off collections if >0
-
-    byte *minAddr;      // min(baseAddr)
-    byte *maxAddr;      // max(topAddr)
-
-    size_t npools;
-    Pool **pooltable;
-
-    List *bucket[B_MAX];        // free list for each size
-
-
-    void initialize()
-    {   int dummy;
-
-        (cast(byte*)&this)[0 .. Gcx.sizeof] = 0;
-        stackBottom = cast(char*)&dummy;
-        log_init();
-        debug (THREADINVARIANT)
-            self = pthread_self();
-        //printf("gcx = %p, self = %x\n", this, self);
-        inited = 1;
-    }
-
-
-    void Dtor()
-    {
-        inited = 0;
-
-        for (size_t i = 0; i < npools; i++)
-        {   Pool *pool = pooltable[i];
-
-            pool.Dtor();
-            cstdlib.free(pool);
-        }
-        if (pooltable)
-            cstdlib.free(pooltable);
-
-        if (roots)
-            cstdlib.free(roots);
-
-        if (ranges)
-            cstdlib.free(ranges);
-    }
-
-
-    void Invariant() { }
-
-
-    invariant()
-    {
-        if (inited)
-        {
-        //printf("Gcx.invariant(): this = %p\n", this);
-            size_t i;
-
-            // Assure we're called on the right thread
-            debug (THREADINVARIANT) assert(self == pthread_self());
-
-            for (i = 0; i < npools; i++)
-            {   Pool *pool = pooltable[i];
-
-                pool.Invariant();
-                if (i == 0)
-                {
-                    assert(minAddr == pool.baseAddr);
-                }
-                if (i + 1 < npools)
-                {
-                    assert(pool.opCmp(pooltable[i + 1]) < 0);
-                }
-                else if (i + 1 == npools)
-                {
-                    assert(maxAddr == pool.topAddr);
-                }
-            }
-
-            if (roots)
-            {
-                assert(rootdim != 0);
-                assert(nroots <= rootdim);
-            }
-
-            if (ranges)
-            {
-                assert(rangedim != 0);
-                assert(nranges <= rangedim);
-
-                for (i = 0; i < nranges; i++)
-                {
-                    assert(ranges[i].pbot);
-                    assert(ranges[i].ptop);
-                    assert(ranges[i].pbot <= ranges[i].ptop);
-                }
-            }
-
-            for (i = 0; i < B_PAGE; i++)
-            {
-                for (List *list = bucket[i]; list; list = list.next)
-                {
-                }
-            }
-        }
-    }
-
-
-    /**
-     *
-     */
-    void addRoot(void *p)
-    {
-        if (nroots == rootdim)
-        {
-            size_t newdim = rootdim * 2 + 16;
-            void** newroots;
-
-            newroots = cast(void**)cstdlib.malloc(newdim * newroots[0].sizeof);
-            if (!newroots)
-                onOutOfMemoryError();
-            if (roots)
-            {   memcpy(newroots, roots, nroots * newroots[0].sizeof);
-                cstdlib.free(roots);
-            }
-            roots = newroots;
-            rootdim = newdim;
-        }
-        roots[nroots] = p;
-        nroots++;
-    }
-
-
-    /**
-     *
-     */
-    void removeRoot(void *p)
-    {
-        for (size_t i = nroots; i--;)
-        {
-            if (roots[i] == p)
-            {
-                nroots--;
-                memmove(roots + i, roots + i + 1, (nroots - i) * roots[0].sizeof);
-                return;
-            }
-        }
-        assert(0);
-    }
-
-
-    /**
-     *
-     */
-    int rootIter(int delegate(inout void*) dg)
-    {
-        int result = 0;
-        for( size_t i = 0; i < nroots; ++i )
-        {
-            result = dg(roots[i]);
-            if (result)
-                break;
-        }
-        return result;
-    }
-
-
-    /**
-     *
-     */
-    void addRange(void *pbot, void *ptop)
-    {
-        //debug(PRINTF) printf("Thread %x ", pthread_self());
-        debug(PRINTF) printf("%x.Gcx::addRange(%x, %x), nranges = %d\n", this, pbot, ptop, nranges);
-        if (nranges == rangedim)
-        {
-            size_t newdim = rangedim * 2 + 16;
-            Range *newranges;
-
-            newranges = cast(Range*)cstdlib.malloc(newdim * newranges[0].sizeof);
-            if (!newranges)
-                onOutOfMemoryError();
-            if (ranges)
-            {   memcpy(newranges, ranges, nranges * newranges[0].sizeof);
-                cstdlib.free(ranges);
-            }
-            ranges = newranges;
-            rangedim = newdim;
-        }
-        ranges[nranges].pbot = pbot;
-        ranges[nranges].ptop = ptop;
-        nranges++;
-    }
-
-
-    /**
-     *
-     */
-    void removeRange(void *pbot)
-    {
-        //debug(PRINTF) printf("Thread %x ", pthread_self());
-        debug(PRINTF) printf("%x.Gcx.removeRange(%x), nranges = %d\n", this, pbot, nranges);
-        for (size_t i = nranges; i--;)
-        {
-            if (ranges[i].pbot == pbot)
-            {
-                nranges--;
-                memmove(ranges + i, ranges + i + 1, (nranges - i) * ranges[0].sizeof);
-                return;
-            }
-        }
-        debug(PRINTF) printf("Wrong thread\n");
-
-        // This is a fatal error, but ignore it.
-        // The problem is that we can get a Close() call on a thread
-        // other than the one the range was allocated on.
-        //assert(zero);
-    }
-
-
-    /**
-     *
-     */
-    int rangeIter(int delegate(inout Range) dg)
-    {
-        int result = 0;
-        for( size_t i = 0; i < nranges; ++i )
-        {
-            result = dg(ranges[i]);
-            if (result)
-                break;
-        }
-        return result;
-    }
-
-
-    /**
-     * Find Pool that pointer is in.
-     * Return null if not in a Pool.
-     * Assume pooltable[] is sorted.
-     */
-    Pool *findPool(void *p)
-    {
-        if (p >= minAddr && p < maxAddr)
-        {
-            if (npools == 1)
-            {
-                return pooltable[0];
-            }
-
-            for (size_t i = 0; i < npools; i++)
-            {   Pool *pool;
-
-                pool = pooltable[i];
-                if (p < pool.topAddr)
-                {   if (pool.baseAddr <= p)
-                        return pool;
-                    break;
-                }
-            }
-        }
-        return null;
-    }
-
-
-    /**
-     * Find base address of block containing pointer p.
-     * Returns null if not a gc'd pointer
-     */
-    void* findBase(void *p)
-    {
-        Pool *pool;
-
-        pool = findPool(p);
-        if (pool)
-        {
-            size_t offset = cast(size_t)(p - pool.baseAddr);
-            size_t pn = offset / PAGESIZE;
-            Bins   bin = cast(Bins)pool.pagetable[pn];
-
-            // Adjust bit to be at start of allocated memory block
-            if (bin <= B_PAGE)
-            {
-                return pool.baseAddr + (offset & notbinsize[bin]);
-            }
-            else if (bin == B_PAGEPLUS)
-            {
-                do
-                {   --pn, offset -= PAGESIZE;
-                } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
-
-                return pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
-            }
-            else
-            {
-                // we are in a B_FREE or B_UNCOMMITTED page
-                return null;
-            }
-        }
-        return null;
-    }
-
-
-    /**
-     * Find size of pointer p.
-     * Returns 0 if not a gc'd pointer
-     */
-    size_t findSize(void *p)
-    {
-        Pool*  pool;
-        size_t size = 0;
-
-        if (USE_CACHE && p == cached_size_key)
-            return cached_size_val;
-            
-        pool = findPool(p);
-        if (pool)
-        {
-            size_t pagenum;
-            Bins   bin;
-
-            pagenum = cast(size_t)(p - pool.baseAddr) / PAGESIZE;
-            bin = cast(Bins)pool.pagetable[pagenum];
-            size = binsize[bin];
-            if (bin == B_PAGE)
-            {   size_t npages = pool.ncommitted;
-                ubyte* pt;
-                size_t i;
-
-                pt = &pool.pagetable[0];
-                for (i = pagenum + 1; i < npages; i++)
-                {
-                    if (pt[i] != B_PAGEPLUS)
-                        break;
-                }
-                size = (i - pagenum) * PAGESIZE;
-            }
-            cached_size_key = p;
-            cached_size_val = size;
-        }
-        return size;
-    }
-
-
-    /**
-     *
-     */
-    BlkInfo getInfo(void* p)
-    {
-        Pool*   pool;
-        BlkInfo info;
-        
-        if (USE_CACHE && p == cached_info_key)
-            return cached_info_val;
-
-        pool = findPool(p);
-        if (pool)
-        {
-            size_t offset = cast(size_t)(p - pool.baseAddr);
-            size_t pn = offset / PAGESIZE;
-            Bins   bin = cast(Bins)pool.pagetable[pn];
-
-            ////////////////////////////////////////////////////////////////////
-            // findAddr
-            ////////////////////////////////////////////////////////////////////
-
-            if (bin <= B_PAGE)
-            {
-                info.base = pool.baseAddr + (offset & notbinsize[bin]);
-            }
-            else if (bin == B_PAGEPLUS)
-            {
-                do
-                {   --pn, offset -= PAGESIZE;
-                } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
-
-                info.base = pool.baseAddr + (offset & (offset.max ^ (PAGESIZE-1)));
-
-                // fix bin for use by size calc below
-                bin = cast(Bins)pool.pagetable[pn];
-            }
-
-            ////////////////////////////////////////////////////////////////////
-            // findSize
-            ////////////////////////////////////////////////////////////////////
-
-            info.size = binsize[bin];
-            if (bin == B_PAGE)
-            {   size_t npages = pool.ncommitted;
-                ubyte* pt;
-                size_t i;
-
-                pt = &pool.pagetable[0];
-                for (i = pn + 1; i < npages; i++)
-                {
-                    if (pt[i] != B_PAGEPLUS)
-                        break;
-                }
-                info.size = (i - pn) * PAGESIZE;
-            }
-
-            ////////////////////////////////////////////////////////////////////
-            // getBits
-            ////////////////////////////////////////////////////////////////////
-
-            info.attr = getBits(pool, cast(size_t)(offset / 16));
-            
-            cached_info_key = p;
-            cached_info_val = info;
-        }
-        return info;
-    }
-
-
-    /**
-     * Compute bin for size.
-     */
-    static Bins findBin(size_t size)
-    {   Bins bin;
-
-        if (size <= 256)
-        {
-            if (size <= 64)
-            {
-                if (size <= 16)
-                    bin = B_16;
-                else if (size <= 32)
-                    bin = B_32;
-                else
-                    bin = B_64;
-            }
-            else
-            {
-                if (size <= 128)
-                    bin = B_128;
-                else
-                    bin = B_256;
-            }
-        }
-        else
-        {
-            if (size <= 1024)
-            {
-                if (size <= 512)
-                    bin = B_512;
-                else
-                    bin = B_1024;
-            }
-            else
-            {
-                if (size <= 2048)
-                    bin = B_2048;
-                else
-                    bin = B_PAGE;
-            }
-        }
-        return bin;
-    }
-
-
-    /**
-     * Allocate a new pool of at least size bytes.
-     * Sort it into pooltable[].
-     * Mark all memory in the pool as B_FREE.
-     * Return the actual number of bytes reserved or 0 on error.
-     */
-    size_t reserve(size_t size)
-    {
-        size_t npages = (size + PAGESIZE - 1) / PAGESIZE;
-        Pool*  pool = newPool(npages);
-
-        if (!pool || pool.extendPages(npages) == OPFAIL)
-            return 0;
-        return pool.ncommitted * PAGESIZE;
-    }
-
-
-    /**
-     * Minimizes physical memory usage by returning free pools to the OS.
-     */
-    void minimize()
-    {
-        size_t n;
-        size_t pn;
-        Pool*  pool;
-        size_t ncommitted;
-
-        for (n = 0; n < npools; n++)
-        {
-            pool = pooltable[n];
-            ncommitted = pool.ncommitted;
-            for (pn = 0; pn < ncommitted; pn++)
-            {
-                if (cast(Bins)pool.pagetable[pn] != B_FREE)
-                    break;
-            }
-            if (pn < ncommitted)
-            {
-                n++;
-                continue;
-            }
-            pool.Dtor();
-            cstdlib.free(pool);
-            memmove(pooltable + n,
-                    pooltable + n + 1,
-                    (--npools - n) * (Pool*).sizeof);
-            minAddr = pooltable[0].baseAddr;
-            maxAddr = pooltable[npools - 1].topAddr;
-        }
-    }
-
-
-    /**
-     * Allocate a chunk of memory that is larger than a page.
-     * Return null if out of memory.
-     */
-    void *bigAlloc(size_t size)
-    {
-        Pool*  pool;
-        size_t npages;
-        size_t n;
-        size_t pn;
-        size_t freedpages;
-        void*  p;
-        int    state;
-        bool   collected = false;
-
-        npages = (size + PAGESIZE - 1) / PAGESIZE;
-
-        for (state = disabled ? 1 : 0; ; )
-        {
-            // This code could use some refinement when repeatedly
-            // allocating very large arrays.
-
-            for (n = 0; n < npools; n++)
-            {
-                pool = pooltable[n];
-                pn = pool.allocPages(npages);
-                if (pn != OPFAIL)
-                    goto L1;
-            }
-
-            // Failed
-            switch (state)
-            {
-            case 0:
-                // Try collecting
-                collected = true;
-                freedpages = fullcollectshell();
-                if (freedpages >= npools * ((POOLSIZE / PAGESIZE) / 4))
-                {   state = 1;
-                    continue;
-                }
-                // Release empty pools to prevent bloat
-                minimize();
-                // Allocate new pool
-                pool = newPool(npages);
-                if (!pool)
-                {   state = 2;
-                    continue;
-                }
-                pn = pool.allocPages(npages);
-                assert(pn != OPFAIL);
-                goto L1;
-            case 1:
-                // Release empty pools to prevent bloat
-                minimize();
-                // Allocate new pool
-                pool = newPool(npages);
-                if (!pool)
-                {
-                    if (collected)
-                        goto Lnomemory;
-                    state = 0;
-                    continue;
-                }
-                pn = pool.allocPages(npages);
-                assert(pn != OPFAIL);
-                goto L1;
-            case 2:
-                goto Lnomemory;
-            default:
-                assert(false);
-            }
-        }
-
-      L1:
-        pool.pagetable[pn] = B_PAGE;
-        if (npages > 1)
-            memset(&pool.pagetable[pn + 1], B_PAGEPLUS, npages - 1);
-        p = pool.baseAddr + pn * PAGESIZE;
-        memset(cast(char *)p + size, 0, npages * PAGESIZE - size);
-        debug (MEMSTOMP) memset(p, 0xF1, size);
-        //debug(PRINTF) printf("\tp = %x\n", p);
-        return p;
-
-      Lnomemory:
-        return null; // let caller handle the error
-    }
-
-
-    /**
-     * Allocate a new pool with at least npages in it.
-     * Sort it into pooltable[].
-     * Return null if failed.
-     */
-    Pool *newPool(size_t npages)
-    {
-        Pool*  pool;
-        Pool** newpooltable;
-        size_t newnpools;
-        size_t i;
-
-        //debug(PRINTF) printf("************Gcx::newPool(npages = %d)****************\n", npages);
-
-        // Round up to COMMITSIZE pages
-        npages = (npages + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1);
-
-        // Minimum of POOLSIZE
-        if (npages < POOLSIZE/PAGESIZE)
-            npages = POOLSIZE/PAGESIZE;
-        else if (npages > POOLSIZE/PAGESIZE)
-        {   // Give us 150% of requested size, so there's room to extend
-            auto n = npages + (npages >> 1);
-            if (n < size_t.max/PAGESIZE)
-                npages = n;
-        }
-
-        // Allocate successively larger pools up to 8 megs
-        if (npools)
-        {   size_t n;
-
-            n = npools;
-            if (n > 8)
-                n = 8;                  // cap pool size at 8 megs
-            n *= (POOLSIZE / PAGESIZE);
-            if (npages < n)
-                npages = n;
-        }
-
-        pool = cast(Pool *)cstdlib.calloc(1, Pool.sizeof);
-        if (pool)
-        {
-            pool.initialize(npages);
-            if (!pool.baseAddr)
-                goto Lerr;
-
-            newnpools = npools + 1;
-            newpooltable = cast(Pool **)cstdlib.realloc(pooltable, newnpools * (Pool *).sizeof);
-            if (!newpooltable)
-                goto Lerr;
-
-            // Sort pool into newpooltable[]
-            for (i = 0; i < npools; i++)
-            {
-                if (pool.opCmp(newpooltable[i]) < 0)
-                     break;
-            }
-            memmove(newpooltable + i + 1, newpooltable + i, (npools - i) * (Pool *).sizeof);
-            newpooltable[i] = pool;
-
-            pooltable = newpooltable;
-            npools = newnpools;
-
-            minAddr = pooltable[0].baseAddr;
-            maxAddr = pooltable[npools - 1].topAddr;
-        }
-        return pool;
-
-      Lerr:
-        pool.Dtor();
-        cstdlib.free(pool);
-        return null;
-    }
-
-
-    /**
-     * Allocate a page of bin's.
-     * Returns:
-     *  0       failed
-     */
-    int allocPage(Bins bin)
-    {
-        Pool*  pool;
-        size_t n;
-        size_t pn;
-        byte*  p;
-        byte*  ptop;
-
-        //debug(PRINTF) printf("Gcx::allocPage(bin = %d)\n", bin);
-        for (n = 0; n < npools; n++)
-        {
-            pool = pooltable[n];
-            pn = pool.allocPages(1);
-            if (pn != OPFAIL)
-                goto L1;
-        }
-        return 0;               // failed
-
-      L1:
-        pool.pagetable[pn] = cast(ubyte)bin;
-
-        // Convert page to free list
-        size_t size = binsize[bin];
-        List **b = &bucket[bin];
-
-        p = pool.baseAddr + pn * PAGESIZE;
-        ptop = p + PAGESIZE;
-        for (; p < ptop; p += size)
-        {
-            (cast(List *)p).next = *b;
-            *b = cast(List *)p;
-        }
-        return 1;
-    }
-
-
-    /**
-     * Search a range of memory values and mark any pointers into the GC pool.
-     */
-    void mark(void *pbot, void *ptop)
-    {
-        void **p1 = cast(void **)pbot;
-        void **p2 = cast(void **)ptop;
-        size_t pcache = 0;
-        uint changes = 0;
-
-        //printf("marking range: %p -> %p\n", pbot, ptop);
-        for (; p1 < p2; p1++)
-        {
-            Pool *pool;
-            byte *p = cast(byte *)(*p1);
-
-            //if (log) debug(PRINTF) printf("\tmark %x\n", p);
-            if (p >= minAddr && p < maxAddr)
-            {
-                if ((cast(size_t)p & ~(PAGESIZE-1)) == pcache)
-                    continue;
-
-                pool = findPool(p);
-                if (pool)
-                {
-                    size_t offset = cast(size_t)(p - pool.baseAddr);
-                    size_t biti;
-                    size_t pn = offset / PAGESIZE;
-                    Bins   bin = cast(Bins)pool.pagetable[pn];
-
-                    //debug(PRINTF) printf("\t\tfound pool %x, base=%x, pn = %d, bin = %d, biti = x%x\n", pool, pool.baseAddr, pn, bin, biti);
-
-                    // Adjust bit to be at start of allocated memory block
-                    if (bin <= B_PAGE)
-                    {
-                        biti = (offset & notbinsize[bin]) >> 4;
-                        //debug(PRINTF) printf("\t\tbiti = x%x\n", biti);
-                    }
-                    else if (bin == B_PAGEPLUS)
-                    {
-                        do
-                        {   --pn;
-                        } while (cast(Bins)pool.pagetable[pn] == B_PAGEPLUS);
-                        biti = pn * (PAGESIZE / 16);
-                    }
-                    else
-                    {
-                        // Don't mark bits in B_FREE or B_UNCOMMITTED pages
-                        continue;
-                    }
-
-                    if (bin >= B_PAGE) // Cache B_PAGE and B_PAGEPLUS lookups
-                        pcache = cast(size_t)p & ~(PAGESIZE-1);
-
-                    //debug(PRINTF) printf("\t\tmark(x%x) = %d\n", biti, pool.mark.test(biti));
-                    if (!pool.mark.test(biti))
-                    {
-                        //if (log) debug(PRINTF) printf("\t\tmarking %x\n", p);
-                        pool.mark.set(biti);
-                        if (!pool.noscan.test(biti))
-                        {
-                            pool.scan.set(biti);
-                            changes = 1;
-                        }
-                        log_parent(sentinel_add(pool.baseAddr + biti * 16), sentinel_add(pbot));
-                    }
-                }
-            }
-        }
-        anychanges |= changes;
-    }
-
-
-    /**
-     * Return number of full pages free'd.
-     */
-    size_t fullcollectshell()
-    {
-        // The purpose of the 'shell' is to ensure all the registers
-        // get put on the stack so they'll be scanned
-        void *sp;
-        size_t result;
-        version (GNU)
-        {
-            __builtin_unwind_init();
-            sp = & sp;
-        }
-        else
-        {
-        asm
-        {
-            pushad              ;
-            mov sp[EBP],ESP     ;
-        }
-        }
-        result = fullcollect(sp);
-        version (GNU)
-        {
-            // nothing to do
-        }
-        else
-        {
-        asm
-        {
-            popad               ;
-        }
-        }
-        return result;
-    }
-
-
-    /**
-     *
-     */
-    size_t fullcollect(void *stackTop)
-    {
-        size_t n;
-        Pool*  pool;
-
-        debug(COLLECT_PRINTF) printf("Gcx.fullcollect()\n");
-
-        thread_suspendAll();
-
-        cached_size_key = cached_size_key.init;
-        cached_size_val = cached_size_val.init;
-        cached_info_key = cached_info_key.init;
-        cached_info_val = cached_info_val.init;
-
-        anychanges = 0;
-        for (n = 0; n < npools; n++)
-        {
-            pool = pooltable[n];
-            pool.mark.zero();
-            pool.scan.zero();
-            pool.freebits.zero();
-        }
-
-        // Mark each free entry, so it doesn't get scanned
-        for (n = 0; n < B_PAGE; n++)
-        {
-            for (List *list = bucket[n]; list; list = list.next)
-            {
-                pool = findPool(list);
-                assert(pool);
-                pool.freebits.set(cast(size_t)(cast(byte*)list - pool.baseAddr) / 16);
-            }
-        }
-
-        for (n = 0; n < npools; n++)
-        {
-            pool = pooltable[n];
-            pool.mark.copy(&pool.freebits);
-        }
-
-        version (MULTI_THREADED)
-        {
-            if (!noStack)
-            {
-                // Scan stacks and registers for each paused thread
-                thread_scanAll( &mark, stackTop );
-            }
-        }
-        else
-        {
-            if (!noStack)
-            {
-                // Scan stack for main thread
-                debug(PRINTF) printf(" scan stack bot = %x, top = %x\n", stackTop, stackBottom);
-                version (STACKGROWSDOWN)
-                    mark(stackTop, stackBottom);
-                else
-                    mark(stackBottom, stackTop);
-            }
-        }
-
-        // Scan roots[]
-        debug(COLLECT_PRINTF) printf("scan roots[]\n");
-        mark(roots, roots + nroots);
-
-        // Scan ranges[]
-        debug(COLLECT_PRINTF) printf("scan ranges[]\n");
-        //log++;
-        for (n = 0; n < nranges; n++)
-        {
-            debug(COLLECT_PRINTF) printf("\t%x .. %x\n", ranges[n].pbot, ranges[n].ptop);
-            mark(ranges[n].pbot, ranges[n].ptop);
-        }
-        //log--;
-
-        debug(COLLECT_PRINTF) printf("\tscan heap\n");
-        while (anychanges)
-        {
-            anychanges = 0;
-            for (n = 0; n < npools; n++)
-            {
-                uint *bbase;
-                uint *b;
-                uint *btop;
-
-                pool = pooltable[n];
-
-                bbase = pool.scan.base();
-                btop = bbase + pool.scan.nwords;
-                for (b = bbase; b < btop;)
-                {   Bins   bin;
-                    size_t pn;
-                    size_t u;
-                    size_t bitm;
-                    byte*  o;
-
-                    bitm = *b;
-                    if (!bitm)
-                    {   b++;
-                        continue;
-                    }
-                    *b = 0;
-
-                    o = pool.baseAddr + (b - bbase) * 32 * 16;
-                    if (!(bitm & 0xFFFF))
-                    {
-                        bitm >>= 16;
-                        o += 16 * 16;
-                    }
-                    for (; bitm; o += 16, bitm >>= 1)
-                    {
-                        if (!(bitm & 1))
-                            continue;
-
-                        pn = cast(size_t)(o - pool.baseAddr) / PAGESIZE;
-                        bin = cast(Bins)pool.pagetable[pn];
-                        if (bin < B_PAGE)
-                        {
-                            mark(o, o + binsize[bin]);
-                        }
-                        else if (bin == B_PAGE || bin == B_PAGEPLUS)
-                        {
-                            if (bin == B_PAGEPLUS)
-                            {
-                                while (pool.pagetable[pn - 1] != B_PAGE)
-                                    pn--;
-                            }
-                            u = 1;
-                            while (pn + u < pool.ncommitted && pool.pagetable[pn + u] == B_PAGEPLUS)
-                                u++;
-                            mark(o, o + u * PAGESIZE);
-                        }
-                    }
-                }
-            }
-        }
-
-        thread_resumeAll();
-
-        // Free up everything not marked
-        debug(COLLECT_PRINTF) printf("\tfree'ing\n");
-        size_t freedpages = 0;
-        size_t freed = 0;
-        for (n = 0; n < npools; n++)
-        {   size_t pn;
-            size_t ncommitted;
-            uint*  bbase;
-
-            pool = pooltable[n];
-            bbase = pool.mark.base();
-            ncommitted = pool.ncommitted;
-            for (pn = 0; pn < ncommitted; pn++, bbase += PAGESIZE / (32 * 16))
-            {
-                Bins bin = cast(Bins)pool.pagetable[pn];
-
-                if (bin < B_PAGE)
-                {   byte* p;
-                    byte* ptop;
-                    size_t biti;
-                    size_t bitstride;
-                    auto   size = binsize[bin];
-
-                    p = pool.baseAddr + pn * PAGESIZE;
-                    ptop = p + PAGESIZE;
-                    biti = pn * (PAGESIZE/16);
-                    bitstride = size / 16;
-
-    version(none) // BUG: doesn't work because freebits() must also be cleared
-    {
-                    // If free'd entire page
-                    if (bbase[0] == 0 && bbase[1] == 0 && bbase[2] == 0 && bbase[3] == 0 &&
-                        bbase[4] == 0 && bbase[5] == 0 && bbase[6] == 0 && bbase[7] == 0)
-                    {
-                        for (; p < ptop; p += size, biti += bitstride)
-                        {
-                            if (pool.finals.nbits && pool.finals.testClear(biti))
-                                rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/);
-                            gcx.clrBits(pool, biti, BlkAttr.ALL_BITS);
-
-                            List *list = cast(List *)p;
-                            //debug(PRINTF) printf("\tcollecting %x\n", list);
-                            log_free(sentinel_add(list));
-
-                            debug (MEMSTOMP) memset(p, 0xF3, size);
-                        }
-                        pool.pagetable[pn] = B_FREE;
-                        freed += PAGESIZE;
-                        //debug(PRINTF) printf("freeing entire page %d\n", pn);
-                        continue;
-                    }
-    }
-                    for (; p < ptop; p += size, biti += bitstride)
-                    {
-                        if (!pool.mark.test(biti))
-                        {
-                            sentinel_Invariant(sentinel_add(p));
-
-                            pool.freebits.set(biti);
-                            if (pool.finals.nbits && pool.finals.testClear(biti))
-                                rt_finalize(cast(List *)sentinel_add(p), false/*noStack > 0*/);
-                            clrBits(pool, biti, BlkAttr.ALL_BITS);
-
-                            List *list = cast(List *)p;
-                            debug(PRINTF) printf("\tcollecting %x\n", list);
-                            log_free(sentinel_add(list));
-
-                            debug (MEMSTOMP) memset(p, 0xF3, size);
-
-                            freed += size;
-                        }
-                    }
-                }
-                else if (bin == B_PAGE)
-                {   size_t biti = pn * (PAGESIZE / 16);
-
-                    if (!pool.mark.test(biti))
-                    {   byte *p = pool.baseAddr + pn * PAGESIZE;
-
-                        sentinel_Invariant(sentinel_add(p));
-                        if (pool.finals.nbits && pool.finals.testClear(biti))
-                            rt_finalize(sentinel_add(p), false/*noStack > 0*/);
-                        clrBits(pool, biti, BlkAttr.ALL_BITS);
-
-                        debug(COLLECT_PRINTF) printf("\tcollecting big %x\n", p);
-                        log_free(sentinel_add(p));
-                        pool.pagetable[pn] = B_FREE;
-                        freedpages++;
-                        debug (MEMSTOMP) memset(p, 0xF3, PAGESIZE);
-                        while (pn + 1 < ncommitted && pool.pagetable[pn + 1] == B_PAGEPLUS)
-                        {
-                            pn++;
-                            pool.pagetable[pn] = B_FREE;
-                            freedpages++;
-
-                            debug (MEMSTOMP)
-                            {   p += PAGESIZE;
-                                memset(p, 0xF3, PAGESIZE);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-
-        // Zero buckets
-        bucket[] = null;
-
-        // Free complete pages, rebuild free list
-        debug(COLLECT_PRINTF) printf("\tfree complete pages\n");
-        size_t recoveredpages = 0;
-        for (n = 0; n < npools; n++)
-        {   size_t pn;
-            size_t ncommitted;
-
-            pool = pooltable[n];
-            ncommitted = pool.ncommitted;
-            for (pn = 0; pn < ncommitted; pn++)
-            {
-                Bins   bin = cast(Bins)pool.pagetable[pn];
-                size_t biti;
-                size_t u;
-
-                if (bin < B_PAGE)
-                {
-                    size_t size = binsize[bin];
-                    size_t bitstride = size / 16;
-                    size_t bitbase = pn * (PAGESIZE / 16);
-                    size_t bittop = bitbase + (PAGESIZE / 16);
-                    byte*  p;
-
-                    biti = bitbase;
-                    for (biti = bitbase; biti < bittop; biti += bitstride)
-                    {   if (!pool.freebits.test(biti))
-                            goto Lnotfree;
-                    }
-                    pool.pagetable[pn] = B_FREE;
-                    recoveredpages++;
-                    continue;
-
-                 Lnotfree:
-                    p = pool.baseAddr + pn * PAGESIZE;
-                    for (u = 0; u < PAGESIZE; u += size)
-                    {   biti = bitbase + u / 16;
-                        if (pool.freebits.test(biti))
-                        {   List *list;
-
-                            list = cast(List *)(p + u);
-                            if (list.next != bucket[bin])       // avoid unnecessary writes
-                                list.next = bucket[bin];
-                            bucket[bin] = list;
-                        }
-                    }
-                }
-            }
-        }
-
-        debug(COLLECT_PRINTF) printf("recovered pages = %d\n", recoveredpages);
-        debug(COLLECT_PRINTF) printf("\tfree'd %u bytes, %u pages from %u pools\n", freed, freedpages, npools);
-
-        return freedpages + recoveredpages;
-    }
-
-
-    /**
-     *
-     */
-    uint getBits(Pool* pool, size_t biti)
-    in
-    {
-        assert( pool );
-    }
-    body
-    {
-        uint bits;
-
-        if (pool.finals.nbits &&
-            pool.finals.test(biti))
-            bits |= BlkAttr.FINALIZE;
-        if (pool.noscan.test(biti))
-            bits |= BlkAttr.NO_SCAN;
-//        if (pool.nomove.nbits &&
-//            pool.nomove.test(biti))
-//            bits |= BlkAttr.NO_MOVE;
-        return bits;
-    }
-
-
-    /**
-     *
-     */
-    void setBits(Pool* pool, size_t biti, uint mask)
-    in
-    {
-        assert( pool );
-    }
-    body
-    {
-        if (mask & BlkAttr.FINALIZE)
-        {
-            if (!pool.finals.nbits)
-                pool.finals.alloc(pool.mark.nbits);
-            pool.finals.set(biti);
-        }
-        if (mask & BlkAttr.NO_SCAN)
-        {
-            pool.noscan.set(biti);
-        }
-//        if (mask & BlkAttr.NO_MOVE)
-//        {
-//            if (!pool.nomove.nbits)
-//                pool.nomove.alloc(pool.mark.nbits);
-//            pool.nomove.set(biti);
-//        }
-    }
-
-
-    /**
-     *
-     */
-    void clrBits(Pool* pool, size_t biti, uint mask)
-    in
-    {
-        assert( pool );
-    }
-    body
-    {
-        if (mask & BlkAttr.FINALIZE && pool.finals.nbits)
-            pool.finals.clear(biti);
-        if (mask & BlkAttr.NO_SCAN)
-            pool.noscan.clear(biti);
-//        if (mask & BlkAttr.NO_MOVE && pool.nomove.nbits)
-//            pool.nomove.clear(biti);
-    }
-
-
-    /***** Leak Detector ******/
-
-
-    debug (LOGGING)
-    {
-        LogArray current;
-        LogArray prev;
-
-
-        void log_init()
-        {
-            //debug(PRINTF) printf("+log_init()\n");
-            current.reserve(1000);
-            prev.reserve(1000);
-            //debug(PRINTF) printf("-log_init()\n");
-        }
-
-
-        void log_malloc(void *p, size_t size)
-        {
-            //debug(PRINTF) printf("+log_malloc(p = %x, size = %d)\n", p, size);
-            Log log;
-
-            log.p = p;
-            log.size = size;
-            log.line = GC.line;
-            log.file = GC.file;
-            log.parent = null;
-
-            GC.line = 0;
-            GC.file = null;
-
-            current.push(log);
-            //debug(PRINTF) printf("-log_malloc()\n");
-        }
-
-
-        void log_free(void *p)
-        {
-            //debug(PRINTF) printf("+log_free(%x)\n", p);
-            size_t i;
-
-            i = current.find(p);
-            if (i == OPFAIL)
-            {
-                debug(PRINTF) printf("free'ing unallocated memory %x\n", p);
-            }
-            else
-                current.remove(i);
-            //debug(PRINTF) printf("-log_free()\n");
-        }
-
-
-        void log_collect()
-        {
-            //debug(PRINTF) printf("+log_collect()\n");
-            // Print everything in current that is not in prev
-
-            debug(PRINTF) printf("New pointers this cycle: --------------------------------\n");
-            size_t used = 0;
-            for (size_t i = 0; i < current.dim; i++)
-            {
-                size_t j;
-
-                j = prev.find(current.data[i].p);
-                if (j == OPFAIL)
-                    current.data[i].print();
-                else
-                    used++;
-            }
-
-            debug(PRINTF) printf("All roots this cycle: --------------------------------\n");
-            for (size_t i = 0; i < current.dim; i++)
-            {
-                void *p;
-                size_t j;
-
-                p = current.data[i].p;
-                if (!findPool(current.data[i].parent))
-                {
-                    j = prev.find(current.data[i].p);
-                    if (j == OPFAIL)
-                        debug(PRINTF) printf("N");
-                    else
-                        debug(PRINTF) printf(" ");;
-                    current.data[i].print();
-                }
-            }
-
-            debug(PRINTF) printf("Used = %d-------------------------------------------------\n", used);
-            prev.copy(&current);
-
-            debug(PRINTF) printf("-log_collect()\n");
-        }
-
-
-        void log_parent(void *p, void *parent)
-        {
-            //debug(PRINTF) printf("+log_parent()\n");
-            size_t i;
-
-            i = current.find(p);
-            if (i == OPFAIL)
-            {
-                debug(PRINTF) printf("parent'ing unallocated memory %x, parent = %x\n", p, parent);
-                Pool *pool;
-                pool = findPool(p);
-                assert(pool);
-                size_t offset = cast(size_t)(p - pool.baseAddr);
-                size_t biti;
-                size_t pn = offset / PAGESIZE;
-                Bins bin = cast(Bins)pool.pagetable[pn];
-                biti = (offset & notbinsize[bin]);
-                debug(PRINTF) printf("\tbin = %d, offset = x%x, biti = x%x\n", bin, offset, biti);
-            }
-            else
-            {
-                current.data[i].parent = parent;
-            }
-            //debug(PRINTF) printf("-log_parent()\n");
-        }
-
-    }
-    else
-    {
-        void log_init() { }
-        void log_malloc(void *p, size_t size) { }
-        void log_free(void *p) { }
-        void log_collect() { }
-        void log_parent(void *p, void *parent) { }
-    }
-}
-
-
-/* ============================ Pool  =============================== */
-
-
-struct Pool
-{
-    byte* baseAddr;
-    byte* topAddr;
-    GCBits mark;        // entries already scanned, or should not be scanned
-    GCBits scan;        // entries that need to be scanned
-    GCBits freebits;    // entries that are on the free list
-    GCBits finals;      // entries that need finalizer run on them
-    GCBits noscan;      // entries that should not be scanned
-
-    size_t npages;
-    size_t ncommitted;    // ncommitted <= npages
-    ubyte* pagetable;
-
-
-    void initialize(size_t npages)
-    {
-        size_t poolsize;
-
-        //debug(PRINTF) printf("Pool::Pool(%u)\n", npages);
-        poolsize = npages * PAGESIZE;
-        assert(poolsize >= POOLSIZE);
-        baseAddr = cast(byte *)os_mem_map(poolsize);
-
-        // Some of the code depends on page alignment of memory pools
-        assert((cast(size_t)baseAddr & (PAGESIZE - 1)) == 0);
-
-        if (!baseAddr)
-        {
-            //debug(PRINTF) printf("GC fail: poolsize = x%x, errno = %d\n", poolsize, errno);
-            //debug(PRINTF) printf("message = '%s'\n", sys_errlist[errno]);
-
-            npages = 0;
-            poolsize = 0;
-        }
-        //assert(baseAddr);
-        topAddr = baseAddr + poolsize;
-
-        mark.alloc(cast(size_t)poolsize / 16);
-        scan.alloc(cast(size_t)poolsize / 16);
-        freebits.alloc(cast(size_t)poolsize / 16);
-        noscan.alloc(cast(size_t)poolsize / 16);
-
-        pagetable = cast(ubyte*)cstdlib.malloc(npages);
-        if (!pagetable)
-            onOutOfMemoryError();
-        memset(pagetable, B_UNCOMMITTED, npages);
-
-        this.npages = npages;
-        ncommitted = 0;
-    }
-
-
-    void Dtor()
-    {
-        if (baseAddr)
-        {
-            int result;
-
-            if (ncommitted)
-            {
-                result = os_mem_decommit(baseAddr, 0, ncommitted * PAGESIZE);
-                assert(result == 0);
-                ncommitted = 0;
-            }
-
-            if (npages)
-            {
-                result = os_mem_unmap(baseAddr, npages * PAGESIZE);
-                assert(result == 0);
-                npages = 0;
-            }
-
-            baseAddr = null;
-            topAddr = null;
-        }
-        if (pagetable)
-            cstdlib.free(pagetable);
-
-        mark.Dtor();
-        scan.Dtor();
-        freebits.Dtor();
-        finals.Dtor();
-        noscan.Dtor();
-    }
-
-
-    void Invariant() { }
-
-
-    invariant()
-    {
-        //mark.Invariant();
-        //scan.Invariant();
-        //freebits.Invariant();
-        //finals.Invariant();
-        //noscan.Invariant();
-
-        if (baseAddr)
-        {
-            //if (baseAddr + npages * PAGESIZE != topAddr)
-                //printf("baseAddr = %p, npages = %d, topAddr = %p\n", baseAddr, npages, topAddr);
-            assert(baseAddr + npages * PAGESIZE == topAddr);
-            assert(ncommitted <= npages);
-        }
-
-        for (size_t i = 0; i < npages; i++)
-        {   Bins bin = cast(Bins)pagetable[i];
-
-            assert(bin < B_MAX);
-        }
-    }
-
-
-    /**
-     * Allocate n pages from Pool.
-     * Returns OPFAIL on failure.
-     */
-    size_t allocPages(size_t n)
-    {
-        size_t i;
-        size_t n2;
-
-        //debug(PRINTF) printf("Pool::allocPages(n = %d)\n", n);
-        n2 = n;
-        for (i = 0; i < ncommitted; i++)
-        {
-            if (pagetable[i] == B_FREE)
-            {
-                if (--n2 == 0)
-                {   //debug(PRINTF) printf("\texisting pn = %d\n", i - n + 1);
-                    return i - n + 1;
-                }
-            }
-            else
-                n2 = n;
-        }
-        return extendPages(n);
-    }
-
-    /**
-     * Extend Pool by n pages.
-     * Returns OPFAIL on failure.
-     */
-    size_t extendPages(size_t n)
-    {
-        //debug(PRINTF) printf("Pool::extendPages(n = %d)\n", n);
-        if (ncommitted + n <= npages)
-        {
-            size_t tocommit;
-
-            tocommit = (n + (COMMITSIZE/PAGESIZE) - 1) & ~(COMMITSIZE/PAGESIZE - 1);
-            if (ncommitted + tocommit > npages)
-                tocommit = npages - ncommitted;
-            //debug(PRINTF) printf("\tlooking to commit %d more pages\n", tocommit);
-            //fflush(stdout);
-            if (os_mem_commit(baseAddr, ncommitted * PAGESIZE, tocommit * PAGESIZE) == 0)
-            {
-                memset(pagetable + ncommitted, B_FREE, tocommit);
-                auto i = ncommitted;
-                ncommitted += tocommit;
-
-                while (i && pagetable[i - 1] == B_FREE)
-                    i--;
-
-                return i;
-            }
-            //debug(PRINTF) printf("\tfailed to commit %d pages\n", tocommit);
-        }
-
-        return OPFAIL;
-    }
-
-
-    /**
-     * Free npages pages starting with pagenum.
-     */
-    void freePages(size_t pagenum, size_t npages)
-    {
-        memset(&pagetable[pagenum], B_FREE, npages);
-    }
-
-
-    /**
-     * Used for sorting pooltable[]
-     */
-    int opCmp(Pool *p2)
-    {
-        if (baseAddr < p2.baseAddr)
-            return -1;
-        else
-        return cast(int)(baseAddr > p2.baseAddr);
-    }
-}
-
-
-/* ============================ SENTINEL =============================== */
-
-
-version (SENTINEL)
-{
-    const size_t SENTINEL_PRE = cast(size_t) 0xF4F4F4F4F4F4F4F4UL; // 32 or 64 bits
-    const ubyte SENTINEL_POST = 0xF5;           // 8 bits
-    const uint SENTINEL_EXTRA = 2 * size_t.sizeof + 1;
-
-
-    size_t* sentinel_size(void *p)  { return &(cast(size_t *)p)[-2]; }
-    size_t* sentinel_pre(void *p)   { return &(cast(size_t *)p)[-1]; }
-    ubyte* sentinel_post(void *p) { return &(cast(ubyte *)p)[*sentinel_size(p)]; }
-
-
-    void sentinel_init(void *p, size_t size)
-    {
-        *sentinel_size(p) = size;
-        *sentinel_pre(p) = SENTINEL_PRE;
-        *sentinel_post(p) = SENTINEL_POST;
-    }
-
-
-    void sentinel_Invariant(void *p)
-    {
-        assert(*sentinel_pre(p) == SENTINEL_PRE);
-        assert(*sentinel_post(p) == SENTINEL_POST);
-    }
-
-
-    void *sentinel_add(void *p)
-    {
-        return p + 2 * size_t.sizeof;
-    }
-
-
-    void *sentinel_sub(void *p)
-    {
-        return p - 2 * size_t.sizeof;
-    }
-}
-else
-{
-    const uint SENTINEL_EXTRA = 0;
-
-
-    void sentinel_init(void *p, size_t size)
-    {
-    }
-
-
-    void sentinel_Invariant(void *p)
-    {
-    }
-
-
-    void *sentinel_add(void *p)
-    {
-        return p;
-    }
-
-
-    void *sentinel_sub(void *p)
-    {
-        return p;
-    }
-}
Index: src/gc/basic/gcalloc.d
===================================================================
--- src/gc/basic/gcalloc.d	(revision 166)
+++ src/gc/basic/gcalloc.d	(working copy)
@@ -1,201 +0,0 @@
-/**
- * Contains OS-level allocation routines.
- *
- * Copyright: Copyright Digital Mars 2005 - 2009.
- * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
- * Authors:   Walter Bright, David Friedman, Sean Kelly
- *
- *          Copyright Digital Mars 2005 - 2009.
- * Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- */
-module gc.gcalloc;
-
-
-version (Windows)
-{
-    private import core.sys.windows.windows;
-
-    alias int pthread_t;
-
-    pthread_t pthread_self()
-    {
-        return cast(pthread_t) GetCurrentThreadId();
-    }
-
-    //version = GC_Use_Alloc_Win32;
-}
-else version (Posix)
-{
-    private import core.sys.posix.sys.mman;
-    private import core.stdc.stdlib;
-
-    //version = GC_Use_Alloc_MMap;
-}
-else
-{
-    private import core.stdc.stdlib;
-
-    //version = GC_Use_Alloc_Malloc;
-}
-
-/+
-static if(is(typeof(VirtualAlloc)))
-    version = GC_Use_Alloc_Win32;
-else static if (is(typeof(mmap)))
-    version = GC_Use_Alloc_MMap;
-else static if (is(typeof(valloc)))
-    version = GC_Use_Alloc_Valloc;
-else static if (is(typeof(malloc)))
-    version = GC_Use_Alloc_Malloc;
-else static assert(false, "No supported allocation methods available.");
-+/
-
-static if (is(typeof(VirtualAlloc))) // version (GC_Use_Alloc_Win32)
-{
-    /**
-     * Map memory.
-     */
-    void *os_mem_map(size_t nbytes)
-    {
-        return VirtualAlloc(null, nbytes, MEM_RESERVE, PAGE_READWRITE);
-    }
-
-
-    /**
-     * Commit memory.
-     * Returns:
-     *      0       success
-     *      !=0     failure
-     */
-    int os_mem_commit(void *base, size_t offset, size_t nbytes)
-    {   void *p;
-
-        p = VirtualAlloc(base + offset, nbytes, MEM_COMMIT, PAGE_READWRITE);
-    return cast(int)(p is null);
-    }
-
-
-    /**
-     * Decommit memory.
-     * Returns:
-     *      0       success
-     *      !=0     failure
-     */
-    int os_mem_decommit(void *base, size_t offset, size_t nbytes)
-    {
-    return cast(int)(VirtualFree(base + offset, nbytes, MEM_DECOMMIT) == 0);
-    }
-
-
-    /**
-     * Unmap memory allocated with os_mem_map().
-     * Memory must have already been decommitted.
-     * Returns:
-     *      0       success
-     *      !=0     failure
-     */
-    int os_mem_unmap(void *base, size_t nbytes)
-    {
-        return cast(int)(VirtualFree(base, 0, MEM_RELEASE) == 0);
-    }
-}
-else static if (is(typeof(mmap)))  // else version (GC_Use_Alloc_MMap)
-{
-    void *os_mem_map(size_t nbytes)
-    {   void *p;
-
-        p = mmap(null, nbytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
-        return (p == MAP_FAILED) ? null : p;
-    }
-
-
-    int os_mem_commit(void *base, size_t offset, size_t nbytes)
-    {
-        return 0;
-    }
-
-
-    int os_mem_decommit(void *base, size_t offset, size_t nbytes)
-    {
-        return 0;
-    }
-
-
-    int os_mem_unmap(void *base, size_t nbytes)
-    {
-        return munmap(base, nbytes);
-    }
-}
-else static if (is(typeof(valloc))) // else version (GC_Use_Alloc_Valloc)
-{
-    void *os_mem_map(size_t nbytes)
-    {
-        return valloc(nbytes);
-    }
-
-
-    int os_mem_commit(void *base, size_t offset, size_t nbytes)
-    {
-        return 0;
-    }
-
-
-    int os_mem_decommit(void *base, size_t offset, size_t nbytes)
-    {
-        return 0;
-    }
-
-
-    int os_mem_unmap(void *base, size_t nbytes)
-    {
-        free(base);
-        return 0;
-    }
-}
-else static if (is(typeof(malloc))) // else version (GC_Use_Alloc_Malloc)
-{
-    // NOTE: This assumes malloc granularity is at least (void*).sizeof.  If
-    //       (req_size + PAGESIZE) is allocated, and the pointer is rounded up
-    //       to PAGESIZE alignment, there will be space for a void* at the end
-    //       after PAGESIZE bytes used by the GC.
-
-
-    private import gcx : PAGESIZE;
-
-
-    const size_t PAGE_MASK = PAGESIZE - 1;
-
-
-    void *os_mem_map(size_t nbytes)
-    {   byte *p, q;
-        p = cast(byte *) malloc(nbytes + PAGESIZE);
-        q = p + ((PAGESIZE - ((cast(size_t) p & PAGE_MASK))) & PAGE_MASK);
-        * cast(void**)(q + nbytes) = p;
-        return q;
-    }
-
-
-    int os_mem_commit(void *base, size_t offset, size_t nbytes)
-    {
-        return 0;
-    }
-
-
-    int os_mem_decommit(void *base, size_t offset, size_t nbytes)
-    {
-        return 0;
-    }
-
-
-    int os_mem_unmap(void *base, size_t nbytes)
-    {
-        free( *cast(void**)( cast(byte*) base + nbytes ) );
-        return 0;
-    }
-}
-else
-{
-    static assert(false, "No supported allocation methods available.");
-}
Index: src/gc/basic/gc/gcx.d
===================================================================
--- src/gc/basic/gc/gcx.d	(revision 0)
+++ src/gc/basic/gc/gcx.d	(working copy)
@@ -2217,6 +2217,51 @@
             __builtin_unwind_init();
             sp = & sp;
         }
+        else version(LDC)
+        {
+            version(X86)
+            {
+                uint eax,ecx,edx,ebx,ebp,esi,edi;
+                asm
+                {
+                    mov eax[EBP], EAX      ;
+                    mov ecx[EBP], ECX      ;
+                    mov edx[EBP], EDX      ;
+                    mov ebx[EBP], EBX      ;
+                    mov ebp[EBP], EBP      ;
+                    mov esi[EBP], ESI      ;
+                    mov edi[EBP], EDI      ;
+                    mov sp[EBP],ESP     ;
+                }
+            }
+            else version (X86_64)
+            {
+                ulong rax,rbx,rcx,rdx,rbp,rsi,rdi,rsp,r8,r9,r10,r11,r12,r13,r14,r15;
+                asm
+                {
+                    movq rax[RBP], RAX      ;
+                    movq rbx[RBP], RBX      ;
+                    movq rcx[RBP], RCX      ;
+                    movq rdx[RBP], RDX      ;
+                    movq rbp[RBP], RBP      ;
+                    movq rsi[RBP], RSI      ;
+                    movq rdi[RBP], RDI      ;
+                    movq rsp[RBP], RSP      ;
+                    movq  r8[RBP], R8       ;
+                    movq  r9[RBP], R9       ;
+                    movq r10[RBP], R10      ;
+                    movq r11[RBP], R11      ;
+                    movq r12[RBP], R12      ;
+                    movq r13[RBP], R13      ;
+                    movq r14[RBP], R14      ;
+                    movq r15[RBP], R15      ;
+                }
+            }
+            else
+            {
+                static assert( false, "Architecture not supported." );
+            }
+        }
         else
         {
         asm
@@ -2230,6 +2275,10 @@
         {
             // nothing to do
         }
+	else version (LDC)
+	{
+	    // Nothing to do
+	}
         else
         {
         asm
Index: src/gc/basic/gcstats.d
===================================================================
--- src/gc/basic/gcstats.d	(revision 166)
+++ src/gc/basic/gcstats.d	(working copy)
@@ -1,26 +0,0 @@
-/**
- * Contains a struct for storing GC statistics.
- *
- * Copyright: Copyright Digital Mars 2005 - 2009.
- * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
- * Authors:   Walter Bright, Sean Kelly
- *
- *          Copyright Digital Mars 2005 - 2009.
- * Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- */
-module gc.gcstats;
-
-
-/**
- *
- */
-struct GCStats
-{
-    size_t poolsize;        // total size of pool
-    size_t usedsize;        // bytes allocated
-    size_t freeblocks;      // number of blocks marked FREE
-    size_t freelistsize;    // total of memory on free lists
-    size_t pageblocks;      // number of blocks marked PAGE
-}
Index: src/gc/basic/gc.d
===================================================================
--- src/gc/basic/gc.d	(revision 166)
+++ src/gc/basic/gc.d	(working copy)
@@ -1,315 +0,0 @@
-/**
- * Contains the external GC interface.
- *
- * Copyright: Copyright Digital Mars 2005 - 2009.
- * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
- * Authors:   Walter Bright, Sean Kelly
- *
- *          Copyright Digital Mars 2005 - 2009.
- * Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- */
-module gc.gc;
-
-private
-{
-    import gc.gcx;
-    import gc.gcstats;
-    import core.stdc.stdlib;
-
-    version = GCCLASS;
-
-    version( GCCLASS )
-        alias GC gc_t;
-    else
-        alias GC* gc_t;
-
-    __gshared gc_t _gc;
-
-    extern (C) void thread_init();
-
-    struct Proxy
-    {
-        extern (C) void function() gc_enable;
-        extern (C) void function() gc_disable;
-        extern (C) void function() gc_collect;
-        extern (C) void function() gc_minimize;
-
-        extern (C) uint function(void*) gc_getAttr;
-        extern (C) uint function(void*, uint) gc_setAttr;
-        extern (C) uint function(void*, uint) gc_clrAttr;
-
-        extern (C) void*  function(size_t, uint) gc_malloc;
-        extern (C) void*  function(size_t, uint) gc_calloc;
-        extern (C) void*  function(void*, size_t, uint ba) gc_realloc;
-        extern (C) size_t function(void*, size_t, size_t) gc_extend;
-        extern (C) size_t function(size_t) gc_reserve;
-        extern (C) void   function(void*) gc_free;
-
-        extern (C) void*   function(void*) gc_addrOf;
-        extern (C) size_t  function(void*) gc_sizeOf;
-
-        extern (C) BlkInfo function(void*) gc_query;
-
-        extern (C) void function(void*) gc_addRoot;
-        extern (C) void function(void*, size_t) gc_addRange;
-
-        extern (C) void function(void*) gc_removeRoot;
-        extern (C) void function(void*) gc_removeRange;
-    }
-
-    __gshared Proxy  pthis;
-    __gshared Proxy* proxy;
-
-    void initProxy()
-    {
-        pthis.gc_enable = &gc_enable;
-        pthis.gc_disable = &gc_disable;
-        pthis.gc_collect = &gc_collect;
-        pthis.gc_minimize = &gc_minimize;
-
-        pthis.gc_getAttr = &gc_getAttr;
-        pthis.gc_setAttr = &gc_setAttr;
-        pthis.gc_clrAttr = &gc_clrAttr;
-
-        pthis.gc_malloc = &gc_malloc;
-        pthis.gc_calloc = &gc_calloc;
-        pthis.gc_realloc = &gc_realloc;
-        pthis.gc_extend = &gc_extend;
-        pthis.gc_reserve = &gc_reserve;
-        pthis.gc_free = &gc_free;
-
-        pthis.gc_addrOf = &gc_addrOf;
-        pthis.gc_sizeOf = &gc_sizeOf;
-
-        pthis.gc_query = &gc_query;
-
-        pthis.gc_addRoot = &gc_addRoot;
-        pthis.gc_addRange = &gc_addRange;
-
-        pthis.gc_removeRoot = &gc_removeRoot;
-        pthis.gc_removeRange = &gc_removeRange;
-    }
-}
-
-extern (C) void gc_init()
-{
-    version (GCCLASS)
-    {   void* p;
-        ClassInfo ci = GC.classinfo;
-
-        p = malloc(ci.init.length);
-        (cast(byte*)p)[0 .. ci.init.length] = ci.init[];
-        _gc = cast(GC)p;
-    }
-    else
-    {
-        _gc = cast(GC*) calloc(1, GC.sizeof);
-    }
-    _gc.initialize();
-    // NOTE: The GC must initialize the thread library
-    //       before its first collection.
-    thread_init();
-    initProxy();
-}
-
-extern (C) void gc_term()
-{
-    // NOTE: There may be daemons threads still running when this routine is
-    //       called.  If so, cleaning memory out from under then is a good
-    //       way to make them crash horribly.  This probably doesn't matter
-    //       much since the app is supposed to be shutting down anyway, but
-    //       I'm disabling cleanup for now until I can think about it some
-    //       more.
-    //
-    // NOTE: Due to popular demand, this has been re-enabled.  It still has
-    //       the problems mentioned above though, so I guess we'll see.
-    _gc.fullCollectNoStack(); // not really a 'collect all' -- still scans
-                              // static data area, roots, and ranges.
-    _gc.Dtor();
-}
-
-extern (C) void gc_enable()
-{
-    if( proxy is null )
-        return _gc.enable();
-    return proxy.gc_enable();
-}
-
-extern (C) void gc_disable()
-{
-    if( proxy is null )
-        return _gc.disable();
-    return proxy.gc_disable();
-}
-
-extern (C) void gc_collect()
-{
-    if( proxy is null )
-        return _gc.fullCollect();
-    return proxy.gc_collect();
-}
-
-
-extern (C) void gc_minimize()
-{
-    if( proxy is null )
-        return _gc.minimize();
-    return proxy.gc_minimize();
-}
-
-extern (C) uint gc_getAttr( void* p )
-{
-    if( proxy is null )
-        return _gc.getAttr( p );
-    return proxy.gc_getAttr( p );
-}
-
-extern (C) uint gc_setAttr( void* p, uint a )
-{
-    if( proxy is null )
-        return _gc.setAttr( p, a );
-    return proxy.gc_setAttr( p, a );
-}
-
-extern (C) uint gc_clrAttr( void* p, uint a )
-{
-    if( proxy is null )
-        return _gc.clrAttr( p, a );
-    return proxy.gc_clrAttr( p, a );
-}
-
-extern (C) void* gc_malloc( size_t sz, uint ba = 0 )
-{
-    if( proxy is null )
-        return _gc.malloc( sz, ba );
-    return proxy.gc_malloc( sz, ba );
-}
-
-extern (C) void* gc_calloc( size_t sz, uint ba = 0 )
-{
-    if( proxy is null )
-        return _gc.calloc( sz, ba );
-    return proxy.gc_calloc( sz, ba );
-}
-
-extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 )
-{
-    if( proxy is null )
-        return _gc.realloc( p, sz, ba );
-    return proxy.gc_realloc( p, sz, ba );
-}
-
-extern (C) size_t gc_extend( void* p, size_t mx, size_t sz )
-{
-    if( proxy is null )
-        return _gc.extend( p, mx, sz );
-    return proxy.gc_extend( p, mx, sz );
-}
-
-extern (C) size_t gc_reserve( size_t sz )
-{
-    if( proxy is null )
-        return _gc.reserve( sz );
-    return proxy.gc_reserve( sz );
-}
-
-extern (C) void gc_free( void* p )
-{
-    if( proxy is null )
-        return _gc.free( p );
-    return proxy.gc_free( p );
-}
-
-extern (C) void* gc_addrOf( void* p )
-{
-    if( proxy is null )
-        return _gc.addrOf( p );
-    return proxy.gc_addrOf( p );
-}
-
-extern (C) size_t gc_sizeOf( void* p )
-{
-    if( proxy is null )
-        return _gc.sizeOf( p );
-    return proxy.gc_sizeOf( p );
-}
-
-extern (C) BlkInfo gc_query( void* p )
-{
-    if( proxy is null )
-        return _gc.query( p );
-    return proxy.gc_query( p );
-}
-
-// NOTE: This routine is experimental.  The stats or function name may change
-//       before it is made officially available.
-extern (C) GCStats gc_stats()
-{
-    if( proxy is null )
-    {
-        GCStats stats = void;
-        _gc.getStats( stats );
-        return stats;
-    }
-    // TODO: Add proxy support for this once the layout of GCStats is
-    //       finalized.
-    //return proxy.gc_stats();
-    return GCStats.init;
-}
-
-extern (C) void gc_addRoot( void* p )
-{
-    if( proxy is null )
-        return _gc.addRoot( p );
-    return proxy.gc_addRoot( p );
-}
-
-extern (C) void gc_addRange( void* p, size_t sz )
-{
-    if( proxy is null )
-        return _gc.addRange( p, sz );
-    return proxy.gc_addRange( p, sz );
-}
-
-extern (C) void gc_removeRoot( void* p )
-{
-    if( proxy is null )
-        return _gc.removeRoot( p );
-    return proxy.gc_removeRoot( p );
-}
-
-extern (C) void gc_removeRange( void* p )
-{
-    if( proxy is null )
-        return _gc.removeRange( p );
-    return proxy.gc_removeRange( p );
-}
-
-extern (C) Proxy* gc_getProxy()
-{
-    return &pthis;
-}
-
-export extern (C) void gc_setProxy( Proxy* p )
-{
-    if( proxy !is null )
-    {
-        // TODO: Decide if this is an error condition.
-    }
-    proxy = p;
-    foreach( r; _gc.rootIter )
-        proxy.gc_addRoot( r );
-    foreach( r; _gc.rangeIter )
-        proxy.gc_addRange( r.pbot, r.ptop - r.pbot );
-}
-
-export extern (C) void gc_clrProxy()
-{
-    foreach( r; _gc.rangeIter )
-        proxy.gc_removeRange( r.pbot );
-    foreach( r; _gc.rootIter )
-        proxy.gc_removeRoot( r );
-    proxy = null;
-}
Index: src/gc/basic/gcbits.d
===================================================================
--- src/gc/basic/gcbits.d	(revision 166)
+++ src/gc/basic/gcbits.d	(working copy)
@@ -1,193 +0,0 @@
-/**
- * Contains a bitfield used by the GC.
- *
- * Copyright: Copyright Digital Mars 2005 - 2009.
- * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
- * Authors:   Walter Bright, David Friedman, Sean Kelly
- *
- *          Copyright Digital Mars 2005 - 2009.
- * Distributed under the Boost Software License, Version 1.0.
- *    (See accompanying file LICENSE_1_0.txt or copy at
- *          http://www.boost.org/LICENSE_1_0.txt)
- */
-module gc.gcbits;
-
-
-private
-{
-    import core.bitop;
-    import core.stdc.string;
-    import core.stdc.stdlib;
-    extern (C) void onOutOfMemoryError();
-}
-
-
-version (DigitalMars)
-{
-    version = bitops;
-}
-else version (GNU)
-{
-    // use the unoptimized version
-}
-else version (D_InlineAsm_X86)
-{
-    version = Asm86;
-}
-
-struct GCBits
-{
-    const int BITS_PER_WORD = 32;
-    const int BITS_SHIFT = 5;
-    const int BITS_MASK = 31;
-
-    uint*  data = null;
-    size_t nwords = 0;    // allocated words in data[] excluding sentinals
-    size_t nbits = 0;     // number of bits in data[] excluding sentinals
-
-    void Dtor()
-    {
-        if (data)
-        {
-            free(data);
-            data = null;
-        }
-    }
-
-    invariant()
-    {
-        if (data)
-        {
-            assert(nwords * data[0].sizeof * 8 >= nbits);
-        }
-    }
-
-    void alloc(size_t nbits)
-    {
-        this.nbits = nbits;
-        nwords = (nbits + (BITS_PER_WORD - 1)) >> BITS_SHIFT;
-        data = cast(uint*)calloc(nwords + 2, uint.sizeof);
-        if (!data)
-            onOutOfMemoryError();
-    }
-
-    uint test(size_t i)
-    in
-    {
-        assert(i < nbits);
-    }
-    body
-    {
-        //return (cast(bit *)(data + 1))[i];
-        return data[1 + (i >> BITS_SHIFT)] & (1 << (i & BITS_MASK));
-    }
-
-    void set(size_t i)
-    in
-    {
-        assert(i < nbits);
-    }
-    body
-    {
-        //(cast(bit *)(data + 1))[i] = 1;
-        data[1 + (i >> BITS_SHIFT)] |= (1 << (i & BITS_MASK));
-    }
-
-    void clear(size_t i)
-    in
-    {
-        assert(i < nbits);
-    }
-    body
-    {
-        //(cast(bit *)(data + 1))[i] = 0;
-        data[1 + (i >> BITS_SHIFT)] &= ~(1 << (i & BITS_MASK));
-    }
-
-    uint testClear(size_t i)
-    {
-        version (bitops)
-        {
-            return std.intrinsic.btr(data + 1, i);
-        }
-        else version (Asm86)
-        {
-            asm
-            {
-                naked                   ;
-                mov     EAX,data[EAX]   ;
-                mov     ECX,i-4[ESP]    ;
-                btr     4[EAX],ECX      ;
-                sbb     EAX,EAX         ;
-                ret     4               ;
-            }
-        }
-        else
-        {   uint result;
-
-            //result = (cast(bit *)(data + 1))[i];
-            //(cast(bit *)(data + 1))[i] = 0;
-
-            uint* p = &data[1 + (i >> BITS_SHIFT)];
-            uint  mask = (1 << (i & BITS_MASK));
-            result = *p & mask;
-            *p &= ~mask;
-            return result;
-        }
-    }
-
-    void zero()
-    {
-        memset(data + 1, 0, nwords * uint.sizeof);
-    }
-
-    void copy(GCBits *f)
-    in
-    {
-        assert(nwords == f.nwords);
-    }
-    body
-    {
-        memcpy(data + 1, f.data + 1, nwords * uint.sizeof);
-    }
-
-    uint* base()
-    in
-    {
-        assert(data);
-    }
-    body
-    {
-        return data + 1;
-    }
-}
-
-unittest
-{
-    GCBits b;
-
-    b.alloc(786);
-    assert(b.test(123) == 0);
-    assert(b.testClear(123) == 0);
-    b.set(123);
-    assert(b.test(123) != 0);
-    assert(b.testClear(123) != 0);
-    assert(b.test(123) == 0);
-
-    b.set(785);
-    b.set(0);
-    assert(b.test(785) != 0);
-    assert(b.test(0) != 0);
-    b.zero();
-    assert(b.test(785) == 0);
-    assert(b.test(0) == 0);
-
-    GCBits b2;
-    b2.alloc(786);
-    b2.set(38);
-    b.copy(&b2);
-    assert(b.test(38) != 0);
-    b2.Dtor();
-
-    b.Dtor();
-}
Index: src/compiler/ldc/memory_osx.c
===================================================================
--- src/compiler/ldc/memory_osx.c	(revision 0)
+++ src/compiler/ldc/memory_osx.c	(revision 0)
@@ -0,0 +1,75 @@
+/**
+ * This module provides OSX-specific support routines for memory.d.
+ *
+ * Copyright: Copyright Digital Mars 2008 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2008 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifdef __APPLE__
+
+
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
+
+void gc_addRange( void* p, size_t sz );
+void gc_removeRange( void* p );
+
+typedef struct
+{
+    const char* seg;
+    const char* sect;
+} seg_ref;
+
+const static seg_ref data_segs[] = {{SEG_DATA, SECT_DATA},
+                                    {SEG_DATA, SECT_BSS},
+                                    {SEG_DATA, SECT_COMMON}};
+const static int NUM_DATA_SEGS   = sizeof(data_segs) / sizeof(seg_ref);
+
+
+static void on_add_image( const struct mach_header* h, intptr_t slide )
+{
+    const struct section* sect;
+    int i;
+
+    for( i = 0; i < NUM_DATA_SEGS; ++i )
+    {
+        sect = getsectbynamefromheader( h,
+                                        data_segs[i].seg,
+                                        data_segs[i].sect );
+        if( sect == NULL || sect->size == 0 )
+            continue;
+        gc_addRange( (void*) sect->addr + slide, sect->size );
+    }
+}
+
+
+static void on_remove_image( const struct mach_header* h, intptr_t slide )
+{
+    const struct section* sect;
+    int i;
+
+    for( i = 0; i < NUM_DATA_SEGS; ++i )
+    {
+        sect = getsectbynamefromheader( h,
+                                        data_segs[i].seg,
+                                        data_segs[i].sect );
+        if( sect == NULL || sect->size == 0 )
+            continue;
+        gc_removeRange( (void*) sect->addr + slide );
+    }
+}
+
+
+void _d_osx_image_init()
+{
+    _dyld_register_func_for_add_image( &on_add_image );
+    _dyld_register_func_for_remove_image( &on_remove_image );
+}
+
+
+#endif
Index: src/compiler/ldc/arrayInit.d
===================================================================
--- src/compiler/ldc/arrayInit.d	(revision 0)
+++ src/compiler/ldc/arrayInit.d	(revision 0)
@@ -0,0 +1,169 @@
+private import ldc.intrinsics;
+
+extern(C):
+
+int memcmp(void*,void*,size_t);
+size_t strlen(char*);
+
+version(LLVM64)
+alias llvm_memcpy_i64 llvm_memcpy;
+else
+alias llvm_memcpy_i32 llvm_memcpy;
+
+// per-element array init routines
+
+void _d_array_init_i1(bool* a, size_t n, bool v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i8(ubyte* a, size_t n, ubyte v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i16(ushort* a, size_t n, ushort v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i32(uint* a, size_t n, uint v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_i64(ulong* a, size_t n, ulong v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_float(float* a, size_t n, float v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_double(double* a, size_t n, double v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_real(real* a, size_t n, real v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_cfloat(cfloat* a, size_t n, cfloat v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_cdouble(cdouble* a, size_t n, cdouble v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_creal(creal* a, size_t n, creal v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_pointer(void** a, size_t n, void* v)
+{
+    auto p = a;
+    auto end = a+n;
+    while (p !is end)
+        *p++ = v;
+}
+
+void _d_array_init_mem(void* a, size_t na, void* v, size_t nv)
+{
+    auto p = a;
+    auto end = a + na*nv;
+    while (p !is end) {
+        llvm_memcpy(p,v,nv,0);
+        p += nv;
+    }
+}
+
+/*
+void _d_array_init(TypeInfo ti, void* a)
+{
+    auto initializer = ti.next.init();
+    auto isize = initializer.length;
+    auto q = initializer.ptr;
+
+    if (isize == 1)
+        memset(p, *cast(ubyte*)q, size);
+    else if (isize == int.sizeof)
+    {
+        int init = *cast(int*)q;
+        size /= int.sizeof;
+        for (size_t u = 0; u < size; u++)
+        {
+            (cast(int*)p)[u] = init;
+        }
+    }
+    else
+    {
+        for (size_t u = 0; u < size; u += isize)
+        {
+            memcpy(p + u, q, isize);
+        }
+    }
+}*/
+
+// for array cast
+size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz)
+{
+    if (newelemsz == 1) {
+        return len*elemsz;
+    }
+    else if ((len*elemsz) % newelemsz) {
+        throw new Exception("Bad array cast");
+    }
+    return (len*elemsz)/newelemsz;
+}
+
+// slice copy when assertions are enabled
+void _d_array_slice_copy(void* dst, size_t dstlen, void* src, size_t srclen)
+{
+    if (dstlen != srclen)
+        throw new Exception("lengths don't match for array copy");
+    else if (dst+dstlen <= src || src+srclen <= dst)
+        llvm_memcpy(dst, src, dstlen, 0);
+    else
+        throw new Exception("overlapping array copy");
+}
Index: src/compiler/ldc/rt/adi.d
===================================================================
--- src/compiler/ldc/rt/adi.d	(revision 0)
+++ src/compiler/ldc/rt/adi.d	(revision 0)
@@ -0,0 +1,603 @@
+/**
+ * Implementation of dynamic array property support routines.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.adi;
+
+//debug=adi;            // uncomment to turn on debugging printf's
+
+private
+{
+    debug(adi) import core.stdc.stdio;
+    import core.stdc.string;
+    import core.stdc.stdlib;
+    import rt.util.utf;
+
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) void  gc_free( void* p );
+}
+
+
+struct Array
+{
+    size_t  length;
+    void*   ptr;
+}
+
+/**********************************************
+ * Reverse array of chars.
+ * Handled separately because embedded multibyte encodings should not be
+ * reversed.
+ */
+
+extern (C) long _adReverseChar(char[] a)
+{
+    if (a.length > 1)
+    {
+        char[6] tmp;
+        char[6] tmplo;
+        char* lo = a.ptr;
+        char* hi = &a[length - 1];
+
+        while (lo < hi)
+        {   auto clo = *lo;
+            auto chi = *hi;
+
+            debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
+            if (clo <= 0x7F && chi <= 0x7F)
+            {
+                debug(adi) printf("\tascii\n");
+                *lo = chi;
+                *hi = clo;
+                lo++;
+                hi--;
+                continue;
+            }
+
+            uint stridelo = UTF8stride[clo];
+
+            uint stridehi = 1;
+            while ((chi & 0xC0) == 0x80)
+            {
+                chi = *--hi;
+                stridehi++;
+                assert(hi >= lo);
+            }
+            if (lo == hi)
+                break;
+
+            debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
+            if (stridelo == stridehi)
+            {
+
+                memcpy(tmp.ptr, lo, stridelo);
+                memcpy(lo, hi, stridelo);
+                memcpy(hi, tmp.ptr, stridelo);
+                lo += stridelo;
+                hi--;
+                continue;
+            }
+
+            /* Shift the whole array. This is woefully inefficient
+             */
+            memcpy(tmp.ptr, hi, stridehi);
+            memcpy(tmplo.ptr, lo, stridelo);
+            memmove(lo + stridehi, lo + stridelo , (hi - lo) - stridelo);
+            memcpy(lo, tmp.ptr, stridehi);
+            memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
+
+            lo += stridehi;
+            hi = hi - 1 + (stridehi - stridelo);
+        }
+    }
+    return *cast(long*)(&a);
+}
+
+unittest
+{
+    auto a = "abcd"c[];
+
+    auto r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "dcba");
+
+    a = "a\u1235\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234\u1235a");
+
+    a = "ab\u1234c";
+    //writefln(a);
+    r = a.dup.reverse;
+    //writefln(r);
+    assert(r == "c\u1234ba");
+
+    a = "\u3026\u2021\u3061\n";
+    r = a.dup.reverse;
+    assert(r == "\n\u3061\u2021\u3026");
+}
+
+
+/**********************************************
+ * Reverse array of wchars.
+ * Handled separately because embedded multiword encodings should not be
+ * reversed.
+ */
+
+extern (C) long _adReverseWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+        wchar[2] tmp;
+        wchar* lo = a.ptr;
+        wchar* hi = &a[length - 1];
+
+        while (lo < hi)
+        {   auto clo = *lo;
+            auto chi = *hi;
+
+            if ((clo < 0xD800 || clo > 0xDFFF) &&
+                (chi < 0xD800 || chi > 0xDFFF))
+            {
+                *lo = chi;
+                *hi = clo;
+                lo++;
+                hi--;
+                continue;
+            }
+
+            int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
+
+            int stridehi = 1;
+            if (chi >= 0xDC00 && chi <= 0xDFFF)
+            {
+                chi = *--hi;
+                stridehi++;
+                assert(hi >= lo);
+            }
+            if (lo == hi)
+                break;
+
+            if (stridelo == stridehi)
+            {   int stmp;
+
+                assert(stridelo == 2);
+                assert(stmp.sizeof == 2 * (*lo).sizeof);
+                stmp = *cast(int*)lo;
+                *cast(int*)lo = *cast(int*)hi;
+                *cast(int*)hi = stmp;
+                lo += stridelo;
+                hi--;
+                continue;
+            }
+
+            /* Shift the whole array. This is woefully inefficient
+             */
+            memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
+            memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
+            memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
+            memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
+
+            lo += stridehi;
+            hi = hi - 1 + (stridehi - stridelo);
+        }
+    }
+    return *cast(long*)(&a);
+}
+
+unittest
+{
+    wstring a = "abcd";
+
+    auto r = a.dup.reverse;
+    assert(r == "dcba");
+
+    a = "a\U00012356\U00012346c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012346\U00012356a");
+
+    a = "ab\U00012345c";
+    r = a.dup.reverse;
+    assert(r == "c\U00012345ba");
+}
+
+
+/**********************************************
+ * Support for array.reverse property.
+ */
+
+extern (C) long _adReverse(Array a, size_t szelem)
+out (result)
+{
+    assert(result is *cast(long*)(&a));
+}
+body
+{
+    if (a.length >= 2)
+    {
+        byte*    tmp;
+        byte[16] buffer;
+
+        void* lo = a.ptr;
+        void* hi = a.ptr + (a.length - 1) * szelem;
+
+        tmp = buffer.ptr;
+        if (szelem > 16)
+        {
+            //version (Windows)
+                //tmp = cast(byte*) alloca(szelem);
+            //else
+                tmp = cast(byte*) gc_malloc(szelem);
+        }
+
+        for (; lo < hi; lo += szelem, hi -= szelem)
+        {
+            memcpy(tmp, lo,  szelem);
+            memcpy(lo,  hi,  szelem);
+            memcpy(hi,  tmp, szelem);
+        }
+
+        version (Windows)
+        {
+        }
+        else
+        {
+            //if (szelem > 16)
+                // BUG: bad code is generate for delete pointer, tries
+                // to call delclass.
+                //gc_free(tmp);
+        }
+    }
+    return *cast(long*)(&a);
+}
+
+unittest
+{
+    debug(adi) printf("array.reverse.unittest\n");
+
+    int[] a = new int[5];
+    int[] b;
+    size_t i;
+
+    for (i = 0; i < 5; i++)
+        a[i] = i;
+    b = a.reverse;
+    assert(b is a);
+    for (i = 0; i < 5; i++)
+        assert(a[i] == 4 - i);
+
+    struct X20
+    {   // More than 16 bytes in size
+        int a;
+        int b, c, d, e;
+    }
+
+    X20[] c = new X20[5];
+    X20[] d;
+
+    for (i = 0; i < 5; i++)
+    {   c[i].a = i;
+        c[i].e = 10;
+    }
+    d = c.reverse;
+    assert(d is c);
+    for (i = 0; i < 5; i++)
+    {
+        assert(c[i].a == 4 - i);
+        assert(c[i].e == 10);
+    }
+}
+
+/**********************************************
+ * Sort array of chars.
+ */
+
+extern (C) long _adSortChar(char[] a)
+{
+    if (a.length > 1)
+    {
+        dstring da = toUTF32(a);
+        da.sort;
+        size_t i = 0;
+        foreach (dchar d; da)
+        {   char[4] buf;
+            auto t = toUTF8(buf, d);
+            a[i .. i + t.length] = t[];
+            i += t.length;
+        }
+        delete da;
+    }
+    return *cast(long*)(&a);
+}
+
+/**********************************************
+ * Sort array of wchars.
+ */
+
+extern (C) long _adSortWchar(wchar[] a)
+{
+    if (a.length > 1)
+    {
+        dstring da = toUTF32(a);
+        da.sort;
+        size_t i = 0;
+        foreach (dchar d; da)
+        {   wchar[2] buf;
+            auto t = toUTF16(buf, d);
+            a[i .. i + t.length] = t[];
+            i += t.length;
+        }
+        delete da;
+    }
+    return *cast(long*)(&a);
+}
+
+/***************************************
+ * Support for array equality test.
+ * Returns:
+ *      1       equal
+ *      0       not equal
+ */
+
+extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    if (a1.length != a2.length)
+        return 0; // not equal
+    auto sz = ti.tsize();
+    auto p1 = a1.ptr;
+    auto p2 = a2.ptr;
+
+    if (sz == 1)
+        // We should really have a ti.isPOD() check for this
+        return (memcmp(p1, p2, a1.length) == 0);
+
+    for (size_t i = 0; i < a1.length; i++)
+    {
+        if (!ti.equals(p1 + i * sz, p2 + i * sz))
+            return 0; // not equal
+    }
+    return 1; // equal
+}
+
+extern (C) int _adEq2(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    if (a1.length != a2.length)
+        return 0;               // not equal
+    if (!ti.equals(&a1, &a2))
+        return 0;
+    return 1;
+}
+unittest
+{
+    debug(adi) printf("array.Eq unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a != "hel");
+    assert(a != "helloo");
+    assert(a != "betty");
+    assert(a == "hello");
+    assert(a != "hxxxx");
+}
+
+/***************************************
+ * Support for array compare test.
+ */
+
+extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("adCmp()\n");
+    auto len = a1.length;
+    if (a2.length < len)
+        len = a2.length;
+    auto sz = ti.tsize();
+    void *p1 = a1.ptr;
+    void *p2 = a2.ptr;
+
+    if (sz == 1)
+    {   // We should really have a ti.isPOD() check for this
+        auto c = memcmp(p1, p2, len);
+        if (c)
+            return c;
+    }
+    else
+    {
+        for (size_t i = 0; i < len; i++)
+        {
+            auto c = ti.compare(p1 + i * sz, p2 + i * sz);
+            if (c)
+                return c;
+        }
+    }
+    if (a1.length == a2.length)
+        return 0;
+    return (a1.length > a2.length) ? 1 : -1;
+}
+
+extern (C) int _adCmp2(Array a1, Array a2, TypeInfo ti)
+{
+    debug(adi) printf("_adCmp2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+    return ti.compare(&a1, &a2);
+}
+unittest
+{
+    debug(adi) printf("array.Cmp unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
+
+/***************************************
+ * Support for array compare test.
+ */
+
+extern (C) int _adCmpChar(Array a1, Array a2)
+{
+  version (X86)
+  {
+    asm
+    {   naked                   ;
+
+        push    EDI             ;
+        push    ESI             ;
+
+        mov    ESI,a1+4[4+ESP]  ;
+        mov    EDI,a2+4[4+ESP]  ;
+
+        mov    ECX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        cmp     ECX,EDX         ;
+        jb      GotLength       ;
+
+        mov     ECX,EDX         ;
+
+GotLength:
+        cmp    ECX,4            ;
+        jb    DoBytes           ;
+
+        // Do alignment if neither is dword aligned
+        test    ESI,3           ;
+        jz    Aligned           ;
+
+        test    EDI,3           ;
+        jz    Aligned           ;
+DoAlign:
+        mov    AL,[ESI]         ; //align ESI to dword bounds
+        mov    DL,[EDI]         ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        inc    ESI              ;
+        inc    EDI              ;
+
+        test    ESI,3           ;
+
+        lea    ECX,[ECX-1]      ;
+        jnz    DoAlign          ;
+Aligned:
+        mov    EAX,ECX          ;
+
+        // do multiple of 4 bytes at a time
+
+        shr    ECX,2            ;
+        jz    TryOdd            ;
+
+        repe                    ;
+        cmpsd                   ;
+
+        jnz    UnequalQuad      ;
+
+TryOdd:
+        mov    ECX,EAX          ;
+DoBytes:
+        // if still equal and not end of string, do up to 3 bytes slightly
+        // slower.
+
+        and    ECX,3            ;
+        jz    Equal             ;
+
+        repe                    ;
+        cmpsb                   ;
+
+        jnz    Unequal          ;
+Equal:
+        mov    EAX,a1[4+ESP]    ;
+        mov    EDX,a2[4+ESP]    ;
+
+        sub    EAX,EDX          ;
+        pop    ESI              ;
+
+        pop    EDI              ;
+        ret                     ;
+
+UnequalQuad:
+        mov    EDX,[EDI-4]      ;
+        mov    EAX,[ESI-4]      ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        cmp    AH,DH            ;
+        jnz    Unequal          ;
+
+        shr    EAX,16           ;
+
+        shr    EDX,16           ;
+
+        cmp    AL,DL            ;
+        jnz    Unequal          ;
+
+        cmp    AH,DH            ;
+Unequal:
+        sbb    EAX,EAX          ;
+        pop    ESI              ;
+
+        or     EAX,1            ;
+        pop    EDI              ;
+
+        ret                     ;
+    }
+  }
+  else
+  {
+    int len;
+    int c;
+
+    debug(adi) printf("adCmpChar()\n");
+    len = cast(int)a1.length;
+    if (a2.length < len)
+        len = cast(int)a2.length;
+    c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
+    if (!c)
+        c = cast(int)a1.length - cast(int)a2.length;
+    return c;
+  }
+}
+
+unittest
+{
+    debug(adi) printf("array.CmpChar unittest\n");
+
+    auto a = "hello"c;
+
+    assert(a >  "hel");
+    assert(a >= "hel");
+    assert(a <  "helloo");
+    assert(a <= "helloo");
+    assert(a >  "betty");
+    assert(a >= "betty");
+    assert(a == "hello");
+    assert(a <= "hello");
+    assert(a >= "hello");
+}
Index: src/compiler/ldc/rt/arrayshort.d
===================================================================
--- src/compiler/ldc/rt/arrayshort.d	(revision 0)
+++ src/compiler/ldc/rt/arrayshort.d	(revision 0)
@@ -0,0 +1,2303 @@
+/**
+ * Contains SSE2 and MMX versions of certain operations for wchar, short,
+ * and ushort ('u', 's' and 't' suffixes).
+ *
+ * Copyright: Copyright Digital Mars 2008 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, based on code originally written by Burton Radons
+ *
+ *          Copyright Digital Mars 2008 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.arrayshort;
+
+private import rt.util.cpuid;
+
+version (unittest)
+{
+    private import core.stdc.stdio : printf;
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 4;
+    bool mmx()      { return cpuid == 1 && rt.util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && rt.util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && rt.util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && rt.util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias rt.util.cpuid.mmx mmx;
+    alias rt.util.cpuid.sse sse;
+    alias rt.util.cpuid.sse2 sse2;
+    alias rt.util.cpuid.sse2 sse2;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias short T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_u(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_t(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_s(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 3343% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 3343% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                paddw MM0, MM2;
+                paddw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ + value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_u(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_t(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_s(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceAddSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 3777% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    movdqu XMM2, [ECX];
+                    movdqu XMM3, [ECX+16];
+                    add ECX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    movdqa XMM2, [ECX];
+                    movdqa XMM3, [ECX+16];
+                    add ECX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 2068% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                movq MM2, [ECX];
+                movq MM3, [ECX+8];
+                add ECX, 16;
+                paddw MM0, MM2;
+                paddw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ + *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_u(T[] a, T value)
+{
+    return _arrayExpSliceAddass_s(a, value);
+}
+
+T[] _arrayExpSliceAddass_t(T[] a, T value)
+{
+    return _arrayExpSliceAddass_s(a, value);
+}
+
+T[] _arrayExpSliceAddass_s(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 832% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 826% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                paddw MM0, MM2;
+                paddw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            a[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(c[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, a[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_u(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_s(a, b);
+}
+
+T[] _arraySliceSliceAddass_t(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_s(a, b);
+}
+
+T[] _arraySliceSliceAddass_s(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2085% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    movdqu XMM2, [ECX];
+                    movdqu XMM3, [ECX+16];
+                    add ECX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    movdqa XMM2, [ECX];
+                    movdqa XMM3, [ECX+16];
+                    add ECX, 32;
+                    paddw XMM0, XMM2;
+                    paddw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 1022% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                movq MM2, [ECX];
+                movq MM3, [ECX+8];
+                add ECX, 16;
+                paddw MM0, MM2;
+                paddw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] + a[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_u(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_t(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_s(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 3695% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 3049% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ - value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_u(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_s(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_t(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_s(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_s(T[] a, T[] b, T value)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 4995% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+
+                    align 4;
+                startaddsse2u:
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+                    movd XMM3, l;
+                    pshufd XMM3, XMM3, 0;
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubw XMM2, XMM0;
+                    psubw XMM3, XMM1;
+                    movdqu [ESI   -32], XMM2;
+                    movdqu [ESI+16-32], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+
+                    align 4;
+                startaddsse2a:
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+                    movd XMM3, l;
+                    pshufd XMM3, XMM3, 0;
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubw XMM2, XMM0;
+                    psubw XMM3, XMM1;
+                    movdqa [ESI   -32], XMM2;
+                    movdqa [ESI+16-32], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 4562% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM2, [EAX];
+                movq MM3, [EAX+8];
+                movq MM0, MM4;
+                movq MM1, MM4;
+                add EAX, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(value - *bptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = 6 - a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - a[i]))
+                {
+                    printf("[%d]: %d != 6 - %d\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_u(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_t(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_s(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 4129% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    movdqu XMM2, [ECX];
+                    movdqu XMM3, [ECX+16];
+                    add ECX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    movdqa XMM2, [ECX];
+                    movdqa XMM3, [ECX+16];
+                    add ECX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 2018% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                movq MM2, [ECX];
+                movq MM3, [ECX+8];
+                add ECX, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ - *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_u(T[] a, T value)
+{
+    return _arrayExpSliceMinass_s(a, value);
+}
+
+T[] _arrayExpSliceMinass_t(T[] a, T value)
+{
+    return _arrayExpSliceMinass_s(a, value);
+}
+
+T[] _arrayExpSliceMinass_s(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 835% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= (l << 16);
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 835% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            a[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(c[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, a[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_u(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_s(a, b);
+}
+
+T[] _arraySliceSliceMinass_t(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_s(a, b);
+}
+
+T[] _arraySliceSliceMinass_s(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2121% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    movdqu XMM2, [ECX];
+                    movdqu XMM3, [ECX+16];
+                    add ECX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    movdqa XMM2, [ECX];
+                    movdqa XMM3, [ECX+16];
+                    add ECX, 32;
+                    psubw XMM0, XMM2;
+                    psubw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 1116% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                movq MM2, [ECX];
+                movq MM3, [ECX+8];
+                add ECX, 16;
+                psubw MM0, MM2;
+                psubw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] -= a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] - a[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAssign_u(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpMulSliceAssign_t(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAssign_s(a, value, b);
+}
+
+T[] _arraySliceExpMulSliceAssign_s(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMulSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 3733% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= l << 16;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 3733% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                pmullw MM0, MM2;
+                pmullw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ * value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %d != %d * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * c[]
+ */
+
+T[] _arraySliceSliceMulSliceAssign_u(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMulSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceMulSliceAssign_t(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMulSliceAssign_s(a, c, b);
+}
+
+T[] _arraySliceSliceMulSliceAssign_s(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceMulSliceAssign_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2515% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+               }
+            }
+        }
+        else
+        // MMX version is 2515% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM2, [ECX];
+                movq MM1, [EAX+8];
+                movq MM3, [ECX+8];
+                add EAX, 16;
+                add ECX, 16;
+                pmullw MM0, MM2;
+                pmullw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ * *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * b[i]))
+                {
+                    printf("[%d]: %d != %d * %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= value
+ */
+
+T[] _arrayExpSliceMulass_u(T[] a, T value)
+{
+    return _arrayExpSliceMulass_s(a, value);
+}
+
+T[] _arrayExpSliceMulass_t(T[] a, T value)
+{
+    return _arrayExpSliceMulass_s(a, value);
+}
+
+T[] _arrayExpSliceMulass_s(T[] a, T value)
+{
+    //printf("_arrayExpSliceMulass_s(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2044% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            uint l = cast(ushort) value;
+            l |= l << 16;
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 2056% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = cast(ushort) value;
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM2, l;
+                pshufw MM2, MM2, 0;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                pmullw MM0, MM2;
+                pmullw MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = a[];
+            a[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(b[i] * 6))
+                {
+                    printf("[%d]: %d != %d * 6\n", i, a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= b[]
+ */
+
+T[] _arraySliceSliceMulass_u(T[] a, T[] b)
+{
+    return _arraySliceSliceMulass_s(a, b);
+}
+
+T[] _arraySliceSliceMulass_t(T[] a, T[] b)
+{
+    return _arraySliceSliceMulass_s(a, b);
+}
+
+T[] _arraySliceSliceMulass_s(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMulass_s()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 2519% faster
+        if (sse2() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    pmullw XMM0, XMM2;
+                    pmullw XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+               }
+            }
+        }
+        else
+        // MMX version is 1712% faster
+        if (mmx() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM2, [ECX];
+                movq MM1, [ESI+8];
+                movq MM3, [ECX+8];
+                add ESI, 16;
+                add ECX, 16;
+                pmullw MM0, MM2;
+                pmullw MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulass_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = a[];
+            a[] *= c[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(b[i] * c[i]))
+                {
+                    printf("[%d]: %d != %d * %d\n", i, a[i], b[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
Index: src/compiler/ldc/rt/lifetime.d
===================================================================
--- src/compiler/ldc/rt/lifetime.d	(revision 0)
+++ src/compiler/ldc/rt/lifetime.d	(revision 0)
@@ -0,0 +1,1090 @@
+/**
+ * This module contains all functions related to an object's lifetime:
+ * allocation, resizing, deallocation, and finalization.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly, Robert Clipsham
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.lifetime;
+
+
+private
+{
+    import core.stdc.stdlib;
+    import core.stdc.string;
+    import core.stdc.stdarg;
+    debug(PRINTF) import core.stdc.stdio;
+}
+
+
+private
+{
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    struct BlkInfo
+    {
+        void*  base;
+        size_t size;
+        uint   attr;
+    }
+
+    extern (C) uint gc_getAttr( void* p );
+    extern (C) uint gc_setAttr( void* p, uint a );
+    extern (C) uint gc_clrAttr( void* p, uint a );
+
+    extern (C) void*  gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void*  gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
+    extern (C) void   gc_free( void* p );
+
+    extern (C) void*   gc_addrOf( void* p );
+    extern (C) size_t  gc_sizeOf( void* p );
+    extern (C) BlkInfo gc_query( void* p );
+
+    extern (C) bool onCollectResource( Object o );
+    extern (C) void onFinalizeError( ClassInfo c, Throwable e );
+    extern (C) void onOutOfMemoryError();
+
+    extern (C) void _d_monitordelete(Object h, bool det = true);
+
+    enum
+    {
+        PAGESIZE = 4096
+    }
+
+    alias bool function(Object) CollectHandler;
+    __gshared CollectHandler collectHandler = null;
+
+    size_t length_adjust(size_t sizeelem, size_t newlength)
+    {
+        size_t newsize = void;
+        static if (size_t.sizeof < ulong.sizeof)
+        {
+            ulong s = cast(ulong)sizeelem * cast(ulong)newlength;
+            if (s > size_t.max)
+                onOutOfMemoryError();
+            newsize = cast(size_t)s;
+        }
+        else
+        {
+            newsize = sizeelem * newlength;
+            if (newsize / newlength != sizeelem)
+                onOutOfMemoryError();
+        }
+        return newsize;
+    }
+}
+
+/+
+/**
+ *
+ */
+extern (C) void* _d_allocmemory(size_t sz)
+{
+    return gc_malloc(sz);
+}
++/
+
+
+/**
+ * for allocating a single POD value
+ */
+extern (C) void* _d_allocmemoryT(TypeInfo ti)
+{
+    return gc_malloc(ti.tsize(), !(ti.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+}
+
+/**
+ *
+ */
+extern (C) Object _d_allocclass(ClassInfo ci)
+{
+    void* p;
+
+    debug(PRINTF) printf("_d_allocclass(ci = %p, %s)\n", ci, cast(char *)ci.name);
+    if (ci.flags & 1) // if COM object
+    {   /* COM objects are not garbage collected, they are reference counted
+         * using AddRef() and Release().  They get free'd by C's free()
+         * function called by Release() when Release()'s reference count goes
+         * to zero.
+     */
+        p = malloc(ci.init.length);
+        if (!p)
+            onOutOfMemoryError();
+    }
+    else
+    {
+        p = gc_malloc(ci.init.length,
+                      BlkAttr.FINALIZE | (ci.flags & 2 ? BlkAttr.NO_SCAN : 0));
+        debug(PRINTF) printf(" p = %p\n", p);
+    }
+
+    debug(PRINTF)
+    {
+        printf("p = %p\n", p);
+        printf("ci = %p, ci.init = %p, len = %d\n", ci, ci.init.ptr, ci.init.length);
+        printf("vptr = %p\n", *cast(void**) ci.init.ptr);
+        printf("vtbl[0] = %p\n", (*cast(void***) ci.init.ptr)[0]);
+        printf("vtbl[1] = %p\n", (*cast(void***) ci.init.ptr)[1]);
+        printf("init[0] = %p\n", (cast(uint**) ci.init.ptr)[0]);
+        printf("init[1] = %p\n", (cast(uint**) ci.init.ptr)[1]);
+        printf("init[2] = %p\n", (cast(uint**) ci.init.ptr)[2]);
+        printf("init[3] = %p\n", (cast(uint**) ci.init.ptr)[3]);
+        printf("init[4] = %p\n", (cast(uint**) ci.init.ptr)[4]);
+    }
+
+    // initialize it
+    // ldc does this inline
+    //(cast(byte*) p)[0 .. ci.init.length] = ci.init[];
+
+    debug(PRINTF) printf("initialization done\n");
+    return cast(Object) p;
+}
+
+/**
+ *
+ */
+extern (C) void _d_delinterface(void* p)
+{
+    if (p)
+    {
+        Interface* pi = **cast(Interface ***)p;
+        Object     o  = cast(Object)(p - pi.offset);
+
+        _d_delclass(o);
+        //*p = null;
+    }
+}
+
+
+// used for deletion
+private extern (D) alias void function(Object) fp_t;
+
+
+/**
+ *
+ */
+extern (C) void _d_delclass(Object p)
+{
+    if (p)
+    {
+        debug(PRINTF) printf("_d_delclass(%p)\n", p);
+
+        ClassInfo **pc = cast(ClassInfo **)p;
+        if (*pc)
+        {
+            ClassInfo c = **pc;
+
+            rt_finalize(cast(void*) p);
+
+            if (c.deallocator)
+            {
+                fp_t fp = cast(fp_t)c.deallocator;
+                (*fp)(p); // call deallocator
+                //*p = null;
+                return;
+            }
+        }
+        else
+        {
+            rt_finalize(cast(void*) p);
+        }
+        gc_free(cast(void*) p);
+        //*p = null;
+    }
+}
+
+
+/**
+ * Allocate a new array of length elements.
+ * ti is the type of the resulting array, or pointer to element.
+ * The resulting array is initialized to 0
+ */
+extern (C) void* _d_newarrayT(TypeInfo ti, size_t length)
+{
+    void* p;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayT(length = x%x, size = %d)\n", length, size);
+    if (length == 0 || size == 0)
+        return null;
+
+    size = length_adjust(size, length);
+
+    p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    debug(PRINTF) printf(" p = %p\n", p);
+    memset(p, 0, size);
+
+    return p;
+}
+
+/**
+ * As _d_newarrayT, but 
+ * for when the array has a non-zero initializer.
+ */
+extern (C) void* _d_newarrayiT(TypeInfo ti, size_t length)
+{
+    void* result;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayiT(length = %d, size = %d)\n", length, size);
+
+    if (length == 0 || size == 0)
+        result = null;
+    else
+    {
+        auto initializer = ti.next.init();
+        auto isize = initializer.length;
+        auto q = initializer.ptr;
+
+        size = length_adjust(size, length);
+
+        auto p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        debug(PRINTF) printf(" p = %p\n", p);
+        if (isize == 1)
+            memset(p, *cast(ubyte*)q, size);
+        else if (isize == int.sizeof)
+        {
+            int init = *cast(int*)q;
+            size /= int.sizeof;
+            for (size_t u = 0; u < size; u++)
+            {
+                (cast(int*)p)[u] = init;
+            }
+        }
+        else
+        {
+            for (size_t u = 0; u < size; u += isize)
+            {
+                memcpy(p + u, q, isize);
+            }
+        }
+        result = p;
+    }
+    return result;
+}
+
+/**
+ * As _d_newarrayT, but without initialization
+ */
+extern (C) void* _d_newarrayvT(TypeInfo ti, size_t length)
+{
+    void* p;
+    auto size = ti.next.tsize();                // array element size
+
+    debug(PRINTF) printf("_d_newarrayvT(length = %u, size = %d)\n", length, size);
+    if (length == 0 || size == 0)
+        return null;
+
+    size = length_adjust(size, length);
+
+    p = gc_malloc(size + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    debug(PRINTF) printf(" p = %p\n", p);
+    return p;
+}
+
+/**
+ * Allocate a new array of arrays of arrays of arrays ...
+ * ti is the type of the resulting array.
+ * ndims is the number of nested arrays.
+ * dims it the array of dimensions, its size is ndims.
+ * The resulting array is initialized to 0
+ */
+extern (C) void* _d_newarraymT(TypeInfo ti, int ndims, size_t* dims)
+{
+    void* result;
+
+    debug(PRINTF) printf("_d_newarraymT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = null;
+    else
+    {
+        static void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, ndims);
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayT(ti, dim);
+                return r[0 .. dim];
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        result = foo(ti, dims, ndims).ptr;
+        debug(PRINTF) printf("result = %p\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, *dims++);
+            }
+        }
+    }
+    return result;
+}
+
+
+/**
+ *
+ */
+extern (C) void* _d_newarraymiT(TypeInfo ti, int ndims, size_t* dims)
+{
+    void* result;
+
+    debug(PRINTF) printf("_d_newarraymiT(ndims = %d)\n", ndims);
+    if (ndims == 0)
+        result = null;
+    else
+    {
+        static void[] foo(TypeInfo ti, size_t* pdim, int ndims)
+        {
+            size_t dim = *pdim;
+            void[] p;
+
+            if (ndims == 1)
+            {
+                auto r = _d_newarrayiT(ti, dim);
+                p = r[0 .. dim];
+            }
+            else
+            {
+                p = gc_malloc(dim * (void[]).sizeof + 1)[0 .. dim];
+                for (int i = 0; i < dim; i++)
+                {
+                    (cast(void[]*)p.ptr)[i] = foo(ti.next, pdim + 1, ndims - 1);
+                }
+            }
+            return p;
+        }
+
+        result = foo(ti, dims, ndims).ptr;
+        debug(PRINTF) printf("result = %p\n", result);
+
+        version (none)
+        {
+            for (int i = 0; i < ndims; i++)
+            {
+                printf("index %d: %d\n", i, *dims++);
+                printf("init = %d\n", *dims++);
+            }
+        }
+    }
+    return result;
+}
+
+
+/**
+ *
+ */
+struct Array
+{
+    size_t length;
+    byte*  data;
+}
+
+
+/**
+ * This function has been replaced by _d_delarray_t
+ */
+extern (C) void _d_delarray(Array *p)
+{
+    if (p)
+    {
+        assert(!p.length || p.data);
+
+        if (p.data)
+            gc_free(p.data);
+        p.data = null;
+        p.length = 0;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_delarray_t(Array *p, TypeInfo ti)
+{
+    if (p)
+    {
+        assert(!p.length || p.data);
+        if (p.data)
+        {
+            if (ti)
+            {
+                // Call destructors on all the sub-objects
+                auto sz = ti.tsize();
+                auto pe = p.data;
+                auto pend = pe + p.length * sz;
+                while (pe != pend)
+                {
+                    pend -= sz;
+                    ti.destroy(pend);
+                }
+            }
+            gc_free(p.data);
+        }
+        p.data = null;
+        p.length = 0;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_delmemory(void* *p)
+{
+    if (*p)
+    {
+        gc_free(*p);
+        *p = null;
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_callinterfacefinalizer(void *p)
+{
+    if (p)
+    {
+        Interface *pi = **cast(Interface ***)p;
+        Object o = cast(Object)(p - pi.offset);
+        rt_finalize(cast(void*)o);
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void _d_callfinalizer(void* p)
+{
+    rt_finalize( p );
+}
+
+
+/**
+ *
+ */
+extern (C) void  rt_setCollectHandler(CollectHandler h)
+{
+    collectHandler = h;
+}
+
+
+/**
+ *
+ */
+extern (C) void rt_finalize(void* p, bool det = true)
+{
+    debug(PRINTF) printf("rt_finalize(p = %p)\n", p);
+
+    if (p) // not necessary if called from gc
+    {
+        ClassInfo** pc = cast(ClassInfo**)p;
+
+        if (*pc)
+        {
+            ClassInfo c = **pc;
+
+            try
+            {
+                if (det || collectHandler is null || collectHandler(cast(Object)p))
+                {
+                    do
+                    {
+                        if (c.destructor)
+                        {
+                            fp_t fp = cast(fp_t)c.destructor;
+                            (*fp)(cast(Object)p); // call destructor
+                        }
+                        c = c.base;
+                    } while (c);
+                }
+                if ((cast(void**)p)[1]) // if monitor is not null
+                    _d_monitordelete(cast(Object)p, det);
+            }
+            catch (Throwable e)
+            {
+                onFinalizeError(**pc, e);
+            }
+            finally
+            {
+                *pc = null; // zero vptr
+            }
+        }
+    }
+}
+
+
+/**
+ * Resize dynamic arrays with 0 initializers.
+ */
+extern (C) byte[] _d_arraysetlengthT(TypeInfo ti, size_t newlength, Array *p)
+in
+{
+    assert(ti);
+    assert(!p.length || p.data);
+}
+body
+{
+    debug(PRINTF)
+    {
+        printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
+        if (p)
+            printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
+    }
+
+    byte* newdata = void;
+    if (newlength)
+    {
+        if (newlength <= p.length)
+        {
+            p.length = newlength;
+            newdata = p.data;
+            return newdata[0 .. newlength];
+        }
+        size_t sizeelem = ti.next.tsize();
+        version (D_InlineAsm_X86)
+        {
+            size_t newsize = void;
+
+            asm
+            {
+                mov EAX, newlength;
+                mul EAX, sizeelem;
+                mov newsize, EAX;
+                jc  Loverflow;
+            }
+        }
+        else
+        {
+            size_t newsize = sizeelem * newlength;
+
+            if (newsize / newlength != sizeelem)
+                goto Loverflow;
+        }
+
+        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+        if (p.data)
+        {
+            newdata = p.data;
+            if (newlength > p.length)
+            {
+                size_t size = p.length * sizeelem;
+                auto   info = gc_query(p.data);
+
+                if (info.size <= newsize || info.base != p.data)
+                {
+                    if (info.size >= PAGESIZE && info.base == p.data)
+                    {   // Try to extend in-place
+                        auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+                        if (u)
+                        {
+                            goto L1;
+                        }
+                    }
+                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
+                    newdata[0 .. size] = p.data[0 .. size];
+                }
+             L1:
+                newdata[size .. newsize] = 0;
+            }
+        }
+        else
+        {
+            newdata = cast(byte *)gc_calloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        }
+    }
+    else
+    {
+        newdata = p.data;
+    }
+
+    p.data = newdata;
+    p.length = newlength;
+    return newdata[0 .. newlength];
+
+Loverflow:
+    onOutOfMemoryError();
+    assert(0);
+}
+
+
+/**
+ * Resize arrays for non-zero initializers.
+ *      p               pointer to array lvalue to be updated
+ *      newlength       new .length property of array
+ *      sizeelem        size of each element of array
+ *      initsize        size of initializer
+ *      ...             initializer
+ */
+extern (C) byte[] _d_arraysetlengthiT(TypeInfo ti, size_t newlength, Array *p)
+in
+{
+    assert(!p.length || p.data);
+}
+body
+{
+    byte* newdata;
+    size_t sizeelem = ti.next.tsize();
+    void[] initializer = ti.next.init();
+    size_t initsize = initializer.length;
+
+    assert(sizeelem);
+    assert(initsize);
+    assert(initsize <= sizeelem);
+    assert((sizeelem / initsize) * initsize == sizeelem);
+
+    debug(PRINTF)
+    {
+        printf("_d_arraysetlengthiT(p = %p, sizeelem = %d, newlength = %d, initsize = %d)\n", p, sizeelem, newlength, initsize);
+        if (p)
+            printf("\tp.data = %p, p.length = %d\n", p.data, p.length);
+    }
+
+    if (newlength)
+    {
+        version (D_InlineAsm_X86)
+        {
+            size_t newsize = void;
+
+            asm
+            {
+                mov     EAX,newlength   ;
+                mul     EAX,sizeelem    ;
+                mov     newsize,EAX     ;
+                jc      Loverflow       ;
+            }
+        }
+        else
+        {
+            size_t newsize = sizeelem * newlength;
+
+            if (newsize / newlength != sizeelem)
+                goto Loverflow;
+        }
+        debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+
+        size_t size = p.length * sizeelem;
+
+        if (p.data)
+        {
+            newdata = p.data;
+            if (newlength > p.length)
+            {
+                auto info = gc_query(p.data);
+
+                if (info.size <= newsize || info.base != p.data)
+                {
+                    if (info.size >= PAGESIZE && info.base == p.data)
+                    {   // Try to extend in-place
+                        auto u = gc_extend(p.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+                        if (u)
+                        {
+                            goto L1;
+                        }
+                    }
+                    newdata = cast(byte *)gc_malloc(newsize + 1, info.attr);
+                    newdata[0 .. size] = p.data[0 .. size];
+                L1: ;
+                }
+            }
+        }
+        else
+        {
+            newdata = cast(byte *)gc_malloc(newsize + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        }
+
+        auto q = initializer.ptr; // pointer to initializer
+
+        if (newsize > size)
+        {
+            if (initsize == 1)
+            {
+                debug(PRINTF) printf("newdata = %p, size = %d, newsize = %d, *q = %d\n", newdata, size, newsize, *cast(byte*)q);
+                newdata[size .. newsize] = *(cast(byte*)q);
+            }
+            else
+            {
+                for (size_t u = size; u < newsize; u += initsize)
+                {
+                    memcpy(newdata + u, q, initsize);
+                }
+            }
+        }
+    }
+    else
+    {
+        newdata = p.data;
+    }
+
+    p.data = newdata;
+    p.length = newlength;
+    return newdata[0 .. newlength];
+
+Loverflow:
+    onOutOfMemoryError();
+    assert(0);
+}
+
+/+
+/**
+ * Append y[] to array x[].
+ * size is size of each array element.
+ */
+extern (C) long _d_arrayappendT(TypeInfo ti, Array *px, byte[] y)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    auto info = gc_query(px.data);
+    auto length = px.length;
+    auto newlength = length + y.length;
+    auto newsize = newlength * sizeelem;
+
+    if (info.size < newsize || info.base != px.data)
+    {   byte* newdata;
+
+        if (info.size >= PAGESIZE && info.base == px.data)
+        {   // Try to extend in-place
+            auto u = gc_extend(px.data, (newsize + 1) - info.size, (newsize + 1) - info.size);
+            if (u)
+            {
+                goto L1;
+            }
+        }
+        newdata = cast(byte *)gc_malloc(newCapacity(newlength, sizeelem) + 1, info.attr);
+        memcpy(newdata, px.data, length * sizeelem);
+        px.data = newdata;
+    }
+  L1:
+    px.length = newlength;
+    memcpy(px.data + length * sizeelem, y.ptr, y.length * sizeelem);
+    return *cast(long*)px;
+}
+
+
+/**
+ *
+ */
+size_t newCapacity(size_t newlength, size_t size)
+{
+    version(none)
+    {
+        size_t newcap = newlength * size;
+    }
+    else
+    {
+        /*
+         * Better version by Dave Fladebo:
+         * This uses an inverse logorithmic algorithm to pre-allocate a bit more
+         * space for larger arrays.
+         * - Arrays smaller than PAGESIZE bytes are left as-is, so for the most
+         * common cases, memory allocation is 1 to 1. The small overhead added
+         * doesn't affect small array perf. (it's virtually the same as
+         * current).
+         * - Larger arrays have some space pre-allocated.
+         * - As the arrays grow, the relative pre-allocated space shrinks.
+         * - The logorithmic algorithm allocates relatively more space for
+         * mid-size arrays, making it very fast for medium arrays (for
+         * mid-to-large arrays, this turns out to be quite a bit faster than the
+         * equivalent realloc() code in C, on Linux at least. Small arrays are
+         * just as fast as GCC).
+         * - Perhaps most importantly, overall memory usage and stress on the GC
+         * is decreased significantly for demanding environments.
+         */
+        size_t newcap = newlength * size;
+        size_t newext = 0;
+
+        if (newcap > PAGESIZE)
+        {
+            //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0)));
+
+            // redo above line using only integer math
+
+            static int log2plus1(size_t c)
+            {   int i;
+
+                if (c == 0)
+                    i = -1;
+                else
+                    for (i = 1; c >>= 1; i++)
+                    {
+                    }
+                return i;
+            }
+
+            /* The following setting for mult sets how much bigger
+             * the new size will be over what is actually needed.
+             * 100 means the same size, more means proportionally more.
+             * More means faster but more memory consumption.
+             */
+            //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap));
+            long mult = 100 + (1000L * size) / log2plus1(newcap);
+
+            // testing shows 1.02 for large arrays is about the point of diminishing return
+            if (mult < 102)
+                mult = 102;
+            newext = cast(size_t)((newcap * mult) / 100);
+            newext -= newext % size;
+            debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size);
+        }
+        newcap = newext > newcap ? newext : newcap;
+        debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
+    }
+    return newcap;
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arrayappendcT(TypeInfo ti, inout byte[] x, ...)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    auto info = gc_query(x.ptr);
+    auto length = x.length;
+    auto newlength = length + 1;
+    auto newsize = newlength * sizeelem;
+
+    assert(info.size == 0 || length * sizeelem <= info.size);
+
+    debug(PRINTF) printf("_d_arrayappendcT(sizeelem = %d, ptr = %p, length = %d, cap = %d)\n", sizeelem, x.ptr, x.length, info.size);
+
+    if (info.size <= newsize || info.base != x.ptr)
+    {   byte* newdata;
+
+        if (info.size >= PAGESIZE && info.base == x.ptr)
+        {   // Try to extend in-place
+            auto u = gc_extend(x.ptr, (newsize + 1) - info.size, (newsize + 1) - info.size);
+            if (u)
+            {
+                goto L1;
+            }
+        }
+        debug(PRINTF) printf("_d_arrayappendcT(length = %d, newlength = %d, cap = %d)\n", length, newlength, info.size);
+        auto newcap = newCapacity(newlength, sizeelem);
+        assert(newcap >= newlength * sizeelem);
+        newdata = cast(byte *)gc_malloc(newcap + 1, info.attr);
+        memcpy(newdata, x.ptr, length * sizeelem);
+        (cast(void**)(&x))[1] = newdata;
+    }
+  L1:
+    byte *argp = cast(byte *)(&ti + 2);
+
+    *cast(size_t *)&x = newlength;
+    x.ptr[length * sizeelem .. newsize] = argp[0 .. sizeelem];
+    assert((cast(size_t)x.ptr & 15) == 0);
+    assert(gc_sizeOf(x.ptr) > x.length * sizeelem);
+    return x;
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arraycatT(TypeInfo ti, byte[] x, byte[] y)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d => %d,%p)\n", x.length, x.ptr, y.length, y.ptr, sizeelem, result.length, result.ptr);
+    assert(result.length == x.length + y.length);
+    for (size_t i = 0; i < x.length * sizeelem; i++)
+        assert((cast(byte*)result)[i] == (cast(byte*)x)[i]);
+    for (size_t i = 0; i < y.length * sizeelem; i++)
+        assert((cast(byte*)result)[x.length * sizeelem + i] == (cast(byte*)y)[i]);
+
+    size_t cap = gc_sizeOf(result.ptr);
+    assert(!cap || cap > result.length * sizeelem);
+}
+body
+{
+    version (none)
+    {
+        /* Cannot use this optimization because:
+         *  char[] a, b;
+         *  char c = 'a';
+         *  b = a ~ c;
+         *  c = 'b';
+         * will change the contents of b.
+         */
+        if (!y.length)
+            return x;
+        if (!x.length)
+            return y;
+    }
+
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p)\n", x.length, x.ptr, y.length, y.ptr);
+    auto sizeelem = ti.next.tsize();            // array element size
+    debug(PRINTF) printf("_d_arraycatT(%d,%p ~ %d,%p sizeelem = %d)\n", x.length, x.ptr, y.length, y.ptr, sizeelem);
+    size_t xlen = x.length * sizeelem;
+    size_t ylen = y.length * sizeelem;
+    size_t len  = xlen + ylen;
+
+    if (!len)
+        return null;
+
+    byte* p = cast(byte*)gc_malloc(len + 1, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    memcpy(p, x.ptr, xlen);
+    memcpy(p + xlen, y.ptr, ylen);
+    p[len] = 0;
+    return p[0 .. x.length + y.length];
+}
+
+
+/**
+ *
+ */
+extern (C) byte[] _d_arraycatnT(TypeInfo ti, uint n, ...)
+{   void* a;
+    size_t length;
+    byte[]* p;
+    uint i;
+    byte[] b;
+    auto size = ti.next.tsize(); // array element size
+
+    p = cast(byte[]*)(&n + 1);
+
+    for (i = 0; i < n; i++)
+    {
+        b = *p++;
+        length += b.length;
+    }
+    if (!length)
+        return null;
+
+    a = gc_malloc(length * size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+    p = cast(byte[]*)(&n + 1);
+
+    uint j = 0;
+    for (i = 0; i < n; i++)
+    {
+        b = *p++;
+        if (b.length)
+        {
+            memcpy(a + j, b.ptr, b.length * size);
+            j += b.length * size;
+        }
+    }
+
+    byte[] result;
+    *cast(int *)&result = length;       // jam length
+    (cast(void **)&result)[1] = a;      // jam ptr
+    return result;
+}
+
+
+/**
+ *
+ */
+extern (C) void* _d_arrayliteralT(TypeInfo ti, size_t length, ...)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    void* result;
+
+    debug(PRINTF) printf("_d_arrayliteralT(sizeelem = %d, length = %d)\n", sizeelem, length);
+    if (length == 0 || sizeelem == 0)
+        result = null;
+    else
+    {
+        result = gc_malloc(length * sizeelem, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+
+        va_list q;
+        va_start!(size_t)(q, length);
+
+        size_t stacksize = (sizeelem + int.sizeof - 1) & ~(int.sizeof - 1);
+
+        if (stacksize == sizeelem)
+        {
+            memcpy(result, q, length * sizeelem);
+        }
+        else
+        {
+            for (size_t i = 0; i < length; i++)
+            {
+                memcpy(result + i * sizeelem, q, sizeelem);
+                q += stacksize;
+            }
+        }
+
+        va_end(q);
+    }
+    return result;
+}
++/
+
+/**
+ * Support for array.dup property.
+ */
+struct Array2
+{
+    size_t length;
+    void*  ptr;
+}
+
+
+/**
+ *
+ */
+extern (C) long _adDupT(TypeInfo ti, Array2 a)
+out (result)
+{
+    auto sizeelem = ti.next.tsize();            // array element size
+    assert(memcmp((*cast(Array2*)&result).ptr, a.ptr, a.length * sizeelem) == 0);
+}
+body
+{
+    Array2 r;
+
+    if (a.length)
+    {
+        auto sizeelem = ti.next.tsize();                // array element size
+        auto size = a.length * sizeelem;
+        r.ptr = gc_malloc(size, !(ti.next.flags() & 1) ? BlkAttr.NO_SCAN : 0);
+        r.length = a.length;
+        memcpy(r.ptr, a.ptr, size);
+    }
+    return *cast(long*)(&r);
+}
+
+
+unittest
+{
+    int[] a;
+    int[] b;
+    int i;
+
+    a = new int[3];
+    a[0] = 1; a[1] = 2; a[2] = 3;
+    b = a.dup;
+    assert(b.length == 3);
+    for (i = 0; i < 3; i++)
+        assert(b[i] == i + 1);
+}
Index: src/compiler/ldc/rt/switch_.d
===================================================================
--- src/compiler/ldc/rt/switch_.d	(revision 0)
+++ src/compiler/ldc/rt/switch_.d	(revision 0)
@@ -0,0 +1,411 @@
+/**
+ * Contains support code for switch blocks using string constants.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.switch_;
+
+private import core.stdc.string;
+
+/******************************************************
+ * Support for switch statements switching on strings.
+ * Input:
+ *      table[]         sorted array of strings generated by compiler
+ *      ca              string to look up in table
+ * Output:
+ *      result          index of match in table[]
+ *                      -1 if not in table
+ */
+
+extern (C):
+
+int _d_switch_string(char[][] table, char[] ca)
+in
+{
+    //printf("in _d_switch_string()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        size_t len1 = table[j - 1].length;
+        size_t len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int ci;
+
+            ci = memcmp(table[j - 1].ptr, table[j].ptr, len1);
+            assert(ci < 0); // ci==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int cj;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   cj = memcmp(table[i].ptr, ca.ptr, ca.length);
+                assert(cj != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                cj = memcmp(table[i].ptr, ca.ptr, ca.length);
+                if (cj == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_string(%.*s)\n", ca);
+    size_t low;
+    size_t high;
+    size_t mid;
+    ptrdiff_t c;
+    char[] pca;
+
+    low = 0;
+    high = table.length;
+
+    version (none)
+    {
+        // Print table
+        printf("ca[] = '%s'\n", cast(char *)ca);
+        for (mid = 0; mid < high; mid++)
+        {
+            pca = table[mid];
+            printf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+        }
+    }
+    if (high &&
+        ca.length >= table[0].length &&
+        ca.length <= table[high - 1].length)
+    {
+        // Looking for 0 length string, which would only be at the beginning
+        if (ca.length == 0)
+            return 0;
+
+        char c1 = ca[0];
+
+        // Do binary search
+        while (low < high)
+        {
+            mid = (low + high) >> 1;
+            pca = table[mid];
+            c = ca.length - pca.length;
+            if (c == 0)
+            {
+                c = cast(ubyte)c1 - cast(ubyte)pca[0];
+                if (c == 0)
+                {
+                    c = memcmp(ca.ptr, pca.ptr, ca.length);
+                    if (c == 0)
+                    {   //printf("found %d\n", mid);
+                        return cast(int)mid;
+                    }
+                }
+            }
+            if (c < 0)
+            {
+                high = mid;
+            }
+            else
+            {
+                low = mid + 1;
+            }
+        }
+    }
+
+    //printf("not found\n");
+    return -1; // not found
+}
+
+unittest
+{
+    switch (cast(char []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
+
+/**********************************
+ * Same thing, but for wide chars.
+ */
+
+int _d_switch_ustring(wchar[][] table, wchar[] ca)
+in
+{
+    //printf("in _d_switch_ustring()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        size_t len1 = table[j - 1].length;
+        size_t len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int c;
+
+            c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof);
+            assert(c < 0);  // c==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int c;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
+                assert(c != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
+                if (c == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_ustring()\n");
+    size_t low;
+    size_t high;
+    size_t mid;
+    ptrdiff_t c;
+    wchar[] pca;
+
+    low = 0;
+    high = table.length;
+
+/*
+    // Print table
+    wprintf("ca[] = '%.*s'\n", ca);
+    for (mid = 0; mid < high; mid++)
+    {
+        pca = table[mid];
+        wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+    }
+*/
+
+    // Do binary search
+    while (low < high)
+    {
+        mid = (low + high) >> 1;
+        pca = table[mid];
+        c = ca.length - pca.length;
+        if (c == 0)
+        {
+            c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof);
+            if (c == 0)
+            {   //printf("found %d\n", mid);
+                return cast(int)mid;
+            }
+        }
+        if (c < 0)
+        {
+            high = mid;
+        }
+        else
+        {
+            low = mid + 1;
+        }
+    }
+    //printf("not found\n");
+    return -1;              // not found
+}
+
+
+unittest
+{
+    switch (cast(wchar []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
+
+
+/**********************************
+ * Same thing, but for wide chars.
+ */
+
+int _d_switch_dstring(dchar[][] table, dchar[] ca)
+in
+{
+    //printf("in _d_switch_dstring()\n");
+    assert(table.length >= 0);
+    assert(ca.length >= 0);
+
+    // Make sure table[] is sorted correctly
+    int j;
+
+    for (j = 1; j < table.length; j++)
+    {
+        size_t len1 = table[j - 1].length;
+        size_t len2 = table[j].length;
+
+        assert(len1 <= len2);
+        if (len1 == len2)
+        {
+            int c;
+
+            c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof);
+            assert(c < 0);  // c==0 means a duplicate
+        }
+    }
+}
+out (result)
+{
+    int i;
+    int c;
+
+    //printf("out _d_switch_string()\n");
+    if (result == -1)
+    {
+        // Not found
+        for (i = 0; i < table.length; i++)
+        {
+            if (table[i].length == ca.length)
+            {   c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
+                assert(c != 0);
+            }
+        }
+    }
+    else
+    {
+        assert(0 <= result && result < table.length);
+        for (i = 0; 1; i++)
+        {
+            assert(i < table.length);
+            if (table[i].length == ca.length)
+            {
+                c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
+                if (c == 0)
+                {
+                    assert(i == result);
+                    break;
+                }
+            }
+        }
+    }
+}
+body
+{
+    //printf("body _d_switch_ustring()\n");
+    size_t low;
+    size_t high;
+    size_t mid;
+    ptrdiff_t c;
+    dchar[] pca;
+
+    low = 0;
+    high = table.length;
+
+/*
+    // Print table
+    wprintf("ca[] = '%.*s'\n", ca);
+    for (mid = 0; mid < high; mid++)
+    {
+        pca = table[mid];
+        wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
+    }
+*/
+
+    // Do binary search
+    while (low < high)
+    {
+        mid = (low + high) >> 1;
+        pca = table[mid];
+        c = ca.length - pca.length;
+        if (c == 0)
+        {
+            c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof);
+            if (c == 0)
+            {   //printf("found %d\n", mid);
+                return cast(int)mid;
+            }
+        }
+        if (c < 0)
+        {
+            high = mid;
+        }
+        else
+        {
+            low = mid + 1;
+        }
+    }
+    //printf("not found\n");
+    return -1; // not found
+}
+
+
+unittest
+{
+    switch (cast(dchar []) "c")
+    {
+         case "coo":
+         default:
+             break;
+    }
+}
Index: src/compiler/ldc/rt/arraybyte.d
===================================================================
--- src/compiler/ldc/rt/arraybyte.d	(revision 0)
+++ src/compiler/ldc/rt/arraybyte.d	(revision 0)
@@ -0,0 +1,1893 @@
+/**
+ * Contains SSE2 and MMX versions of certain operations for char, byte, and
+ * ubyte ('a', 'g' and 'h' suffixes).
+ *
+ * Copyright: Copyright Digital Mars 2008 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, based on code originally written by Burton Radons
+ *
+ *          Copyright Digital Mars 2008 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.arraybyte;
+
+import rt.util.cpuid;
+
+version (unittest)
+{
+    private import core.stdc.stdio : printf;
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 4;
+    bool mmx()      { return cpuid == 1 && rt.util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && rt.util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && rt.util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && rt.util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias rt.util.cpuid.mmx mmx;
+    alias rt.util.cpuid.sse sse;
+    alias rt.util.cpuid.sse2 sse2;
+    alias rt.util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias byte T;
+
+extern (C):
+
+/* ======================================================================== */
+
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_a(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_g(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_h(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_g(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_g(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1088% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startaddsse2u:
+                    add ESI, 64;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM4;
+                    paddb XMM2, XMM4;
+                    paddb XMM3, XMM4;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startaddsse2a:
+                    add ESI, 64;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM4;
+                    paddb XMM2, XMM4;
+                    paddb XMM3, XMM4;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 1000% faster
+        if (mmx() && a.length >= 32)
+        {
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 4;
+            startaddmmx:
+                add ESI, 32;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                paddb MM0, MM4;
+                paddb MM1, MM4;
+                paddb MM2, MM4;
+                paddb MM3, MM4;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startaddmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        /* trying to be fair and treat normal 32-bit cpu the same way as we do
+         * the SIMD units, with unrolled asm.  There's not enough registers,
+         * really.
+         */
+        else
+        if (a.length >= 4)
+        {
+
+            auto n = aptr + (a.length & ~3);
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov CL, value;
+
+                align 4;
+            startadd386:
+                add ESI, 4;
+                mov DX, [EAX];
+                mov BX, [EAX+2];
+                add EAX, 4;
+                add BL, CL;
+                add BH, CL;
+                add DL, CL;
+                add DH, CL;
+                mov [ESI   -4], DX;
+                mov [ESI+2 -4], BX;
+                cmp ESI, EDI;
+                jb startadd386;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ + value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_a(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_g(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_h(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_g(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_g(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceAddSliceAssign_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 5739% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                version (log) printf("\tsse2 unaligned\n");
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 8;
+                startaddlsse2u:
+                    add ESI, 64;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    movdqu XMM4, [ECX];
+                    movdqu XMM5, [ECX+16];
+                    movdqu XMM6, [ECX+32];
+                    movdqu XMM7, [ECX+48];
+                    add ECX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM5;
+                    paddb XMM2, XMM6;
+                    paddb XMM3, XMM7;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddlsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                version (log) printf("\tsse2 aligned\n");
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 8;
+                startaddlsse2a:
+                    add ESI, 64;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    movdqa XMM4, [ECX];
+                    movdqa XMM5, [ECX+16];
+                    movdqa XMM6, [ECX+32];
+                    movdqa XMM7, [ECX+48];
+                    add ECX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM5;
+                    paddb XMM2, XMM6;
+                    paddb XMM3, XMM7;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddlsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 4428% faster
+        if (mmx() && a.length >= 32)
+        {
+            version (log) printf("\tmmx\n");
+            auto n = aptr + (a.length & ~31);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startaddlmmx:
+                add ESI, 32;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                movq MM4, [ECX];
+                movq MM5, [ECX+8];
+                movq MM6, [ECX+16];
+                movq MM7, [ECX+24];
+                add ECX, 32;
+                paddb MM0, MM4;
+                paddb MM1, MM5;
+                paddb MM2, MM6;
+                paddb MM3, MM7;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startaddlmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    version (log) if (aptr < aend) printf("\tbase\n");
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ + *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_a(T[] a, T value)
+{
+    return _arrayExpSliceAddass_g(a, value);
+}
+
+T[] _arrayExpSliceAddass_h(T[] a, T value)
+{
+    return _arrayExpSliceAddass_g(a, value);
+}
+
+T[] _arrayExpSliceAddass_g(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_g(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1578% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startaddasssse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM2, [ESI+32];
+                    movdqu XMM3, [ESI+48];
+                    add ESI, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM4;
+                    paddb XMM2, XMM4;
+                    paddb XMM3, XMM4;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddasssse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startaddasssse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM2, [ESI+32];
+                    movdqa XMM3, [ESI+48];
+                    add ESI, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM4;
+                    paddb XMM2, XMM4;
+                    paddb XMM3, XMM4;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddasssse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 1721% faster
+        if (mmx() && a.length >= 32)
+        {
+
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 8;
+            startaddassmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                add ESI, 32;
+                paddb MM0, MM4;
+                paddb MM1, MM4;
+                paddb MM2, MM4;
+                paddb MM3, MM4;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startaddassmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_a(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_g(a, b);
+}
+
+T[] _arraySliceSliceAddass_h(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_g(a, b);
+}
+
+T[] _arraySliceSliceAddass_g(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 4727% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 8;
+                startaddasslsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM2, [ESI+32];
+                    movdqu XMM3, [ESI+48];
+                    add ESI, 64;
+                    movdqu XMM4, [ECX];
+                    movdqu XMM5, [ECX+16];
+                    movdqu XMM6, [ECX+32];
+                    movdqu XMM7, [ECX+48];
+                    add ECX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM5;
+                    paddb XMM2, XMM6;
+                    paddb XMM3, XMM7;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddasslsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 8;
+                startaddasslsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM2, [ESI+32];
+                    movdqa XMM3, [ESI+48];
+                    add ESI, 64;
+                    movdqa XMM4, [ECX];
+                    movdqa XMM5, [ECX+16];
+                    movdqa XMM6, [ECX+32];
+                    movdqa XMM7, [ECX+48];
+                    add ECX, 64;
+                    paddb XMM0, XMM4;
+                    paddb XMM1, XMM5;
+                    paddb XMM2, XMM6;
+                    paddb XMM3, XMM7;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startaddasslsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 3059% faster
+        if (mmx() && a.length >= 32)
+        {
+
+            auto n = aptr + (a.length & ~31);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 8;
+            startaddasslmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                add ESI, 32;
+                movq MM4, [ECX];
+                movq MM5, [ECX+8];
+                movq MM6, [ECX+16];
+                movq MM7, [ECX+24];
+                add ECX, 32;
+                paddb MM0, MM4;
+                paddb MM1, MM5;
+                paddb MM2, MM6;
+                paddb MM3, MM7;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startaddasslmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_a(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_g(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_h(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_g(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_g(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1189% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubsse2u:
+                    add ESI, 64;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM4;
+                    psubb XMM2, XMM4;
+                    psubb XMM3, XMM4;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubsse2a:
+                    add ESI, 64;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM4;
+                    psubb XMM2, XMM4;
+                    psubb XMM3, XMM4;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 1079% faster
+        if (mmx() && a.length >= 32)
+        {
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 4;
+            startsubmmx:
+                add ESI, 32;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                psubb MM0, MM4;
+                psubb MM1, MM4;
+                psubb MM2, MM4;
+                psubb MM3, MM4;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startsubmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        // trying to be fair and treat normal 32-bit cpu the same way as we do the SIMD units, with unrolled asm.  There's not enough registers, really.
+        else
+        if (a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov CL, value;
+
+                align 4;
+            startsub386:
+                add ESI, 4;
+                mov DX, [EAX];
+                mov BX, [EAX+2];
+                add EAX, 4;
+                sub BL, CL;
+                sub BH, CL;
+                sub DL, CL;
+                sub DH, CL;
+                mov [ESI   -4], DX;
+                mov [ESI+2 -4], BX;
+                cmp ESI, EDI;
+                jb startsub386;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ - value);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] = b[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, c[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_a(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_g(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_h(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_g(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_g(T[] a, T[] b, T value)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 8748% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubrsse2u:
+                    add ESI, 64;
+                    movdqa XMM5, XMM4;
+                    movdqa XMM6, XMM4;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    psubb XMM5, XMM0;
+                    psubb XMM6, XMM1;
+                    movdqu [ESI   -64], XMM5;
+                    movdqu [ESI+16-64], XMM6;
+                    movdqa XMM5, XMM4;
+                    movdqa XMM6, XMM4;
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    psubb XMM5, XMM2;
+                    psubb XMM6, XMM3;
+                    movdqu [ESI+32-64], XMM5;
+                    movdqu [ESI+48-64], XMM6;
+                    cmp ESI, EDI;
+                    jb startsubrsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubrsse2a:
+                    add ESI, 64;
+                    movdqa XMM5, XMM4;
+                    movdqa XMM6, XMM4;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    psubb XMM5, XMM0;
+                    psubb XMM6, XMM1;
+                    movdqa [ESI   -64], XMM5;
+                    movdqa [ESI+16-64], XMM6;
+                    movdqa XMM5, XMM4;
+                    movdqa XMM6, XMM4;
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    psubb XMM5, XMM2;
+                    psubb XMM6, XMM3;
+                    movdqa [ESI+32-64], XMM5;
+                    movdqa [ESI+48-64], XMM6;
+                    cmp ESI, EDI;
+                    jb startsubrsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 7397% faster
+        if (mmx() && a.length >= 32)
+        {
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 4;
+            startsubrmmx:
+                add ESI, 32;
+                movq MM5, MM4;
+                movq MM6, MM4;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                psubb MM5, MM0;
+                psubb MM6, MM1;
+                movq [ESI   -32], MM5;
+                movq [ESI+8 -32], MM6;
+                movq MM5, MM4;
+                movq MM6, MM4;
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                psubb MM5, MM2;
+                psubb MM6, MM3;
+                movq [ESI+16-32], MM5;
+                movq [ESI+24-32], MM6;
+                cmp ESI, EDI;
+                jb startsubrmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(value - *bptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] = 6 - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - b[i]))
+                {
+                    printf("[%d]: %d != 6 - %d\n", i, c[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_a(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_g(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_h(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_g(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_g(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 5756% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 8;
+                startsublsse2u:
+                    add ESI, 64;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM2, [EAX+32];
+                    movdqu XMM3, [EAX+48];
+                    add EAX, 64;
+                    movdqu XMM4, [ECX];
+                    movdqu XMM5, [ECX+16];
+                    movdqu XMM6, [ECX+32];
+                    movdqu XMM7, [ECX+48];
+                    add ECX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM5;
+                    psubb XMM2, XMM6;
+                    psubb XMM3, XMM7;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsublsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 8;
+                startsublsse2a:
+                    add ESI, 64;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM2, [EAX+32];
+                    movdqa XMM3, [EAX+48];
+                    add EAX, 64;
+                    movdqa XMM4, [ECX];
+                    movdqa XMM5, [ECX+16];
+                    movdqa XMM6, [ECX+32];
+                    movdqa XMM7, [ECX+48];
+                    add ECX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM5;
+                    psubb XMM2, XMM6;
+                    psubb XMM3, XMM7;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsublsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 4428% faster
+        if (mmx() && a.length >= 32)
+        {
+            auto n = aptr + (a.length & ~31);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 8;
+            startsublmmx:
+                add ESI, 32;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                add EAX, 32;
+                movq MM4, [ECX];
+                movq MM5, [ECX+8];
+                movq MM6, [ECX+16];
+                movq MM7, [ECX+24];
+                add ECX, 32;
+                psubb MM0, MM4;
+                psubb MM1, MM5;
+                psubb MM2, MM6;
+                psubb MM3, MM7;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startsublmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = cast(T)(*bptr++ - *cptr++);
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_a(T[] a, T value)
+{
+    return _arrayExpSliceMinass_g(a, value);
+}
+
+T[] _arrayExpSliceMinass_h(T[] a, T value)
+{
+    return _arrayExpSliceMinass_g(a, value);
+}
+
+T[] _arrayExpSliceMinass_g(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_g(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1577% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+            l |= (l << 16);
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubasssse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM2, [ESI+32];
+                    movdqu XMM3, [ESI+48];
+                    add ESI, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM4;
+                    psubb XMM2, XMM4;
+                    psubb XMM3, XMM4;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubasssse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 8;
+                startsubasssse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM2, [ESI+32];
+                    movdqa XMM3, [ESI+48];
+                    add ESI, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM4;
+                    psubb XMM2, XMM4;
+                    psubb XMM3, XMM4;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubasssse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 1577% faster
+        if (mmx() && a.length >= 32)
+        {
+
+            auto n = aptr + (a.length & ~31);
+
+            uint l = cast(ubyte) value;
+            l |= (l << 8);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movd MM4, l;
+                pshufw MM4, MM4, 0;
+
+                align 8;
+            startsubassmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                add ESI, 32;
+                psubb MM0, MM4;
+                psubb MM1, MM4;
+                psubb MM2, MM4;
+                psubb MM3, MM4;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startsubassmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_a(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_g(a, b);
+}
+
+T[] _arraySliceSliceMinass_h(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_g(a, b);
+}
+
+T[] _arraySliceSliceMinass_g(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_g()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 4800% faster
+        if (sse2() && a.length >= 64)
+        {
+            auto n = aptr + (a.length & ~63);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 8;
+                startsubasslsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM2, [ESI+32];
+                    movdqu XMM3, [ESI+48];
+                    add ESI, 64;
+                    movdqu XMM4, [ECX];
+                    movdqu XMM5, [ECX+16];
+                    movdqu XMM6, [ECX+32];
+                    movdqu XMM7, [ECX+48];
+                    add ECX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM5;
+                    psubb XMM2, XMM6;
+                    psubb XMM3, XMM7;
+                    movdqu [ESI   -64], XMM0;
+                    movdqu [ESI+16-64], XMM1;
+                    movdqu [ESI+32-64], XMM2;
+                    movdqu [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubasslsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 8;
+                startsubasslsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM2, [ESI+32];
+                    movdqa XMM3, [ESI+48];
+                    add ESI, 64;
+                    movdqa XMM4, [ECX];
+                    movdqa XMM5, [ECX+16];
+                    movdqa XMM6, [ECX+32];
+                    movdqa XMM7, [ECX+48];
+                    add ECX, 64;
+                    psubb XMM0, XMM4;
+                    psubb XMM1, XMM5;
+                    psubb XMM2, XMM6;
+                    psubb XMM3, XMM7;
+                    movdqa [ESI   -64], XMM0;
+                    movdqa [ESI+16-64], XMM1;
+                    movdqa [ESI+32-64], XMM2;
+                    movdqa [ESI+48-64], XMM3;
+                    cmp ESI, EDI;
+                    jb startsubasslsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 3107% faster
+        if (mmx() && a.length >= 32)
+        {
+
+            auto n = aptr + (a.length & ~31);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 8;
+            startsubasslmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                add ESI, 32;
+                movq MM4, [ECX];
+                movq MM5, [ECX+8];
+                movq MM6, [ECX+16];
+                movq MM7, [ECX+24];
+                add ECX, 32;
+                psubb MM0, MM4;
+                psubb MM1, MM5;
+                psubb MM2, MM6;
+                psubb MM3, MM7;
+                movq [ESI   -32], MM0;
+                movq [ESI+8 -32], MM1;
+                movq [ESI+16-32], MM2;
+                movq [ESI+24-32], MM3;
+                cmp ESI, EDI;
+                jb startsubasslmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinass_g unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
Index: src/compiler/ldc/rt/arrayfloat.d
===================================================================
--- src/compiler/ldc/rt/arrayfloat.d	(revision 0)
+++ src/compiler/ldc/rt/arrayfloat.d	(revision 0)
@@ -0,0 +1,2309 @@
+/**
+ * Contains SSE2 and MMX versions of certain operations for float.
+ *
+ * Copyright: Copyright Digital Mars 2008 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, based on code originally written by Burton Radons
+ *
+ *          Copyright Digital Mars 2008 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.arrayfloat;
+
+private import rt.util.cpuid;
+
+version (unittest)
+{
+    private import core.stdc.stdio : printf;
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 5;
+    bool mmx()      { return cpuid == 1 && rt.util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && rt.util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && rt.util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && rt.util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias rt.util.cpuid.mmx mmx;
+    alias rt.util.cpuid.sse sse;
+    alias rt.util.cpuid.sse2 sse2;
+    alias rt.util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias float T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_f(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceAddSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 834% faster
+        if (sse() && b.length >= 16)
+        {
+            version (log) printf("\tsse unaligned\n");
+            auto n = aptr + (b.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ESI, 64;
+                addps XMM0, XMM4;
+                addps XMM1, XMM5;
+                addps XMM2, XMM6;
+                addps XMM3, XMM7;
+                add ECX, 64;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is only 13% faster
+        if (amd3dnow() && b.length >= 8)
+        {
+            version (log) printf("\tamd3dnow\n");
+            auto n = aptr + (b.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+
+                align 4;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfadd MM0, [ECX];
+                pfadd MM1, [ECX+8];
+                pfadd MM2, [ECX+16];
+                pfadd MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ECX, 32;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    // Handle remainder
+    version (log) if (aptr < aend) printf("\tbase\n");
+    while (aptr < aend)
+        *aptr++ = *bptr++ + *cptr++;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_f(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 834% faster
+        if (sse() && b.length >= 16)
+        {
+            auto n = aptr + (b.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ESI, 64;
+                subps XMM0, XMM4;
+                subps XMM1, XMM5;
+                subps XMM2, XMM6;
+                subps XMM3, XMM7;
+                add ECX, 64;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is only 13% faster
+        if (amd3dnow() && b.length >= 8)
+        {
+            auto n = aptr + (b.length & ~7);
+
+            asm
+            {
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+
+                align 4;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfsub MM0, [ECX];
+                pfsub MM1, [ECX+8];
+                pfsub MM2, [ECX+16];
+                pfsub MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ECX, 32;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ = *bptr++ - *cptr++;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %g != %gd - %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_f(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 665% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                addps XMM0, XMM4;
+                addps XMM1, XMM4;
+                addps XMM2, XMM4;
+                addps XMM3, XMM4;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 69% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfadd MM0, MM4;
+                pfadd MM1, MM4;
+                pfadd MM2, MM4;
+                pfadd MM3, MM4;
+                movq [ESI],    MM0;
+                movq [ESI+8],  MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ + value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %g != %g + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_f(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 302% faster
+        if (sse() && a.length >= 16)
+        {
+            // align pointer
+            auto n = cast(T*)((cast(uint)aptr + 15) & ~15);
+            while (aptr < n)
+                *aptr++ += value;
+            n = cast(T*)((cast(uint)aend) & ~15);
+            if (aptr < n)
+
+            // Aligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movaps XMM0, [ESI];
+                movaps XMM1, [ESI+16];
+                movaps XMM2, [ESI+32];
+                movaps XMM3, [ESI+48];
+                add ESI, 64;
+                addps XMM0, XMM4;
+                addps XMM1, XMM4;
+                addps XMM2, XMM4;
+                addps XMM3, XMM4;
+                movaps [ESI+ 0-64], XMM0;
+                movaps [ESI+16-64], XMM1;
+                movaps [ESI+32-64], XMM2;
+                movaps [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+        else
+        // 3DNow! version is 63% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start3dnow:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfadd MM0, MM4;
+                pfadd MM1, MM4;
+                pfadd MM2, MM4;
+                pfadd MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %g != %g + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_f(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 468% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [ESI];
+                movups XMM1, [ESI+16];
+                movups XMM2, [ESI+32];
+                movups XMM3, [ESI+48];
+                add ESI, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ECX, 64;
+                addps XMM0, XMM4;
+                addps XMM1, XMM5;
+                addps XMM2, XMM6;
+                addps XMM3, XMM7;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is 57% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr]; // destination operand
+                mov EDI, dword ptr [n];    // end comparison
+                mov ECX, dword ptr [bptr]; // right operand
+
+                align 4;
+            start3dnow:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfadd MM0, [ECX];
+                pfadd MM1, [ECX+8];
+                pfadd MM2, [ECX+16];
+                pfadd MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add ECX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+                mov dword ptr [bptr], ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_f(T[] a, T value, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 622% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                subps XMM0, XMM4;
+                subps XMM1, XMM4;
+                subps XMM2, XMM4;
+                subps XMM3, XMM4;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 67% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            T[2] w;
+
+            w[0] = w[1] = value;
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                mov EAX, dword ptr [bptr];
+                movq MM4, qword ptr [w];
+
+                align 8;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfsub MM0, MM4;
+                pfsub MM1, MM4;
+                pfsub MM2, MM4;
+                pfsub MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+                mov dword ptr [bptr], EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ - value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_f(T[] a, T[] b, T value)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 690% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movaps XMM5, XMM4;
+                movaps XMM6, XMM4;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                subps XMM5, XMM0;
+                subps XMM6, XMM1;
+                movups [ESI+ 0-64], XMM5;
+                movups [ESI+16-64], XMM6;
+                movaps XMM5, XMM4;
+                movaps XMM6, XMM4;
+                subps XMM5, XMM2;
+                subps XMM6, XMM3;
+                movups [ESI+32-64], XMM5;
+                movups [ESI+48-64], XMM6;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 67% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start3dnow:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfsubr MM0, MM4;
+                pfsubr MM1, MM4;
+                pfsubr MM2, MM4;
+                pfsubr MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start3dnow;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = value - *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = 6 - a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - a[i]))
+                {
+                    printf("[%d]: %g != 6 - %g\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_f(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 304% faster
+        if (sse() && a.length >= 16)
+        {
+            // align pointer
+            auto n = cast(T*)((cast(uint)aptr + 15) & ~15);
+            while (aptr < n)
+                *aptr++ -= value;
+            n = cast(T*)((cast(uint)aend) & ~15);
+            if (aptr < n)
+
+            // Aligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movaps XMM0, [ESI];
+                movaps XMM1, [ESI+16];
+                movaps XMM2, [ESI+32];
+                movaps XMM3, [ESI+48];
+                add ESI, 64;
+                subps XMM0, XMM4;
+                subps XMM1, XMM4;
+                subps XMM2, XMM4;
+                subps XMM3, XMM4;
+                movaps [ESI+ 0-64], XMM0;
+                movaps [ESI+16-64], XMM1;
+                movaps [ESI+32-64], XMM2;
+                movaps [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+        else
+        // 3DNow! version is 63% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfsub MM0, MM4;
+                pfsub MM1, MM4;
+                pfsub MM2, MM4;
+                pfsub MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceminass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_f(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 468% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [ESI];
+                movups XMM1, [ESI+16];
+                movups XMM2, [ESI+32];
+                movups XMM3, [ESI+48];
+                add ESI, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ECX, 64;
+                subps XMM0, XMM4;
+                subps XMM1, XMM5;
+                subps XMM2, XMM6;
+                subps XMM3, XMM7;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is 57% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr]; // destination operand
+                mov EDI, dword ptr [n]; // end comparison
+                mov ECX, dword ptr [bptr]; // right operand
+
+                align 4;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfsub MM0, [ECX];
+                pfsub MM1, [ECX+8];
+                pfsub MM2, [ECX+16];
+                pfsub MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add ECX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAssign_f(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMulSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 607% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM4;
+                mulps XMM2, XMM4;
+                mulps XMM3, XMM4;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 69% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                mov EAX, dword ptr [bptr];
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfmul MM0, MM4;
+                pfmul MM1, MM4;
+                pfmul MM2, MM4;
+                pfmul MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * c[]
+ */
+
+T[] _arraySliceSliceMulSliceAssign_f(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceMulSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 833% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add ESI, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add EAX, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM5;
+                mulps XMM2, XMM6;
+                mulps XMM3, XMM7;
+                add ECX, 64;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is only 13% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr]; // destination operand
+                mov EDI, dword ptr [n]; // end comparison
+                mov EAX, dword ptr [bptr]; // left operand
+                mov ECX, dword ptr [cptr]; // right operand
+
+                align 4;
+            start:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfmul MM0, [ECX];
+                pfmul MM1, [ECX+8];
+                pfmul MM2, [ECX+16];
+                pfmul MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ECX, 32;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * b[i]))
+                {
+                    printf("[%d]: %g != %g * %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= value
+ */
+
+T[] _arrayExpSliceMulass_f(T[] a, T value)
+{
+    //printf("_arrayExpSliceMulass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 303% faster
+        if (sse() && a.length >= 16)
+        {
+            // align pointer
+            auto n = cast(T*)((cast(uint)aptr + 15) & ~15);
+            while (aptr < n)
+                *aptr++ *= value;
+            n = cast(T*)((cast(uint)aend) & ~15);
+            if (aptr < n)
+
+            // Aligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, value;
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movaps XMM0, [ESI];
+                movaps XMM1, [ESI+16];
+                movaps XMM2, [ESI+32];
+                movaps XMM3, [ESI+48];
+                add ESI, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM4;
+                mulps XMM2, XMM4;
+                mulps XMM3, XMM4;
+                movaps [ESI+ 0-64], XMM0;
+                movaps [ESI+16-64], XMM1;
+                movaps [ESI+32-64], XMM2;
+                movaps [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+        else
+        // 3DNow! version is 63% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            ulong w = *cast(uint *) &value;
+            ulong v = w | (w << 32L);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                movq MM4, qword ptr [v];
+
+                align 8;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfmul MM0, MM4;
+                pfmul MM1, MM4;
+                pfmul MM2, MM4;
+                pfmul MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= b[]
+ */
+
+T[] _arraySliceSliceMulass_f(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMulass_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 525% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movups XMM0, [ESI];
+                movups XMM1, [ESI+16];
+                movups XMM2, [ESI+32];
+                movups XMM3, [ESI+48];
+                add ESI, 64;
+                movups XMM4, [ECX];
+                movups XMM5, [ECX+16];
+                movups XMM6, [ECX+32];
+                movups XMM7, [ECX+48];
+                add ECX, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM5;
+                mulps XMM2, XMM6;
+                mulps XMM3, XMM7;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+        else
+        // 3DNow! version is 57% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            asm
+            {
+                mov ESI, dword ptr [aptr]; // destination operand
+                mov EDI, dword ptr [n]; // end comparison
+                mov ECX, dword ptr [bptr]; // right operand
+
+                align 4;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfmul MM0, [ECX];
+                pfmul MM1, [ECX+8];
+                pfmul MM2, [ECX+16];
+                pfmul MM3, [ECX+24];
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add ECX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+                mov dword ptr [bptr], ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] / value
+ */
+
+T[] _arraySliceExpDivSliceAssign_f(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpDivSliceAssign_f()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    /* Multiplying by the reciprocal is faster, but does
+     * not produce as accurate an answer.
+     */
+    T recip = cast(T)1 / value;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 587% faster
+        if (sse() && a.length >= 16)
+        {
+            auto n = aptr + (a.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, recip;
+                //movss XMM4, value
+                //rcpss XMM4, XMM4
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movups XMM0, [EAX];
+                movups XMM1, [EAX+16];
+                movups XMM2, [EAX+32];
+                movups XMM3, [EAX+48];
+                add EAX, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM4;
+                mulps XMM2, XMM4;
+                mulps XMM3, XMM4;
+                //divps XMM0, XMM4;
+                //divps XMM1, XMM4;
+                //divps XMM2, XMM4;
+                //divps XMM3, XMM4;
+                movups [ESI+ 0-64], XMM0;
+                movups [ESI+16-64], XMM1;
+                movups [ESI+32-64], XMM2;
+                movups [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        // 3DNow! version is 72% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            T[2] w = void;
+
+            w[0] = recip;
+            w[1] = recip;
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                mov EAX, dword ptr [bptr];
+                movq MM4, qword ptr [w];
+
+                align 8;
+            start:
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                movq MM2, [EAX+16];
+                movq MM3, [EAX+24];
+                pfmul MM0, MM4;
+                pfmul MM1, MM4;
+                pfmul MM2, MM4;
+                pfmul MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                add EAX, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+                mov dword ptr [bptr], EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * recip;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpDivSliceAssign_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] / 8;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] / 8))
+                {
+                    printf("[%d]: %g != %g / 8\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] /= value
+ */
+
+T[] _arrayExpSliceDivass_f(T[] a, T value)
+{
+    //printf("_arrayExpSliceDivass_f(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    /* Multiplying by the reciprocal is faster, but does
+     * not produce as accurate an answer.
+     */
+    T recip = cast(T)1 / value;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE version is 245% faster
+        if (sse() && a.length >= 16)
+        {
+            // align pointer
+            auto n = cast(T*)((cast(uint)aptr + 15) & ~15);
+            while (aptr < n)
+                *aptr++ *= recip;
+            n = cast(T*)((cast(uint)aend) & ~15);
+            if (aptr < n)
+
+            // Aligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movss XMM4, recip;
+                //movss XMM4, value
+                //rcpss XMM4, XMM4
+                shufps XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movaps XMM0, [ESI];
+                movaps XMM1, [ESI+16];
+                movaps XMM2, [ESI+32];
+                movaps XMM3, [ESI+48];
+                add ESI, 64;
+                mulps XMM0, XMM4;
+                mulps XMM1, XMM4;
+                mulps XMM2, XMM4;
+                mulps XMM3, XMM4;
+                //divps XMM0, XMM4;
+                //divps XMM1, XMM4;
+                //divps XMM2, XMM4;
+                //divps XMM3, XMM4;
+                movaps [ESI+ 0-64], XMM0;
+                movaps [ESI+16-64], XMM1;
+                movaps [ESI+32-64], XMM2;
+                movaps [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+        else
+        // 3DNow! version is 57% faster
+        if (amd3dnow() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            T[2] w = void;
+
+            w[0] = w[1] = recip;
+
+            asm
+            {
+                mov ESI, dword ptr [aptr];
+                mov EDI, dword ptr [n];
+                movq MM4, qword ptr [w];
+
+                align 8;
+            start:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                movq MM2, [ESI+16];
+                movq MM3, [ESI+24];
+                pfmul MM0, MM4;
+                pfmul MM1, MM4;
+                pfmul MM2, MM4;
+                pfmul MM3, MM4;
+                movq [ESI], MM0;
+                movq [ESI+8], MM1;
+                movq [ESI+16], MM2;
+                movq [ESI+24], MM3;
+                add ESI, 32;
+                cmp ESI, EDI;
+                jb start;
+
+                emms;
+                mov dword ptr [aptr], ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= recip;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceDivass_f unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] /= 8;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] / 8))
+                {
+                    printf("[%d]: %g != %g / 8\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[] * value
+ */
+
+T[] _arraySliceExpMulSliceMinass_f(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAddass_f(a, -value, b);
+}
+
+/***********************
+ * Computes:
+ *      a[] += b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAddass_f(T[] a, T value, T[] b)
+in
+{
+        assert(a.length == b.length);
+        assert(disjoint(a, b));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ += *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAddass_f unittest\n");
+
+    cpuid = 1;
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 1; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]);
+                if (c[i] != cast(T)(b[i] + a[i] * 6))
+                {
+                    printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
Index: src/compiler/ldc/rt/arraycat.d
===================================================================
--- src/compiler/ldc/rt/arraycat.d	(revision 0)
+++ src/compiler/ldc/rt/arraycat.d	(revision 0)
@@ -0,0 +1,42 @@
+/**
+ * Implementation of array copy support routines.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.arraycat;
+
+private
+{
+    import core.stdc.string;
+    debug import core.stdc.stdio;
+}
+
+extern (C):
+
+byte[] _d_arraycopy(size_t size, byte[] from, byte[] to)
+{
+    debug printf("f = %p,%d, t = %p,%d, size = %d\n",
+                 from.ptr, from.length, to.ptr, to.length, size);
+
+    if (to.length != from.length)
+    {
+        throw new Exception("lengths don't match for array copy");
+    }
+    else if (to.ptr + to.length * size <= from.ptr ||
+             from.ptr + from.length * size <= to.ptr)
+    {
+        memcpy(to.ptr, from.ptr, to.length * size);
+    }
+    else
+    {
+        throw new Exception("overlapping array copy");
+    }
+    return to;
+}
Index: src/compiler/ldc/rt/aApplyR.d
===================================================================
--- src/compiler/ldc/rt/aApplyR.d	(revision 0)
+++ src/compiler/ldc/rt/aApplyR.d	(revision 0)
@@ -0,0 +1,957 @@
+/**
+ * This code handles decoding UTF strings for foreach_reverse loops.  There are
+ * 6 combinations of conversions between char, wchar, and dchar, and 2 of each
+ * of those.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.aApplyR;
+
+/* This code handles decoding UTF strings for foreach_reverse loops.
+ * There are 6 combinations of conversions between char, wchar,
+ * and dchar, and 2 of each of those.
+ */
+
+private import rt.util.utf;
+
+/**********************************************/
+/* 1 argument versions */
+
+// dg is D, but _aApplyRcd() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d & 0x80)
+        {   char c = cast(char)d;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+        }
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcd1.unittest\n");
+
+    auto s = "hello"c[];
+    int i;
+
+    foreach_reverse(dchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(dchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == '\U00100456'); break;
+            case 2:     assert(d == '\u1234'); break;
+            case 3:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwd1.unittest\n");
+
+    auto s = "hello"w[];
+    int i;
+
+    foreach_reverse(dchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(dchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == '\U00100456'); break;
+            case 2:     assert(d == '\u1234'); break;
+            case 3:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        wchar w;
+
+        i--;
+        w = aa[i];
+        if (w & 0x80)
+        {   char c = cast(char)w;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcw1.unittest\n");
+
+    auto s = "hello"c[];
+    int i;
+
+    foreach_reverse(wchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(wchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xDBC1); break;
+            case 2:     assert(d == 0xDC56); break;
+            case 3:     assert(d == 0x1234); break;
+            case 4:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        char c;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        c = cast(char)d;
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwc1.unittest\n");
+
+    auto s = "hello"w[];
+    int i;
+
+    foreach_reverse(char d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(char d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xF4); break;
+            case 2:     assert(d == 0x80); break;
+            case 3:     assert(d == 0x91); break;
+            case 4:     assert(d == 0x96); break;
+            case 5:     assert(d == 0xE1); break;
+            case 6:     assert(d == 0x88); break;
+            case 7:     assert(d == 0xB4); break;
+            case 8:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0;)
+    {   dchar d = aa[--i];
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {
+            c = cast(char)d;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdc1.unittest\n");
+
+    auto s = "hello"d[];
+    int i;
+
+    foreach_reverse(char d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(char d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xF4); break;
+            case 2:     assert(d == 0x80); break;
+            case 3:     assert(d == 0x91); break;
+            case 4:     assert(d == 0x96); break;
+            case 5:     assert(d == 0xE1); break;
+            case 6:     assert(d == 0x88); break;
+            case 7:     assert(d == 0xB4); break;
+            case 8:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdw1.unittest\n");
+
+    auto s = "hello"d[];
+    int i;
+
+    foreach_reverse(wchar d; s)
+    {
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(wchar d; s)
+    {
+        //printf("i = %d, d = %x\n", i, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); break;
+            case 1:     assert(d == 0xDBC1); break;
+            case 2:     assert(d == 0xDC56); break;
+            case 3:     assert(d == 0x1234); break;
+            case 4:     assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+
+/****************************************************************************/
+/* 2 argument versions */
+
+// dg is D, but _aApplyRcd2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
+    for (i = len; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d & 0x80)
+        {   char c = cast(char)d;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+        }
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcd2.unittest\n");
+
+    auto s = "hello"c[];
+    int i;
+
+    foreach_reverse(k, dchar d; s)
+    {
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(d == 'b'); assert(k == 8); break;
+            case 1:     assert(d == '\U00100456'); assert(k == 4); break;
+            case 2:     assert(d == '\u1234'); assert(k == 1); break;
+            case 3:     assert(d == 'a'); assert(k == 0); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwd2.unittest\n");
+
+    auto s = "hello"w[];
+    int i;
+
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, dchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 4); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == '\U00100456'); break;
+            case 2:     assert(k == 1); assert(d == '\u1234'); break;
+            case 3:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 4);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        wchar w;
+
+        i--;
+        w = aa[i];
+        if (w & 0x80)
+        {   char c = cast(char)w;
+            uint j;
+            uint m = 0x3F;
+            d = 0;
+            while ((c & 0xC0) != 0xC0)
+            {   if (i == 0)
+                    onUnicodeError("Invalid UTF-8 sequence", 0);
+                i--;
+                d |= (c & 0x3F) << j;
+                j += 6;
+                m >>= 1;
+                c = aa[i];
+            }
+            d |= (c & m) << j;
+
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(&i, cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRcw2.unittest\n");
+
+    auto s = "hello"c[];
+    int i;
+
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 8); assert(d == 'b'); break;
+            case 1:     assert(k == 4); assert(d == 0xDBC1); break;
+            case 2:     assert(k == 4); assert(d == 0xDC56); break;
+            case 3:     assert(k == 1); assert(d == 0x1234); break;
+            case 4:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d;
+        char c;
+
+        i--;
+        d = aa[i];
+        if (d >= 0xDC00 && d <= 0xDFFF)
+        {   if (i == 0)
+                onUnicodeError("Invalid UTF-16 sequence", 0);
+            i--;
+            d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
+        }
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        c = cast(char)d;
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRwc2.unittest\n");
+
+    auto s = "hello"w[];
+    int i;
+
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 4); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xF4); break;
+            case 2:     assert(k == 2); assert(d == 0x80); break;
+            case 3:     assert(k == 2); assert(d == 0x91); break;
+            case 4:     assert(k == 2); assert(d == 0x96); break;
+            case 5:     assert(k == 1); assert(d == 0xE1); break;
+            case 6:     assert(k == 1); assert(d == 0x88); break;
+            case 7:     assert(k == 1); assert(d == 0xB4); break;
+            case 8:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)d;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdc2.unittest\n");
+
+    auto s = "hello"d[];
+    int i;
+
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, char d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 3); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xF4); break;
+            case 2:     assert(k == 2); assert(d == 0x80); break;
+            case 3:     assert(k == 2); assert(d == 0x91); break;
+            case 4:     assert(k == 2); assert(d == 0x96); break;
+            case 5:     assert(k == 1); assert(d == 0xE1); break;
+            case 6:     assert(k == 1); assert(d == 0x88); break;
+            case 7:     assert(k == 1); assert(d == 0xB4); break;
+            case 8:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 9);
+}
+
+/*****************************/
+
+extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
+    for (size_t i = aa.length; i != 0; )
+    {   dchar d = aa[--i];
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(&i, cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+unittest
+{
+    debug(apply) printf("_aApplyRdw2.unittest\n");
+
+    auto s = "hello"d[];
+    int i;
+
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        assert(k == 4 - i);
+        switch (i)
+        {
+            case 0:     assert(d == 'o'); break;
+            case 1:     assert(d == 'l'); break;
+            case 2:     assert(d == 'l'); break;
+            case 3:     assert(d == 'e'); break;
+            case 4:     assert(d == 'h'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+
+    s = "a\u1234\U00100456b";
+    i = 0;
+    foreach_reverse(k, wchar d; s)
+    {
+        //printf("i = %d, k = %d, d = %x\n", i, k, d);
+        switch (i)
+        {
+            case 0:     assert(k == 3); assert(d == 'b'); break;
+            case 1:     assert(k == 2); assert(d == 0xDBC1); break;
+            case 2:     assert(k == 2); assert(d == 0xDC56); break;
+            case 3:     assert(k == 1); assert(d == 0x1234); break;
+            case 4:     assert(k == 0); assert(d == 'a'); break;
+            default:    assert(0);
+        }
+        i++;
+    }
+    assert(i == 5);
+}
Index: src/compiler/ldc/rt/memory.d
===================================================================
--- src/compiler/ldc/rt/memory.d	(revision 0)
+++ src/compiler/ldc/rt/memory.d	(revision 0)
@@ -0,0 +1,218 @@
+/**
+ * This module exposes functionality for inspecting and manipulating memory.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.memory;
+
+
+private
+{
+    version( linux )
+    {
+        version = SimpleLibcStackEnd;
+
+        version( SimpleLibcStackEnd )
+        {
+            extern (C) extern __gshared void* __libc_stack_end;
+        }
+    }
+    version( FreeBSD )
+    {
+        version = SimpleLibcStackEnd;
+
+        version( SimpleLibcStackEnd )
+        {
+            extern (C) extern __gshared void* __libc_stack_end;
+        }
+    }
+    version( Solaris )
+    {
+        version = SimpleLibcStackEnd;
+
+        version( SimpleLibcStackEnd )
+        {
+            extern (C) extern __gshared void* __libc_stack_end;
+        }
+    }
+    extern (C) void gc_addRange( void* p, size_t sz );
+    extern (C) void gc_removeRange( void* p );
+
+    pragma( intrinsic, "llvm.frameaddress" )
+    {
+	    void* llvm_frameaddress(uint level=0);
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void* rt_stackBottom()
+{
+    version( Windows )
+    {
+        asm
+        {
+            naked;
+            mov EAX,FS:4;
+            ret;
+        }
+    }
+    else version( linux )
+    {
+        version( SimpleLibcStackEnd )
+        {
+            return __libc_stack_end;
+        }
+        else
+        {
+            // See discussion: http://autopackage.org/forums/viewtopic.php?t=22
+            static void** libc_stack_end;
+
+            if( libc_stack_end == libc_stack_end.init )
+            {
+                void* handle = dlopen( null, RTLD_NOW );
+                libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" );
+                dlclose( handle );
+            }
+            return *libc_stack_end;
+        }
+    }
+    else version( OSX )
+    {
+        return cast(void*) 0xc0000000;
+    }
+    else version( FreeBSD )
+    {
+        return __libc_stack_end;
+    }
+    else version( Solaris )
+    {
+        return __libc_stack_end;
+    }
+    else
+    {
+        static assert( false, "Operating system not supported." );
+    }
+}
+
+
+/**
+ *
+ */
+extern (C) void* rt_stackTop()
+{
+    version( D_InlineAsm_X86 )
+    {
+        asm
+        {
+            naked;
+            mov EAX, ESP;
+            ret;
+        }
+    }
+    else
+    {
+        return llvm_frameaddress();
+    }
+}
+
+
+private
+{
+    version( Windows )
+    {
+        extern (C)
+        {
+            extern __gshared
+            {
+                int _xi_a;   // &_xi_a just happens to be start of data segment
+                int _edata;  // &_edata is start of BSS segment
+                int _end;    // &_end is past end of BSS
+            }
+        }
+    }
+    else version( linux )
+    {
+        extern (C)
+        {
+            extern __gshared
+            {
+                int _data;
+                int __data_start;
+                int _end;
+                int _data_start__;
+                int _data_end__;
+                int _bss_start__;
+                int _bss_end__;
+                int __fini_array_end;
+            }
+        }
+
+            alias __data_start  Data_Start;
+            alias _end          Data_End;
+    }
+    else version( OSX )
+    {
+        extern (C) void _d_osx_image_init();
+    }
+    else version( FreeBSD )
+    {
+        extern (C)
+        {
+            extern __gshared
+            {
+                int etext;
+                int _end;
+            }
+        }
+    }
+    else version( Solaris )
+    {
+        extern (C)
+        {
+            extern __gshared
+            {
+                int etext;
+                int _end;
+            }
+        }
+    }
+}
+
+
+void initStaticDataGC()
+{
+    version( Windows )
+    {
+        gc_addRange( &_xi_a, cast(size_t) &_end - cast(size_t) &_xi_a );
+    }
+    else version( linux )
+    {
+        gc_addRange( &__data_start, cast(size_t) &_end - cast(size_t) &__data_start );
+    }
+    else version( OSX )
+    {
+        _d_osx_image_init();
+    }
+    else version( FreeBSD )
+    {
+        gc_addRange( &etext, cast(size_t) &_end - cast(size_t) &etext );
+    }
+    else version( Solaris )
+    {
+        gc_addRange( &etext, cast(size_t) &_end - cast(size_t) &etext );
+    }
+    else
+    {
+        static assert( false, "Operating system not supported." );
+    }
+}
Index: src/compiler/ldc/rt/arraydouble.d
===================================================================
--- src/compiler/ldc/rt/arraydouble.d	(revision 0)
+++ src/compiler/ldc/rt/arraydouble.d	(revision 0)
@@ -0,0 +1,1720 @@
+/**
+ * Contains SSE2 and MMX versions of certain operations for double.
+ *
+ * Copyright: Copyright Digital Mars 2008 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, based on code originally written by Burton Radons
+ *
+ *          Copyright Digital Mars 2008 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.arraydouble;
+
+private import rt.util.cpuid;
+
+version (unittest)
+{
+    private import core.stdc.stdio : printf;
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 5;
+    bool mmx()      { return cpuid == 1 && rt.util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && rt.util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && rt.util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && rt.util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias rt.util.cpuid.mmx mmx;
+    alias rt.util.cpuid.sse sse;
+    alias rt.util.cpuid.sse2 sse2;
+    alias rt.util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+/* Performance figures measured by Burton Radons
+ */
+
+alias double T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_d(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 333% faster
+        if (sse2() && b.length >= 16)
+        {
+            auto n = aptr + (b.length & ~15);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ESI, 64;
+                addpd XMM0, XMM4;
+                addpd XMM1, XMM5;
+                addpd XMM2, XMM6;
+                addpd XMM3, XMM7;
+                add ECX, 64;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ = *bptr++ + *cptr++;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_d(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 324% faster
+        if (sse2() && b.length >= 8)
+        {
+            auto n = aptr + (b.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n;    // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ESI, 64;
+                subpd XMM0, XMM4;
+                subpd XMM1, XMM5;
+                subpd XMM2, XMM6;
+                subpd XMM3, XMM7;
+                add ECX, 64;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ = *bptr++ - *cptr++;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %g != %g - %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_d(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 305% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                addpd XMM0, XMM4;
+                addpd XMM1, XMM4;
+                addpd XMM2, XMM4;
+                addpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ + value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %g != %g + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_d(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 114% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+            if (aptr < n)
+
+            // Unaligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                addpd XMM0, XMM4;
+                addpd XMM1, XMM4;
+                addpd XMM2, XMM4;
+                addpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %g != %g + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_d(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 183% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ECX, 64;
+                addpd XMM0, XMM4;
+                addpd XMM1, XMM5;
+                addpd XMM2, XMM6;
+                addpd XMM3, XMM7;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] += b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %g != %g + %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_d(T[] a, T value, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 305% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                subpd XMM0, XMM4;
+                subpd XMM1, XMM4;
+                subpd XMM2, XMM4;
+                subpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ - value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_d(T[] a, T[] b, T value)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 66% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movapd XMM5, XMM4;
+                movapd XMM6, XMM4;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                subpd XMM5, XMM0;
+                subpd XMM6, XMM1;
+                movupd [ESI+ 0-64], XMM5;
+                movupd [ESI+16-64], XMM6;
+                movapd XMM5, XMM4;
+                movapd XMM6, XMM4;
+                subpd XMM5, XMM2;
+                subpd XMM6, XMM3;
+                movupd [ESI+32-64], XMM5;
+                movupd [ESI+48-64], XMM6;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = value - *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = 6 - a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - a[i]))
+                {
+                    printf("[%d]: %g != 6 - %g\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_d(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 115% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+            if (aptr < n)
+
+            // Unaligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                subpd XMM0, XMM4;
+                subpd XMM1, XMM4;
+                subpd XMM2, XMM4;
+                subpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_d(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 183% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ECX, 64;
+                subpd XMM0, XMM4;
+                subpd XMM1, XMM5;
+                subpd XMM2, XMM6;
+                subpd XMM3, XMM7;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %g != %g - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAssign_d(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMulSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 304% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM4;
+                mulpd XMM2, XMM4;
+                mulpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * c[]
+ */
+
+T[] _arraySliceSliceMulSliceAssign_d(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceMulSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 329% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr; // left operand
+                mov ECX, cptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add ESI, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add EAX, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM5;
+                mulpd XMM2, XMM6;
+                mulpd XMM3, XMM7;
+                add ECX, 64;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * b[i]))
+                {
+                    printf("[%d]: %g != %g * %g\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= value
+ */
+
+T[] _arrayExpSliceMulass_d(T[] a, T value)
+{
+    //printf("_arrayExpSliceMulass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 109% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+            if (aptr < n)
+
+            // Unaligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, value;
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM4;
+                mulpd XMM2, XMM4;
+                mulpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= b[]
+ */
+
+T[] _arraySliceSliceMulass_d(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMulass_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 205% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov ECX, bptr; // right operand
+                mov ESI, aptr; // destination operand
+                mov EDI, n; // end comparison
+
+                align 8;
+            startsseloopb:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                movupd XMM4, [ECX];
+                movupd XMM5, [ECX+16];
+                movupd XMM6, [ECX+32];
+                movupd XMM7, [ECX+48];
+                add ECX, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM5;
+                mulpd XMM2, XMM6;
+                mulpd XMM3, XMM7;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopb;
+
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %g != %g * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] / value
+ */
+
+T[] _arraySliceExpDivSliceAssign_d(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpDivSliceAssign_d()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    /* Multiplying by the reciprocal is faster, but does
+     * not produce as accurate an answer.
+     */
+    T recip = cast(T)1 / value;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 299% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov EAX, bptr;
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, recip;
+                //movsd XMM4, value
+                //rcpsd XMM4, XMM4
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloop:
+                add ESI, 64;
+                movupd XMM0, [EAX];
+                movupd XMM1, [EAX+16];
+                movupd XMM2, [EAX+32];
+                movupd XMM3, [EAX+48];
+                add EAX, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM4;
+                mulpd XMM2, XMM4;
+                mulpd XMM3, XMM4;
+                //divpd XMM0, XMM4;
+                //divpd XMM1, XMM4;
+                //divpd XMM2, XMM4;
+                //divpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloop;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+    {
+        *aptr++ = *bptr++ / value;
+        //*aptr++ = *bptr++ * recip;
+    }
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpDivSliceAssign_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] / 8;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %g ?= %g / 8\n", i, c[i], a[i]);
+                if (c[i] != cast(T)(a[i] / 8))
+                {
+                    printf("[%d]: %g != %g / 8\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] /= value
+ */
+
+T[] _arrayExpSliceDivass_d(T[] a, T value)
+{
+    //printf("_arrayExpSliceDivass_d(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    /* Multiplying by the reciprocal is faster, but does
+     * not produce as accurate an answer.
+     */
+    T recip = cast(T)1 / value;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 version is 65% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            // Unaligned case
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movsd XMM4, recip;
+                //movsd XMM4, value
+                //rcpsd XMM4, XMM4
+                shufpd XMM4, XMM4, 0;
+
+                align 8;
+            startsseloopa:
+                movupd XMM0, [ESI];
+                movupd XMM1, [ESI+16];
+                movupd XMM2, [ESI+32];
+                movupd XMM3, [ESI+48];
+                add ESI, 64;
+                mulpd XMM0, XMM4;
+                mulpd XMM1, XMM4;
+                mulpd XMM2, XMM4;
+                mulpd XMM3, XMM4;
+                //divpd XMM0, XMM4;
+                //divpd XMM1, XMM4;
+                //divpd XMM2, XMM4;
+                //divpd XMM3, XMM4;
+                movupd [ESI+ 0-64], XMM0;
+                movupd [ESI+16-64], XMM1;
+                movupd [ESI+32-64], XMM2;
+                movupd [ESI+48-64], XMM3;
+                cmp ESI, EDI;
+                jb startsseloopa;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ *= recip;
+
+    return a;
+}
+
+
+unittest
+{
+    printf("_arrayExpSliceDivass_d unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            c[] /= 8;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] / 8))
+                {
+                    printf("[%d]: %g != %g / 8\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[] * value
+ */
+
+T[] _arraySliceExpMulSliceMinass_d(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAddass_d(a, -value, b);
+}
+
+/***********************
+ * Computes:
+ *      a[] += b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAddass_d(T[] a, T value, T[] b)
+in
+{
+        assert(a.length == b.length);
+        assert(disjoint(a, b));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ += *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAddass_d unittest\n");
+
+    cpuid = 1;
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 1; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]);
+                if (c[i] != cast(T)(b[i] + a[i] * 6))
+                {
+                    printf("[%d]: %g ?= %g + %g * 6\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
Index: src/compiler/ldc/rt/obj.d
===================================================================
--- src/compiler/ldc/rt/obj.d	(revision 0)
+++ src/compiler/ldc/rt/obj.d	(revision 0)
@@ -0,0 +1,34 @@
+/**
+ * Containts object comparator functions called by generated code.
+ *
+ * Copyright: Copyright Digital Mars 2002 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.obj;
+
+extern (C):
+
+/********************************
+ * Compiler helper for operator == for class objects.
+ */
+
+int _d_obj_eq(Object o1, Object o2)
+{
+    return o1 is o2 || (o1 && o1.opEquals(o2));
+}
+
+
+/********************************
+ * Compiler helper for operator <, <=, >, >= for class objects.
+ */
+
+int _d_obj_cmp(Object o1, Object o2)
+{
+    return o1.opCmp(o2);
+}
Index: src/compiler/ldc/rt/compiler.d
===================================================================
--- src/compiler/ldc/rt/compiler.d	(revision 0)
+++ src/compiler/ldc/rt/compiler.d	(revision 0)
@@ -0,0 +1,42 @@
+/**
+ * Compiler information and associated routines.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.compiler;
+
+// Identify the compiler used and its various features.
+
+const
+{
+    // Vendor specific string naming the compiler
+    char[] name = "Digital Mars D";
+
+    // Master list of D compiler vendors
+    enum Vendor
+    {
+        DigitalMars = 1
+    }
+
+    // Which vendor we are
+    Vendor vendor = Vendor.DigitalMars;
+
+
+    // The vendor specific version number, as in
+    // version_major.version_minor
+    uint version_major = 0;
+    uint version_minor = 0;
+
+
+    // The version of the D Programming Language Specification
+    // Supported by the compiler
+    uint D_major = 0;
+    uint D_minor = 0;
+}
Index: src/compiler/ldc/rt/dmain2.d
===================================================================
--- src/compiler/ldc/rt/dmain2.d	(revision 0)
+++ src/compiler/ldc/rt/dmain2.d	(revision 0)
@@ -0,0 +1,396 @@
+/**
+ * Contains main program entry point and support routines.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.dmain2;
+
+private
+{
+    import rt.memory;
+    import rt.util.console;
+    import core.stdc.stddef;
+    import core.stdc.stdlib;
+    import core.stdc.string;
+}
+
+version (Windows)
+{
+    private import core.stdc.wchar_;
+
+    extern (Windows) alias int function() FARPROC;
+    extern (Windows) FARPROC    GetProcAddress(void*, in char*);
+    extern (Windows) void*      LoadLibraryA(in char*);
+    extern (Windows) int        FreeLibrary(void*);
+    extern (Windows) void*      LocalFree(void*);
+    extern (Windows) wchar_t*   GetCommandLineW();
+    extern (Windows) wchar_t**  CommandLineToArgvW(wchar_t*, int*);
+    extern (Windows) export int WideCharToMultiByte(uint, uint, wchar_t*, int, char*, int, char*, int);
+    pragma(lib, "shell32.lib"); // needed for CommandLineToArgvW
+}
+
+extern (C) void _STI_monitor_staticctor();
+extern (C) void _STD_monitor_staticdtor();
+extern (C) void _STI_critical_init();
+extern (C) void _STD_critical_term();
+extern (C) void gc_init();
+extern (C) void gc_term();
+extern (C) void _minit();
+extern (C) void _moduleCtor();
+extern (C) void _moduleDtor();
+extern (C) void thread_joinAll();
+
+version (OSX)
+{
+    // The bottom of the stack
+    extern (C) void* __osx_stack_end = cast(void*)0xC0000000;
+}
+
+/***********************************
+ * These are a temporary means of providing a GC hook for DLL use.  They may be
+ * replaced with some other similar functionality later.
+ */
+extern (C)
+{
+    void* gc_getProxy();
+    void  gc_setProxy(void* p);
+    void  gc_clrProxy();
+
+    alias void* function()      gcGetFn;
+    alias void  function(void*) gcSetFn;
+    alias void  function()      gcClrFn;
+}
+
+extern (C) void* rt_loadLibrary(in char[] name)
+{
+    version (Windows)
+    {
+        char[260] temp = void;
+        temp[0 .. name.length] = name[];
+        temp[name.length] = cast(char) 0;
+        void* ptr = LoadLibraryA(temp.ptr);
+        if (ptr is null)
+            return ptr;
+        gcSetFn gcSet = cast(gcSetFn) GetProcAddress(ptr, "gc_setProxy");
+        if (gcSet !is null)
+            gcSet(gc_getProxy());
+        return ptr;
+
+    }
+    else version (Posix)
+    {
+        throw new Exception("rt_loadLibrary not yet implemented on Posix.");
+    }
+}
+
+extern (C) bool rt_unloadLibrary(void* ptr)
+{
+    version (Windows)
+    {
+        gcClrFn gcClr  = cast(gcClrFn) GetProcAddress(ptr, "gc_clrProxy");
+        if (gcClr !is null)
+            gcClr();
+        return FreeLibrary(ptr) != 0;
+    }
+    else version (Posix)
+    {
+        throw new Exception("rt_unloadLibrary not yet implemented on Posix.");
+    }
+}
+
+/***********************************
+ * These functions must be defined for any D program linked
+ * against this library.
+ */
+extern (C) void onAssertError(string file, size_t line);
+extern (C) void onAssertErrorMsg(string file, size_t line, string msg);
+extern (C) void onRangeError(string file, size_t line);
+extern (C) void onHiddenFuncError(Object o);
+extern (C) void onSwitchError(string file, size_t line);
+extern (C) bool runModuleUnitTests();
+
+// this function is called from the utf module
+//extern (C) void onUnicodeError(string msg, size_t idx);
+
+/***********************************
+ * These are internal callbacks for various language errors.
+ */
+extern (C) void _d_assert(string file, uint line)
+{
+    onAssertError(file, line);
+}
+
+extern (C) static void _d_assert_msg(string msg, string file, uint line)
+{
+    onAssertErrorMsg(file, line, msg);
+}
+
+extern (C) void _d_array_bounds(string file, uint line)
+{
+    onRangeError(file, line);
+}
+
+extern (C) void _d_switch_error(string file, uint line)
+{
+    onSwitchError(file, line);
+}
+
+extern (C) void _d_hidden_func()
+{
+    Object o;
+    asm
+    {
+        mov o, EAX;
+    }
+    onHiddenFuncError(o);
+}
+
+shared bool _d_isHalting = false;
+
+extern (C) bool rt_isHalting()
+{
+    return _d_isHalting;
+}
+
+// This variable is only ever set by a debugger on initialization so it should
+// be fine to leave it as __gshared.
+extern (C) __gshared bool rt_trapExceptions = true;
+
+void _d_criticalInit()
+{
+    version (Posix)
+    {
+        _STI_monitor_staticctor();
+        _STI_critical_init();
+    }
+}
+
+alias void delegate(Throwable) ExceptionHandler;
+
+extern (C) bool rt_init(ExceptionHandler dg = null)
+{
+    _d_criticalInit();
+
+    try
+    {
+        gc_init();
+        initStaticDataGC();
+        version (Windows)
+            _minit();
+        _moduleCtor();
+        runModuleUnitTests();
+        return true;
+    }
+    catch (Throwable e)
+    {
+        if (dg)
+            dg(e);
+    }
+    catch
+    {
+
+    }
+    _d_criticalTerm();
+    return false;
+}
+
+void _d_criticalTerm()
+{
+    version (Posix)
+    {
+        _STD_critical_term();
+        _STD_monitor_staticdtor();
+    }
+}
+
+extern (C) bool rt_term(ExceptionHandler dg = null)
+{
+    try
+    {
+        thread_joinAll();
+        _d_isHalting = true;
+        _moduleDtor();
+        gc_term();
+        return true;
+    }
+    catch (Throwable e)
+    {
+        if (dg)
+            dg(e);
+    }
+    catch
+    {
+
+    }
+    finally
+    {
+        _d_criticalTerm();
+    }
+    return false;
+}
+
+/***********************************
+ * The D main() function supplied by the user's program
+ */
+int main(char[][] args);
+
+/***********************************
+ * Substitutes for the C main() function.
+ * It's purpose is to wrap the call to the D main()
+ * function and catch any unhandled exceptions.
+ */
+
+extern (C) int main(int argc, char **argv)
+{
+    char[][] args;
+    int result;
+
+    version (OSX)
+    {   /* OSX does not provide a way to get at the top of the
+         * stack, except for the magic value 0xC0000000.
+         * But as far as the gc is concerned, argv is at the top
+         * of the main thread's stack, so save the address of that.
+         */
+        __osx_stack_end = cast(void*)&argv;
+    }
+
+    version (Posix)
+    {
+        _STI_monitor_staticctor();
+        _STI_critical_init();
+    }
+
+    version (Windows)
+    {
+        wchar_t*  wcbuf = GetCommandLineW();
+        size_t    wclen = wcslen(wcbuf);
+        int       wargc = 0;
+        wchar_t** wargs = CommandLineToArgvW(wcbuf, &wargc);
+        assert(wargc == argc);
+
+        char*     cargp = null;
+        size_t    cargl = WideCharToMultiByte(65001, 0, wcbuf, wclen, null, 0, null, 0);
+
+        cargp = cast(char*) alloca(cargl);
+        args  = ((cast(char[]*) alloca(wargc * (char[]).sizeof)))[0 .. wargc];
+
+        for (size_t i = 0, p = 0; i < wargc; i++)
+        {
+            int wlen = wcslen(wargs[i]);
+            int clen = WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, null, 0, null, 0);
+            args[i]  = cargp[p .. p+clen];
+            p += clen; assert(p <= cargl);
+            WideCharToMultiByte(65001, 0, &wargs[i][0], wlen, &args[i][0], clen, null, 0);
+        }
+        LocalFree(wargs);
+        wargs = null;
+        wargc = 0;
+    }
+    else version (Posix)
+    {
+        char[]* am = cast(char[]*) malloc(argc * (char[]).sizeof);
+        scope(exit) free(am);
+
+        for (size_t i = 0; i < argc; i++)
+        {
+            auto len = strlen(argv[i]);
+            am[i] = argv[i][0 .. len];
+        }
+        args = am[0 .. argc];
+    }
+
+    bool trapExceptions = rt_trapExceptions;
+
+    void tryExec(scope void delegate() dg)
+    {
+
+        if (trapExceptions)
+        {
+            try
+            {
+                dg();
+            }
+            catch (Throwable e)
+            {
+                while (e)
+                {
+                    if (e.file)
+                    {
+                        // fprintf(stderr, "%.*s(%u): %.*s\n", e.file, e.line, e.msg);
+                        console (e.classinfo.name)("@")(e.file)("(")(e.line)("): ")(e.msg)("\n");
+                    }
+                    else
+                    {
+                        // fprintf(stderr, "%.*s\n", e.toString());
+                        console (e.toString)("\n");
+                    }
+                    if (e.info)
+                    {
+                        console ("----------------\n");
+                        foreach (t; e.info)
+                            console (t)("\n");
+                    }
+                    if (e.next)
+                        console ("\n");
+                    e = e.next;
+                }
+                result = EXIT_FAILURE;
+            }
+            catch (Object o)
+            {
+                // fprintf(stderr, "%.*s\n", o.toString());
+                console (o.toString)("\n");
+                result = EXIT_FAILURE;
+            }
+        }
+        else
+        {
+            dg();
+        }
+    }
+
+    // NOTE: The lifetime of a process is much like the lifetime of an object:
+    //       it is initialized, then used, then destroyed.  If initialization
+    //       fails, the successive two steps are never reached.  However, if
+    //       initialization succeeds, then cleanup will occur even if the use
+    //       step fails in some way.  Here, the use phase consists of running
+    //       the user's main function.  If main terminates with an exception,
+    //       the exception is handled and then cleanup begins.  An exception
+    //       thrown during cleanup, however, will abort the cleanup process.
+
+    void runMain()
+    {
+        result = main(args);
+    }
+
+    void runAll()
+    {
+        gc_init();
+        initStaticDataGC();
+        version (Windows)
+            _minit();
+        _moduleCtor();
+        if (runModuleUnitTests())
+            tryExec(&runMain);
+        thread_joinAll();
+        _d_isHalting = true;
+        _moduleDtor();
+        gc_term();
+    }
+
+    tryExec(&runAll);
+
+    version (Posix)
+    {
+        _STD_critical_term();
+        _STD_monitor_staticdtor();
+    }
+    return result;
+}
Index: src/compiler/ldc/rt/typeinfo/ti_void.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_void.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_void.d	(revision 0)
@@ -0,0 +1,54 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_void;
+
+// void
+
+class TypeInfo_v : TypeInfo
+{
+    override string toString() { return "void"; }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(0);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return void.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        byte t;
+
+        t = *cast(byte *)p1;
+        *cast(byte *)p1 = *cast(byte *)p2;
+        *cast(byte *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_wchar.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_wchar.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_wchar.d	(revision 0)
@@ -0,0 +1,55 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_wchar;
+
+// wchar
+
+class TypeInfo_u : TypeInfo
+{
+    override string toString() { return "wchar"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(wchar *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(wchar *)p1 == *cast(wchar *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(wchar *)p1 - *cast(wchar *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return wchar.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        wchar t;
+
+        t = *cast(wchar *)p1;
+        *cast(wchar *)p1 = *cast(wchar *)p2;
+        *cast(wchar *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable wchar c;
+
+        return (cast(wchar *)&c)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_ptr.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_ptr.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_ptr.d	(revision 0)
@@ -0,0 +1,57 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_ptr;
+
+// pointer
+
+class TypeInfo_P : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {
+        return cast(uint)*cast(void* *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(void* *)p1 == *cast(void* *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        auto c = *cast(void* *)p1 - *cast(void* *)p2;
+        if (c < 0)
+            return -1;
+        else if (c > 0)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (void*).sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        void* t;
+
+        t = *cast(void* *)p1;
+        *cast(void* *)p1 = *cast(void* *)p2;
+        *cast(void* *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Afloat.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Afloat.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Afloat.d	(revision 0)
@@ -0,0 +1,103 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Afloat;
+
+private import rt.typeinfo.ti_float;
+
+// float[]
+
+class TypeInfo_Af : TypeInfo
+{
+    override string toString() { return "float[]"; }
+
+    override hash_t getHash(in void* p)
+    {   float[] s = *cast(float[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str;
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        float[] s1 = *cast(float[]*)p1;
+        float[] s2 = *cast(float[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_f._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        float[] s1 = *cast(float[]*)p1;
+        float[] s2 = *cast(float[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_f._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (float[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(float);
+    }
+}
+
+// ifloat[]
+
+class TypeInfo_Ao : TypeInfo_Af
+{
+    override string toString() { return "ifloat[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(ifloat);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_double.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_double.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_double.d	(revision 0)
@@ -0,0 +1,75 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_double;
+
+// double
+
+class TypeInfo_d : TypeInfo
+{
+    override string toString() { return "double"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static equals_t _equals(double f1, double f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(double d1, double d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(double *)p1, *cast(double *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(double *)p1, *cast(double *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return double.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        double t;
+
+        t = *cast(double *)p1;
+        *cast(double *)p1 = *cast(double *)p2;
+        *cast(double *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable double r;
+
+        return (cast(double *)&r)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_delegate.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_delegate.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_delegate.d	(revision 0)
@@ -0,0 +1,50 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_delegate;
+
+// delegate
+
+alias void delegate(int) dg;
+
+class TypeInfo_D : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {   long l = *cast(long *)p;
+
+        return cast(uint)(l + (l >> 32));
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(dg *)p1 == *cast(dg *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return dg.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        dg t;
+
+        t = *cast(dg *)p1;
+        *cast(dg *)p1 = *cast(dg *)p2;
+        *cast(dg *)p2 = t;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Adouble.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Adouble.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Adouble.d	(revision 0)
@@ -0,0 +1,104 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Adouble;
+
+private import rt.typeinfo.ti_double;
+
+// double[]
+
+class TypeInfo_Ad : TypeInfo
+{
+    override string toString() { return "double[]"; }
+
+    override hash_t getHash(in void* p)
+    {   double[] s = *cast(double[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        double[] s1 = *cast(double[]*)p1;
+        double[] s2 = *cast(double[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_d._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        double[] s1 = *cast(double[]*)p1;
+        double[] s2 = *cast(double[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_d._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (double[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(double);
+    }
+}
+
+// idouble[]
+
+class TypeInfo_Ap : TypeInfo_Ad
+{
+    override string toString() { return "idouble[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(idouble);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_char.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_char.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_char.d	(revision 0)
@@ -0,0 +1,55 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_char;
+
+// char
+
+class TypeInfo_a : TypeInfo
+{
+    override string toString() { return "char"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(char *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(char *)p1 == *cast(char *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(char *)p1 - *cast(char *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return char.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        char t;
+
+        t = *cast(char *)p1;
+        *cast(char *)p1 = *cast(char *)p2;
+        *cast(char *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable char c;
+
+        return (cast(char *)&c)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Acdouble.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Acdouble.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Acdouble.d	(revision 0)
@@ -0,0 +1,94 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Acdouble;
+
+private import rt.typeinfo.ti_cdouble;
+
+// cdouble[]
+
+class TypeInfo_Ar : TypeInfo
+{
+    override string toString() { return "cdouble[]"; }
+
+    override hash_t getHash(in void* p)
+    {   cdouble[] s = *cast(cdouble[]*)p;
+        size_t len = s.length;
+        cdouble *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(uint *)str)[2];
+            hash += (cast(uint *)str)[3];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        cdouble[] s1 = *cast(cdouble[]*)p1;
+        cdouble[] s2 = *cast(cdouble[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_r._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        cdouble[] s1 = *cast(cdouble[]*)p1;
+        cdouble[] s2 = *cast(cdouble[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_r._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (cdouble[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(cdouble);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_uint.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_uint.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_uint.d	(revision 0)
@@ -0,0 +1,53 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_uint;
+
+// uint
+
+class TypeInfo_k : TypeInfo
+{
+    override string toString() { return "uint"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(uint*) p1 < *cast(uint*) p2)
+            return -1;
+        else if (*cast(uint*) p1 > *cast(uint*) p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return uint.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        int t;
+
+        t = *cast(uint *)p1;
+        *cast(uint *)p1 = *cast(uint *)p2;
+        *cast(uint *)p2 = t;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_AC.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_AC.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_AC.d	(revision 0)
@@ -0,0 +1,107 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_AC;
+
+// Object[]
+
+class TypeInfo_AC : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {   Object[] s = *cast(Object[]*)p;
+        hash_t hash = 0;
+
+        foreach (Object o; s)
+        {
+            if (o)
+                hash += o.toHash();
+        }
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in 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 false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object[] s1 = *cast(Object[]*)p1;
+        Object[] s2 = *cast(Object[]*)p2;
+        ptrdiff_t c;
+
+        c = cast(ptrdiff_t)s1.length - cast(ptrdiff_t)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;
+                }
+            }
+        }
+        if (c < 0)
+            c = -1;
+        else if (c > 0)
+            c = 1;
+        return cast(int)c;
+    }
+
+    override size_t tsize()
+    {
+        return (Object[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(Object);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_ulong.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_ulong.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_ulong.d	(revision 0)
@@ -0,0 +1,53 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_ulong;
+
+// ulong
+
+class TypeInfo_m : TypeInfo
+{
+    override string toString() { return "ulong"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p + (cast(uint *)p)[1];
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ulong *)p1 == *cast(ulong *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(ulong *)p1 < *cast(ulong *)p2)
+            return -1;
+        else if (*cast(ulong *)p1 > *cast(ulong *)p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return ulong.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ulong t;
+
+        t = *cast(ulong *)p1;
+        *cast(ulong *)p1 = *cast(ulong *)p2;
+        *cast(ulong *)p2 = t;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_creal.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_creal.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_creal.d	(revision 0)
@@ -0,0 +1,78 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_creal;
+
+// creal
+
+class TypeInfo_c : TypeInfo
+{
+    override string toString() { return "creal"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+               (cast(uint *)p)[2] + (cast(uint *)p)[3] +
+               (cast(uint *)p)[4];
+    }
+
+    static equals_t _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;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(creal *)p1, *cast(creal *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return creal.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        creal t;
+
+        t = *cast(creal *)p1;
+        *cast(creal *)p1 = *cast(creal *)p2;
+        *cast(creal *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable creal r;
+
+        return (cast(creal *)&r)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_ubyte.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_ubyte.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_ubyte.d	(revision 0)
@@ -0,0 +1,54 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_ubyte;
+
+// ubyte
+
+class TypeInfo_h : TypeInfo
+{
+    override string toString() { return "ubyte"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(ubyte *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ubyte *)p1 == *cast(ubyte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(ubyte *)p1 - *cast(ubyte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return ubyte.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ubyte t;
+
+        t = *cast(ubyte *)p1;
+        *cast(ubyte *)p1 = *cast(ubyte *)p2;
+        *cast(ubyte *)p2 = t;
+    }
+}
+
+class TypeInfo_b : TypeInfo_h
+{
+    override string toString() { return "bool"; }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Aint.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Aint.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Aint.d	(revision 0)
@@ -0,0 +1,140 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Aint;
+
+private import core.stdc.string;
+
+// int[]
+
+class TypeInfo_Ai : TypeInfo
+{
+    override string toString() { return "int[]"; }
+
+    override hash_t getHash(in void* p)
+    {   int[] s = *cast(int[]*)p;
+        auto len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str;
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        int[] s1 = *cast(int[]*)p1;
+        int[] s2 = *cast(int[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * int.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        int[] s1 = *cast(int[]*)p1;
+        int[] s2 = *cast(int[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (int[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(int);
+    }
+}
+
+unittest
+{
+    int[][] a = [[5,3,8,7], [2,5,3,8,7]];
+    a.sort;
+    assert(a == [[2,5,3,8,7], [5,3,8,7]]);
+
+    a = [[5,3,8,7], [5,3,8]];
+    a.sort;
+    assert(a == [[5,3,8], [5,3,8,7]]);
+}
+
+// uint[]
+
+class TypeInfo_Ak : TypeInfo_Ai
+{
+    override string toString() { return "uint[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        uint[] s1 = *cast(uint[]*)p1;
+        uint[] s2 = *cast(uint[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(uint);
+    }
+}
+
+// dchar[]
+
+class TypeInfo_Aw : TypeInfo_Ak
+{
+    override string toString() { return "dchar[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(dchar);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_ireal.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_ireal.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_ireal.d	(revision 0)
@@ -0,0 +1,22 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_ireal;
+
+// ireal
+
+private import rt.typeinfo.ti_real;
+
+class TypeInfo_j : TypeInfo_e
+{
+    override string toString() { return "ireal"; }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_long.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_long.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_long.d	(revision 0)
@@ -0,0 +1,53 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_long;
+
+// long
+
+class TypeInfo_l : TypeInfo
+{
+    override string toString() { return "long"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p + (cast(uint *)p)[1];
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(long *)p1 == *cast(long *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(long *)p1 < *cast(long *)p2)
+            return -1;
+        else if (*cast(long *)p1 > *cast(long *)p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return long.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        long t;
+
+        t = *cast(long *)p1;
+        *cast(long *)p1 = *cast(long *)p2;
+        *cast(long *)p2 = t;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_short.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_short.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_short.d	(revision 0)
@@ -0,0 +1,49 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_short;
+
+// short
+
+class TypeInfo_s : TypeInfo
+{
+    override string toString() { return "short"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(short *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(short *)p1 == *cast(short *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(short *)p1 - *cast(short *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return short.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        short t;
+
+        t = *cast(short *)p1;
+        *cast(short *)p1 = *cast(short *)p2;
+        *cast(short *)p2 = t;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Along.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Along.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Along.d	(revision 0)
@@ -0,0 +1,120 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Along;
+
+private import core.stdc.string;
+
+// long[]
+
+class TypeInfo_Al : TypeInfo
+{
+    override string toString() { return "long[]"; }
+
+    override hash_t getHash(in void* p)
+    {   long[] s = *cast(long[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += *cast(uint *)str + *(cast(uint *)str + 1);
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        long[] s1 = *cast(long[]*)p1;
+        long[] s2 = *cast(long[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * long.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        long[] s1 = *cast(long[]*)p1;
+        long[] s2 = *cast(long[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (s1[u] < s2[u])
+                return -1;
+            else if (s1[u] > s2[u])
+                return 1;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (long[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(long);
+    }
+}
+
+
+// ulong[]
+
+class TypeInfo_Am : TypeInfo_Al
+{
+    override string toString() { return "ulong[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        ulong[] s1 = *cast(ulong[]*)p1;
+        ulong[] s2 = *cast(ulong[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (s1[u] < s2[u])
+                return -1;
+            else if (s1[u] > s2[u])
+                return 1;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ulong);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_byte.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_byte.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_byte.d	(revision 0)
@@ -0,0 +1,49 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_byte;
+
+// byte
+
+class TypeInfo_g : TypeInfo
+{
+    override string toString() { return "byte"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(byte *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 == *cast(byte *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(byte *)p1 - *cast(byte *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return byte.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        byte t;
+
+        t = *cast(byte *)p1;
+        *cast(byte *)p1 = *cast(byte *)p2;
+        *cast(byte *)p2 = t;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_float.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_float.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_float.d	(revision 0)
@@ -0,0 +1,75 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_float;
+
+// float
+
+class TypeInfo_f : TypeInfo
+{
+    override string toString() { return "float"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    static equals_t _equals(float f1, float f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(float d1, float d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(float *)p1, *cast(float *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(float *)p1, *cast(float *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return float.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        float t;
+
+        t = *cast(float *)p1;
+        *cast(float *)p1 = *cast(float *)p2;
+        *cast(float *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable float r;
+
+        return (cast(float *)&r)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_cfloat.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_cfloat.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_cfloat.d	(revision 0)
@@ -0,0 +1,76 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_cfloat;
+
+// cfloat
+
+class TypeInfo_q : TypeInfo
+{
+    override string toString() { return "cfloat"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1];
+    }
+
+    static equals_t _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;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(cfloat *)p1, *cast(cfloat *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return cfloat.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        cfloat t;
+
+        t = *cast(cfloat *)p1;
+        *cast(cfloat *)p1 = *cast(cfloat *)p2;
+        *cast(cfloat *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable cfloat r;
+
+        return (cast(cfloat *)&r)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Acfloat.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Acfloat.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Acfloat.d	(revision 0)
@@ -0,0 +1,92 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Acfloat;
+
+private import rt.typeinfo.ti_cfloat;
+
+// cfloat[]
+
+class TypeInfo_Aq : TypeInfo
+{
+    override string toString() { return "cfloat[]"; }
+
+    override hash_t getHash(in void* p)
+    {   cfloat[] s = *cast(cfloat[]*)p;
+        size_t len = s.length;
+        cfloat *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        cfloat[] s1 = *cast(cfloat[]*)p1;
+        cfloat[] s2 = *cast(cfloat[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_q._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        cfloat[] s1 = *cast(cfloat[]*)p1;
+        cfloat[] s2 = *cast(cfloat[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_q._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (cfloat[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(cfloat);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_cdouble.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_cdouble.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_cdouble.d	(revision 0)
@@ -0,0 +1,77 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_cdouble;
+
+// cdouble
+
+class TypeInfo_r : TypeInfo
+{
+    override string toString() { return "cdouble"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] +
+               (cast(uint *)p)[2] + (cast(uint *)p)[3];
+    }
+
+    static equals_t _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;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(cdouble *)p1, *cast(cdouble *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return cdouble.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        cdouble t;
+
+        t = *cast(cdouble *)p1;
+        *cast(cdouble *)p1 = *cast(cdouble *)p2;
+        *cast(cdouble *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable cdouble r;
+
+        return (cast(cdouble *)&r)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_ifloat.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_ifloat.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_ifloat.d	(revision 0)
@@ -0,0 +1,22 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_ifloat;
+
+// ifloat
+
+private import rt.typeinfo.ti_float;
+
+class TypeInfo_o : TypeInfo_f
+{
+    override string toString() { return "ifloat"; }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_dchar.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_dchar.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_dchar.d	(revision 0)
@@ -0,0 +1,55 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_dchar;
+
+// dchar
+
+class TypeInfo_w : TypeInfo
+{
+    override string toString() { return "dchar"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(dchar *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(dchar *)p1 == *cast(dchar *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(dchar *)p1 - *cast(dchar *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return dchar.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        dchar t;
+
+        t = *cast(dchar *)p1;
+        *cast(dchar *)p1 = *cast(dchar *)p2;
+        *cast(dchar *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable dchar c;
+
+        return (cast(dchar *)&c)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_C.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_C.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_C.d	(revision 0)
@@ -0,0 +1,63 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_C;
+
+// Object
+
+class TypeInfo_C : TypeInfo
+{
+    override hash_t getHash(in void* p)
+    {
+        Object o = *cast(Object*)p;
+        return o ? o.toHash() : 0;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+
+        return o1 == o2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (!(o1 is o2))
+        {
+            if (o1)
+            {   if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_idouble.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_idouble.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_idouble.d	(revision 0)
@@ -0,0 +1,22 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_idouble;
+
+// idouble
+
+private import rt.typeinfo.ti_double;
+
+class TypeInfo_p : TypeInfo_d
+{
+    override string toString() { return "idouble"; }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_real.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_real.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_real.d	(revision 0)
@@ -0,0 +1,75 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_real;
+
+// real
+
+class TypeInfo_e : TypeInfo
+{
+    override string toString() { return "real"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return (cast(uint *)p)[0] + (cast(uint *)p)[1] + (cast(ushort *)p)[4];
+    }
+
+    static equals_t _equals(real f1, real f2)
+    {
+        return f1 == f2 ||
+                (f1 !<>= f1 && f2 !<>= f2);
+    }
+
+    static int _compare(real d1, real d2)
+    {
+        if (d1 !<>= d2)         // if either are NaN
+        {
+            if (d1 !<>= d1)
+            {   if (d2 !<>= d2)
+                    return 0;
+                return -1;
+            }
+            return 1;
+        }
+        return (d1 == d2) ? 0 : ((d1 < d2) ? -1 : 1);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return _equals(*cast(real *)p1, *cast(real *)p2);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return _compare(*cast(real *)p1, *cast(real *)p2);
+    }
+
+    override size_t tsize()
+    {
+        return real.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        real t;
+
+        t = *cast(real *)p1;
+        *cast(real *)p1 = *cast(real *)p2;
+        *cast(real *)p2 = t;
+    }
+
+    override void[] init()
+    {   static immutable real r;
+
+        return (cast(real *)&r)[0 .. 1];
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_ushort.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_ushort.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_ushort.d	(revision 0)
@@ -0,0 +1,49 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_ushort;
+
+// ushort
+
+class TypeInfo_t : TypeInfo
+{
+    override string toString() { return "ushort"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(ushort *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(ushort *)p1 == *cast(ushort *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        return *cast(ushort *)p1 - *cast(ushort *)p2;
+    }
+
+    override size_t tsize()
+    {
+        return ushort.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        ushort t;
+
+        t = *cast(ushort *)p1;
+        *cast(ushort *)p1 = *cast(ushort *)p2;
+        *cast(ushort *)p2 = t;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Areal.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Areal.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Areal.d	(revision 0)
@@ -0,0 +1,105 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Areal;
+
+private import rt.typeinfo.ti_real;
+
+// real[]
+
+class TypeInfo_Ae : TypeInfo
+{
+    override string toString() { return "real[]"; }
+
+    override hash_t getHash(in void* p)
+    {   real[] s = *cast(real[]*)p;
+        size_t len = s.length;
+        auto str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(ushort *)str)[4];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        real[] s1 = *cast(real[]*)p1;
+        real[] s2 = *cast(real[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return false;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_e._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        real[] s1 = *cast(real[]*)p1;
+        real[] s2 = *cast(real[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_e._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (real[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(real);
+    }
+}
+
+// ireal[]
+
+class TypeInfo_Aj : TypeInfo_Ae
+{
+    override string toString() { return "ireal[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(ireal);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Acreal.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Acreal.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Acreal.d	(revision 0)
@@ -0,0 +1,95 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Acreal;
+
+private import rt.typeinfo.ti_creal;
+
+// creal[]
+
+class TypeInfo_Ac : TypeInfo
+{
+    override string toString() { return "creal[]"; }
+
+    override hash_t getHash(in void* p)
+    {   creal[] s = *cast(creal[]*)p;
+        size_t len = s.length;
+        creal *str = s.ptr;
+        hash_t hash = 0;
+
+        while (len)
+        {
+            hash *= 9;
+            hash += (cast(uint *)str)[0];
+            hash += (cast(uint *)str)[1];
+            hash += (cast(uint *)str)[2];
+            hash += (cast(uint *)str)[3];
+            hash += (cast(uint *)str)[4];
+            str++;
+            len--;
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        creal[] s1 = *cast(creal[]*)p1;
+        creal[] s2 = *cast(creal[]*)p2;
+        size_t len = s1.length;
+
+        if (len != s2.length)
+            return 0;
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!TypeInfo_c._equals(s1[u], s2[u]))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        creal[] s1 = *cast(creal[]*)p1;
+        creal[] s2 = *cast(creal[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int c = TypeInfo_c._compare(s1[u], s2[u]);
+            if (c)
+                return c;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (creal[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(creal);
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Ag.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Ag.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Ag.d	(revision 0)
@@ -0,0 +1,228 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Ag;
+
+private import rt.util.string;
+private import core.stdc.string;
+
+// byte[]
+
+class TypeInfo_Ag : TypeInfo
+{
+    override string toString() { return "byte[]"; }
+
+    override hash_t getHash(in void* p)
+    {   byte[] s = *cast(byte[]*)p;
+        size_t len = s.length;
+        byte *str = s.ptr;
+        hash_t hash = 0;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ubyte *)str;
+                    return hash;
+
+                case 2:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                case 3:
+                    hash *= 9;
+                    hash += (*cast(ushort *)str << 8) +
+                            (cast(ubyte *)str)[2];
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 4;
+                    len -= 4;
+                    break;
+            }
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        byte[] s1 = *cast(byte[]*)p1;
+        byte[] s2 = *cast(byte[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(byte *)s1, cast(byte *)s2, s1.length) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        byte[] s1 = *cast(byte[]*)p1;
+        byte[] s2 = *cast(byte[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (byte[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(byte);
+    }
+}
+
+
+// ubyte[]
+
+class TypeInfo_Ah : TypeInfo_Ag
+{
+    override string toString() { return "ubyte[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        char[] s1 = *cast(char[]*)p1;
+        char[] s2 = *cast(char[]*)p2;
+
+        return dstrcmp(s1, s2);
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ubyte);
+    }
+}
+
+// void[]
+
+class TypeInfo_Av : TypeInfo_Ah
+{
+    override string toString() { return "void[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(void);
+    }
+}
+
+// bool[]
+
+class TypeInfo_Ab : TypeInfo_Ah
+{
+    override string toString() { return "bool[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(bool);
+    }
+}
+
+// char[]
+
+class TypeInfo_Aa : TypeInfo_Ag
+{
+    override string toString() { return "char[]"; }
+
+    override hash_t getHash(in void* p)
+    {   char[] s = *cast(char[]*)p;
+        hash_t hash = 0;
+
+version (all)
+{
+        foreach (char c; s)
+            hash = hash * 11 + c;
+}
+else
+{
+        size_t len = s.length;
+        char *str = s;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ubyte *)str;
+                    return hash;
+
+                case 2:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                case 3:
+                    hash *= 9;
+                    hash += (*cast(ushort *)str << 8) +
+                            (cast(ubyte *)str)[2];
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 4;
+                    len -= 4;
+                    break;
+            }
+        }
+}
+        return hash;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(char);
+    }
+}
+
+// string
+
+class TypeInfo_Aya : TypeInfo_Aa
+{
+    override string toString() { return "immutable(char)[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(immutable(char));
+    }
+}
+
Index: src/compiler/ldc/rt/typeinfo/ti_int.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_int.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_int.d	(revision 0)
@@ -0,0 +1,53 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_int;
+
+// int
+
+class TypeInfo_i : TypeInfo
+{
+    override string toString() { return "int"; }
+
+    override hash_t getHash(in void* p)
+    {
+        return *cast(uint *)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(uint *)p1 == *cast(uint *)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(int*) p1 < *cast(int*) p2)
+            return -1;
+        else if (*cast(int*) p1 > *cast(int*) p2)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return int.sizeof;
+    }
+
+    override void swap(void *p1, void *p2)
+    {
+        int t;
+
+        t = *cast(int *)p1;
+        *cast(int *)p1 = *cast(int *)p2;
+        *cast(int *)p2 = t;
+    }
+}
Index: src/compiler/ldc/rt/typeinfo/ti_Ashort.d
===================================================================
--- src/compiler/ldc/rt/typeinfo/ti_Ashort.d	(revision 0)
+++ src/compiler/ldc/rt/typeinfo/ti_Ashort.d	(revision 0)
@@ -0,0 +1,143 @@
+/**
+ * TypeInfo support code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.typeinfo.ti_Ashort;
+
+private import core.stdc.string;
+
+// short[]
+
+class TypeInfo_As : TypeInfo
+{
+    override string toString() { return "short[]"; }
+
+    override hash_t getHash(in void* p)
+    {   short[] s = *cast(short[]*)p;
+        size_t len = s.length;
+        short *str = s.ptr;
+        hash_t hash = 0;
+
+        while (1)
+        {
+            switch (len)
+            {
+                case 0:
+                    return hash;
+
+                case 1:
+                    hash *= 9;
+                    hash += *cast(ushort *)str;
+                    return hash;
+
+                default:
+                    hash *= 9;
+                    hash += *cast(uint *)str;
+                    str += 2;
+                    len -= 2;
+                    break;
+            }
+        }
+
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        short[] s1 = *cast(short[]*)p1;
+        short[] s2 = *cast(short[]*)p2;
+
+        return s1.length == s2.length &&
+               memcmp(cast(void *)s1, cast(void *)s2, s1.length * short.sizeof) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        short[] s1 = *cast(short[]*)p1;
+        short[] s2 = *cast(short[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (short[]).sizeof;
+    }
+
+    override uint flags()
+    {
+        return 1;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(short);
+    }
+}
+
+
+// ushort[]
+
+class TypeInfo_At : TypeInfo_As
+{
+    override string toString() { return "ushort[]"; }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        ushort[] s1 = *cast(ushort[]*)p1;
+        ushort[] s2 = *cast(ushort[]*)p2;
+        size_t len = s1.length;
+
+        if (s2.length < len)
+            len = s2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = s1[u] - s2[u];
+            if (result)
+                return result;
+        }
+        if (s1.length < s2.length)
+            return -1;
+        else if (s1.length > s2.length)
+            return 1;
+        return 0;
+    }
+
+    override TypeInfo next()
+    {
+        return typeid(ushort);
+    }
+}
+
+// wchar[]
+
+class TypeInfo_Au : TypeInfo_At
+{
+    override string toString() { return "wchar[]"; }
+
+    override TypeInfo next()
+    {
+        return typeid(wchar);
+    }
+}
Index: src/compiler/ldc/rt/cmath2.d
===================================================================
--- src/compiler/ldc/rt/cmath2.d	(revision 0)
+++ src/compiler/ldc/rt/cmath2.d	(revision 0)
@@ -0,0 +1,218 @@
+/**
+ * Runtime support for complex arithmetic code generation (for Posix).
+ *
+ * Copyright: Copyright Digital Mars 2001 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2001 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.cmath2;
+
+private import core.stdc.math;
+
+extern (C):
+
+/****************************
+ * Multiply two complex floating point numbers, x and y.
+ * Input:
+ *      x.re    ST3
+ *      x.im    ST2
+ *      y.re    ST1
+ *      y.im    ST0
+ * Output:
+ *      ST1     real part
+ *      ST0     imaginary part
+ */
+
+void _Cmul()
+{
+    // p.re = x.re * y.re - x.im * y.im;
+    // p.im = x.im * y.re + x.re * y.im;
+    asm
+    {   naked                   ;
+        fld     ST(1)           ; // x.re
+        fmul    ST,ST(4)        ; // ST0 = x.re * y.re
+
+        fld     ST(1)           ; // y.im
+        fmul    ST,ST(4)        ; // ST0 = x.im * y.im
+
+        fsubp   ST(1),ST        ; // ST0 = x.re * y.re - x.im * y.im
+
+        fld     ST(3)           ; // x.im
+        fmul    ST,ST(3)        ; // ST0 = x.im * y.re
+
+        fld     ST(5)           ; // x.re
+        fmul    ST,ST(3)        ; // ST0 = x.re * y.im
+
+        faddp   ST(1),ST        ; // ST0 = x.im * y.re + x.re * y.im
+
+        fxch    ST(4),ST        ;
+        fstp    ST(0)           ;
+        fxch    ST(4),ST        ;
+        fstp    ST(0)           ;
+        fstp    ST(0)           ;
+        fstp    ST(0)           ;
+
+        ret                     ;
+    }
+/+
+    if (isnan(x) && isnan(y))
+    {
+        // Recover infinities that computed as NaN+ iNaN ...
+        int recalc = 0;
+        if ( isinf( a) || isinf( b) )
+        {   // z is infinite
+            // "Box" the infinity and change NaNs in the other factor to 0
+            a = copysignl( isinf( a) ? 1.0 : 0.0, a);
+            b = copysignl( isinf( b) ? 1.0 : 0.0, b);
+            if (isnan( c)) c = copysignl( 0.0, c);
+            if (isnan( d)) d = copysignl( 0.0, d);
+            recalc = 1;
+        }
+        if (isinf(c) || isinf(d))
+        {   // w is infinite
+            // "Box" the infinity and change NaNs in the other factor to 0
+            c = copysignl( isinf( c) ? 1.0 : 0.0, c);
+            d = copysignl( isinf( d) ? 1.0 : 0.0, d);
+            if (isnan( a)) a = copysignl( 0.0, a);
+            if (isnan( b)) b = copysignl( 0.0, b);
+            recalc = 1;
+        }
+        if (!recalc && (isinf(ac) || isinf(bd) ||
+            isinf(ad) || isinf(bc)))
+        {
+            // Recover infinities from overflow by changing NaNs to 0 ...
+            if (isnan( a)) a = copysignl( 0.0, a);
+            if (isnan( b)) b = copysignl( 0.0, b);
+            if (isnan( c)) c = copysignl( 0.0, c);
+            if (isnan( d)) d = copysignl( 0.0, d);
+            recalc = 1;
+        }
+        if (recalc)
+        {
+            x = INFINITY * (a * c - b * d);
+            y = INFINITY * (a * d + b * c);
+        }
+    }
++/
+}
+
+/****************************
+ * Divide two complex floating point numbers, x / y.
+ * Input:
+ *      x.re    ST3
+ *      x.im    ST2
+ *      y.re    ST1
+ *      y.im    ST0
+ * Output:
+ *      ST1     real part
+ *      ST0     imaginary part
+ */
+
+void _Cdiv()
+{
+    real x_re, x_im;
+    real y_re, y_im;
+    real q_re, q_im;
+    real r;
+    real den;
+
+    asm
+    {
+        fstp    y_im    ;
+        fstp    y_re    ;
+        fstp    x_im    ;
+        fstp    x_re    ;
+    }
+
+    if (fabs(y_re) < fabs(y_im))
+    {
+        r = y_re / y_im;
+        den = y_im + r * y_re;
+        q_re = (x_re * r + x_im) / den;
+        q_im = (x_im * r - x_re) / den;
+    }
+    else
+    {
+        r = y_im / y_re;
+        den = y_re + r * y_im;
+        q_re = (x_re + r * x_im) / den;
+        q_im = (x_im - r * x_re) / den;
+    }
+//printf("q.re = %g, q.im = %g\n", (double)q_re, (double)q_im);
+/+
+    if (isnan(q_re) && isnan(q_im))
+    {
+        real denom = y_re * y_re + y_im * y_im;
+
+        // non-zero / zero
+        if (denom == 0.0 && (!isnan(x_re) || !isnan(x_im)))
+        {
+            q_re = copysignl(INFINITY, y_re) * x_re;
+            q_im = copysignl(INFINITY, y_re) * x_im;
+        }
+        // infinite / finite
+        else if ((isinf(x_re) || isinf(x_im)) && isfinite(y_re) && isfinite(y_im))
+        {
+            x_re = copysignl(isinf(x_re) ? 1.0 : 0.0, x_re);
+            x_im = copysignl(isinf(x_im) ? 1.0 : 0.0, x_im);
+            q_re = INFINITY * (x_re * y_re + x_im * y_im);
+            q_im = INFINITY * (x_im * y_re - x_re * y_im);
+        }
+        // finite / infinite
+        else if (isinf(logbw) && isfinite(x_re) && isfinite(x_im))
+        {
+            y_re = copysignl(isinf(y_re) ? 1.0 : 0.0, y_re);
+            y_im = copysignl(isinf(y_im) ? 1.0 : 0.0, y_im);
+            q_re = 0.0 * (x_re * y_re + x_im * y_im);
+            q_im = 0.0 * (x_im * y_re - x_re * y_im);
+        }
+    }
+    return q_re + q_im * 1.0i;
++/
+    asm
+    {
+        fld     q_re;
+        fld     q_im;
+    }
+}
+
+/****************************
+ * Compare two complex floating point numbers, x and y.
+ * Input:
+ *      x.re    ST3
+ *      x.im    ST2
+ *      y.re    ST1
+ *      y.im    ST0
+ * Output:
+ *      8087 stack is cleared
+ *      flags set
+ */
+
+void _Ccmp()
+{
+    asm
+    {   naked                   ;
+        fucomp  ST(2)           ; // compare x.im and y.im
+        fstsw   AX              ;
+        sahf                    ;
+        jne     L1              ;
+        jp      L1              ; // jmp if NAN
+        fucomp  ST(2)           ; // compare x.re and y.re
+        fstsw   AX              ;
+        sahf                    ;
+        fstp    ST(0)           ; // pop
+        fstp    ST(0)           ; // pop
+        ret                     ;
+
+      L1:
+        fstp    ST(0)           ; // pop
+        fstp    ST(0)           ; // pop
+        fstp    ST(0)           ; // pop
+        ret                     ;
+    }
+}
Index: src/compiler/ldc/rt/arrayreal.d
===================================================================
--- src/compiler/ldc/rt/arrayreal.d	(revision 0)
+++ src/compiler/ldc/rt/arrayreal.d	(revision 0)
@@ -0,0 +1,241 @@
+/**
+ * Contains SSE2 and MMX versions of certain operations for real.
+ *
+ * Copyright: Copyright Digital Mars 2008 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, based on code originally written by Burton Radons
+ *
+ *          Copyright Digital Mars 2008 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.arrayreal;
+
+import rt.util.cpuid;
+
+version (unittest)
+{
+    private import core.stdc.stdio : printf;
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 1;
+    bool mmx()      { return cpuid == 1 && rt.util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && rt.util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && rt.util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && rt.util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias rt.util.cpuid.mmx mmx;
+    alias rt.util.cpuid.sse sse;
+    alias rt.util.cpuid.sse2 sse2;
+    alias rt.util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias real T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_r(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    for (int i = 0; i < a.length; i++)
+        a[i] = b[i] + c[i];
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_r unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %Lg != %Lg + %Lg\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_r(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    for (int i = 0; i < a.length; i++)
+        a[i] = b[i] - c[i];
+    return a;
+}
+
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_r unittest\n");
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %Lg != %Lg - %Lg\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[] * value
+ */
+
+T[] _arraySliceExpMulSliceMinass_r(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAddass_r(a, -value, b);
+}
+
+/***********************
+ * Computes:
+ *      a[] += b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAddass_r(T[] a, T value, T[] b)
+in
+{
+        assert(a.length == b.length);
+        assert(disjoint(a, b));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    // Handle remainder
+    while (aptr < aend)
+        *aptr++ += *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAddass_r unittest\n");
+
+    cpuid = 1;
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 1; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]);
+                if (c[i] != cast(T)(b[i] + a[i] * 6))
+                {
+                    printf("[%d]: %Lg ?= %Lg + %Lg * 6\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
Index: src/compiler/ldc/rt/aaA.d
===================================================================
--- src/compiler/ldc/rt/aaA.d	(revision 0)
+++ src/compiler/ldc/rt/aaA.d	(revision 0)
@@ -0,0 +1,875 @@
+/**
+ * Implementation of associative arrays.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.aaA;
+
+private
+{
+    import core.stdc.stdarg;
+    import core.stdc.string;
+    import core.stdc.stdio;
+
+    enum BlkAttr : uint
+    {
+        FINALIZE = 0b0000_0001,
+        NO_SCAN  = 0b0000_0010,
+        NO_MOVE  = 0b0000_0100,
+        ALL_BITS = 0b1111_1111
+    }
+
+    extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
+    extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
+    extern (C) void  gc_free( void* p );
+}
+
+// Auto-rehash and pre-allocate - Dave Fladebo
+
+immutable size_t[] prime_list = [
+              97UL,            389UL,
+           1_543UL,          6_151UL,
+          24_593UL,         98_317UL,
+          393_241UL,      1_572_869UL,
+        6_291_469UL,     25_165_843UL,
+      100_663_319UL,    402_653_189UL,
+    1_610_612_741UL,  4_294_967_291UL,
+//  8_589_934_513UL, 17_179_869_143UL
+];
+
+/* This is the type of the return value for dynamic arrays.
+ * It should be a type that is returned in registers.
+ * Although DMD will return types of Array in registers,
+ * gcc will not, so we instead use a 'long'.
+ */
+alias long ArrayRet_t;
+
+struct Array
+{
+    size_t length;
+    void* ptr;
+}
+
+struct aaA
+{
+    aaA *left;
+    aaA *right;
+    hash_t hash;
+    /* key   */
+    /* value */
+}
+
+struct BB
+{
+    aaA*[] b;
+    size_t nodes;       // total number of aaA nodes
+    TypeInfo keyti;     // TODO: replace this with TypeInfo_AssociativeArray when available in _aaGet()
+}
+
+/* This is the type actually seen by the programmer, although
+ * it is completely opaque.
+ */
+
+// LDC doesn't pass structs in registers so no need to wrap it ...
+alias BB* AA;
+
+/**********************************
+ * Align to next pointer boundary, so that
+ * GC won't be faced with misaligned pointers
+ * in value.
+ */
+
+size_t aligntsize(size_t tsize)
+{
+    // Is pointer alignment on the x64 4 bytes or 8?
+    return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
+}
+
+extern (C):
+
+/*************************************************
+ * Invariant for aa.
+ */
+
+/+
+void _aaInvAh(aaA*[] aa)
+{
+    for (size_t i = 0; i < aa.length; i++)
+    {
+        if (aa[i])
+            _aaInvAh_x(aa[i]);
+    }
+}
+
+private int _aaCmpAh_x(aaA *e1, aaA *e2)
+{   int c;
+
+    c = e1.hash - e2.hash;
+    if (c == 0)
+    {
+        c = e1.key.length - e2.key.length;
+        if (c == 0)
+            c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
+    }
+    return c;
+}
+
+private void _aaInvAh_x(aaA *e)
+{
+    hash_t key_hash;
+    aaA *e1;
+    aaA *e2;
+
+    key_hash = getHash(e.key);
+    assert(key_hash == e.hash);
+
+    while (1)
+    {   int c;
+
+        e1 = e.left;
+        if (e1)
+        {
+            _aaInvAh_x(e1);             // ordinary recursion
+            do
+            {
+                c = _aaCmpAh_x(e1, e);
+                assert(c < 0);
+                e1 = e1.right;
+            } while (e1 != null);
+        }
+
+        e2 = e.right;
+        if (e2)
+        {
+            do
+            {
+                c = _aaCmpAh_x(e, e2);
+                assert(c < 0);
+                e2 = e2.left;
+            } while (e2 != null);
+            e = e.right;                // tail recursion
+        }
+        else
+            break;
+    }
+}
++/
+
+/****************************************************
+ * Determine number of entries in associative array.
+ */
+
+size_t _aaLen(AA aa)
+in
+{
+    //printf("_aaLen()+\n");
+    //_aaInv(aa);
+}
+out (result)
+{
+    size_t len = 0;
+
+    void _aaLen_x(aaA* ex)
+    {
+        auto e = ex;
+        len++;
+
+        while (1)
+        {
+            if (e.right)
+               _aaLen_x(e.right);
+            e = e.left;
+            if (!e)
+                break;
+            len++;
+        }
+    }
+
+    if (aa)
+    {
+        foreach (e; aa.b)
+        {
+            if (e)
+                _aaLen_x(e);
+        }
+    }
+    assert(len == result);
+
+    //printf("_aaLen()-\n");
+}
+body
+{
+    return aa ? aa.nodes : 0;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Add entry for key if it is not already there.
+ */
+
+void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
+in
+{
+    assert(aa);
+}
+out (result)
+{
+    assert(result);
+    assert(*aa);
+    assert((*aa).b.length);
+    //assert(_aaInAh(*aa.a, key));
+}
+body
+{
+    auto pkey = cast(void *)(&valuesize + 1);
+    size_t i;
+    aaA *e;
+    //printf("keyti = %p\n", keyti);
+    //printf("aa = %p\n", aa);
+    auto keysize = aligntsize(keyti.tsize());
+
+    if (!*aa)
+        *aa = new BB();
+    //printf("aa = %p\n", aa);
+    //printf("aa.a = %p\n", aa.a);
+    (*aa).keyti = keyti;
+
+    if (!(*aa).b.length)
+    {
+        alias aaA *pa;
+        auto len = prime_list[0];
+
+        (*aa).b = new pa[len];
+    }
+
+    auto key_hash = keyti.getHash(pkey);
+    //printf("hash = %d\n", key_hash);
+    i = key_hash % (*aa).b.length;
+    auto pe = &(*aa).b[i];
+    while ((e = *pe) !is null)
+    {
+        if (key_hash == e.hash)
+        {
+            auto c = keyti.compare(pkey, e + 1);
+            if (c == 0)
+                goto Lret;
+            pe = (c < 0) ? &e.left : &e.right;
+        }
+        else
+            pe = (key_hash < e.hash) ? &e.left : &e.right;
+    }
+
+    // Not found, create new elem
+    //printf("create new one\n");
+    size_t size = aaA.sizeof + keysize + valuesize;
+    e = cast(aaA *) gc_calloc(size);
+    memcpy(e + 1, pkey, keysize);
+    e.hash = key_hash;
+    *pe = e;
+
+    auto nodes = ++(*aa).nodes;
+    //printf("length = %d, nodes = %d\n", aa.a.b.length, nodes);
+    if (nodes > (*aa).b.length * 4)
+    {
+        //printf("rehash\n");
+        _aaRehash(aa,keyti);
+    }
+
+Lret:
+    return cast(void *)(e + 1) + keysize;
+}
+
+
+/*************************************************
+ * Get pointer to value in associative array indexed by key.
+ * Returns null if it is not already there.
+ */
+
+void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
+{
+    //printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
+    if (!aa)
+        return null;
+
+    auto pkey = cast(void *)(&valuesize + 1);
+    auto keysize = aligntsize(keyti.tsize());
+    auto len = aa.b.length;
+
+    if (len)
+    {
+        auto key_hash = keyti.getHash(pkey);
+        //printf("hash = %d\n", key_hash);
+        size_t i = key_hash % len;
+        auto e = aa.b[i];
+        while (e !is null)
+        {
+            if (key_hash == e.hash)
+            {
+                auto c = keyti.compare(pkey, e + 1);
+            if (c == 0)
+                return cast(void *)(e + 1) + keysize;
+                e = (c < 0) ? e.left : e.right;
+            }
+            else
+                e = (key_hash < e.hash) ? e.left : e.right;
+        }
+    }
+    return null;    // not found, caller will throw exception
+}
+
+
+/*************************************************
+ * Determine if key is in aa.
+ * Returns:
+ *      null    not in aa
+ *      !=null  in aa, return pointer to value
+ */
+
+void* _aaIn(AA aa, TypeInfo keyti, ...)
+in
+{
+}
+out (result)
+{
+    //assert(result == 0 || result == 1);
+}
+body
+{
+    if (aa)
+    {
+        auto pkey = cast(void *)(&keyti + 1);
+
+        //printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
+        auto len = aa.b.length;
+
+        if (len)
+        {
+            auto key_hash = keyti.getHash(pkey);
+            //printf("hash = %d\n", key_hash);
+            size_t i = key_hash % len;
+            auto e = aa.b[i];
+            while (e !is null)
+            {
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(pkey, e + 1);
+                    if (c == 0)
+                        return cast(void *)(e + 1) + aligntsize(keyti.tsize());
+                    e = (c < 0) ? e.left : e.right;
+                }
+                else
+                    e = (key_hash < e.hash) ? e.left : e.right;
+            }
+        }
+    }
+
+    // Not found
+    return null;
+}
+
+/*************************************************
+ * Delete key entry in aa[].
+ * If key is not in aa[], do nothing.
+ */
+
+void _aaDel(AA aa, TypeInfo keyti, ...)
+{
+    auto pkey = cast(void *)(&keyti + 1);
+    aaA *e;
+
+    if (aa && aa.b.length)
+    {
+        auto key_hash = keyti.getHash(pkey);
+        //printf("hash = %d\n", key_hash);
+        size_t i = key_hash % aa.b.length;
+        auto pe = &aa.b[i];
+        while ((e = *pe) !is null) // null means not found
+        {
+            if (key_hash == e.hash)
+            {
+                auto c = keyti.compare(pkey, e + 1);
+                if (c == 0)
+                {
+                    if (!e.left && !e.right)
+                    {
+                        *pe = null;
+                    }
+                    else if (e.left && !e.right)
+                    {
+                        *pe = e.left;
+                         e.left = null;
+                    }
+                    else if (!e.left && e.right)
+                    {
+                        *pe = e.right;
+                         e.right = null;
+                    }
+                    else
+                    {
+                        *pe = e.left;
+                        e.left = null;
+                        do
+                            pe = &(*pe).right;
+                        while (*pe);
+                        *pe = e.right;
+                        e.right = null;
+                    }
+
+                    aa.nodes--;
+                    gc_free(e);
+                    break;
+                }
+                pe = (c < 0) ? &e.left : &e.right;
+            }
+            else
+                pe = (key_hash < e.hash) ? &e.left : &e.right;
+        }
+    }
+}
+
+
+/********************************************
+ * Produce array of values from aa.
+ */
+
+ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
+in
+{
+    assert(keysize == aligntsize(keysize));
+}
+body
+{
+    size_t resi;
+    Array a;
+
+    void _aaValues_x(aaA* e)
+    {
+        do
+        {
+            memcpy(a.ptr + resi * valuesize,
+                   cast(byte*)e + aaA.sizeof + keysize,
+                   valuesize);
+            resi++;
+            if (e.left)
+            {   if (!e.right)
+                {   e = e.left;
+                    continue;
+                }
+                _aaValues_x(e.left);
+            }
+            e = e.right;
+        } while (e !is null);
+    }
+
+    if (aa)
+    {
+        a.length = _aaLen(aa);
+        a.ptr = cast(byte*) gc_malloc(a.length * valuesize,
+                                      valuesize < (void*).sizeof ? BlkAttr.NO_SCAN : 0);
+        resi = 0;
+        foreach (e; aa.b)
+        {
+            if (e)
+                _aaValues_x(e);
+        }
+        assert(resi == a.length);
+    }
+    return *cast(ArrayRet_t*)(&a);
+}
+
+
+/********************************************
+ * Rehash an array.
+ */
+
+void* _aaRehash(AA* paa, TypeInfo keyti)
+in
+{
+    //_aaInvAh(paa);
+}
+out (result)
+{
+    //_aaInvAh(result);
+}
+body
+{
+    BB newb;
+
+    void _aaRehash_x(aaA* olde)
+    {
+        while (1)
+        {
+            auto left = olde.left;
+            auto right = olde.right;
+            olde.left = null;
+            olde.right = null;
+
+            aaA *e;
+
+            //printf("rehash %p\n", olde);
+            auto key_hash = olde.hash;
+            size_t i = key_hash % newb.b.length;
+            auto pe = &newb.b[i];
+            while ((e = *pe) !is null)
+            {
+                //printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
+                assert(e.left != e);
+                assert(e.right != e);
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(olde + 1, e + 1);
+                    assert(c != 0);
+                    pe = (c < 0) ? &e.left : &e.right;
+                }
+                else
+                    pe = (key_hash < e.hash) ? &e.left : &e.right;
+            }
+            *pe = olde;
+
+            if (right)
+            {
+                if (!left)
+                {   olde = right;
+                    continue;
+                }
+                _aaRehash_x(right);
+            }
+            if (!left)
+                break;
+            olde = left;
+        }
+    }
+
+    //printf("Rehash\n");
+    if (paa)
+    {
+        auto aa = paa;
+        auto len = _aaLen(*paa);
+        if (len)
+        {   size_t i;
+
+            for (i = 0; i < prime_list.length - 1; i++)
+            {
+                if (len <= prime_list[i])
+                    break;
+            }
+            len = prime_list[i];
+            newb.b = new aaA*[len];
+
+            foreach (e; (*aa).b)
+            {
+                if (e)
+                    _aaRehash_x(e);
+            }
+            delete (*aa).b;
+
+            newb.nodes = (*aa).nodes;
+            newb.keyti = (*aa).keyti;
+        }
+
+        **paa = newb;
+        _aaBalance(paa);
+    }
+    return (*paa);
+}
+
+/********************************************
+ * Balance an array.
+ */
+
+void _aaBalance(AA* paa)
+{
+    //printf("_aaBalance()\n");
+    if (paa)
+    {
+        aaA*[16] tmp;
+        aaA*[] array = tmp;
+        auto aa = paa;
+        foreach (j, e; (*aa).b)
+        {
+            /* Temporarily store contents of bucket in array[]
+             */
+            size_t k = 0;
+            void addToArray(aaA* e)
+            {
+                while (e)
+                {   addToArray(e.left);
+                    if (k == array.length)
+                        array.length = array.length * 2;
+                    array[k++] = e;
+                    e = e.right;
+                }
+            }
+            addToArray(e);
+            /* The contents of the bucket are now sorted into array[].
+             * Rebuild the tree.
+             */
+            void buildTree(aaA** p, size_t x1, size_t x2)
+            {
+                if (x1 >= x2)
+                    *p = null;
+                else
+                {   auto mid = (x1 + x2) >> 1;
+                    *p = array[mid];
+                    buildTree(&(*p).left, x1, mid);
+                    buildTree(&(*p).right, mid + 1, x2);
+                }
+            }
+            auto p = &(*aa).b[j];
+            buildTree(p, 0, k);
+        }
+    }
+}
+/********************************************
+ * Produce array of N byte keys from aa.
+ */
+
+ArrayRet_t _aaKeys(AA aa, size_t keysize)
+{
+    byte[] res;
+    size_t resi;
+
+    void _aaKeys_x(aaA* e)
+    {
+        do
+        {
+            memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
+            resi++;
+            if (e.left)
+            {   if (!e.right)
+                {   e = e.left;
+                    continue;
+                }
+                _aaKeys_x(e.left);
+            }
+            e = e.right;
+        } while (e !is null);
+    }
+
+    auto len = _aaLen(aa);
+    if (!len)
+        return 0;
+    res = (cast(byte*) gc_malloc(len * keysize,
+                                 !(aa.keyti.flags() & 1) ? BlkAttr.NO_SCAN : 0))[0 .. len * keysize];
+    resi = 0;
+    foreach (e; aa.b)
+    {
+        if (e)
+            _aaKeys_x(e);
+    }
+    assert(resi == len);
+
+    Array a;
+    a.length = len;
+    a.ptr = res.ptr;
+    return *cast(ArrayRet_t*)(&a);
+}
+
+
+/**********************************************
+ * 'apply' for associative arrays - to support foreach
+ */
+
+// dg is D, but _aaApply() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+int _aaApply(AA aa, size_t keysize, dg_t dg)
+in
+{
+    assert(aligntsize(keysize) == keysize);
+}
+body
+{   int result;
+
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
+
+    int treewalker(aaA* e)
+    {   int result;
+
+        do
+        {
+            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
+            result = dg(cast(void *)(e + 1) + keysize);
+            if (result)
+                break;
+            if (e.right)
+            {   if (!e.left)
+                {
+                    e = e.right;
+                    continue;
+                }
+                result = treewalker(e.right);
+                if (result)
+                    break;
+            }
+            e = e.left;
+        } while (e);
+
+        return result;
+    }
+
+    if (aa)
+    {
+        foreach (e; aa.b)
+        {
+            if (e)
+            {
+                result = treewalker(e);
+                if (result)
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+// dg is D, but _aaApply2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+int _aaApply2(AA aa, size_t keysize, dg2_t dg)
+in
+{
+    assert(aligntsize(keysize) == keysize);
+}
+body
+{   int result;
+
+    //printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
+
+    int treewalker(aaA* e)
+    {   int result;
+
+        do
+        {
+            //printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
+            result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
+            if (result)
+                break;
+            if (e.right)
+            {   if (!e.left)
+                {
+                    e = e.right;
+                    continue;
+                }
+                result = treewalker(e.right);
+                if (result)
+                    break;
+            }
+            e = e.left;
+        } while (e);
+
+        return result;
+    }
+
+    if (aa)
+    {
+        foreach (e; aa.b)
+        {
+            if (e)
+            {
+                result = treewalker(e);
+                if (result)
+                    break;
+            }
+        }
+    }
+    return result;
+}
+
+int _aaEq(AA aa, AA ab, TypeInfo_AssociativeArray ti) 
+{ 
+    return ti.equals(&aa, &ab); 
+} 
+
+
+/***********************************
+ * Construct an associative array of type ti from
+ * length pairs of key/value pairs.
+ */
+
+extern (C)
+BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
+{
+    auto valuesize = ti.next.tsize();           // value size
+    auto keyti = ti.key;
+    auto keysize = keyti.tsize();               // key size
+    BB* result;
+
+    //printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
+    //printf("tivalue = %.*s\n", ti.next.classinfo.name);
+    if (length == 0 || valuesize == 0 || keysize == 0)
+    {
+        ;
+    }
+    else
+    {
+        va_list q;
+        va_start!(size_t)(q, length);
+
+        result = new BB();
+        result.keyti = keyti;
+        size_t i;
+
+        for (i = 0; i < prime_list.length - 1; i++)
+        {
+            if (length <= prime_list[i])
+                break;
+        }
+        auto len = prime_list[i];
+        result.b = new aaA*[len];
+
+        size_t keystacksize   = (keysize   + int.sizeof - 1) & ~(int.sizeof - 1);
+        size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
+
+        size_t keytsize = aligntsize(keysize);
+
+        for (size_t j = 0; j < length; j++)
+        {   void* pkey = q;
+            q += keystacksize;
+            void* pvalue = q;
+            q += valuestacksize;
+            aaA* e;
+
+            auto key_hash = keyti.getHash(pkey);
+            //printf("hash = %d\n", key_hash);
+            i = key_hash % len;
+            auto pe = &result.b[i];
+            while (1)
+            {
+                e = *pe;
+                if (!e)
+                {
+                    // Not found, create new elem
+                    //printf("create new one\n");
+                    e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
+                    memcpy(e + 1, pkey, keysize);
+                    e.hash = key_hash;
+                    *pe = e;
+                    result.nodes++;
+                    break;
+                }
+                if (key_hash == e.hash)
+                {
+                    auto c = keyti.compare(pkey, e + 1);
+                    if (c == 0)
+                        break;
+                    pe = (c < 0) ? &e.left : &e.right;
+                }
+                else
+                    pe = (key_hash < e.hash) ? &e.left : &e.right;
+            }
+            memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
+        }
+
+        va_end(q);
+    }
+    return result;
+}
Index: src/compiler/ldc/rt/aApply.d
===================================================================
--- src/compiler/ldc/rt/aApply.d	(revision 0)
+++ src/compiler/ldc/rt/aApply.d	(revision 0)
@@ -0,0 +1,386 @@
+/**
+ * This code handles decoding UTF strings for foreach loops.  There are 6
+ * combinations of conversions between char, wchar, and dchar, and 2 of each
+ * of those.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.aApply;
+
+private import rt.util.utf;
+
+/**********************************************
+ */
+
+// dg is D, but _aApplycd() is C
+extern (D) typedef int delegate(void *) dg_t;
+
+extern (C) int _aApplycd1(char[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycd1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+
+        d = aa[i];
+        if (d & 0x80)
+            d = decode(aa, i);
+        else
+            i++;
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywd1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+
+        d = aa[i];
+        if (d & ~0x7F)
+            d = decode(aa, i);
+        else
+            i++;
+        result = dg(cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplycw1(char[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycw1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+        wchar w;
+
+        w = aa[i];
+        if (w & 0x80)
+        {   d = decode(aa, i);
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        else
+            i++;
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywc1(), len = %d\n", len);
+    for (i = 0; i < len; )
+    {   dchar d;
+        wchar w;
+        char c;
+
+        w = aa[i];
+        if (w & ~0x7F)
+        {
+            char[4] buf;
+
+            d = decode(aa, i);
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)w;
+            i++;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
+    foreach (dchar d; aa)
+    {
+        char c;
+
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {
+            c = cast(char)d;
+        }
+        result = dg(cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
+    foreach (dchar d; aa)
+    {
+        wchar w;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+
+/****************************************************************************/
+
+// dg is D, but _aApplycd2() is C
+extern (D) typedef int delegate(void *, void *) dg2_t;
+
+extern (C) int _aApplycd2(char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycd2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+
+        d = aa[i];
+        if (d & 0x80)
+        {
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywd2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+
+        d = aa[i];
+        if (d & ~0x7F)
+        {
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&d);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplycw2(char[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplycw2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+        wchar w;
+
+        w = aa[i];
+        if (w & 0x80)
+        {   n = i;
+            d = decode(aa, n);
+            n -= i;
+            if (d <= 0xFFFF)
+                w = cast(wchar) d;
+            else
+            {
+                w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+                result = dg(&i, cast(void *)&w);
+                if (result)
+                    break;
+                w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+            }
+        }
+        else
+            n = 1;
+        result = dg(&i, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t n;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplywc2(), len = %d\n", len);
+    for (i = 0; i < len; i += n)
+    {   dchar d;
+        wchar w;
+        char c;
+
+        w = aa[i];
+        if (w & ~0x7F)
+        {
+            char[4] buf;
+
+            n = i;
+            d = decode(aa, n);
+            n -= i;
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)w;
+            n = 1;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
+{   int result;
+    size_t i;
+    size_t len = aa.length;
+
+    debug(apply) printf("_aApplydc2(), len = %d\n", len);
+    for (i = 0; i < len; i++)
+    {   dchar d;
+        char c;
+
+        d = aa[i];
+        if (d & ~0x7F)
+        {
+            char[4] buf;
+
+            auto b = toUTF8(buf, d);
+            foreach (char c2; b)
+            {
+                result = dg(&i, cast(void *)&c2);
+                if (result)
+                    return result;
+            }
+            continue;
+        }
+        else
+        {   c = cast(char)d;
+        }
+        result = dg(&i, cast(void *)&c);
+        if (result)
+            break;
+    }
+    return result;
+}
+
+extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
+{   int result;
+
+    debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
+    foreach (size_t i, dchar d; aa)
+    {
+        wchar w;
+        auto j = i;
+
+        if (d <= 0xFFFF)
+            w = cast(wchar) d;
+        else
+        {
+            w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
+            result = dg(&j, cast(void *)&w);
+            if (result)
+                break;
+            w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
+        }
+        result = dg(&j, cast(void *)&w);
+        if (result)
+            break;
+    }
+    return result;
+}
Index: src/compiler/ldc/rt/cast_.d
===================================================================
--- src/compiler/ldc/rt/cast_.d	(revision 0)
+++ src/compiler/ldc/rt/cast_.d	(revision 0)
@@ -0,0 +1,169 @@
+/**
+ * Implementation of array assignment support routines.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.cast_;
+
+extern (C):
+
+/******************************************
+ * Given a pointer:
+ *      If it is an Object, return that Object.
+ *      If it is an interface, return the Object implementing the interface.
+ *      If it is null, return null.
+ *      Else, undefined crash
+ */
+
+Object _d_toObject(void* p)
+{   Object o;
+
+    if (p)
+    {
+        o = cast(Object)p;
+        ClassInfo oc = o.classinfo;
+        Interface *pi = **cast(Interface ***)p;
+
+        /* Interface.offset lines up with ClassInfo.name.ptr,
+         * so we rely on pointers never being less than 64K,
+         * and Objects never being greater.
+         */
+        if (pi.offset < 0x10000)
+        {
+            //printf("\tpi.offset = %d\n", pi.offset);
+            o = cast(Object)(p - pi.offset);
+        }
+    }
+    return o;
+}
+
+
+/*************************************
+ * Attempts to cast Object o to class c.
+ * Returns o if successful, null if not.
+ */
+
+Object _d_interface_cast(void* p, ClassInfo c)
+{   Object o;
+
+    //printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
+    if (p)
+    {
+        Interface *pi = **cast(Interface ***)p;
+
+        //printf("\tpi.offset = %d\n", pi.offset);
+        o = cast(Object)(p - pi.offset);
+        return _d_dynamic_cast(o, c);
+    }
+    return o;
+}
+
+Object _d_dynamic_cast(Object o, ClassInfo c)
+{   ClassInfo oc;
+    size_t offset = 0;
+
+    //printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
+
+    if (o)
+    {
+        oc = o.classinfo;
+        if (_d_isbaseof2(oc, c, offset))
+        {
+            //printf("\toffset = %d\n", offset);
+            o = cast(Object)(cast(void*)o + offset);
+        }
+        else
+            o = null;
+    }
+    //printf("\tresult = %p\n", o);
+    return o;
+}
+
+int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout size_t offset)
+{   int i;
+
+    if (oc is c)
+        return 1;
+    do
+    {
+        if (oc.base is c)
+            return 1;
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            if (ic is c)
+            {   offset = oc.interfaces[i].offset;
+                return 1;
+            }
+        }
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            if (_d_isbaseof2(ic, c, offset))
+            {   offset = oc.interfaces[i].offset;
+                return 1;
+            }
+        }
+        oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+int _d_isbaseof(ClassInfo oc, ClassInfo c)
+{   int i;
+
+    if (oc is c)
+        return 1;
+    do
+    {
+        if (oc.base is c)
+            return 1;
+        for (i = 0; i < oc.interfaces.length; i++)
+        {
+            ClassInfo ic;
+
+            ic = oc.interfaces[i].classinfo;
+            if (ic is c || _d_isbaseof(ic, c))
+                return 1;
+        }
+        oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+/*********************************
+ * Find the vtbl[] associated with Interface ic.
+ */
+
+void *_d_interface_vtbl(ClassInfo ic, Object o)
+{   int i;
+    ClassInfo oc;
+
+    //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
+
+    assert(o);
+
+    oc = o.classinfo;
+    for (i = 0; i < oc.interfaces.length; i++)
+    {
+        ClassInfo oic;
+
+        oic = oc.interfaces[i].classinfo;
+        if (oic is ic)
+        {
+            return cast(void *)oc.interfaces[i].vtbl;
+        }
+    }
+    assert(0);
+}
Index: src/compiler/ldc/rt/arrayint.d
===================================================================
--- src/compiler/ldc/rt/arrayint.d	(revision 0)
+++ src/compiler/ldc/rt/arrayint.d	(revision 0)
@@ -0,0 +1,2430 @@
+/**
+ * Contains MMX versions of certain operations for dchar, int, and uint ('w',
+ * 'i' and 'k' suffixes).
+ *
+ * Copyright: Copyright Digital Mars 2008 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, based on code originally written by Burton Radons
+ *
+ *          Copyright Digital Mars 2008 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.arrayint;
+
+private import rt.util.cpuid;
+
+version (unittest)
+{
+    private import core.stdc.stdio : printf;
+    /* This is so unit tests will test every CPU variant
+     */
+    int cpuid;
+    const int CPUID_MAX = 4;
+    bool mmx()      { return cpuid == 1 && rt.util.cpuid.mmx(); }
+    bool sse()      { return cpuid == 2 && rt.util.cpuid.sse(); }
+    bool sse2()     { return cpuid == 3 && rt.util.cpuid.sse2(); }
+    bool amd3dnow() { return cpuid == 4 && rt.util.cpuid.amd3dnow(); }
+}
+else
+{
+    alias rt.util.cpuid.mmx mmx;
+    alias rt.util.cpuid.sse sse;
+    alias rt.util.cpuid.sse2 sse2;
+    alias rt.util.cpuid.amd3dnow amd3dnow;
+}
+
+//version = log;
+
+bool disjoint(T)(T[] a, T[] b)
+{
+    return (a.ptr + a.length <= b.ptr || b.ptr + b.length <= a.ptr);
+}
+
+alias int T;
+
+extern (C):
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + value
+ */
+
+T[] _arraySliceExpAddSliceAssign_w(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_k(T[] a, T value, T[] b)
+{
+    return _arraySliceExpAddSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpAddSliceAssign_i(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpAddSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 380% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 298% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                paddd MM0, MM2;
+                paddd MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        if (a.length >= 2)
+        {
+            auto n = aptr + (a.length & ~1);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov EDX, value;
+
+                align 4;
+            start386:
+                add ESI, 8;
+                mov EBX, [EAX];
+                mov ECX, [EAX+4];
+                add EAX, 8;
+                add EBX, EDX;
+                add ECX, EDX;
+                mov [ESI  -8], EBX;
+                mov [ESI+4-8], ECX;
+                cmp ESI, EDI;
+                jb start386;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ + value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpAddSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] + c[]
+ */
+
+T[] _arraySliceSliceAddSliceAssign_w(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_k(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceAddSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceAddSliceAssign_i(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceAddSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1710% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 995% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM2, [ECX];
+                movq MM1, [EAX+8];
+                movq MM3, [ECX+8];
+                add EAX, 16;
+                add ECX, 16;
+                paddd MM0, MM2;
+                paddd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+normal:
+    while (aptr < aend)
+        *aptr++ = *bptr++ + *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] + b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] + b[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += value
+ */
+
+T[] _arrayExpSliceAddass_w(T[] a, T value)
+{
+    return _arrayExpSliceAddass_i(a, value);
+}
+
+T[] _arrayExpSliceAddass_k(T[] a, T value)
+{
+    return _arrayExpSliceAddass_i(a, value);
+}
+
+T[] _arrayExpSliceAddass_i(T[] a, T value)
+{
+    //printf("_arrayExpSliceAddass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 83% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 81% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                paddd MM0, MM2;
+                paddd MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+        else
+        if (a.length >= 2)
+        {
+            auto n = aptr + (a.length & ~1);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EDX, value;
+
+                align 4;
+            start386:
+                mov EBX, [ESI];
+                mov ECX, [ESI+4];
+                add ESI, 8;
+                add EBX, EDX;
+                add ECX, EDX;
+                mov [ESI  -8], EBX;
+                mov [ESI+4-8], ECX;
+                cmp ESI, EDI;
+                jb start386;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ += value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceAddass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            a[] += 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(c[i] + 6))
+                {
+                    printf("[%d]: %d != %d + 6\n", i, a[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] += b[]
+ */
+
+T[] _arraySliceSliceAddass_w(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_i(a, b);
+}
+
+T[] _arraySliceSliceAddass_k(T[] a, T[] b)
+{
+    return _arraySliceSliceAddass_i(a, b);
+}
+
+T[] _arraySliceSliceAddass_i(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceAddass_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 695% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    paddd XMM0, XMM2;
+                    paddd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 471% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM2, [ECX];
+                movq MM1, [ESI+8];
+                movq MM3, [ECX+8];
+                add ESI, 16;
+                add ECX, 16;
+                paddd MM0, MM2;
+                paddd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+normal:
+    while (aptr < aend)
+        *aptr++ += *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceAddass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] += a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] + a[i]))
+                {
+                    printf("[%d]: %d != %d + %d\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - value
+ */
+
+T[] _arraySliceExpMinSliceAssign_w(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_k(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMinSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpMinSliceAssign_i(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMinSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 400% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 315% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+        else
+        if (a.length >= 2)
+        {
+            auto n = aptr + (a.length & ~1);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov EDX, value;
+
+                align 4;
+            start386:
+                add ESI, 8;
+                mov EBX, [EAX];
+                mov ECX, [EAX+4];
+                add EAX, 8;
+                sub EBX, EDX;
+                sub ECX, EDX;
+                mov [ESI  -8], EBX;
+                mov [ESI+4-8], ECX;
+                cmp ESI, EDI;
+                jb start386;
+
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ - value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMinSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = value - b[]
+ */
+
+T[] _arrayExpSliceMinSliceAssign_w(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_i(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_k(T[] a, T[] b, T value)
+{
+    return _arrayExpSliceMinSliceAssign_i(a, b, value);
+}
+
+T[] _arrayExpSliceMinSliceAssign_i(T[] a, T[] b, T value)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arrayExpSliceMinSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1812% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 4;
+                startaddsse2u:
+                    add ESI, 32;
+                    movdqu XMM2, [EAX];
+                    movdqu XMM3, [EAX+16];
+                    movdqa XMM0, XMM4;
+                    movdqa XMM1, XMM4;
+                    add EAX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM4, l;
+                    pshufd XMM4, XMM4, 0;
+
+                    align 4;
+                startaddsse2a:
+                    add ESI, 32;
+                    movdqa XMM2, [EAX];
+                    movdqa XMM3, [EAX+16];
+                    movdqa XMM0, XMM4;
+                    movdqa XMM1, XMM4;
+                    add EAX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        // MMX version is 1077% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM4, l;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM2, [EAX];
+                movq MM3, [EAX+8];
+                movq MM0, MM4;
+                movq MM1, MM4;
+                add EAX, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = value - *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = 6 - a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(6 - a[i]))
+                {
+                    printf("[%d]: %d != 6 - %d\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] - c[]
+ */
+
+T[] _arraySliceSliceMinSliceAssign_w(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_k(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMinSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceMinSliceAssign_i(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1721% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 1002% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM2, [ECX];
+                movq MM1, [EAX+8];
+                movq MM3, [ECX+8];
+                add EAX, 16;
+                add ECX, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ - *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] - b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] - b[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= value
+ */
+
+T[] _arrayExpSliceMinass_w(T[] a, T value)
+{
+    return _arrayExpSliceMinass_i(a, value);
+}
+
+T[] _arrayExpSliceMinass_k(T[] a, T value)
+{
+    return _arrayExpSliceMinass_i(a, value);
+}
+
+T[] _arrayExpSliceMinass_i(T[] a, T value)
+{
+    //printf("_arrayExpSliceMinass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 81% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startaddsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startaddsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 81% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+        else
+        if (a.length >= 2)
+        {
+            auto n = aptr + (a.length & ~1);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EDX, value;
+
+                align 4;
+            start386:
+                mov EBX, [ESI];
+                mov ECX, [ESI+4];
+                add ESI, 8;
+                sub EBX, EDX;
+                sub ECX, EDX;
+                mov [ESI  -8], EBX;
+                mov [ESI+4-8], ECX;
+                cmp ESI, EDI;
+                jb start386;
+
+                mov aptr, ESI;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMinass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            a[] = c[];
+            a[] -= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(c[i] - 6))
+                {
+                    printf("[%d]: %d != %d - 6\n", i, a[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] -= b[]
+ */
+
+T[] _arraySliceSliceMinass_w(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_i(a, b);
+}
+
+T[] _arraySliceSliceMinass_k(T[] a, T[] b)
+{
+    return _arraySliceSliceMinass_i(a, b);
+}
+
+T[] _arraySliceSliceMinass_i(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMinass_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 731% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm // unaligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm // aligned case
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    psubd XMM0, XMM2;
+                    psubd XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+        }
+        else
+        // MMX version is 441% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM2, [ECX];
+                movq MM1, [ESI+8];
+                movq MM3, [ECX+8];
+                add ESI, 16;
+                add ECX, 16;
+                psubd MM0, MM2;
+                psubd MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
+    }
+
+    while (aptr < aend)
+        *aptr++ -= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMinass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = c[];
+            c[] -= a[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(b[i] - a[i]))
+                {
+                    printf("[%d]: %d != %d - %d\n", i, c[i], b[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * value
+ */
+
+T[] _arraySliceExpMulSliceAssign_w(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpMulSliceAssign_k(T[] a, T value, T[] b)
+{
+    return _arraySliceExpMulSliceAssign_i(a, value, b);
+}
+
+T[] _arraySliceExpMulSliceAssign_i(T[] a, T value, T[] b)
+in
+{
+    assert(a.length == b.length);
+    assert(disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceExpMulSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+  version (none)        // multiplying a pair is not supported by MMX
+  {
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1380% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM1, [EAX+16];
+                    add EAX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM1, [EAX+16];
+                    add EAX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                }
+            }
+        }
+        else
+        {
+        // MMX version is 1380% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM1, [EAX+8];
+                add EAX, 16;
+                pmuludq MM0, MM2;       // only multiplies low 32 bits
+                pmuludq MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+            }
+        }
+    }
+        }
+  }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceExpMulSliceAssign_s unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                //printf("[%d]: %d ?= %d * 6\n", i, c[i], a[i]);
+                if (c[i] != cast(T)(a[i] * 6))
+                {
+                    printf("[%d]: %d != %d * 6\n", i, c[i], a[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] = b[] * c[]
+ */
+
+T[] _arraySliceSliceMulSliceAssign_w(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMulSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceMulSliceAssign_k(T[] a, T[] c, T[] b)
+{
+    return _arraySliceSliceMulSliceAssign_i(a, c, b);
+}
+
+T[] _arraySliceSliceMulSliceAssign_i(T[] a, T[] c, T[] b)
+in
+{
+        assert(a.length == b.length && b.length == c.length);
+        assert(disjoint(a, b));
+        assert(disjoint(a, c));
+        assert(disjoint(b, c));
+}
+body
+{
+    //printf("_arraySliceSliceMulSliceAssign_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+    auto cptr = c.ptr;
+
+  version (none)
+  {
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 1407% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr | cast(uint) cptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2u:
+                    add ESI, 32;
+                    movdqu XMM0, [EAX];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [EAX+16];
+                    movdqu XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov EAX, bptr;
+                    mov ECX, cptr;
+
+                    align 4;
+                startsse2a:
+                    add ESI, 32;
+                    movdqa XMM0, [EAX];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [EAX+16];
+                    movdqa XMM3, [ECX+16];
+                    add EAX, 32;
+                    add ECX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, EAX;
+                    mov cptr, ECX;
+               }
+            }
+        }
+        else
+        // MMX version is 1029% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov EAX, bptr;
+                mov ECX, cptr;
+
+                align 4;
+            startmmx:
+                add ESI, 16;
+                movq MM0, [EAX];
+                movq MM2, [ECX];
+                movq MM1, [EAX+8];
+                movq MM3, [ECX+8];
+                add EAX, 16;
+                add ECX, 16;
+                pmuludq MM0, MM2;
+                pmuludq MM1, MM3;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, EAX;
+                mov cptr, ECX;
+            }
+        }
+    }
+  }
+
+    while (aptr < aend)
+        *aptr++ = *bptr++ * *cptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulSliceAssign_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            c[] = a[] * b[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (c[i] != cast(T)(a[i] * b[i]))
+                {
+                    printf("[%d]: %d != %d * %d\n", i, c[i], a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= value
+ */
+
+T[] _arrayExpSliceMulass_w(T[] a, T value)
+{
+    return _arrayExpSliceMulass_i(a, value);
+}
+
+T[] _arrayExpSliceMulass_k(T[] a, T value)
+{
+    return _arrayExpSliceMulass_i(a, value);
+}
+
+T[] _arrayExpSliceMulass_i(T[] a, T value)
+{
+    //printf("_arrayExpSliceMulass_i(a.length = %d, value = %Lg)\n", a.length, cast(real)value);
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+
+  version (none)
+  {
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 400% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            uint l = value;
+
+            if (((cast(uint) aptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM1, [ESI+16];
+                    add ESI, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM2;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    movd XMM2, l;
+                    pshufd XMM2, XMM2, 0;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM1, [ESI+16];
+                    add ESI, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM2;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                }
+            }
+        }
+        else
+        // MMX version is 402% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            ulong l = cast(uint) value | (cast(ulong)cast(uint) value << 32);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                movq MM2, l;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM1, [ESI+8];
+                add ESI, 16;
+                pmuludq MM0, MM2;
+                pmuludq MM1, MM2;
+                movq [ESI  -16], MM0;
+                movq [ESI+8-16], MM1;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+            }
+        }
+    }
+  }
+
+    while (aptr < aend)
+        *aptr++ *= value;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arrayExpSliceMulass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = a[];
+            a[] *= 6;
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(b[i] * 6))
+                {
+                    printf("[%d]: %d != %d * 6\n", i, a[i], b[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
+
+
+/* ======================================================================== */
+
+/***********************
+ * Computes:
+ *      a[] *= b[]
+ */
+
+T[] _arraySliceSliceMulass_w(T[] a, T[] b)
+{
+    return _arraySliceSliceMulass_i(a, b);
+}
+
+T[] _arraySliceSliceMulass_k(T[] a, T[] b)
+{
+    return _arraySliceSliceMulass_i(a, b);
+}
+
+T[] _arraySliceSliceMulass_i(T[] a, T[] b)
+in
+{
+    assert (a.length == b.length);
+    assert (disjoint(a, b));
+}
+body
+{
+    //printf("_arraySliceSliceMulass_i()\n");
+    auto aptr = a.ptr;
+    auto aend = aptr + a.length;
+    auto bptr = b.ptr;
+
+  version (none)
+  {
+    version (D_InlineAsm_X86)
+    {
+        // SSE2 aligned version is 873% faster
+        if (sse2() && a.length >= 8)
+        {
+            auto n = aptr + (a.length & ~7);
+
+            if (((cast(uint) aptr | cast(uint) bptr) & 15) != 0)
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2u:
+                    movdqu XMM0, [ESI];
+                    movdqu XMM2, [ECX];
+                    movdqu XMM1, [ESI+16];
+                    movdqu XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM3;
+                    movdqu [ESI   -32], XMM0;
+                    movdqu [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2u;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+                }
+            }
+            else
+            {
+                asm
+                {
+                    mov ESI, aptr;
+                    mov EDI, n;
+                    mov ECX, bptr;
+
+                    align 4;
+                startsse2a:
+                    movdqa XMM0, [ESI];
+                    movdqa XMM2, [ECX];
+                    movdqa XMM1, [ESI+16];
+                    movdqa XMM3, [ECX+16];
+                    add ESI, 32;
+                    add ECX, 32;
+                    pmuludq XMM0, XMM2;
+                    pmuludq XMM1, XMM3;
+                    movdqa [ESI   -32], XMM0;
+                    movdqa [ESI+16-32], XMM1;
+                    cmp ESI, EDI;
+                    jb startsse2a;
+
+                    mov aptr, ESI;
+                    mov bptr, ECX;
+               }
+            }
+        }
+/+ BUG: comment out this section until we figure out what is going
+   wrong with the invalid pshufd instructions.
+
+        else
+        // MMX version is 573% faster
+        if (mmx() && a.length >= 4)
+        {
+            auto n = aptr + (a.length & ~3);
+
+            asm
+            {
+                mov ESI, aptr;
+                mov EDI, n;
+                mov ECX, bptr;
+
+                align 4;
+            startmmx:
+                movq MM0, [ESI];
+                movq MM2, [ECX];
+                movq MM1, [ESI+8];
+                movq MM3, [ECX+8];
+                pxor MM4, MM4;
+                pxor MM5, MM5;
+                punpckldq MM4, MM0;
+                punpckldq MM5, MM2;
+                add ESI, 16;
+                add ECX, 16;
+                pmuludq MM4, MM5;
+                pshufd MM4, MM4, 8;     // ?
+                movq [ESI  -16], MM4;
+                pxor MM4, MM4;
+                pxor MM5, MM5;
+                punpckldq MM4, MM1;
+                punpckldq MM5, MM3;
+                pmuludq MM4, MM5;
+                pshufd MM4, MM4, 8;     // ?
+                movq [ESI+8-16], MM4;
+                cmp ESI, EDI;
+                jb startmmx;
+
+                emms;
+                mov aptr, ESI;
+                mov bptr, ECX;
+            }
+        }
++/
+    }
+  }
+
+    while (aptr < aend)
+        *aptr++ *= *bptr++;
+
+    return a;
+}
+
+unittest
+{
+    printf("_arraySliceSliceMulass_i unittest\n");
+
+    for (cpuid = 0; cpuid < CPUID_MAX; cpuid++)
+    {
+        version (log) printf("    cpuid %d\n", cpuid);
+
+        for (int j = 0; j < 2; j++)
+        {
+            const int dim = 67;
+            T[] a = new T[dim + j];     // aligned on 16 byte boundary
+            a = a[j .. dim + j];        // misalign for second iteration
+            T[] b = new T[dim + j];
+            b = b[j .. dim + j];
+            T[] c = new T[dim + j];
+            c = c[j .. dim + j];
+
+            for (int i = 0; i < dim; i++)
+            {   a[i] = cast(T)i;
+                b[i] = cast(T)(i + 7);
+                c[i] = cast(T)(i * 2);
+            }
+
+            b[] = a[];
+            a[] *= c[];
+
+            for (int i = 0; i < dim; i++)
+            {
+                if (a[i] != cast(T)(b[i] * c[i]))
+                {
+                    printf("[%d]: %d != %d * %d\n", i, a[i], b[i], c[i]);
+                    assert(0);
+                }
+            }
+        }
+    }
+}
Index: src/compiler/ldc/rt/arraycast.d
===================================================================
--- src/compiler/ldc/rt/arraycast.d	(revision 0)
+++ src/compiler/ldc/rt/arraycast.d	(revision 0)
@@ -0,0 +1,94 @@
+/**
+ * Implementation of array cast support routines.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.arraycast;
+
+/******************************************
+ * Runtime helper to convert dynamic array of one
+ * type to dynamic array of another.
+ * Adjusts the length of the array.
+ * Throws exception if new length is not aligned.
+ */
+
+extern (C)
+
+void[] _d_arraycast(size_t tsize, size_t fsize, void[] a)
+{
+    auto length = a.length;
+
+    auto nbytes = length * fsize;
+    if (nbytes % tsize != 0)
+    {
+    throw new Exception("array cast misalignment");
+    }
+    length = nbytes / tsize;
+    *cast(size_t *)&a = length; // jam new length
+    return a;
+}
+
+unittest
+{
+    byte[int.sizeof * 3] b;
+    int[] i;
+    short[] s;
+
+    i = cast(int[])b;
+    assert(i.length == 3);
+
+    s = cast(short[])b;
+    assert(s.length == 6);
+
+    s = cast(short[])i;
+    assert(s.length == 6);
+}
+
+/******************************************
+ * Runtime helper to convert dynamic array of bits
+ * dynamic array of another.
+ * Adjusts the length of the array.
+ * Throws exception if new length is not aligned.
+ */
+
+version (none)
+{
+extern (C)
+
+void[] _d_arraycast_frombit(uint tsize, void[] a)
+{
+    uint length = a.length;
+
+    if (length & 7)
+    {
+    throw new Exception("bit[] array cast misalignment");
+    }
+    length /= 8 * tsize;
+    *cast(size_t *)&a = length; // jam new length
+    return a;
+}
+
+unittest
+{
+    version (D_Bits)
+    {
+    bit[int.sizeof * 3 * 8] b;
+    int[] i;
+    short[] s;
+
+    i = cast(int[])b;
+    assert(i.length == 3);
+
+    s = cast(short[])b;
+    assert(s.length == 6);
+    }
+}
+
+}
Index: src/compiler/ldc/rt/invariant_.d
===================================================================
--- src/compiler/ldc/rt/invariant_.d	(revision 0)
+++ src/compiler/ldc/rt/invariant_.d	(revision 0)
@@ -0,0 +1,32 @@
+/**
+ * Implementation of invariant support routines.
+ *
+ * Copyright: Copyright Digital Mars 2007 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2007 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.invariant_;
+
+extern (C) void _d_invariant(Object o)
+{   ClassInfo c;
+
+    //printf("__d_invariant(%p)\n", o);
+
+    // BUG: needs to be filename/line of caller, not library routine
+    assert(o !is null); // just do null check, not invariant check
+
+    c = o.classinfo;
+    do
+    {
+        if (c.classInvariant)
+        {
+            (*c.classInvariant)(o);
+        }
+        c = c.base;
+    } while (c);
+}
Index: src/compiler/ldc/rt/memset.d
===================================================================
--- src/compiler/ldc/rt/memset.d	(revision 0)
+++ src/compiler/ldc/rt/memset.d	(revision 0)
@@ -0,0 +1,109 @@
+/**
+ * Contains a memset implementation used by compiler-generated code.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.memset;
+
+extern (C)
+{
+    // Functions from the C library.
+    void *memcpy(void *, void *, size_t);
+}
+
+extern (C):
+
+short *_memset16(short *p, short value, size_t count)
+{
+    short *pstart = p;
+    short *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+int *_memset32(int *p, int value, size_t count)
+{
+version (X86)
+{
+    asm
+    {
+        mov     EDI,p           ;
+        mov     EAX,value       ;
+        mov     ECX,count       ;
+        mov     EDX,EDI         ;
+        rep                     ;
+        stosd                   ;
+        mov     EAX,EDX         ;
+    }
+}
+else
+{
+    int *pstart = p;
+    int *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+}
+
+long *_memset64(long *p, long value, size_t count)
+{
+    long *pstart = p;
+    long *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+cdouble *_memset128(cdouble *p, cdouble value, size_t count)
+{
+    cdouble *pstart = p;
+    cdouble *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+real *_memset80(real *p, real value, size_t count)
+{
+    real *pstart = p;
+    real *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+creal *_memset160(creal *p, creal value, size_t count)
+{
+    creal *pstart = p;
+    creal *ptop;
+
+    for (ptop = &p[count]; p < ptop; p++)
+        *p = value;
+    return pstart;
+}
+
+void *_memsetn(void *p, void *value, int count, size_t sizelem)
+{   void *pstart = p;
+    int i;
+
+    for (i = 0; i < count; i++)
+    {
+        memcpy(p, value, sizelem);
+        p = cast(void *)(cast(char *)p + sizelem);
+    }
+    return pstart;
+}
Index: src/compiler/ldc/rt/qsort2.d
===================================================================
--- src/compiler/ldc/rt/qsort2.d	(revision 0)
+++ src/compiler/ldc/rt/qsort2.d	(revision 0)
@@ -0,0 +1,71 @@
+/**
+ * This is a public domain version of qsort.d.  All it does is call C's
+ * qsort(), but runs a little slower since it needs to synchronize a global
+ * variable.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.qsort2;
+
+//debug=qsort;
+
+private import core.stdc.stdlib;
+
+struct Array
+{
+    size_t length;
+    void*  ptr;
+}
+
+private TypeInfo tiglobal;
+
+extern (C) int cmp(const void* p1, const void* p2)
+{
+    return tiglobal.compare(p1, p2);
+}
+
+extern (C) long _adSort(Array a, TypeInfo ti)
+{
+    synchronized
+    {
+        tiglobal = ti;
+        qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp);
+    }
+    return *cast(long*)(&a);
+}
+
+
+
+unittest
+{
+    debug(qsort) printf("array.sort.unittest()\n");
+
+    int a[] = new int[10];
+
+    a[0] = 23;
+    a[1] = 1;
+    a[2] = 64;
+    a[3] = 5;
+    a[4] = 6;
+    a[5] = 5;
+    a[6] = 17;
+    a[7] = 3;
+    a[8] = 0;
+    a[9] = -1;
+
+    a.sort;
+
+    for (int i = 0; i < a.length - 1; i++)
+    {
+        //printf("i = %d", i);
+        //printf(" %d %d\n", a[i], a[i + 1]);
+        assert(a[i] <= a[i + 1]);
+    }
+}
Index: src/compiler/ldc/rt/util/utf.d
===================================================================
--- src/compiler/ldc/rt/util/utf.d	(revision 0)
+++ src/compiler/ldc/rt/util/utf.d	(revision 0)
@@ -0,0 +1,901 @@
+/********************************************
+ * Encode and decode UTF-8, UTF-16 and UTF-32 strings.
+ *
+ * For Win32 systems, the C wchar_t type is UTF-16 and corresponds to the D
+ * wchar type.
+ * For Posix systems, the C wchar_t type is UTF-32 and corresponds to
+ * the D utf.dchar type.
+ *
+ * UTF character support is restricted to (\u0000 &lt;= character &lt;= \U0010FFFF).
+ *
+ * See_Also:
+ *	$(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)<br>
+ *	$(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)<br>
+ *	$(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335)
+ * Macros:
+ *	WIKI = Phobos/StdUtf
+ *
+ * Copyright: Copyright Digital Mars 2003 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2003 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.util.utf;
+
+
+extern (C) void onUnicodeError( string msg, size_t idx );
+
+/*******************************
+ * Test if c is a valid UTF-32 character.
+ *
+ * \uFFFE and \uFFFF are considered valid by this function,
+ * as they are permitted for internal use by an application,
+ * but they are not allowed for interchange by the Unicode standard.
+ *
+ * Returns: true if it is, false if not.
+ */
+
+bool isValidDchar(dchar c)
+{
+    /* Note: FFFE and FFFF are specifically permitted by the
+     * Unicode standard for application internal use, but are not
+     * allowed for interchange.
+     * (thanks to Arcane Jill)
+     */
+
+    return c < 0xD800 ||
+	(c > 0xDFFF && c <= 0x10FFFF /*&& c != 0xFFFE && c != 0xFFFF*/);
+}
+
+unittest
+{
+    debug(utf) printf("utf.isValidDchar.unittest\n");
+    assert(isValidDchar(cast(dchar)'a') == true);
+    assert(isValidDchar(cast(dchar)0x1FFFFF) == false);
+}
+
+
+
+immutable UTF8stride =
+[
+    cast(ubyte)
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+    3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
+    4,4,4,4,4,4,4,4,5,5,5,5,6,6,0xFF,0xFF,
+];
+
+/**
+ * stride() returns the length of a UTF-8 sequence starting at index i
+ * in string s.
+ * Returns:
+ *	The number of bytes in the UTF-8 sequence or
+ *	0xFF meaning s[i] is not the start of of UTF-8 sequence.
+ */
+uint stride(in char[] s, size_t i)
+{
+    return UTF8stride[s[i]];
+}
+
+/**
+ * stride() returns the length of a UTF-16 sequence starting at index i
+ * in string s.
+ */
+uint stride(in wchar[] s, size_t i)
+{   uint u = s[i];
+    return 1 + (u >= 0xD800 && u <= 0xDBFF);
+}
+
+/**
+ * stride() returns the length of a UTF-32 sequence starting at index i
+ * in string s.
+ * Returns: The return value will always be 1.
+ */
+uint stride(in dchar[] s, size_t i)
+{
+    return 1;
+}
+
+/*******************************************
+ * Given an index i into an array of characters s[],
+ * and assuming that index i is at the start of a UTF character,
+ * determine the number of UCS characters up to that index i.
+ */
+
+size_t toUCSindex(in char[] s, size_t i)
+{
+    size_t n;
+    size_t j;
+
+    for (j = 0; j < i; )
+    {
+	j += stride(s, j);
+	n++;
+    }
+    if (j > i)
+    {
+        onUnicodeError("invalid UTF-8 sequence", j);
+    }
+    return n;
+}
+
+/** ditto */
+size_t toUCSindex(in wchar[] s, size_t i)
+{
+    size_t n;
+    size_t j;
+
+    for (j = 0; j < i; )
+    {
+	j += stride(s, j);
+	n++;
+    }
+    if (j > i)
+    {
+        onUnicodeError("invalid UTF-16 sequence", j);
+    }
+    return n;
+}
+
+/** ditto */
+size_t toUCSindex(in dchar[] s, size_t i)
+{
+    return i;
+}
+
+/******************************************
+ * Given a UCS index n into an array of characters s[], return the UTF index.
+ */
+
+size_t toUTFindex(in char[] s, size_t n)
+{
+    size_t i;
+
+    while (n--)
+    {
+	uint j = UTF8stride[s[i]];
+	if (j == 0xFF)
+	    onUnicodeError("invalid UTF-8 sequence", i);
+	i += j;
+    }
+    return i;
+}
+
+/** ditto */
+size_t toUTFindex(in wchar[] s, size_t n)
+{
+    size_t i;
+
+    while (n--)
+    {	wchar u = s[i];
+
+	i += 1 + (u >= 0xD800 && u <= 0xDBFF);
+    }
+    return i;
+}
+
+/** ditto */
+size_t toUTFindex(in dchar[] s, size_t n)
+{
+    return n;
+}
+
+/* =================== Decode ======================= */
+
+/***************
+ * Decodes and returns character starting at s[idx]. idx is advanced past the
+ * decoded character. If the character is not well formed, a UtfException is
+ * thrown and idx remains unchanged.
+ */
+dchar decode(in char[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    out (result)
+    {
+	assert(isValidDchar(result));
+    }
+    body
+    {
+	size_t len = s.length;
+	dchar V;
+	size_t i = idx;
+	char u = s[i];
+
+	if (u & 0x80)
+	{   uint n;
+	    char u2;
+
+	    /* The following encodings are valid, except for the 5 and 6 byte
+	     * combinations:
+	     *	0xxxxxxx
+	     *	110xxxxx 10xxxxxx
+	     *	1110xxxx 10xxxxxx 10xxxxxx
+	     *	11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     *	111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     *	1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+	     */
+	    for (n = 1; ; n++)
+	    {
+		if (n > 4)
+		    goto Lerr;		// only do the first 4 of 6 encodings
+		if (((u << n) & 0x80) == 0)
+		{
+		    if (n == 1)
+			goto Lerr;
+		    break;
+		}
+	    }
+
+	    // Pick off (7 - n) significant bits of B from first byte of octet
+	    V = cast(dchar)(u & ((1 << (7 - n)) - 1));
+
+	    if (i + (n - 1) >= len)
+		goto Lerr;			// off end of string
+
+	    /* The following combinations are overlong, and illegal:
+	     *	1100000x (10xxxxxx)
+	     *	11100000 100xxxxx (10xxxxxx)
+	     *	11110000 1000xxxx (10xxxxxx 10xxxxxx)
+	     *	11111000 10000xxx (10xxxxxx 10xxxxxx 10xxxxxx)
+	     *	11111100 100000xx (10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx)
+	     */
+	    u2 = s[i + 1];
+	    if ((u & 0xFE) == 0xC0 ||
+		(u == 0xE0 && (u2 & 0xE0) == 0x80) ||
+		(u == 0xF0 && (u2 & 0xF0) == 0x80) ||
+		(u == 0xF8 && (u2 & 0xF8) == 0x80) ||
+		(u == 0xFC && (u2 & 0xFC) == 0x80))
+		goto Lerr;			// overlong combination
+
+	    for (uint j = 1; j != n; j++)
+	    {
+		u = s[i + j];
+		if ((u & 0xC0) != 0x80)
+		    goto Lerr;			// trailing bytes are 10xxxxxx
+		V = (V << 6) | (u & 0x3F);
+	    }
+	    if (!isValidDchar(V))
+		goto Lerr;
+	    i += n;
+	}
+	else
+	{
+	    V = cast(dchar) u;
+	    i++;
+	}
+
+	idx = i;
+	return V;
+
+      Lerr:
+      onUnicodeError("invalid UTF-8 sequence", i);
+    return V; // dummy return
+    }
+
+unittest
+{   size_t i;
+    dchar c;
+
+    debug(utf) printf("utf.decode.unittest\n");
+
+    static s1 = "abcd"c;
+    i = 0;
+    c = decode(s1, i);
+    assert(c == cast(dchar)'a');
+    assert(i == 1);
+    c = decode(s1, i);
+    assert(c == cast(dchar)'b');
+    assert(i == 2);
+
+    static s2 = "\xC2\xA9"c;
+    i = 0;
+    c = decode(s2, i);
+    assert(c == cast(dchar)'\u00A9');
+    assert(i == 2);
+
+    static s3 = "\xE2\x89\xA0"c;
+    i = 0;
+    c = decode(s3, i);
+    assert(c == cast(dchar)'\u2260');
+    assert(i == 3);
+
+    static s4 =
+    [	"\xE2\x89"c[],		// too short
+	"\xC0\x8A",
+	"\xE0\x80\x8A",
+	"\xF0\x80\x80\x8A",
+	"\xF8\x80\x80\x80\x8A",
+	"\xFC\x80\x80\x80\x80\x8A",
+    ];
+
+    for (int j = 0; j < s4.length; j++)
+    {
+	try
+	{
+	    i = 0;
+	    c = decode(s4[j], i);
+	    assert(0);
+	}
+	catch (Object o)
+	{
+	    i = 23;
+	}
+	assert(i == 23);
+    }
+}
+
+/** ditto */
+
+dchar decode(in wchar[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    out (result)
+    {
+	assert(isValidDchar(result));
+    }
+    body
+    {
+	string msg;
+	dchar V;
+	size_t i = idx;
+	uint u = s[i];
+
+	if (u & ~0x7F)
+	{   if (u >= 0xD800 && u <= 0xDBFF)
+	    {   uint u2;
+
+		if (i + 1 == s.length)
+		{   msg = "surrogate UTF-16 high value past end of string";
+		    goto Lerr;
+		}
+		u2 = s[i + 1];
+		if (u2 < 0xDC00 || u2 > 0xDFFF)
+		{   msg = "surrogate UTF-16 low value out of range";
+		    goto Lerr;
+		}
+		u = ((u - 0xD7C0) << 10) + (u2 - 0xDC00);
+		i += 2;
+	    }
+	    else if (u >= 0xDC00 && u <= 0xDFFF)
+	    {   msg = "unpaired surrogate UTF-16 value";
+		goto Lerr;
+	    }
+	    else if (u == 0xFFFE || u == 0xFFFF)
+	    {   msg = "illegal UTF-16 value";
+		goto Lerr;
+	    }
+	    else
+		i++;
+	}
+	else
+	{
+	    i++;
+	}
+
+	idx = i;
+	return cast(dchar)u;
+
+      Lerr:
+	  onUnicodeError(msg, i);
+	return cast(dchar)u; // dummy return
+    }
+
+/** ditto */
+
+dchar decode(in dchar[] s, inout size_t idx)
+    in
+    {
+	assert(idx >= 0 && idx < s.length);
+    }
+    body
+    {
+	size_t i = idx;
+	dchar c = s[i];
+
+	if (!isValidDchar(c))
+	    goto Lerr;
+	idx = i + 1;
+	return c;
+
+      Lerr:
+	  onUnicodeError("invalid UTF-32 value", i);
+	return c; // dummy return
+    }
+
+
+/* =================== Encode ======================= */
+
+/*******************************
+ * Encodes character c and appends it to array s[].
+ */
+void encode(inout char[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	char[] r = s;
+
+	if (c <= 0x7F)
+	{
+	    r ~= cast(char) c;
+	}
+	else
+	{
+	    char[4] buf;
+	    uint L;
+
+	    if (c <= 0x7FF)
+	    {
+		buf[0] = cast(char)(0xC0 | (c >> 6));
+		buf[1] = cast(char)(0x80 | (c & 0x3F));
+		L = 2;
+	    }
+	    else if (c <= 0xFFFF)
+	    {
+		buf[0] = cast(char)(0xE0 | (c >> 12));
+		buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+		buf[2] = cast(char)(0x80 | (c & 0x3F));
+		L = 3;
+	    }
+	    else if (c <= 0x10FFFF)
+	    {
+		buf[0] = cast(char)(0xF0 | (c >> 18));
+		buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
+		buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+		buf[3] = cast(char)(0x80 | (c & 0x3F));
+		L = 4;
+	    }
+	    else
+	    {
+		assert(0);
+	    }
+	    r ~= buf[0 .. L];
+	}
+	s = r;
+    }
+
+unittest
+{
+    debug(utf) printf("utf.encode.unittest\n");
+
+    char[] s = "abcd".dup;
+    encode(s, cast(dchar)'a');
+    assert(s.length == 5);
+    assert(s == "abcda");
+
+    encode(s, cast(dchar)'\u00A9');
+    assert(s.length == 7);
+    assert(s == "abcda\xC2\xA9");
+    //assert(s == "abcda\u00A9");	// BUG: fix compiler
+
+    encode(s, cast(dchar)'\u2260');
+    assert(s.length == 10);
+    assert(s == "abcda\xC2\xA9\xE2\x89\xA0");
+}
+
+/** ditto */
+
+void encode(inout wchar[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	wchar[] r = s;
+
+	if (c <= 0xFFFF)
+	{
+	    r ~= cast(wchar) c;
+	}
+	else
+	{
+	    wchar[2] buf;
+
+	    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
+	    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
+	    r ~= buf;
+	}
+	s = r;
+    }
+
+/** ditto */
+void encode(inout dchar[] s, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	s ~= c;
+    }
+
+/**
+Returns the code length of $(D c) in the encoding using $(D C) as a
+code point. The code is returned in character count, not in bytes.
+ */
+
+ubyte codeLength(C)(dchar c)
+{
+
+    static if (C.sizeof == 1)
+    {
+        return
+            c <= 0x7F ? 1
+            : c <= 0x7FF ? 2
+            : c <= 0xFFFF ? 3
+            : c <= 0x10FFFF ? 4
+            : (assert(false), 6);
+}
+
+    else static if (C.sizeof == 2)
+{
+	return c <= 0xFFFF ? 1 : 2;
+    }
+    else
+    {
+        static assert(C.sizeof == 4);
+        return 1;
+    }
+}
+
+/* =================== Validation ======================= */
+
+/***********************************
+Checks to see if string is well formed or not. $(D S) can be an array
+ of $(D char), $(D wchar), or $(D dchar). Throws a $(D UtfException)
+ if it is not. Use to check all untrusted input for correctness.
+ */
+void validate(S)(in S s)
+{
+    auto len = s.length;
+    for (size_t i = 0; i < len; )
+    {
+	decode(s, i);
+    }
+}
+
+/* =================== Conversion to UTF8 ======================= */
+
+char[] toUTF8(char[4] buf, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	if (c <= 0x7F)
+	{
+	    buf[0] = cast(char) c;
+	    return buf[0 .. 1];
+	}
+	else if (c <= 0x7FF)
+	{
+	    buf[0] = cast(char)(0xC0 | (c >> 6));
+	    buf[1] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 2];
+	}
+	else if (c <= 0xFFFF)
+	{
+	    buf[0] = cast(char)(0xE0 | (c >> 12));
+	    buf[1] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+	    buf[2] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 3];
+	}
+	else if (c <= 0x10FFFF)
+	{
+	    buf[0] = cast(char)(0xF0 | (c >> 18));
+	    buf[1] = cast(char)(0x80 | ((c >> 12) & 0x3F));
+	    buf[2] = cast(char)(0x80 | ((c >> 6) & 0x3F));
+	    buf[3] = cast(char)(0x80 | (c & 0x3F));
+	    return buf[0 .. 4];
+	}
+	assert(0);
+    }
+
+/*******************
+ * Encodes string s into UTF-8 and returns the encoded string.
+ */
+string toUTF8(string s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/** ditto */
+string toUTF8(in wchar[] s)
+{
+    char[] r;
+    size_t i;
+    size_t slen = s.length;
+
+    r.length = slen;
+
+    for (i = 0; i < slen; i++)
+    {	wchar c = s[i];
+
+	if (c <= 0x7F)
+	    r[i] = cast(char)c;		// fast path for ascii
+	else
+	{
+	    r.length = i;
+	    foreach (dchar c; s[i .. slen])
+	    {
+		encode(r, c);
+	    }
+	    break;
+	}
+    }
+    return cast(string)r;
+}
+
+/** ditto */
+string toUTF8(in dchar[] s)
+{
+    char[] r;
+    size_t i;
+    size_t slen = s.length;
+
+    r.length = slen;
+
+    for (i = 0; i < slen; i++)
+    {	dchar c = s[i];
+
+	if (c <= 0x7F)
+	    r[i] = cast(char)c;		// fast path for ascii
+	else
+	{
+	    r.length = i;
+	    foreach (dchar d; s[i .. slen])
+	    {
+		encode(r, d);
+	    }
+	    break;
+	}
+    }
+    return cast(string)r;
+}
+
+/* =================== Conversion to UTF16 ======================= */
+
+wchar[] toUTF16(wchar[2] buf, dchar c)
+    in
+    {
+	assert(isValidDchar(c));
+    }
+    body
+    {
+	if (c <= 0xFFFF)
+	{
+	    buf[0] = cast(wchar) c;
+	    return buf[0 .. 1];
+	}
+	else
+	{
+	    buf[0] = cast(wchar) ((((c - 0x10000) >> 10) & 0x3FF) + 0xD800);
+	    buf[1] = cast(wchar) (((c - 0x10000) & 0x3FF) + 0xDC00);
+	    return buf[0 .. 2];
+	}
+    }
+
+/****************
+ * Encodes string s into UTF-16 and returns the encoded string.
+ * toUTF16z() is suitable for calling the 'W' functions in the Win32 API that take
+ * an LPWSTR or LPCWSTR argument.
+ */
+wstring toUTF16(in char[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen;
+    r.length = 0;
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c <= 0x7F)
+	{
+	    i++;
+	    r ~= cast(wchar)c;
+	}
+	else
+	{
+	    c = decode(s, i);
+	    encode(r, c);
+	}
+    }
+    return cast(wstring)r;
+}
+
+alias const(wchar)* wptr;
+/** ditto */
+wptr toUTF16z(in char[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen + 1;
+    r.length = 0;
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c <= 0x7F)
+	{
+	    i++;
+	    r ~= cast(wchar)c;
+	}
+	else
+	{
+	    c = decode(s, i);
+	    encode(r, c);
+	}
+    }
+    r ~= "\000";
+    return r.ptr;
+}
+
+/** ditto */
+wstring toUTF16(wstring s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/** ditto */
+wstring toUTF16(in dchar[] s)
+{
+    wchar[] r;
+    size_t slen = s.length;
+
+    r.length = slen;
+    r.length = 0;
+    for (size_t i = 0; i < slen; i++)
+    {
+	encode(r, s[i]);
+    }
+    return cast(wstring)r;
+}
+
+/* =================== Conversion to UTF32 ======================= */
+
+/*****
+ * Encodes string s into UTF-32 and returns the encoded string.
+ */
+dstring toUTF32(in char[] s)
+{
+    dchar[] r;
+    size_t slen = s.length;
+    size_t j = 0;
+
+    r.length = slen;		// r[] will never be longer than s[]
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c >= 0x80)
+	    c = decode(s, i);
+	else
+	    i++;		// c is ascii, no need for decode
+	r[j++] = c;
+    }
+    return cast(dstring)r[0 .. j];
+}
+
+/** ditto */
+dstring toUTF32(in wchar[] s)
+{
+    dchar[] r;
+    size_t slen = s.length;
+    size_t j = 0;
+
+    r.length = slen;		// r[] will never be longer than s[]
+    for (size_t i = 0; i < slen; )
+    {
+	dchar c = s[i];
+	if (c >= 0x80)
+	    c = decode(s, i);
+	else
+	    i++;		// c is ascii, no need for decode
+	r[j++] = c;
+    }
+    return cast(dstring)r[0 .. j];
+}
+
+/** ditto */
+dstring toUTF32(dstring s)
+    in
+    {
+	validate(s);
+    }
+    body
+    {
+	return s;
+    }
+
+/* ================================ tests ================================== */
+
+unittest
+{
+    debug(utf) printf("utf.toUTF.unittest\n");
+
+    auto c = "hello"c[];
+    auto w = toUTF16(c);
+    assert(w == "hello");
+    auto d = toUTF32(c);
+    assert(d == "hello");
+
+    c = toUTF8(w);
+    assert(c == "hello");
+    d = toUTF32(w);
+    assert(d == "hello");
+
+    c = toUTF8(d);
+    assert(c == "hello");
+    w = toUTF16(d);
+    assert(w == "hello");
+
+
+    c = "hel\u1234o";
+    w = toUTF16(c);
+    assert(w == "hel\u1234o");
+    d = toUTF32(c);
+    assert(d == "hel\u1234o");
+
+    c = toUTF8(w);
+    assert(c == "hel\u1234o");
+    d = toUTF32(w);
+    assert(d == "hel\u1234o");
+
+    c = toUTF8(d);
+    assert(c == "hel\u1234o");
+    w = toUTF16(d);
+    assert(w == "hel\u1234o");
+
+
+    c = "he\U0010AAAAllo";
+    w = toUTF16(c);
+    //foreach (wchar c; w) printf("c = x%x\n", c);
+    //foreach (wchar c; cast(wstring)"he\U0010AAAAllo") printf("c = x%x\n", c);
+    assert(w == "he\U0010AAAAllo");
+    d = toUTF32(c);
+    assert(d == "he\U0010AAAAllo");
+
+    c = toUTF8(w);
+    assert(c == "he\U0010AAAAllo");
+    d = toUTF32(w);
+    assert(d == "he\U0010AAAAllo");
+
+    c = toUTF8(d);
+    assert(c == "he\U0010AAAAllo");
+    w = toUTF16(d);
+    assert(w == "he\U0010AAAAllo");
+}
Index: src/compiler/ldc/rt/util/console.d
===================================================================
--- src/compiler/ldc/rt/util/console.d	(revision 0)
+++ src/compiler/ldc/rt/util/console.d	(revision 0)
@@ -0,0 +1,54 @@
+/**
+ * The console module contains some simple routines for console output.
+ *
+ * Copyright: Copyright Sean Kelly 2005 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Sean Kelly
+ *
+ *          Copyright Sean Kelly 2005 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.util.console;
+
+
+private
+{
+    version (Windows)
+    {
+        import core.sys.windows.windows;
+    }
+    else version( Posix )
+    {
+        import core.sys.posix.unistd;
+    }
+    import rt.util.string;
+}
+
+
+struct Console
+{
+    Console opCall( in char[] val )
+    {
+        version( Windows )
+        {
+            uint count = void;
+            WriteFile( GetStdHandle( 0xfffffff5 ), val.ptr, val.length, &count, null );
+        }
+        else version( Posix )
+        {
+            write( 2, val.ptr, val.length );
+        }
+        return this;
+    }
+
+
+    Console opCall( size_t val )
+    {
+            char[10] tmp = void;
+            return opCall( tmp.intToString( val ) );
+    }
+}
+
+__gshared Console console;
Index: src/compiler/ldc/rt/util/cpuid.d
===================================================================
--- src/compiler/ldc/rt/util/cpuid.d	(revision 0)
+++ src/compiler/ldc/rt/util/cpuid.d	(revision 0)
@@ -0,0 +1,719 @@
+/** 
+ * Identify the characteristics of the host CPU, providing information
+ * about cache sizes and assembly optimisation hints.
+ *
+ * Some of this information was extremely difficult to track down. Some of the
+ * documents below were found only in cached versions stored by search engines!
+ * This code relies on information found in:
+    
+ * - "Intel(R) 64 and IA-32 Architectures Software Developers Manual,
+ *    Volume 2A: Instruction Set Reference, A-M" (2007).
+ * - "AMD CPUID Specification", Advanced Micro Devices, Rev 2.28 (2008).
+ * - "AMD Processor Recognition Application Note For Processors Prior to AMD
+ *    Family 0Fh Processors", Advanced Micro Devices, Rev 3.13 (2005).
+ * - "AMD Geode(TM) GX Processors Data Book",
+ *    Advanced Micro Devices, Publication ID 31505E, (2005).
+ * - "AMD K6 Processor Code Optimisation", Advanced Micro Devices, Rev D (2000).
+ * - "Application note 106: Software Customization for the 6x86 Family",
+ *    Cyrix Corporation, Rev 1.5 (1998)
+ * - http://ftp.intron.ac/pub/document/cpu/cpuid.htm
+ * - "Geode(TM) GX1 Processor Series Low Power Integrated X86 Solution",
+ *   National Semiconductor, (2002)
+ * - "The VIA Isaiah Architecture", G. Glenn Henry, Centaur Technology, Inc (2008).
+ * - http://www.sandpile.org/ia32/cpuid.htm
+ * - http://grafi.ii.pw.edu.pl/gbm/x86/cpuid.html
+ * - "What every programmer should know about memory",
+ *    Ulrich Depper, Red Hat, Inc., (2007). 
+ * 
+ * Bugs: Currently only works on x86 and Itanium CPUs.
+ *      Many processors have bugs in their microcode for the CPUID instruction,
+ *      so sometimes the cache information may be incorrect.
+ *
+ * Copyright: Copyright Don Clugston 2007 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Don Clugston, Tomas Lindquist Olsen &lt;tomas@famolsen.dk&gt;
+ *
+ *          Copyright Don Clugston 2007 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.util.cpuid;
+
+// If optimizing for a particular processor, it is generally better
+// to identify based on features rather than model. NOTE: Normally
+// it's only worthwhile to optimise for the latest Intel and AMD CPU,
+// with a backup for other CPUs.
+// Pentium    -- preferPentium1()
+// PMMX       --   + mmx()
+// PPro       -- default
+// PII        --   + mmx()
+// PIII       --   + mmx() + sse()
+// PentiumM   --   + mmx() + sse() + sse2()
+// Pentium4   -- preferPentium4()
+// PentiumD   --   + isX86_64()
+// Core2      -- default + isX86_64()
+// AMD K5     -- preferPentium1()
+// AMD K6     --   + mmx()
+// AMD K6-II  --   + mmx() + 3dnow()
+// AMD K7     -- preferAthlon()
+// AMD K8     --   + sse2()
+// AMD K10    --   + isX86_64()
+// Cyrix 6x86 -- preferPentium1()
+//    6x86MX  --   + mmx()
+
+public:
+
+/// Cache size and behaviour
+struct CacheInfo
+{
+    /// Size of the cache, in kilobytes, per CPU.
+    /// For L1 unified (data + code) caches, this size is half the physical size.
+    /// (we don't halve it for larger sizes, since normally
+    /// data size is much greater than code size for critical loops).
+    uint size;
+    /// Number of ways of associativity, eg:
+    /// 1 = direct mapped
+    /// 2 = 2-way set associative
+    /// 3 = 3-way set associative
+    /// ubyte.max = fully associative
+    ubyte associativity;
+    /// Number of bytes read into the cache when a cache miss occurs.
+    uint lineSize;
+}
+
+public:
+    /// Returns vendor string, for display purposes only.
+    /// Do NOT use this to determine features!
+    /// Note that some CPUs have programmable vendorIDs.
+    char[] vendor()     {return vendorID;}
+    /// Returns processor string, for display purposes only
+    char[] processor()  {return processorName;}    
+    
+    /// The data caches. If there are fewer than 5 physical caches levels,
+    /// the remaining levels are set to uint.max (== entire memory space)
+    __gshared CacheInfo[5] datacache;
+    /// Does it have an x87 FPU on-chip?
+    bool x87onChip()    {return (features&FPU_BIT)!=0;}
+    /// Is MMX supported?
+    bool mmx()          {return (features&MMX_BIT)!=0;}
+    /// Is SSE supported?
+    bool sse()          {return (features&SSE_BIT)!=0;}
+    /// Is SSE2 supported?
+    bool sse2()         {return (features&SSE2_BIT)!=0;}
+    /// Is SSE3 supported?
+    bool sse3()         {return (miscfeatures&SSE3_BIT)!=0;}
+    /// Is SSSE3 supported?
+    bool ssse3()        {return (miscfeatures&SSSE3_BIT)!=0;}
+    /// Is SSE4.1 supported?
+    bool sse41()        {return (miscfeatures&SSE41_BIT)!=0;}
+    /// Is SSE4.2 supported?
+    bool sse42()        {return (miscfeatures&SSE42_BIT)!=0;}
+    /// Is SSE4a supported?
+    bool sse4a()        {return (amdmiscfeatures&SSE4A_BIT)!=0;}
+    /// Is SSE5 supported?
+    bool sse5()         {return (amdmiscfeatures&SSE5_BIT)!=0;}
+    /// Is AMD 3DNOW supported?
+    bool amd3dnow()     {return (amdfeatures&AMD_3DNOW_BIT)!=0;}
+    /// Is AMD 3DNOW Ext supported?
+    bool amd3dnowExt()  {return (amdfeatures&AMD_3DNOW_EXT_BIT)!=0;}
+    /// Are AMD extensions to MMX supported?
+    bool amdMmx()       {return (amdfeatures&AMD_MMX_BIT)!=0;}
+    /// Is fxsave/fxrstor supported?
+    bool hasFxsr()          {return (features&FXSR_BIT)!=0;}
+    /// Is cmov supported?
+    bool hasCmov()          {return (features&CMOV_BIT)!=0;}
+    /// Is rdtsc supported?
+    bool hasRdtsc()         {return (features&TIMESTAMP_BIT)!=0;}
+    /// Is cmpxchg8b supported?
+    bool hasCmpxchg8b()     {return (features&CMPXCHG8B_BIT)!=0;}
+    /// Is cmpxchg8b supported?
+    bool hasCmpxchg16b()    {return (miscfeatures&CMPXCHG16B_BIT)!=0;}
+    /// Is 3DNow prefetch supported?
+    bool has3dnowPrefetch()
+        {return (amdmiscfeatures&AMD_3DNOW_PREFETCH_BIT)!=0;}
+    /// Are LAHF and SAHF supported in 64-bit mode?
+    bool hasLahfSahf()          {return (amdmiscfeatures&LAHFSAHF_BIT)!=0;}
+    /// Is POPCNT supported?
+    bool hasPopcnt()        {return (miscfeatures&POPCNT_BIT)!=0;}    
+    /// Is LZCNT supported?
+    bool hasLzcnt()         {return (amdmiscfeatures&LZCNT_BIT)!=0;}
+    /// Is this an Intel64 or AMD 64?
+    bool isX86_64()         {return (amdfeatures&AMD64_BIT)!=0;}
+            
+    /// Is this an IA64 (Itanium) processor?
+    bool isItanium()        { return (features&IA64_BIT)!=0; }
+
+    /// Is hyperthreading supported?
+    bool hyperThreading()   { return maxThreads>maxCores; }
+    /// Returns number of threads per CPU
+    uint threadsPerCPU()    {return maxThreads;}
+    /// Returns number of cores in CPU
+    uint coresPerCPU()      {return maxCores;}
+    
+    /// Optimisation hints for assembly code.
+    /// For forward compatibility, the CPU is compared against different
+    /// microarchitectures. For 32-bit X86, comparisons are made against
+    /// the Intel PPro/PII/PIII/PM family.
+    ///
+    /// The major 32-bit x86 microarchitecture 'dynasties' have been:
+    /// (1) Intel P6 (PentiumPro, PII, PIII, PM, Core, Core2).
+    /// (2) AMD Athlon (K7, K8, K10).
+    /// (3) Intel NetBurst (Pentium 4, Pentium D).
+    /// (4) In-order Pentium (Pentium1, PMMX)
+    /// Other early CPUs (Nx586, AMD K5, K6, Centaur C3, Transmeta,
+    ///   Cyrix, Rise) were mostly in-order.
+    /// Some new processors do not fit into the existing categories:
+    /// Intel Atom 230/330 (family 6, model 0x1C) is an in-order core.
+    /// Centaur Isiah = VIA Nano (family 6, model F) is an out-of-order core.
+    ///
+    /// Within each dynasty, the optimisation techniques are largely
+    /// identical (eg, use instruction pairing for group 4). Major
+    /// instruction set improvements occur within each group.
+    
+    /// Does this CPU perform better on AMD K7 code than PentiumPro..Core2 code?
+    bool preferAthlon() { return probablyAMD && family >=6; }
+    /// Does this CPU perform better on Pentium4 code than PentiumPro..Core2 code?
+    bool preferPentium4() { return probablyIntel && family == 0xF; }
+    /// Does this CPU perform better on Pentium I code than Pentium Pro code?
+    bool preferPentium1() { return family < 6 || (family==6 && model < 0xF && !probablyIntel); }
+
+__gshared:
+public:
+    /// Processor type (vendor-dependent).
+    /// This should be visible ONLY for display purposes.
+    uint stepping, model, family;
+    uint numCacheLevels = 1;
+private:
+    bool probablyIntel; // true = _probably_ an Intel processor, might be faking
+    bool probablyAMD; // true = _probably_ an AMD processor
+    char [12] vendorID;
+    char [] processorName;
+    char [48] processorNameBuffer;
+    uint features = 0;     // mmx, sse, sse2, hyperthreading, etc
+    uint miscfeatures = 0; // sse3, etc.
+    uint amdfeatures = 0;  // 3DNow!, mmxext, etc
+    uint amdmiscfeatures = 0; // sse4a, sse5, svm, etc
+    uint maxCores = 1;
+    uint maxThreads = 1;
+    // Note that this may indicate multi-core rather than hyperthreading.
+    bool hyperThreadingBit()    { return (features&HTT_BIT)!=0;}
+    
+    // feature flags CPUID1_EDX
+    enum : uint
+    {
+        FPU_BIT = 1,
+        TIMESTAMP_BIT = 1<<4, // rdtsc
+        MDSR_BIT = 1<<5,      // RDMSR/WRMSR
+        CMPXCHG8B_BIT = 1<<8,
+            CMOV_BIT = 1<<15,
+        MMX_BIT = 1<<23,
+        FXSR_BIT = 1<<24,
+        SSE_BIT = 1<<25,
+        SSE2_BIT = 1<<26,
+        HTT_BIT = 1<<28,
+        IA64_BIT = 1<<30
+    }
+    // feature flags misc CPUID1_ECX
+    enum : uint
+    {
+        SSE3_BIT = 1,
+            PCLMULQDQ_BIT = 1<<1, // from AVX
+        MWAIT_BIT = 1<<3,
+        SSSE3_BIT = 1<<9,
+            FMA_BIT = 1<<12,     // from AVX
+        CMPXCHG16B_BIT = 1<<13,
+        SSE41_BIT = 1<<19,
+        SSE42_BIT = 1<<20,
+        POPCNT_BIT = 1<<23,
+            AES_BIT = 1<<25, // AES instructions from AVX
+            OSXSAVE_BIT = 1<<27, // Used for AVX
+            AVX_BIT = 1<<28
+    }
+/+    
+version(X86_64) {    
+    bool hasAVXinHardware() {
+        // This only indicates hardware support, not OS support.
+        return (miscfeatures&AVX_BIT) && (miscfeatures&OSXSAVE_BIT);
+    }
+    // Is AVX supported (in both hardware & OS)?
+    bool Avx() {
+        if (!hasAVXinHardware()) return false;
+        // Check for OS support
+        uint xfeatures;
+        asm {mov ECX, 0; xgetbv; mov xfeatures, EAX; }
+        return (xfeatures&0x6)==6;
+    }
+    bool hasAvxFma() {
+        if (!AVX()) return false;
+        return (features&FMA_BIT)!=0;        
+    }
+}
++/    
+    // AMD feature flags CPUID80000001_EDX
+    enum : uint
+    {
+        AMD_MMX_BIT = 1<<22,
+//      FXR_OR_CYRIXMMX_BIT = 1<<24, // Cyrix/NS: 6x86MMX instructions. 
+        FFXSR_BIT = 1<<25,
+        PAGE1GB_BIT = 1<<26, // support for 1GB pages
+        RDTSCP_BIT = 1<<27,
+        AMD64_BIT = 1<<29,
+        AMD_3DNOW_EXT_BIT = 1<<30,
+        AMD_3DNOW_BIT = 1<<31
+    }
+    // AMD misc feature flags CPUID80000001_ECX
+    enum : uint
+    {
+        LAHFSAHF_BIT = 1,
+        LZCNT_BIT = 1<<5,
+        SSE4A_BIT = 1<<6,       
+        AMD_3DNOW_PREFETCH_BIT = 1<<8,
+        SSE5_BIT = 1<<11
+    }
+
+version(GNU){
+    // GDC is a filthy liar. It can't actually do inline asm.
+} else version(D_InlineAsm_X86) {
+    version = Really_D_InlineAsm_X86;
+}
+
+version(Really_D_InlineAsm_X86) {
+// Note that this code will also work for Itanium in x86 mode.
+
+shared uint max_cpuid, max_extended_cpuid;
+
+// CPUID2: "cache and tlb information"
+void getcacheinfoCPUID2()
+{
+    // We are only interested in the data caches
+    void decipherCpuid2(ubyte x) {
+        if (x==0) return;
+        // Values from http://www.sandpile.org/ia32/cpuid.htm.
+        // Includes Itanium and non-Intel CPUs.
+        //
+        immutable ubyte [47] ids = [
+            0x0A, 0x0C, 0x2C, 0x60, 0x0E, 0x66, 0x67, 0x68,
+            // level 2 cache
+            0x41, 0x42, 0x43, 0x44, 0x45, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7F,
+            0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x49, 0x4E,
+            0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x48, 0x80, 0x81,
+            // level 3 cache
+            0x22, 0x23, 0x25, 0x29, 0x46, 0x47, 0x4A, 0x4B, 0x4C, 0x4D
+        ];
+        immutable uint [47] sizes = [
+            8, 16, 32, 16, 24, 8, 16, 32,
+            128, 256, 512, 1024, 2048, 1024, 128, 256, 512, 1024, 2048, 512,
+            256, 512, 1024, 2048, 512, 1024, 4096, 6*1024,
+            128, 192, 128, 256, 384, 512, 3072, 512, 128,           
+            512, 1024, 2048, 4096, 4096, 8192, 6*1024, 8192, 12*1024, 16*1024
+        ];
+    // CPUBUG: Pentium M reports 0x2C but tests show it is only 4-way associative
+        immutable ubyte [47] ways = [
+            2, 4, 8, 8, 6, 4, 4, 4,
+            4, 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 2,
+            8, 8, 8, 8, 4, 8, 16, 24,
+            4, 6, 2, 4, 6, 4, 12, 8, 8,
+            4, 8, 8, 8, 4, 8, 12, 16, 12, 16
+        ];
+        enum { FIRSTDATA2 = 8, FIRSTDATA3 = 28+9 }
+        for (int i=0; i< ids.length; ++i) {
+            if (x==ids[i]) {
+                int level = i< FIRSTDATA2 ? 0: i<FIRSTDATA3 ? 1 : 2;
+                if (x==0x49 && family==0xF && model==0x6) level=2;
+                datacache[level].size=sizes[i];
+                datacache[level].associativity=ways[i];
+                if (level == 3 || x==0x2C || (x>=0x48 && x<=0x80) 
+                                   || x==0x86 || x==0x87
+                                   || (x>=0x66 && x<=0x68) || (x>=0x39 && x<=0x3E)){
+                    datacache[level].lineSize = 64;
+                } else datacache[level].lineSize = 32;
+            }
+        }
+    }
+
+    uint[4] a;  
+    bool firstTime = true;
+    // On a multi-core system, this could theoretically fail, but it's only used
+    // for old single-core CPUs.
+    uint numinfos = 1;
+    do {
+        asm {
+            mov EAX, 2;
+            cpuid;
+            mov a, EAX;
+            mov a+4, EBX;
+            mov a+8, ECX;
+            mov a+12, EDX;
+        }
+        if (firstTime) {
+            if (a[0]==0x0000_7001 && a[3]==0x80 && a[1]==0 && a[2]==0) {
+        // Cyrix MediaGX MMXEnhanced returns: EAX= 00007001, EDX=00000080.
+        // These are NOT standard Intel values
+        // (TLB = 32 entry, 4 way associative, 4K pages)
+        // (L1 cache = 16K, 4way, linesize16)
+                datacache[0].size=8;
+                datacache[0].associativity=4;
+                datacache[0].lineSize=16;
+                return;             
+            }
+            // lsb of a is how many times to loop.
+            numinfos = a[0] & 0xFF;
+            // and otherwise it should be ignored
+            a[0] &= 0xFFFF_FF00;
+            firstTime = false;
+        }
+        for (int c=0; c<4;++c) {
+            // high bit set == no info.
+            if (a[c] & 0x8000_0000) continue;
+            decipherCpuid2(cast(ubyte)(a[c] & 0xFF));
+            decipherCpuid2(cast(ubyte)((a[c]>>8) & 0xFF));
+            decipherCpuid2(cast(ubyte)((a[c]>>16) & 0xFF));
+            decipherCpuid2(cast(ubyte)((a[c]>>24) & 0xFF));
+        }
+    } while (--numinfos);
+}
+
+// CPUID4: "Deterministic cache parameters" leaf
+void getcacheinfoCPUID4()
+{
+    int cachenum = 0;
+    for(;;) {
+        uint a, b, number_of_sets;  
+        asm {
+            mov EAX, 4;
+            mov ECX, cachenum;
+            cpuid;
+            mov a, EAX;
+            mov b, EBX;
+            mov number_of_sets, ECX;
+        }
+        ++cachenum;
+        if ((a&0x1F)==0) break; // no more caches
+        uint numthreads = ((a>>14) & 0xFFF)  + 1;
+        uint numcores = ((a>>26) & 0x3F) + 1;
+        if (numcores > maxCores) maxCores = numcores;
+        if ((a&0x1F)!=1 && ((a&0x1F)!=3)) continue; // we only want data & unified caches
+        
+        ++number_of_sets;
+        ubyte level = cast(ubyte)(((a>>5)&7)-1);
+        if (level > datacache.length) continue; // ignore deep caches
+        datacache[level].associativity = a & 0x200 ? ubyte.max :cast(ubyte)((b>>22)+1);
+        datacache[level].lineSize = (b & 0xFFF)+ 1; // system coherency line size
+        uint line_partitions = ((b >> 12)& 0x3FF) + 1;
+        // Size = number of sets * associativity * cachelinesize * linepartitions
+        // and must convert to Kb, also dividing by the number of hyperthreads using this cache.
+        ulong sz = (datacache[level].associativity< ubyte.max)? number_of_sets *
+            datacache[level].associativity : number_of_sets;        
+        datacache[level].size = cast(uint)(
+                (sz * datacache[level].lineSize * line_partitions ) / (numthreads *1024));
+        if (level == 0 && (a&0xF)==3) {
+            // Halve the size for unified L1 caches
+            datacache[level].size/=2;
+        }
+    }
+}
+
+// CPUID8000_0005 & 6
+void getAMDcacheinfo()
+{
+    uint c5, c6, d6;
+    asm {
+        mov EAX, 0x8000_0005; // L1 cache
+        cpuid;
+        // EAX has L1_TLB_4M.
+        // EBX has L1_TLB_4K
+        // EDX has L1 instruction cache
+        mov c5, ECX;
+    }
+
+    datacache[0].size = ( (c5>>24) & 0xFF);
+    datacache[0].associativity = cast(ubyte)( (c5 >> 16) & 0xFF);
+    datacache[0].lineSize = c5 & 0xFF;
+
+    if (max_extended_cpuid >= 0x8000_0006) {
+        // AMD K6-III or K6-2+ or later.
+        ubyte numcores = 1;
+        if (max_extended_cpuid >=0x8000_0008) {
+            asm {
+                mov EAX, 0x8000_0008;
+                cpuid;
+                mov numcores, CL;
+            }
+            ++numcores;
+            if (numcores>maxCores) maxCores = numcores;
+        }
+        asm {
+            mov EAX, 0x8000_0006; // L2/L3 cache
+            cpuid;
+            mov c6, ECX; // L2 cache info
+            mov d6, EDX; // L3 cache info
+        }
+    
+        immutable ubyte [] assocmap = [ 0, 1, 2, 0, 4, 0, 8, 0, 16, 0, 32, 48, 64, 96, 128, 0xFF ];
+        datacache[1].size = (c6>>16) & 0xFFFF;
+        datacache[1].associativity = assocmap[(c6>>12)&0xF];
+        datacache[1].lineSize = c6 & 0xFF;
+        
+        // The L3 cache value is TOTAL, not per core.
+        datacache[2].size = ((d6>>18)*512)/numcores; // could be up to 2 * this, -1.
+        datacache[2].associativity = assocmap[(d6>>12)&0xF];
+        datacache[2].lineSize = d6 & 0xFF;
+    }
+}
+
+
+void cpuidX86()
+{
+    char * venptr = vendorID.ptr;
+    asm {
+        mov EAX, 0;
+        cpuid;
+        mov max_cpuid, EAX;
+        mov EAX, venptr;
+        mov [EAX], EBX;
+        mov [EAX + 4], EDX;
+        mov [EAX + 8], ECX;
+        mov EAX, 0x8000_0000;
+        cpuid;
+        mov max_extended_cpuid, EAX;
+    }
+    
+    probablyIntel = vendorID == "GenuineIntel";
+    probablyAMD = vendorID == "AuthenticAMD";
+    uint a, b, c, d;
+    uint apic = 0; // brand index, apic id
+    asm {
+        mov EAX, 1; // model, stepping
+        cpuid;
+        mov a, EAX;
+        mov apic, EBX;
+        mov miscfeatures, ECX;
+        mov features, EDX;
+    }
+    amdfeatures = 0;
+    amdmiscfeatures = 0;
+    if (max_extended_cpuid >= 0x8000_0001) {
+        asm {
+            mov EAX, 0x8000_0001;
+            cpuid;
+            mov amdmiscfeatures, ECX;
+            mov amdfeatures, EDX;
+        }
+    }
+    // Try to detect fraudulent vendorIDs
+    if (amd3dnow) probablyIntel = false;
+    
+    stepping = a & 0xF;
+    uint fbase = (a >> 8) & 0xF;
+    uint mbase = (a >> 4) & 0xF;
+    family = ((fbase == 0xF) || (fbase == 0)) ? fbase + (a >> 20) & 0xFF : fbase;
+    model = ((fbase == 0xF) || (fbase == 6 && probablyIntel) ) ?
+         mbase + ((a >> 12) & 0xF0) : mbase;
+         
+    if (!probablyIntel && max_extended_cpuid >= 0x8000_0008) {
+        // determine max number of cores for AMD
+        asm {
+            mov EAX, 0x8000_0008;
+            cpuid;
+            mov c, ECX;
+        }
+        uint apicsize = (c>>12) & 0xF;
+        if (apicsize == 0) {
+            // use legacy method
+            if (hyperThreadingBit)  maxCores = c & 0xFF;
+            else maxCores = 1;
+        } else {
+            // maxcores = 2^ apicsize
+            maxCores = 1;
+            while (apicsize) { maxCores<<=1; --apicsize; }
+        }
+    }
+    
+    if (max_extended_cpuid >= 0x8000_0004) {
+        char *procptr = processorNameBuffer.ptr;
+        asm {
+            push ESI;
+            mov ESI, procptr;
+            mov EAX, 0x8000_0002;
+            cpuid;
+            mov [ESI], EAX;
+            mov [ESI+4], EBX;
+            mov [ESI+8], ECX;
+            mov [ESI+12], EDX;
+            mov EAX, 0x8000_0003;
+            cpuid;
+            mov [ESI+16], EAX;
+            mov [ESI+20], EBX;
+            mov [ESI+24], ECX;
+            mov [ESI+28], EDX;
+            mov EAX, 0x8000_0004;
+            cpuid;
+            mov [ESI+32], EAX;
+            mov [ESI+36], EBX;
+            mov [ESI+40], ECX;
+            mov [ESI+44], EDX;
+            pop ESI;            
+        }
+        // Intel P4 and PM pad at front with spaces.
+        // Other CPUs pad at end with nulls.
+        int start = 0, end = 0;
+        while (processorNameBuffer[start] == ' ') { ++start; }
+        while (processorNameBuffer[$-end-1] == 0) { ++end; }
+        processorName = processorNameBuffer[start..$-end];
+    } else {
+        processorName[] = "Unknown CPU";
+    }
+    // Determine cache sizes
+    
+    // Intel docs specify that they return 0 for 0x8000_0005.
+    // AMD docs do not specify the behaviour for 0004 and 0002.
+    // Centaur/VIA and most other manufacturers use the AMD method,
+    // except Cyrix MediaGX MMX Enhanced uses their OWN form of CPUID2!
+    // NS Geode GX1 provides CyrixCPUID2 _and_ does the same wrong behaviour
+    // for CPUID80000005. But Geode GX uses the AMD method
+    
+    // Deal with Geode GX1 - make it same as MediaGX MMX.
+    if (max_extended_cpuid==0x8000_0005 && max_cpuid==2) {      
+        max_extended_cpuid = 0x8000_0004;
+    }
+    // Therefore, we try the AMD method unless it's an Intel chip.
+    // If we still have no info, try the Intel methods.
+    datacache[0].size = 0;
+    if (max_cpuid<2 || !probablyIntel) {
+        if (max_extended_cpuid >= 0x8000_0005) {
+            getAMDcacheinfo();
+        } else if (probablyAMD) {       
+            // According to AMDProcRecognitionAppNote, this means CPU
+            // K5 model 0, or Am5x86 (model 4), or Am4x86DX4 (model 4)
+            // Am5x86 has 16Kb 4-way unified data & code cache.
+            datacache[0].size = 8;
+            datacache[0].associativity = 4;
+            datacache[0].lineSize = 32;     
+        } else {
+            // Some obscure CPU.
+            // Values for Cyrix 6x86MX (family 6, model 0)
+            datacache[0].size = 64;
+            datacache[0].associativity = 4;
+            datacache[0].lineSize = 32;     
+        }
+    }   
+    if ((datacache[0].size == 0) && max_cpuid>=4) {
+        getcacheinfoCPUID4();
+    }
+    if ((datacache[0].size == 0) && max_cpuid>=2) {     
+        getcacheinfoCPUID2();
+    }
+    if (datacache[0].size == 0) {
+        // Pentium, PMMX, late model 486, or an obscure CPU
+        if (mmx) { // Pentium MMX. Also has 8kB code cache.
+            datacache[0].size = 16;
+            datacache[0].associativity = 4;
+            datacache[0].lineSize = 32;     
+        } else { // Pentium 1 (which also has 8kB code cache)
+                 // or 486.
+            // Cyrix 6x86: 16, 4way, 32 linesize
+            datacache[0].size = 8;
+            datacache[0].associativity = 2;
+            datacache[0].lineSize = 32;
+        }       
+    }
+    if (hyperThreadingBit) maxThreads = (apic>>>16) & 0xFF;
+    else maxThreads = maxCores;
+}
+
+// Return true if the cpuid instruction is supported.
+// BUG(WONTFIX): Returns false for Cyrix 6x86 and 6x86L. They will be treated as 486 machines.
+bool hasCPUID()
+{
+    uint flags;
+    asm {
+        pushfd;
+        pop EAX;
+        mov flags, EAX;
+        xor EAX, 0x0020_0000;
+        push EAX;
+        popfd;
+        pushfd;
+        pop EAX;
+        xor flags, EAX;
+    }
+    return (flags & 0x0020_0000) !=0;
+}
+
+} else { // inline asm X86
+
+    bool hasCPUID() { return false; }
+
+    void cpuidX86()
+    {
+            datacache[0].size = 8;
+            datacache[0].associativity = 2;
+            datacache[0].lineSize = 32;     
+    }   
+}
+
+// TODO: Implement this function with OS support
+void cpuidPPC()
+{
+    enum :int  { PPC601, PPC603, PPC603E, PPC604,
+                 PPC604E, PPC620, PPCG3, PPCG4, PPCG5 };
+
+    // TODO:
+    // asm { mfpvr; } returns the CPU version but unfortunately it can
+    // only be used in kernel mode. So OS support is required.
+    int cputype = PPC603;
+    
+    // 601 has a 8KB combined data & code L1 cache.
+    uint sizes[] = [4, 8, 16, 16, 32, 32, 32, 32, 64];
+    ubyte ways[] = [8, 2,  4,  4,  4,  8,  8,  8,  8];
+    uint L2size[]= [0, 0,  0,  0,  0,  0,  0,  256,  512];
+    uint L3size[]= [0, 0,  0,  0,  0,  0,  0,  2048,  0];
+    
+    datacache[0].size = sizes[cputype];
+    datacache[0].associativity = ways[cputype]; 
+    datacache[0].lineSize = (cputype==PPCG5)? 128 : 
+        (cputype == PPC620 || cputype == PPCG3)? 64 : 32;
+    datacache[1].size = L2size[cputype];
+    datacache[2].size = L3size[cputype];
+    datacache[1].lineSize = datacache[0].lineSize;
+    datacache[2].lineSize = datacache[0].lineSize;
+}
+
+// TODO: Implement this function with OS support
+void cpuidSparc()
+{
+    // UltaSparcIIi  : L1 = 16,  2way. L2 = 512, 4 way.
+    // UltraSparcIII : L1 = 64,  4way. L2= 4096 or 8192.
+    // UltraSparcIIIi: L1 = 64,  4way. L2= 1024, 4 way
+    // UltraSparcIV  : L1 = 64,  4way. L2 = 16*1024.
+    // UltraSparcIV+ : L1 = 64,  4way. L2 = 2048, L3=32*1024.
+    // Sparc64V      : L1 = 128, 2way. L2 = 4096 4way.  
+}
+
+
+static this()
+{
+    if (hasCPUID()) {
+        cpuidX86();
+    } else {
+        // it's a 386 or 486, or a Cyrix 6x86.
+        //Probably still has an external cache.
+    }
+    if (datacache[0].size==0) {
+            // Guess same as Pentium 1.
+            datacache[0].size = 8;
+            datacache[0].associativity = 2;
+            datacache[0].lineSize = 32;     
+    }
+    numCacheLevels = 1;
+    // And now fill up all the unused levels with full memory space.
+    for (int i=1; i< datacache.length; ++i) {
+        if (datacache[i].size==0) {
+            // Set all remaining levels of cache equal to full address space.
+            datacache[i].size = uint.max/1024;
+            datacache[i].associativity = 1;
+            datacache[i].lineSize = datacache[i-1].lineSize;
+        } else numCacheLevels = i+1;
+    }
+}
Index: src/compiler/ldc/rt/util/ctype.d
===================================================================
--- src/compiler/ldc/rt/util/ctype.d	(revision 0)
+++ src/compiler/ldc/rt/util/ctype.d	(revision 0)
@@ -0,0 +1,92 @@
+/**
+ * Simple ASCII char classification functions.
+ *
+ * Copyright: Copyright Digital Mars 2004 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2004 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.util.ctype;
+
+int isalnum(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG) : 0; }
+int isalpha(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP)      : 0; }
+int iscntrl(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_CTL)      : 0; }
+int isdigit(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_DIG)      : 0; }
+int islower(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_LC)       : 0; }
+int ispunct(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_PNC)      : 0; }
+int isspace(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_SPC)      : 0; }
+int isupper(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_UC)       : 0; }
+int isxdigit(dchar c) { return (c <= 0x7F) ? _ctype[c] & (_HEX)      : 0; }
+int isgraph(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC) : 0; }
+int isprint(dchar c)  { return (c <= 0x7F) ? _ctype[c] & (_ALP|_DIG|_PNC|_BLK) : 0; }
+int isascii(dchar c)  { return c <= 0x7F; }
+
+dchar tolower(dchar c)
+out (result)
+{
+    assert(!isupper(result));
+}
+body
+{
+    return isupper(c) ? c + (cast(dchar)'a' - 'A') : c;
+}
+
+dchar toupper(dchar c)
+out (result)
+{
+    assert(!islower(result));
+}
+body
+{
+    return islower(c) ? c - (cast(dchar)'a' - 'A') : c;
+}
+
+private:
+
+enum
+{
+    _SPC =	8,
+    _CTL =	0x20,
+    _BLK =	0x40,
+    _HEX =	0x80,
+    _UC  =	1,
+    _LC  =	2,
+    _PNC =	0x10,
+    _DIG =	4,
+    _ALP =	_UC|_LC,
+}
+
+immutable ubyte _ctype[128] =
+[
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_CTL,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL|_SPC,_CTL,_CTL,
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,_CTL,
+	_SPC|_BLK,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
+	_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,_DIG|_HEX,
+	_PNC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC|_HEX,_UC,
+	_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
+	_UC,_UC,_UC,_UC,_UC,_UC,_UC,_UC,
+	_UC,_UC,_UC,_PNC,_PNC,_PNC,_PNC,_PNC,
+	_PNC,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC|_HEX,_LC,
+	_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
+	_LC,_LC,_LC,_LC,_LC,_LC,_LC,_LC,
+	_LC,_LC,_LC,_PNC,_PNC,_PNC,_PNC,_CTL
+];
+
+
+unittest
+{
+    assert(isspace(' '));
+    assert(!isspace('z'));
+    assert(toupper('a') == 'A');
+    assert(tolower('Q') == 'q');
+    assert(!isxdigit('G'));
+}
Index: src/compiler/ldc/rt/util/string.d
===================================================================
--- src/compiler/ldc/rt/util/string.d	(revision 0)
+++ src/compiler/ldc/rt/util/string.d	(revision 0)
@@ -0,0 +1,40 @@
+/**
+ * The exception module defines all system-level exceptions and provides a
+ * mechanism to alter system-level error handling.
+ *
+ * Copyright: Copyright Sean Kelly 2005 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Sean Kelly
+ *
+ *          Copyright Sean Kelly 2005 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+module rt.util.string;
+
+private import core.stdc.string;
+
+char[] intToString( char[] buf, size_t val )
+{
+    assert( buf.length > 9 );
+    auto p = buf.ptr + buf.length;
+
+    do
+    {
+        *--p = cast(char)(val % 10 + '0');
+    } while( val /= 10 );
+
+    return buf[p - buf.ptr .. $];
+}
+
+
+int dstrcmp( in char[] s1, in char[] s2 )
+{
+    auto len = s1.length;
+    if( s2.length < len )
+        len = s2.length;
+    if( memcmp( s1.ptr, s2.ptr, len ) == 0 )
+        return 0;
+    return s1.length > s2.length ? 1 : -1;
+}
Index: src/compiler/ldc/rt/eh.d
===================================================================
--- src/compiler/ldc/rt/eh.d	(revision 0)
+++ src/compiler/ldc/rt/eh.d	(revision 0)
@@ -0,0 +1,419 @@
+/**
+ * This module contains functions and structures required for
+ * exception handling.
+ */
+module rt.eh;
+
+import rt.util.console;
+import core.stdc.stdarg;
+
+// debug = EH_personality;
+
+// current EH implementation works on x86
+// if it has a working unwind runtime
+version(X86) {
+    version(linux) version=X86_UNWIND;
+    version(darwin) version=X86_UNWIND;
+    version(solaris) version=X86_UNWIND;
+}
+version(X86_64) {
+    version(linux) version=X86_UNWIND;
+    version(darwin) version=X86_UNWIND;
+    version(solaris) version=X86_UNWIND;
+}
+
+//version = HP_LIBUNWIND;
+
+private extern(C) void abort();
+private extern(C) int printf(const char*, ...);
+private extern(C) int vprintf(const char*, va_list va);
+
+// D runtime functions
+extern(C) {
+    int _d_isbaseof(ClassInfo oc, ClassInfo c);
+}
+
+// libunwind headers
+extern(C)
+{
+    enum _Unwind_Reason_Code
+    {
+        NO_REASON = 0,
+        FOREIGN_EXCEPTION_CAUGHT = 1,
+        FATAL_PHASE2_ERROR = 2,
+        FATAL_PHASE1_ERROR = 3,
+        NORMAL_STOP = 4,
+        END_OF_STACK = 5,
+        HANDLER_FOUND = 6,
+        INSTALL_CONTEXT = 7,
+        CONTINUE_UNWIND = 8
+    }
+
+    enum _Unwind_Action
+    {
+        SEARCH_PHASE = 1,
+        CLEANUP_PHASE = 2,
+        HANDLER_PHASE = 3,
+        FORCE_UNWIND = 4
+    }
+
+    alias void* _Unwind_Context_Ptr;
+
+    alias void function(_Unwind_Reason_Code, _Unwind_Exception*) _Unwind_Exception_Cleanup_Fn;
+
+    struct _Unwind_Exception
+    {
+        char[8] exception_class;
+        _Unwind_Exception_Cleanup_Fn exception_cleanup;
+        ptrdiff_t private_1;
+        ptrdiff_t private_2;
+    }
+
+// interface to HP's libunwind from http://www.nongnu.org/libunwind/
+version(HP_LIBUNWIND)
+{
+    void __libunwind_Unwind_Resume(_Unwind_Exception *);
+    _Unwind_Reason_Code __libunwind_Unwind_RaiseException(_Unwind_Exception *);
+    ptrdiff_t __libunwind_Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr
+            context);
+    ptrdiff_t __libunwind_Unwind_GetIP(_Unwind_Context_Ptr context);
+    ptrdiff_t __libunwind_Unwind_SetIP(_Unwind_Context_Ptr context,
+            ptrdiff_t new_value);
+    ptrdiff_t __libunwind_Unwind_SetGR(_Unwind_Context_Ptr context, int index,
+            ptrdiff_t new_value);
+    ptrdiff_t __libunwind_Unwind_GetRegionStart(_Unwind_Context_Ptr context);
+
+    alias __libunwind_Unwind_Resume _Unwind_Resume;
+    alias __libunwind_Unwind_RaiseException _Unwind_RaiseException;
+    alias __libunwind_Unwind_GetLanguageSpecificData
+        _Unwind_GetLanguageSpecificData;
+    alias __libunwind_Unwind_GetIP _Unwind_GetIP;
+    alias __libunwind_Unwind_SetIP _Unwind_SetIP;
+    alias __libunwind_Unwind_SetGR _Unwind_SetGR;
+    alias __libunwind_Unwind_GetRegionStart _Unwind_GetRegionStart;
+}
+else version(X86_UNWIND) 
+{
+    void _Unwind_Resume(_Unwind_Exception*);
+    _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*);
+    ptrdiff_t _Unwind_GetLanguageSpecificData(_Unwind_Context_Ptr context);
+    ptrdiff_t _Unwind_GetIP(_Unwind_Context_Ptr context);
+    ptrdiff_t _Unwind_SetIP(_Unwind_Context_Ptr context, ptrdiff_t new_value);
+    ptrdiff_t _Unwind_SetGR(_Unwind_Context_Ptr context, int index,
+            ptrdiff_t new_value);
+    ptrdiff_t _Unwind_GetRegionStart(_Unwind_Context_Ptr context);
+}
+else
+{
+    // runtime calls these directly
+    void _Unwind_Resume(_Unwind_Exception*)
+    {
+        console("_Unwind_Resume is not implemented on this platform.\n");
+    }
+    _Unwind_Reason_Code _Unwind_RaiseException(_Unwind_Exception*)
+    {
+        console("_Unwind_RaiseException is not implemented on this platform.\n");
+        return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+    }
+}
+
+}
+
+// error and exit
+extern(C) private void fatalerror(const char* format, ...)
+{
+  va_list args;
+  va_start(args, format);
+  printf("Fatal error in EH code: ");
+  vprintf(format, args);
+  printf("\n");
+  abort();
+}
+
+
+// helpers for reading certain DWARF data
+private ubyte* get_uleb128(ubyte* addr, ref size_t res)
+{
+  res = 0;
+  size_t bitsize = 0;
+
+  // read as long as high bit is set
+  while(*addr & 0x80) {
+    res |= (*addr & 0x7f) << bitsize;
+    bitsize += 7;
+    addr += 1;
+    if(bitsize >= size_t.sizeof*8)
+       fatalerror("tried to read uleb128 that exceeded size of size_t");
+  }
+  // read last
+  if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
+    fatalerror("Fatal error in EH code: tried to read uleb128 that exceeded size of size_t");
+  res |= (*addr) << bitsize;
+
+  return addr + 1;
+}
+
+private ubyte* get_sleb128(ubyte* addr, ref ptrdiff_t res)
+{
+  res = 0;
+  size_t bitsize = 0;
+
+  // read as long as high bit is set
+  while(*addr & 0x80) {
+    res |= (*addr & 0x7f) << bitsize;
+    bitsize += 7;
+    addr += 1;
+    if(bitsize >= size_t.sizeof*8)
+       fatalerror("tried to read sleb128 that exceeded size of size_t");
+  }
+  // read last
+  if(bitsize != 0 && *addr >= 1 << size_t.sizeof*8 - bitsize)
+    fatalerror("tried to read sleb128 that exceeded size of size_t");
+  res |= (*addr) << bitsize;
+
+  // take care of sign
+  if(bitsize < size_t.sizeof*8 && ((*addr) & 0x40))
+    res |= cast(ptrdiff_t)(-1) ^ ((1 << (bitsize+7)) - 1);
+
+  return addr + 1;
+}
+
+
+// exception struct used by the runtime.
+// _d_throw allocates a new instance and passes the address of its
+// _Unwind_Exception member to the unwind call. The personality
+// routine is then able to get the whole struct by looking at the data
+// surrounding the unwind info.
+struct _d_exception
+{
+  Object exception_object;
+  _Unwind_Exception unwind_info;
+}
+
+// the 8-byte string identifying the type of exception
+// the first 4 are for vendor, the second 4 for language
+//TODO: This may be the wrong way around
+char[8] _d_exception_class = "LLDCD1\0\0";
+
+
+//
+// x86 unwind specific implementation of personality function
+// and helpers
+//
+version(X86_UNWIND)
+{
+
+// the personality routine gets called by the unwind handler and is responsible for
+// reading the EH tables and deciding what to do
+extern(C) _Unwind_Reason_Code _d_eh_personality(int ver, _Unwind_Action actions, ulong exception_class, _Unwind_Exception* exception_info, _Unwind_Context_Ptr context)
+{
+  // check ver: the C++ Itanium ABI only allows ver == 1
+  if(ver != 1)
+    return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+
+  // check exceptionClass
+  //TODO: Treat foreign exceptions with more respect
+  if((cast(char*)&exception_class)[0..8] != _d_exception_class)
+    return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+
+  // find call site table, action table and classinfo table
+  // Note: callsite and action tables do not contain static-length
+  // data and will be parsed as needed
+  // Note: classinfo_table points past the end of the table
+  ubyte* callsite_table;
+  ubyte* action_table;
+  ClassInfo* classinfo_table;
+  _d_getLanguageSpecificTables(context, callsite_table, action_table, classinfo_table);
+
+
+  /*
+    find landing pad and action table index belonging to ip by walking
+    the callsite_table
+  */
+  ubyte* callsite_walker = callsite_table;
+
+  // get the instruction pointer
+  // will be used to find the right entry in the callsite_table
+  // -1 because it will point past the last instruction
+  ptrdiff_t ip = _Unwind_GetIP(context) - 1;
+
+  // address block_start is relative to
+  ptrdiff_t region_start = _Unwind_GetRegionStart(context);
+
+  // table entries
+  uint block_start_offset, block_size;
+  ptrdiff_t landing_pad;
+  size_t action_offset;
+
+  while(true) {
+    // if we've gone through the list and found nothing...
+    if(callsite_walker >= action_table)
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+    block_start_offset = *cast(uint*)callsite_walker;
+    block_size = *(cast(uint*)callsite_walker + 1);
+    landing_pad = *(cast(uint*)callsite_walker + 2);
+    if(landing_pad)
+      landing_pad += region_start;
+    callsite_walker = get_uleb128(callsite_walker + 3*uint.sizeof, action_offset);
+
+    debug(EH_personality_verbose) printf("ip=%llx %d %d %llx\n", ip, block_start_offset, block_size, landing_pad);
+
+    // since the list is sorted, as soon as we're past the ip
+    // there's no handler to be found
+    if(ip < region_start + block_start_offset)
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+    // if we've found our block, exit
+    if(ip < region_start + block_start_offset + block_size)
+      break;
+  }
+
+  debug(EH_personality) printf("Found correct landing pad and actionOffset %d\n", action_offset);
+
+  // now we need the exception's classinfo to find a handler
+  // the exception_info is actually a member of a larger _d_exception struct
+  // the runtime allocated. get that now
+  _d_exception* exception_struct = cast(_d_exception*)(cast(ubyte*)exception_info - _d_exception.unwind_info.offsetof);
+
+  // if there's no action offset and no landing pad, continue unwinding
+  if(!action_offset && !landing_pad)
+    return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+  // if there's no action offset but a landing pad, this is a cleanup handler
+  else if(!action_offset && landing_pad)
+    return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
+
+  /*
+   walk action table chain, comparing classinfos using _d_isbaseof
+  */
+  ubyte* action_walker = action_table + action_offset - 1;
+
+  ptrdiff_t ti_offset, next_action_offset;
+  while(true) {
+    action_walker = get_sleb128(action_walker, ti_offset);
+    // it is intentional that we not modify action_walker here
+    // next_action_offset is from current action_walker position
+    get_sleb128(action_walker, next_action_offset);
+
+    // negative are 'filters' which we don't use
+    if(!(ti_offset >= 0))
+      fatalerror("Filter actions are unsupported");
+
+    // zero means cleanup, which we require to be the last action
+    if(ti_offset == 0) {
+      if(!(next_action_offset == 0))
+        fatalerror("Cleanup action must be last in chain");
+      return _d_eh_install_finally_context(actions, landing_pad, exception_struct, context);
+    }
+
+    // get classinfo for action and check if the one in the
+    // exception structure is a base
+    ClassInfo catch_ci = *(classinfo_table - ti_offset);
+    debug(EH_personality) printf("Comparing catch %s to exception %s\n", catch_ci.name.ptr, exception_struct.exception_object.classinfo.name.ptr);
+    if(_d_isbaseof(exception_struct.exception_object.classinfo, catch_ci))
+      return _d_eh_install_catch_context(actions, ti_offset, landing_pad, exception_struct, context);
+
+    // we've walked through all actions and found nothing...
+    if(next_action_offset == 0)
+      return _Unwind_Reason_Code.CONTINUE_UNWIND;
+    else
+      action_walker += next_action_offset;
+  }
+
+  fatalerror("reached unreachable");
+  return _Unwind_Reason_Code.FATAL_PHASE1_ERROR;
+}
+
+// These are the register numbers for SetGR that
+// llvm's eh.exception and eh.selector intrinsics
+// will pick up.
+// Hints for these can be found by looking at the
+// EH_RETURN_DATA_REGNO macro in GCC, careful testing
+// is required though.
+version (X86_64)
+{
+  private int eh_exception_regno = 0;
+  private int eh_selector_regno = 1;
+} else {
+  private int eh_exception_regno = 0;
+  private int eh_selector_regno = 2;
+}
+
+private _Unwind_Reason_Code _d_eh_install_catch_context(_Unwind_Action actions, ptrdiff_t switchval, ptrdiff_t landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
+{
+  debug(EH_personality) printf("Found catch clause!\n");
+
+  if(actions & _Unwind_Action.SEARCH_PHASE)
+    return _Unwind_Reason_Code.HANDLER_FOUND;
+
+  else if(actions & _Unwind_Action.HANDLER_PHASE)
+  {
+    debug(EH_personality) printf("Setting switch value to: %d!\n", switchval);
+    _Unwind_SetGR(context, eh_exception_regno, cast(ptrdiff_t)cast(void*)(exception_struct.exception_object));
+    _Unwind_SetGR(context, eh_selector_regno, cast(ptrdiff_t)switchval);
+    _Unwind_SetIP(context, landing_pad);
+    return _Unwind_Reason_Code.INSTALL_CONTEXT;
+  }
+
+  fatalerror("reached unreachable");
+  return _Unwind_Reason_Code.FATAL_PHASE2_ERROR;
+}
+
+private _Unwind_Reason_Code _d_eh_install_finally_context(_Unwind_Action actions, ptrdiff_t landing_pad, _d_exception* exception_struct, _Unwind_Context_Ptr context)
+{
+  // if we're merely in search phase, continue
+  if(actions & _Unwind_Action.SEARCH_PHASE)
+    return _Unwind_Reason_Code.CONTINUE_UNWIND;
+
+  debug(EH_personality) printf("Calling cleanup routine...\n");
+
+  _Unwind_SetGR(context, eh_exception_regno, cast(ptrdiff_t)exception_struct);
+  _Unwind_SetGR(context, eh_selector_regno, 0);
+  _Unwind_SetIP(context, landing_pad);
+  return _Unwind_Reason_Code.INSTALL_CONTEXT;
+}
+
+private void _d_getLanguageSpecificTables(_Unwind_Context_Ptr context, ref ubyte* callsite, ref ubyte* action, ref ClassInfo* ci)
+{
+  ubyte* data = cast(ubyte*)_Unwind_GetLanguageSpecificData(context);
+
+  //TODO: Do proper DWARF reading here
+  if(*data++ != 0xff)
+    fatalerror("DWARF header has unexpected format 1");
+
+  if(*data++ != 0x00)
+    fatalerror("DWARF header has unexpected format 2");
+  size_t cioffset;
+  data = get_uleb128(data, cioffset);
+  ci = cast(ClassInfo*)(data + cioffset);
+
+  if(*data++ != 0x03)
+    fatalerror("DWARF header has unexpected format 3");
+  size_t callsitelength;
+  data = get_uleb128(data, callsitelength);
+  action = data + callsitelength;
+
+  callsite = data;
+}
+
+} // end of x86 Linux specific implementation
+
+
+extern(C) void _d_throw_exception(Object e)
+{
+    if (e !is null)
+    {
+        _d_exception* exc_struct = new _d_exception;
+        exc_struct.unwind_info.exception_class[] = _d_exception_class;
+        exc_struct.exception_object = e;
+        _Unwind_Reason_Code ret = _Unwind_RaiseException(&exc_struct.unwind_info);
+        console("_Unwind_RaiseException failed with reason code: ")(ret)("\n");
+    }
+    abort();
+}
+
+extern(C) void _d_eh_resume_unwind(_d_exception* exception_struct)
+{
+  _Unwind_Resume(&exception_struct.unwind_info);
+}
Index: src/compiler/ldc/genobj.d
===================================================================
--- src/compiler/ldc/genobj.d	(revision 0)
+++ src/compiler/ldc/genobj.d	(revision 0)
@@ -0,0 +1,1621 @@
+/**
+ * Forms the symbols available to all D programs. Includes Object, which is
+ * the root of the class object hierarchy.  This module is implicitly
+ * imported.
+ * Macros:
+ *      WIKI = Object
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+module object;
+
+private
+{
+    import core.stdc.string;
+    import core.stdc.stdlib;
+    import rt.util.string;
+    import rt.aaA;
+    debug(PRINTF) import core.stdc.stdio;
+
+    extern (C) void onOutOfMemoryError();
+    extern (C) Object _d_allocclass(ClassInfo ci);
+}
+
+// NOTE: For some reason, this declaration method doesn't work
+//       in this particular file (and this file only).  It must
+//       be a DMD thing.
+//alias typeof(int.sizeof)                    size_t;
+//alias typeof(cast(void*)0 - cast(void*)0)   ptrdiff_t;
+
+version(X86_64)
+{
+    alias ulong size_t;
+    alias long  ptrdiff_t;
+}
+else
+{
+    alias uint  size_t;
+    alias int   ptrdiff_t;
+}
+
+alias size_t hash_t;
+alias bool equals_t;
+
+alias immutable(char)[]  string;
+alias immutable(wchar)[] wstring;
+alias immutable(dchar)[] dstring;
+
+/**
+ * All D class objects inherit from Object.
+ */
+class Object
+{
+    /**
+     * Convert Object to a human readable string.
+     */
+    string toString()
+    {
+        return this.classinfo.name;
+    }
+
+    /**
+     * Compute hash function for Object.
+     */
+    hash_t toHash()
+    {
+        // BUG: this prevents a compacting GC from working, needs to be fixed
+        return cast(hash_t)cast(void*)this;
+    }
+
+    /**
+     * Compare with another Object obj.
+     * Returns:
+     *  $(TABLE
+     *  $(TR $(TD this &lt; obj) $(TD &lt; 0))
+     *  $(TR $(TD this == obj) $(TD 0))
+     *  $(TR $(TD this &gt; obj) $(TD &gt; 0))
+     *  )
+     */
+    int opCmp(Object o)
+    {
+        // BUG: this prevents a compacting GC from working, needs to be fixed
+        //return cast(int)cast(void*)this - cast(int)cast(void*)o;
+
+        throw new Exception("need opCmp for class " ~ this.classinfo.name);
+        //return this !is o;
+    }
+
+    /**
+     * Returns !=0 if this object does have the same contents as obj.
+     */
+    equals_t opEquals(Object o)
+    {
+        return this is o;
+    }
+
+    interface Monitor
+    {
+        void lock();
+        void unlock();
+    }
+
+    /**
+     * Create instance of class specified by classname.
+     * The class must either have no constructors or have
+     * a default constructor.
+     * Returns:
+     *   null if failed
+     */
+    static Object factory(string classname)
+    {
+        auto ci = ClassInfo.find(classname);
+        if (ci)
+        {
+            return ci.create();
+        }
+        return null;
+    }
+}
+
+/**
+ * Information about an interface.
+ * When an object is accessed via an interface, an Interface* appears as the
+ * first entry in its vtbl.
+ */
+struct Interface
+{
+    ClassInfo   classinfo;  /// .classinfo for this interface (not for containing class)
+    void*[]     vtbl;
+    ptrdiff_t   offset;     /// offset to Interface 'this' from Object 'this'
+}
+
+/**
+ * Runtime type information about a class. Can be retrieved for any class type
+ * or instance by using the .classinfo property.
+ * A pointer to this appears as the first entry in the class's vtbl[].
+ */
+class ClassInfo : Object
+{
+    byte[]      init;           /** class static initializer
+                                 * (init.length gives size in bytes of class)
+                                 */
+    string      name;           /// class name
+    void*[]     vtbl;           /// virtual function pointer table
+    Interface[] interfaces;     /// interfaces this class implements
+    ClassInfo   base;           /// base class
+    void*       destructor;
+    void(*classInvariant)(Object);
+    uint        flags;
+    //  1:                      // is IUnknown or is derived from IUnknown
+    //  2:                      // has no possible pointers into GC memory
+    //  4:                      // has offTi[] member
+    //  8:                      // has constructors
+    // 16:                      // has xgetMembers member
+    // 32:                      // has typeinfo member
+    void*       deallocator;
+    OffsetTypeInfo[] offTi;
+    void*	 defaultConstructor;   // default Constructor
+    const(MemberInfo[]) function(string) xgetMembers;
+    TypeInfo typeinfo;
+
+    /**
+     * Search all modules for ClassInfo corresponding to classname.
+     * Returns: null if not found
+     */
+    static ClassInfo find(in char[] classname)
+    {
+        foreach (m; ModuleInfo)
+        {
+            //writefln("module %s, %d", m.name, m.localClasses.length);
+            foreach (c; m.localClasses)
+            {
+                //writefln("\tclass %s", c.name);
+                if (c.name == classname)
+                    return c;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Create instance of Object represented by 'this'.
+     */
+    Object create()
+    {
+        if (flags & 8 && !defaultConstructor)
+            return null;
+        Object o = _d_allocclass(this);
+        if (flags & 8 && defaultConstructor)
+        {
+            Object delegate() ctor;
+            ctor.ptr = cast(void*)o;
+            ctor.funcptr = cast(Object function())defaultConstructor;
+            ctor();
+            //defaultConstructor(o);
+        }
+        return o;
+    }
+
+    /**
+     * Search for all members with the name 'name'.
+     * If name[] is null, return all members.
+     */
+    const(MemberInfo[]) getMembers(string name)
+    {
+        if (flags & 16 && xgetMembers)
+            return xgetMembers(name);
+        return null;
+    }
+}
+
+/**
+ * Array of pairs giving the offset and type information for each
+ * member in an aggregate.
+ */
+struct OffsetTypeInfo
+{
+    size_t   offset;    /// Offset of member from start of object
+    TypeInfo ti;        /// TypeInfo for this member
+}
+
+/**
+ * Runtime type information about a type.
+ * Can be retrieved for any type using a
+ * <a href="../expression.html#typeidexpression">TypeidExpression</a>.
+ */
+class TypeInfo : Object
+{
+    override hash_t toHash()
+    {
+        hash_t hash;
+
+        foreach (char c; this.toString())
+            hash = hash * 9 + c;
+        return hash;
+    }
+
+    override int opCmp(Object o)
+    {
+        if (this is o)
+            return 0;
+        TypeInfo ti = cast(TypeInfo)o;
+        if (ti is null)
+            return 1;
+        return dstrcmp(this.toString(), ti.toString());
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        /* TypeInfo instances are singletons, but duplicates can exist
+         * across DLL's. Therefore, comparing for a name match is
+         * sufficient.
+         */
+        if (this is o)
+            return true;
+        TypeInfo ti = cast(TypeInfo)o;
+        return ti && this.toString() == ti.toString();
+    }
+
+    /// Returns a hash of the instance of a type.
+    hash_t getHash(in void* p) { return cast(hash_t)p; }
+
+    /// Compares two instances for equality.
+    equals_t equals(in void* p1, in void* p2) { return p1 == p2; }
+
+    /// Compares two instances for &lt;, ==, or &gt;.
+    int compare(in void* p1, in void* p2) { return 0; }
+
+    /// Returns size of the type.
+    size_t tsize() { return 0; }
+
+    /// Swaps two instances of the type.
+    void swap(void* p1, void* p2)
+    {
+        size_t n = tsize();
+        for (size_t i = 0; i < n; i++)
+        {
+            byte t = (cast(byte *)p1)[i];
+            (cast(byte*)p1)[i] = (cast(byte*)p2)[i];
+            (cast(byte*)p2)[i] = t;
+        }
+    }
+
+    /// Get TypeInfo for 'next' type, as defined by what kind of type this is,
+    /// null if none.
+    TypeInfo next() { return null; }
+
+    /// Return default initializer, null if default initialize to 0
+    void[] init() { return null; }
+
+    /// Get flags for type: 1 means GC should scan for pointers
+    uint flags() { return 0; }
+
+    /// Get type information on the contents of the type; null if not available
+    OffsetTypeInfo[] offTi() { return null; }
+    /// Run the destructor on the object and all its sub-objects
+    void destroy(void* p) {}
+    /// Run the postblit on the object and all its sub-objects
+    void postblit(void* p) {}
+}
+
+class TypeInfo_Typedef : TypeInfo
+{
+    override string toString() { return name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Typedef c;
+        return this is o ||
+               ((c = cast(TypeInfo_Typedef)o) !is null &&
+                this.name == c.name &&
+                this.base == c.base);
+    }
+
+    override hash_t getHash(in void* p) { return base.getHash(p); }
+    override equals_t equals(in void* p1, in void* p2) { return base.equals(p1, p2); }
+    override int compare(in void* p1, in void* p2) { return base.compare(p1, p2); }
+    override size_t tsize() { return base.tsize(); }
+    override void swap(void* p1, void* p2) { return base.swap(p1, p2); }
+
+    override TypeInfo next() { return base.next(); }
+    override uint flags() { return base.flags(); }
+    override void[] init() { return m_init.length ? m_init : base.init(); }
+
+    TypeInfo base;
+    string   name;
+    void[]   m_init;
+}
+
+class TypeInfo_Enum : TypeInfo_Typedef
+{
+
+}
+
+class TypeInfo_Pointer : TypeInfo
+{
+    override string toString() { return m_next.toString() ~ "*"; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Pointer c;
+        return this is o ||
+                ((c = cast(TypeInfo_Pointer)o) !is null &&
+                 this.m_next == c.m_next);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        return cast(hash_t)*cast(void**)p;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        return *cast(void**)p1 == *cast(void**)p2;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        if (*cast(void**)p1 < *cast(void**)p2)
+            return -1;
+        else if (*cast(void**)p1 > *cast(void**)p2)
+            return 1;
+        else
+            return 0;
+    }
+
+    override size_t tsize()
+    {
+        return (void*).sizeof;
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void* tmp = *cast(void**)p1;
+        *cast(void**)p1 = *cast(void**)p2;
+        *cast(void**)p2 = tmp;
+    }
+
+    override TypeInfo next() { return m_next; }
+    override uint flags() { return 1; }
+
+    TypeInfo m_next;
+}
+
+class TypeInfo_Array : TypeInfo
+{
+    override string toString() { return value.toString() ~ "[]"; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Array c;
+        return this is o ||
+               ((c = cast(TypeInfo_Array)o) !is null &&
+                this.value == c.value);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        size_t sz = value.tsize();
+        hash_t hash = 0;
+        void[] a = *cast(void[]*)p;
+        for (size_t i = 0; i < a.length; i++)
+            hash += value.getHash(a.ptr + i * sz) * 11;
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        void[] a1 = *cast(void[]*)p1;
+        void[] a2 = *cast(void[]*)p2;
+        if (a1.length != a2.length)
+            return false;
+        size_t sz = value.tsize();
+        for (size_t i = 0; i < a1.length; i++)
+        {
+            if (!value.equals(a1.ptr + i * sz, a2.ptr + i * sz))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        void[] a1 = *cast(void[]*)p1;
+        void[] a2 = *cast(void[]*)p2;
+        size_t sz = value.tsize();
+        size_t len = a1.length;
+
+        if (a2.length < len)
+            len = a2.length;
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = value.compare(a1.ptr + u * sz, a2.ptr + u * sz);
+            if (result)
+                return result;
+        }
+        return cast(int)a1.length - cast(int)a2.length;
+    }
+
+    override size_t tsize()
+    {
+        return (void[]).sizeof;
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void[] tmp = *cast(void[]*)p1;
+        *cast(void[]*)p1 = *cast(void[]*)p2;
+        *cast(void[]*)p2 = tmp;
+    }
+
+    TypeInfo value;
+
+    override TypeInfo next()
+    {
+        return value;
+    }
+
+    override uint flags() { return 1; }
+}
+
+class TypeInfo_StaticArray : TypeInfo
+{
+    override string toString()
+    {
+        char[10] tmp = void;
+        return cast(string)(value.toString() ~ "[" ~ tmp.intToString(len) ~ "]");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_StaticArray c;
+        return this is o ||
+               ((c = cast(TypeInfo_StaticArray)o) !is null &&
+                this.len == c.len &&
+                this.value == c.value);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        size_t sz = value.tsize();
+        hash_t hash = 0;
+        for (size_t i = 0; i < len; i++)
+            hash += value.getHash(p + i * sz);
+        return hash;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        size_t sz = value.tsize();
+
+        for (size_t u = 0; u < len; u++)
+        {
+            if (!value.equals(p1 + u * sz, p2 + u * sz))
+                return false;
+        }
+        return true;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        size_t sz = value.tsize();
+
+        for (size_t u = 0; u < len; u++)
+        {
+            int result = value.compare(p1 + u * sz, p2 + u * sz);
+            if (result)
+                return result;
+        }
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return len * value.tsize();
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        void* tmp;
+        size_t sz = value.tsize();
+        ubyte[16] buffer;
+        void* pbuffer;
+
+        if (sz < buffer.sizeof)
+            tmp = buffer.ptr;
+        else
+            tmp = pbuffer = (new void[sz]).ptr;
+
+        for (size_t u = 0; u < len; u += sz)
+        {   size_t o = u * sz;
+            memcpy(tmp, p1 + o, sz);
+            memcpy(p1 + o, p2 + o, sz);
+            memcpy(p2 + o, tmp, sz);
+        }
+        if (pbuffer)
+            delete pbuffer;
+    }
+
+    override void[] init() { return value.init(); }
+    override TypeInfo next() { return value; }
+    override uint flags() { return value.flags(); }
+
+    override void destroy(void* p)
+    {
+        auto sz = value.tsize();
+        p += sz * len;
+        foreach (i; 0 .. len)
+        {
+            p -= sz;
+            value.destroy(p);
+        }
+    }
+
+    override void postblit(void* p)
+    {
+        auto sz = value.tsize();
+        foreach (i; 0 .. len)
+        {
+            value.postblit(p);
+            p += sz;
+        }
+    }
+
+    TypeInfo value;
+    size_t   len;
+}
+
+class TypeInfo_AssociativeArray : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ "[" ~ key.toString() ~ "]");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_AssociativeArray c;
+        return this is o ||
+                ((c = cast(TypeInfo_AssociativeArray)o) !is null &&
+                 this.key == c.key &&
+                 this.value == c.value);
+    }
+
+    // BUG: need to add the rest of the functions
+ 
+    override equals_t equals(in void *p1, in void *p2) 
+    { 
+        AA aa = *cast(AA*)p1; 
+        AA ab = *cast(AA*)p2; 
+	         
+        if (_aaLen(aa) != _aaLen(ab)) 
+            return 0; 
+	         
+        equals_t equal = true; 
+        int eq_x(void* k, void* va) 
+        { 
+            void* vb = _aaIn(ab, key, k); 
+            if (!vb || !value.equals(va, vb)) 
+            { 
+                equal = false; 
+                return 1; // break 
+            } 
+            return 0; 
+        } 
+        _aaApply2(aa, key.tsize(), &eq_x); 
+        return equal; 
+    }
+
+    override size_t tsize()
+    {
+        return (char[int]).sizeof;
+    }
+
+    override TypeInfo next() { return value; }
+    override uint flags() { return 1; }
+
+    TypeInfo value;
+    TypeInfo key;
+}
+
+class TypeInfo_Function : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ "()");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Function c;
+        return this is o ||
+                ((c = cast(TypeInfo_Function)o) !is null &&
+                 this.next == c.next);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    override size_t tsize()
+    {
+        return 0;       // no size for functions
+    }
+
+    TypeInfo next;
+}
+
+class TypeInfo_Delegate : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string)(next.toString() ~ " delegate()");
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Delegate c;
+        return this is o ||
+                ((c = cast(TypeInfo_Delegate)o) !is null &&
+                 this.next == c.next);
+    }
+
+    // BUG: need to add the rest of the functions
+
+    override size_t tsize()
+    {
+        alias int delegate() dg;
+        return dg.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    TypeInfo next;
+}
+
+class TypeInfo_Class : TypeInfo
+{
+    override string toString() { return info.name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Class c;
+        return this is o ||
+                ((c = cast(TypeInfo_Class)o) !is null &&
+                 this.info.name == c.classinfo.name);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        Object o = *cast(Object*)p;
+        return o ? o.toHash() : 0;
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+
+        return (o1 is o2) || (o1 && o1.opEquals(o2));
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Object o1 = *cast(Object*)p1;
+        Object o2 = *cast(Object*)p2;
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (o1 !is o2)
+        {
+            if (o1)
+            {
+                if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    override OffsetTypeInfo[] offTi()
+    {
+        return (info.flags & 4) ? info.offTi : null;
+    }
+
+    ClassInfo info;
+}
+
+class TypeInfo_Interface : TypeInfo
+{
+    override string toString() { return info.name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Interface c;
+        return this is o ||
+                ((c = cast(TypeInfo_Interface)o) !is null &&
+                 this.info.name == c.classinfo.name);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p;
+        Object o = cast(Object)(*cast(void**)p - pi.offset);
+        assert(o);
+        return o.toHash();
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p1;
+        Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
+        pi = **cast(Interface ***)*cast(void**)p2;
+        Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
+
+        return o1 == o2 || (o1 && o1.opCmp(o2) == 0);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        Interface* pi = **cast(Interface ***)*cast(void**)p1;
+        Object o1 = cast(Object)(*cast(void**)p1 - pi.offset);
+        pi = **cast(Interface ***)*cast(void**)p2;
+        Object o2 = cast(Object)(*cast(void**)p2 - pi.offset);
+        int c = 0;
+
+        // Regard null references as always being "less than"
+        if (o1 != o2)
+        {
+            if (o1)
+            {
+                if (!o2)
+                    c = 1;
+                else
+                    c = o1.opCmp(o2);
+            }
+            else
+                c = -1;
+        }
+        return c;
+    }
+
+    override size_t tsize()
+    {
+        return Object.sizeof;
+    }
+
+    override uint flags() { return 1; }
+
+    ClassInfo info;
+}
+
+class TypeInfo_Struct : TypeInfo
+{
+    override string toString() { return name; }
+
+    override equals_t opEquals(Object o)
+    {
+        TypeInfo_Struct s;
+        return this is o ||
+                ((s = cast(TypeInfo_Struct)o) !is null &&
+                 this.name == s.name &&
+                 this.init.length == s.init.length);
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(p);
+        if (xtoHash)
+        {
+            debug(PRINTF) printf("getHash() using xtoHash\n");
+            return (*xtoHash)(p);
+        }
+        else
+        {
+            hash_t h;
+            debug(PRINTF) printf("getHash() using default hash\n");
+            // A sorry hash algorithm.
+            // Should use the one for strings.
+            // BUG: relies on the GC not moving objects
+            auto q = cast(const(ubyte)*)p;
+            for (size_t i = 0; i < init.length; i++)
+            {
+                h = h * 9 + *q;
+                q++;
+            }
+            return h;
+        }
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        if (p1 == p2)
+            return true;
+        else if (!p1 || !p2)
+            return false;
+        else if (xopEquals)
+            return (*xopEquals)(p1, p2);
+        else
+            // BUG: relies on the GC not moving objects
+            return memcmp(p1, p2, init.length) == 0;
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        // Regard null references as always being "less than"
+        if (p1 != p2)
+        {
+            if (p1)
+            {
+                if (!p2)
+                    return true;
+                else if (xopCmp)
+                    return (*xopCmp)(p2, p1);
+                else
+                    // BUG: relies on the GC not moving objects
+                    return memcmp(p1, p2, init.length);
+            }
+            else
+                return -1;
+        }
+        return 0;
+    }
+
+    override size_t tsize()
+    {
+        return init.length;
+    }
+
+    override void[] init() { return m_init; }
+
+    override uint flags() { return m_flags; }
+
+    override void destroy(void* p)
+    {
+        if (xdtor)
+            (*xdtor)(p);
+    }
+
+    override void postblit(void* p)
+    {
+        if (xpostblit)
+            (*xpostblit)(p);
+    }
+
+    string name;
+    void[] m_init;      // initializer; init.ptr == null if 0 initialize
+
+    hash_t   function(in void*)           xtoHash;
+    equals_t function(in void*, in void*) xopEquals;
+    int      function(in void*, in void*) xopCmp;
+    string   function(in void*)           xtoString;
+
+    uint m_flags;
+
+    const(MemberInfo[]) function(in char[]) xgetMembers;
+    void function(void*)                    xdtor;
+    void function(void*)                    xpostblit;
+}
+
+class TypeInfo_Tuple : TypeInfo
+{
+    TypeInfo[] elements;
+
+    override string toString()
+    {
+        string s = "(";
+        foreach (i, element; elements)
+        {
+            if (i)
+                s ~= ',';
+            s ~= element.toString();
+        }
+        s ~= ")";
+        return s;
+    }
+
+    override equals_t opEquals(Object o)
+    {
+        if (this is o)
+            return true;
+
+        auto t = cast(TypeInfo_Tuple)o;
+        if (t && elements.length == t.elements.length)
+        {
+            for (size_t i = 0; i < elements.length; i++)
+            {
+                if (elements[i] != t.elements[i])
+                    return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    override hash_t getHash(in void* p)
+    {
+        assert(0);
+    }
+
+    override equals_t equals(in void* p1, in void* p2)
+    {
+        assert(0);
+    }
+
+    override int compare(in void* p1, in void* p2)
+    {
+        assert(0);
+    }
+
+    override size_t tsize()
+    {
+        assert(0);
+    }
+
+    override void swap(void* p1, void* p2)
+    {
+        assert(0);
+    }
+
+    override void destroy(void* p)
+    {
+        assert(0);
+    }
+
+    override void postblit(void* p)
+    {
+        assert(0);
+    }
+}
+
+class TypeInfo_Const : TypeInfo
+{
+    override string toString()
+    {
+        return cast(string) ("const(" ~ base.toString() ~ ")");
+    }
+
+    override equals_t opEquals(Object o) { return base.opEquals(o); }
+    override hash_t getHash(in void *p) { return base.getHash(p); }
+    override equals_t equals(in void *p1, in void *p2) { return base.equals(p1, p2); }
+    override int compare(in void *p1, in void *p2) { return base.compare(p1, p2); }
+    override size_t tsize() { return base.tsize(); }
+    override void swap(void *p1, void *p2) { return base.swap(p1, p2); }
+
+    override TypeInfo next() { return base.next(); }
+    override uint flags() { return base.flags(); }
+    override void[] init() { return base.init(); }
+
+    TypeInfo base;
+}
+
+class TypeInfo_Invariant : TypeInfo_Const
+{
+    override string toString()
+    {
+        return cast(string) ("immutable(" ~ base.toString() ~ ")");
+    }
+}
+
+class TypeInfo_Shared : TypeInfo_Const
+{
+    override string toString()
+    {
+        return cast(string) ("shared(" ~ base.toString() ~ ")");
+    }
+}
+
+abstract class MemberInfo
+{
+    abstract string name();
+}
+
+class MemberInfo_field : MemberInfo
+{
+    this(string name, TypeInfo ti, size_t offset)
+    {
+        m_name = name;
+        m_typeinfo = ti;
+        m_offset = offset;
+    }
+
+    override string name() { return m_name; }
+    TypeInfo typeInfo() { return m_typeinfo; }
+    size_t offset() { return m_offset; }
+
+    string   m_name;
+    TypeInfo m_typeinfo;
+    size_t   m_offset;
+}
+
+class MemberInfo_function : MemberInfo
+{
+    this(string name, TypeInfo ti, void* fp, uint flags)
+    {
+        m_name = name;
+        m_typeinfo = ti;
+        m_fp = fp;
+        m_flags = flags;
+    }
+
+    override string name() { return m_name; }
+    TypeInfo typeInfo() { return m_typeinfo; }
+    void* fp() { return m_fp; }
+    uint flags() { return m_flags; }
+
+    string   m_name;
+    TypeInfo m_typeinfo;
+    void*    m_fp;
+    uint     m_flags;
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Throwable
+///////////////////////////////////////////////////////////////////////////////
+
+
+class Throwable : Object
+{
+    interface TraceInfo
+    {
+        int opApply(int delegate(inout char[]));
+    }
+
+    string      msg;
+    string      file;
+    size_t      line;
+    TraceInfo   info;
+    Throwable   next;
+
+    this(string msg, Throwable next = null)
+    {
+        this.msg = msg;
+        this.next = next;
+        this.info = traceContext();
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        this(msg, next);
+        this.file = file;
+        this.line = line;
+        this.info = traceContext();
+    }
+
+    override string toString()
+    {
+        char[10] tmp = void;
+        char[]   buf;
+
+        for (Throwable e = this; e !is null; e = e.next)
+        {
+            if (e.file)
+            {
+               buf ~= e.classinfo.name ~ "@" ~ e.file ~ "(" ~ tmp.intToString(e.line) ~ "): " ~ e.msg;
+            }
+            else
+            {
+               buf ~= e.classinfo.name ~ ": " ~ e.msg;
+            }
+            if (e.info)
+            {
+                buf ~= "\n----------------";
+                foreach (t; e.info)
+                    buf ~= "\n" ~ t;
+            }
+            if (e.next)
+                buf ~= "\n";
+        }
+        return cast(string) buf;
+    }
+}
+
+
+alias Throwable.TraceInfo function(void* ptr = null) TraceHandler;
+private __gshared TraceHandler traceHandler = null;
+
+
+/**
+ * Overrides the default trace hander with a user-supplied version.
+ *
+ * Params:
+ *  h = The new trace handler.  Set to null to use the default handler.
+ */
+extern (C) void  rt_setTraceHandler(TraceHandler h)
+{
+    traceHandler = h;
+}
+
+
+/**
+ * This function will be called when an exception is constructed.  The
+ * user-supplied trace handler will be called if one has been supplied,
+ * otherwise no trace will be generated.
+ *
+ * Params:
+ *  ptr = A pointer to the location from which to generate the trace, or null
+ *        if the trace should be generated from within the trace handler
+ *        itself.
+ *
+ * Returns:
+ *  An object describing the current calling context or null if no handler is
+ *  supplied.
+ */
+Throwable.TraceInfo traceContext(void* ptr = null)
+{
+    if (traceHandler is null)
+        return null;
+    return traceHandler(ptr);
+}
+
+
+class Exception : Throwable
+{
+    this(string msg, Throwable next = null)
+    {
+        super(msg, next);
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        super(msg, file, line, next);
+    }
+}
+
+
+class Error : Throwable
+{
+    this(string msg, Throwable next = null)
+    {
+        super(msg, next);
+    }
+
+    this(string msg, string file, size_t line, Throwable next = null)
+    {
+        super(msg, file, line, next);
+    }
+}
+
+
+///////////////////////////////////////////////////////////////////////////////
+// ModuleInfo
+///////////////////////////////////////////////////////////////////////////////
+
+
+enum
+{
+    MIctorstart  = 1,   // we've started constructing it
+    MIctordone   = 2,   // finished construction
+    MIstandalone = 4,   // module ctor does not depend on other module
+                        // ctors being done first
+    MIhasictor   = 8,   // has ictor member
+}
+
+
+class ModuleInfo
+{
+    string          name;
+    ModuleInfo[]    importedModules;
+    ClassInfo[]     localClasses;
+    uint            flags;
+
+    void function() ctor;       // module static constructor (order dependent)
+    void function() dtor;       // module static destructor
+    void function() unitTest;   // module unit tests
+
+    void* xgetMembers;          // module getMembers() function
+
+    void function() ictor;      // module static constructor (order independent)
+
+    void*[4] reserved;		// for future expansion
+
+    static int opApply(int delegate(inout ModuleInfo) dg)
+    {
+        int ret = 0;
+
+        foreach (m; _moduleinfo_array)
+        {
+            ret = dg(m);
+            if (ret)
+                break;
+        }
+        return ret;
+    }
+}
+
+
+// Windows: this gets initialized by minit.asm
+// Posix: this gets initialized in _moduleCtor()
+extern (C) __gshared ModuleInfo[] _moduleinfo_array;
+
+
+version (linux)
+{
+    // This linked list is created by a compiler generated function inserted
+    // into the .ctor list by the compiler.
+    struct ModuleReference
+    {
+        ModuleReference* next;
+        ModuleInfo       mod;
+    }
+
+    extern (C) __gshared ModuleReference* _Dmodule_ref;   // start of linked list
+}
+
+version (FreeBSD)
+{
+    // This linked list is created by a compiler generated function inserted
+    // into the .ctor list by the compiler.
+    struct ModuleReference
+    {
+        ModuleReference* next;
+        ModuleInfo       mod;
+    }
+
+    extern (C) __gshared ModuleReference* _Dmodule_ref;   // start of linked list
+}
+
+version (Solaris)
+{
+    // This linked list is created by a compiler generated function inserted
+    // into the .ctor list by the compiler.
+    struct ModuleReference
+    {
+        ModuleReference* next;
+        ModuleInfo       mod;
+    }
+
+    extern (C) __gshared ModuleReference* _Dmodule_ref;   // start of linked list
+}
+
+version (OSX)
+{
+    extern (C)
+    {
+        extern __gshared void* _minfo_beg;
+        extern __gshared void* _minfo_end;
+    }
+}
+
+__gshared ModuleInfo[] _moduleinfo_dtors;
+__gshared uint         _moduleinfo_dtors_i;
+
+// Register termination function pointers
+extern (C) int _fatexit(void*);
+
+/**
+ * Initialize the modules.
+ */
+
+extern (C) void _moduleCtor()
+{
+    debug(PRINTF) printf("_moduleCtor()\n");
+    version (linux)
+    {
+        int len = 0;
+        ModuleReference *mr;
+
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+            len++;
+        _moduleinfo_array = new ModuleInfo[len];
+        len = 0;
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+        {   _moduleinfo_array[len] = mr.mod;
+            len++;
+        }
+    }
+
+    version (FreeBSD)
+    {
+        int len = 0;
+        ModuleReference *mr;
+
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+            len++;
+        _moduleinfo_array = new ModuleInfo[len];
+        len = 0;
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+        {   _moduleinfo_array[len] = mr.mod;
+            len++;
+        }
+    }
+
+    version (Solaris)
+    {
+        int len = 0;
+        ModuleReference *mr;
+
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+            len++;
+        _moduleinfo_array = new ModuleInfo[len];
+        len = 0;
+        for (mr = _Dmodule_ref; mr; mr = mr.next)
+        {   _moduleinfo_array[len] = mr.mod;
+            len++;
+        }
+    }
+
+    version (OSX)
+    {
+        /* The ModuleInfo references are stored in the special segment
+         * __minfodata, which is bracketed by the segments __minfo_beg
+         * and __minfo_end. The variables _minfo_beg and _minfo_end
+         * are of zero size and are in the two bracketing segments,
+         * respectively.
+         */
+         size_t length = cast(ModuleInfo*)&_minfo_end - cast(ModuleInfo*)&_minfo_beg;
+         _moduleinfo_array = (cast(ModuleInfo*)&_minfo_beg)[0 .. length];
+         debug printf("moduleinfo: ptr = %p, length = %d\n", _moduleinfo_array.ptr, _moduleinfo_array.length);
+
+         debug foreach (m; _moduleinfo_array)
+         {
+             //printf("\t%p\n", m);
+             printf("\t%.*s\n", m.name);
+         }
+    }    
+
+    version (Windows)
+    {
+        // Ensure module destructors also get called on program termination
+        //_fatexit(&_STD_moduleDtor);
+    }
+
+    _moduleinfo_dtors = new ModuleInfo[_moduleinfo_array.length];
+    debug(PRINTF) printf("_moduleinfo_dtors = x%x\n", cast(void*)_moduleinfo_dtors);
+    _moduleIndependentCtors();
+    _moduleCtor2(_moduleinfo_array, 0);
+}
+
+extern (C) void _moduleIndependentCtors()
+{
+    debug(PRINTF) printf("_moduleIndependentCtors()\n");
+    foreach (m; _moduleinfo_array)
+    {
+        if (m && m.flags & MIhasictor && m.ictor)
+        {
+            (*m.ictor)();
+        }
+    }
+}
+
+void _moduleCtor2(ModuleInfo[] mi, int skip)
+{
+    debug(PRINTF) printf("_moduleCtor2(): %d modules\n", mi.length);
+    for (uint i = 0; i < mi.length; i++)
+    {
+        ModuleInfo m = mi[i];
+
+        debug(PRINTF) printf("\tmodule[%d] = '%p'\n", i, m);
+        if (!m)
+            continue;
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s'\n", i, m.name);
+        if (m.flags & MIctordone)
+            continue;
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s', m = x%x\n", i, m.name, m);
+
+        if (m.ctor || m.dtor)
+        {
+            if (m.flags & MIctorstart)
+            {   if (skip || m.flags & MIstandalone)
+                    continue;
+                    throw new Exception("Cyclic dependency in module " ~ m.name);
+            }
+
+            m.flags |= MIctorstart;
+            _moduleCtor2(m.importedModules, 0);
+            if (m.ctor)
+                (*m.ctor)();
+            m.flags &= ~MIctorstart;
+            m.flags |= MIctordone;
+
+            // Now that construction is done, register the destructor
+            //printf("\tadding module dtor x%x\n", m);
+            assert(_moduleinfo_dtors_i < _moduleinfo_dtors.length);
+            _moduleinfo_dtors[_moduleinfo_dtors_i++] = m;
+        }
+        else
+        {
+            m.flags |= MIctordone;
+            _moduleCtor2(m.importedModules, 1);
+        }
+    }
+}
+
+/**
+ * Destruct the modules.
+ */
+
+// Starting the name with "_STD" means under Posix a pointer to the
+// function gets put in the .dtors segment.
+
+extern (C) void _moduleDtor()
+{
+    debug(PRINTF) printf("_moduleDtor(): %d modules\n", _moduleinfo_dtors_i);
+
+    for (uint i = _moduleinfo_dtors_i; i-- != 0;)
+    {
+        ModuleInfo m = _moduleinfo_dtors[i];
+
+        debug(PRINTF) printf("\tmodule[%d] = '%.*s', x%x\n", i, m.name, m);
+        if (m.dtor)
+        {
+            (*m.dtor)();
+        }
+    }
+    debug(PRINTF) printf("_moduleDtor() done\n");
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Monitor
+///////////////////////////////////////////////////////////////////////////////
+
+alias Object.Monitor        IMonitor;
+alias void delegate(Object) DEvent;
+
+// NOTE: The dtor callback feature is only supported for monitors that are not
+//       supplied by the user.  The assumption is that any object with a user-
+//       supplied monitor may have special storage or lifetime requirements and
+//       that as a result, storing references to local objects within Monitor
+//       may not be safe or desirable.  Thus, devt is only valid if impl is
+//       null.
+struct Monitor
+{
+    IMonitor impl;
+    /* internal */
+    DEvent[] devt;
+    /* stuff */
+}
+
+Monitor* getMonitor(Object h)
+{
+    return cast(Monitor*) (cast(void**) h)[1];
+}
+
+void setMonitor(Object h, Monitor* m)
+{
+    (cast(void**) h)[1] = m;
+}
+
+extern (C) void _d_monitor_create(Object);
+extern (C) void _d_monitor_destroy(Object);
+extern (C) void _d_monitor_lock(Object);
+extern (C) int  _d_monitor_unlock(Object);
+
+extern (C) void _d_monitordelete(Object h, bool det)
+{
+    Monitor* m = getMonitor(h);
+
+    if (m !is null)
+    {
+        IMonitor i = m.impl;
+        if (i is null)
+        {
+            _d_monitor_devt(m, h);
+            _d_monitor_destroy(h);
+            setMonitor(h, null);
+            return;
+        }
+        if (det && (cast(void*) i) !is (cast(void*) h))
+            delete i;
+        setMonitor(h, null);
+    }
+}
+
+extern (C) void _d_monitorenter(Object h)
+{
+    Monitor* m = getMonitor(h);
+
+    if (m is null)
+    {
+        _d_monitor_create(h);
+        m = getMonitor(h);
+    }
+
+    IMonitor i = m.impl;
+
+    if (i is null)
+    {
+        _d_monitor_lock(h);
+        return;
+    }
+    i.lock();
+}
+
+extern (C) void _d_monitorexit(Object h)
+{
+    Monitor* m = getMonitor(h);
+    IMonitor i = m.impl;
+
+    if (i is null)
+    {
+        _d_monitor_unlock(h);
+        return;
+    }
+    i.unlock();
+}
+
+extern (C) void _d_monitor_devt(Monitor* m, Object h)
+{
+    if (m.devt.length)
+    {
+        DEvent[] devt;
+
+        synchronized (h)
+        {
+            devt = m.devt;
+            m.devt = null;
+        }
+        foreach (v; devt)
+        {
+            if (v)
+                v(h);
+        }
+        free(devt.ptr);
+    }
+}
+
+extern (C) void rt_attachDisposeEvent(Object h, DEvent e)
+{
+    synchronized (h)
+    {
+        Monitor* m = getMonitor(h);
+        assert(m.impl is null);
+
+        foreach (inout v; m.devt)
+        {
+            if (v is null || v == e)
+            {
+                v = e;
+                return;
+            }
+        }
+
+        auto len = m.devt.length + 4; // grow by 4 elements
+        auto pos = m.devt.length;     // insert position
+        auto p = realloc(m.devt.ptr, DEvent.sizeof * len);
+        if (!p)
+            onOutOfMemoryError();
+        m.devt = (cast(DEvent*)p)[0 .. len];
+        m.devt[pos+1 .. len] = null;
+        m.devt[pos] = e;
+    }
+}
+
+extern (C) void rt_detachDisposeEvent(Object h, DEvent e)
+{
+    synchronized (h)
+    {
+        Monitor* m = getMonitor(h);
+        assert(m.impl is null);
+
+        foreach (p, v; m.devt)
+        {
+            if (v == e)
+            {
+                memmove(&m.devt[p],
+                        &m.devt[p+1],
+                        (m.devt.length - p - 1) * DEvent.sizeof);
+                m.devt[$ - 1] = null;
+                return;
+            }
+        }
+    }
+}
Index: src/compiler/ldc/mars.h
===================================================================
--- src/compiler/ldc/mars.h	(revision 0)
+++ src/compiler/ldc/mars.h	(revision 0)
@@ -0,0 +1,105 @@
+/**
+ * Common declarations for runtime implementation.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+#include <stddef.h>
+
+#if __cplusplus
+extern "C" {
+#endif
+
+struct ClassInfo;
+struct Vtbl;
+
+typedef struct Vtbl
+{
+    size_t len;
+    void **vptr;
+} Vtbl;
+
+typedef struct Interface
+{
+    struct ClassInfo *classinfo;
+    struct Vtbl vtbl;
+    int offset;
+} Interface;
+
+typedef struct Object
+{
+    void **vptr;
+    void *monitor;
+} Object;
+
+typedef struct ClassInfo
+{
+    Object object;
+
+    size_t initlen;
+    void *init;
+
+    size_t namelen;
+    char *name;
+
+    Vtbl vtbl;
+
+    size_t interfacelen;
+    Interface *interfaces;
+
+    struct ClassInfo *baseClass;
+
+    void *destructor;
+    void *invariant;
+
+    int flags;
+} ClassInfo;
+
+typedef struct Throwable
+{
+    Object object;
+
+    size_t msglen;
+    char*  msg;
+
+    size_t filelen;
+    char*  file;
+
+    size_t line;
+
+    struct Interface *info;
+    struct Throwable *next;
+} Throwable;
+
+typedef struct Array
+{
+    size_t length;
+    void *ptr;
+} Array;
+
+typedef struct Delegate
+{
+    void *thisptr;
+    void (*funcptr)();
+} Delegate;
+
+void _d_monitorenter(Object *h);
+void _d_monitorexit(Object *h);
+
+int _d_isbaseof(ClassInfo *b, ClassInfo *c);
+Object *_d_dynamic_cast(Object *o, ClassInfo *ci);
+
+Object * _d_newclass(ClassInfo *ci);
+void _d_delclass(Object **p);
+
+void _d_OutOfMemory();
+
+#if __cplusplus
+}
+#endif
Index: src/compiler/ldc/complex.c
===================================================================
--- src/compiler/ldc/complex.c	(revision 0)
+++ src/compiler/ldc/complex.c	(revision 0)
@@ -0,0 +1,112 @@
+/**
+ * Implementation of complex number support routines.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+#include <math.h>
+
+typedef struct Complex
+{
+    long double re;
+    long double im;
+} Complex;
+
+Complex _complex_div(Complex x, Complex y)
+{
+    Complex q;
+    long double r;
+    long double den;
+
+    if (fabs(y.re) < fabs(y.im))
+    {
+        r = y.re / y.im;
+        den = y.im + r * y.re;
+        q.re = (x.re * r + x.im) / den;
+        q.im = (x.im * r - x.re) / den;
+    }
+    else
+    {
+        r = y.im / y.re;
+        den = y.re + r * y.im;
+        q.re = (x.re + r * x.im) / den;
+        q.im = (x.im - r * x.re) / den;
+    }
+    return q;
+}
+
+Complex _complex_mul(Complex x, Complex y)
+{
+    Complex p;
+
+    p.re = x.re * y.re - x.im * y.im;
+    p.im = x.im * y.re + x.re * y.im;
+    return p;
+}
+
+long double _complex_abs(Complex z)
+{
+    long double x,y,ans,temp;
+
+    x = fabs(z.re);
+    y = fabs(z.im);
+    if (x == 0)
+        ans = y;
+    else if (y == 0)
+        ans = x;
+    else if (x > y)
+    {
+        temp = y / x;
+        ans = x * sqrt(1 + temp * temp);
+    }
+    else
+    {
+        temp = x / y;
+        ans = y * sqrt(1 + temp * temp);
+    }
+    return ans;
+}
+
+Complex _complex_sqrt(Complex z)
+{
+    Complex c;
+    long double x,y,w,r;
+
+    if (z.re == 0 && z.im == 0)
+    {
+        c.re = 0;
+        c.im = 0;
+    }
+    else
+    {
+        x = fabs(z.re);
+        y = fabs(z.im);
+        if (x >= y)
+        {
+            r = y / x;
+            w = sqrt(x) * sqrt(0.5 * (1 + sqrt(1 + r * r)));
+        }
+        else
+        {
+            r = x / y;
+            w = sqrt(y) * sqrt(0.5 * (r + sqrt(1 + r * r)));
+        }
+        if (z.re >= 0)
+        {
+            c.re = w;
+            c.im = z.im / (w + w);
+        }
+        else
+        {
+            c.im = (z.im >= 0) ? w : -w;
+            c.re = z.im / (c.im + c.im);
+        }
+    }
+    return c;
+}
Index: src/compiler/ldc/minit.obj
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream

Property changes on: src/compiler/ldc/minit.obj
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream

Index: src/compiler/ldc/minit.asm
===================================================================
--- src/compiler/ldc/minit.asm	(revision 0)
+++ src/compiler/ldc/minit.asm	(revision 0)
@@ -0,0 +1,85 @@
+;_ minit.asm
+;  Module initialization support.
+; 
+;  Copyright: Copyright Digital Mars 2000 - 2009.
+;  License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+;  Authors:   Walter Bright
+; 
+;           Copyright Digital Mars 2000 - 2009.
+;  Distributed under the Boost Software License, Version 1.0.
+;     (See accompanying file LICENSE_1_0.txt or copy at
+;           http://www.boost.org/LICENSE_1_0.txt)
+;
+include macros.asm
+
+ifdef _WIN32
+  DATAGRP      EQU     FLAT
+else
+  DATAGRP      EQU     DGROUP
+endif
+
+; Provide a default resolution for weak extern records, no way in C
+; to define an omf symbol with a specific value
+public __nullext
+__nullext   equ 0
+
+    extrn   __moduleinfo_array:near
+
+; This bit of assembler is needed because, from C or D, one cannot
+; specify the names of data segments. Why does this matter?
+; All the ModuleInfo pointers are placed into a segment named 'FM'.
+; The order in which they are placed in 'FM' is arbitrarily up to the linker.
+; In order to walk all the pointers, we need to be able to find the
+; beginning and the end of the 'FM' segment.
+; This is done by bracketing the 'FM' segment with two other, empty,
+; segments named 'FMB' and 'FME'. Since this module is the only one that
+; ever refers to 'FMB' and 'FME', we get to control the order in which
+; these segments appear relative to 'FM' by using a GROUP statement.
+; So, we have in memory:
+;   FMB empty segment
+;   FM  contains all the pointers
+;   FME empty segment
+; and finding the limits of FM is as easy as taking the address of FMB
+; and the address of FME.
+
+; These segments bracket FM, which contains the list of ModuleInfo pointers
+FMB     segment dword use32 public 'DATA'
+FMB     ends
+FM      segment dword use32 public 'DATA'
+FM      ends
+FME     segment dword use32 public 'DATA'
+FME     ends
+
+; This leaves room in the _fatexit() list for _moduleDtor()
+XOB     segment dword use32 public 'BSS'
+XOB     ends
+XO      segment dword use32 public 'BSS'
+    dd  ?
+XO      ends
+XOE     segment dword use32 public 'BSS'
+XOE     ends
+
+DGROUP         group   FMB,FM,FME
+
+    begcode minit
+
+; extern (C) void _minit();
+; Converts array of ModuleInfo pointers to a D dynamic array of them,
+; so they can be accessed via D.
+; Result is written to:
+; extern (C) ModuleInfo[] _moduleinfo_array;
+
+    public  __minit
+__minit proc    near
+    mov EDX,offset DATAGRP:FMB
+    mov EAX,offset DATAGRP:FME
+    mov dword ptr __moduleinfo_array+4,EDX
+    sub EAX,EDX         ; size in bytes of FM segment
+    shr EAX,2           ; convert to array length
+    mov dword ptr __moduleinfo_array,EAX
+    ret
+__minit endp
+
+    endcode minit
+
+    end
Index: src/compiler/ldc/ldc/intrinsics.di
===================================================================
--- src/compiler/ldc/ldc/intrinsics.di	(revision 0)
+++ src/compiler/ldc/ldc/intrinsics.di	(revision 0)
@@ -0,0 +1,413 @@
+/*
+ * This module holds declarations to LLVM intrinsics.
+ *
+ * See the LLVM language reference for more information:
+ *
+ * - http://llvm.org/docs/LangRef.html#intrinsics
+ *
+ */
+
+module ldc.intrinsics;
+
+// Check for the right compiler
+version(LDC)
+{
+    // OK
+}
+else
+{
+    static assert(false, "This module is only valid for LDC");
+}
+
+//
+// CODE GENERATOR INTRINSICS
+//
+
+
+// The 'llvm.returnaddress' intrinsic attempts to compute a target-specific
+// value indicating the return address of the current function or one of its
+// callers.
+
+pragma(intrinsic, "llvm.returnaddress")
+    void* llvm_returnaddress(uint level);
+
+
+// The 'llvm.frameaddress' intrinsic attempts to return the target-specific
+// frame pointer value for the specified stack frame.
+
+pragma(intrinsic, "llvm.frameaddress")
+    void* llvm_frameaddress(uint level);
+
+
+// The 'llvm.stacksave' intrinsic is used to remember the current state of the
+// function stack, for use with llvm.stackrestore. This is useful for
+// implementing language features like scoped automatic variable sized arrays
+// in C99.
+
+pragma(intrinsic, "llvm.stacksave")
+    void* llvm_stacksave();
+
+
+// The 'llvm.stackrestore' intrinsic is used to restore the state of the
+// function stack to the state it was in when the corresponding llvm.stacksave
+// intrinsic executed. This is useful for implementing language features like
+// scoped automatic variable sized arrays in C99.
+
+pragma(intrinsic, "llvm.stackrestore")
+    void llvm_stackrestore(void* ptr);
+
+
+// The 'llvm.prefetch' intrinsic is a hint to the code generator to insert a
+// prefetch instruction if supported; otherwise, it is a noop. Prefetches have
+// no effect on the behavior of the program but can change its performance
+// characteristics.
+
+pragma(intrinsic, "llvm.prefetch")
+    void llvm_prefetch(void* ptr, uint rw, uint locality);
+
+
+// The 'llvm.pcmarker' intrinsic is a method to export a Program Counter (PC)
+// in a region of code to simulators and other tools. The method is target
+// specific, but it is expected that the marker will use exported symbols to
+// transmit the PC of the marker. The marker makes no guarantees that it will
+// remain with any specific instruction after optimizations. It is possible
+// that the presence of a marker will inhibit optimizations. The intended use
+// is to be inserted after optimizations to allow correlations of simulation
+// runs.
+
+pragma(intrinsic, "llvm.pcmarker")
+    void llvm_pcmarker(uint id);
+
+
+// The 'llvm.readcyclecounter' intrinsic provides access to the cycle counter
+// register (or similar low latency, high accuracy clocks) on those targets that
+// support it. On X86, it should map to RDTSC. On Alpha, it should map to RPCC.
+// As the backing counters overflow quickly (on the order of 9 seconds on
+// alpha), this should only be used for small timings.
+
+pragma(intrinsic, "llvm.readcyclecounter")
+    ulong readcyclecounter();
+
+
+
+
+//
+// STANDARD C LIBRARY INTRINSICS
+//
+
+
+// The 'llvm.memcpy.*' intrinsics copy a block of memory from the source
+// location to the destination location.
+// Note that, unlike the standard libc function, the llvm.memcpy.* intrinsics do
+// not return a value, and takes an extra alignment argument.
+
+pragma(intrinsic, "llvm.memcpy.i#")
+    void llvm_memcpy(T)(void* dst, void* src, T len, uint alignment);
+
+deprecated {
+    alias llvm_memcpy!(uint)  llvm_memcpy_i32;
+    alias llvm_memcpy!(ulong) llvm_memcpy_i64;
+}
+
+
+// The 'llvm.memmove.*' intrinsics move a block of memory from the source
+// location to the destination location. It is similar to the 'llvm.memcpy'
+// intrinsic but allows the two memory locations to overlap.
+// Note that, unlike the standard libc function, the llvm.memmove.* intrinsics
+// do not return a value, and takes an extra alignment argument.
+
+pragma(intrinsic, "llvm.memmove.i#")
+    void llvm_memmove(T)(void* dst, void* src, T len, uint alignment);
+
+deprecated {
+    alias llvm_memmove!(uint)  llvm_memmove_i32;
+    alias llvm_memmove!(ulong) llvm_memmove_i64;
+}
+
+
+// The 'llvm.memset.*' intrinsics fill a block of memory with a particular byte
+// value.
+// Note that, unlike the standard libc function, the llvm.memset intrinsic does
+// not return a value, and takes an extra alignment argument.
+
+pragma(intrinsic, "llvm.memset.i#")
+    void llvm_memset(T)(void* dst, ubyte val, T len, uint alignment);
+
+deprecated {
+    alias llvm_memset!(uint)  llvm_memset_i32;
+    alias llvm_memset!(ulong) llvm_memset_i64;
+}
+
+
+// The 'llvm.sqrt' intrinsics return the sqrt of the specified operand,
+// returning the same value as the libm 'sqrt' functions would. Unlike sqrt in
+// libm, however, llvm.sqrt has undefined behavior for negative numbers other
+// than -0.0 (which allows for better optimization, because there is no need to
+// worry about errno being set). llvm.sqrt(-0.0) is defined to return -0.0 like
+// IEEE sqrt.
+
+pragma(intrinsic, "llvm.sqrt.f#")
+    T llvm_sqrt(T)(T val);
+
+deprecated {
+    alias llvm_sqrt!(float)  llvm_sqrt_f32;
+    alias llvm_sqrt!(double) llvm_sqrt_f64;
+    alias llvm_sqrt!(real)   llvm_sqrt_f80;     // may not actually be .f80
+}
+
+
+// The 'llvm.sin.*' intrinsics return the sine of the operand.
+
+pragma(intrinsic, "llvm.sin.f#")
+    T llvm_sin(T)(T val);
+
+deprecated {
+    alias llvm_sin!(float)  llvm_sin_f32;
+    alias llvm_sin!(double) llvm_sin_f64;
+    alias llvm_sin!(real)   llvm_sin_f80;       // may not actually be .f80
+}
+
+
+// The 'llvm.cos.*' intrinsics return the cosine of the operand.
+
+pragma(intrinsic, "llvm.cos.f#")
+    T llvm_cos(T)(T val);
+
+deprecated {
+    alias llvm_cos!(float)  llvm_cos_f32;
+    alias llvm_cos!(double) llvm_cos_f64;
+    alias llvm_cos!(real)   llvm_cos_f80;       // may not actually be .f80
+}
+
+
+// The 'llvm.powi.*' intrinsics return the first operand raised to the specified
+// (positive or negative) power. The order of evaluation of multiplications is
+// not defined. When a vector of floating point type is used, the second
+// argument remains a scalar integer value.
+
+pragma(intrinsic, "llvm.powi.f#")
+    T llvm_powi(T)(T val, int power);
+
+deprecated {
+    alias llvm_powi!(float)  llvm_powi_f32;
+    alias llvm_powi!(double) llvm_powi_f64;
+    alias llvm_powi!(real)   llvm_powi_f80;     // may not actually be .f80
+}
+
+
+// The 'llvm.pow.*' intrinsics return the first operand raised to the specified
+// (positive or negative) power.
+
+pragma(intrinsic, "llvm.pow.f#")
+    T llvm_pow(T)(T val, T power);
+
+deprecated {
+    alias llvm_pow!(float)  llvm_pow_f32;
+    alias llvm_pow!(double) llvm_pow_f64;
+    alias llvm_pow!(real)   llvm_pow_f80;       // may not actually be .f80
+}
+
+
+//
+// BIT MANIPULATION INTRINSICS
+//
+
+// The 'llvm.bswap' family of intrinsics is used to byte swap integer values
+// with an even number of bytes (positive multiple of 16 bits). These are
+// useful for performing operations on data that is not in the target's native
+// byte order.
+
+pragma(intrinsic, "llvm.bswap.i#.i#")
+    T llvm_bswap(T)(T val);
+
+deprecated {
+    alias llvm_bswap!(ushort) llvm_bswap_i16;
+    alias llvm_bswap!(uint)   llvm_bswap_i32;
+    alias llvm_bswap!(ulong)  llvm_bswap_i64;
+}
+
+
+// The 'llvm.ctpop' family of intrinsics counts the number of bits set in a
+// value.
+
+pragma(intrinsic, "llvm.ctpop.i#")
+    T llvm_ctpop(T)(T src);
+
+deprecated {
+    alias llvm_ctpop!(ubyte)  llvm_ctpop_i8;
+    alias llvm_ctpop!(ushort) llvm_ctpop_i16;
+    alias llvm_ctpop!(uint)   llvm_ctpop_i32;
+    alias llvm_ctpop!(ulong)  llvm_ctpop_i64;
+}
+
+
+// The 'llvm.ctlz' family of intrinsic functions counts the number of leading
+// zeros in a variable.
+
+pragma(intrinsic, "llvm.ctlz.i#")
+    T llvm_ctlz(T)(T src);
+
+deprecated {
+    alias llvm_ctlz!(ubyte)  llvm_ctlz_i8;
+    alias llvm_ctlz!(ushort) llvm_ctlz_i16;
+    alias llvm_ctlz!(uint)   llvm_ctlz_i32;
+    alias llvm_ctlz!(ulong)  llvm_ctlz_i64;
+}
+
+
+// The 'llvm.cttz' family of intrinsic functions counts the number of trailing
+// zeros.
+
+pragma(intrinsic, "llvm.cttz.i#")
+    T llvm_cttz(T)(T src);
+
+deprecated {
+    alias llvm_cttz!(ubyte)  llvm_cttz_i8;
+    alias llvm_cttz!(ushort) llvm_cttz_i16;
+    alias llvm_cttz!(uint)   llvm_cttz_i32;
+    alias llvm_cttz!(ulong)  llvm_cttz_i64;
+}
+
+
+// The 'llvm.part.select' family of intrinsic functions selects a range of bits
+// from an integer value and returns them in the same bit width as the original
+// value.
+
+pragma(intrinsic, "llvm.part.select.i#")
+    T llvm_part_select(T)(T val, uint loBit, uint hiBit);
+
+deprecated {
+    alias llvm_part_select!(ubyte)  llvm_part_select_i;
+    alias llvm_part_select!(ushort) llvm_part_select_i;
+    alias llvm_part_select!(uint)   llvm_part_select_i;
+    alias llvm_part_select!(ulong)  llvm_part_select_i;
+}
+
+
+// The 'llvm.part.set' family of intrinsic functions replaces a range of bits
+// in an integer value with another integer value. It returns the integer with
+// the replaced bits.
+
+// TODO
+// declare i17 @llvm.part.set.i17.i9 (i17 %val, i9 %repl, i32 %lo, i32 %hi)
+// declare i29 @llvm.part.set.i29.i9 (i29 %val, i9 %repl, i32 %lo, i32 %hi)
+
+
+
+
+//
+// ATOMIC OPERATIONS AND SYNCHRONIZATION INTRINSICS
+//
+
+// The llvm.memory.barrier intrinsic guarantees ordering between specific
+// pairs of memory access types.
+
+pragma(intrinsic, "llvm.memory.barrier")
+    void llvm_memory_barrier(bool ll, bool ls, bool sl, bool ss, bool device);
+
+// This loads a value in memory and compares it to a given value. If they are
+// equal, it stores a new value into the memory.
+
+pragma(intrinsic, "llvm.atomic.cmp.swap.i#.p0i#")
+    T llvm_atomic_cmp_swap(T)(T* ptr, T cmp, T val);
+
+// This intrinsic loads the value stored in memory at ptr and yields the value
+// from memory. It then stores the value in val in the memory at ptr.
+
+pragma(intrinsic, "llvm.atomic.swap.i#.p0i#")
+    T llvm_atomic_swap(T)(T* ptr, T val);
+
+// This intrinsic adds delta to the value stored in memory at ptr. It yields
+// the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.add.i#.p0i#")
+    T llvm_atomic_load_add(T)(T* ptr, T val);
+
+// This intrinsic subtracts delta to the value stored in memory at ptr. It
+// yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.sub.i#.p0i#")
+    T llvm_atomic_load_sub(T)(T* ptr, T val);
+
+// These intrinsics bitwise the operation (and, nand, or, xor) delta to the
+// value stored in memory at ptr. It yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.and.i#.p0i#")
+    T llvm_atomic_load_and(T)(T* ptr, T val);
+
+pragma(intrinsic, "llvm.atomic.load.nand.i#.p0i#")
+    T llvm_atomic_load_nand(T)(T* ptr, T val);
+
+pragma(intrinsic, "llvm.atomic.load.or.i#.p0i#")
+    T llvm_atomic_load_or(T)(T* ptr, T val);
+
+pragma(intrinsic, "llvm.atomic.load.xor.i#.p0i#")
+    T llvm_atomic_load_xor(T)(T* ptr, T val);
+
+// These intrinsics takes the signed or unsigned minimum or maximum of delta
+// and the value stored in memory at ptr. It yields the original value at ptr.
+
+pragma(intrinsic, "llvm.atomic.load.max.i#.p0i#")
+    T llvm_atomic_load_max(T)(T* ptr, T val);
+
+pragma(intrinsic, "llvm.atomic.load.min.i#.p0i#")
+    T llvm_atomic_load_min(T)(T* ptr, T val);
+
+pragma(intrinsic, "llvm.atomic.load.umax.i#.p0i#")
+    T llvm_atomic_load_umax(T)(T* ptr, T val);
+
+pragma(intrinsic, "llvm.atomic.load.umin.i#.p0i#")
+    T llvm_atomic_load_umin(T)(T* ptr, T val);
+
+
+//
+// ARITHMETIC-WITH-OVERFLOW INTRINSICS
+//
+
+struct OverflowRet(T) {
+    static assert(is(T : int), T.stringof ~ " is not an integer type!");
+    T result;
+    bool overflow;
+}
+
+// Signed and unsigned addition
+pragma(intrinsic, "llvm.sadd.with.overflow.i#")
+    OverflowRet!(T) llvm_sadd_with_overflow(T)(T lhs, T rhs);
+
+pragma(intrinsic, "llvm.uadd.with.overflow.i#")
+    OverflowRet!(T) llvm_uadd_with_overflow(T)(T lhs, T rhs);
+
+
+// Signed and unsigned subtraction
+pragma(intrinsic, "llvm.ssub.with.overflow.i#")
+    OverflowRet!(T) llvm_ssub_with_overflow(T)(T lhs, T rhs);
+
+pragma(intrinsic, "llvm.usub.with.overflow.i#")
+    OverflowRet!(T) llvm_usub_with_overflow(T)(T lhs, T rhs);
+
+
+// Signed and unsigned multiplication
+pragma(intrinsic, "llvm.smul.with.overflow.i#")
+    OverflowRet!(T) llvm_smul_with_overflow(T)(T lhs, T rhs);
+
+/* Note: LLVM documentations says:
+ *  Warning: 'llvm.umul.with.overflow' is badly broken.
+ *  It is actively being fixed, but it should not currently be used!
+ *
+ * See: http://llvm.org/docs/LangRef.html#int_umul_overflow
+ */
+//pragma(intrinsic, "llvm.umul.with.overflow.i#")
+//    OverflowRet!(T) llvm_umul_with_overflow(T)(T lhs, T rhs);
+
+
+//
+// GENERAL INTRINSICS
+//
+
+
+// This intrinsics is lowered to the target dependent trap instruction. If the
+// target does not have a trap instruction, this intrinsic will be lowered to
+// the call of the abort() function.
+
+pragma(intrinsic, "llvm.trap")
+    void llvm_trap();
Index: src/compiler/ldc/ldc/cstdarg.di
===================================================================
--- src/compiler/ldc/ldc/cstdarg.di	(revision 0)
+++ src/compiler/ldc/ldc/cstdarg.di	(revision 0)
@@ -0,0 +1,29 @@
+/*
+ * vararg support for extern(C) functions
+ */
+
+module ldc.cstdarg;
+
+// Check for the right compiler
+version(LDC)
+{
+    // OK
+}
+else
+{
+    static assert(false, "This module is only valid for LDC");
+}
+
+alias void* va_list;
+
+pragma(va_start)
+    void va_start(T)(va_list ap, ref T);
+
+pragma(va_arg)
+    T va_arg(T)(va_list ap);
+
+pragma(va_end)
+    void va_end(va_list args);
+
+pragma(va_copy)
+    void va_copy(va_list dst, va_list src);
Index: src/compiler/ldc/tls.S
===================================================================
--- src/compiler/ldc/tls.S	(revision 0)
+++ src/compiler/ldc/tls.S	(revision 0)
@@ -0,0 +1,44 @@
+/**
+ * Contains support code for thread-local storage.
+ *
+ * Copyright: Copyright Digital Mars 2008 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2008 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+#if linux
+
+/* The memory between the addresses of _tlsstart and _tlsend is the storage for
+ * thread-local data in D 2.0.  Both of these rely on the default linker script
+ * of:
+ *      .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ *      .tbss  : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ * to group the sections in that order.
+ *
+ * Sadly, this does not work because ld orders .tdata after .tdata.*, despite
+ * what the linker script says.
+ */
+
+.file "tls.S"
+
+.globl _tlsstart
+    .section .tdata,"awT",@progbits
+    .align 4
+    .type   _tlsstart, @object
+    .size   _tlsstart, 4
+_tlsstart:
+    .long   3
+
+.globl _tlsend
+    .section .tcommon,"awT",@nobits
+    .align 4
+    .type   _tlsend, @object
+    .size   _tlsend, 4
+_tlsend:
+    .zero   4
+
+#endif
Index: src/compiler/ldc/monitor.c
===================================================================
--- src/compiler/ldc/monitor.c	(revision 0)
+++ src/compiler/ldc/monitor.c	(revision 0)
@@ -0,0 +1,215 @@
+/**
+ * Contains the implementation for object monitors.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#if _WIN32
+#elif linux || __APPLE__
+#define USE_PTHREADS    1
+#else
+#endif
+
+#if _WIN32
+#include <windows.h>
+#endif
+
+#if USE_PTHREADS
+#include <pthread.h>
+#endif
+
+#include "mars.h"
+
+// This is what the monitor reference in Object points to
+typedef struct Monitor
+{
+    void* impl; // for user-level monitors
+    Array devt; // for internal monitors
+
+#if _WIN32
+    CRITICAL_SECTION mon;
+#endif
+
+#if USE_PTHREADS
+    pthread_mutex_t mon;
+#endif
+} Monitor;
+
+#define MONPTR(h)       (&((Monitor *)(h)->monitor)->mon)
+
+static volatile int inited;
+
+/* =============================== Win32 ============================ */
+
+#if _WIN32
+
+static CRITICAL_SECTION _monitor_critsec;
+
+void _STI_monitor_staticctor()
+{
+    if (!inited)
+    {   InitializeCriticalSection(&_monitor_critsec);
+        inited = 1;
+    }
+}
+
+void _STD_monitor_staticdtor()
+{
+    if (inited)
+    {   inited = 0;
+        DeleteCriticalSection(&_monitor_critsec);
+    }
+}
+
+void _d_monitor_create(Object *h)
+{
+    /*
+     * NOTE: Assume this is only called when h->monitor is null prior to the
+     * call.  However, please note that another thread may call this function
+     * at the same time, so we can not assert this here.  Instead, try and
+     * create a lock, and if one already exists then forget about it.
+     */
+
+    //printf("+_d_monitor_create(%p)\n", h);
+    assert(h);
+    Monitor *cs = NULL;
+    EnterCriticalSection(&_monitor_critsec);
+    if (!h->monitor)
+    {
+        cs = (Monitor *)calloc(sizeof(Monitor), 1);
+        assert(cs);
+        InitializeCriticalSection(&cs->mon);
+        h->monitor = (void *)cs;
+        cs = NULL;
+    }
+    LeaveCriticalSection(&_monitor_critsec);
+    if (cs)
+        free(cs);
+    //printf("-_d_monitor_create(%p)\n", h);
+}
+
+void _d_monitor_destroy(Object *h)
+{
+    //printf("+_d_monitor_destroy(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    DeleteCriticalSection(MONPTR(h));
+    free((void *)h->monitor);
+    h->monitor = NULL;
+    //printf("-_d_monitor_destroy(%p)\n", h);
+}
+
+int _d_monitor_lock(Object *h)
+{
+    //printf("+_d_monitor_acquire(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    EnterCriticalSection(MONPTR(h));
+    //printf("-_d_monitor_acquire(%p)\n", h);
+}
+
+void _d_monitor_unlock(Object *h)
+{
+    //printf("+_d_monitor_release(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    LeaveCriticalSection(MONPTR(h));
+    //printf("-_d_monitor_release(%p)\n", h);
+}
+
+#endif
+
+/* =============================== linux ============================ */
+
+#if USE_PTHREADS
+
+#ifndef PTHREAD_MUTEX_RECURSIVE
+#    define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+
+// Includes attribute fixes from David Friedman's GDC port
+
+static pthread_mutex_t _monitor_critsec;
+static pthread_mutexattr_t _monitors_attr;
+
+void _STI_monitor_staticctor()
+{
+    if (!inited)
+    {
+        pthread_mutexattr_init(&_monitors_attr);
+        pthread_mutexattr_settype(&_monitors_attr, PTHREAD_MUTEX_RECURSIVE);
+        pthread_mutex_init(&_monitor_critsec, 0);
+        inited = 1;
+    }
+}
+
+void _STD_monitor_staticdtor()
+{
+    if (inited)
+    {   inited = 0;
+        pthread_mutex_destroy(&_monitor_critsec);
+        pthread_mutexattr_destroy(&_monitors_attr);
+    }
+}
+
+void _d_monitor_create(Object *h)
+{
+    /*
+     * NOTE: Assume this is only called when h->monitor is null prior to the
+     * call.  However, please note that another thread may call this function
+     * at the same time, so we can not assert this here.  Instead, try and
+     * create a lock, and if one already exists then forget about it.
+     */
+
+    //printf("+_d_monitor_create(%p)\n", h);
+    assert(h);
+    Monitor *cs = NULL;
+    pthread_mutex_lock(&_monitor_critsec);
+    if (!h->monitor)
+    {
+        cs = (Monitor *)calloc(sizeof(Monitor), 1);
+        assert(cs);
+        pthread_mutex_init(&cs->mon, & _monitors_attr);
+        h->monitor = (void *)cs;
+        cs = NULL;
+    }
+    pthread_mutex_unlock(&_monitor_critsec);
+    if (cs)
+        free(cs);
+    //printf("-_d_monitor_create(%p)\n", h);
+}
+
+void _d_monitor_destroy(Object *h)
+{
+    //printf("+_d_monitor_destroy(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_destroy(MONPTR(h));
+    free((void *)h->monitor);
+    h->monitor = NULL;
+    //printf("-_d_monitor_destroy(%p)\n", h);
+}
+
+int _d_monitor_lock(Object *h)
+{
+    //printf("+_d_monitor_acquire(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_lock(MONPTR(h));
+    //printf("-_d_monitor_acquire(%p)\n", h);
+}
+
+void _d_monitor_unlock(Object *h)
+{
+    //printf("+_d_monitor_release(%p)\n", h);
+    assert(h && h->monitor && !(((Monitor*)h->monitor)->impl));
+    pthread_mutex_unlock(MONPTR(h));
+    //printf("-_d_monitor_release(%p)\n", h);
+}
+
+#endif
Index: src/compiler/ldc/posix.mak
===================================================================
--- src/compiler/ldc/posix.mak	(revision 0)
+++ src/compiler/ldc/posix.mak	(revision 0)
@@ -0,0 +1,82 @@
+# Makefile to build the compiler runtime D library for Linux
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make debug
+#		Build the debug version of the library
+#   make release
+#       Build the release version of the library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete all files created by build process
+
+# Essentials
+
+LIBDIR=../../../lib
+DOCDIR=../../../doc
+IMPDIR=../../../import
+LIBBASENAME=libdruntime-rt-dmd.a
+MODULES=
+BUILDS=debug release unittest
+
+MODULES_BASE=aaA aApply aApplyR adi alloca arrayassign arraybyte	\
+    arraycast arraycat arraydouble arrayfloat arrayint arrayreal	\
+    arrayshort cast_ cmath2 cover deh2 dmain2 invariant invariant_	\
+    lifetime llmath memory memset obj object_ qsort switch_ trace
+# NOTE: trace.o and cover.o are not necessary for a successful build
+#       as both are used for debugging features (profiling and coverage)
+# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and
+#       minit.asm is not used by dmd for Linux
+# NOTE: deh.o is only needed for Win32, Linux uses deh2.o
+MODULES_UTIL=$(addprefix util/,console cpuid ctype string utf)
+MODULES_TI=$(addprefix typeinfo/ti_,AC Acdouble Acfloat Acreal Adouble	\
+    Afloat Ag Aint Along Areal Ashort byte C cdouble cfloat char creal	\
+    dchar delegate double float idouble ifloat int ireal long ptr real	\
+    short ubyte uint ulong ushort void wchar)
+C_SRCS=complex.c critical.c memory_osx.c monitor.c
+
+# Symbols
+
+DMD=dmd
+DOCFLAGS=-version=DDoc
+DFLAGS_release=-d -release -O -inline -w -nofloat
+DFLAGS_debug=-d -g -w -nofloat
+DFLAGS_unittest=$(DFLAGS_release) -unittest
+CFLAGS_release=-m32 -O
+CFLAGS_debug=-m32 -g
+CFLAGS_unittest=$(CFLAGS_release)
+
+# Derived symbols
+
+C_OBJS=$(addsuffix .o,$(basename $(C_SRCS)))
+AS_OBJS=$(addsuffix .o,$(basename $(AS_SRCS)))
+ALL_MODULES=$(MODULES_BASE) $(MODULES_UTIL) $(MODULES_TI)
+D_SRCS=$(addsuffix .d,$(ALL_MODULES))
+ALLLIBS=$(addsuffix /$(LIBBASENAME),$(addprefix $(LIBDIR)/,$(BUILDS)))
+
+# Patterns
+
+$(LIBDIR)/%/$(LIBBASENAME) : $(D_SRCS) $(C_SRCS) $(AS_SRCS)
+	$(CC) -c $(CFLAGS_$*) $(C_SRCS)
+	$(DMD) $(DFLAGS_$*) -lib -of$@ $(D_SRCS) $(C_OBJS) $(AS_OBJS)
+	rm $(C_OBJS) $(AS_OBJS)
+
+$(DOCDIR)/%.html : %.d
+	$(DMD) -c -d -o- -Df$@ $<
+
+$(IMPDIR)/%.di : %.d
+	$(DMD) -c -d -o- -Hf$@ $<
+
+# Rulez
+
+all : $(BUILDS) doc
+
+debug : $(LIBDIR)/debug/$(LIBBASENAME) $(IMPORTS)
+release : $(LIBDIR)/release/$(LIBBASENAME) $(IMPORTS)
+unittest : $(LIBDIR)/unittest/$(LIBBASENAME) $(IMPORTS)
+#doc : $(DOCS)
+
+clean :
+	rm -f $(IMPORTS) $(DOCS) $(ALLLIBS)
Index: src/compiler/ldc/win32.mak
===================================================================
--- src/compiler/ldc/win32.mak	(revision 0)
+++ src/compiler/ldc/win32.mak	(revision 0)
@@ -0,0 +1,175 @@
+# Makefile to build the D runtime library core components for Posix
+# Designed to work with GNU make
+# Targets:
+#	make
+#		Same as make all
+#	make debug
+#		Build the debug version of the library
+#   make release
+#       Build the release version of the library
+#   make doc
+#       Generate documentation
+#	make clean
+#		Delete all files created by build process
+
+# Essentials
+
+LIBDIR=..\..\..\lib
+DOCDIR=..\..\..\doc
+IMPDIR=..\..\..\import
+LIBBASENAME=druntime_rt_dmd.lib
+#MODULES=bitop exception memory runtime thread vararg \
+#	$(addprefix sync/,barrier condition config exception mutex rwmutex semaphore)
+BUILDS=debug release unittest
+
+MODULES_BASE= \
+	aaA.d \
+	aApply.d \
+	aApplyR.d \
+	adi.d \
+	arrayassign.d \
+	arraybyte.d \
+	arraycast.d \
+	arraycat.d \
+	arraydouble.d \
+	arrayfloat.d \
+	arrayint.d \
+	arrayreal.d \
+	arrayshort.d \
+	cast_.d \
+	cover.d \
+	dmain2.d \
+	invariant.d \
+	invariant_.d \
+	lifetime.d \
+	memory.d \
+	memset.d \
+	obj.d \
+	object_.d \
+	qsort.d \
+	switch_.d \
+	trace.d
+# NOTE: trace.d and cover.d are not necessary for a successful build
+#       as both are used for debugging features (profiling and coverage)
+# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and
+#       minit.asm is not used by dmd for Linux
+
+MODULES_UTIL= \
+	util\console.d \
+	util\cpuid.d \
+	util\ctype.d \
+	util\string.d \
+	util\utf.d
+
+MODULES_TI= \
+	typeinfo\ti_AC.d \
+	typeinfo\ti_Acdouble.d \
+	typeinfo\ti_Acfloat.d \
+	typeinfo\ti_Acreal.d \
+	typeinfo\ti_Adouble.d \
+	typeinfo\ti_Afloat.d \
+	typeinfo\ti_Ag.d \
+	typeinfo\ti_Aint.d \
+	typeinfo\ti_Along.d \
+	typeinfo\ti_Areal.d \
+	typeinfo\ti_Ashort.d \
+	typeinfo\ti_byte.d \
+	typeinfo\ti_C.d \
+	typeinfo\ti_cdouble.d \
+	typeinfo\ti_cfloat.d \
+	typeinfo\ti_char.d \
+	typeinfo\ti_creal.d \
+	typeinfo\ti_dchar.d \
+	typeinfo\ti_delegate.d \
+	typeinfo\ti_double.d \
+	typeinfo\ti_float.d \
+	typeinfo\ti_idouble.d \
+	typeinfo\ti_ifloat.d \
+	typeinfo\ti_int.d \
+	typeinfo\ti_ireal.d \
+	typeinfo\ti_long.d \
+	typeinfo\ti_ptr.d \
+	typeinfo\ti_real.d \
+	typeinfo\ti_short.d \
+	typeinfo\ti_ubyte.d \
+	typeinfo\ti_uint.d \
+	typeinfo\ti_ulong.d \
+	typeinfo\ti_ushort.d \
+	typeinfo\ti_void.d \
+	typeinfo\ti_wchar.d
+
+C_SRCS=complex.c critical.c deh.c monitor.c
+
+# Symbols
+
+CC=dmc
+DMD=dmd
+DOCFLAGS=-version=DDoc
+DFLAGS_release=-d -release -O -inline -w -nofloat
+DFLAGS_debug=-d -g -w -nofloat
+DFLAGS_unittest=$(DFLAGS_release) -unittest
+CFLAGS_release=-mn -6 -r
+CFLAGS_debug=-g -mn -6 -r
+CFLAGS_unittest=$(CFLAGS_release)
+
+# Derived symbols
+
+C_OBJS=complex.obj critical.obj deh.obj monitor.obj
+AS_OBJS=minit.obj
+ALL_MODULES=$(MODULES_BASE) $(MODULES_UTIL) $(MODULES_TI)
+D_SRCS=$(ALL_MODULES)
+ALLLIBS=\
+	$(LIBDIR)\debug\$(LIBBASENAME) \
+	$(LIBDIR)\release\$(LIBBASENAME) \
+	$(LIBDIR)\unittest\$(LIBBASENAME)
+
+# Patterns
+
+#$(LIBDIR)\%\$(LIBBASENAME) : $(D_SRCS) $(C_SRCS) $(AS_OBJS)
+#	$(CC) -c $(CFLAGS_$*) $(C_SRCS)
+#	$(DMD) $(DFLAGS_$*) -lib -of$@ $(D_SRCS) $(C_OBJS) $(AS_OBJS)
+#	del $(C_OBJS)
+
+#$(DOCDIR)\%.html : %.d
+#	$(DMD) -c -d -o- -Df$@ $<
+
+#$(IMPDIR)\%.di : %.d
+#	$(DMD) -c -d -o- -Hf$@ $<
+
+# Patterns - debug
+
+$(LIBDIR)\debug\$(LIBBASENAME) : $(D_SRCS) $(C_SRCS) $(AS_OBJS)
+	$(CC) -c $(CFLAGS_debug) $(C_SRCS)
+	$(DMD) $(DFLAGS_debug) -lib -of$@ $(D_SRCS) $(C_OBJS) $(AS_OBJS)
+	del $(C_OBJS)
+
+# Patterns - release
+
+$(LIBDIR)\release\$(LIBBASENAME) : $(D_SRCS) $(C_SRCS) $(AS_OBJS)
+	$(CC) -c $(CFLAGS_release) $(C_SRCS)
+	$(DMD) $(DFLAGS_release) -lib -of$@ $(D_SRCS) $(C_OBJS) $(AS_OBJS)
+	del $(C_OBJS)
+
+# Patterns - unittest
+
+$(LIBDIR)\unittest\$(LIBBASENAME) : $(D_SRCS) $(C_SRCS) $(AS_OBJS)
+	$(CC) -c $(CFLAGS_unittest) $(C_SRCS)
+	$(DMD) $(DFLAGS_unittest) -lib -of$@ $(D_SRCS) $(C_OBJS) $(AS_OBJS)
+	del $(C_OBJS)
+
+# Patterns - asm
+
+minit.obj : minit.asm
+	$(CC) -c $**
+
+# Rulez
+
+all : $(BUILDS) doc
+
+debug : $(LIBDIR)\debug\$(LIBBASENAME) $(IMPORTS)
+release : $(LIBDIR)\release\$(LIBBASENAME) $(IMPORTS)
+unittest : $(LIBDIR)\unittest\$(LIBBASENAME) $(IMPORTS)
+#doc : $(DOCS)
+
+clean :
+	del $(IMPORTS) $(DOCS) $(ALLLIBS)
Index: src/compiler/ldc/critical.c
===================================================================
--- src/compiler/ldc/critical.c	(revision 0)
+++ src/compiler/ldc/critical.c	(revision 0)
@@ -0,0 +1,173 @@
+/**
+ * Implementation of support routines for synchronized blocks.
+ *
+ * Copyright: Copyright Digital Mars 2000 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright, Sean Kelly
+ *
+ *          Copyright Digital Mars 2000 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+/* ================================= Win32 ============================ */
+
+#if _WIN32
+
+#include <windows.h>
+
+/******************************************
+ * Enter/exit critical section.
+ */
+
+/* We don't initialize critical sections unless we actually need them.
+ * So keep a linked list of the ones we do use, and in the static destructor
+ * code, walk the list and release them.
+ */
+
+typedef struct D_CRITICAL_SECTION
+{
+    struct D_CRITICAL_SECTION *next;
+    CRITICAL_SECTION cs;
+} D_CRITICAL_SECTION;
+
+static D_CRITICAL_SECTION *dcs_list;
+static D_CRITICAL_SECTION critical_section;
+static volatile int inited;
+
+void _d_criticalenter(D_CRITICAL_SECTION *dcs)
+{
+    if (!dcs->next)
+    {
+        EnterCriticalSection(&critical_section.cs);
+        if (!dcs->next) // if, in the meantime, another thread didn't set it
+        {
+            dcs->next = dcs_list;
+            dcs_list = dcs;
+            InitializeCriticalSection(&dcs->cs);
+        }
+        LeaveCriticalSection(&critical_section.cs);
+    }
+    EnterCriticalSection(&dcs->cs);
+}
+
+void _d_criticalexit(D_CRITICAL_SECTION *dcs)
+{
+    LeaveCriticalSection(&dcs->cs);
+}
+
+void _STI_critical_init()
+{
+    if (!inited)
+    {   InitializeCriticalSection(&critical_section.cs);
+        dcs_list = &critical_section;
+        inited = 1;
+    }
+}
+
+void _STD_critical_term()
+{
+    if (inited)
+    {   inited = 0;
+        while (dcs_list)
+        {
+            DeleteCriticalSection(&dcs_list->cs);
+            dcs_list = dcs_list->next;
+        }
+    }
+}
+
+#endif
+
+/* ================================= linux ============================ */
+
+#if linux || __APPLE__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+
+// PTHREAD_MUTEX_RECURSIVE is the "standard" symbol,
+// while the _NP version is specific to Linux
+#ifndef PTHREAD_MUTEX_RECURSIVE
+#    define PTHREAD_MUTEX_RECURSIVE PTHREAD_MUTEX_RECURSIVE_NP
+#endif
+
+/******************************************
+ * Enter/exit critical section.
+ */
+
+/* We don't initialize critical sections unless we actually need them.
+ * So keep a linked list of the ones we do use, and in the static destructor
+ * code, walk the list and release them.
+ */
+
+typedef struct D_CRITICAL_SECTION
+{
+    struct D_CRITICAL_SECTION *next;
+    pthread_mutex_t cs;
+} D_CRITICAL_SECTION;
+
+static D_CRITICAL_SECTION *dcs_list;
+static D_CRITICAL_SECTION critical_section;
+static pthread_mutexattr_t _criticals_attr;
+
+void _STI_critical_init(void);
+void _STD_critical_term(void);
+
+void _d_criticalenter(D_CRITICAL_SECTION *dcs)
+{
+    if (!dcs_list)
+    {   _STI_critical_init();
+        atexit(_STD_critical_term);
+    }
+    //printf("_d_criticalenter(dcs = x%x)\n", dcs);
+    if (!dcs->next)
+    {
+        pthread_mutex_lock(&critical_section.cs);
+        if (!dcs->next) // if, in the meantime, another thread didn't set it
+        {
+            dcs->next = dcs_list;
+            dcs_list = dcs;
+            pthread_mutex_init(&dcs->cs, &_criticals_attr);
+        }
+        pthread_mutex_unlock(&critical_section.cs);
+    }
+    pthread_mutex_lock(&dcs->cs);
+}
+
+void _d_criticalexit(D_CRITICAL_SECTION *dcs)
+{
+    //printf("_d_criticalexit(dcs = x%x)\n", dcs);
+    pthread_mutex_unlock(&dcs->cs);
+}
+
+void _STI_critical_init()
+{
+    if (!dcs_list)
+    {   //printf("_STI_critical_init()\n");
+        pthread_mutexattr_init(&_criticals_attr);
+        pthread_mutexattr_settype(&_criticals_attr, PTHREAD_MUTEX_RECURSIVE);
+
+        // The global critical section doesn't need to be recursive
+        pthread_mutex_init(&critical_section.cs, 0);
+        dcs_list = &critical_section;
+    }
+}
+
+void _STD_critical_term()
+{
+    if (dcs_list)
+    {   //printf("_STI_critical_term()\n");
+        while (dcs_list)
+        {
+            //printf("\tlooping... %x\n", dcs_list);
+            pthread_mutex_destroy(&dcs_list->cs);
+            dcs_list = dcs_list->next;
+        }
+    }
+}
+
+#endif
+
Index: src/compiler/ldc/invariant.d
===================================================================
--- src/compiler/ldc/invariant.d	(revision 0)
+++ src/compiler/ldc/invariant.d	(revision 0)
@@ -0,0 +1,35 @@
+/**
+ * Implementation of invariant support routines.
+ *
+ * Copyright: Copyright Digital Mars 2007 - 2009.
+ * License:   <a href="http://www.boost.org/LICENSE_1_0.txt>Boost License 1.0</a>.
+ * Authors:   Walter Bright
+ *
+ *          Copyright Digital Mars 2007 - 2009.
+ * Distributed under the Boost Software License, Version 1.0.
+ *    (See accompanying file LICENSE_1_0.txt or copy at
+ *          http://www.boost.org/LICENSE_1_0.txt)
+ */
+
+
+/**
+ *
+ */
+void _d_invariant(Object o)
+{   ClassInfo c;
+
+    //printf("__d_invariant(%p)\n", o);
+
+    // BUG: needs to be filename/line of caller, not library routine
+    assert(o !is null); // just do null check, not invariant check
+
+    c = o.classinfo;
+    do
+    {
+        if (c.classInvariant)
+        {
+            (*c.classInvariant)(o);
+        }
+        c = c.base;
+    } while (c);
+}
Index: import/core/stdc/stdarg.d
===================================================================
--- import/core/stdc/stdarg.d	(revision 166)
+++ import/core/stdc/stdarg.d	(working copy)
@@ -13,33 +13,39 @@
  */
 module core.stdc.stdarg;
 
+version(LDC)
+{
+    public import ldc.cstdarg;
+}
+else
+{
+    alias void* va_list;
 
-alias void* va_list;
-
-template va_start( T )
-{
-    void va_start( out va_list ap, inout T parmn )
+    template va_start( T )
     {
-        ap = cast(va_list) ( cast(void*) &parmn + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) );
+        void va_start( out va_list ap, inout T parmn )
+        {
+            ap = cast(va_list) ( cast(void*) &parmn + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) );
+        }
     }
-}
 
-template va_arg( T )
-{
-    T va_arg( inout va_list ap )
+    template va_arg( T )
     {
-        T arg = *cast(T*) ap;
-        ap = cast(va_list) ( cast(void*) ap + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) );
-        return arg;
+        T va_arg( inout va_list ap )
+        {
+            T arg = *cast(T*) ap;
+            ap = cast(va_list) ( cast(void*) ap + ( ( T.sizeof + int.sizeof - 1 ) & ~( int.sizeof - 1 ) ) );
+            return arg;
+        }
     }
-}
 
-void va_end( va_list ap )
-{
+    void va_end( va_list ap )
+    {
 
-}
+    }
 
-void va_copy( out va_list dest, va_list src )
-{
-    dest = src;
+    void va_copy( out va_list dest, va_list src )
+    {
+        dest = src;
+    }
 }
