diff dmd/AsmStatement.d @ 0:10317f0c89a5

Initial commit
author korDen
date Sat, 24 Oct 2009 08:42:06 +0400
parents
children 3f834bed4f13
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dmd/AsmStatement.d	Sat Oct 24 08:42:06 2009 +0400
@@ -0,0 +1,373 @@
+module dmd.AsmStatement;
+
+import dmd.Loc;
+import dmd.Statement;
+import dmd.Token;
+import dmd.Scope;
+import dmd.OutBuffer;
+import dmd.HdrGenState;
+import dmd.IRState;
+import dmd.BE;
+import dmd.LabelDsymbol;
+import dmd.Dsymbol;
+import dmd.Id;
+import dmd.TOK;
+import dmd.Global;
+import dmd.FuncDeclaration;
+import dmd.Declaration;
+import dmd.LabelStatement;
+import dmd.Util;
+
+import dmd.backend.code;
+import dmd.backend.iasm;
+import dmd.backend.block;
+import dmd.backend.Blockx;
+import dmd.backend.Util;
+import dmd.codegen.Util;
+import dmd.backend.BC;
+import dmd.backend.FL;
+import dmd.backend.SFL;
+import dmd.backend.SC;
+import dmd.backend.mTY;
+import dmd.backend.Symbol;
+import dmd.backend.LIST;
+
+import core.stdc.string : memset;
+import core.stdc.stdlib : exit, EXIT_FAILURE;
+
+class AsmStatement : Statement
+{
+    Token* tokens;
+    code* asmcode;
+    uint asmalign;		// alignment of this statement
+    bool refparam;		// true if function parameter is referenced
+    bool naked;		// true if function is to be naked
+    uint regs;		// mask of registers modified
+
+    this(Loc loc, Token* tokens)
+	{
+		super(loc);
+		this.tokens = tokens;
+	}
+	
+    Statement syntaxCopy()
+	{
+		assert(false);
+	}
+	
+    Statement semantic(Scope sc)
+	{
+		//printf("AsmStatement.semantic()\n");
+
+		if (global.params.safe && !sc.module_.safe)
+		{
+			error("inline assembler not allowed in safe mode");
+		}
+
+		OP* o;
+		OPND* o1 = null;
+		OPND* o2 = null;
+		OPND* o3 = null;
+
+		PTRNTAB ptb;
+		uint usNumops;
+		ubyte uchPrefix = 0;
+		ubyte bAsmseen;
+		char* pszLabel = null;
+		code* c;
+		FuncDeclaration fd = sc.parent.isFuncDeclaration();
+
+		assert(fd);
+		fd.inlineAsm = 1;
+
+		if (!tokens)
+			return null;
+
+		memset(&asmstate, 0, asmstate.sizeof);
+
+		asmstate.statement = this;
+		asmstate.sc = sc;
+
+static if (false) {
+		// don't use bReturnax anymore, and will fail anyway if we use return type inference
+		// Scalar return values will always be in AX.  So if it is a scalar
+		// then asm block sets return value if it modifies AX, if it is non-scalar
+		// then always assume that the ASM block sets up an appropriate return
+		// value.
+
+		asmstate.bReturnax = 1;
+		if (sc.func.type.nextOf().isscalar())
+			asmstate.bReturnax = 0;
+}
+
+		// Assume assembler code takes care of setting the return value
+		sc.func.hasReturnExp |= 8;
+		
+		if (!asmstate.bInit)
+		{
+			asmstate.bInit = true;
+			init_optab();
+			asmstate.psDollar = new LabelDsymbol(Id.__dollar);
+			//asmstate.psLocalsize = new VarDeclaration(0, Type.tint32, Id.__LOCAL_SIZE, null);
+			asmstate.psLocalsize = new Dsymbol(Id.__LOCAL_SIZE);
+			cod3_set386();
+		}
+		
+		asmstate.loc = loc;
+
+		asmtok = tokens;
+		asm_token_trans(asmtok);
+		if (setjmp(asmstate.env))
+		{	
+			asmtok = null;			// skip rest of line
+			tok_value = TOK.TOKeof;
+			exit(EXIT_FAILURE);
+			goto AFTER_EMIT;
+		}
+
+		switch (cast(int)tok_value)
+		{
+			case ASMTK.ASMTKnaked:
+				naked = true;
+				sc.func.naked = true;
+				asm_token();
+				break;
+
+			case ASMTK.ASMTKeven:
+				asm_token();
+				asmalign = 2;
+				break;
+
+			case TOK.TOKalign:
+			{   
+				asm_token();
+				uint align_ = asm_getnum();
+				if (ispow2(align_) == -1)
+					asmerr(ASMERRMSGS.EM_align, align_);	// power of 2 expected
+				else
+					asmalign = align_;
+				break;
+			}
+
+			// The following three convert the keywords 'int', 'in', 'out'
+			// to identifiers, since they are x86 instructions.
+			case TOK.TOKint32:
+				o = asm_op_lookup(Id.__int.toChars());
+				goto Lopcode;
+
+			case TOK.TOKin:
+				o = asm_op_lookup(Id.___in.toChars());
+				goto Lopcode;
+
+			case TOK.TOKout:
+				o = asm_op_lookup(Id.___out.toChars());
+				goto Lopcode;
+
+			case TOK.TOKidentifier:
+				o = asm_op_lookup(asmtok.ident.toChars());
+				if (!o)
+					goto OPCODE_EXPECTED;
+
+			Lopcode:
+				asmstate.ucItype = o.usNumops & IT.ITMASK;
+				asm_token();
+				if (o.usNumops > 3)
+				{
+					switch (asmstate.ucItype)
+					{
+						case IT.ITdata:
+							asmcode = asm_db_parse(o);
+							goto AFTER_EMIT;
+
+						case IT.ITaddr:
+							asmcode = asm_da_parse(o);
+							goto AFTER_EMIT;
+						
+						default:
+							break;
+					}
+				}
+				// get the first part of an expr
+				o1 = asm_cond_exp();
+				if (tok_value == TOK.TOKcomma)
+				{
+					asm_token();
+					o2 = asm_cond_exp();
+				}
+				if (tok_value == TOK.TOKcomma)
+				{
+					asm_token();
+					o3 = asm_cond_exp();
+				}
+				// match opcode and operands in ptrntab to verify legal inst and
+				// generate
+
+				ptb = asm_classify(o, o1, o2, o3, &usNumops);
+				assert(ptb.pptb0);
+
+				//
+				// The Multiply instruction takes 3 operands, but if only 2 are seen
+				// then the third should be the second and the second should
+				// be a duplicate of the first.
+				//
+						
+				if (asmstate.ucItype == IT.ITopt &&
+					(usNumops == 2) &&
+					(ASM_GET_aopty(o2.usFlags) == ASM_OPERAND_TYPE._imm) &&
+					((o.usNumops & IT.ITSIZE) == 3))
+				{
+					o3 = o2;
+					o2 = opnd_calloc();
+					*o2 = *o1;
+
+					// Re-classify the opcode because the first classification
+					// assumed 2 operands.
+
+					ptb = asm_classify(o, o1, o2, o3, &usNumops);
+				}
+				else
+				{
+static if (false) {
+					if (asmstate.ucItype == IT.ITshift && (ptb.pptb2.usOp2 == 0 ||
+						(ptb.pptb2.usOp2 & _cl))) {
+						opnd_free(o2);
+						o2 = null;
+						usNumops = 1;
+					}
+}
+				}
+
+				asmcode = asm_emit(loc, usNumops, ptb, o, o1, o2, o3);
+				break;
+
+			default:
+			OPCODE_EXPECTED:
+				asmerr(ASMERRMSGS.EM_opcode_exp, asmtok.toChars());	// assembler opcode expected
+				break;
+		}
+
+	AFTER_EMIT:
+		opnd_free(o1);
+		opnd_free(o2);
+		opnd_free(o3);
+		o1 = o2 = o3 = null;
+
+		if (tok_value != TOK.TOKeof)
+			asmerr(ASMERRMSGS.EM_eol);			// end of line expected
+
+		//return asmstate.bReturnax;
+		return this;
+	}
+	
+    BE blockExit()
+	{
+		assert(false);
+	}
+	
+    bool comeFrom()
+	{
+		assert(false);
+	}
+
+    void toCBuffer(OutBuffer buf, HdrGenState* hgs)
+	{
+		assert(false);
+	}
+	
+    AsmStatement isAsmStatement() { return this; }
+
+    void toIR(IRState *irs)
+	{
+		block* bpre;
+		block* basm;
+		Declaration d;
+		Symbol* s;
+		Blockx* blx = irs.blx;
+
+//		dumpCode(asmcode);
+
+		//printf("AsmStatement::toIR(asmcode = %x)\n", asmcode);
+		bpre = blx.curblock;
+		block_next(blx,BCgoto,null);
+		basm = blx.curblock;
+		list_append(&bpre.Bsucc, basm);
+		basm.Bcode = asmcode;
+		basm.Balign = cast(ubyte)asmalign;
+static if (false) {
+		if (label)
+		{	
+			block* b = labelToBlock(loc, blx, label);
+			printf("AsmStatement::toIR() %p\n", b);
+			if (b)
+				list_append(&basm.Bsucc, b);
+		}
+}
+		// Loop through each instruction, fixing Dsymbols into Symbol's
+		for (code* c = asmcode; c; c = c.next)
+		{	
+			LabelDsymbol label;
+			block* b;
+
+			switch (c.IFL1)
+			{
+				case FLblockoff:
+				case FLblock:
+					// FLblock and FLblockoff have LabelDsymbol's - convert to blocks
+					label = c.IEVlsym1;
+					b = labelToBlock(loc, blx, label);
+					list_append(&basm.Bsucc, b);
+					c.IEV1.Vblock = b;
+					break;
+
+				case FLdsymbol:
+				case FLfunc:
+					s = c.IEVdsym1.toSymbol();
+					if (s.Sclass == SCauto && s.Ssymnum == -1)
+						symbol_add(s);
+					c.IEVsym1() = s;
+					c.IFL1 = s.Sfl ? s.Sfl : FLauto;
+					break;
+				default:
+					break;
+			}
+
+			// Repeat for second operand
+			switch (c.IFL2)
+			{
+				case FLblockoff:
+				case FLblock:
+					label = c.IEVlsym2;
+					b = labelToBlock(loc, blx, label);
+					list_append(&basm.Bsucc, b);
+					c.IEV2.Vblock = b;
+					break;
+
+				case FLdsymbol:
+				case FLfunc:
+					d = c.IEVdsym2;
+					s = d.toSymbol();
+					if (s.Sclass == SCauto && s.Ssymnum == -1)
+						symbol_add(s);
+					c.IEVsym2() = s;
+					c.IFL2 = s.Sfl ? s.Sfl : FLauto;
+					if (d.isDataseg())
+						s.Sflags |= SFLlivexit;
+					break;
+				default:
+					break;
+			}
+			//c.print();
+		}
+
+		basm.bIasmrefparam = refparam;		// are parameters reference?
+		basm.usIasmregs = cast(ushort)regs;			// registers modified
+
+		block_next(blx,BCasm, null);
+		list_prepend(&basm.Bsucc, blx.curblock);
+
+		if (naked)
+		{
+			blx.funcsym.Stype.Tty |= mTYnaked;
+		}
+	}
+}
\ No newline at end of file