view dmd/StructLiteralExp.d @ 67:f708f0452e81

some of the backend/codegen stuff implemented
author korDen
date Mon, 23 Aug 2010 21:21:05 +0400
parents 4290d870944a
children 2e2a5c3f943a
line wrap: on
line source

module dmd.StructLiteralExp;

import dmd.Expression;
import dmd.MOD;
import dmd.TypeStruct;
import dmd.TypeSArray;
import dmd.expression.Util;
import dmd.ErrorExp;
import dmd.Dsymbol;
import dmd.VarDeclaration;
import dmd.StructDeclaration;
import dmd.FuncDeclaration;
import dmd.ThisDeclaration;
import dmd.backend.elem;
import dmd.InterState;
import dmd.MATCH;
import dmd.WANT;
import dmd.TY;
import dmd.Type;
import dmd.OutBuffer;
import dmd.Loc;
import dmd.Scope;
import dmd.InlineCostState;
import dmd.IRState;
import dmd.InlineDoState;
import dmd.backend.Symbol;
import dmd.HdrGenState;
import dmd.backend.dt_t;
import dmd.InlineScanState;
import dmd.ArrayTypes;
import dmd.TOK;

import dmd.codegen.Util;
import dmd.backend.Util;
import dmd.backend.RTLSYM;
import dmd.backend.TYM;
import dmd.backend.mTY;
import dmd.backend.OPER;


class StructLiteralExp : Expression
{
	StructDeclaration sd;		// which aggregate this is for
    Expressions elements;	// parallels sd->fields[] with
				// NULL entries for fields to skip

    Symbol* sym;		// back end symbol to initialize with literal
    size_t soffset;		// offset from start of s
    int fillHoles;		// fill alignment 'holes' with zero

	this(Loc loc, StructDeclaration sd, Expressions elements)
	{
		super(loc, TOKstructliteral, StructLiteralExp.sizeof);
		this.sd = sd;
		this.elements = elements;
		this.sym = null;
		this.soffset = 0;
		this.fillHoles = 1;
	}

	Expression syntaxCopy()
	{
		assert(false);
	}

	Expression semantic(Scope sc)
	{
		Expression e;
		int nfields = sd.fields.dim - sd.isnested;

version (LOGSEMANTIC) {
		printf("StructLiteralExp.semantic('%s')\n", toChars());
}
		if (type)
			return this;

		// Run semantic() on each element
		for (size_t i = 0; i < elements.dim; i++)
		{	
			e = cast(Expression)elements.data[i];
			if (!e)
				continue;
			e = e.semantic(sc);
			elements.data[i] = cast(void*)e;
		}
		expandTuples(elements);
		size_t offset = 0;
		for (size_t i = 0; i < elements.dim; i++)
		{	
			e = cast(Expression)elements.data[i];
			if (!e)
				continue;

			if (!e.type)
				error("%s has no value", e.toChars());
			e = resolveProperties(sc, e);
			if (i >= nfields)
			{   
				error("more initializers than fields of %s", sd.toChars());
				return new ErrorExp();
			}
			Dsymbol s = cast(Dsymbol)sd.fields.data[i];
			VarDeclaration v = s.isVarDeclaration();
			assert(v);
			if (v.offset < offset)
				error("overlapping initialization for %s", v.toChars());
			offset = v.offset + cast(uint)v.type.size();

			Type telem = v.type;
			while (!e.implicitConvTo(telem) && telem.toBasetype().ty == Tsarray)
			{   
				/* Static array initialization, as in:
				 *	T[3][5] = e;
				 */
				telem = telem.toBasetype().nextOf();
			}

			e = e.implicitCastTo(sc, telem);

			elements.data[i] = cast(void*)e;
		}

		/* Fill out remainder of elements[] with default initializers for fields[]
		 */
		for (size_t i = elements.dim; i < nfields; i++)
		{	
			Dsymbol s = cast(Dsymbol)sd.fields.data[i];
			VarDeclaration v = s.isVarDeclaration();
			assert(v);
			assert(!v.isThisDeclaration());

			if (v.offset < offset)
			{   
				e = null;
				sd.hasUnions = 1;
			}
			else
			{
				if (v.init)
				{   
					e = v.init.toExpression();
					if (!e)
						error("cannot make expression out of initializer for %s", v.toChars());
				}
				else
				{	
					e = v.type.defaultInit(Loc(0));
					e.loc = loc;
				}
				offset = v.offset + cast(uint)v.type.size();
			}
			elements.push(cast(void*)e);
		}

		type = sd.type;
		return this;
	}

