1: // Copyright (C) 1984-1998 by Symantec
   2: // Copyright (C) 2000-2011 by Digital Mars
   3: // All Rights Reserved
   4: // http://www.digitalmars.com
   5: // Written by Walter Bright
   6: /*
   7:  * This source file is made available for personal use
   8:  * only. The license is in /dmd/src/dmd/backendlicense.txt
   9:  * or /dm/src/dmd/backendlicense.txt
  10:  * For any other uses, please contact Digital Mars.
  11:  */
  12: 
  13: #if !SPP
  14: 
  15: #include        <stdio.h>
  16: #include        <string.h>
  17: #include        <stdlib.h>
  18: #include        <time.h>
  19: 
  20: #if __sun&&__SVR4
  21: #include        <alloca.h>
  22: #elif _MSC_VER
  23: #include        <malloc.h>
  24: #endif
  25: 
  26: #include        "cc.h"
  27: #include        "el.h"
  28: #include        "oper.h"
  29: #include        "code.h"
  30: #include        "global.h"
  31: #include        "type.h"
  32: 
  33: static char __file__[] = __FILE__;      /* for tassert.h                */
  34: #include        "tassert.h"
  35: 
  36: /* Generate the appropriate ESC instruction     */
  37: #define ESC(MF,b)       (0xD8 + ((MF) << 1) + (b))
  38: enum MF
  39: {       // Values for MF
  40:         MFfloat         = 0,
  41:         MFlong          = 1,
  42:         MFdouble        = 2,
  43:         MFword          = 3
  44: };
  45: code * genf2(code *c,unsigned op,unsigned rm);
  46: 
  47: targ_size_t paramsize(elem *e,unsigned stackalign);
  48: STATIC code * funccall (elem *,unsigned,unsigned,regm_t *,regm_t);
  49: 
  50: /* array to convert from index register to r/m field    */
  51:                                        /* AX CX DX BX SP BP SI DI       */
  52: static const signed char regtorm32[8] = {  0, 1, 2, 3,-1, 5, 6, 7 };
  53:              signed char regtorm  [8] = { -1,-1,-1, 7,-1, 6, 4, 5 };
  54: 
  55: /**************************
  56:  * Determine if e is a 32 bit scaled index addressing mode.
  57:  * Returns:
  58:  *      0       not a scaled index addressing mode
  59:  *      !=0     the value for ss in the SIB byte
  60:  */
  61: 
  62: int isscaledindex(elem *e)
  63: {   targ_uns ss;
  64: 
  65:     assert(!I16);
  66:     while (e->Eoper == OPcomma)
  67:         e = e->E2;
  68:     if (!(e->Eoper == OPshl && !e->Ecount &&
  69:           e->E2->Eoper == OPconst &&
  70:           (ss = e->E2->EV.Vuns) <= 3
  71:          )
  72:        )
  73:         ss = 0;
  74:     return ss;
  75: }
  76: 
  77: /*********************************************
  78:  * Generate code for which isscaledindex(e) returned a non-zero result.
  79:  */
  80: 
  81: code *cdisscaledindex(elem *e,regm_t *pidxregs,regm_t keepmsk)
  82: {   code *c;
  83:     regm_t r;
  84: 
  85:     // Load index register with result of e->E1
  86:     c = NULL;
  87:     while (e->Eoper == OPcomma)
  88:     {
  89:         r = 0;
  90:         c = cat(c,scodelem(e->E1,&r,keepmsk,TRUE));
  91:         freenode(e);
  92:         e = e->E2;
  93:     }
  94:     assert(e->Eoper == OPshl);
  95:     c = cat(c,scodelem(e->E1,pidxregs,keepmsk,TRUE));
  96:     freenode(e->E2);
  97:     freenode(e);
  98:     return c;
  99: }
 100: 
 101: /***********************************
 102:  * Determine index if we can do two LEA instructions as a multiply.
 103:  * Returns:
 104:  *      0       can't do it
 105:  */
 106: 
 107: static struct Ssindex
 108: {
 109:     targ_uns product;
 110:     char ss1;
 111:     char ss2;
 112:     char ssflags;
 113:         #define SSFLnobp        1       // can't have EBP in relconst
 114:         #define SSFLnobase1     2       // no base register for first LEA
 115:         #define SSFLnobase      4       // no base register
 116:         #define SSFLlea         8       // can do it in one LEA
 117: } ssindex_array[] =
 118: {       {0, 0,0},               // [0] is a place holder
 119: 
 120:         {3, 1,0,SSFLnobp | SSFLlea},
 121:         {5, 2,0,SSFLnobp | SSFLlea},
 122:         {9, 3,0,SSFLnobp | SSFLlea},
 123: 
 124:         {6, 1,1,SSFLnobase},
 125:         {12,1,2,SSFLnobase},
 126:         {24,1,3,SSFLnobase},
 127:         {10,2,1,SSFLnobase},
 128:         {20,2,2,SSFLnobase},
 129:         {40,2,3,SSFLnobase},
 130:         {18,3,1,SSFLnobase},
 131:         {36,3,2,SSFLnobase},
 132:         {72,3,3,SSFLnobase},
 133: 
 134:         {15,2,1,SSFLnobp},
 135:         {25,2,2,SSFLnobp},
 136:         {27,3,1,SSFLnobp},
 137:         {45,3,2,SSFLnobp},
 138:         {81,3,3,SSFLnobp},
 139: 
 140:         {16,3,1,SSFLnobase1 | SSFLnobase},
 141:         {32,3,2,SSFLnobase1 | SSFLnobase},
 142:         {64,3,3,SSFLnobase1 | SSFLnobase},
 143: };
 144: 
 145: int ssindex(int op,targ_uns product)
 146: {   int i;
 147: 
 148:     if (op == OPshl)
 149:         product = 1 << product;
 150:     for (i = 1; i < arraysize(ssindex_array); i++)
 151:     {
 152:         if (ssindex_array[i].product == product)
 153:             return i;
 154:     }
 155:     return 0;
 156: }
 157: 
 158: /***************************************
 159:  * Build an EA of the form disp[base][index*scale].
 160:  * Input:
 161:  *      c       struct to fill in
 162:  *      base    base register (-1 if none)
 163:  *      index   index register (-1 if none)
 164:  *      scale   scale factor - 1,2,4,8
 165:  *      disp    displacement
 166:  */
 167: 
 168: void buildEA(code *c,int base,int index,int scale,targ_size_t disp)
 169: {   unsigned char rm;
 170:     unsigned char sib;
 171:     unsigned char rex = 0;
 172: 
 173:     sib = 0;
 174:     if (!I16)
 175:     {   unsigned ss;
 176: 
 177:         assert(index != SP);
 178: 
 179:         switch (scale)
 180:         {   case 1:     ss = 0; break;
 181:             case 2:     ss = 1; break;
 182:             case 4:     ss = 2; break;
 183:             case 8:     ss = 3; break;
 184:             default:    assert(0);
 185:         }
 186: 
 187:         if (base == -1)
 188:         {
 189:             if (index == -1)
 190:                 rm = modregrm(0,0,5);
 191:             else
 192:             {
 193:                 rm  = modregrm(0,0,4);
 194:                 sib = modregrm(ss,index & 7,5);
 195:                 if (index & 8)
 196:                     rex |= REX_X;
 197:             }
 198:         }
 199:         else if (index == -1)
 200:         {
 201:             if (base == SP)
 202:             {
 203:                 rm  = modregrm(2,0,4);
 204:                 sib = modregrm(0,4,SP);
 205:             }
 206:             else
 207:             {   rm = modregrm(2,0,base & 7);
 208:                 if (base & 8)
 209:                 {   rex |= REX_B;
 210:                     if (base == R12)
 211:                     {
 212:                         rm = modregrm(2,0,4);
 213:                         sib = modregrm(0,4,4);
 214:                     }
 215:                 }
 216:             }
 217:         }
 218:         else
 219:         {
 220:             rm  = modregrm(2,0,4);
 221:             sib = modregrm(ss,index & 7,base & 7);
 222:             if (index & 8)
 223:                 rex |= REX_X;
 224:             if (base & 8)
 225:                 rex |= REX_B;
 226:         }
 227:     }
 228:     else
 229:     {
 230:         // -1 AX CX DX BX SP BP SI DI
 231:         static unsigned char EA16rm[9][9] =
 232:         {
 233:             {   0x06,0x09,0x09,0x09,0x87,0x09,0x86,0x84,0x85,   },      // -1
 234:             {   0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,   },      // AX
 235:             {   0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,   },      // CX
 236:             {   0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,   },      // DX
 237:             {   0x87,0x09,0x09,0x09,0x09,0x09,0x09,0x80,0x81,   },      // BX
 238:             {   0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,   },      // SP
 239:             {   0x86,0x09,0x09,0x09,0x09,0x09,0x09,0x82,0x83,   },      // BP
 240:             {   0x84,0x09,0x09,0x09,0x80,0x09,0x82,0x09,0x09,   },      // SI
 241:             {   0x85,0x09,0x09,0x09,0x81,0x09,0x83,0x09,0x09,   }       // DI
 242:         };
 243: 
 244:         assert(scale == 1);
 245:         rm = EA16rm[base + 1][index + 1];
 246:         assert(rm != 9);
 247:     }
 248:     c->Irm = rm;
 249:     c->Isib = sib;
 250:     c->Irex = rex;
 251:     c->IFL1 = FLconst;
 252:     c->IEV1.Vuns = disp;
 253: }
 254: 
 255: /*********************************************
 256:  * Build REX, modregrm and sib bytes
 257:  */
 258: 
 259: unsigned buildModregrm(int mod, int reg, int rm)
 260: {   unsigned m;
 261:     if (I16)
 262:         m = modregrm(mod, reg, rm);
 263:     else
 264:     {
 265:         if ((rm & 7) == SP && mod != 3)
 266:             m = (modregrm(0,4,SP) << 8) | modregrm(mod,reg & 7,4);
 267:         else
 268:             m = modregrm(mod,reg & 7,rm & 7);
 269:         if (reg & 8)
 270:             m |= REX_R << 16;
 271:         if (rm & 8)
 272:             m |= REX_B << 16;
 273:     }
 274:     return m;
 275: }
 276: 
 277: /**************************
 278:  * For elems in regcon that don't match regconsave,
 279:  * clear the corresponding bit in regcon.cse.mval.
 280:  * Do same for regcon.immed.
 281:  */
 282: 
 283: void andregcon(con_t *pregconsave)
 284: {
 285:     regm_t m = ~1;
 286:     for (int i = 0; i < REGMAX; i++)
 287:     {   if (pregconsave->cse.value[i] != regcon.cse.value[i])
 288:             regcon.cse.mval &= m;
 289:         if (pregconsave->immed.value[i] != regcon.immed.value[i])
 290:             regcon.immed.mval &= m;
 291:         m <<= 1;
 292:         m |= 1;
 293:     }
 294:     //printf("regcon.cse.mval = x%x, regconsave->mval = x%x ",regcon.cse.mval,pregconsave->cse.mval);
 295:     regcon.used |= pregconsave->used;
 296:     regcon.cse.mval &= pregconsave->cse.mval;
 297:     regcon.immed.mval &= pregconsave->immed.mval;
 298:     regcon.params &= pregconsave->params;
 299:     //printf("regcon.cse.mval&regcon.cse.mops = x%x, regcon.cse.mops = x%x\n",regcon.cse.mval & regcon.cse.mops,regcon.cse.mops);
 300:     regcon.cse.mops &= regcon.cse.mval;
 301: }
 302: 
 303: /*********************************
 304:  * Scan down comma-expressions.
 305:  * Output:
 306:  *      *pe = first elem down right side that is not an OPcomma
 307:  * Returns:
 308:  *      code generated for left branches of comma-expressions
 309:  */
 310: 
 311: code *docommas(elem **pe)
 312: {   elem *e;
 313:     code *cc;
 314:     unsigned stackpushsave;
 315:     int stackcleansave;
 316: 
 317:     stackpushsave = stackpush;
 318:     stackcleansave = cgstate.stackclean;
 319:     cgstate.stackclean = 0;
 320:     cc = CNIL;
 321:     e = *pe;
 322:     while (1)
 323:     {   elem *eold;
 324:         regm_t retregs;
 325: 
 326:         if (configv.addlinenumbers && e->Esrcpos.Slinnum)
 327:         {       cc = genlinnum(cc,e->Esrcpos);
 328:                 //e->Esrcpos.Slinnum = 0;               // don't do it twice
 329:         }
 330:         if (e->Eoper != OPcomma)
 331:                 break;
 332:         retregs = 0;
 333:         cc = cat(cc,codelem(e->E1,&retregs,TRUE));
 334:         eold = e;
 335:         e = e->E2;
 336:         freenode(eold);
 337:     }
 338:     *pe = e;
 339:     assert(cgstate.stackclean == 0);
 340:     cgstate.stackclean = stackcleansave;
 341:     cc = genstackclean(cc,stackpush - stackpushsave,0);
 342:     return cc;
 343: }
 344: 
 345: /****************************************
 346:  * Clean stack after call to codelem().
 347:  */
 348: 
 349: code *gencodelem(code *c,elem *e,regm_t *pretregs,bool constflag)
 350: {
 351:     if (e)
 352:     {
 353:         unsigned stackpushsave;
 354:         int stackcleansave;
 355: 
 356:         stackpushsave = stackpush;
 357:         stackcleansave = cgstate.stackclean;
 358:         cgstate.stackclean = 0;                         // defer cleaning of stack
 359:         c = cat(c,codelem(e,pretregs,constflag));
 360:         assert(cgstate.stackclean == 0);
 361:         cgstate.stackclean = stackcleansave;
 362:         c = genstackclean(c,stackpush - stackpushsave,*pretregs);       // do defered cleaning
 363:     }
 364:     return c;
 365: }
 366: 
 367: /********************************************
 368:  * Gen a save/restore sequence for mask of registers.
 369:  */
 370: 
 371: void gensaverestore2(regm_t regm,code **csave,code **crestore)
 372: {
 373:     code *cs1 = *csave;
 374:     code *cs2 = *crestore;
 375: 
 376:     //printf("gensaverestore2(%s)\n", regm_str(regm));
 377:     regm &= mBP | mES | ALLREGS | XMMREGS;
 378:     for (int i = 0; regm; i++)
 379:     {
 380:         if (regm & 1)
 381:         {
 382:             if (i == ES)
 383:             {
 384:                 cs1 = gen1(cs1, 0x06);                  // PUSH ES
 385:                 cs2 = cat(gen1(CNIL, 0x07),cs2);        // POP  ES
 386:             }
 387:             else if (i >= XMM0)
 388:             {   unsigned idx;
 389:                 cs1 = regsave.save(cs1, i, &idx);
 390:                 cs2 = regsave.restore(cs2, i, idx);
 391:             }
 392:             else
 393:             {
 394:                 cs1 = gen1(cs1,0x50 + (i & 7));         // PUSH i
 395:                 code *c = gen1(NULL, 0x58 + (i & 7));   // POP  i
 396:                 if (i & 8)
 397:                 {   code_orrex(cs1, REX_B);
 398:                     code_orrex(c, REX_B);
 399:                 }
 400:                 cs2 = cat(c,cs2);
 401:             }
 402:         }
 403:         regm >>= 1;
 404:     }
 405:     *csave = cs1;
 406:     *crestore = cs2;
 407: }
 408: 
 409: void gensaverestore(regm_t regm,code **csave,code **crestore)
 410: {
 411:     *csave = NULL;
 412:     *crestore = NULL;
 413:     gensaverestore2(regm, csave, crestore);
 414: }
 415: 
 416: /****************************************
 417:  * Clean parameters off stack.
 418:  * Input:
 419:  *      numpara         amount to adjust stack pointer
 420:  *      keepmsk         mask of registers to not destroy
 421:  */
 422: 
 423: code *genstackclean(code *c,unsigned numpara,regm_t keepmsk)
 424: {
 425:     //dbg_printf("genstackclean(numpara = %d, stackclean = %d)\n",numpara,cgstate.stackclean);
 426:     if (numpara && (cgstate.stackclean || STACKALIGN == 16))
 427:     {
 428: #if 0       // won't work if operand of scodelem
 429:         if (numpara == stackpush &&             // if this is all those pushed
 430:             needframe &&                        // and there will be a BP
 431:             !config.windows &&
 432:             !(regcon.mvar & fregsaved)          // and no registers will be pushed
 433:         )
 434:             c = genregs(c,0x89,BP,SP);  // MOV SP,BP
 435:         else
 436: #endif
 437:         {   regm_t scratchm = 0;
 438: 
 439:             if (numpara == REGSIZE && config.flags4 & CFG4space)
 440:             {
 441:                 scratchm = ALLREGS & ~keepmsk & regcon.used & ~regcon.mvar;
 442:             }
 443: 
 444:             if (scratchm)
 445:             {   unsigned r;
 446:                 c = cat(c,allocreg(&scratchm,&r,TYint));
 447:                 c = gen1(c,0x58 + r);           // POP r
 448:             }
 449:             else
 450:             {   c = genc2(c,0x81,modregrm(3,0,SP),numpara); // ADD SP,numpara
 451:                 if (I64)
 452:                     code_orrex(c, REX_W);
 453:             }
 454:         }
 455:         stackpush -= numpara;
 456:         c = genadjesp(c,-numpara);
warning C4146: unary minus operator applied to unsigned type, result still unsigned
457: } 458: return c; 459: } 460: 461: 462: /********************************* 463: * Generate code for a logical expression. 464: * Input: 465: * e elem 466: * jcond 467: * bit 1 if TRUE then goto jump address if e 468: * if FALSE then goto jump address if !e 469: * 2 don't call save87() 470: * fltarg FLcode or FLblock, flavor of target if e evaluates to jcond 471: * targ either code or block pointer to destination 472: */ 473: 474: code *logexp(elem *e,int jcond,unsigned fltarg,code *targ) 475: { code *c,*ce,*cnop; 476: regm_t retregs; 477: unsigned op; 478: 479: //printf("logexp(e = %p, jcond = %d)\n", e, jcond); 480: int no87 = (jcond & 2) == 0; 481: _chkstack(); 482: code *cc = docommas(&e); // scan down commas 483: cgstate.stackclean++; 484: 485: if (EOP(e) && !e->Ecount) /* if operator and not common sub */ 486: { con_t regconsave; 487: 488: switch (e->Eoper) 489: { case OPoror: 490: if (jcond & 1) 491: { c = logexp(e->E1,jcond,fltarg,targ); 492: regconsave = regcon; 493: ce = logexp(e->E2,jcond,fltarg,targ); 494: } 495: else 496: { cnop = gennop(CNIL); 497: c = logexp(e->E1,jcond | 1,FLcode,cnop); 498: regconsave = regcon; 499: ce = logexp(e->E2,jcond,fltarg,targ); 500: ce = cat(ce,cnop); 501: } 502: cnop = CNIL; 503: goto L1; 504: 505: case OPandand: 506: if (jcond & 1) 507: { cnop = gennop(CNIL); /* a dummy target address */ 508: c = logexp(e->E1,jcond & ~1,FLcode,cnop); 509: regconsave = regcon; 510: ce = logexp(e->E2,jcond,fltarg,targ); 511: } 512: else 513: { c = logexp(e->E1,jcond,fltarg,targ); 514: regconsave = regcon; 515: ce = logexp(e->E2,jcond,fltarg,targ); 516: cnop = CNIL; 517: } 518: L1: andregcon(&regconsave); 519: freenode(e); 520: c = cat4(cc,c,ce,cnop); 521: goto Lret; 522: 523: case OPnot: 524: jcond ^= 1; 525: case OPbool: 526: case OPs8int: 527: case OPu8int: 528: case OPs16_32: 529: case OPu16_32: 530: case OPs32_64: 531: case OPu32_64: 532: case OPu32_d: 533: case OPd_ld: 534: c = logexp(e->E1,jcond,fltarg,targ); 535: freenode(e); 536: goto Lretc; 537: 538: case OPcond: 539: { 540: code *cnop2 = gennop(CNIL); // addresses of start of leaves 541: cnop = gennop(CNIL); 542: c = logexp(e->E1,FALSE,FLcode,cnop2); /* eval condition */ 543: con_t regconold = regcon; 544: ce = logexp(e->E2->E1,jcond,fltarg,targ); 545: ce = genjmp(ce,JMP,FLcode,(block *) cnop); /* skip second leaf */ 546: 547: regconsave = regcon; 548: regcon = regconold; 549: 550: code_next(cnop2) = logexp(e->E2->E2,jcond,fltarg,targ); 551: andregcon(&regconold); 552: andregcon(&regconsave); 553: freenode(e->E2); 554: freenode(e); 555: c = cat6(cc,c,NULL,ce,cnop2,cnop); 556: goto Lret; 557: } 558: } 559: } 560: 561: /* Special code for signed long compare. 562: * Not necessary for I64 until we do cents. 563: */ 564: if (OTrel2(e->Eoper) && /* if < <= >= > */ 565: !e->Ecount && 566: ( (I16 && tybasic(e->E1->Ety) == TYlong && tybasic(e->E2->Ety) == TYlong) || 567: (I32 && tybasic(e->E1->Ety) == TYllong && tybasic(e->E2->Ety) == TYllong)) 568: ) 569: { 570: c = longcmp(e,jcond,fltarg,targ);
warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
571: goto Lretc; 572: } 573: 574: retregs = mPSW; /* return result in flags */ 575: op = jmpopcode(e); /* get jump opcode */ 576: if (!(jcond & 1)) 577: op ^= 0x101; // toggle jump condition(s) 578: c = codelem(e,&retregs,TRUE); /* evaluate elem */ 579: if (no87) 580: c = cat(c,cse_flush(no87)); // flush CSE's to memory 581: genjmp(c,op,fltarg,(block *) targ); /* generate jmp instruction */ 582: Lretc: 583: c = cat(cc,c); 584: Lret: 585: cgstate.stackclean--; 586: return c; 587: } 588: 589: 590: /****************************** 591: * Routine to aid in setting things up for gen(). 592: * Look for common subexpression. 593: * Can handle indirection operators, but not if they're common subs. 594: * Input: 595: * e -> elem where we get some of the data from 596: * cs -> partially filled code to add 597: * op = opcode 598: * reg = reg field of (mod reg r/m) 599: * offset = data to be added to Voffset field 600: * keepmsk = mask of registers we must not destroy 601: * desmsk = mask of registers destroyed by executing the instruction 602: * Returns: 603: * pointer to code generated 604: */ 605: 606: code *loadea(elem *e,code *cs,unsigned op,unsigned reg,targ_size_t offset, 607: regm_t keepmsk,regm_t desmsk) 608: { 609: code *c,*cg,*cd; 610: 611: #ifdef DEBUG 612: if (debugw) 613: printf("loadea: e=%p cs=%p op=x%x reg=%d offset=%lld keepmsk=x%x desmsk=x%x\n", 614: e,cs,op,reg,(unsigned long long)offset,keepmsk,desmsk); 615: #endif 616: 617: assert(e); 618: cs->Iflags = 0; 619: cs->Irex = 0; 620: cs->Iop = op; 621: tym_t tym = e->Ety; 622: int sz = tysize(tym); 623: 624: /* Determine if location we want to get is in a register. If so, */ 625: /* substitute the register for the EA. */ 626: /* Note that operators don't go through this. CSE'd operators are */ 627: /* picked up by comsub(). */ 628: if (e->Ecount && /* if cse */ 629: e->Ecount != e->Ecomsub && /* and cse was generated */ 630: op != 0x8D && op != 0xC4 && /* and not an LEA or LES */ 631: (op != 0xFF || reg != 3) && /* and not CALLF MEM16 */ 632: (op & 0xFFF8) != 0xD8) // and not 8087 opcode 633: { 634: assert(!EOP(e)); /* can't handle this */ 635: regm_t rm = regcon.cse.mval & ~regcon.cse.mops & ~regcon.mvar; // possible regs 636: if (sz > REGSIZE) // value is in 2 or 4 registers 637: { 638: if (I16 && sz == 8) // value is in 4 registers 639: { static regm_t rmask[4] = { mDX,mCX,mBX,mAX }; 640: rm &= rmask[offset >> 1]; 641: } 642: 643: else if (offset) 644: rm &= mMSW; /* only high words */ 645: else 646: rm &= mLSW; /* only low words */ 647: } 648: for (unsigned i = 0; rm; i++) 649: { if (mask[i] & rm) 650: { if (regcon.cse.value[i] == e && // if register has elem 651: /* watch out for a CWD destroying DX */ 652: !(i == DX && op == 0xF7 && desmsk & mDX)) 653: { 654: /* if ES, then it can only be a load */ 655: if (i == ES) 656: { if (op != 0x8B) 657: goto L1; /* not a load */ 658: cs->Iop = 0x8C; /* MOV reg,ES */ 659: cs->Irm = modregrm(3,0,reg & 7); 660: if (reg & 8) 661: code_orrex(cs, REX_B); 662: } 663: else // XXX reg,i 664: { 665: cs->Irm = modregrm(3,reg & 7,i & 7); 666: if (reg & 8) 667: cs->Irex |= REX_R; 668: if (i & 8) 669: cs->Irex |= REX_B; 670: if (sz == 1 && I64 && (i >= 4 || reg >= 4)) 671: cs->Irex |= REX; 672: if (I64 && (sz == 8 || sz == 16)) 673: cs->Irex |= REX_W; 674: } 675: c = CNIL; 676: goto L2; 677: } 678: rm &= ~mask[i]; 679: } 680: } 681: } 682: 683: L1: 684: c = getlvalue(cs,e,keepmsk); 685: if (offset == REGSIZE) 686: getlvalue_msw(cs); 687: else 688: cs->IEVoffset1 += offset; 689: if (I64) 690: { if (reg >= 4 && sz == 1) // if byte register 691: // Can only address those 8 bit registers if a REX byte is present 692: cs->Irex |= REX; 693: if ((op & 0xFFFFFFF8) == 0xD8) 694: cs->Irex &= ~REX_W; // not needed for x87 ops 695: } 696: code_newreg(cs, reg); // OR in reg field 697: if (!I16) 698: { 699: if (reg == 6 && op == 0xFF || /* don't PUSH a word */ 700: op == 0x0FB7 || op == 0x0FBF || /* MOVZX/MOVSX */ 701: (op & 0xFFF8) == 0xD8 || /* 8087 instructions */ 702: op == 0x8D) /* LEA */ 703: { 704: cs->Iflags &= ~CFopsize; 705: if (reg == 6 && op == 0xFF) // if PUSH 706: cs->Irex &= ~REX_W; // REX is ignored for PUSH anyway 707: } 708: } 709: else if ((op & 0xFFF8) == 0xD8 && ADDFWAIT()) 710: cs->Iflags |= CFwait; 711: L2: 712: cg = getregs(desmsk); /* save any regs we destroy */ 713: 714: /* KLUDGE! fix up DX for divide instructions */ 715: cd = CNIL; 716: if (op == 0xF7 && desmsk == (mAX|mDX)) /* if we need to fix DX */ 717: { if (reg == 7) /* if IDIV */ 718: { cd = gen1(cd,0x99); // CWD 719: if (I64 && sz == 8) 720: code_orrex(cd, REX_W); 721: } 722: else if (reg == 6) // if DIV 723: { cd = genregs(cd,0x33,DX,DX); // XOR DX,DX 724: if (I64 && sz == 8) 725: code_orrex(cd, REX_W); 726: } 727: } 728: 729: // Eliminate MOV reg,reg 730: if ((cs->Iop & ~3) == 0x88 && 731: (cs->Irm & 0xC7) == modregrm(3,0,reg & 7)) 732: { 733: unsigned r = cs->Irm & 7; 734: if (cs->Irex & REX_B) 735: r |= 8; 736: if (r == reg) 737: cs->Iop = NOP; 738: } 739: 740: return cat4(c,cg,cd,gen(NULL,cs)); 741: } 742: 743: /************************** 744: * Get addressing mode. 745: */ 746: 747: unsigned getaddrmode(regm_t idxregs) 748: { 749: unsigned mode; 750: 751: if (I16) 752: { 753: mode = (idxregs & mBX) ? modregrm(2,0,7) : /* [BX] */ 754: (idxregs & mDI) ? modregrm(2,0,5): /* [DI] */ 755: (idxregs & mSI) ? modregrm(2,0,4): /* [SI] */ 756: (assert(0),1); 757: } 758: else 759: { unsigned reg = findreg(idxregs & (ALLREGS | mBP)); 760: if (reg == R12) 761: mode = (REX_B << 16) | (modregrm(0,4,4) << 8) | modregrm(2,0,4); 762: else 763: mode = modregrmx(2,0,reg); 764: } 765: return mode; 766: } 767: 768: void setaddrmode(code *c, regm_t idxregs) 769: { 770: unsigned mode = getaddrmode(idxregs); 771: c->Irm = mode & 0xFF; 772: c->Isib = mode >> 8; 773: c->Irex &= ~REX_B; 774: c->Irex |= mode >> 16; 775: } 776: 777: /********************************************** 778: */ 779: 780: void getlvalue_msw(code *c) 781: { 782: if (c->IFL1 == FLreg) 783: { 784: unsigned regmsw = c->IEVsym1->Sregmsw; 785: c->Irm = (c->Irm & ~7) | (regmsw & 7); 786: if (regmsw & 8) 787: c->Irex |= REX_B; 788: else 789: c->Irex &= ~REX_B; 790: } 791: else 792: c->IEVoffset1 += REGSIZE; 793: } 794: 795: /********************************************** 796: */ 797: 798: void getlvalue_lsw(code *c) 799: { 800: if (c->IFL1 == FLreg) 801: { 802: unsigned reglsw = c->IEVsym1->Sreglsw; 803: c->Irm = (c->Irm & ~7) | (reglsw & 7); 804: if (reglsw & 8) 805: c->Irex |= REX_B; 806: else 807: c->Irex &= ~REX_B; 808: } 809: else 810: c->IEVoffset1 -= REGSIZE; 811: } 812: 813: /****************** 814: * Compute addressing mode. 815: * Generate & return sequence of code (if any). 816: * Return in cs the info on it. 817: * Input: 818: * pcs -> where to store data about addressing mode 819: * e -> the lvalue elem 820: * keepmsk mask of registers we must not destroy or use 821: * if (keepmsk & RMstore), this will be only a store operation 822: * into the lvalue 823: * if (keepmsk & RMload), this will be a read operation only 824: */ 825: 826: code *getlvalue(code *pcs,elem *e,regm_t keepmsk) 827: { regm_t idxregs; 828: unsigned fl,f,opsave; 829: code *c; 830: elem *e1; 831: elem *e11; 832: elem *e12; 833: bool e1isadd,e1free; 834: unsigned reg; 835: tym_t e1ty; 836: symbol *s; 837: 838: //printf("getlvalue(e = %p)\n",e); 839: //elem_print(e); 840: assert(e); 841: elem_debug(e); 842: if (e->Eoper == OPvar || e->Eoper == OPrelconst) 843: { s = e->EV.sp.Vsym; 844: fl = s->Sfl; 845: if (tyfloating(s->ty())) 846: obj_fltused(); 847: } 848: else 849: fl = FLoper; 850: pcs->IFL1 = fl; 851: pcs->Iflags = CFoff; /* only want offsets */ 852: pcs->Irex = 0; 853: pcs->IEVoffset1 = 0; 854: 855: tym_t ty = e->Ety; 856: unsigned sz = tysize(ty); 857: if (tyfloating(ty)) 858: obj_fltused(); 859: if (I64 && (sz == 8 || sz == 16)) 860: pcs->Irex |= REX_W; 861: if (!I16 && sz == SHORTSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
862: pcs->Iflags |= CFopsize; 863: if (ty & mTYvolatile) 864: pcs->Iflags |= CFvolatile; 865: c = CNIL; 866: switch (fl) 867: { 868: #if 0 && TARGET_LINUX 869: case FLgot: 870: case FLgotoff: 871: gotref = 1; 872: pcs->IEVsym1 = s; 873: pcs->IEVoffset1 = e->EV.sp.Voffset; 874: if (e->Eoper == OPvar && fl == FLgot) 875: { 876: code *c1; 877: unsigned saveop = pcs->Iop; 878: idxregs = allregs & ~keepmsk; // get a scratch register 879: c = allocreg(&idxregs,&reg,TYptr); 880: pcs->Irm = modregrm(2,reg,BX); // BX has GOT 881: pcs->Isib = 0; 882: //pcs->Iflags |= CFvolatile; 883: pcs->Iop = 0x8B; 884: c = gen(c,pcs); // MOV reg,disp[EBX] 885: pcs->Irm = modregrm(0,0,reg); 886: pcs->IEVoffset1 = 0; 887: pcs->Iop = saveop; 888: } 889: else 890: { 891: pcs->Irm = modregrm(2,0,BX); // disp[EBX] is addr 892: pcs->Isib = 0; 893: } 894: break; 895: #endif 896: case FLoper: 897: #ifdef DEBUG 898: if (debugw) printf("getlvalue(e = %p, km = x%x)\n",e,keepmsk); 899: #endif 900: switch (e->Eoper) 901: { 902: case OPadd: // this way when we want to do LEA 903: e1 = e; 904: e1free = FALSE; 905: e1isadd = TRUE; 906: break; 907: case OPind: 908: case OPpostinc: // when doing (*p++ = ...) 909: case OPpostdec: // when doing (*p-- = ...) 910: case OPbt: 911: case OPbtc: 912: case OPbtr: 913: case OPbts: 914: e1 = e->E1; 915: e1free = TRUE; 916: e1isadd = e1->Eoper == OPadd; 917: break; 918: default: 919: #ifdef DEBUG 920: elem_print(e); 921: #endif 922: assert(0); 923: } 924: e1ty = tybasic(e1->Ety); 925: if (e1isadd) 926: { e12 = e1->E2; 927: e11 = e1->E1; 928: } 929: 930: /* First see if we can replace *(e+&v) with 931: * MOV idxreg,e 932: * EA = [ES:] &v+idxreg 933: */ 934: f = FLconst; 935: if (e1isadd && 936: ((e12->Eoper == OPrelconst && (f = el_fl(e12)) != FLfardata) || 937: (e12->Eoper == OPconst && !I16 && !e1->Ecount && (!I64 || el_signx32(e12)))) &&
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
938: !(I64 && config.flags3 & CFG3pic) && 939: e1->Ecount == e1->Ecomsub && 940: (!e1->Ecount || (~keepmsk & ALLREGS & mMSW) || (e1ty != TYfptr && e1ty != TYhptr)) && 941: tysize(e11->Ety) == REGSIZE 942: ) 943: { unsigned char t; /* component of r/m field */ 944: int ss; 945: int ssi; 946: 947: /*assert(datafl[f]);*/ /* what if addr of func? */ 948: if (!I16) 949: { /* Any register can be an index register */ 950: regm_t idxregs = allregs & ~keepmsk;
warning C6246: Local declaration of 'idxregs' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '827' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 827
951: assert(idxregs); 952: 953: /* See if e1->E1 can be a scaled index */ 954: ss = isscaledindex(e11); 955: if (ss) 956: { 957: /* Load index register with result of e11->E1 */ 958: c = cdisscaledindex(e11,&idxregs,keepmsk); 959: reg = findreg(idxregs); 960: #if 0 && TARGET_LINUX 961: if (f == FLgot || f == FLgotoff) // config.flags3 & CFG3pic 962: { 963: gotref = 1; 964: pcs->Irm = modregrm(2,0,4); 965: pcs->Isib = modregrm(ss,reg,BX); 966: } 967: else 968: #endif 969: { 970: t = stackfl[f] ? 2 : 0; 971: pcs->Irm = modregrm(t,0,4); 972: pcs->Isib = modregrm(ss,reg & 7,5); 973: if (reg & 8) 974: pcs->Irex |= REX_X; 975: } 976: } 977: else if ((e11->Eoper == OPmul || e11->Eoper == OPshl) && 978: !e11->Ecount && 979: e11->E2->Eoper == OPconst && 980: (ssi = ssindex(e11->Eoper,e11->E2->EV.Vuns)) != 0 981: ) 982: { 983: regm_t scratchm; 984: 985: #if 0 && TARGET_LINUX 986: assert(f != FLgot && f != FLgotoff); 987: #endif 988: char ssflags = ssindex_array[ssi].ssflags; 989: if (ssflags & SSFLnobp && stackfl[f]) 990: goto L6; 991: 992: // Load index register with result of e11->E1 993: c = scodelem(e11->E1,&idxregs,keepmsk,TRUE); 994: reg = findreg(idxregs); 995: 996: int ss1 = ssindex_array[ssi].ss1; 997: if (ssflags & SSFLlea) 998: { 999: assert(!stackfl[f]); 1000: pcs->Irm = modregrm(2,0,4); 1001: pcs->Isib = modregrm(ss1,reg & 7,reg & 7); 1002: if (reg & 8) 1003: pcs->Irex |= REX_X | REX_B; 1004: } 1005: else 1006: { int rbase; 1007: unsigned r; 1008: 1009: scratchm = ALLREGS & ~keepmsk; 1010: c = cat(c,allocreg(&scratchm,&r,TYint)); 1011: 1012: if (ssflags & SSFLnobase1) 1013: { t = 0; 1014: rbase = 5; 1015: } 1016: else 1017: { t = 0; 1018: rbase = reg; 1019: if (rbase == BP || rbase == R13) 1020: { static unsigned imm32[4] = {1+1,2+1,4+1,8+1}; 1021: 1022: // IMUL r,BP,imm32 1023: c = genc2(c,0x69,modregxrmx(3,r,rbase),imm32[ss1]); 1024: goto L7; 1025: } 1026: } 1027: 1028: c = gen2sib(c,0x8D,modregxrm(t,r,4),modregrm(ss1,reg & 7,rbase & 7)); 1029: if (reg & 8) 1030: code_orrex(c, REX_X); 1031: if (rbase & 8) 1032: code_orrex(c, REX_B); 1033: if (I64) 1034: code_orrex(c, REX_W); 1035: 1036: if (ssflags & SSFLnobase1) 1037: { code_last(c)->IFL1 = FLconst; 1038: code_last(c)->IEV1.Vuns = 0; 1039: } 1040: L7: 1041: if (ssflags & SSFLnobase) 1042: { t = stackfl[f] ? 2 : 0; 1043: rbase = 5; 1044: } 1045: else 1046: { t = 2; 1047: rbase = r; 1048: assert(rbase != BP); 1049: } 1050: pcs->Irm = modregrm(t,0,4); 1051: pcs->Isib = modregrm(ssindex_array[ssi].ss2,r & 7,rbase & 7); 1052: if (r & 8) 1053: pcs->Irex |= REX_X; 1054: if (rbase & 8) 1055: pcs->Irex |= REX_B; 1056: } 1057: freenode(e11->E2); 1058: freenode(e11); 1059: } 1060: else 1061: { 1062: L6: 1063: /* Load index register with result of e11 */ 1064: c = scodelem(e11,&idxregs,keepmsk,TRUE); 1065: setaddrmode(pcs, idxregs); 1066: #if 0 && TARGET_LINUX 1067: if (e12->EV.sp.Vsym->Sfl == FLgot || e12->EV.sp.Vsym->Sfl == FLgotoff) 1068: { 1069: gotref = 1; 1070: #if 1 1071: reg = findreg(idxregs & (ALLREGS | mBP)); 1072: pcs->Irm = modregrm(2,0,4); 1073: pcs->Isib = modregrm(0,reg,BX); 1074: #else 1075: pcs->Isib = modregrm(0,pcs->Irm,BX); 1076: pcs->Irm = modregrm(2,0,4); 1077: #endif 1078: } 1079: else 1080: #endif 1081: if (stackfl[f]) /* if we need [EBP] too */ 1082: { unsigned idx = pcs->Irm & 7; 1083: if (pcs->Irex & REX_B) 1084: pcs->Irex = (pcs->Irex & ~REX_B) | REX_X; 1085: pcs->Isib = modregrm(0,idx,BP); 1086: pcs->Irm = modregrm(2,0,4); 1087: } 1088: } 1089: } 1090: else 1091: { 1092: idxregs = IDXREGS & ~keepmsk; /* only these can be index regs */ 1093: assert(idxregs); 1094: #if 0 && TARGET_LINUX 1095: assert(f != FLgot && f != FLgotoff); 1096: #endif 1097: if (stackfl[f]) /* if stack data type */ 1098: { idxregs &= mSI | mDI; /* BX can't index off stack */ 1099: if (!idxregs) goto L1; /* index regs aren't avail */ 1100: t = 6; /* [BP+SI+disp] */ 1101: } 1102: else 1103: t = 0; /* [SI + disp] */ 1104: c = scodelem(e11,&idxregs,keepmsk,TRUE); /* load idx reg */ 1105: pcs->Irm = getaddrmode(idxregs) ^ t; 1106: } 1107: if (f == FLpara) 1108: refparam = TRUE; 1109: else if (f == FLauto || f == FLtmp || f == FLbprel || f == FLfltreg) 1110: reflocal = TRUE; 1111: else if (f == FLcsdata || tybasic(e12->Ety) == TYcptr) 1112: pcs->Iflags |= CFcs; 1113: else 1114: assert(f != FLreg); 1115: pcs->IFL1 = f; 1116: if (f != FLconst) 1117: pcs->IEVsym1 = e12->EV.sp.Vsym; 1118: pcs->IEVoffset1 = e12->EV.sp.Voffset; /* += ??? */ 1119: 1120: /* If e1 is a CSE, we must generate an addressing mode */ 1121: /* but also leave EA in registers so others can use it */ 1122: if (e1->Ecount) 1123: { unsigned flagsave; 1124: 1125: idxregs = IDXREGS & ~keepmsk; 1126: c = cat(c,allocreg(&idxregs,&reg,TYoffset)); 1127: 1128: /* If desired result is a far pointer, we'll have */ 1129: /* to load another register with the segment of v */ 1130: if (e1ty == TYfptr) 1131: { 1132: unsigned msreg; 1133: 1134: idxregs |= mMSW & ALLREGS & ~keepmsk; 1135: c = cat(c,allocreg(&idxregs,&msreg,TYfptr)); 1136: msreg = findregmsw(idxregs); 1137: /* MOV msreg,segreg */ 1138: c = genregs(c,0x8C,segfl[f],msreg); 1139: } 1140: opsave = pcs->Iop; 1141: flagsave = pcs->Iflags; 1142: pcs->Iop = 0x8D; 1143: code_newreg(pcs, reg); 1144: if (!I16) 1145: pcs->Iflags &= ~CFopsize; 1146: if (I64) 1147: pcs->Irex |= REX_W; 1148: c = gen(c,pcs); /* LEA idxreg,EA */ 1149: cssave(e1,idxregs,TRUE); 1150: if (!I16) 1151: pcs->Iflags = flagsave; 1152: if (stackfl[f] && (config.wflags & WFssneds)) // if pointer into stack 1153: pcs->Iflags |= CFss; // add SS: override 1154: pcs->Iop = opsave; 1155: pcs->IFL1 = FLoffset; 1156: pcs->IEV1.Vuns = 0; 1157: setaddrmode(pcs, idxregs); 1158: } 1159: freenode(e12); 1160: if (e1free) 1161: freenode(e1); 1162: goto Lptr; 1163: } 1164: 1165: L1: 1166: 1167: /* The rest of the cases could be a far pointer */ 1168: 1169: idxregs = (I16 ? IDXREGS : allregs) & ~keepmsk; // only these can be index regs 1170: assert(idxregs); 1171: if (!I16 &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1172: (sz == REGSIZE || (I64 && sz == 4)) && 1173: keepmsk & RMstore) 1174: idxregs |= regcon.mvar; 1175: 1176: #if !TARGET_FLAT 1177: switch (e1ty) 1178: { case TYfptr: /* if far pointer */ 1179: case TYhptr: 1180: idxregs = (mES | IDXREGS) & ~keepmsk; // need segment too 1181: assert(idxregs & mES); 1182: pcs->Iflags |= CFes; /* ES segment override */ 1183: break; 1184: case TYsptr: /* if pointer to stack */ 1185: if (config.wflags & WFssneds) // if SS != DS 1186: pcs->Iflags |= CFss; /* then need SS: override */ 1187: break; 1188: case TYcptr: /* if pointer to code */ 1189: pcs->Iflags |= CFcs; /* then need CS: override */ 1190: break; 1191: } 1192: #endif 1193: pcs->IFL1 = FLoffset; 1194: pcs->IEV1.Vuns = 0; 1195: 1196: /* see if we can replace *(e+c) with 1197: * MOV idxreg,e 1198: * [MOV ES,segment] 1199: * EA = [ES:]c[idxreg] 1200: */ 1201: if (e1isadd && e12->Eoper == OPconst && 1202: (!I64 || el_signx32(e12)) && 1203: (tysize(e12->Ety) == REGSIZE || (I64 && tysize(e12->Ety) == 4)) && 1204: (!e1->Ecount || !e1free) 1205: ) 1206: { int ss; 1207: 1208: pcs->IEV1.Vuns = e12->EV.Vuns; 1209: freenode(e12); 1210: if (e1free) freenode(e1); 1211: if (!I16 && e11->Eoper == OPadd && !e11->Ecount &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1212: tysize(e11->Ety) == REGSIZE) 1213: { 1214: e12 = e11->E2; 1215: e11 = e11->E1; 1216: e1 = e1->E1; 1217: e1free = TRUE; 1218: goto L4; 1219: } 1220: if (!I16 && (ss = isscaledindex(e11)) != 0)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1221: { // (v * scale) + const 1222: c = cdisscaledindex(e11,&idxregs,keepmsk); 1223: reg = findreg(idxregs); 1224: pcs->Irm = modregrm(0,0,4); 1225: pcs->Isib = modregrm(ss,reg & 7,5); 1226: if (reg & 8) 1227: pcs->Irex |= REX_X; 1228: } 1229: else 1230: { 1231: c = scodelem(e11,&idxregs,keepmsk,TRUE); // load index reg 1232: setaddrmode(pcs, idxregs); 1233: } 1234: goto Lptr; 1235: } 1236: 1237: /* Look for *(v1 + v2) 1238: * EA = [v1][v2] 1239: */ 1240: 1241: if (!I16 && e1isadd && (!e1->Ecount || !e1free) &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1242: (tysize[e1ty] == REGSIZE || (I64 && tysize[e1ty] == 4))) 1243: { code *c2; 1244: regm_t idxregs2; 1245: unsigned base,index; 1246: int ss; 1247: 1248: L4: 1249: // Look for *(v1 + v2 << scale) 1250: ss = isscaledindex(e12); 1251: if (ss) 1252: { 1253: c = scodelem(e11,&idxregs,keepmsk,TRUE); 1254: idxregs2 = allregs & ~(idxregs | keepmsk); 1255: c2 = cdisscaledindex(e12,&idxregs2,keepmsk | idxregs); 1256: } 1257: 1258: // Look for *(v1 << scale + v2) 1259: else if ((ss = isscaledindex(e11)) != 0) 1260: { 1261: idxregs2 = idxregs; 1262: c = cdisscaledindex(e11,&idxregs2,keepmsk); 1263: idxregs = allregs & ~(idxregs2 | keepmsk); 1264: c2 = scodelem(e12,&idxregs,keepmsk | idxregs2,TRUE); 1265: } 1266: // Look for *(((v1 << scale) + c1) + v2) 1267: else if (e11->Eoper == OPadd && !e11->Ecount && 1268: e11->E2->Eoper == OPconst && 1269: (ss = isscaledindex(e11->E1)) != 0 1270: ) 1271: { 1272: pcs->IEV1.Vuns = e11->E2->EV.Vuns; 1273: idxregs2 = idxregs; 1274: c = cdisscaledindex(e11->E1,&idxregs2,keepmsk); 1275: idxregs = allregs & ~(idxregs2 | keepmsk); 1276: c2 = scodelem(e12,&idxregs,keepmsk | idxregs2,TRUE); 1277: freenode(e11->E2); 1278: freenode(e11); 1279: } 1280: else 1281: { 1282: c = scodelem(e11,&idxregs,keepmsk,TRUE); 1283: idxregs2 = allregs & ~(idxregs | keepmsk); 1284: c2 = scodelem(e12,&idxregs2,keepmsk | idxregs,TRUE); 1285: } 1286: c = cat(c,c2); 1287: base = findreg(idxregs); 1288: index = findreg(idxregs2); 1289: pcs->Irm = modregrm(2,0,4); 1290: pcs->Isib = modregrm(ss,index & 7,base & 7); 1291: if (index & 8) 1292: pcs->Irex |= REX_X; 1293: if (base & 8) 1294: pcs->Irex |= REX_B; 1295: if (e1free) freenode(e1); 1296: goto Lptr; 1297: } 1298: 1299: /* give up and replace *e1 with 1300: * MOV idxreg,e 1301: * EA = 0[idxreg] 1302: * pinholeopt() will usually correct the 0, we need it in case 1303: * we have a pointer to a long and need an offset to the second 1304: * word. 1305: */ 1306: 1307: assert(e1free); 1308: c = scodelem(e1,&idxregs,keepmsk,TRUE); /* load index register */ 1309: setaddrmode(pcs, idxregs); 1310: Lptr: 1311: if (config.flags3 & CFG3ptrchk) 1312: cod3_ptrchk(&c,pcs,keepmsk); // validate pointer code 1313: break; 1314: case FLdatseg: 1315: assert(0); 1316: #if 0 1317: pcs->Irm = modregrm(0,0,BPRM); 1318: pcs->IEVpointer1 = e->EVpointer; 1319: break; 1320: #endif 1321: case FLfltreg: 1322: reflocal = TRUE; 1323: pcs->Irm = modregrm(2,0,BPRM); 1324: pcs->IEV1.Vint = 0; 1325: break; 1326: case FLreg: 1327: goto L2; 1328: case FLpara: 1329: refparam = TRUE; 1330: pcs->Irm = modregrm(2,0,BPRM); 1331: goto L2; 1332: 1333: case FLauto: 1334: if (s->Sclass == SCfastpar && regcon.params & mask[s->Spreg]) 1335: { 1336: if (keepmsk & RMload) 1337: { 1338: if (sz == REGSIZE) // could this be (sz <= REGSIZE) ? 1339: { 1340: pcs->Irm = modregrm(3,0,s->Spreg & 7); 1341: if (s->Spreg & 8) 1342: pcs->Irex |= REX_B; 1343: regcon.used |= mask[s->Spreg]; 1344: break; 1345: } 1346: } 1347: else 1348: regcon.params &= ~mask[s->Spreg]; 1349: } 1350: case FLtmp: 1351: case FLbprel: 1352: reflocal = TRUE; 1353: pcs->Irm = modregrm(2,0,BPRM); 1354: goto L2; 1355: case FLextern: 1356: if (s->Sident[0] == '_' && memcmp(s->Sident + 1,"tls_array",10) == 0) 1357: { 1358: #if TARGET_LINUX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1359: // Rewrite as GS:[0000], or FS:[0000] for 64 bit 1360: if (I64) 1361: { 1362: pcs->Irm = modregrm(0, 0, 4); 1363: pcs->Isib = modregrm(0, 4, 5); // don't use [RIP] addressing 1364: pcs->IFL1 = FLconst; 1365: pcs->IEV1.Vuns = 0; 1366: pcs->Iflags = CFfs; 1367: pcs->Irex |= REX_W; 1368: } 1369: else 1370: { 1371: pcs->Irm = modregrm(0, 0, BPRM); 1372: pcs->IFL1 = FLconst; 1373: pcs->IEV1.Vuns = 0; 1374: pcs->Iflags = CFgs; 1375: } 1376: break; 1377: #else 1378: pcs->Iflags |= CFfs; // add FS: override 1379: #endif 1380: } 1381: if (s->ty() & mTYcs && LARGECODE) 1382: goto Lfardata; 1383: goto L3; 1384: case FLdata: 1385: case FLudata: 1386: case FLcsdata: 1387: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1388: case FLgot: 1389: case FLgotoff: 1390: case FLtlsdata: 1391: #endif 1392: L3: 1393: pcs->Irm = modregrm(0,0,BPRM); 1394: L2: 1395: if (fl == FLreg) 1396: { assert(s->Sregm & regcon.mvar); 1397: if ( 1398: s->Sclass == SCregpar || 1399: s->Sclass == SCparameter) 1400: { refparam = TRUE; 1401: reflocal = TRUE; // kludge to set up prolog 1402: } 1403: pcs->Irm = modregrm(3,0,s->Sreglsw & 7); 1404: if (s->Sreglsw & 8) 1405: pcs->Irex |= REX_B; 1406: if (e->EV.sp.Voffset == 1 && sz == 1) 1407: { assert(s->Sregm & BYTEREGS); 1408: assert(s->Sreglsw < 4); 1409: pcs->Irm |= 4; // use 2nd byte of register 1410: } 1411: else 1412: { assert(!e->EV.sp.Voffset); 1413: if (I64 && sz == 1 && s->Sreglsw >= 4) 1414: pcs->Irex |= REX; 1415: } 1416: } 1417: else if (s->ty() & mTYcs && !(fl == FLextern && LARGECODE)) 1418: { 1419: pcs->Iflags |= CFcs | CFoff; 1420: } 1421: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1422: if (I64 && config.flags3 & CFG3pic && 1423: (fl == FLtlsdata || s->ty() & mTYthread)) 1424: { 1425: pcs->Iflags |= CFopsize; 1426: pcs->Irex = 0x48; 1427: } 1428: #endif 1429: pcs->IEVsym1 = s; 1430: pcs->IEVoffset1 = e->EV.sp.Voffset; 1431: if (sz == 1) 1432: { /* Don't use SI or DI for this variable */ 1433: s->Sflags |= GTbyte; 1434: if (e->EV.sp.Voffset > 1) 1435: s->Sflags &= ~GTregcand; 1436: } 1437: else if (e->EV.sp.Voffset) 1438: s->Sflags &= ~GTregcand; 1439: if (!(keepmsk & RMstore)) // if not store only 1440: { s->Sflags |= SFLread; // assume we are doing a read 1441: } 1442: break; 1443: case FLpseudo: 1444: #if MARS 1445: assert(0); 1446: #else 1447: { 1448: unsigned u = s->Sreglsw; 1449: c = getregs(pseudomask[u]); 1450: pcs->Irm = modregrm(3,0,pseudoreg[u] & 7); 1451: break; 1452: } 1453: #endif 1454: case FLfardata: 1455: assert(!TARGET_FLAT); 1456: case FLfunc: /* reading from code seg */ 1457: if (config.exe & EX_flat) 1458: goto L3; 1459: Lfardata: 1460: { 1461: regm_t regm = ALLREGS & ~keepmsk; // need scratch register 1462: code *c1 = allocreg(&regm,&reg,TYint); 1463: /* MOV mreg,seg of symbol */ 1464: c = gencs(CNIL,0xB8 + reg,0,FLextern,s); 1465: c->Iflags = CFseg; 1466: c = gen2(c,0x8E,modregrmx(3,0,reg)); /* MOV ES,reg */ 1467: c = cat3(c1,getregs(mES),c); 1468: pcs->Iflags |= CFes | CFoff; /* ES segment override */ 1469: goto L3; 1470: } 1471: 1472: case FLstack: 1473: assert(!I16); 1474: pcs->Irm = modregrm(2,0,4); 1475: pcs->Isib = modregrm(0,4,SP); 1476: pcs->IEVsym1 = s; 1477: pcs->IEVoffset1 = e->EV.sp.Voffset; 1478: break; 1479: 1480: default: 1481: #ifdef DEBUG 1482: WRFL((enum FL)fl); 1483: symbol_print(s); 1484: #endif 1485: assert(0); 1486: } 1487: return c; 1488: } 1489: 1490: /******************************* 1491: * Same as codelem(), but do not destroy the registers in keepmsk. 1492: * Use scratch registers as much as possible, then use stack. 1493: * Input: 1494: * constflag TRUE if user of result will not modify the 1495: * registers returned in *pretregs. 1496: */ 1497: 1498: code *scodelem(elem *e,regm_t *pretregs,regm_t keepmsk,bool constflag) 1499: { code *c,*cs1,*cs2,*cs3; 1500: unsigned i,j; 1501: regm_t oldmfuncreg,oldregcon,oldregimmed,overlap,tosave,touse; 1502: int adjesp; 1503: unsigned stackpushsave; 1504: char calledafuncsave; 1505: 1506: #ifdef DEBUG 1507: if (debugw) 1508: printf("+scodelem(e=%p *pretregs=%s keepmsk=%s constflag=%d\n", 1509: e,regm_str(*pretregs),regm_str(keepmsk),constflag); 1510: #endif 1511: elem_debug(e); 1512: if (constflag) 1513: { regm_t regm; 1514: unsigned reg; 1515: 1516: if (isregvar(e,&regm,&reg) && // if e is a register variable 1517: (regm & *pretregs) == regm && // in one of the right regs 1518: e->EV.sp.Voffset == 0 1519: ) 1520: { 1521: unsigned sz1 = tysize(e->Ety); 1522: unsigned sz2 = tysize(e->EV.sp.Vsym->Stype->Tty); 1523: if (sz1 <= REGSIZE && sz2 > REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
warning C4018: '>' : signed/unsigned mismatch
1524: regm &= mLSW; 1525: c = fixresult(e,regm,pretregs); 1526: cssave(e,regm,0); 1527: freenode(e); 1528: #ifdef DEBUG 1529: if (debugw) 1530: printf("-scodelem(e=%p *pretregs=x%x keepmsk=x%x constflag=%d\n", 1531: e,*pretregs,keepmsk,constflag); 1532: #endif 1533: return c; 1534: } 1535: } 1536: overlap = msavereg & keepmsk; 1537: msavereg |= keepmsk; /* add to mask of regs to save */ 1538: oldregcon = regcon.cse.mval; 1539: oldregimmed = regcon.immed.mval; 1540: oldmfuncreg = mfuncreg; /* remember old one */ 1541: mfuncreg = (mBP | mES | ALLREGS) & ~regcon.mvar; 1542: stackpushsave = stackpush; 1543: #if 0 1544: if (keepmsk) 1545: stackpush++; /* assume we'll have to save stuff on stack */ 1546: #endif 1547: calledafuncsave = calledafunc; 1548: calledafunc = 0; 1549: c = codelem(e,pretregs,constflag); /* generate code for the elem */ 1550: #if 0 1551: if (keepmsk) 1552: stackpush--; 1553: #endif 1554: 1555: tosave = keepmsk & ~msavereg; /* registers to save */ 1556: if (tosave) 1557: { cgstate.stackclean++; 1558: c = genstackclean(c,stackpush - stackpushsave,*pretregs | msavereg); 1559: cgstate.stackclean--; 1560: } 1561: 1562: /* Assert that no new CSEs are generated that are not reflected */ 1563: /* in mfuncreg. */ 1564: #ifdef DEBUG 1565: if ((mfuncreg & (regcon.cse.mval & ~oldregcon)) != 0) 1566: printf("mfuncreg x%x, regcon.cse.mval x%x, oldregcon x%x, regcon.mvar x%x\n", 1567: mfuncreg,regcon.cse.mval,oldregcon,regcon.mvar); 1568: #endif 1569: assert((mfuncreg & (regcon.cse.mval & ~oldregcon)) == 0); 1570: 1571: /* bugzilla 3521 1572: * The problem is: 1573: * reg op (reg = exp) 1574: * where reg must be preserved (in keepregs) while the expression to be evaluated 1575: * must change it. 1576: * The only solution is to make this variable not a register. 1577: */ 1578: if (regcon.mvar & tosave) 1579: { 1580: //elem_print(e); 1581: //printf("test1: regcon.mvar x%x tosave x%x\n", regcon.mvar, tosave); 1582: cgreg_unregister(regcon.mvar & tosave); 1583: } 1584: 1585: /* which registers can we use to save other registers in? */ 1586: if (config.flags4 & CFG4space || // if optimize for space 1587: config.target_cpu >= TARGET_80486) // PUSH/POP ops are 1 cycle 1588: touse = 0; // PUSH/POP pairs are always shorter 1589: else 1590: { touse = mfuncreg & allregs & ~(msavereg | oldregcon | regcon.cse.mval); 1591: /* Don't use registers we'll have to save/restore */ 1592: touse &= ~(fregsaved & oldmfuncreg); 1593: /* Don't use registers that have constant values in them, since 1594: the code generated might have used the value. 1595: */ 1596: touse &= ~oldregimmed; 1597: } 1598: 1599: cs1 = cs2 = cs3 = NULL; 1600: adjesp = 0; 1601: 1602: for (i = 0; tosave; i++) 1603: { regm_t mi = mask[i]; 1604: 1605: assert(i < REGMAX); 1606: if (mi & tosave) /* i = register to save */ 1607: { 1608: if (touse) /* if any scratch registers */ 1609: { for (j = 0; j < 8; j++) 1610: { regm_t mj = mask[j]; 1611: 1612: if (touse & mj) 1613: { cs1 = genmovreg(cs1,j,i); 1614: cs2 = cat(genmovreg(CNIL,i,j),cs2); 1615: touse &= ~mj; 1616: mfuncreg &= ~mj; 1617: regcon.used |= mj; 1618: break; 1619: } 1620: } 1621: assert(j < 8); 1622: } 1623: else /* else use stack */ 1624: #if 0 1625: { int push,pop; 1626: 1627: stackchanged = 1; 1628: adjesp += REGSIZE; 1629: if (i == ES) 1630: { push = 0x06; 1631: pop = 0x07; 1632: } 1633: else 1634: { push = 0x50 + i; 1635: pop = push | 8; 1636: } 1637: cs1 = gen1(cs1,push); /* PUSH i */ 1638: cs2 = cat(gen1(CNIL,pop),cs2); /* POP i */ 1639: } 1640: #else 1641: { 1642: stackchanged = 1; 1643: adjesp += REGSIZE; 1644: gensaverestore2(mask[i], &cs1, &cs2); 1645: } 1646: #endif 1647: cs3 = cat(getregs(mi),cs3); 1648: tosave &= ~mi; 1649: } 1650: } 1651: if (adjesp) 1652: { 1653: // If this is done an odd number of times, it 1654: // will throw off the 8 byte stack alignment. 1655: // We should *only* worry about this if a function 1656: // was called in the code generation by codelem(). 1657: int sz; 1658: if (STACKALIGN == 16) 1659: sz = -(adjesp & (STACKALIGN - 1)) & (STACKALIGN - 1); 1660: else 1661: sz = -(adjesp & 7) & 7; 1662: if (calledafunc && !I16 && sz && (STACKALIGN == 16 || config.flags4 & CFG4stackalign))
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1663: { 1664: unsigned grex = I64 ? REX_W << 16 : 0; 1665: regm_t mval_save = regcon.immed.mval; 1666: regcon.immed.mval = 0; // prevent reghasvalue() optimizations 1667: // because c hasn't been executed yet 1668: cs1 = genc2(cs1,0x81,grex | modregrm(3,5,SP),sz); // SUB ESP,sz 1669: if (I64) 1670: code_orrex(cs1, REX_W); 1671: regcon.immed.mval = mval_save; 1672: cs1 = genadjesp(cs1, sz); 1673: 1674: code *cx = genc2(CNIL,0x81,grex | modregrm(3,0,SP),sz); // ADD ESP,sz 1675: if (I64) 1676: code_orrex(cx, REX_W); 1677: cx = genadjesp(cx, -sz); 1678: cs2 = cat(cx, cs2); 1679: } 1680: 1681: cs1 = genadjesp(cs1,adjesp); 1682: cs2 = genadjesp(cs2,-adjesp); 1683: } 1684: 1685: calledafunc |= calledafuncsave; 1686: msavereg &= ~keepmsk | overlap; /* remove from mask of regs to save */ 1687: mfuncreg &= oldmfuncreg; /* update original */ 1688: #ifdef DEBUG 1689: if (debugw) 1690: printf("-scodelem(e=%p *pretregs=x%x keepmsk=x%x constflag=%d\n", 1691: e,*pretregs,keepmsk,constflag); 1692: #endif 1693: return cat4(cs1,c,cs3,cs2); 1694: } 1695: 1696: 1697: /***************************** 1698: * Given an opcode and EA in cs, generate code 1699: * for each floating register in turn. 1700: * Input: 1701: * tym either TYdouble or TYfloat 1702: */ 1703: 1704: code *fltregs(code *pcs,tym_t tym) 1705: { code *c; 1706: 1707: assert(!I64); 1708: tym = tybasic(tym); 1709: if (I32) 1710: { 1711: c = getregs((tym == TYfloat) ? mAX : mAX | mDX); 1712: if (tym != TYfloat) 1713: { 1714: pcs->IEVoffset1 += REGSIZE; 1715: NEWREG(pcs->Irm,DX); 1716: c = gen(c,pcs); 1717: pcs->IEVoffset1 -= REGSIZE; 1718: } 1719: NEWREG(pcs->Irm,AX); 1720: c = gen(c,pcs); 1721: } 1722: else 1723: { 1724: c = getregs((tym == TYfloat) ? FLOATREGS_16 : DOUBLEREGS_16); 1725: pcs->IEVoffset1 += (tym == TYfloat) ? 2 : 6; 1726: if (tym == TYfloat) 1727: NEWREG(pcs->Irm,DX); 1728: else 1729: NEWREG(pcs->Irm,AX); 1730: c = gen(c,pcs); 1731: pcs->IEVoffset1 -= 2; 1732: if (tym == TYfloat) 1733: NEWREG(pcs->Irm,AX); 1734: else 1735: NEWREG(pcs->Irm,BX); 1736: gen(c,pcs); 1737: if (tym != TYfloat) 1738: { pcs->IEVoffset1 -= 2; 1739: NEWREG(pcs->Irm,CX); 1740: gen(c,pcs); 1741: pcs->IEVoffset1 -= 2; /* note that exit is with Voffset unaltered */ 1742: NEWREG(pcs->Irm,DX); 1743: gen(c,pcs); 1744: } 1745: } 1746: return c; 1747: } 1748: 1749: 1750: /***************************** 1751: * Given a result in registers, test it for TRUE or FALSE. 1752: * Will fail if TYfptr and the reg is ES! 1753: * If saveflag is TRUE, preserve the contents of the 1754: * registers. 1755: */ 1756: 1757: code *tstresult(regm_t regm,tym_t tym,unsigned saveflag) 1758: { 1759: unsigned scrreg; /* scratch register */ 1760: regm_t scrregm; 1761: 1762: #ifdef DEBUG 1763: if (!(regm & (mBP | ALLREGS))) 1764: printf("tstresult(regm = %s, tym = x%x, saveflag = %d)\n", 1765: regm_str(regm),tym,saveflag); 1766: #endif 1767: assert(regm & (XMMREGS | mBP | ALLREGS)); 1768: tym = tybasic(tym); 1769: code *ce = CNIL; 1770: unsigned reg = findreg(regm); 1771: unsigned sz = tysize[tym]; 1772: if (sz == 1) 1773: { assert(regm & BYTEREGS); 1774: ce = genregs(ce,0x84,reg,reg); // TEST regL,regL 1775: if (I64 && reg >= 4) 1776: code_orrex(ce, REX); 1777: return ce; 1778: } 1779: if (regm & XMMREGS) 1780: { 1781: unsigned xreg; 1782: regm_t xregs = XMMREGS & ~regm; 1783: ce = allocreg(&xregs, &xreg, TYdouble); 1784: unsigned op = 0; 1785: if (tym == TYdouble || tym == TYidouble || tym == TYcdouble) 1786: op = 0x660000; 1787: ce = gen2(ce,op | 0x0F57,modregrm(3,xreg-XMM0,xreg-XMM0)); // XORPS xreg,xreg 1788: gen2(ce,op | 0x0F2E,modregrm(3,xreg-XMM0,reg-XMM0)); // UCOMISS xreg,reg 1789: if (tym == TYcfloat || tym == TYcdouble) 1790: { code *cnop = gennop(CNIL); 1791: genjmp(ce,JNE,FLcode,(block *) cnop); // JNE L1 1792: genjmp(ce,JP, FLcode,(block *) cnop); // JP L1 1793: reg = findreg(regm & ~mask[reg]); 1794: gen2(ce,op | 0x0F2E,modregrm(3,xreg-XMM0,reg-XMM0)); // UCOMISS xreg,reg 1795: ce = cat(ce, cnop); 1796: } 1797: return ce; 1798: } 1799: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1800: { 1801: if (!I16) 1802: { 1803: if (tym == TYfloat) 1804: { if (saveflag) 1805: { 1806: scrregm = allregs & ~regm; /* possible scratch regs */ 1807: ce = allocreg(&scrregm,&scrreg,TYoffset); /* allocate scratch reg */ 1808: ce = genmovreg(ce,scrreg,reg); /* MOV scrreg,msreg */ 1809: reg = scrreg; 1810: } 1811: ce = cat(ce,getregs(mask[reg])); 1812: return gen2(ce,0xD1,modregrmx(3,4,reg)); // SHL reg,1 1813: } 1814: ce = gentstreg(ce,reg); // TEST reg,reg 1815: if (sz == SHORTSIZE) 1816: ce->Iflags |= CFopsize; /* 16 bit operands */ 1817: else if (sz == 8) 1818: code_orrex(ce, REX_W); 1819: } 1820: else 1821: ce = gentstreg(ce,reg); // TEST reg,reg 1822: return ce; 1823: } 1824: if (saveflag || tyfv(tym)) 1825: { 1826: scrregm = ALLREGS & ~regm; /* possible scratch regs */ 1827: ce = allocreg(&scrregm,&scrreg,TYoffset); /* allocate scratch reg */ 1828: if (I32 || sz == REGSIZE * 2) 1829: { code *c; 1830: 1831: assert(regm & mMSW && regm & mLSW); 1832: 1833: reg = findregmsw(regm); 1834: if (I32) 1835: { 1836: if (tyfv(tym)) 1837: { c = genregs(CNIL,0x0FB7,scrreg,reg); // MOVZX scrreg,msreg 1838: ce = cat(ce,c); 1839: } 1840: else 1841: { ce = genmovreg(ce,scrreg,reg); /* MOV scrreg,msreg */ 1842: if (tym == TYdouble || tym == TYdouble_alias) 1843: gen2(ce,0xD1,modregrm(3,4,scrreg)); /* SHL scrreg,1 */ 1844: } 1845: } 1846: else 1847: { 1848: ce = genmovreg(ce,scrreg,reg); /* MOV scrreg,msreg */ 1849: if (tym == TYfloat) 1850: gen2(ce,0xD1,modregrm(3,4,scrreg)); /* SHL scrreg,1 */ 1851: } 1852: reg = findreglsw(regm); 1853: genorreg(ce,scrreg,reg); /* OR scrreg,lsreg */ 1854: } 1855: else if (sz == 8) 1856: { /* !I32 */ 1857: ce = genmovreg(ce,scrreg,AX); /* MOV scrreg,AX */ 1858: if (tym == TYdouble || tym == TYdouble_alias) 1859: gen2(ce,0xD1,modregrm(3,4,scrreg)); // SHL scrreg,1 1860: genorreg(ce,scrreg,BX); /* OR scrreg,BX */ 1861: genorreg(ce,scrreg,CX); /* OR scrreg,CX */ 1862: genorreg(ce,scrreg,DX); /* OR scrreg,DX */ 1863: } 1864: else 1865: assert(0); 1866: } 1867: else 1868: { 1869: if (I32 || sz == REGSIZE * 2) 1870: { 1871: /* can't test ES:LSW for 0 */ 1872: assert(regm & mMSW & ALLREGS && regm & (mLSW | mBP)); 1873: 1874: reg = findregmsw(regm); 1875: ce = getregs(mask[reg]); /* we're going to trash reg */ 1876: if (tyfloating(tym) && sz == 2 * intsize) 1877: ce = gen2(ce,0xD1,modregrm(3,4,reg)); // SHL reg,1 1878: ce = genorreg(ce,reg,findreglsw(regm)); // OR reg,reg+1 1879: } 1880: else if (sz == 8) 1881: { assert(regm == DOUBLEREGS_16); 1882: ce = getregs(mAX); // allocate AX 1883: if (tym == TYdouble || tym == TYdouble_alias) 1884: ce = gen2(ce,0xD1,modregrm(3,4,AX)); // SHL AX,1 1885: genorreg(ce,AX,BX); // OR AX,BX 1886: genorreg(ce,AX,CX); // OR AX,CX 1887: genorreg(ce,AX,DX); // OR AX,DX 1888: } 1889: else 1890: assert(0); 1891: } 1892: code_orflag(ce,CFpsw); 1893: return ce; 1894: } 1895: 1896: 1897: /****************************** 1898: * Given the result of an expression is in retregs, 1899: * generate necessary code to return result in *pretregs. 1900: */ 1901: 1902: code *fixresult(elem *e,regm_t retregs,regm_t *pretregs) 1903: { code *c,*ce; 1904: unsigned reg,rreg; 1905: regm_t forccs,forregs; 1906: tym_t tym; 1907: int sz; 1908: 1909: //printf("fixresult(e = %p, retregs = %s, *pretregs = %s)\n",e,regm_str(retregs),regm_str(*pretregs)); 1910: if (*pretregs == 0) return CNIL; /* if don't want result */ 1911: assert(e && retregs); /* need something to work with */ 1912: forccs = *pretregs & mPSW; 1913: forregs = *pretregs & (mST01 | mST0 | mBP | ALLREGS | mES | mSTACK | XMMREGS); 1914: tym = tybasic(e->Ety); 1915: #if 0 1916: if (tym == TYstruct) 1917: // Hack to support cdstreq() 1918: tym = TYfptr; 1919: #else 1920: if (tym == TYstruct) 1921: // Hack to support cdstreq() 1922: tym = (forregs & mMSW) ? TYfptr : TYnptr; 1923: #endif 1924: c = CNIL; 1925: sz = tysize[tym]; 1926: if (sz == 1) 1927: { 1928: assert(retregs & BYTEREGS); 1929: unsigned reg = findreg(retregs);
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1904' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 1904
1930: if (e->Eoper == OPvar && 1931: e->EV.sp.Voffset == 1 && 1932: e->EV.sp.Vsym->Sfl == FLreg) 1933: { 1934: assert(reg < 4); 1935: if (forccs) 1936: c = gen2(c,0x84,modregrm(3,reg | 4,reg | 4)); // TEST regH,regH 1937: forccs = 0; 1938: } 1939: } 1940: if ((retregs & forregs) == retregs) /* if already in right registers */ 1941: *pretregs = retregs; 1942: else if (forregs) /* if return the result in registers */ 1943: { 1944: if (forregs & (mST01 | mST0)) 1945: return fixresult87(e,retregs,pretregs); 1946: ce = CNIL; 1947: unsigned opsflag = FALSE; 1948: if (I16 && sz == 8) 1949: { if (forregs & mSTACK) 1950: { assert(retregs == DOUBLEREGS_16); 1951: /* Push floating regs */ 1952: c = CNIL; 1953: ce = gen1(ce,0x50 + AX); 1954: gen1(ce,0x50 + BX); 1955: gen1(ce,0x50 + CX); 1956: gen1(ce,0x50 + DX); 1957: stackpush += DOUBLESIZE; 1958: } 1959: else if (retregs & mSTACK) 1960: { assert(forregs == DOUBLEREGS_16); 1961: /* Pop floating regs */ 1962: c = getregs(forregs); 1963: ce = gen1(ce,0x58 + DX); 1964: gen1(ce,0x58 + CX); 1965: gen1(ce,0x58 + BX); 1966: gen1(ce,0x58 + AX); 1967: stackpush -= DOUBLESIZE; 1968: retregs = DOUBLEREGS_16; /* for tstresult() below */ 1969: } 1970: else 1971: #ifdef DEBUG 1972: printf("retregs = x%x, forregs = x%x\n",retregs,forregs), 1973: #endif 1974: assert(0); 1975: if (EOP(e)) 1976: opsflag = TRUE; 1977: } 1978: else 1979: { 1980: c = allocreg(pretregs,&rreg,tym); /* allocate return regs */ 1981: if (sz > REGSIZE) 1982: { 1983: unsigned msreg = findregmsw(retregs); 1984: unsigned lsreg = findreglsw(retregs); 1985: unsigned msrreg = findregmsw(*pretregs); 1986: unsigned lsrreg = findreglsw(*pretregs); 1987: 1988: ce = genmovreg(ce,msrreg,msreg); /* MOV msrreg,msreg */ 1989: ce = genmovreg(ce,lsrreg,lsreg); /* MOV lsrreg,lsreg */ 1990: } 1991: else if (retregs & XMMREGS) 1992: { 1993: reg = findreg(retregs & XMMREGS); 1994: // MOVSD floatreg, XMM? 1995: ce = genfltreg(ce,0xF20F11,reg - XMM0,0); 1996: if (mask[rreg] & XMMREGS) 1997: // MOVSD XMM?, floatreg 1998: ce = genfltreg(ce,0xF20F10,rreg - XMM0,0); 1999: else 2000: { 2001: // MOV rreg,floatreg 2002: ce = genfltreg(ce,0x8B,rreg,0); 2003: if (sz == 8) 2004: code_orrex(ce,REX_W); 2005: } 2006: } 2007: else if (forregs & XMMREGS) 2008: { 2009: reg = findreg(retregs & (mBP | ALLREGS)); 2010: // MOV floatreg,reg 2011: ce = genfltreg(ce,0x89,reg,0); 2012: if (sz == 8) 2013: code_orrex(ce,REX_W); 2014: // MOVSS/MOVSD XMMreg,floatreg 2015: ce = genfltreg(ce,0xF20F10,rreg - XMM0,0); 2016: } 2017: else 2018: { 2019: assert(!(retregs & XMMREGS)); 2020: assert(!(forregs & XMMREGS)); 2021: reg = findreg(retregs & (mBP | ALLREGS)); 2022: ce = genmovreg(ce,rreg,reg); /* MOV rreg,reg */ 2023: } 2024: } 2025: c = cat(c,ce); 2026: cssave(e,retregs | *pretregs,opsflag); 2027: forregs = 0; /* don't care about result in reg */ 2028: /* cuz we have real result in rreg */ 2029: retregs = *pretregs & ~mPSW; 2030: } 2031: if (forccs) /* if return result in flags */ 2032: c = cat(c,tstresult(retregs,tym,forregs)); 2033: return c; 2034: } 2035: 2036: 2037: /******************************** 2038: * Generate code sequence to call C runtime library support routine. 2039: * clib = CLIBxxxx 2040: * keepmask = mask of registers not to destroy. Currently can 2041: * handle only 1. Should use a temporary rather than 2042: * push/pop for speed. 2043: */ 2044: 2045: int clib_inited = 0; // != 0 if initialized 2046: 2047: code *callclib(elem *e,unsigned clib,regm_t *pretregs,regm_t keepmask) 2048: { 2049: //printf("callclib(e = %p, clib = %d, *pretregs = %s, keepmask = %s\n", e, clib, regm_str(*pretregs), regm_str(keepmask)); 2050: //elem_print(e); 2051: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 2052: static symbol lib[] = 2053: { 2054: /* Convert destroyed regs into saved regs */ 2055: #define Z(desregs) (~(desregs) & (mBP| mES | ALLREGS)) 2056: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 2057: #define N(name) "_" name 2058: #else 2059: #define N(name) name 2060: #endif 2061: 2062: /* Shorthand to map onto SYMBOLY() */ 2063: #define Y(desregs,name) SYMBOLY(FLfunc,Z(desregs),N(name),0) 2064: 2065: Y(0,"_LCMP__"), // CLIBlcmp 2066: Y(mAX|mCX|mDX,"_LMUL__"), // CLIBlmul 2067: #if 1 2068: Y(mAX|mBX|mCX|mDX,"_LDIV__"), // CLIBldiv 2069: Y(mAX|mBX|mCX|mDX,"_LDIV__"), // CLIBlmod 2070: Y(mAX|mBX|mCX|mDX,"_ULDIV__"), // CLIBuldiv 2071: Y(mAX|mBX|mCX|mDX,"_ULDIV__"), // CLIBulmod 2072: #else 2073: Y(ALLREGS,"_LDIV__"), // CLIBldiv 2074: Y(ALLREGS,"_LDIV__"), // CLIBlmod 2075: Y(ALLREGS,"_ULDIV__"), // CLIBuldiv 2076: Y(ALLREGS,"_ULDIV__"), // CLIBulmod 2077: #endif 2078: #if 0 2079: Y(DOUBLEREGS_16,"_DNEG"), 2080: Y(mAX|mBX|mCX|mDX,"_DMUL"), // CLIBdmul 2081: Y(mAX|mBX|mCX|mDX,"_DDIV"), // CLIBddiv 2082: Y(0,"_DTST0"), // CLIBdtst0 2083: Y(0,"_DTST0EXC"), // CLIBdtst0exc 2084: Y(0,"_DCMP"), // CLIBdcmp 2085: Y(0,"_DCMPEXC"), // CLIBdcmpexc 2086: 2087: Y(mAX|mBX|mCX|mDX,"_DADD"), // CLIBdadd 2088: Y(mAX|mBX|mCX|mDX,"_DSUB"), // CLIBdsub 2089: 2090: Y(mAX|mBX|mCX|mDX,"_FMUL"), // CLIBfmul 2091: Y(mAX|mBX|mCX|mDX,"_FDIV"), // CLIBfdiv 2092: Y(0,"_FTST0"), // CLIBftst0 2093: Y(0,"_FTST0EXC"), // CLIBftst0exc 2094: Y(0,"_FCMP"), // CLIBfcmp 2095: Y(0,"_FCMPEXC"), // CLIBfcmpexc 2096: Y(FLOATREGS_32,"_FNEG"), // CLIBfneg 2097: Y(mAX|mBX|mCX|mDX,"_FADD"), // CLIBfadd 2098: Y(mAX|mBX|mCX|mDX,"_FSUB"), // CLIBfsub 2099: #endif 2100: Y(DOUBLEREGS_32,"_DBLLNG"), // CLIBdbllng 2101: Y(DOUBLEREGS_32,"_LNGDBL"), // CLIBlngdbl 2102: Y(DOUBLEREGS_32,"_DBLINT"), // CLIBdblint 2103: Y(DOUBLEREGS_32,"_INTDBL"), // CLIBintdbl 2104: Y(DOUBLEREGS_32,"_DBLUNS"), // CLIBdbluns 2105: Y(DOUBLEREGS_32,"_UNSDBL"), // CLIBunsdbl 2106: Y(mAX|mST0,"_DBLULNG"), // CLIBdblulng 2107: #if 0 2108: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _ULNGDBL@ ulngdbl 2109: #endif 2110: Y(DOUBLEREGS_32,"_DBLFLT"), // CLIBdblflt 2111: Y(DOUBLEREGS_32,"_FLTDBL"), // CLIBfltdbl 2112: 2113: Y(DOUBLEREGS_32,"_DBLLLNG"), // CLIBdblllng 2114: Y(DOUBLEREGS_32,"_LLNGDBL"), // CLIBllngdbl 2115: Y(DOUBLEREGS_32,"_DBLULLNG"), // CLIBdblullng 2116: Y(DOUBLEREGS_32,"_ULLNGDBL"), // CLIBullngdbl 2117: 2118: Y(0,"_DTST"), // CLIBdtst 2119: Y(mES|mBX,"_HTOFPTR"), // CLIBvptrfptr 2120: Y(mES|mBX,"_HCTOFPTR"), // CLIBcvptrfptr 2121: Y(0,"_87TOPSW"), // CLIB87topsw 2122: Y(mST0,"_FLTTO87"), // CLIBfltto87 2123: Y(mST0,"_DBLTO87"), // CLIBdblto87 2124: Y(mST0|mAX,"_DBLINT87"), // CLIBdblint87 2125: Y(mST0|mAX|mDX,"_DBLLNG87"), // CLIBdbllng87 2126: Y(0,"_FTST"), // CLIBftst 2127: Y(0,"_FCOMPP"), // CLIBfcompp 2128: Y(0,"_FTEST"), // CLIBftest 2129: Y(0,"_FTEST0"), // CLIBftest0 2130: Y(mST0|mAX|mBX|mCX|mDX,"_FDIVP"), // CLIBfdiv87 2131: 2132: Y(mST0|mST01,"Cmul"), // CLIBcmul 2133: Y(mAX|mCX|mDX|mST0|mST01,"Cdiv"), // CLIBcdiv 2134: Y(mAX|mST0|mST01,"Ccmp"), // CLIBccmp 2135: 2136: Y(mST0,"_U64_LDBL"), // CLIBu64_ldbl 2137: #if ELFOBJ || MACHOBJ 2138: Y(mST0|mAX|mDX,"_LDBLULLNG"), // CLIBld_u64 2139: #else 2140: Y(mST0|mAX|mDX,"__LDBLULLNG"), // CLIBld_u64 2141: #endif 2142: }; 2143: #else 2144: static symbol lib[CLIBMAX] = 2145: { 2146: /* Convert destroyed regs into saved regs */ 2147: #define Z(desregs) (~(desregs) & (mBP| mES | ALLREGS)) 2148: 2149: /* Shorthand to map onto SYMBOLY() */ 2150: #define Y(desregs,name) SYMBOLY(FLfunc,Z(desregs),name,0) 2151: 2152: Y(0,"_LCMP@"), 2153: Y(mAX|mCX|mDX,"_LMUL@"), 2154: Y(ALLREGS,"_LDIV@"), 2155: Y(ALLREGS,"_LDIV@"), 2156: Y(ALLREGS,"_ULDIV@"), 2157: Y(ALLREGS,"_ULDIV@"), 2158: Y(mAX|mBX|mCX|mDX,"_DMUL@"), 2159: Y(mAX|mBX|mCX|mDX,"_DDIV@"), 2160: Y(0,"_DTST0@"), 2161: Y(0,"_DTST0EXC@"), 2162: Y(0,"_DCMP@"), 2163: Y(0,"_DCMPEXC@"), 2164: 2165: /* _DNEG@ only really destroys EDX, but then EAX would hold */ 2166: /* 2 values, and we can't handle that. */ 2167: 2168: /* _DNEG@ only really destroys AX, but then BX,CX,DX would hold */ 2169: /* 2 values, and we can't handle that. */ 2170: 2171: Y(DOUBLEREGS_16,"_DNEG@"), 2172: Y(mAX|mBX|mCX|mDX,"_DADD@"), 2173: Y(mAX|mBX|mCX|mDX,"_DSUB@"), 2174: 2175: Y(mAX|mBX|mCX|mDX,"_FMUL@"), 2176: Y(mAX|mBX|mCX|mDX,"_FDIV@"), 2177: Y(0,"_FTST0@"), 2178: Y(0,"_FTST0EXC@"), 2179: Y(0,"_FCMP@"), 2180: Y(0,"_FCMPEXC@"), 2181: Y(FLOATREGS_16,"_FNEG@"), 2182: Y(mAX|mBX|mCX|mDX,"_FADD@"), 2183: Y(mAX|mBX|mCX|mDX,"_FSUB@"), 2184: Y(DOUBLEREGS_16,"_DBLLNG@"), 2185: Y(DOUBLEREGS_16,"_LNGDBL@"), 2186: Y(DOUBLEREGS_16,"_DBLINT@"), 2187: Y(DOUBLEREGS_16,"_INTDBL@"), 2188: Y(DOUBLEREGS_16,"_DBLUNS@"), 2189: Y(DOUBLEREGS_16,"_UNSDBL@"), 2190: Y(DOUBLEREGS_16,"_DBLULNG@"), 2191: Y(DOUBLEREGS_16,"_ULNGDBL@"), 2192: Y(DOUBLEREGS_16,"_DBLFLT@"), 2193: Y(ALLREGS,"_FLTDBL@"), 2194: 2195: Y(DOUBLEREGS_16,"_DBLLLNG@"), 2196: Y(DOUBLEREGS_16,"_LLNGDBL@"), 2197: #if 0 2198: Y(DOUBLEREGS_16,"__DBLULLNG"), 2199: #else 2200: Y(DOUBLEREGS_16,"_DBLULLNG@"), 2201: #endif 2202: Y(DOUBLEREGS_16,"_ULLNGDBL@"), 2203: 2204: Y(0,"_DTST@"), 2205: Y(mES|mBX,"_HTOFPTR@"), // CLIBvptrfptr 2206: Y(mES|mBX,"_HCTOFPTR@"), // CLIBcvptrfptr 2207: Y(0,"_87TOPSW@"), // CLIB87topsw 2208: Y(mST0,"_FLTTO87@"), // CLIBfltto87 2209: Y(mST0,"_DBLTO87@"), // CLIBdblto87 2210: Y(mST0|mAX,"_DBLINT87@"), // CLIBdblint87 2211: Y(mST0|mAX|mDX,"_DBLLNG87@"), // CLIBdbllng87 2212: Y(0,"_FTST@"), 2213: Y(0,"_FCOMPP@"), // CLIBfcompp 2214: Y(0,"_FTEST@"), // CLIBftest 2215: Y(0,"_FTEST0@"), // CLIBftest0 2216: Y(mST0|mAX|mBX|mCX|mDX,"_FDIVP"), // CLIBfdiv87 2217: 2218: // NOTE: desregs is wrong for 16 bit code, mBX should be included 2219: Y(mST0|mST01,"_Cmul"), // CLIBcmul 2220: Y(mAX|mCX|mDX|mST0|mST01,"_Cdiv"), // CLIBcdiv 2221: Y(mAX|mST0|mST01,"_Ccmp"), // CLIBccmp 2222: 2223: Y(mST0,"_U64_LDBL"), // CLIBu64_ldbl 2224: Y(mST0|mAX|mDX,"__LDBLULLNG"), // CLIBld_u64 2225: }; 2226: #endif 2227: 2228: static struct 2229: { 2230: regm_t retregs16; /* registers that 16 bit result is returned in */ 2231: regm_t retregs32; /* registers that 32 bit result is returned in */ 2232: char pop; /* # of bytes popped off of stack upon return */ 2233: char flags; 2234: #define INF32 1 // if 32 bit only 2235: #define INFfloat 2 // if this is floating point 2236: #define INFwkdone 4 // if weak extern is already done 2237: #define INF64 8 // if 64 bit only 2238: char push87; // # of pushes onto the 8087 stack 2239: char pop87; // # of pops off of the 8087 stack 2240: } info[CLIBMAX] = 2241: { 2242: {0,0,0,0}, /* _LCMP@ lcmp */ 2243: {mDX|mAX,mDX|mAX,0,0}, // _LMUL@ lmul 2244: {mDX|mAX,mDX|mAX,0,0}, // _LDIV@ ldiv 2245: {mCX|mBX,mCX|mBX,0,0}, /* _LDIV@ lmod */ 2246: {mDX|mAX,mDX|mAX,0,0}, /* _ULDIV@ uldiv */ 2247: {mCX|mBX,mCX|mBX,0,0}, /* _ULDIV@ ulmod */ 2248: 2249: #if TARGET_WINDOS 2250: {DOUBLEREGS_16,DOUBLEREGS_32,8,INFfloat,1,1}, // _DMUL@ dmul 2251: {DOUBLEREGS_16,DOUBLEREGS_32,8,INFfloat,1,1}, // _DDIV@ ddiv 2252: {0,0,0,2}, // _DTST0@ 2253: {0,0,0,2}, // _DTST0EXC@ 2254: {0,0,8,INFfloat,1,1}, // _DCMP@ dcmp 2255: {0,0,8,INFfloat,1,1}, // _DCMPEXC@ dcmp 2256: {DOUBLEREGS_16,DOUBLEREGS_32,0,2}, // _DNEG@ dneg 2257: {DOUBLEREGS_16,DOUBLEREGS_32,8,INFfloat,1,1}, // _DADD@ dadd 2258: {DOUBLEREGS_16,DOUBLEREGS_32,8,INFfloat,1,1}, // _DSUB@ dsub 2259: 2260: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _FMUL@ fmul 2261: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _FDIV@ fdiv 2262: {0,0,0,2}, // _FTST0@ 2263: {0,0,0,2}, // _FTST0EXC@ 2264: {0,0,0,INFfloat,1,1}, // _FCMP@ fcmp 2265: {0,0,0,INFfloat,1,1}, // _FCMPEXC@ fcmp 2266: {FLOATREGS_16,FLOATREGS_32,0,2}, // _FNEG@ fneg 2267: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _FADD@ fadd 2268: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _FSUB@ fsub 2269: #endif 2270: 2271: {mDX|mAX,mAX,0,INFfloat,1,1}, // _DBLLNG@ dbllng 2272: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _LNGDBL@ lngdbl 2273: {mAX,mAX,0,INFfloat,1,1}, // _DBLINT@ dblint 2274: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _INTDBL@ intdbl 2275: {mAX,mAX,0,INFfloat,1,1}, // _DBLUNS@ dbluns 2276: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _UNSDBL@ unsdbl 2277: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 2278: {mDX|mAX,mAX,0,INF32|INFfloat,0,1}, // _DBLULNG@ dblulng 2279: #else 2280: {mDX|mAX,mAX,0,INFfloat,1,1}, // _DBLULNG@ dblulng 2281: #endif 2282: #if TARGET_WINDOS 2283: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _ULNGDBL@ ulngdbl 2284: #endif 2285: {FLOATREGS_16,FLOATREGS_32,0,INFfloat,1,1}, // _DBLFLT@ dblflt 2286: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _FLTDBL@ fltdbl 2287: 2288: {DOUBLEREGS_16,mDX|mAX,0,INFfloat,1,1}, // _DBLLLNG@ 2289: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _LLNGDBL@ 2290: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 2291: {DOUBLEREGS_16,mDX|mAX,0,INFfloat,2,2}, // _DBLULLNG@ 2292: #else 2293: {DOUBLEREGS_16,mDX|mAX,0,INFfloat,1,1}, // _DBLULLNG@ 2294: #endif 2295: {DOUBLEREGS_16,DOUBLEREGS_32,0,INFfloat,1,1}, // _ULLNGDBL@ 2296: 2297: {0,0,0,2}, // _DTST@ dtst 2298: {mES|mBX,mES|mBX,0,0}, // _HTOFPTR@ vptrfptr 2299: {mES|mBX,mES|mBX,0,0}, // _HCTOFPTR@ cvptrfptr 2300: {0,0,0,2}, // _87TOPSW@ 87topsw 2301: {mST0,mST0,0,INFfloat,1,0}, // _FLTTO87@ fltto87 2302: {mST0,mST0,0,INFfloat,1,0}, // _DBLTO87@ dblto87 2303: {mAX,mAX,0,2}, // _DBLINT87@ dblint87 2304: {mDX|mAX,mAX,0,2}, // _DBLLNG87@ dbllng87 2305: {0,0,0,2}, // _FTST@ 2306: {mPSW,mPSW,0,INFfloat,0,2}, // _FCOMPP@ 2307: {mPSW,mPSW,0,2}, // _FTEST@ 2308: {mPSW,mPSW,0,2}, // _FTEST0@ 2309: {mST0,mST0,0,INFfloat,1,1}, // _FDIV@ 2310: 2311: {mST01,mST01,0,INF32|INFfloat,3,5}, // _Cmul 2312: {mST01,mST01,0,INF32|INFfloat,0,2}, // _Cdiv 2313: {mPSW, mPSW, 0,INF32|INFfloat,0,4}, // _Ccmp 2314: 2315: {mST0,mST0,0,INF32|INF64|INFfloat,2,1}, // _U64_LDBL 2316: {0,mDX|mAX,0,INF32|INF64|INFfloat,1,2}, // __LDBLULLNG 2317: }; 2318: 2319: if (!clib_inited) /* if not initialized */ 2320: { 2321: assert(sizeof(lib) / sizeof(lib[0]) == CLIBMAX); 2322: assert(sizeof(info) / sizeof(info[0]) == CLIBMAX); 2323: for (int i = 0; i < CLIBMAX; i++) 2324: { lib[i].Stype = tsclib; 2325: #if MARS 2326: lib[i].Sxtrnnum = 0; 2327: lib[i].Stypidx = 0; 2328: #endif 2329: } 2330: 2331: if (!I16) 2332: { /* Adjust table for 386 */ 2333: lib[CLIBdbllng].Sregsaved = Z(DOUBLEREGS_32); 2334: lib[CLIBlngdbl].Sregsaved = Z(DOUBLEREGS_32); 2335: lib[CLIBdblint].Sregsaved = Z(DOUBLEREGS_32); 2336: lib[CLIBintdbl].Sregsaved = Z(DOUBLEREGS_32); 2337: #if TARGET_WINDOS 2338: lib[CLIBfneg].Sregsaved = Z(FLOATREGS_32); 2339: lib[CLIBdneg].Sregsaved = Z(DOUBLEREGS_32); 2340: lib[CLIBdbluns].Sregsaved = Z(DOUBLEREGS_32); 2341: lib[CLIBunsdbl].Sregsaved = Z(DOUBLEREGS_32); 2342: lib[CLIBdblulng].Sregsaved = Z(DOUBLEREGS_32); 2343: lib[CLIBulngdbl].Sregsaved = Z(DOUBLEREGS_32); 2344: #endif 2345: lib[CLIBdblflt].Sregsaved = Z(DOUBLEREGS_32); 2346: lib[CLIBfltdbl].Sregsaved = Z(DOUBLEREGS_32); 2347: 2348: lib[CLIBdblllng].Sregsaved = Z(DOUBLEREGS_32); 2349: lib[CLIBllngdbl].Sregsaved = Z(DOUBLEREGS_32); 2350: lib[CLIBdblullng].Sregsaved = Z(DOUBLEREGS_32); 2351: lib[CLIBullngdbl].Sregsaved = Z(DOUBLEREGS_32); 2352: 2353: if (I64) 2354: { 2355: info[CLIBullngdbl].retregs32 = mAX; 2356: info[CLIBdblullng].retregs32 = mAX; 2357: } 2358: } 2359: clib_inited++; 2360: } 2361: #undef Z 2362: 2363: assert(clib < CLIBMAX); 2364: symbol *s = &lib[clib]; 2365: if (I16) 2366: assert(!(info[clib].flags & (INF32 | INF64))); 2367: code *cpop = CNIL; 2368: code *c = getregs((~s->Sregsaved & (mES | mBP | ALLREGS)) & ~keepmask); // mask of regs destroyed 2369: keepmask &= ~s->Sregsaved; 2370: int npushed = numbitsset(keepmask); 2371: gensaverestore2(keepmask, &c, &cpop); 2372: #if 0 2373: while (keepmask) 2374: { unsigned keepreg; 2375: 2376: if (keepmask & (mBP|ALLREGS)) 2377: { keepreg = findreg(keepmask & (mBP|ALLREGS)); 2378: c = gen1(c,0x50 + keepreg); /* PUSH keepreg */ 2379: cpop = cat(gen1(CNIL,0x58 + keepreg),cpop); // POP keepreg 2380: keepmask &= ~mask[keepreg]; 2381: npushed++; 2382: } 2383: if (keepmask & mES) 2384: { c = gen1(c,0x06); /* PUSH ES */ 2385: cpop = cat(gen1(CNIL,0x07),cpop); /* POP ES */ 2386: keepmask &= ~mES; 2387: npushed++; 2388: } 2389: } 2390: #endif 2391: 2392: c = cat(c, save87regs(info[clib].push87)); 2393: for (int i = 0; i < info[clib].push87; i++) 2394: c = cat(c, push87()); 2395: 2396: for (int i = 0; i < info[clib].pop87; i++) 2397: pop87(); 2398: 2399: if (config.target_cpu >= TARGET_80386 && clib == CLIBlmul && !I32) 2400: { static char lmul[] = { 2401: 0x66,0xc1,0xe1,0x10, // shl ECX,16
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2402: 0x8b,0xcb, // mov CX,BX ;ECX = CX,BX
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2403: 0x66,0xc1,0xe0,0x10, // shl EAX,16
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2404: 0x66,0x0f,0xac,0xd0,0x10, // shrd EAX,EDX,16 ;EAX = DX,AX
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2405: 0x66,0xf7,0xe1, // mul ECX
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2406: 0x66,0x0f,0xa4,0xc2,0x10, // shld EDX,EAX,16 ;DX,AX = EAX
warning C4309: 'initializing' : truncation of constant value
warning C4309: 'initializing' : truncation of constant value
2407: }; 2408: 2409: c = genasm(c,lmul,sizeof(lmul)); 2410: } 2411: else 2412: { makeitextern(s); 2413: int nalign = 0; 2414: if (STACKALIGN == 16) 2415: { // Align the stack (assume no args on stack) 2416: int npush = npushed * REGSIZE + stackpush; 2417: if (npush & (STACKALIGN - 1)) 2418: { nalign = STACKALIGN - (npush & (STACKALIGN - 1)); 2419: c = genc2(c,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign 2420: if (I64) 2421: code_orrex(c, REX_W); 2422: } 2423: } 2424: c = gencs(c,(LARGECODE) ? 0x9A : 0xE8,0,FLfunc,s); // CALL s 2425: if (nalign) 2426: { c = genc2(c,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign 2427: if (I64) 2428: code_orrex(c, REX_W); 2429: } 2430: calledafunc = 1; 2431: 2432: if (I16 && // bug in Optlink for weak references 2433: config.flags3 & CFG3wkfloat && 2434: (info[clib].flags & (INFfloat | INFwkdone)) == INFfloat) 2435: { info[clib].flags |= INFwkdone; 2436: makeitextern(rtlsym[RTLSYM_INTONLY]); 2437: obj_wkext(s,rtlsym[RTLSYM_INTONLY]); 2438: } 2439: } 2440: if (I16) 2441: stackpush -= info[clib].pop; 2442: regm_t retregs = I16 ? info[clib].retregs16 : info[clib].retregs32; 2443: return cat(cat(c,cpop),fixresult(e,retregs,pretregs)); 2444: } 2445: 2446: /************************************************* 2447: * Helper function for converting OPparam's into array of Parameters. 2448: */ 2449: struct Parameter { elem *e; int reg; unsigned numalign; }; 2450: 2451: void fillParameters(elem *e, Parameter *parameters, int *pi) 2452: { 2453: if (e->Eoper == OPparam) 2454: { 2455: fillParameters(e->E1, parameters, pi); 2456: fillParameters(e->E2, parameters, pi); 2457: freenode(e); 2458: } 2459: else 2460: { 2461: parameters[*pi].e = e; 2462: (*pi)++; 2463: } 2464: } 2465: 2466: 2467: /******************************* 2468: * Generate code sequence for function call. 2469: */ 2470: 2471: code *cdfunc(elem *e,regm_t *pretregs) 2472: { unsigned numpara = 0; 2473: unsigned stackpushsave; 2474: unsigned preg; 2475: regm_t keepmsk; 2476: unsigned numalign = 0; 2477: code *c; 2478: 2479: //printf("cdfunc()\n"); elem_print(e); 2480: assert(e); 2481: stackpushsave = stackpush; /* so we can compute # of parameters */ 2482: cgstate.stackclean++; 2483: c = CNIL; 2484: keepmsk = 0; 2485: if (OTbinary(e->Eoper)) // if parameters 2486: { 2487: if (I16) 2488: { 2489: c = cat(c, params(e->E2,2)); // push parameters 2490: } 2491: else if (I32) 2492: { 2493: unsigned stackalign = REGSIZE; 2494: tym_t tyf = tybasic(e->E1->Ety); 2495: 2496: // First compute numpara, the total bytes pushed on the stack 2497: switch (tyf) 2498: { case TYf16func: 2499: stackalign = 2; 2500: goto Ldefault; 2501: case TYmfunc: 2502: case TYjfunc: 2503: // last parameter goes into register 2504: elem *ep; 2505: for (ep = e->E2; ep->Eoper == OPparam; ep = ep->E2) 2506: { 2507: numpara += paramsize(ep->E1,stackalign); 2508: } 2509: unsigned sz; 2510: if (tyf == TYjfunc && 2511: // This must match type_jparam() 2512: !(tyjparam(ep->Ety) || 2513: ((tybasic(ep->Ety) == TYstruct || tybasic(ep->Ety) == TYarray) && 2514: (sz = type_size(ep->ET)) <= intsize && sz != 3 && sz)
warning C4018: '<=' : signed/unsigned mismatch
2515: ) 2516: ) 2517: { 2518: numpara += paramsize(ep,stackalign); 2519: } 2520: break; 2521: default: 2522: Ldefault: 2523: numpara += paramsize(e->E2,stackalign); 2524: break; 2525: } 2526: assert((numpara & (REGSIZE - 1)) == 0); 2527: assert((stackpush & (REGSIZE - 1)) == 0); 2528: 2529: /* Special handling for call to __tls_get_addr, we must save registers 2530: * before evaluating the parameter, so that the parameter load and call 2531: * are adjacent. 2532: */ 2533: if (e->E2->Eoper != OPparam && e->E1->Eoper == OPvar) 2534: { symbol *s = e->E1->EV.sp.Vsym; 2535: if (s == tls_get_addr_sym) 2536: c = getregs(~s->Sregsaved & (mBP | ALLREGS | mES | XMMREGS)); 2537: } 2538: 2539: 2540: /* Adjust start of the stack so after all args are pushed, 2541: * the stack will be aligned. 2542: */ 2543: if (STACKALIGN == 16 && (numpara + stackpush) & (STACKALIGN - 1)) 2544: { 2545: numalign = STACKALIGN - ((numpara + stackpush) & (STACKALIGN - 1)); 2546: c = genc2(c,0x81,modregrm(3,5,SP),numalign); // SUB ESP,numalign 2547: if (I64) 2548: code_orrex(c, REX_W); 2549: c = genadjesp(c, numalign); 2550: stackpush += numalign; 2551: stackpushsave += numalign; 2552: } 2553: 2554: switch (tyf) 2555: { case TYf16func: 2556: stackalign = 2; 2557: goto Ldefault2; 2558: case TYmfunc: // last parameter goes into ECX 2559: preg = CX; 2560: goto L1; 2561: case TYjfunc: // last parameter goes into EAX 2562: preg = AX; 2563: goto L1; 2564: L1: 2565: { elem *ep; 2566: elem *en; 2567: for (ep = e->E2; ep->Eoper == OPparam; ep = en) 2568: { 2569: c = cat(c,params(ep->E1,stackalign)); 2570: en = ep->E2; 2571: freenode(ep); 2572: } 2573: unsigned sz; 2574: if (tyf == TYjfunc && 2575: // This must match type_jparam() 2576: !(tyjparam(ep->Ety) || 2577: ((tybasic(ep->Ety) == TYstruct || tybasic(ep->Ety) == TYarray) && 2578: (sz = type_size(ep->ET)) <= intsize && sz != 3 && sz)
warning C4018: '<=' : signed/unsigned mismatch
2579: ) 2580: ) 2581: { 2582: c = cat(c,params(ep,stackalign)); 2583: goto Lret; 2584: } 2585: // preg is the register to put the parameter ep in 2586: keepmsk = mask[preg]; // don't change preg when evaluating func address 2587: regm_t retregs = keepmsk; 2588: if (ep->Eoper == OPstrthis) 2589: { code *c2; 2590: 2591: code *c1 = getregs(retregs); 2592: // LEA preg,np[ESP] 2593: unsigned np = stackpush - ep->EV.Vuns; // stack delta to parameter 2594: c2 = genc1(CNIL,0x8D,(modregrm(0,4,SP) << 8) | modregrm(2,preg,4),FLconst,np); 2595: if (I64) 2596: code_orrex(c2, REX_W); 2597: c = cat3(c,c1,c2); 2598: } 2599: else 2600: { code *cp = codelem(ep,&retregs,FALSE); 2601: c = cat(c,cp); 2602: } 2603: goto Lret; 2604: } 2605: default: 2606: Ldefault2: 2607: c = cat(c, params(e->E2,stackalign)); // push parameters 2608: break; 2609: } 2610: } 2611: else 2612: { assert(I64); 2613: 2614: // Easier to deal with parameters as an array: parameters[0..np] 2615: int np = el_nparams(e->E2); 2616: Parameter *parameters = (Parameter *)alloca(np * sizeof(Parameter));
warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead
2617: 2618: { int n = 0; 2619: fillParameters(e->E2, parameters, &n); 2620: assert(n == np); 2621: } 2622: 2623: /* Special handling for call to __tls_get_addr, we must save registers 2624: * before evaluating the parameter, so that the parameter load and call 2625: * are adjacent. 2626: */ 2627: if (np == 1 && e->E1->Eoper == OPvar) 2628: { symbol *s = e->E1->EV.sp.Vsym; 2629: if (s == tls_get_addr_sym) 2630: c = getregs(~s->Sregsaved & (mBP | ALLREGS | mES | XMMREGS)); 2631: } 2632: 2633: unsigned stackalign = REGSIZE; 2634: 2635: // Figure out which parameters go in registers 2636: // Compute numpara, the total bytes pushed on the stack 2637: int r = 0; 2638: int xmmcnt = XMM0; 2639: for (int i = np; --i >= 0;) 2640: { 2641: static const unsigned char argregs[6] = { DI,SI,DX,CX,R8,R9 }; 2642: elem *ep = parameters[i].e; 2643: tym_t ty = ep->Ety; 2644: if (r < sizeof(argregs)/sizeof(argregs[0])) // if more arg regs 2645: { unsigned sz; 2646: if ( 2647: // This must match type_jparam() 2648: ty64reg(ty) || 2649: ((tybasic(ty) == TYstruct || tybasic(ty) == TYarray) && 2650: ((sz = type_size(ep->ET)) == 1 || sz == 2 || sz == 4 || sz == 8)) 2651: ) 2652: { 2653: parameters[i].reg = argregs[r]; 2654: r++; 2655: continue; // goes in register, not stack 2656: } 2657: } 2658: if (xmmcnt <= XMM7) 2659: { 2660: if (tyfloating(ty) && tysize(ty) <= 8 && !tycomplex(ty)) 2661: { 2662: parameters[i].reg = xmmcnt; 2663: xmmcnt++; 2664: continue; // goes in register, not stack 2665: } 2666: } 2667: 2668: // Parameter i goes on the stack 2669: parameters[i].reg = -1; // -1 means no register 2670: unsigned alignsize = el_alignsize(ep); 2671: parameters[i].numalign = 0; 2672: if (alignsize > stackalign) 2673: { unsigned newnumpara = (numpara + (alignsize - 1)) & ~(alignsize - 1); 2674: parameters[i].numalign = newnumpara - numpara; 2675: numpara = newnumpara; 2676: } 2677: numpara += paramsize(ep,stackalign); 2678: } 2679: 2680: assert((numpara & (REGSIZE - 1)) == 0); 2681: assert((stackpush & (REGSIZE - 1)) == 0); 2682: 2683: /* Should consider reordering the order of evaluation of the parameters 2684: * so that args that go into registers are evaluated after args that get 2685: * pushed. We can reorder args that are constants or relconst's. 2686: */ 2687: 2688: /* Adjust start of the stack so after all args are pushed, 2689: * the stack will be aligned. 2690: */ 2691: if (STACKALIGN == 16 && (numpara + stackpush) & (STACKALIGN - 1)) 2692: { 2693: numalign = STACKALIGN - ((numpara + stackpush) & (STACKALIGN - 1)); 2694: c = genc2(c,0x81,(REX_W << 16) | modregrm(3,5,SP),numalign); // SUB RSP,numalign 2695: c = genadjesp(c, numalign); 2696: stackpush += numalign; 2697: stackpushsave += numalign; 2698: } 2699: 2700: int regsaved[XMM7 + 1]; 2701: memset(regsaved, -1, sizeof(regsaved)); 2702: code *crest = NULL; 2703: regm_t saved = 0; 2704: 2705: /* Parameters go into the registers RDI,RSI,RDX,RCX,R8,R9 2706: * float and double parameters go into XMM0..XMM7 2707: * For variadic functions, count of XMM registers used goes in AL 2708: */ 2709: for (int i = 0; i < np; i++) 2710: { 2711: elem *ep = parameters[i].e; 2712: int preg = parameters[i].reg;
warning C6246: Local declaration of 'preg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2474' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 2474
2713: if (preg == -1) 2714: { 2715: /* Push parameter on stack, but keep track of registers used 2716: * in the process. If they interfere with keepmsk, we'll have 2717: * to save/restore them. 2718: */ 2719: code *csave = NULL; 2720: regm_t overlap = msavereg & keepmsk; 2721: msavereg |= keepmsk; 2722: code *cp = params(ep,stackalign); 2723: regm_t tosave = keepmsk & ~msavereg; 2724: msavereg &= ~keepmsk | overlap; 2725: 2726: // tosave is the mask to save and restore 2727: for (int j = 0; tosave; j++) 2728: { regm_t mi = mask[j]; 2729: assert(j <= XMM7); 2730: if (mi & tosave) 2731: { 2732: unsigned idx; 2733: csave = regsave.save(csave, j, &idx); 2734: crest = regsave.restore(crest, j, idx); 2735: saved |= mi; 2736: keepmsk &= ~mi; // don't need to keep these for rest of params 2737: tosave &= ~mi; 2738: } 2739: } 2740: 2741: c = cat4(c, csave, cp, NULL); 2742: 2743: // Alignment for parameter comes after it got pushed 2744: unsigned numalign = parameters[i].numalign;
warning C6246: Local declaration of 'numalign' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2476' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 2476
2745: if (numalign) 2746: { 2747: c = genc2(c,0x81,(REX_W << 16) | modregrm(3,5,SP),numalign); // SUB RSP,numalign 2748: c = genadjesp(c, numalign); 2749: stackpush += numalign; 2750: } 2751: } 2752: else 2753: { 2754: // Goes in register preg, not stack 2755: regm_t retregs = mask[preg]; 2756: if (ep->Eoper == OPstrthis) 2757: { 2758: code *c1 = getregs(retregs); 2759: // LEA preg,np[RSP] 2760: unsigned np = stackpush - ep->EV.Vuns; // stack delta to parameter
warning C6246: Local declaration of 'np' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2615' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 2615
2761: code *c2 = genc1(CNIL,0x8D,(REX_W << 16) | 2762: (modregrm(0,4,SP) << 8) | 2763: modregxrm(2,preg,4), FLconst,np); 2764: c = cat3(c,c1,c2); 2765: } 2766: else 2767: { code *cp = scodelem(ep,&retregs,keepmsk,FALSE); 2768: c = cat(c,cp); 2769: } 2770: keepmsk |= retregs; // don't change preg when evaluating func address 2771: } 2772: } 2773: 2774: // Restore any register parameters we saved 2775: c = cat4(c, getregs(saved), crest, NULL); 2776: keepmsk |= saved; 2777: 2778: // Variadic functions store the number of XMM registers used in AL 2779: if (e->Eflags & EFLAGS_variadic) 2780: { code *c1 = getregs(mAX); 2781: c1 = movregconst(c1,AX,xmmcnt - XMM0,1); 2782: c = cat(c, c1); 2783: keepmsk |= mAX; 2784: } 2785: } 2786: } 2787: else 2788: { 2789: /* Adjust start of the stack so 2790: * the stack will be aligned. 2791: */ 2792: if (STACKALIGN == 16 && (stackpush) & (STACKALIGN - 1)) 2793: { 2794: numalign = STACKALIGN - ((stackpush) & (STACKALIGN - 1)); 2795: c = genc2(NULL,0x81,modregrm(3,5,SP),numalign); // SUB ESP,numalign 2796: if (I64) 2797: code_orrex(c, REX_W); 2798: c = genadjesp(c, numalign); 2799: stackpush += numalign; 2800: stackpushsave += numalign; 2801: } 2802: 2803: } 2804: Lret: 2805: cgstate.stackclean--; 2806: if (I16) 2807: numpara = stackpush - stackpushsave; 2808: else 2809: { 2810: if (numpara != stackpush - stackpushsave) 2811: printf("numpara = %d, stackpush = %d, stackpushsave = %d\n", numpara, stackpush, stackpushsave); 2812: assert(numpara == stackpush - stackpushsave); 2813: } 2814: return cat(c,funccall(e,numpara,numalign,pretregs,keepmsk)); 2815: } 2816: 2817: /*********************************** 2818: */ 2819: 2820: code *cdstrthis(elem *e,regm_t *pretregs) 2821: { 2822: code *c1; 2823: code *c2; 2824: 2825: assert(tysize(e->Ety) == REGSIZE); 2826: unsigned reg = findreg(*pretregs & allregs); 2827: c1 = getregs(mask[reg]); 2828: // LEA reg,np[ESP] 2829: unsigned np = stackpush - e->EV.Vuns; // stack delta to parameter 2830: c2 = genc1(CNIL,0x8D,(modregrm(0,4,SP) << 8) | modregxrm(2,reg,4),FLconst,np); 2831: if (I64) 2832: code_orrex(c2, REX_W); 2833: return cat3(c1,c2,fixresult(e,mask[reg],pretregs)); 2834: } 2835: 2836: /****************************** 2837: * Call function. All parameters are pushed onto the stack, numpara gives 2838: * the size of them all. 2839: */ 2840: 2841: STATIC code * funccall(elem *e,unsigned numpara,unsigned numalign,regm_t *pretregs,regm_t keepmsk) 2842: { 2843: elem *e1; 2844: code *c,*ce,cs; 2845: tym_t tym1; 2846: char farfunc; 2847: regm_t retregs; 2848: symbol *s; 2849: 2850: //printf("funccall(e = %p, *pretregs = x%x, numpara = %d, numalign = %d)\n",e,*pretregs,numpara,numalign); 2851: calledafunc = 1; 2852: /* Determine if we need frame for function prolog/epilog */ 2853: #if TARGET_WINDOS 2854: if (config.memmodel == Vmodel) 2855: { 2856: if (tyfarfunc(funcsym_p->ty())) 2857: needframe = TRUE; 2858: } 2859: #endif 2860: e1 = e->E1; 2861: tym1 = tybasic(e1->Ety); 2862: farfunc = tyfarfunc(tym1) || tym1 == TYifunc; 2863: c = NULL; 2864: if (e1->Eoper == OPvar) 2865: { /* Call function directly */ 2866: code *c1; 2867: 2868: #ifdef DEBUG 2869: if (!tyfunc(tym1)) WRTYxx(tym1); 2870: #endif 2871: assert(tyfunc(tym1)); 2872: s = e1->EV.sp.Vsym; 2873: if (s->Sflags & SFLexit) 2874: c = NULL; 2875: else if (s != tls_get_addr_sym) 2876: c = save87(); // assume 8087 regs are all trashed 2877: if (s->Sflags & SFLexit) 2878: // Function doesn't return, so don't worry about registers 2879: // it may use 2880: c1 = NULL; 2881: else if (!tyfunc(s->ty()) || !(config.flags4 & CFG4optimized)) 2882: // so we can replace func at runtime 2883: c1 = getregs(~fregsaved & (mBP | ALLREGS | mES | XMMREGS)); 2884: else 2885: c1 = getregs(~s->Sregsaved & (mBP | ALLREGS | mES | XMMREGS)); 2886: if (strcmp(s->Sident,"alloca") == 0) 2887: { 2888: #if 1 2889: s = rtlsym[RTLSYM_ALLOCA]; 2890: makeitextern(s); 2891: c1 = cat(c1,getregs(mCX)); 2892: c1 = genc(c1,0x8D,modregrm(2,CX,BPRM),FLallocatmp,0,0,0); // LEA CX,&localsize[BP] 2893: if (I64) 2894: code_orrex(c1, REX_W); 2895: usedalloca = 2; // new way 2896: #else 2897: usedalloca = 1; // old way 2898: #endif 2899: } 2900: if (sytab[s->Sclass] & SCSS) // if function is on stack (!) 2901: { 2902: retregs = allregs & ~keepmsk; 2903: s->Sflags &= ~GTregcand; 2904: s->Sflags |= SFLread; 2905: ce = cat(c1,cdrelconst(e1,&retregs)); 2906: if (farfunc) 2907: goto LF1; 2908: else 2909: goto LF2; 2910: } 2911: else 2912: { int fl; 2913: 2914: fl = FLfunc; 2915: if (!tyfunc(s->ty())) 2916: fl = el_fl(e1); 2917: if (tym1 == TYifunc) 2918: c1 = gen1(c1,0x9C); // PUSHF 2919: #if 0 && TARGET_LINUX 2920: if (s->Sfl == FLgot || s->Sfl == FLgotoff) 2921: fl = s->Sfl; 2922: #endif 2923: ce = gencs(CNIL,farfunc ? 0x9A : 0xE8,0,fl,s); // CALL extern 2924: ce->Iflags |= farfunc ? (CFseg | CFoff) : (CFselfrel | CFoff); 2925: #if TARGET_LINUX 2926: if (s == tls_get_addr_sym) 2927: { 2928: if (I32) 2929: { 2930: /* Append a NOP so GNU linker has patch room 2931: */ 2932: ce = gen1(ce, 0x90); // NOP 2933: code_orflag(ce, CFvolatile); // don't schedule it 2934: } 2935: else 2936: { /* Prepend 66 66 48 so GNU linker has patch room 2937: */ 2938: assert(I64); 2939: ce->Irex = REX | REX_W; 2940: ce = cat(gen1(CNIL, 0x66), ce); 2941: ce = cat(gen1(CNIL, 0x66), ce); 2942: } 2943: } 2944: #endif 2945: } 2946: ce = cat(c1,ce); 2947: } 2948: else 2949: { /* Call function via pointer */ 2950: elem *e11; 2951: tym_t e11ty; 2952: 2953: #ifdef DEBUG 2954: if (e1->Eoper != OPind 2955: ) { WRFL((enum FL)el_fl(e1)); WROP(e1->Eoper); } 2956: #endif 2957: c = save87(); // assume 8087 regs are all trashed 2958: assert(e1->Eoper == OPind); 2959: e11 = e1->E1; 2960: e11ty = tybasic(e11->Ety); 2961: assert(!I16 || (e11ty == (farfunc ? TYfptr : TYnptr))); 2962: 2963: /* if we can't use loadea() */ 2964: if ((EOP(e11) || e11->Eoper == OPconst) && 2965: (e11->Eoper != OPind || e11->Ecount)) 2966: { 2967: unsigned reg; 2968: 2969: retregs = allregs & ~keepmsk; 2970: cgstate.stackclean++; 2971: ce = scodelem(e11,&retregs,keepmsk,TRUE); 2972: cgstate.stackclean--; 2973: /* Kill registers destroyed by an arbitrary function call */ 2974: ce = cat(ce,getregs((mBP | ALLREGS | mES | XMMREGS) & ~fregsaved)); 2975: if (e11ty == TYfptr) 2976: { unsigned lsreg; 2977: LF1: 2978: reg = findregmsw(retregs); 2979: lsreg = findreglsw(retregs); 2980: floatreg = TRUE; /* use float register */ 2981: reflocal = TRUE; 2982: ce = genc1(ce,0x89, /* MOV floatreg+2,reg */ 2983: modregrm(2,reg,BPRM),FLfltreg,REGSIZE); 2984: genc1(ce,0x89, /* MOV floatreg,lsreg */ 2985: modregrm(2,lsreg,BPRM),FLfltreg,0); 2986: if (tym1 == TYifunc) 2987: gen1(ce,0x9C); // PUSHF 2988: genc1(ce,0xFF, /* CALL [floatreg] */ 2989: modregrm(2,3,BPRM),FLfltreg,0); 2990: } 2991: else 2992: { 2993: LF2: 2994: reg = findreg(retregs); 2995: ce = gen2(ce,0xFF,modregrmx(3,2,reg)); /* CALL reg */ 2996: if (I64) 2997: code_orrex(ce, REX_W); 2998: } 2999: } 3000: else 3001: { 3002: if (tym1 == TYifunc) 3003: c = gen1(c,0x9C); // PUSHF 3004: // CALL [function] 3005: cs.Iflags = 0; 3006: cgstate.stackclean++; 3007: ce = loadea(e11,&cs,0xFF,farfunc ? 3 : 2,0,keepmsk,(mBP|ALLREGS|mES|XMMREGS) & ~fregsaved); 3008: cgstate.stackclean--; 3009: freenode(e11); 3010: } 3011: s = NULL; 3012: } 3013: c = cat(c,ce); 3014: freenode(e1); 3015: 3016: /* See if we will need the frame pointer. 3017: Calculate it here so we can possibly use BP to fix the stack. 3018: */ 3019: #if 0 3020: if (!needframe) 3021: { SYMIDX si; 3022: 3023: /* If there is a register available for this basic block */ 3024: if (config.flags4 & CFG4optimized && (ALLREGS & ~regcon.used)) 3025: ; 3026: else 3027: { 3028: for (si = 0; si < globsym.top; si++) 3029: { symbol *s = globsym.tab[si]; 3030: 3031: if (s->Sflags & GTregcand && type_size(s->Stype) != 0) 3032: { 3033: if (config.flags4 & CFG4optimized) 3034: { /* If symbol is live in this basic block and */ 3035: /* isn't already in a register */ 3036: if (s->Srange && vec_testbit(dfoidx,s->Srange) && 3037: s->Sfl != FLreg) 3038: { /* Then symbol must be allocated on stack */ 3039: needframe = TRUE; 3040: break; 3041: } 3042: } 3043: else 3044: { if (mfuncreg == 0) /* if no registers left */ 3045: { needframe = TRUE; 3046: break; 3047: } 3048: } 3049: } 3050: } 3051: } 3052: } 3053: #endif 3054: 3055: retregs = regmask(e->Ety, tym1); 3056: 3057: // If stack needs cleanup 3058: if (OTbinary(e->Eoper) && 3059: !typfunc(tym1) && 3060: !(s && s->Sflags & SFLexit)) 3061: { 3062: if (tym1 == TYhfunc) 3063: { // Hidden parameter is popped off by the callee 3064: c = genadjesp(c, -REGSIZE); 3065: stackpush -= REGSIZE; 3066: if (numpara + numalign > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
3067: c = genstackclean(c, numpara + numalign - REGSIZE, retregs); 3068: } 3069: else 3070: c = genstackclean(c,numpara + numalign,retregs); 3071: } 3072: else 3073: { 3074: c = genadjesp(c,-numpara);
warning C4146: unary minus operator applied to unsigned type, result still unsigned
3075: stackpush -= numpara; 3076: if (numalign) 3077: c = genstackclean(c,numalign,retregs); 3078: } 3079: 3080: /* Special handling for functions which return a floating point 3081: value in the top of the 8087 stack. 3082: */ 3083: 3084: if (retregs & mST0) 3085: { 3086: if (*pretregs) // if we want the result 3087: { //assert(stackused == 0); 3088: push87(); // one item on 8087 stack 3089: return cat(c,fixresult87(e,retregs,pretregs)); 3090: } 3091: else 3092: /* Pop unused result off 8087 stack */ 3093: c = gen2(c,0xDD,modregrm(3,3,0)); /* FPOP */ 3094: } 3095: else if (retregs & mST01) 3096: { 3097: if (*pretregs) // if we want the result 3098: { assert(stackused == 0); 3099: push87(); 3100: push87(); // two items on 8087 stack 3101: return cat(c,fixresult_complex87(e,retregs,pretregs)); 3102: } 3103: else 3104: { 3105: // Pop unused result off 8087 stack 3106: c = gen2(c,0xDD,modregrm(3,3,0)); // FPOP 3107: c = gen2(c,0xDD,modregrm(3,3,0)); // FPOP 3108: } 3109: } 3110: 3111: return cat(c,fixresult(e,retregs,pretregs)); 3112: } 3113: 3114: /*************************** 3115: * Determine size of everything that will be pushed. 3116: */ 3117: 3118: targ_size_t paramsize(elem *e,unsigned stackalign) 3119: { 3120: targ_size_t psize = 0; 3121: targ_size_t szb; 3122: 3123: while (e->Eoper == OPparam) /* if more params */ 3124: { 3125: elem *e2 = e->E2; 3126: psize += paramsize(e->E1,stackalign); // push them backwards 3127: e = e2; 3128: } 3129: tym_t tym = tybasic(e->Ety); 3130: if (tyscalar(tym)) 3131: szb = size(tym); 3132: else if (tym == TYstruct) 3133: szb = type_size(e->ET); 3134: else 3135: { 3136: #ifdef DEBUG 3137: WRTYxx(tym); 3138: #endif 3139: assert(0); 3140: } 3141: psize += align(stackalign,szb); /* align on word stack boundary */ 3142: return psize; 3143: } 3144: 3145: /*************************** 3146: * Generate code to push parameter list. 3147: * stackpush is incremented by stackalign for each PUSH. 3148: */ 3149: 3150: code *params(elem *e,unsigned stackalign) 3151: { code *c,*ce,cs; 3152: code *cp; 3153: unsigned reg; 3154: targ_size_t szb; // size before alignment 3155: targ_size_t sz; // size after alignment 3156: tym_t tym; 3157: regm_t retregs; 3158: elem *e1; 3159: elem *e2; 3160: symbol *s;
warning C4101: 's' : unreferenced local variable
3161: int fl;
warning C4101: 'fl' : unreferenced local variable
3162: 3163: //printf("params(e = %p, stackalign = %d)\n", e, stackalign); 3164: cp = NULL; 3165: stackchanged = 1; 3166: assert(e); 3167: while (e->Eoper == OPparam) /* if more params */ 3168: { 3169: e2 = e->E2; 3170: cp = cat(cp,params(e->E1,stackalign)); // push them backwards 3171: freenode(e); 3172: e = e2; 3173: } 3174: //printf("params()\n"); elem_print(e); 3175: 3176: tym = tybasic(e->Ety); 3177: if (tyfloating(tym)) 3178: obj_fltused(); 3179: 3180: int grex = I64 ? REX_W << 16 : 0; 3181: 3182: /* sz = number of bytes pushed */ 3183: if (tyscalar(tym)) 3184: szb = size(tym); 3185: else if (tym == TYstruct) 3186: szb = type_size(e->ET); 3187: else 3188: { 3189: #ifdef DEBUG 3190: WRTYxx(tym); 3191: #endif 3192: assert(0); 3193: } 3194: sz = align(stackalign,szb); /* align on word stack boundary */ 3195: assert((sz & (stackalign - 1)) == 0); /* ensure that alignment worked */ 3196: assert((sz & (REGSIZE - 1)) == 0); 3197: 3198: c = CNIL; 3199: cs.Iflags = 0; 3200: cs.Irex = 0; 3201: switch (e->Eoper) 3202: { 3203: #if SCPP 3204: case OPstrctor: 3205: { 3206: e1 = e->E1; 3207: c = docommas(&e1); /* skip over any comma expressions */ 3208: 3209: c = genc2(c,0x81,grex | modregrm(3,5,SP),sz); // SUB SP,sizeof(struct) 3210: stackpush += sz; 3211: genadjesp(c,sz); 3212: 3213: // Find OPstrthis and set it to stackpush 3214: exp2_setstrthis(e1,NULL,stackpush,NULL); 3215: 3216: retregs = 0; 3217: ce = codelem(e1,&retregs,TRUE); 3218: goto L2; 3219: } 3220: case OPstrthis: 3221: // This is the parameter for the 'this' pointer corresponding to 3222: // OPstrctor. We push a pointer to an object that was already 3223: // allocated on the stack by OPstrctor. 3224: { unsigned np; 3225: 3226: retregs = allregs; 3227: c = allocreg(&retregs,&reg,TYoffset); 3228: c = genregs(c,0x89,SP,reg); // MOV reg,SP 3229: if (I64) 3230: code_orrex(c, REX_W); 3231: np = stackpush - e->EV.Vuns; // stack delta to parameter 3232: c = genc2(c,0x81,grex | modregrmx(3,0,reg),np); // ADD reg,np 3233: if (sz > REGSIZE) 3234: { c = gen1(c,0x16); // PUSH SS 3235: stackpush += REGSIZE; 3236: } 3237: c = gen1(c,0x50 + (reg & 7)); // PUSH reg 3238: if (reg & 8) 3239: code_orrex(c, REX_B); 3240: stackpush += REGSIZE; 3241: genadjesp(c,sz); 3242: ce = CNIL; 3243: goto L2; 3244: } 3245: #endif 3246: case OPstrpar: 3247: { code *cc,*c1,*c2,*c3; 3248: unsigned rm; 3249: unsigned seg; // segment override prefix flags 3250: bool doneoff; 3251: unsigned pushsize = REGSIZE; 3252: unsigned op16 = 0; 3253: unsigned npushes; 3254: 3255: e1 = e->E1; 3256: if (sz == 0) 3257: { 3258: ce = docommas(&e1); /* skip over any commas */ 3259: goto L2; 3260: } 3261: if ((sz & 3) == 0 && (sz / REGSIZE) <= 4 && e1->Eoper == OPvar) 3262: { freenode(e); 3263: e = e1; 3264: goto L1; 3265: } 3266: cc = docommas(&e1); /* skip over any commas */ 3267: seg = 0; /* assume no seg override */ 3268: retregs = sz ? IDXREGS : 0; 3269: doneoff = FALSE; 3270: if (!I16 && sz & 2) // if odd number of words to push
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3271: { pushsize = 2; 3272: op16 = 1; 3273: } 3274: else if (I16 && config.target_cpu >= TARGET_80386 && (sz & 3) == 0) 3275: { pushsize = 4; // push DWORDs at a time 3276: op16 = 1; 3277: } 3278: npushes = sz / pushsize; 3279: switch (e1->Eoper) 3280: { case OPind: 3281: if (sz) 3282: { switch (tybasic(e1->E1->Ety)) 3283: { 3284: case TYfptr: 3285: case TYhptr: 3286: seg = CFes; 3287: retregs |= mES; 3288: break; 3289: case TYsptr: 3290: if (config.wflags & WFssneds) 3291: seg = CFss; 3292: break; 3293: case TYcptr: 3294: seg = CFcs; 3295: break; 3296: } 3297: } 3298: c1 = codelem(e1->E1,&retregs,FALSE); 3299: freenode(e1); 3300: break; 3301: case OPvar: 3302: /* Symbol is no longer a candidate for a register */ 3303: e1->EV.sp.Vsym->Sflags &= ~GTregcand; 3304: 3305: if (!e1->Ecount && npushes > 4) 3306: { /* Kludge to point at last word in struct. */ 3307: /* Don't screw up CSEs. */ 3308: e1->EV.sp.Voffset += sz - pushsize; 3309: doneoff = TRUE; 3310: } 3311: //if (LARGEDATA) /* if default isn't DS */ 3312: { static unsigned segtocf[4] = { CFes,CFcs,CFss,0 }; 3313: unsigned s;
warning C6246: Local declaration of 's' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3160' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3160
3314: int fl;
warning C6246: Local declaration of 'fl' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3161' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3161
3315: 3316: fl = el_fl(e1); 3317: if (fl == FLfardata) 3318: { seg = CFes; 3319: assert(!TARGET_FLAT); 3320: retregs |= mES; 3321: } 3322: else 3323: { 3324: s = segfl[fl]; 3325: assert(s < 4); 3326: seg = segtocf[s]; 3327: if (seg == CFss && !(config.wflags & WFssneds)) 3328: seg = 0; 3329: } 3330: } 3331: #if !TARGET_FLAT 3332: if (e1->Ety & mTYfar) 3333: { seg = CFes; 3334: retregs |= mES; 3335: } 3336: #endif 3337: c1 = cdrelconst(e1,&retregs); 3338: /* Reverse the effect of the previous add */ 3339: if (doneoff) 3340: e1->EV.sp.Voffset -= sz - pushsize; 3341: freenode(e1); 3342: break; 3343: case OPstreq: 3344: //case OPcond: 3345: if (!(config.exe & EX_flat)) 3346: { seg = CFes; 3347: retregs |= mES; 3348: } 3349: c1 = codelem(e1,&retregs,FALSE); 3350: break; 3351: default: 3352: #ifdef DEBUG 3353: elem_print(e1); 3354: #endif 3355: assert(0); 3356: } 3357: reg = findreglsw(retregs); 3358: rm = I16 ? regtorm[reg] : regtorm32[reg]; 3359: if (op16) 3360: seg |= CFopsize; // operand size 3361: if (npushes <= 4) 3362: { 3363: assert(!doneoff); 3364: for (c2 = CNIL; npushes > 1; npushes--) 3365: { c2 = genc1(c2,0xFF,buildModregrm(2,6,rm),FLconst,pushsize * (npushes - 1)); // PUSH [reg] 3366: code_orflag(c2,seg); 3367: genadjesp(c2,pushsize); 3368: } 3369: c3 = gen2(CNIL,0xFF,buildModregrm(0,6,rm)); // PUSH [reg] 3370: c3->Iflags |= seg; 3371: genadjesp(c3,pushsize); 3372: ce = cat4(cc,c1,c2,c3); 3373: } 3374: else if (sz) 3375: { int size; 3376: 3377: c2 = getregs_imm(mCX | retregs); 3378: /* MOV CX,sz/2 */ 3379: c2 = movregconst(c2,CX,npushes,0); 3380: if (!doneoff) 3381: { /* This disgusting thing should be done when */ 3382: /* reg is loaded. Too lazy to fix it now. */ 3383: /* ADD reg,sz-2 */ 3384: c2 = genc2(c2,0x81,grex | modregrmx(3,0,reg),sz-pushsize); 3385: } 3386: c3 = getregs(mCX); // the LOOP decrements it 3387: c3 = gen2(c3,0xFF,buildModregrm(0,6,rm)); // PUSH [reg] 3388: c3->Iflags |= seg | CFtarg2; 3389: genc2(c3,0x81,grex | buildModregrm(3,5,reg),pushsize); // SUB reg,2 3390: size = ((seg & CFSEG) ? -8 : -7) - op16; 3391: if (code_next(c3)->Iop != 0x81) 3392: size++; 3393: //genc2(c3,0xE2,0,size); // LOOP .-7 or .-8 3394: genjmp(c3,0xE2,FLcode,(block *)c3); // LOOP c3 3395: regimmed_set(CX,0); 3396: genadjesp(c3,sz); 3397: ce = cat4(cc,c1,c2,c3); 3398: } 3399: else 3400: ce = cat(cc,c1); 3401: stackpush += sz; 3402: goto L2; 3403: } 3404: case OPind: 3405: if (!e->Ecount) /* if *e1 */ 3406: { if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
3407: { // Watch out for single byte quantities being up 3408: // against the end of a segment or in memory-mapped I/O 3409: if (!(config.exe & EX_flat) && szb == 1) 3410: break; 3411: goto L1; // can handle it with loadea() 3412: } 3413: 3414: // Avoid PUSH MEM on the Pentium when optimizing for speed 3415: if (config.flags4 & CFG4speed && 3416: (config.target_cpu >= TARGET_80486 && 3417: config.target_cpu <= TARGET_PentiumMMX) && 3418: sz <= 2 * REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
3419: !tyfloating(tym)) 3420: break; 3421: 3422: if (tym == TYldouble || tym == TYildouble || tycomplex(tym)) 3423: break; 3424: if (I32) 3425: { 3426: assert(sz == REGSIZE * 2); 3427: ce = loadea(e,&cs,0xFF,6,REGSIZE,0,0); /* PUSH EA+4 */ 3428: ce = genadjesp(ce,REGSIZE); 3429: } 3430: else 3431: { 3432: if (sz == DOUBLESIZE) 3433: { ce = loadea(e,&cs,0xFF,6,DOUBLESIZE - REGSIZE,0,0); /* PUSH EA+6 */ 3434: cs.IEVoffset1 -= REGSIZE; 3435: gen(ce,&cs); /* PUSH EA+4 */ 3436: ce = genadjesp(ce,REGSIZE); 3437: getlvalue_lsw(&cs); 3438: gen(ce,&cs); /* PUSH EA+2 */ 3439: } 3440: else /* TYlong */ 3441: ce = loadea(e,&cs,0xFF,6,REGSIZE,0,0); /* PUSH EA+2 */ 3442: ce = genadjesp(ce,REGSIZE); 3443: } 3444: stackpush += sz; 3445: getlvalue_lsw(&cs); 3446: gen(ce,&cs); /* PUSH EA */ 3447: ce = genadjesp(ce,REGSIZE); 3448: goto L2; 3449: } 3450: break; 3451: case OPptrlptr: 3452: if (!e->Ecount) /* if (far *)e1 */ 3453: { 3454: int segreg; 3455: tym_t tym1; 3456: 3457: e1 = e->E1; 3458: tym1 = tybasic(e1->Ety); 3459: /* BUG: what about pointers to functions? */ 3460: segreg = (tym1 == TYnptr) ? 3<<3 : 3461: (tym1 == TYcptr) ? 1<<3 : 2<<3; 3462: if (I32 && stackalign == 2) 3463: c = gen1(c,0x66); /* push a word */ 3464: c = gen1(c,0x06 + segreg); /* PUSH SEGREG */ 3465: if (I32 && stackalign == 2) 3466: code_orflag(c,CFopsize); // push a word 3467: c = genadjesp(c,stackalign); 3468: stackpush += stackalign; 3469: ce = params(e1,stackalign); 3470: goto L2; 3471: } 3472: break; 3473: case OPrelconst: 3474: #if !TARGET_FLAT 3475: /* Determine if we can just push the segment register */ 3476: /* Test size of type rather than TYfptr because of (long)(&v) */ 3477: s = e->EV.sp.Vsym; 3478: //if (sytab[s->Sclass] & SCSS && !I32) // if variable is on stack 3479: // needframe = TRUE; // then we need stack frame 3480: if (tysize[tym] == tysize[TYfptr] && 3481: (fl = s->Sfl) != FLfardata && 3482: /* not a function that CS might not be the segment of */ 3483: (!((fl == FLfunc || s->ty() & mTYcs) && 3484: (s->Sclass == SCcomdat || s->Sclass == SCextern || s->Sclass == SCinline || config.wflags & WFthunk)) || 3485: (fl == FLfunc && config.exe == EX_DOSX) 3486: ) 3487: ) 3488: { 3489: stackpush += sz; 3490: c = gen1(c,0x06 + /* PUSH SEGREG */ 3491: (((fl == FLfunc || s->ty() & mTYcs) ? 1 : segfl[fl]) << 3)); 3492: c = genadjesp(c,REGSIZE); 3493: 3494: if (config.target_cpu >= TARGET_80286 && !e->Ecount) 3495: { ce = getoffset(e,STACK); 3496: goto L2; 3497: } 3498: else 3499: { c = cat(c,offsetinreg(e,&retregs)); 3500: unsigned reg = findreg(retregs); 3501: c = genpush(c,reg); // PUSH reg 3502: genadjesp(c,REGSIZE); 3503: } 3504: goto ret; 3505: } 3506: if (config.target_cpu >= TARGET_80286 && !e->Ecount) 3507: { 3508: stackpush += sz; 3509: if (tysize[tym] == tysize[TYfptr]) 3510: { 3511: /* PUSH SEG e */ 3512: code *c1 = gencs(CNIL,0x68,0,FLextern,s); 3513: c1->Iflags = CFseg; 3514: genadjesp(c1,REGSIZE); 3515: c = cat(c,c1); 3516: } 3517: ce = getoffset(e,STACK); 3518: goto L2; 3519: } 3520: #endif 3521: break; /* else must evaluate expression */ 3522: case OPvar: 3523: L1: 3524: if (0 && I32 && sz == 2) 3525: { /* 32 bit code, but pushing 16 bit values anyway */ 3526: ce = loadea(e,&cs,0xFF,6,0,0,0); /* PUSH EA */ 3527: // BUG: 0x66 fails with scheduler 3528: ce = cat(gen1(CNIL,0x66),ce); /* 16 bit override */ 3529: stackpush += sz; 3530: genadjesp(ce,sz); 3531: } 3532: else if (config.flags4 & CFG4speed && 3533: (config.target_cpu >= TARGET_80486 && 3534: config.target_cpu <= TARGET_PentiumMMX) && 3535: sz <= 2 * REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
3536: !tyfloating(tym)) 3537: { // Avoid PUSH MEM on the Pentium when optimizing for speed 3538: break; 3539: } 3540: else 3541: { int regsize = REGSIZE; 3542: unsigned flag = 0; 3543: 3544: if (I16 && config.target_cpu >= TARGET_80386 && sz > 2 && 3545: !e->Ecount) 3546: { regsize = 4; 3547: flag |= CFopsize; 3548: } 3549: ce = loadea(e,&cs,0xFF,6,sz - regsize,RMload,0); // PUSH EA+sz-2 3550: code_orflag(ce,flag); 3551: ce = genadjesp(ce,REGSIZE); 3552: stackpush += sz; 3553: while ((targ_int)(sz -= regsize) > 0) 3554: { ce = cat(ce,loadea(e,&cs,0xFF,6,sz - regsize,RMload,0)); 3555: code_orflag(ce,flag); 3556: ce = genadjesp(ce,REGSIZE); 3557: } 3558: } 3559: L2: 3560: freenode(e); 3561: c = cat(c,ce); 3562: goto ret; 3563: case OPconst: 3564: { 3565: char pushi = 0; 3566: unsigned flag = 0; 3567: int regsize = REGSIZE; 3568: targ_int value; 3569: 3570: if (tycomplex(tym)) 3571: break; 3572: 3573: if (I64 && tyfloating(tym) && sz > 4 && boolres(e)) 3574: // Can't push 64 bit non-zero args directly 3575: break; 3576: 3577: if (I32 && szb == 10) // special case for long double constants 3578: { 3579: assert(sz == 12); 3580: value = ((unsigned short *)&e->EV.Vldouble)[4]; 3581: stackpush += sz; 3582: ce = genadjesp(NULL,sz); 3583: for (int i = 2; i >= 0; i--) 3584: { 3585: if (reghasvalue(allregs, value, &reg)) 3586: ce = gen1(ce,0x50 + reg); // PUSH reg 3587: else 3588: ce = genc2(ce,0x68,0,value); // PUSH value 3589: value = ((unsigned *)&e->EV.Vldouble)[i - 1]; 3590: } 3591: goto L2; 3592: } 3593: 3594: assert(I64 || sz <= LNGDBLSIZE); 3595: int i = sz; 3596: if (!I16 && i == 2)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3597: flag = CFopsize; 3598: 3599: if (config.target_cpu >= TARGET_80286) 3600: // && (e->Ecount == 0 || e->Ecount != e->Ecomsub)) 3601: { pushi = 1; 3602: if (I16 && config.target_cpu >= TARGET_80386 && i >= 4) 3603: { regsize = 4; 3604: flag = CFopsize; 3605: } 3606: } 3607: else if (i == REGSIZE) 3608: break; 3609: 3610: stackpush += sz; 3611: ce = genadjesp(NULL,sz); 3612: targ_uns *pi = (targ_uns *) &e->EV.Vdouble; 3613: targ_ushort *ps = (targ_ushort *) pi; 3614: targ_ullong *pl = (targ_ullong *)pi; 3615: i /= regsize; 3616: do 3617: { 3618: if (i) /* be careful not to go negative */ 3619: i--; 3620: targ_size_t value = (regsize == 4) ? pi[i] : ps[i];
warning C6246: Local declaration of 'value' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3568' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3568
3621: if (regsize == 8) 3622: value = pl[i];
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3623: if (pushi) 3624: { 3625: if (I64 && regsize == 8 && value != (int)value) 3626: { ce = regwithvalue(ce,allregs,value,&reg,64); 3627: goto Preg; // cannot push imm64 unless it is sign extended 32 bit value 3628: } 3629: if (regsize == REGSIZE && reghasvalue(allregs,value,&reg)) 3630: goto Preg; 3631: ce = genc2(ce,(szb == 1) ? 0x6A : 0x68,0,value); // PUSH value 3632: } 3633: else 3634: { 3635: ce = regwithvalue(ce,allregs,value,&reg,0); 3636: Preg: 3637: ce = genpush(ce,reg); // PUSH reg 3638: } 3639: code_orflag(ce,flag); /* operand size */ 3640: } while (i); 3641: goto L2; 3642: } 3643: default: 3644: break; 3645: } 3646: retregs = tybyte(tym) ? BYTEREGS : allregs; 3647: if (tyfloating(tym)) 3648: { if (config.inline8087) 3649: { code *c1,*c2; 3650: unsigned op; 3651: unsigned r; 3652: 3653: retregs = tycomplex(tym) ? mST01 : mST0; 3654: c = cat(c,codelem(e,&retregs,FALSE)); 3655: stackpush += sz; 3656: c = genadjesp(c,sz); 3657: c = genc2(c,0x81,grex | modregrm(3,5,SP),sz); // SUB SP,sz 3658: switch (tym) 3659: { 3660: case TYfloat: 3661: case TYifloat: 3662: case TYcfloat: 3663: op = 0xD9; 3664: r = 3; 3665: break; 3666: 3667: case TYdouble: 3668: case TYidouble: 3669: case TYdouble_alias: 3670: case TYcdouble: 3671: op = 0xDD; 3672: r = 3; 3673: break; 3674: 3675: case TYldouble: 3676: case TYildouble: 3677: case TYcldouble: 3678: op = 0xDB; 3679: r = 7; 3680: break; 3681: 3682: default: 3683: assert(0); 3684: } 3685: if (!I16) 3686: { 3687: c1 = NULL; 3688: c2 = NULL; 3689: if (tycomplex(tym)) 3690: { 3691: // FSTP sz/2[ESP] 3692: c2 = genc1(CNIL,op,(modregrm(0,4,SP) << 8) | modregxrm(2,r,4),FLconst,sz/2); 3693: pop87(); 3694: } 3695: pop87(); 3696: c2 = gen2sib(c2,op,modregrm(0,r,4),modregrm(0,4,SP)); // FSTP [ESP] 3697: } 3698: else 3699: { 3700: retregs = IDXREGS; /* get an index reg */ 3701: c1 = allocreg(&retregs,&reg,TYoffset); 3702: c1 = genregs(c1,0x89,SP,reg); /* MOV reg,SP */ 3703: pop87(); 3704: c2 = gen2(CNIL,op,modregrm(0,r,regtorm[reg])); // FSTP [reg] 3705: } 3706: if (LARGEDATA) 3707: c2->Iflags |= CFss; /* want to store into stack */ 3708: genfwait(c2); // FWAIT 3709: c = cat3(c,c1,c2); 3710: goto ret; 3711: } 3712: else if (I16 && (tym == TYdouble || tym == TYdouble_alias)) 3713: retregs = mSTACK; 3714: } 3715: #if LONGLONG 3716: else if (I16 && sz == 8) // if long long 3717: retregs = mSTACK; 3718: #endif 3719: c = cat(c,scodelem(e,&retregs,0,TRUE)); 3720: if (retregs != mSTACK) /* if stackpush not already inc'd */ 3721: stackpush += sz; 3722: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
3723: { 3724: c = genpush(c,findreg(retregs)); // PUSH reg 3725: genadjesp(c,REGSIZE); 3726: } 3727: else if (sz == REGSIZE * 2) 3728: { c = genpush(c,findregmsw(retregs)); // PUSH msreg 3729: genpush(c,findreglsw(retregs)); // PUSH lsreg 3730: genadjesp(c,sz); 3731: } 3732: ret: 3733: return cat(cp,c); 3734: } 3735: 3736: 3737: /******************************* 3738: * Get offset portion of e, and store it in an index 3739: * register. Return mask of index register in *pretregs. 3740: */ 3741: 3742: code *offsetinreg( elem *e, regm_t *pretregs) 3743: { regm_t retregs; 3744: code *c; 3745: unsigned reg; 3746: 3747: retregs = mLSW; /* want only offset */ 3748: if (e->Ecount && e->Ecount != e->Ecomsub) 3749: { unsigned i; 3750: regm_t rm; 3751: 3752: rm = retregs & regcon.cse.mval & ~regcon.cse.mops & ~regcon.mvar; /* possible regs */ 3753: for (i = 0; rm; i++) 3754: { if (mask[i] & rm && regcon.cse.value[i] == e) 3755: { reg = i; 3756: *pretregs = mask[i]; 3757: c = getregs(*pretregs); 3758: goto L3; 3759: } 3760: rm &= ~mask[i]; 3761: } 3762: } 3763: 3764: *pretregs = retregs; 3765: c = allocreg(pretregs,&reg,TYoffset); 3766: c = cat(c,getoffset(e,reg)); 3767: L3: 3768: cssave(e,*pretregs,FALSE); 3769: freenode(e); 3770: return c; 3771: } 3772: 3773: 3774: /****************************** 3775: * Generate code to load data into registers. 3776: */ 3777: 3778: code *loaddata(elem *e,regm_t *pretregs) 3779: { unsigned reg,nreg,op,sreg; 3780: tym_t tym; 3781: int sz; 3782: code *c,*ce,cs; 3783: regm_t flags,forregs,regm; 3784: 3785: #ifdef DEBUG 3786: if (debugw) 3787: printf("loaddata(e = %p,*pretregs = %s)\n",e,regm_str(*pretregs)); 3788: //elem_print(e); 3789: #endif 3790: assert(e); 3791: elem_debug(e); 3792: if (*pretregs == 0) 3793: return CNIL; 3794: tym = tybasic(e->Ety); 3795: if (tym == TYstruct) 3796: return cdrelconst(e,pretregs); 3797: if (tyfloating(tym)) 3798: { obj_fltused(); 3799: if (config.inline8087) 3800: { if (*pretregs & mST0) 3801: return load87(e,0,pretregs,NULL,-1); 3802: else if (tycomplex(tym)) 3803: return cload87(e, pretregs); 3804: } 3805: } 3806: sz = tysize[tym]; 3807: cs.Iflags = 0; 3808: cs.Irex = 0; 3809: if (*pretregs == mPSW) 3810: { 3811: regm = allregs; 3812: if (e->Eoper == OPconst) 3813: { /* TRUE: OR SP,SP (SP is never 0) */ 3814: /* FALSE: CMP SP,SP (always equal) */ 3815: c = genregs(CNIL,(boolres(e)) ? 0x09 : 0x39,SP,SP); 3816: if (I64) 3817: code_orrex(c, REX_W); 3818: } 3819: else if (sz <= REGSIZE) 3820: { 3821: if (!I16 && (tym == TYfloat || tym == TYifloat))
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3822: { c = allocreg(&regm,&reg,TYoffset); /* get a register */ 3823: ce = loadea(e,&cs,0x8B,reg,0,0,0); // MOV reg,data 3824: c = cat(c,ce); 3825: ce = gen2(CNIL,0xD1,modregrmx(3,4,reg)); /* SHL reg,1 */ 3826: c = cat(c,ce); 3827: } 3828: else 3829: { cs.IFL2 = FLconst; 3830: cs.IEV2.Vsize_t = 0; 3831: op = (sz == 1) ? 0x80 : 0x81; 3832: c = loadea(e,&cs,op,7,0,0,0); /* CMP EA,0 */ 3833: 3834: // Convert to TEST instruction if EA is a register 3835: // (to avoid register contention on Pentium) 3836: if ((c->Iop & ~1) == 0x38 && 3837: (c->Irm & modregrm(3,0,0)) == modregrm(3,0,0) 3838: ) 3839: { c->Iop = (c->Iop & 1) | 0x84; 3840: code_newreg(c, c->Irm & 7); 3841: if (c->Irex & REX_B) 3842: //c->Irex = (c->Irex & ~REX_B) | REX_R; 3843: c->Irex |= REX_R; 3844: } 3845: } 3846: } 3847: else if (sz < 8) 3848: { 3849: c = allocreg(&regm,&reg,TYoffset); /* get a register */ 3850: if (I32) // it's a 48 bit pointer 3851: ce = loadea(e,&cs,0x0FB7,reg,REGSIZE,0,0); /* MOVZX reg,data+4 */ 3852: else 3853: { ce = loadea(e,&cs,0x8B,reg,REGSIZE,0,0); /* MOV reg,data+2 */ 3854: if (tym == TYfloat || tym == TYifloat) // dump sign bit 3855: gen2(ce,0xD1,modregrm(3,4,reg)); /* SHL reg,1 */ 3856: } 3857: c = cat(c,ce); 3858: ce = loadea(e,&cs,0x0B,reg,0,regm,0); /* OR reg,data */ 3859: c = cat(c,ce); 3860: } 3861: else if (sz == 8 || (I64 && sz == 2 * REGSIZE && !tyfloating(tym))) 3862: { 3863: c = allocreg(&regm,&reg,TYoffset); /* get a register */ 3864: int i = sz - REGSIZE; 3865: ce = loadea(e,&cs,0x8B,reg,i,0,0); /* MOV reg,data+6 */ 3866: if (tyfloating(tym)) // TYdouble or TYdouble_alias 3867: gen2(ce,0xD1,modregrm(3,4,reg)); // SHL reg,1 3868: c = cat(c,ce); 3869: 3870: while ((i -= REGSIZE) >= 0) 3871: { 3872: code *c1 = loadea(e,&cs,0x0B,reg,i,regm,0); // OR reg,data+i 3873: if (i == 0) 3874: c1->Iflags |= CFpsw; // need the flags on last OR 3875: c = cat(c,c1); 3876: } 3877: } 3878: else if (sz == tysize[TYldouble]) // TYldouble 3879: return load87(e,0,pretregs,NULL,-1); 3880: else 3881: { 3882: #ifdef DEBUG 3883: elem_print(e); 3884: #endif 3885: assert(0); 3886: } 3887: return c; 3888: } 3889: /* not for flags only */ 3890: flags = *pretregs & mPSW; /* save original */ 3891: forregs = *pretregs & (mBP | ALLREGS | mES | XMMREGS); 3892: if (*pretregs & mSTACK) 3893: forregs |= DOUBLEREGS; 3894: if (e->Eoper == OPconst) 3895: { 3896: targ_size_t value = e->EV.Vint; 3897: if (sz == 8) 3898: value = e->EV.Vullong;
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3899: 3900: if (sz == REGSIZE && reghasvalue(forregs,value,&reg)) 3901: forregs = mask[reg]; 3902: 3903: regm_t save = regcon.immed.mval; 3904: c = allocreg(&forregs,&reg,tym); /* allocate registers */ 3905: regcon.immed.mval = save; // KLUDGE! 3906: if (sz <= REGSIZE) 3907: { 3908: if (sz == 1) 3909: flags |= 1; 3910: else if (!I16 && sz == SHORTSIZE &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3911: !(mask[reg] & regcon.mvar) && 3912: !(config.flags4 & CFG4speed) 3913: ) 3914: flags |= 2; 3915: if (sz == 8) 3916: flags |= 64; 3917: if (reg >= XMM0) 3918: { /* This comes about because 0, 1, pi, etc., constants don't get stored 3919: * in the data segment, because they are x87 opcodes. 3920: * Not so efficient. We should at least do a PXOR for 0. 3921: */ 3922: unsigned r; 3923: targ_size_t value = e->EV.Vuns;
warning C6246: Local declaration of 'value' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3896' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3896
3924: if (sz == 8) 3925: value = e->EV.Vullong;
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3926: ce = regwithvalue(CNIL,ALLREGS,value,&r,flags); 3927: flags = 0; // flags are already set 3928: ce = genfltreg(ce,0x89,r,0); // MOV floatreg,r 3929: if (sz == 8) 3930: code_orrex(ce, REX_W); 3931: assert(sz == 4 || sz == 8); // float or double 3932: unsigned op = (sz == 4) ? 0xF30F10 : 0xF20F10;
warning C6246: Local declaration of 'op' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3779' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3779
3933: ce = genfltreg(ce,op,reg - XMM0,0); // MOVSS/MOVSD XMMreg,floatreg 3934: } 3935: else 3936: { ce = movregconst(CNIL,reg,value,flags); 3937: flags = 0; // flags are already set 3938: } 3939: } 3940: else if (sz < 8) // far pointers, longs for 16 bit targets 3941: { 3942: targ_int msw,lsw; 3943: regm_t mswflags; 3944: 3945: msw = I32 ? e->EV.Vfp.Vseg 3946: : (e->EV.Vulong >> 16); 3947: lsw = e->EV.Vfp.Voff; 3948: mswflags = 0; 3949: if (forregs & mES) 3950: { 3951: ce = movregconst(CNIL,reg,msw,0); // MOV reg,segment 3952: genregs(ce,0x8E,0,reg); // MOV ES,reg 3953: msw = lsw; // MOV reg,offset 3954: } 3955: else 3956: { 3957: sreg = findreglsw(forregs); 3958: ce = movregconst(CNIL,sreg,lsw,0); 3959: reg = findregmsw(forregs); 3960: /* Decide if we need to set flags when we load msw */ 3961: if (flags && (msw && msw|lsw || !(msw|lsw))) 3962: { mswflags = mPSW; 3963: flags = 0; 3964: } 3965: } 3966: ce = movregconst(ce,reg,msw,mswflags); 3967: } 3968: else if (sz == 8) 3969: { 3970: if (I32) 3971: { targ_long *p = (targ_long *) &e->EV.Vdouble; 3972: ce = movregconst(CNIL,findreglsw(forregs),p[0],0); 3973: ce = movregconst(ce,findregmsw(forregs),p[1],0); 3974: } 3975: else 3976: { targ_short *p = (targ_short *) &e->EV.Vdouble; 3977: 3978: assert(reg == AX); 3979: ce = movregconst(CNIL,AX,p[3],0); /* MOV AX,p[3] */ 3980: ce = movregconst(ce,DX,p[0],0); 3981: ce = movregconst(ce,CX,p[1],0); 3982: ce = movregconst(ce,BX,p[2],0); 3983: } 3984: } 3985: else if (I64 && sz == 16) 3986: { 3987: ce = movregconst(CNIL,findreglsw(forregs),e->EV.Vcent.lsw,0);
warning C4244: 'argument' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3988: ce = movregconst(ce,findregmsw(forregs),e->EV.Vcent.msw,0);
warning C4244: 'argument' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
3989: } 3990: else 3991: assert(0); 3992: c = cat(c,ce); 3993: } 3994: else 3995: { 3996: // See if we can use register that parameter was passed in 3997: if (regcon.params && e->EV.sp.Vsym->Sclass == SCfastpar && 3998: regcon.params & mask[e->EV.sp.Vsym->Spreg] && 3999: !(e->Eoper == OPvar && e->EV.sp.Voffset > 0) && // Must be at the base of that variable 4000: sz <= REGSIZE) // make sure no 'paint' to a larger size happened 4001: { 4002: reg = e->EV.sp.Vsym->Spreg; 4003: forregs = mask[reg]; 4004: mfuncreg &= ~forregs; 4005: regcon.used |= forregs; 4006: return fixresult(e,forregs,pretregs); 4007: } 4008: 4009: c = allocreg(&forregs,&reg,tym); /* allocate registers */ 4010: 4011: if (sz == 1) 4012: { regm_t nregm; 4013: 4014: #ifdef DEBUG 4015: if (!(forregs & BYTEREGS)) 4016: { elem_print(e); 4017: printf("forregs = x%x\n",forregs); 4018: } 4019: #endif 4020: assert(forregs & BYTEREGS); 4021: if (!I16) 4022: c = cat(c,loadea(e,&cs,0x8A,reg,0,0,0)); // MOV regL,data 4023: else 4024: { nregm = tyuns(tym) ? BYTEREGS : mAX; 4025: if (*pretregs & nregm) 4026: nreg = reg; /* already allocated */ 4027: else 4028: c = cat(c,allocreg(&nregm,&nreg,tym)); 4029: ce = loadea(e,&cs,0x8A,nreg,0,0,0); /* MOV nregL,data */ 4030: c = cat(c,ce); 4031: if (reg != nreg) 4032: { genmovreg(c,reg,nreg); /* MOV reg,nreg */ 4033: cssave(e,mask[nreg],FALSE); 4034: } 4035: } 4036: } 4037: else if (forregs & XMMREGS) 4038: { 4039: // Can't load from registers directly to XMM regs 4040: e->EV.sp.Vsym->Sflags &= ~GTregcand; 4041: 4042: assert(sz == 4 || sz == 8); // float or double 4043: unsigned op = (sz == 4) ? 0xF30F10 : 0xF20F10;
warning C6246: Local declaration of 'op' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3779' of 'c:\projects\extern\d\dmd\src\backend\cod1.c': Lines: 3779
4044: ce = loadea(e,&cs,op,reg,0,RMload,0); // MOVSS/MOVSD reg,data 4045: c = cat(c,ce); 4046: } 4047: else if (sz <= REGSIZE) 4048: { 4049: ce = loadea(e,&cs,0x8B,reg,0,RMload,0); // MOV reg,data 4050: c = cat(c,ce); 4051: } 4052: else if (sz <= 2 * REGSIZE && forregs & mES) 4053: { 4054: ce = loadea(e,&cs,0xC4,reg,0,0,mES); /* LES data */ 4055: c = cat(c,ce); 4056: } 4057: else if (sz <= 2 * REGSIZE) 4058: { 4059: if (I32 && sz == 8 && 4060: (*pretregs & (mSTACK | mPSW)) == mSTACK) 4061: { int i; 4062: 4063: assert(0); 4064: /* Note that we allocreg(DOUBLEREGS) needlessly */ 4065: stackchanged = 1; 4066: i = DOUBLESIZE - REGSIZE; 4067: do 4068: { c = cat(c,loadea(e,&cs,0xFF,6,i,0,0)); /* PUSH EA+i */ 4069: c = genadjesp(c,REGSIZE); 4070: stackpush += REGSIZE; 4071: i -= REGSIZE; 4072: } 4073: while (i >= 0); 4074: return c; 4075: } 4076: 4077: reg = findregmsw(forregs); 4078: ce = loadea(e,&cs,0x8B,reg,REGSIZE,forregs,0); /* MOV reg,data+2 */ 4079: if (I32 && sz == REGSIZE + 2) 4080: ce->Iflags |= CFopsize; /* seg is 16 bits */ 4081: c = cat(c,ce); 4082: reg = findreglsw(forregs); 4083: ce = loadea(e,&cs,0x8B,reg,0,forregs,0); 4084: c = cat(c,ce); 4085: } 4086: else if (sz >= 8) 4087: { 4088: code *c1,*c2,*c3; 4089: 4090: assert(!I32); 4091: if ((*pretregs & (mSTACK | mPSW)) == mSTACK) 4092: { int i; 4093: 4094: /* Note that we allocreg(DOUBLEREGS) needlessly */ 4095: stackchanged = 1; 4096: i = sz - REGSIZE; 4097: do 4098: { c = cat(c,loadea(e,&cs,0xFF,6,i,0,0)); /* PUSH EA+i */ 4099: c = genadjesp(c,REGSIZE); 4100: stackpush += REGSIZE; 4101: i -= REGSIZE; 4102: } 4103: while (i >= 0); 4104: return c; 4105: } 4106: else 4107: { 4108: assert(reg == AX); 4109: ce = loadea(e,&cs,0x8B,AX,6,0,0); /* MOV AX,data+6 */ 4110: c1 = loadea(e,&cs,0x8B,BX,4,mAX,0); /* MOV BX,data+4 */ 4111: c2 = loadea(e,&cs,0x8B,CX,2,mAX|mBX,0); /* MOV CX,data+2 */ 4112: c3 = loadea(e,&cs,0x8B,DX,0,mAX|mCX|mCX,0); /* MOV DX,data */ 4113: c = cat6(c,ce,c1,c2,c3,CNIL); 4114: } 4115: } 4116: else 4117: assert(0); 4118: } 4119: /* Flags may already be set */ 4120: *pretregs &= flags | ~mPSW; 4121: c = cat(c,fixresult(e,forregs,pretregs)); 4122: return c; 4123: } 4124: 4125: #endif // SPP 4126: