diff dmd/CastExp.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 832f71e6f96c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/CastExp.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,1201 @@
+module dmd.CastExp;
+
+import dmd.Expression;
+import dmd.TY;
+import dmd.TypeStruct;
+import dmd.TypeExp;
+import dmd.DotIdExp;
+import dmd.CallExp;
+import dmd.Global;
+import dmd.Id;
+import dmd.Identifier;
+import dmd.BinExp;
+import dmd.backend.elem;
+import dmd.UnaExp;
+import dmd.VarExp;
+import dmd.Token;
+import dmd.VarDeclaration;
+import dmd.InterState;
+import dmd.MATCH;
+import dmd.Type;
+import dmd.OutBuffer;
+import dmd.Loc;
+import dmd.Scope;
+import dmd.IntRange;
+import dmd.IRState;
+import dmd.ArrayTypes;
+import dmd.HdrGenState;
+import dmd.MOD;
+import dmd.TOK;
+import dmd.WANT;
+import dmd.ClassDeclaration;
+
+import dmd.Optimize;
+import dmd.PREC;
+import dmd.Cast;
+
+import dmd.backend.Util;
+import dmd.expression.Util;
+import dmd.backend.TYM;
+import dmd.backend.OPER;
+import dmd.codegen.Util;
+import dmd.backend.RTLSYM;
+
+class CastExp : UnaExp
+{
+	// Possible to cast to one type while painting to another type
+	Type to;				// type to cast to
+	MOD mod;				// MODxxxxx
+
+	this(Loc loc, Expression e, Type t)
+	{
+		super(loc, TOK.TOKcast, CastExp.sizeof, e);
+		to = t;
+		this.mod = cast(MOD)~0;
+	}
+
+	this(Loc loc, Expression e, MOD mod)
+	{
+		super(loc, TOK.TOKcast, CastExp.sizeof, e);
+		to = null;
+		this.mod = mod;
+	}
+
+	Expression syntaxCopy()
+	{
+		return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy())
+	      : new CastExp(loc, e1.syntaxCopy(), mod);
+	}
+
+	Expression semantic(Scope sc)
+	{
+		Expression e;
+		BinExp b;
+		UnaExp u;
+
+version (LOGSEMANTIC) {
+		printf("CastExp.semantic('%s')\n", toChars());
+}
+
+		//static int x; assert(++x < 10);
+
+		if (type)
+			return this;
+		super.semantic(sc);
+		if (e1.type)		// if not a tuple
+		{
+		e1 = resolveProperties(sc, e1);
+
+		if (!to)
+		{
+			/* Handle cast(const) and cast(immutable), etc.
+			 */
+			to = e1.type.castMod(mod);
+		}
+		else
+			to = to.semantic(loc, sc);
+
+		if (!to.equals(e1.type))
+		{
+			e = op_overload(sc);
+			if (e)
+			{
+			return e.implicitCastTo(sc, to);
+			}
+		}
+
+		Type t1b = e1.type.toBasetype();
+		Type tob = to.toBasetype();
+		if (tob.ty == TY.Tstruct &&
+			!tob.equals(t1b) &&
+			(cast(TypeStruct)tob).sym.search(Loc(0), Id.call, 0)
+		   )
+		{
+			/* Look to replace:
+			 *	cast(S)t
+			 * with:
+			 *	S(t)
+			 */
+
+			// Rewrite as to.call(e1)
+			e = new TypeExp(loc, to);
+			e = new DotIdExp(loc, e, Id.call);
+			e = new CallExp(loc, e, e1);
+			e = e.semantic(sc);
+			return e;
+		}
+		}
+		else if (!to)
+		{	error("cannot cast tuple");
+		to = Type.terror;
+		}
+
+		if (global.params.safe && !sc.module_.safe && !sc.intypeof)
+		{	// Disallow unsafe casts
+			Type tob = to.toBasetype();
+			Type t1b = e1.type.toBasetype();
+			if (!t1b.isMutable() && tob.isMutable())
+			{   // Cast not mutable to mutable
+			  Lunsafe:
+				error("cast from %s to %s not allowed in safe mode", e1.type.toChars(), to.toChars());
+			}
+			else if (t1b.isShared() && !tob.isShared())
+				// Cast away shared
+				goto Lunsafe;
+			else if (tob.ty == TY.Tpointer)
+			{   if (t1b.ty != TY.Tpointer)
+				goto Lunsafe;
+				Type tobn = tob.nextOf().toBasetype();
+				Type t1bn = t1b.nextOf().toBasetype();
+
+				if (!t1bn.isMutable() && tobn.isMutable())
+					// Cast away pointer to not mutable
+					goto Lunsafe;
+
+				if (t1bn.isShared() && !tobn.isShared())
+					// Cast away pointer to shared
+					goto Lunsafe;
+
+				if (tobn.isTypeBasic() && tobn.size() < t1bn.size()) {
+					// Allow things like casting a long* to an int*
+					;
+				} else if (tobn.ty != TY.Tvoid) {
+					// Cast to a pointer other than void*
+					goto Lunsafe;
+				}
+			}
+
+			// BUG: Check for casting array types, such as void[] to int*[]
+		}
+
+		e = e1.castTo(sc, to);
+		return e;
+	}
+
+	MATCH implicitConvTo(Type t)
+	{
+	static if (false) {
+		printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", toChars(), type.toChars(), t.toChars());
+	}
+		MATCH result = type.implicitConvTo(t);
+
+		if (result == MATCHnomatch)
+		{
+			if (t.isintegral() &&
+				e1.type.isintegral() &&
+				e1.implicitConvTo(t) != MATCHnomatch)
+				result = MATCHconvert;
+			else
+				result = Expression.implicitConvTo(t);
+		}
+		return result;
+	}
+
+	IntRange getIntRange()
+	{
+		assert(false);
+	}
+
+	Expression optimize(int result)
+	{
+		//printf("CastExp.optimize(result = %d) %s\n", result, toChars());
+		//printf("from %s to %s\n", type.toChars(), to.toChars());
+		//printf("from %s\n", type.toChars());
+		//printf("e1.type %s\n", e1.type.toChars());
+		//printf("type = %p\n", type);
+		assert(type);
+		TOK op1 = e1.op;
+
+		Expression e1old = e1;
+		e1 = e1.optimize(result);
+		e1 = fromConstInitializer(result, e1);
+
+		if (e1 == e1old &&
+		e1.op == TOK.TOKarrayliteral &&
+		type.toBasetype().ty == TY.Tpointer &&
+		e1.type.toBasetype().ty != TY.Tsarray)
+		{
+		// Casting this will result in the same expression, and
+		// infinite loop because of Expression.implicitCastTo()
+		return this;		// no change
+		}
+
+		if ((e1.op == TOK.TOKstring || e1.op == TOK.TOKarrayliteral) &&
+		(type.ty == TY.Tpointer || type.ty == TY.Tarray) &&
+		e1.type.nextOf().size() == type.nextOf().size()
+		   )
+		{
+		Expression e = e1.castTo(null, type);
+
+static if (false) {
+		printf(" returning1 %s\n", e.toChars());
+}
+		return e;
+		}
+
+		if (e1.op == TOK.TOKstructliteral &&
+		e1.type.implicitConvTo(type) >= MATCH.MATCHconst)
+		{
+		e1.type = type;
+static if (false) {
+		printf(" returning2 %s\n", e1.toChars());
+}
+		return e1;
+		}
+
+		/* The first test here is to prevent infinite loops
+		 */
+		if (op1 != TOK.TOKarrayliteral && e1.op == TOK.TOKarrayliteral)
+		return e1.castTo(null, to);
+		if (e1.op == TOK.TOKnull &&
+		(type.ty == TY.Tpointer || type.ty == TY.Tclass || type.ty == TY.Tarray))
+		{
+		e1.type = type;
+static if (false) {
+		printf(" returning3 %s\n", e1.toChars());
+}
+		return e1;
+		}
+
+		if (result & WANT.WANTflags && type.ty == TY.Tclass && e1.type.ty == TY.Tclass)
+		{
+		// See if we can remove an unnecessary cast
+		ClassDeclaration cdfrom;
+		ClassDeclaration cdto;
+		int offset;
+
+		cdfrom = e1.type.isClassHandle();
+		cdto   = type.isClassHandle();
+		if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
+		{
+			e1.type = type;
+static if (false) {
+			printf(" returning4 %s\n", e1.toChars());
+}
+			return e1;
+		}
+		}
+
+		// We can convert 'head const' to mutable
+		if (to.constOf().equals(e1.type.constOf()))
+	//    if (to.constConv(e1.type) >= MATCHconst)
+		{
+		e1.type = type;
+static if (false) {
+		printf(" returning5 %s\n", e1.toChars());
+}
+		return e1;
+		}
+
+		Expression e;
+
+		if (e1.isConst())
+		{
+		if (e1.op == TOK.TOKsymoff)
+		{
+			if (type.size() == e1.type.size() &&
+			type.toBasetype().ty != TY.Tsarray)
+			{
+			e1.type = type;
+			return e1;
+			}
+			return this;
+		}
+		if (to.toBasetype().ty == TY.Tvoid)
+			e = this;
+		else
+			e = Cast(type, to, e1);
+		}
+		else
+		e = this;
+static if (false) {
+		printf(" returning6 %s\n", e.toChars());
+}
+		return e;
+	}
+
+	Expression interpret(InterState* istate)
+	{
+		assert(false);
+	}
+
+	bool checkSideEffect(int flag)
+	{
+		assert(false);
+	}
+
+	void checkEscape()
+	{
+		Type tb = type.toBasetype();
+		if (tb.ty == TY.Tarray && e1.op == TOK.TOKvar && e1.type.toBasetype().ty ==TY.Tsarray)
+		{	
+			VarExp ve = cast(VarExp)e1;
+			VarDeclaration v = ve.var.isVarDeclaration();
+			if (v)
+			{
+				if (!v.isDataseg() && !v.isParameter())
+					error("escaping reference to local %s", v.toChars());
+			}
+		}
+	}
+
+	void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		buf.writestring("cast(");
+	version (DMDV1) {
+		to.toCBuffer(buf, null, hgs);
+	} else {
+		if (to)
+			to.toCBuffer(buf, null, hgs);
+		else
+		{
+			switch (mod)
+			{   
+				case MODundefined:
+					break;
+				case MODconst:
+					buf.writestring(Token.tochars[TOKconst]);
+					break;
+				case MODinvariant:
+					buf.writestring(Token.tochars[TOKimmutable]);
+					break;
+				case MODshared:
+					buf.writestring(Token.tochars[TOKshared]);
+					break;
+				case MODshared | MODconst:
+					buf.writestring(Token.tochars[TOKshared]);
+					buf.writeByte(' ');
+					buf.writestring(Token.tochars[TOKconst]);
+					break;
+				default:
+					assert(0);
+			}
+		}
+	}
+		buf.writeByte(')');
+		expToCBuffer(buf, hgs, e1, precedence[op]);
+	}
+
+	void buildArrayIdent(OutBuffer buf, Expressions arguments)
+	{
+		assert(false);
+	}
+
+	Expression buildArrayLoop(Arguments fparams)
+	{
+		assert(false);
+	}
+	
+	static int X(int fty, int tty) {
+		return ((fty) * TY.TMAX + (tty));
+	}
+
+	elem* toElem(IRState* irs)
+	{
+		elem* e;
+		TY fty;
+		TY tty;
+		tym_t ftym;
+		tym_t ttym;
+		OPER eop;
+		Type t;
+		Type tfrom;
+
+static if (false) {
+		printf("CastExp::toElem()\n");
+		print();
+		printf("\tfrom: %s\n", e1.type.toChars());
+		printf("\tto  : %s\n", to.toChars());
+}
+
+		e = e1.toElem(irs);
+		tfrom = e1.type.toBasetype();
+		t = to.toBasetype();		// skip over typedef's
+		if (t.equals(tfrom))
+			goto Lret;
+
+		fty = tfrom.ty;
+		//printf("fty = %d\n", fty);
+		tty = t.ty;
+
+		if (tty == TY.Tpointer && fty == TY.Tarray
+///static if (false) {
+///		&& (t.next.ty == Tvoid || t.next.equals(e1.type.next))
+///}
+		   )
+		{
+			if (e.Eoper == OPER.OPvar)
+			{
+				// e1 . *(&e1 + 4)
+				e = el_una(OPER.OPaddr, TYM.TYnptr, e);
+				e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, 4));
+				e = el_una(OPER.OPind, t.totym(),e);
+			}
+			else
+			{
+				// e1 . (unsigned)(e1 >> 32)
+				e = el_bin(OPER.OPshr, TYM.TYullong, e, el_long(TYM.TYint, 32));
+				e = el_una(OPER.OP64_32, t.totym(), e);
+			}
+			goto Lret;
+		}
+
+		if (tty == TY.Tpointer && fty == TY.Tsarray
+///static if (false) {
+///		&& (t.next.ty == Tvoid || t.next.equals(e1.type.next))
+///}
+		)
+		{
+			// e1 . &e1
+			e = el_una(OPER.OPaddr, TYM.TYnptr, e);
+			goto Lret;
+		}
+
+		// Convert from static array to dynamic array
+		if (tty == TY.Tarray && fty == TY.Tsarray)
+		{
+			e = sarray_toDarray(loc, tfrom, t, e);
+			goto Lret;
+		}
+
+		// Convert from dynamic array to dynamic array
+		if (tty == TY.Tarray && fty == TY.Tarray)
+		{
+			uint fsize = cast(uint)tfrom.nextOf().size();
+			uint tsize = cast(uint)t.nextOf().size();
+
+			if (fsize != tsize)
+			{
+				elem* ep = el_params(e, el_long(TYM.TYint, fsize), el_long(TYM.TYint, tsize), null);
+				e = el_bin(OPER.OPcall, type.totym(), el_var(rtlsym[RTLSYM.RTLSYM_ARRAYCAST]), ep);
+			}
+			goto Lret;
+		}
+
+static if (false) {
+		// Convert from dynamic array string literal to static array
+		if (tty == TY.Tsarray && fty == TY.Tarray && e1.op == TOK.TOKstring)
+		{
+			goto Lret;	// treat as a 'paint'
+		}
+}
+
+		// Casting from base class to derived class requires a runtime check
+		if (fty == TY.Tclass && tty == TY.Tclass)
+		{
+			// Casting from derived class to base class is a no-op
+			ClassDeclaration cdfrom;
+			ClassDeclaration cdto;
+			int offset;
+			int rtl = RTLSYM.RTLSYM_DYNAMIC_CAST;
+
+			cdfrom = tfrom.isClassHandle();
+			cdto   = t.isClassHandle();
+			if (cdfrom.isInterfaceDeclaration())
+			{
+				rtl = RTLSYM.RTLSYM_INTERFACE_CAST;
+				if (cdfrom.isCPPinterface())
+				{
+					if (cdto.isCPPinterface())
+					{
+						/* Casting from a C++ interface to a C++ interface
+						 * is always a 'paint' operation
+						 */
+						goto Lret;			// no-op
+					}
+
+					/* Casting from a C++ interface to a class
+					 * always results in null because there is no runtime
+					 * information available to do it.
+					 *
+					 * Casting from a C++ interface to a non-C++ interface
+					 * always results in null because there's no way one
+					 * can be derived from the other.
+					 */
+					e = el_bin(OPER.OPcomma, TYM.TYnptr, e, el_long(TYM.TYnptr, 0));
+					goto Lret;
+				}
+			}
+			if (cdto.isBaseOf(cdfrom, &offset) && offset != OFFSET_RUNTIME)
+			{
+				/* The offset from cdfrom=>cdto is known at compile time.
+				 */
+			
+				//printf("offset = %d\n", offset);
+				if (offset)
+				{
+					/* Rewrite cast as (e ? e + offset : null)
+					 */
+					elem* etmp;
+					elem* ex;
+
+					if (e1.op == TOK.TOKthis)
+					{   
+						// Assume 'this' is never null, so skip null check
+						e = el_bin(OPER.OPadd, TYM.TYnptr, e, el_long(TYM.TYint, offset));
+					}
+					else
+					{
+						etmp = el_same(&e);
+						ex = el_bin(OPER.OPadd, TYM.TYnptr, etmp, el_long(TYM.TYint, offset));
+						ex = el_bin(OPER.OPcolon, TYM.TYnptr, ex, el_long(TYM.TYnptr, 0));
+						e = el_bin(OPER.OPcond, TYM.TYnptr, e, ex);
+					}
+				}
+				goto Lret;			// no-op
+			}
+
+			/* The offset from cdfrom=>cdto can only be determined at runtime.
+			 */
+			elem* ep;
+
+			ep = el_param(el_ptr(cdto.toSymbol()), e);
+			e = el_bin(OPER.OPcall, TYM.TYnptr, el_var(rtlsym[rtl]), ep);
+			goto Lret;
+		}
+
+		ftym = e.Ety;
+		ttym = t.totym();
+		if (ftym == ttym)
+		goto Lret;
+
+		switch (tty)
+		{
+			case TY.Tpointer:
+				if (fty == TY.Tdelegate)
+					goto Lpaint;
+				tty = TY.Tuns32;
+				break;
+
+			case TY.Tchar:
+				tty = TY.Tuns8;	
+				break;
+			case TY.Twchar:
+				tty = TY.Tuns16;	
+				break;
+			case TY.Tdchar:	
+				tty = TY.Tuns32;	
+				break;
+			case TY.Tvoid:	
+				goto Lpaint;
+
+			case TY.Tbool:
+			{
+				// Construct e?true:false
+				elem* eq;
+
+				e = el_una(OPER.OPbool, ttym, e);
+				goto Lret;
+			}
+			
+			default:
+				break;	///
+		}
+
+		switch (fty)
+		{
+			case TY.Tpointer:	fty = TY.Tuns32;	break;
+			case TY.Tchar:		fty = TY.Tuns8;		break;
+			case TY.Twchar:		fty = TY.Tuns16;	break;
+			case TY.Tdchar:		fty = TY.Tuns32;	break;
+			default:	break;	///
+		}
+
+	Lagain:
+		switch (X(fty,tty))
+		{
+static if (false) {
+			case X(TY.Tbit,TY.Tint8):
+			case X(TY.Tbit,TY.Tuns8):
+				goto Lpaint;
+			case X(TY.Tbit,TY.Tint16):
+			case X(TY.Tbit,TY.Tuns16):
+			case X(TY.Tbit,TY.Tint32):
+			case X(TY.Tbit,TY.Tuns32):	
+				eop = OPu8_16;
+				goto Leop;
+			case X(TY.Tbit,TY.Tint64):
+			case X(TY.Tbit,TY.Tuns64):
+			case X(TY.Tbit,TY.Tfloat32):
+			case X(TY.Tbit,TY.Tfloat64):
+			case X(TY.Tbit,TY.Tfloat80):
+			case X(TY.Tbit,TY.Tcomplex32):
+			case X(TY.Tbit,TY.Tcomplex64):
+			case X(TY.Tbit,TY.Tcomplex80):
+				e = el_una(OPER.OPu8_16, TYM.TYuint, e);
+				fty = TY.Tuns32;
+				goto Lagain;
+			case X(Tbit,Timaginary32):
+			case X(Tbit,Timaginary64):
+			case X(Tbit,Timaginary80):
+				goto Lzero;
+}
+		/* ============================= */
+
+		case X(TY.Tbool,TY.Tint8):
+		case X(TY.Tbool,TY.Tuns8):
+			goto Lpaint;
+		case X(TY.Tbool,TY.Tint16):
+		case X(TY.Tbool,TY.Tuns16):
+		case X(TY.Tbool,TY.Tint32):
+		case X(TY.Tbool,TY.Tuns32):
+			eop = OPER.OPu8_16;
+			goto Leop;
+		case X(TY.Tbool,TY.Tint64):
+		case X(TY.Tbool,TY.Tuns64):
+		case X(TY.Tbool,TY.Tfloat32):
+		case X(TY.Tbool,TY.Tfloat64):
+		case X(TY.Tbool,TY.Tfloat80):
+		case X(TY.Tbool,TY.Tcomplex32):
+		case X(TY.Tbool,TY.Tcomplex64):
+		case X(TY.Tbool,TY.Tcomplex80):
+			e = el_una(OPER.OPu8_16, TYM.TYuint, e);
+			fty = TY.Tuns32;
+			goto Lagain;
+		case X(TY.Tbool,TY.Timaginary32):
+		case X(TY.Tbool,TY.Timaginary64):
+		case X(TY.Tbool,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tint8,TY.Tuns8):
+			goto Lpaint;
+		case X(TY.Tint8,TY.Tint16):
+		case X(TY.Tint8,TY.Tuns16):
+		case X(TY.Tint8,TY.Tint32):
+		case X(TY.Tint8,TY.Tuns32):
+			eop = OPER.OPs8_16;
+			goto Leop;
+		case X(TY.Tint8,TY.Tint64):
+		case X(TY.Tint8,TY.Tuns64):
+		case X(TY.Tint8,TY.Tfloat32):
+		case X(TY.Tint8,TY.Tfloat64):
+		case X(TY.Tint8,TY.Tfloat80):
+		case X(TY.Tint8,TY.Tcomplex32):
+		case X(TY.Tint8,TY.Tcomplex64):
+		case X(TY.Tint8,TY.Tcomplex80):
+			e = el_una(OPER.OPs8_16, TYM.TYint, e);
+			fty = TY.Tint32;
+			goto Lagain;
+		case X(TY.Tint8,TY.Timaginary32):
+		case X(TY.Tint8,TY.Timaginary64):
+		case X(TY.Tint8,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tuns8,TY.Tint8):
+			goto Lpaint;
+		case X(TY.Tuns8,TY.Tint16):
+		case X(TY.Tuns8,TY.Tuns16):
+		case X(TY.Tuns8,TY.Tint32):
+		case X(TY.Tuns8,TY.Tuns32):
+			eop = OPER.OPu8_16;
+			goto Leop;
+		case X(TY.Tuns8,TY.Tint64):
+		case X(TY.Tuns8,TY.Tuns64):
+		case X(TY.Tuns8,TY.Tfloat32):
+		case X(TY.Tuns8,TY.Tfloat64):
+		case X(TY.Tuns8,TY.Tfloat80):
+		case X(TY.Tuns8,TY.Tcomplex32):
+		case X(TY.Tuns8,TY.Tcomplex64):
+		case X(TY.Tuns8,TY.Tcomplex80):
+			e = el_una(OPER.OPu8_16, TYM.TYuint, e);
+			fty = TY.Tuns32;
+			goto Lagain;
+		case X(TY.Tuns8,TY.Timaginary32):
+		case X(TY.Tuns8,TY.Timaginary64):
+		case X(TY.Tuns8,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tint16,TY.Tint8):
+		case X(TY.Tint16,TY.Tuns8):
+			eop = OPER.OP16_8;
+			goto Leop;
+		case X(TY.Tint16,TY.Tuns16):
+			goto Lpaint;
+		case X(TY.Tint16,TY.Tint32):
+		case X(TY.Tint16,TY.Tuns32):
+			eop = OPER.OPs16_32;
+			goto Leop;
+		case X(TY.Tint16,TY.Tint64):
+		case X(TY.Tint16,TY.Tuns64):
+			e = el_una(OPER.OPs16_32, TYM.TYint, e);
+			fty = TY.Tint32;
+			goto Lagain;
+		case X(TY.Tint16,TY.Tfloat32):
+		case X(TY.Tint16,TY.Tfloat64):
+		case X(TY.Tint16,TY.Tfloat80):
+		case X(TY.Tint16,TY.Tcomplex32):
+		case X(TY.Tint16,TY.Tcomplex64):
+		case X(TY.Tint16,TY.Tcomplex80):
+			e = el_una(OPER.OPs16_d, TYM.TYdouble, e);
+			fty = TY.Tfloat64;
+			goto Lagain;
+		case X(TY.Tint16,TY.Timaginary32):
+		case X(TY.Tint16,TY.Timaginary64):
+		case X(TY.Tint16,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tuns16,TY.Tint8):
+		case X(TY.Tuns16,TY.Tuns8):
+			eop = OPER.OP16_8;
+			goto Leop;
+		case X(TY.Tuns16,TY.Tint16):
+			goto Lpaint;
+		case X(TY.Tuns16,TY.Tint32):
+		case X(TY.Tuns16,TY.Tuns32):
+			eop = OPER.OPu16_32;
+			goto Leop;
+		case X(TY.Tuns16,TY.Tint64):
+		case X(TY.Tuns16,TY.Tuns64):
+		case X(TY.Tuns16,TY.Tfloat64):
+		case X(TY.Tuns16,TY.Tfloat32):
+		case X(TY.Tuns16,TY.Tfloat80):
+		case X(TY.Tuns16,TY.Tcomplex32):
+		case X(TY.Tuns16,TY.Tcomplex64):
+		case X(TY.Tuns16,TY.Tcomplex80):
+			e = el_una(OPER.OPu16_32, TYM.TYuint, e);
+			fty = TY.Tuns32;
+			goto Lagain;
+		case X(TY.Tuns16,TY.Timaginary32):
+		case X(TY.Tuns16,TY.Timaginary64):
+		case X(TY.Tuns16,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tint32,TY.Tint8):
+		case X(TY.Tint32,TY.Tuns8):	
+			e = el_una(OPER.OP32_16, TYM.TYshort, e);
+			fty = TY.Tint16;
+			goto Lagain;
+		case X(TY.Tint32,TY.Tint16):
+		case X(TY.Tint32,TY.Tuns16):
+			eop = OPER.OP32_16;
+			goto Leop;
+		case X(TY.Tint32,TY.Tuns32):
+			goto Lpaint;
+		case X(TY.Tint32,TY.Tint64):
+		case X(TY.Tint32,TY.Tuns64):
+			eop = OPER.OPs32_64;
+			goto Leop;
+		case X(TY.Tint32,TY.Tfloat32):
+		case X(TY.Tint32,TY.Tfloat64):
+		case X(TY.Tint32,TY.Tfloat80):
+		case X(TY.Tint32,TY.Tcomplex32):
+		case X(TY.Tint32,TY.Tcomplex64):
+		case X(TY.Tint32,TY.Tcomplex80):
+			e = el_una(OPER.OPs32_d, TYM.TYdouble, e);
+			fty = TY.Tfloat64;
+			goto Lagain;
+		case X(TY.Tint32,TY.Timaginary32):
+		case X(TY.Tint32,TY.Timaginary64):
+		case X(TY.Tint32,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tuns32,TY.Tint8):
+		case X(TY.Tuns32,TY.Tuns8):
+			e = el_una(OPER.OP32_16, TYM.TYshort, e);
+			fty = TY.Tuns16;
+			goto Lagain;
+		case X(TY.Tuns32,TY.Tint16):
+		case X(TY.Tuns32,TY.Tuns16):
+			eop = OPER.OP32_16;
+			goto Leop;
+		case X(TY.Tuns32,TY.Tint32):
+			goto Lpaint;
+		case X(TY.Tuns32,TY.Tint64):
+		case X(TY.Tuns32,TY.Tuns64):
+			eop = OPER.OPu32_64;
+			goto Leop;
+		case X(TY.Tuns32,TY.Tfloat32):
+		case X(TY.Tuns32,TY.Tfloat64):
+		case X(TY.Tuns32,TY.Tfloat80):
+		case X(TY.Tuns32,TY.Tcomplex32):
+		case X(TY.Tuns32,TY.Tcomplex64):
+		case X(TY.Tuns32,TY.Tcomplex80):
+			e = el_una(OPER.OPu32_d, TYM.TYdouble, e);
+			fty = TY.Tfloat64;
+			goto Lagain;
+		case X(TY.Tuns32,TY.Timaginary32):
+		case X(TY.Tuns32,TY.Timaginary64):
+		case X(TY.Tuns32,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tint64,TY.Tint8):
+		case X(TY.Tint64,TY.Tuns8):
+		case X(TY.Tint64,TY.Tint16):
+		case X(TY.Tint64,TY.Tuns16):
+			e = el_una(OPER.OP64_32, TYM.TYint, e);
+			fty = TY.Tint32;
+			goto Lagain;
+		case X(TY.Tint64,TY.Tint32):
+		case X(TY.Tint64,TY.Tuns32):
+			eop = OPER.OP64_32;
+			goto Leop;
+		case X(TY.Tint64,TY.Tuns64):
+			goto Lpaint;
+		case X(TY.Tint64,TY.Tfloat32):
+		case X(TY.Tint64,TY.Tfloat64):
+		case X(TY.Tint64,TY.Tfloat80):
+		case X(TY.Tint64,TY.Tcomplex32):
+		case X(TY.Tint64,TY.Tcomplex64):
+		case X(TY.Tint64,TY.Tcomplex80):
+			e = el_una(OPER.OPs64_d, TYM.TYdouble, e);
+			fty = TY.Tfloat64;
+			goto Lagain;
+		case X(TY.Tint64,TY.Timaginary32):
+		case X(TY.Tint64,TY.Timaginary64):
+		case X(TY.Tint64,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tuns64,TY.Tint8):
+		case X(TY.Tuns64,TY.Tuns8):
+		case X(TY.Tuns64,TY.Tint16):
+		case X(TY.Tuns64,TY.Tuns16):
+			e = el_una(OPER.OP64_32, TYM.TYint, e);
+			fty = TY.Tint32;
+			goto Lagain;
+		case X(TY.Tuns64,TY.Tint32):
+		case X(TY.Tuns64,TY.Tuns32):
+			eop = OPER.OP64_32;
+			goto Leop;
+		case X(TY.Tuns64,TY.Tint64):
+			goto Lpaint;
+		case X(TY.Tuns64,TY.Tfloat32):
+		case X(TY.Tuns64,TY.Tfloat64):
+		case X(TY.Tuns64,TY.Tfloat80):
+		case X(TY.Tuns64,TY.Tcomplex32):
+		case X(TY.Tuns64,TY.Tcomplex64):
+		case X(TY.Tuns64,TY.Tcomplex80):
+			 e = el_una(OPER.OPu64_d, TYM.TYdouble, e);
+			 fty = TY.Tfloat64;
+			 goto Lagain;
+		case X(TY.Tuns64,TY.Timaginary32):
+		case X(TY.Tuns64,TY.Timaginary64):
+		case X(TY.Tuns64,TY.Timaginary80):
+			goto Lzero;
+
+		/* ============================= */
+
+		case X(TY.Tfloat32,TY.Tint8):
+		case X(TY.Tfloat32,TY.Tuns8):
+		case X(TY.Tfloat32,TY.Tint16):
+		case X(TY.Tfloat32,TY.Tuns16):
+		case X(TY.Tfloat32,TY.Tint32):
+		case X(TY.Tfloat32,TY.Tuns32):
+		case X(TY.Tfloat32,TY.Tint64):
+		case X(TY.Tfloat32,TY.Tuns64):
+		case X(TY.Tfloat32,TY.Tfloat80):
+			e = el_una(OPER.OPf_d, TYM.TYdouble, e);
+			fty = TY.Tfloat64;
+			goto Lagain;
+		case X(TY.Tfloat32,TY.Tfloat64):
+			eop = OPER.OPf_d;
+			goto Leop;
+		case X(TY.Tfloat32,TY.Timaginary32):
+			goto Lzero;
+		case X(TY.Tfloat32,TY.Timaginary64):
+			goto Lzero;
+		case X(TY.Tfloat32,TY.Timaginary80):
+			goto Lzero;
+		case X(TY.Tfloat32,TY.Tcomplex32):
+		case X(TY.Tfloat32,TY.Tcomplex64):
+		case X(TY.Tfloat32,TY.Tcomplex80):
+			e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYifloat,0),e);
+			fty = TY.Tcomplex32;
+			goto Lagain;
+
+		/* ============================= */
+
+		case X(TY.Tfloat64,TY.Tint8):
+		case X(TY.Tfloat64,TY.Tuns8):
+			e = el_una(OPER.OPd_s16, TYM.TYshort, e);
+			fty = TY.Tint16;
+			goto Lagain;
+		case X(TY.Tfloat64,TY.Tint16):  
+			eop = OPER.OPd_s16;
+			goto Leop;
+		case X(TY.Tfloat64,TY.Tuns16):  
+			eop = OPER.OPd_u16;
+			goto Leop;
+		case X(TY.Tfloat64,TY.Tint32):   
+			eop = OPER.OPd_s32; 
+			goto Leop;
+		case X(TY.Tfloat64,TY.Tuns32):   
+			eop = OPER.OPd_u32; 
+			goto Leop;
+		case X(TY.Tfloat64,TY.Tint64):   
+			eop = OPER.OPd_s64; 
+			goto Leop;
+		case X(TY.Tfloat64,TY.Tuns64):   
+			eop = OPER.OPd_u64; 
+			goto Leop;
+		case X(TY.Tfloat64,TY.Tfloat32): 
+			eop = OPER.OPd_f;   
+			goto Leop;
+		case X(TY.Tfloat64,TY.Tfloat80): 
+			eop = OPER.OPd_ld;  
+			goto Leop;
+		case X(TY.Tfloat64,TY.Timaginary32):	
+			goto Lzero;
+		case X(TY.Tfloat64,TY.Timaginary64):	
+			goto Lzero;
+		case X(TY.Tfloat64,TY.Timaginary80):	
+			goto Lzero;
+		case X(TY.Tfloat64,TY.Tcomplex32):
+		case X(TY.Tfloat64,TY.Tcomplex64):
+		case X(TY.Tfloat64,TY.Tcomplex80):
+			e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYidouble,0),e);
+			fty = TY.Tcomplex64;
+			goto Lagain;
+
+		/* ============================= */
+
+		case X(TY.Tfloat80,TY.Tint8):
+		case X(TY.Tfloat80,TY.Tuns8):
+		case X(TY.Tfloat80,TY.Tint16):
+		case X(TY.Tfloat80,TY.Tuns16):
+		case X(TY.Tfloat80,TY.Tint32):
+		case X(TY.Tfloat80,TY.Tuns32):
+		case X(TY.Tfloat80,TY.Tint64):
+		case X(TY.Tfloat80,TY.Tfloat32):
+			e = el_una(OPER.OPld_d, TYM.TYdouble, e);
+			fty = TY.Tfloat64;
+			goto Lagain;
+		case X(TY.Tfloat80,TY.Tuns64):
+			eop = OPER.OPld_u64;
+			goto Leop;
+		case X(TY.Tfloat80,TY.Tfloat64):
+			eop = OPER.OPld_d;
+			goto Leop;
+		case X(TY.Tfloat80,TY.Timaginary32):
+			goto Lzero;
+		case X(TY.Tfloat80,TY.Timaginary64):
+			goto Lzero;
+		case X(TY.Tfloat80,TY.Timaginary80):
+			goto Lzero;
+		case X(TY.Tfloat80,TY.Tcomplex32):
+		case X(TY.Tfloat80,TY.Tcomplex64):
+		case X(TY.Tfloat80,TY.Tcomplex80):
+			e = el_bin(OPER.OPadd,TYM.TYcldouble,e,el_long(TYM.TYildouble,0));
+			fty = TY.Tcomplex80;
+			goto Lagain;
+
+		/* ============================= */
+
+		case X(TY.Timaginary32,TY.Tint8):
+		case X(TY.Timaginary32,TY.Tuns8):
+		case X(TY.Timaginary32,TY.Tint16):
+		case X(TY.Timaginary32,TY.Tuns16):
+		case X(TY.Timaginary32,TY.Tint32):
+		case X(TY.Timaginary32,TY.Tuns32):
+		case X(TY.Timaginary32,TY.Tint64):
+		case X(TY.Timaginary32,TY.Tuns64):
+		case X(TY.Timaginary32,TY.Tfloat32):
+		case X(TY.Timaginary32,TY.Tfloat64):
+		case X(TY.Timaginary32,TY.Tfloat80):
+			goto Lzero;
+		case X(TY.Timaginary32,TY.Timaginary64):
+			eop = OPER.OPf_d;
+			goto Leop;
+		case X(TY.Timaginary32,TY.Timaginary80):
+			e = el_una(OPER.OPf_d, TYM.TYidouble, e);
+			fty = TY.Timaginary64;
+			goto Lagain;
+		case X(TY.Timaginary32,TY.Tcomplex32):
+		case X(TY.Timaginary32,TY.Tcomplex64):
+		case X(TY.Timaginary32,TY.Tcomplex80):
+			e = el_bin(OPER.OPadd,TYM.TYcfloat,el_long(TYM.TYfloat,0),e);
+			fty = TY.Tcomplex32;
+			goto Lagain;
+
+		/* ============================= */
+
+		case X(TY.Timaginary64,TY.Tint8):
+		case X(TY.Timaginary64,TY.Tuns8):
+		case X(TY.Timaginary64,TY.Tint16):
+		case X(TY.Timaginary64,TY.Tuns16):
+		case X(TY.Timaginary64,TY.Tint32):
+		case X(TY.Timaginary64,TY.Tuns32):
+		case X(TY.Timaginary64,TY.Tint64):
+		case X(TY.Timaginary64,TY.Tuns64):
+		case X(TY.Timaginary64,TY.Tfloat32):
+		case X(TY.Timaginary64,TY.Tfloat64):
+		case X(TY.Timaginary64,TY.Tfloat80):
+			goto Lzero;
+		case X(TY.Timaginary64,TY.Timaginary32):
+			eop = OPER.OPd_f;  
+			goto Leop;
+		case X(TY.Timaginary64,TY.Timaginary80):
+			eop = OPER.OPd_ld; 
+			goto Leop;
+		case X(TY.Timaginary64,TY.Tcomplex32):
+		case X(TY.Timaginary64,TY.Tcomplex64):
+		case X(TY.Timaginary64,TY.Tcomplex80):
+			e = el_bin(OPER.OPadd, TYM.TYcdouble, el_long(TYM.TYdouble,0), e);
+			fty = TY.Tcomplex64;
+			goto Lagain;
+
+		/* ============================= */
+
+		case X(TY.Timaginary80,TY.Tint8):
+		case X(TY.Timaginary80,TY.Tuns8):
+		case X(TY.Timaginary80,TY.Tint16):
+		case X(TY.Timaginary80,TY.Tuns16):
+		case X(TY.Timaginary80,TY.Tint32):
+		case X(TY.Timaginary80,TY.Tuns32):
+		case X(TY.Timaginary80,TY.Tint64):
+		case X(TY.Timaginary80,TY.Tuns64):
+		case X(TY.Timaginary80,TY.Tfloat32):
+		case X(TY.Timaginary80,TY.Tfloat64):
+		case X(TY.Timaginary80,TY.Tfloat80):
+			goto Lzero;
+		case X(TY.Timaginary80,TY.Timaginary32):
+			e = el_una(OPER.OPf_d, TYM.TYidouble, e);
+			fty = TY.Timaginary64;
+			goto Lagain;
+		case X(TY.Timaginary80,TY.Timaginary64):
+			eop = OPER.OPld_d;
+			goto Leop;
+		case X(TY.Timaginary80,TY.Tcomplex32):
+		case X(TY.Timaginary80,TY.Tcomplex64):
+		case X(TY.Timaginary80,TY.Tcomplex80):
+			e = el_bin(OPER.OPadd, TYM.TYcldouble, el_long(TYM.TYldouble,0), e);
+			fty = TY.Tcomplex80;
+			goto Lagain;
+
+		/* ============================= */
+
+		case X(TY.Tcomplex32,TY.Tint8):
+		case X(TY.Tcomplex32,TY.Tuns8):
+		case X(TY.Tcomplex32,TY.Tint16):
+		case X(TY.Tcomplex32,TY.Tuns16):
+		case X(TY.Tcomplex32,TY.Tint32):
+		case X(TY.Tcomplex32,TY.Tuns32):
+		case X(TY.Tcomplex32,TY.Tint64):
+		case X(TY.Tcomplex32,TY.Tuns64):
+		case X(TY.Tcomplex32,TY.Tfloat32):
+		case X(TY.Tcomplex32,TY.Tfloat64):
+		case X(TY.Tcomplex32,TY.Tfloat80):
+			e = el_una(OPER.OPc_r, TYM.TYfloat, e);
+			fty = TY.Tfloat32;
+			goto Lagain;
+		case X(TY.Tcomplex32,TY.Timaginary32):
+		case X(TY.Tcomplex32,TY.Timaginary64):
+		case X(TY.Tcomplex32,TY.Timaginary80):
+			e = el_una(OPER.OPc_i, TYM.TYifloat, e);
+			fty = TY.Timaginary32;
+			goto Lagain;
+		case X(TY.Tcomplex32,TY.Tcomplex64):
+		case X(TY.Tcomplex32,TY.Tcomplex80):
+			e = el_una(OPER.OPf_d, TYM.TYcdouble, e);
+			fty = TY.Tcomplex64;
+			goto Lagain;
+
+		/* ============================= */
+
+		case X(TY.Tcomplex64,TY.Tint8):
+		case X(TY.Tcomplex64,TY.Tuns8):
+		case X(TY.Tcomplex64,TY.Tint16):
+		case X(TY.Tcomplex64,TY.Tuns16):
+		case X(TY.Tcomplex64,TY.Tint32):
+		case X(TY.Tcomplex64,TY.Tuns32):
+		case X(TY.Tcomplex64,TY.Tint64):
+		case X(TY.Tcomplex64,TY.Tuns64):
+		case X(TY.Tcomplex64,TY.Tfloat32):
+		case X(TY.Tcomplex64,TY.Tfloat64):
+		case X(TY.Tcomplex64,TY.Tfloat80):
+			e = el_una(OPER.OPc_r, TYM.TYdouble, e);
+			fty = TY.Tfloat64;
+			goto Lagain;
+		case X(TY.Tcomplex64,TY.Timaginary32):
+		case X(TY.Tcomplex64,TY.Timaginary64):
+		case X(TY.Tcomplex64,TY.Timaginary80):
+			e = el_una(OPER.OPc_i, TYM.TYidouble, e);
+			fty = TY.Timaginary64;
+			goto Lagain;
+		case X(TY.Tcomplex64,TY.Tcomplex32):
+			eop = OPER.OPd_f;
+			goto Leop;
+		case X(TY.Tcomplex64,TY.Tcomplex80):
+			eop = OPER.OPd_ld;
+			goto Leop;
+
+		/* ============================= */
+
+		case X(TY.Tcomplex80,TY.Tint8):
+		case X(TY.Tcomplex80,TY.Tuns8):
+		case X(TY.Tcomplex80,TY.Tint16):
+		case X(TY.Tcomplex80,TY.Tuns16):
+		case X(TY.Tcomplex80,TY.Tint32):
+		case X(TY.Tcomplex80,TY.Tuns32):
+		case X(TY.Tcomplex80,TY.Tint64):
+		case X(TY.Tcomplex80,TY.Tuns64):
+		case X(TY.Tcomplex80,TY.Tfloat32):
+		case X(TY.Tcomplex80,TY.Tfloat64):
+		case X(TY.Tcomplex80,TY.Tfloat80):
+			e = el_una(OPER.OPc_r, TYM.TYldouble, e);
+			fty = TY.Tfloat80;
+			goto Lagain;
+		case X(TY.Tcomplex80,TY.Timaginary32):
+		case X(TY.Tcomplex80,TY.Timaginary64):
+		case X(TY.Tcomplex80,TY.Timaginary80):
+			e = el_una(OPER.OPc_i, TYM.TYildouble, e);
+			fty = TY.Timaginary80;
+			goto Lagain;
+		case X(TY.Tcomplex80,TY.Tcomplex32):
+		case X(TY.Tcomplex80,TY.Tcomplex64):
+			e = el_una(OPER.OPld_d, TYM.TYcdouble, e);
+			fty = TY.Tcomplex64;
+			goto Lagain;
+
+		/* ============================= */
+
+		default:
+			if (fty == tty)
+				goto Lpaint;
+			//dump(0);
+			//printf("fty = %d, tty = %d\n", fty, tty);
+			error("e2ir: cannot cast from %s to %s", e1.type.toChars(), t.toChars());
+			goto Lzero;
+
+		Lzero:
+			e = el_long(ttym, 0);
+			break;
+
+		Lpaint:
+			e.Ety = ttym;
+			break;
+
+		Leop:
+			e = el_una(eop, ttym, e);
+			break;
+		}
+	Lret:
+		// Adjust for any type paints
+		t = type.toBasetype();
+		e.Ety = t.totym();
+
+		el_setLoc(e,loc);
+		return e;
+	}
+
+	Identifier opId()
+	{
+		return Id.cast_;
+	}
+}
+