Esempio n. 1
0
File: nteh.c Progetto: spott/dmd
code *nteh_unwind(regm_t retregs,unsigned index)
{   code *c;
    code cs;
    code *cs1;
    code *cs2;
    regm_t desregs;
    int reg;
    int local_unwind;

    // Shouldn't this always be CX?
#if SCPP
    reg = AX;
#else
    reg = CX;
#endif

#if MARS
    local_unwind = RTLSYM_D_LOCAL_UNWIND2;
#else
    local_unwind = RTLSYM_LOCAL_UNWIND2;
#endif
    desregs = (~rtlsym[local_unwind]->Sregsaved & (ALLREGS)) | mask[reg];
    gensaverestore(retregs & desregs,&cs1,&cs2);

    c = getregs(desregs);

    cs.Iop = 0x8D;
    cs.Irm = modregrm(2,reg,BPRM);
    cs.Iflags = 0;
    cs.Irex = 0;
    cs.IFL1 = FLconst;
    // EBP offset of __context.prev
    cs.IEV1.Vint = nteh_EBPoffset_prev();
    c = gen(c,&cs);                             // LEA  ECX,contextsym

    genc2(c,0x68,0,index);                      // PUSH index
    gen1(c,0x50 + reg);                         // PUSH ECX

#if MARS
    //gencs(c,0xB8+AX,0,FLextern,nteh_scopetable());    // MOV EAX,&scope_table
    gencs(c,0x68,0,FLextern,nteh_scopetable());         // PUSH &scope_table

    gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]);        // CALL __d_local_unwind2()
    genc2(c,0x81,modregrm(3,0,SP),12);                  // ADD ESP,12
#else
    gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]);        // CALL __local_unwind2()
    genc2(c,0x81,modregrm(3,0,SP),8);                   // ADD ESP,8
#endif

    c = cat4(cs1,c,cs2,NULL);
    return c;
}
Esempio n. 2
0
File: nteh.c Progetto: spott/dmd
code *linux_unwind(regm_t retregs,unsigned index)
{   code *c;
    code *cs1;
    code *cs2;
    int i;
    regm_t desregs;
    int reg;
    int local_unwind;

    // Shouldn't this always be CX?
#if SCPP
    reg = AX;
#else
    reg = CX;
#endif

#if MARS
    local_unwind = RTLSYM_D_LOCAL_UNWIND2;
#else
    local_unwind = RTLSYM_LOCAL_UNWIND2;
#endif
    desregs = (~rtlsym[local_unwind]->Sregsaved & (ALLREGS)) | mask[reg];
    gensaverestore(retregs & desregs,&cs1,&cs2);

    c = getregs(desregs);
    c = genc2(c,0x68,0,index);                  // PUSH index

#if MARS
//    gencs(c,0x68,0,FLextern,nteh_scopetable());               // PUSH &scope_table

    gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]);        // CALL __d_local_unwind2()
    genc2(c,0x81,modregrm(3,0,SP),4);                   // ADD ESP,12
#else
    gencs(c,0xE8,0,FLfunc,rtlsym[local_unwind]);        // CALL __local_unwind2()
    genc2(c,0x81,modregrm(3,0,SP),8);                   // ADD ESP,8
