Mercurial > projects > ddmd
view dmd/AsmStatement.d @ 178:e3afd1303184
Many small bugs fixed
Made all classes derive from TObject to detect memory leaks (functionality is disabled for now)
Began work on overriding backend memory allocations (to avoid memory leaks)
author | korDen |
---|---|
date | Sun, 17 Oct 2010 07:42:00 +0400 |
parents | fa9a71a9f5a8 |
children | b0d41ff5e0df |
line wrap: on
line source
module dmd.AsmStatement; import dmd.common; 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; import std.stdio; 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) { register(); super(loc); this.tokens = tokens; } override Statement syntaxCopy() { assert(false); } override Statement semantic(Scope sc) { //printf("AsmStatement.semantic()\n"); //static if (true) { if (sc.func && sc.func.isSafe()) error("inline assembler not allowed in @safe function %s", sc.func.toChars()); //} else { // 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; auto asmstate = &global.asmstate; 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; global.asmtok = tokens; asm_token_trans(global.asmtok); if (setjmp(asmstate.env)) { global.asmtok = null; // skip rest of line global.tok_value = TOK.TOKeof; exit(EXIT_FAILURE); goto AFTER_EMIT; } switch (cast(int)global.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(global.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 (global.tok_value == TOK.TOKcomma) { asm_token(); o2 = asm_cond_exp(); } if (global.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, global.asmtok.toChars()); // assembler opcode expected break; } AFTER_EMIT: opnd_free(o1); opnd_free(o2); opnd_free(o3); o1 = o2 = o3 = null; if (global.tok_value != TOK.TOKeof) asmerr(ASMERRMSGS.EM_eol); // end of line expected //return asmstate.bReturnax; return this; } override BE blockExit() { assert(false); } override bool comeFrom() { assert(false); } override void toCBuffer(OutBuffer buf, HdrGenState* hgs) { buf.writestring("asm { "); Token* t = tokens; while (t) { buf.writestring(t.toChars()); if (t.next && t.value != TOKmin && t.value != TOKcomma && t.next.value != TOKcomma && t.value != TOKlbracket && t.next.value != TOKlbracket && t.next.value != TOKrbracket && t.value != TOKlparen && t.next.value != TOKlparen && t.next.value != TOKrparen && t.value != TOKdot && t.next.value != TOKdot) { buf.writebyte(' '); } t = t.next; } buf.writestring("; }"); buf.writenl(); } override AsmStatement isAsmStatement() { return this; } override 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; } } }