	Expression getField(Type type, uint offset)
	{
		assert(false);
	}

	int getFieldIndex(Type type, uint offset)
	{
		assert(false);
	}

	elem* toElem(IRState* irs)
	{
		elem* e;
		size_t dim;

		//printf("StructLiteralExp.toElem() %s\n", toChars());

		// struct symbol to initialize with the literal
		Symbol* stmp = sym ? sym : symbol_genauto(sd.type.toCtype());

		e = null;

		if (fillHoles)
		{
			/* Initialize all alignment 'holes' to zero.
			 * Do before initializing fields, as the hole filling process
			 * can spill over into the fields.
			 */
			size_t offset = 0;
			for (size_t i = 0; i < sd.fields.dim; i++)
			{
				Dsymbol s = cast(Dsymbol)sd.fields.data[i];
				VarDeclaration v = s.isVarDeclaration();
				assert(v);

				e = el_combine(e, fillHole(stmp, &offset, v.offset, sd.structsize));
				size_t vend = v.offset + cast(uint)v.type.size();
				if (offset < vend)
					offset = vend;
			}
			e = el_combine(e, fillHole(stmp, &offset, sd.structsize, sd.structsize));
		}

		if (elements)
		{
			dim = elements.dim;
			assert(dim <= sd.fields.dim);
			for (size_t i = 0; i < dim; i++)
			{   
				Expression el = cast(Expression)elements.data[i];
				if (!el)
					continue;

				Dsymbol s = cast(Dsymbol)sd.fields.data[i];
				VarDeclaration v = s.isVarDeclaration();
				assert(v);
				assert(!v.isThisDeclaration());

				elem* e1;
				if (tybasic(stmp.Stype.Tty) == TYnptr)
				{	
					e1 = el_var(stmp);
					e1.EV.sp.Voffset = soffset;
				}
				else
				{	
					e1 = el_ptr(stmp);
					if (soffset)
						e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset));
				}
				e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset));
				elem* ec = e1;			// pointer to destination

				elem* ep = el.toElem(irs);

				Type t1b = v.type.toBasetype();
				Type t2b = el.type.toBasetype();
				if (t1b.ty == Tsarray)
				{
					if (t2b.implicitConvTo(t1b))
					{
		///version (DMDV2) {
						// Determine if postblit is needed
						int postblit = 0;
						if (needsPostblit(t1b))
							postblit = 1;

						if (postblit)
						{
							/* Generate:
							 *	_d_arrayctor(ti, From: ep, To: e1)
							 */
							Expression ti = t1b.nextOf().toBasetype().getTypeInfo(null);
							elem* esize = el_long(TYsize_t, (cast(TypeSArray)t1b).dim.toInteger());
							e1 = el_pair(TYdarray, esize, e1);
							ep = el_pair(TYdarray, el_copytree(esize), array_toPtr(el.type, ep));
							ep = el_params(e1, ep, ti.toElem(irs), null);
							int rtl = RTLSYM_ARRAYCTOR;
							e1 = el_bin(OPcall, type.totym(), el_var(rtlsym[rtl]), ep);
						}
						else
		///}
						{
							elem* esize = el_long(TYsize_t, t1b.size());
							ep = array_toPtr(el.type, ep);
							e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize));
						}
					}
					else
					{
						elem* edim = el_long(TYsize_t, t1b.size() / t2b.size());
						e1 = setArray(e1, edim, t2b, ep, irs, TOKconstruct);
					}
				}
				else
				{
					tym_t ty = v.type.totym();
					e1 = el_una(OPind, ty, e1);
					if (tybasic(ty) == TYstruct)
						e1.Enumbytes = cast(uint)v.type.size();
					e1 = el_bin(OPeq, ty, e1, ep);
					if (tybasic(ty) == TYstruct)
					{   
						e1.Eoper = OPstreq;
						e1.Enumbytes = cast(uint)v.type.size();
					}
version (DMDV2) {
					/* Call postblit() on e1
					 */
					StructDeclaration sd = needsPostblit(v.type);
					if (sd)
					{   
						FuncDeclaration fd = sd.postblit;
						ec = el_copytree(ec);
						ec = callfunc(loc, irs, 1, Type.tvoid, ec, sd.type.pointerTo(), fd, fd.type, null, null);
						e1 = el_bin(OPcomma, ec.Ety, e1, ec);
					}
}
				}
				e = el_combine(e, e1);
			}
		}

version (DMDV2) {
		if (sd.isnested)
		{	// Initialize the hidden 'this' pointer
			assert(sd.fields.dim);
			Dsymbol s = cast(Dsymbol)sd.fields.data[sd.fields.dim - 1];
			ThisDeclaration v = s.isThisDeclaration();
			assert(v);

			elem* e1;
			if (tybasic(stmp.Stype.Tty) == TYnptr)
			{   
				e1 = el_var(stmp);
				e1.EV.sp.Voffset = soffset;
			}
			else
			{   
				e1 = el_ptr(stmp);
				if (soffset)
					e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, soffset));
			}
			e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset));
			e1 = setEthis(loc, irs, e1, sd);

			e = el_combine(e, e1);
		}
}

		elem* ev = el_var(stmp);
		ev.Enumbytes = sd.structsize;
		e = el_combine(e, ev);
		el_setLoc(e,loc);
		return e;
	}

	bool checkSideEffect(int flag)
	{
		assert(false);
	}

	void toCBuffer(OutBuffer buf, HdrGenState* hgs)
	{
		assert(false);
	}

	void toMangleBuffer(OutBuffer buf)
	{
		assert(false);
	}

	void scanForNestedRef(Scope sc)
	{
		assert(false);
	}

	Expression optimize(int result)
	{
		if (elements)
		{
			for (size_t i = 0; i < elements.dim; i++)
			{   
				Expression e = cast(Expression)elements.data[i];
				if (!e)
					continue;
				e = e.optimize(WANTvalue | (result & WANTinterpret));
				elements.data[i] = cast(void*)e;
			}
		}
		return this;
	}

	Expression interpret(InterState istate)
	{
		assert(false);
	}

	dt_t** toDt(dt_t** pdt)
	{
		assert(false);
	}

	int isLvalue()
	{
		assert(false);
	}

	Expression toLvalue(Scope sc, Expression e)
	{
		assert(false);
	}

	bool canThrow()
	{
		return arrayExpressionCanThrow(elements);
	}

	MATCH implicitConvTo(Type t)
	{
static if (false) {
		printf("StructLiteralExp.implicitConvTo(this=%.*s, type=%.*s, t=%.*s)\n",
			toChars(), type.toChars(), t.toChars());
}
		MATCH m = Expression.implicitConvTo(t);
		if (m != MATCHnomatch)
			return m;
		if (type.ty == t.ty && type.ty == Tstruct && (cast(TypeStruct)type).sym == (cast(TypeStruct)t).sym)
		{
			m = MATCHconst;
			for (int i = 0; i < elements.dim; i++)
			{   
				Expression e = cast(Expression)elements.data[i];
				Type te = e.type;
				if (t.mod == 0)
					te = te.mutableOf();
				else
				{	
					assert(t.mod == MODinvariant);
					te = te.invariantOf();
				}
				MATCH m2 = e.implicitConvTo(te);
				//printf("\t%s => %s, match = %d\n", e.toChars(), te.toChars(), m2);
				if (m2 < m)
					m = m2;
			}
		}
		return m;
	}

	int inlineCost(InlineCostState* ics)
	{
		assert(false);
	}

	Expression doInline(InlineDoState ids)
	{
		assert(false);
	}

	Expression inlineScan(InlineScanState* iss)
	{
		assert(false);
	}
}