#endif

    c = cat4(cs1,c,cs2,NULL);
    return c;
}
Esempio n. 3
0
File: nteh.c Progetto: spott/dmd
code *cdsetjmp(elem *e,regm_t *pretregs)
{   code cs;
    code *c;
    regm_t retregs;
    unsigned stackpushsave;
    unsigned flag;

    c = NULL;
    stackpushsave = stackpush;
#if SCPP
    if (CPP && (funcsym_p->Sfunc->Fflags3 & Fcppeh || usednteh & NTEHcpp))
    {
        /*  If in C++ try block
            If the frame that is calling setjmp has a try,catch block then
            the call to setjmp3 is as follows:
              __setjmp3(environment,3,__cpp_longjmp_unwind,trylevel,funcdata);

            __cpp_longjmp_unwind is a routine in the RTL. This is a
            stdcall routine that will deal with unwinding for CPP Frames.
            trylevel is the value that gets incremented at each catch,
            constructor invocation.
            funcdata is the same value that you put into EAX prior to
            cppframehandler getting called.
         */
        symbol *s;

        s = except_gensym();
        if (!s)
            goto L1;

        c = gencs(c,0x68,0,FLextern,s);                 // PUSH &scope_table
        stackpush += 4;
        genadjesp(c,4);

        c = genc1(c,0xFF,modregrm(1,6,BP),FLconst,(targ_uns)-4);
        // PUSH trylevel
        stackpush += 4;
        genadjesp(c,4);

        cs.Iop = 0x68;
        cs.Iflags = CFoff;
        cs.Irex = 0;
        cs.IFL2 = FLextern;
        cs.IEVsym2 = rtlsym[RTLSYM_CPP_LONGJMP];
        cs.IEVoffset2 = 0;
        c = gen(c,&cs);                         // PUSH &_cpp_longjmp_unwind
        stackpush += 4;
        genadjesp(c,4);

        flag = 3;
    }
    else
#endif
        if (funcsym_p->Sfunc->Fflags3 & Fnteh)
        {
            /*  If in NT SEH try block
                If the frame that is calling setjmp has a try, except block
                then the call to setjmp3 is as follows:
                  __setjmp3(environment,2,__seh_longjmp_unwind,trylevel);
                __seth_longjmp_unwind is supplied by the RTL and is a stdcall
                function. It is the name that MSOFT uses, we should
                probably use the same one.
                trylevel is the value that you increment at each try and
                decrement at the close of the try.  This corresponds to the
                index field of the ehrec.
             */
            int sindex_off;

            sindex_off = 20;                // offset of __context.sindex
            cs.Iop = 0xFF;
            cs.Irm = modregrm(2,6,BPRM);
            cs.Iflags = 0;
            cs.Irex = 0;
            cs.IFL1 = FLbprel;
            cs.IEVsym1 = nteh_contextsym();
            cs.IEVoffset1 = sindex_off;
            c = gen(c,&cs);                 // PUSH scope_index
            stackpush += 4;
            genadjesp(c,4);

            cs.Iop = 0x68;
            cs.Iflags = CFoff;
            cs.Irex = 0;
            cs.IFL2 = FLextern;
            cs.IEVsym2 = rtlsym[RTLSYM_LONGJMP];
            cs.IEVoffset2 = 0;
            c = gen(c,&cs);                 // PUSH &_seh_longjmp_unwind
            stackpush += 4;
            genadjesp(c,4);

            flag = 2;
        }
        else
        {
            /*  If the frame calling setjmp has neither a try..except, nor a
                try..catch, then call setjmp3 as follows:
                _setjmp3(environment,0)
             */
L1:
            flag = 0;
        }

    cs.Iop = 0x68;
    cs.Iflags = 0;
    cs.Irex = 0;
    cs.IFL2 = FLconst;
    cs.IEV2.Vint = flag;
    c = gen(c,&cs);                     // PUSH flag
    stackpush += 4;
    genadjesp(c,4);

    c = cat(c,params(e->E1,REGSIZE));

    c = cat(c,getregs(~rtlsym[RTLSYM_SETJMP3]->Sregsaved & (ALLREGS | mES)));
    gencs(c,0xE8,0,FLfunc,rtlsym[RTLSYM_SETJMP3]);      // CALL __setjmp3

    c = genc2(c,0x81,modregrm(3,0,SP),stackpush - stackpushsave);       // ADD ESP,8
    genadjesp(c,-(stackpush - stackpushsave));

    stackpush = stackpushsave;
    retregs = regmask(e->Ety, TYnfunc);
    return cat(c,fixresult(e,retregs,pretregs));
}
Esempio n. 4
0
File: nteh.c Progetto: spott/dmd
code *nteh_prolog()
{
    code cs;
    code *c1;
    code *c;

    if (usednteh & NTEHpassthru)
    {
        /* An sindex value of -2 is a magic value that tells the
         * stack unwinder to skip this frame.
         */
        assert(config.exe & (EX_LINUX | EX_LINUX64 | EX_OSX | EX_OSX64 | EX_FREEBSD | EX_FREEBSD64 | EX_SOLARIS | EX_SOLARIS64));
        cs.Iop = 0x68;
        cs.Iflags = 0;
        cs.Irex = 0;
        cs.IFL2 = FLconst;
        cs.IEV2.Vint = -2;
        return gen(CNIL,&cs);                   // PUSH -2
    }

    /* Generate instance of struct __nt_context on stack frame:
        [  ]                                    // previous ebp already there
        push    -1                              // sindex
        mov     EDX,FS:__except_list
        push    offset FLAT:scope_table         // stable (not for MARS or C++)
        push    offset FLAT:__except_handler3   // handler
        push    EDX                             // prev
        mov     FS:__except_list,ESP
        sub     ESP,8                           // info, esp for __except support
     */

//    useregs(mAX);                     // What is this for?

    cs.Iop = 0x68;
    cs.Iflags = 0;
    cs.Irex = 0;
    cs.IFL2 = FLconst;
    cs.IEV2.Vint = -1;
    c1 = gen(CNIL,&cs);                 // PUSH -1

    if (usednteh & NTEHcpp || MARS)
    {
        // PUSH &framehandler
        cs.IFL2 = FLframehandler;
#if MARS
        nteh_scopetable();
#endif
    }
    else
    {
        // Do stable
        cs.Iflags |= CFoff;
        cs.IFL2 = FLextern;
        cs.IEVsym2 = nteh_scopetable();
        cs.IEVoffset2 = 0;
        c1 = gen(c1,&cs);                       // PUSH &scope_table

        cs.IFL2 = FLextern;
        cs.IEVsym2 = rtlsym[RTLSYM_EXCEPT_HANDLER3];
        makeitextern(rtlsym[RTLSYM_EXCEPT_HANDLER3]);
    }
    c = gen(NULL,&cs);                          // PUSH &__except_handler3

    if (config.exe == EX_NT)
    {
        makeitextern(rtlsym[RTLSYM_EXCEPT_LIST]);
#if 0
        cs.Iop = 0xFF;
        cs.Irm = modregrm(0,6,BPRM);
        cs.Iflags = CFfs;
        cs.Irex = 0;
        cs.IFL1 = FLextern;
        cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
        cs.IEVoffset1 = 0;
        gen(c,&cs);                             // PUSH FS:__except_list
#else
        useregs(mDX);
        cs.Iop = 0x8B;
        cs.Irm = modregrm(0,DX,BPRM);
        cs.Iflags = CFfs;
        cs.Irex = 0;
        cs.IFL1 = FLextern;
        cs.IEVsym1 = rtlsym[RTLSYM_EXCEPT_LIST];
        cs.IEVoffset1 = 0;
        gen(c1,&cs);                            // MOV EDX,FS:__except_list

        gen1(c,0x50 + DX);                      // PUSH EDX
#endif
        cs.Iop = 0x89;
        NEWREG(cs.Irm,SP);
        gen(c,&cs);                             // MOV FS:__except_list,ESP
    }

    c = genc2(c,0x81,modregrm(3,5,SP),8);       // SUB ESP,8

    return cat(c1,c);
}
Esempio n. 5
0
File: cgxmm.c Progetto: dsagal/dmd
code *cdvector(elem *e, regm_t *pretregs)
{
    /* e should look like one of:
     *    vector
     *      |
     *    param
     *    /   \
     *  param op2
     *  /   \
     * op   op1
     */

    if (!config.fpxmmregs)
    {   printf("SIMD operations not supported on this platform\n");
        exit(1);
    }

    unsigned n = el_nparams(e->E1);
    elem **params = (elem **)malloc(n * sizeof(elem *));
    assert(params);
    elem **tmp = params;
    el_paramArray(&tmp, e->E1);

#if 0
    printf("cdvector()\n");
    for (int i = 0; i < n; i++)
    {
        printf("[%d]: ", i);
        elem_print(params[i]);
    }
#endif

    if (*pretregs == 0)
    {   /* Evaluate for side effects only
         */
        code *c = CNIL;
        for (int i = 0; i < n; i++)
        {
            c = cat(c, codelem(params[i], pretregs, FALSE));
            *pretregs = 0;      // in case they got set
        }
        return c;
    }

    assert(n >= 2 && n <= 4);

    elem *eop = params[0];
    elem *op1 = params[1];
    elem *op2 = NULL;
    tym_t ty2 = 0;
    if (n >= 3)
    {   op2 = params[2];
        ty2 = tybasic(op2->Ety);
    }

    unsigned op = el_tolong(eop);
#ifdef DEBUG
    assert(!isXMMstore(op));
#endif
    tym_t ty1 = tybasic(op1->Ety);
    unsigned sz1 = tysize[ty1];
//    assert(sz1 == 16);       // float or double

    regm_t retregs;
    code *c;
    code *cr, *cg, *co;
    if (n == 3 && ty2 == TYuchar && op2->Eoper == OPconst)
    {   // Handle: op xmm,imm8

        retregs = *pretregs & XMMREGS;
        if (!retregs)
            retregs = XMMREGS;
        c = codelem(op1,&retregs,FALSE); // eval left leaf
        unsigned reg = findreg(retregs);
        int r;
        switch (op)
        {
            case PSLLD:  r = 6; op = 0x660F72;  break;
            case PSLLQ:  r = 6; op = 0x660F73;  break;
            case PSLLW:  r = 6; op = 0x660F71;  break;
            case PSRAD:  r = 4; op = 0x660F72;  break;
            case PSRAW:  r = 4; op = 0x660F71;  break;
            case PSRLD:  r = 2; op = 0x660F72;  break;
            case PSRLQ:  r = 2; op = 0x660F73;  break;
            case PSRLW:  r = 2; op = 0x660F71;  break;
            case PSRLDQ: r = 3; op = 0x660F73;  break;
            case PSLLDQ: r = 7; op = 0x660F73;  break;

            default:
                printf("op = x%x\n", op);
                assert(0);
                break;
        }
        cr = CNIL;
        cg = getregs(retregs);
        co = genc2(CNIL,op,modregrmx(3,r,reg-XMM0), el_tolong(op2));
    }
    else if (n == 2)
    {   /* Handle: op xmm,mem
         * where xmm is written only, not read
         */
        code cs;

        if ((op1->Eoper == OPind && !op1->Ecount) || op1->Eoper == OPvar)
        {
            c = getlvalue(&cs, op1, RMload);     // get addressing mode
        }
        else
        {
            regm_t rretregs = XMMREGS;
            c = codelem(op1, &rretregs, FALSE);
            unsigned rreg = findreg(rretregs) - XMM0;
            cs.Irm = modregrm(3,0,rreg & 7);
            cs.Iflags = 0;
            cs.Irex = 0;
            if (rreg & 8)
                cs.Irex |= REX_B;
        }

        retregs = *pretregs & XMMREGS;
        if (!retregs)
            retregs = XMMREGS;
        unsigned reg;
        cr = CNIL;
        cg = allocreg(&retregs, &reg, e->Ety);
        code_newreg(&cs, reg - XMM0);
        cs.Iop = op;
        co = gen(CNIL,&cs);
    }
    else if (n == 3 || n == 4)
    {   /* Handle:
         *      op xmm,mem        // n = 3
         *      op xmm,mem,imm8   // n = 4
         * Both xmm and mem are operands, evaluate xmm first.
         */

        code cs;

        retregs = *pretregs & XMMREGS;
        if (!retregs)
            retregs = XMMREGS;
        c = codelem(op1,&retregs,FALSE); // eval left leaf
        unsigned reg = findreg(retregs);

        if ((op2->Eoper == OPind && !op2->Ecount) || op2->Eoper == OPvar)
        {
            cr = getlvalue(&cs, op2, RMload | retregs);     // get addressing mode
        }
        else
        {
            unsigned rretregs = XMMREGS & ~retregs;
            cr = scodelem(op2, &rretregs, retregs, TRUE);
            unsigned rreg = findreg(rretregs) - XMM0;
            cs.Irm = modregrm(3,0,rreg & 7);
            cs.Iflags = 0;
            cs.Irex = 0;
            if (rreg & 8)
                cs.Irex |= REX_B;
        }

        cg = getregs(retregs);
        if (n == 4)
        {
            switch (op)
            {
                case CMPPD:   case CMPSS:   case CMPSD:   case CMPPS:
                case PSHUFD:  case PSHUFHW: case PSHUFLW:
                case BLENDPD: case BLENDPS: case DPPD:    case DPPS:
                case MPSADBW: case PBLENDW:
                case ROUNDPD: case ROUNDPS: case ROUNDSD: case ROUNDSS:
                case SHUFPD:  case SHUFPS:
                    break;
                default:
                    printf("op = x%x\n", op);
                    assert(0);
                    break;
            }
            elem *imm8 = params[3];
            cs.IFL2 = FLconst;
            cs.IEV2.Vsize_t = el_tolong(imm8);
        }
        code_newreg(&cs, reg - XMM0);
        cs.Iop = op;
        co = gen(CNIL,&cs);
    }
    else
        assert(0);
    co = cat(co,fixresult(e,retregs,pretregs));
    free(params);
    freenode(e);
    return cat4(c,cr,cg,co);
}
Esempio n. 6
0
File: cgxmm.c Progetto: dsagal/dmd
code *xmmeq(elem *e, unsigned op, elem *e1, elem *e2,regm_t *pretregs)
{
    tym_t tymll;
    unsigned reg;
    int i;
    code *cl,*cr,*c,cs;
    elem *e11;
    bool regvar;                  /* TRUE means evaluate into register variable */
    regm_t varregm;
    unsigned varreg;
    targ_int postinc;

    //printf("xmmeq(e1 = %p, e2 = %p, *pretregs = %s)\n", e1, e2, regm_str(*pretregs));
    int e2oper = e2->Eoper;
    tym_t tyml = tybasic(e1->Ety);              /* type of lvalue               */
    regm_t retregs = *pretregs;

    if (!(retregs & XMMREGS))
        retregs = XMMREGS;              // pick any XMM reg

    cs.Iop = (op == OPeq) ? xmmstore(tyml) : op;
    regvar = FALSE;
    varregm = 0;
    if (config.flags4 & CFG4optimized)
    {
        // Be careful of cases like (x = x+x+x). We cannot evaluate in
        // x if x is in a register.
        if (isregvar(e1,&varregm,&varreg) &&    // if lvalue is register variable
            doinreg(e1->EV.sp.Vsym,e2)          // and we can compute directly into it
           )
        {   regvar = TRUE;
            retregs = varregm;
            reg = varreg;       /* evaluate directly in target register */
        }
    }
    if (*pretregs & mPSW && !EOP(e1))     // if evaluating e1 couldn't change flags
    {   // Be careful that this lines up with jmpopcode()
        retregs |= mPSW;
        *pretregs &= ~mPSW;
    }
    cr = scodelem(e2,&retregs,0,TRUE);    // get rvalue

    // Look for special case of (*p++ = ...), where p is a register variable
    if (e1->Eoper == OPind &&
        ((e11 = e1->E1)->Eoper == OPpostinc || e11->Eoper == OPpostdec) &&
        e11->E1->Eoper == OPvar &&
        e11->E1->EV.sp.Vsym->Sfl == FLreg
       )
    {
        postinc = e11->E2->EV.Vint;
        if (e11->Eoper == OPpostdec)
            postinc = -postinc;
        cl = getlvalue(&cs,e11,RMstore | retregs);
        freenode(e11->E2);
    }
    else
    {   postinc = 0;
        cl = getlvalue(&cs,e1,RMstore | retregs);       // get lvalue (cl == CNIL if regvar)
    }

    c = getregs_imm(varregm);

    reg = findreg(retregs & XMMREGS);
    cs.Irm |= modregrm(0,(reg - XMM0) & 7,0);
    if ((reg - XMM0) & 8)
        cs.Irex |= REX_R;

    // Do not generate mov from register onto itself
    if (!(regvar && reg == XMM0 + ((cs.Irm & 7) | (cs.Irex & REX_B ? 8 : 0))))
        c = gen(c,&cs);         // MOV EA+offset,reg

    if (e1->Ecount ||                     // if lvalue is a CSE or
        regvar)                           // rvalue can't be a CSE
    {
        c = cat(c,getregs_imm(retregs));        // necessary if both lvalue and
                                        //  rvalue are CSEs (since a reg
                                        //  can hold only one e at a time)
        cssave(e1,retregs,EOP(e1));     // if lvalue is a CSE
    }

    c = cat4(cr,cl,c,fixresult(e,retregs,pretregs));
Lp:
    if (postinc)
    {
        int reg = findreg(idxregm(&cs));
        if (*pretregs & mPSW)
        {   // Use LEA to avoid touching the flags
            unsigned rm = cs.Irm & 7;
            if (cs.Irex & REX_B)
                rm |= 8;
            c = genc1(c,0x8D,buildModregrm(2,reg,rm),FLconst,postinc);
            if (tysize(e11->E1->Ety) == 8)
                code_orrex(c, REX_W);
        }
        else if (I64)
        {
            c = genc2(c,0x81,modregrmx(3,0,reg),postinc);
            if (tysize(e11->E1->Ety) == 8)
                code_orrex(c, REX_W);
        }
        else
        {
            if (postinc == 1)
                c = gen1(c,0x40 + reg);         // INC reg
            else if (postinc == -(targ_int)1)
                c = gen1(c,0x48 + reg);         // DEC reg
            else
            {
                c = genc2(c,0x81,modregrm(3,0,reg),postinc);
            }
        }
    }
    freenode(e1);
    return c;
}