Mercurial > projects > ddmd
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