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        <time.h>
  18: #include        "cc.h"
  19: #include        "oper.h"
  20: #include        "el.h"
  21: #include        "code.h"
  22: #include        "global.h"
  23: #include        "type.h"
  24: #if SCPP
  25: #include        "exh.h"
  26: #endif
  27: 
  28: static char __file__[] = __FILE__;      /* for tassert.h                */
  29: #include        "tassert.h"
  30: 
  31: int cdcmp_flag;
  32: extern signed char regtorm[8];
  33: 
  34: /********************************
  35:  * Return mask of index registers used by addressing mode.
  36:  * Index is rm of modregrm field.
  37:  */
  38: 
  39: regm_t idxregm(code *c)
  40: {
  41:     static const unsigned char idxsib[8] = { mAX,mCX,mDX,mBX,0,mBP,mSI,mDI };
  42:     static const unsigned char idxrm[8] = {mBX|mSI,mBX|mDI,mSI,mDI,mSI,mDI,0,mBX};
  43: 
  44:     unsigned rm = c->Irm;
  45:     regm_t idxm = 0;
  46:     if ((rm & 0xC0) != 0xC0)            /* if register is not the destination */
  47:     {
  48:         if (I16)
  49:             idxm = idxrm[rm & 7];
  50:         else
  51:         {
  52:             if ((rm & 7) == 4)          /* if sib byte                  */
  53:             {
  54:                 unsigned sib = c->Isib;
  55:                 unsigned idxreg = (sib >> 3) & 7;
  56:                 if (c->Irex & REX_X)
  57:                 {   idxreg |= 8;
  58:                     idxm = mask[idxreg];  // scaled index reg
  59:                 }
  60:                 else
  61:                     idxm = idxsib[idxreg];  // scaled index reg
  62:                 if ((sib & 7) == 5 && (rm & 0xC0) == 0)
  63:                     ;
  64:                 else
  65:                 {   unsigned base = sib & 7;
  66:                     if (c->Irex & REX_B)
  67:                         idxm |= mask[base | 8];
  68:                     else
  69:                         idxm |= idxsib[base];
  70:                 }
  71:             }
  72:             else
  73:             {   unsigned base = rm & 7;
  74:                 if (c->Irex & REX_B)
  75:                     idxm |= mask[base | 8];
  76:                 else
  77:                     idxm |= idxsib[base];
  78:             }
  79:         }
  80:     }
  81:     return idxm;
  82: }
  83: 
  84: 
  85: #if TARGET_WINDOS
  86: /***************************
  87:  * Gen code for call to floating point routine.
  88:  */
  89: 
  90: code *opdouble(elem *e,regm_t *pretregs,unsigned clib)
  91: {
  92:     regm_t retregs1,retregs2;
  93:     code *cl, *cr, *c;
  94: 
  95:     if (config.inline8087)
  96:         return orth87(e,pretregs);
  97: 
  98:     if (tybasic(e->E1->Ety) == TYfloat)
  99:     {
 100:         clib += CLIBfadd - CLIBdadd;    /* convert to float operation   */
 101:         retregs1 = FLOATREGS;
 102:         retregs2 = FLOATREGS2;
 103:     }
 104:     else
 105:     {
 106:         if (I32)
 107:         {   retregs1 = DOUBLEREGS_32;
 108:             retregs2 = DOUBLEREGS2_32;
 109:         }
 110:         else
 111:         {   retregs1 = mSTACK;
 112:             retregs2 = DOUBLEREGS_16;
 113:         }
 114:     }
 115:     cl = codelem(e->E1, &retregs1,FALSE);
 116:     if (retregs1 & mSTACK)
 117:         cgstate.stackclean++;
 118:     cr = scodelem(e->E2, &retregs2, retregs1 & ~mSTACK, FALSE);
 119:     if (retregs1 & mSTACK)
 120:         cgstate.stackclean--;
 121:     c = callclib(e, clib, pretregs, 0);
 122:     return cat3(cl, cr, c);
 123: }
 124: #endif
 125: 
 126: 
 127: /*****************************
 128:  * Handle operators which are more or less orthogonal
 129:  * ( + - & | ^ )
 130:  */
 131: 
 132: code *cdorth(elem *e,regm_t *pretregs)
 133: { tym_t ty1;
 134:   regm_t retregs,rretregs,posregs;
 135:   unsigned reg,rreg,op1,op2,mode;
 136:   int rval;
 137:   code *c,*cg,*cl;
 138:   targ_size_t i;
 139:   elem *e1,*e2;
 140:   int numwords;                         /* # of words to be operated on */
 141:   static int nest;
 142: 
 143:   //printf("cdorth(e = %p, *pretregs = %s)\n",e,regm_str(*pretregs));
 144:   e1 = e->E1;
 145:   e2 = e->E2;
 146:   if (*pretregs == 0)                   /* if don't want result         */
 147:   {     c = codelem(e1,pretregs,FALSE); /* eval left leaf               */
 148:         *pretregs = 0;                  /* in case they got set         */
 149:         return cat(c,codelem(e2,pretregs,FALSE));
 150:   }
 151: 
 152:   ty1 = tybasic(e1->Ety);
 153:   if (tyfloating(ty1))
 154: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
 155:         return orth87(e,pretregs);
 156: #else
 157:         return opdouble(e,pretregs,(e->Eoper == OPadd) ? CLIBdadd
 158:                                                        : CLIBdsub);
 159: #endif
 160:   tym_t ty2 = tybasic(e2->Ety);
 161:   int e2oper = e2->Eoper;
 162:   tym_t ty = tybasic(e->Ety);
 163:   unsigned sz = tysize[ty];
 164:   unsigned byte = (sz == 1);
 165:   unsigned char word = (!I16 && sz == SHORTSIZE) ? CFopsize : 0;
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 166:   unsigned test = FALSE;                // assume we destroyed lvalue
 167:   code cs;
 168:   cs.Iflags = 0;
 169:   cs.Irex = 0;
 170:   code *cr = CNIL;
 171: 
 172:   switch (e->Eoper)
 173:   {     case OPadd:     mode = 0;
 174:                         op1 = 0x03; op2 = 0x13; break;  /* ADD, ADC     */
 175:         case OPmin:     mode = 5;
 176:                         op1 = 0x2B; op2 = 0x1B; break;  /* SUB, SBB     */
 177:         case OPor:      mode = 1;
 178:                         op1 = 0x0B; op2 = 0x0B; break;  /* OR , OR      */
 179:         case OPxor:     mode = 6;
 180:                         op1 = 0x33; op2 = 0x33; break;  /* XOR, XOR     */
 181:         case OPand:     mode = 4;
 182:                         op1 = 0x23; op2 = 0x23;         /* AND, AND     */
 183:                         if (tyreg(ty1) &&
 184:                             *pretregs == mPSW)          /* if flags only */
 185:                         {       test = TRUE;
 186:                                 op1 = 0x85;             /* TEST         */
 187:                                 mode = 0;
 188:                         }
 189:                         break;
 190:         default:
 191:                 assert(0);
 192:   }
 193:   op1 ^= byte;                                  /* if byte operation    */
 194: 
 195:   /* Compute number of words to operate on.                             */
 196:   numwords = 1;
 197:   if (!I16)
 198:   {     /* Cannot operate on longs and then do a 'paint' to a far       */
 199:         /* pointer, because far pointers are 48 bits and longs are 32.  */
 200:         /* Therefore, numwords can never be 2.                          */
 201:         assert(!(tyfv(ty1) && tyfv(ty2)));
 202:         if (sz == 2 * REGSIZE)
 203:         {
 204:             numwords++;
 205:         }
 206:   }
 207:   else
 208:   {     /* If ty is a TYfptr, but both operands are long, treat the     */
 209:         /* operation as a long.                                         */
 210:         if ((tylong(ty1) || ty1 == TYhptr) &&
 211:             (tylong(ty2) || ty2 == TYhptr))
 212:             numwords++;
 213:   }
 214: 
 215:   // Special cases where only flags are set
 216:   if (test && tysize[ty1] <= REGSIZE &&
 217:       (e1->Eoper == OPvar || (e1->Eoper == OPind && !e1->Ecount)))
 218:   {
 219:         // Handle the case of (var & const)
 220:         if (e2->Eoper == OPconst && el_signx32(e2))
 221:         {
 222:             c = getlvalue(&cs,e1,0);
 223:             targ_size_t value = e2->EV.Vpointer;
 224:             if (sz == 2)
 225:                 value &= 0xFFFF;
 226:             else if (sz == 4)
 227:                 value &= 0xFFFFFFFF;
 228:             if (reghasvalue(byte ? BYTEREGS : ALLREGS,value,®))
 229:                 goto L11;
 230:             if (sz == 8 && !I64)
 231:             {
 232:                 assert(value == (int)value);    // sign extend imm32
 233:             }
 234:             op1 = 0xF7;
 235:             cs.IEV2.Vint = value;
 236:             cs.IFL2 = FLconst;
 237:             goto L10;
 238:         }
 239: 
 240:         // Handle (exp & reg)
 241:         if (isregvar(e2,&retregs,®))
 242:         {
 243:             c = getlvalue(&cs,e1,0);
 244:         L11:
 245:             code_newreg(&cs, reg);
 246:             if (I64 && byte && reg >= 4)
 247:                 cs.Irex |= REX;
 248:         L10:
 249:             cs.Iop = op1 ^ byte;
 250:             cs.Iflags |= word | CFpsw;
 251:             freenode(e1);
 252:             freenode(e2);
 253:             return gen(c,&cs);
 254:         }
 255:   }
 256: 
 257:   // Look for possible uses of LEA
 258:   if (e->Eoper == OPadd &&
 259:       !(*pretregs & mPSW) &&            /* flags aren't set by LEA      */
 260:       !nest &&                          // could cause infinite recursion if e->Ecount
 261:       (sz == REGSIZE || (I64 && sz == 4)))  // far pointers aren't handled
 262:   {
 263:         unsigned rex = (sz == 8) ? REX_W : 0;
 264: 
 265:         // Handle the case of (e + &var)
 266:         int e1oper = e1->Eoper;
 267:         if ((e2oper == OPrelconst && (config.target_cpu >= TARGET_Pentium || (!e2->Ecount && stackfl[el_fl(e2)])))
 268:                 || // LEA costs too much for simple EAs on older CPUs
 269:             (e2oper == OPconst && (e1->Eoper == OPcall || e1->Eoper == OPcallns) && !(*pretregs & mAX)) ||
 270:             (!I16 && (isscaledindex(e1) || isscaledindex(e2))) ||
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 271:             (!I16 && e1oper == OPvar && e1->EV.sp.Vsym->Sfl == FLreg && (e2oper == OPconst || (e2oper == OPvar && e2->EV.sp.Vsym->Sfl == FLreg))) ||
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 272:             (e2oper == OPconst && e1oper == OPeq && e1->E1->Eoper == OPvar) ||
 273:             (!I16 && (e2oper == OPrelconst || e2oper == OPconst) && !e1->Ecount &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 274:              (e1oper == OPmul || e1oper == OPshl) &&
 275:              e1->E2->Eoper == OPconst &&
 276:              ssindex(e1oper,e1->E2->EV.Vuns)
 277:             ) ||
 278:             (!I16 && e1->Ecount)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 279:            )
 280:         {
 281:             int inc = e->Ecount != 0;
 282:             nest += inc;
 283:             c = getlvalue(&cs,e,0);
 284:             nest -= inc;
 285:             unsigned reg;
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '135' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 135
 286:             c = cat(c,allocreg(pretregs,®,ty));
 287:             cs.Iop = 0x8D;
 288:             code_newreg(&cs, reg);
 289:             c = gen(c,&cs);          // LEA reg,EA
 290:             if (rex)
 291:                 code_orrex(c, rex);
 292:             return c;
 293:         }
 294: 
 295:         // Handle the case of ((e + c) + e2)
 296:         if (!I16 &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 297:             e1oper == OPadd &&
 298:             (e1->E2->Eoper == OPconst && el_signx32(e1->E2) ||
 299:              e2oper == OPconst && el_signx32(e2)) &&
 300:             !e1->Ecount
 301:            )
 302:         {   elem *e11;
 303:             elem *ebase;
 304:             elem *edisp;
 305:             int ss;
 306:             int ss2;
 307:             unsigned reg1,reg2;
 308:             code *c1,*c2,*c3;
 309: 
 310:             if (e2oper == OPconst && el_signx32(e2))
 311:             {   edisp = e2;
 312:                 ebase = e1->E2;
 313:             }
 314:             else
 315:             {   edisp = e1->E2;
 316:                 ebase = e2;
 317:             }
 318: 
 319:             e11 = e1->E1;
 320:             retregs = *pretregs & ALLREGS;
 321:             if (!retregs)
 322:                 retregs = ALLREGS;
 323:             ss = 0;
 324:             ss2 = 0;
 325: 
 326:             // Handle the case of (((e *  c1) + c2) + e2)
 327:             // Handle the case of (((e << c1) + c2) + e2)
 328:             if ((e11->Eoper == OPmul || e11->Eoper == OPshl) &&
 329:                 e11->E2->Eoper == OPconst &&
 330:                 !e11->Ecount
 331:                )
 332:             {
 333:                 targ_size_t co1 = el_tolong(e11->E2);
warning C4244: 'initializing' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
 334:                 if (e11->Eoper == OPshl)
 335:                 {
 336:                     if (co1 > 3)
 337:                         goto L13;
 338:                     ss = co1;
 339:                 }
 340:                 else
 341:                 {
 342:                     ss2 = 1;
 343:                     switch (co1)
 344:                     {
 345:                         case  6:        ss = 1;                 break;
 346:                         case 12:        ss = 1; ss2 = 2;        break;
 347:                         case 24:        ss = 1; ss2 = 3;        break;
 348:                         case 10:        ss = 2;                 break;
 349:                         case 20:        ss = 2; ss2 = 2;        break;
 350:                         case 40:        ss = 2; ss2 = 3;        break;
 351:                         case 18:        ss = 3;                 break;
 352:                         case 36:        ss = 3; ss2 = 2;        break;
 353:                         case 72:        ss = 3; ss2 = 3;        break;
 354:                         default:
 355:                             ss2 = 0;
 356:                             goto L13;
 357:                     }
 358:                 }
 359:                 freenode(e11->E2);
 360:                 freenode(e11);
 361:                 e11 = e11->E1;
 362:                 goto L13;
 363:             }
 364:             else
 365:             {
 366:             L13:
 367:                 regm_t regm;
 368:                 if (e11->Eoper == OPvar && isregvar(e11,®m,®1))
 369:                 {
 370:                     if (tysize[tybasic(e11->Ety)]<= REGSIZE)
 371:                         retregs = mask[reg1]; // only want the LSW
 372:                     else
 373:                         retregs = regm;
 374:                     c1 = NULL;
 375:                     freenode(e11);
 376:                 }
 377:                 else
 378:                     c1 = codelem(e11,&retregs,FALSE);
 379:             }
 380:             rretregs = ALLREGS & ~retregs;
 381:             c2 = scodelem(ebase,&rretregs,retregs,TRUE);
 382:             {
 383:                 regm_t sregs = *pretregs & ~rretregs;
 384:                 if (!sregs)
 385:                     sregs = ALLREGS & ~rretregs;
 386:                 c3 = allocreg(&sregs,®,ty);
 387:             }
 388: 
 389:             assert((retregs & (retregs - 1)) == 0); // must be only one register
 390:             assert((rretregs & (rretregs - 1)) == 0); // must be only one register
 391: 
 392:             reg1 = findreg(retregs);
 393:             reg2 = findreg(rretregs);
 394: 
 395:             if (ss2)
 396:             {
 397:                 assert(reg != reg2);
 398:                 if ((reg1 & 7) == BP)
 399:                 {   static unsigned imm32[4] = {1+1,2+1,4+1,8+1};
 400: 
 401:                     // IMUL reg,imm32
 402:                     c = genc2(CNIL,0x69,modregxrmx(3,reg,reg1),imm32[ss]);
 403:                 }
 404:                 else
 405:                 {   // LEA reg,[reg1*ss][reg1]
 406:                     c = gen2sib(CNIL,0x8D,modregxrm(0,reg,4),modregrm(ss,reg1 & 7,reg1 & 7));
 407:                     if (reg1 & 8)
 408:                         code_orrex(c, REX_X | REX_B);
 409:                 }
 410:                 if (rex)
 411:                     code_orrex(c, rex);
 412:                 reg1 = reg;
 413:                 ss = ss2;                               // use *2 for scale
 414:             }
 415:             else
 416:                 c = NULL;
 417:             c = cat4(c1,c2,c3,c);
 418: 
 419:             cs.Iop = 0x8D;                      // LEA reg,c[reg1*ss][reg2]
 420:             cs.Irm = modregrm(2,reg & 7,4);
 421:             cs.Isib = modregrm(ss,reg1 & 7,reg2 & 7);
 422:             assert(reg2 != BP);
 423:             cs.Iflags = CFoff;
 424:             cs.Irex = rex;
 425:             if (reg & 8)
 426:                 cs.Irex |= REX_R;
 427:             if (reg1 & 8)
 428:                 cs.Irex |= REX_X;
 429:             if (reg2 & 8)
 430:                 cs.Irex |= REX_B;
 431:             cs.IFL1 = FLconst;
 432:             cs.IEV1.Vsize_t = edisp->EV.Vuns;
 433: 
 434:             freenode(edisp);
 435:             freenode(e1);
 436:             c = gen(c,&cs);
 437:             return cat(c,fixresult(e,mask[reg],pretregs));
 438:         }
 439:   }
 440: 
 441:   posregs = (byte) ? BYTEREGS : (mES | ALLREGS | mBP);
 442:   retregs = *pretregs & posregs;
 443:   if (retregs == 0)                     /* if no return regs speced     */
 444:                                         /* (like if wanted flags only)  */
 445:         retregs = ALLREGS & posregs;    // give us some
 446: 
 447:   if (tysize[ty1] > REGSIZE && numwords == 1)
 448:   {     /* The only possibilities are (TYfptr + tyword) or (TYfptr - tyword) */
 449: #if DEBUG
 450:         if (tysize[ty2] != REGSIZE)
 451:         {       printf("e = %p, e->Eoper = ",e);
 452:                 WROP(e->Eoper);
 453:                 printf(" e1->Ety = ");
 454:                 WRTYxx(ty1);
 455:                 printf(" e2->Ety = ");
 456:                 WRTYxx(ty2);
 457:                 printf("\n");
 458:                 elem_print(e);
 459:         }
 460: #endif
 461:         assert(tysize[ty2] == REGSIZE);
 462: 
 463:         /* Watch out for the case here where you are going to OP reg,EA */
 464:         /* and both the reg and EA use ES! Prevent this by forcing      */
 465:         /* reg into the regular registers.                              */
 466:         if ((e2oper == OPind ||
 467:             (e2oper == OPvar && el_fl(e2) == FLfardata)) &&
 468:             !e2->Ecount)
 469:         {
 470:                 retregs = ALLREGS;
 471:                 assert(!TARGET_FLAT);
 472:         }
 473: 
 474:         cl = codelem(e1,&retregs,test);
warning C4800: 'unsigned int' : forcing value to bool 'true' or 'false' (performance warning)
 475:         reg = findreglsw(retregs);      /* reg is the register with the offset*/
 476:   }
 477:   else if (ty1 == TYhptr || ty2 == TYhptr)
 478:   {     /* Generate code for add/subtract of huge pointers.
 479:            No attempt is made to generate very good code.
 480:          */
 481:         unsigned mreg,lreg;
 482:         unsigned lrreg;
 483: 
 484:         retregs = (retregs & mLSW) | mDX;
 485:         if (ty1 == TYhptr)
 486:         {   // hptr +- long
 487:             rretregs = mLSW & ~(retregs | regcon.mvar);
 488:             if (!rretregs)
 489:                 rretregs = mLSW;
 490:             rretregs |= mCX;
 491:             cl = codelem(e1,&rretregs,0);
 492:             retregs &= ~rretregs;
 493:             if (!(retregs & mLSW))
 494:                 retregs |= mLSW & ~rretregs;
 495: 
 496:             cr = scodelem(e2,&retregs,rretregs,TRUE);
 497:         }
 498:         else
 499:         {   // long + hptr
 500:             cl = codelem(e1,&retregs,0);
 501:             rretregs = (mLSW | mCX) & ~retregs;
 502:             if (!(rretregs & mLSW))
 503:                 rretregs |= mLSW;
 504:             cr = scodelem(e2,&rretregs,retregs,TRUE);
 505:         }
 506:         cg = getregs(rretregs | retregs);
 507:         mreg = DX;
 508:         lreg = findreglsw(retregs);
 509:         c = CNIL;
 510:         if (e->Eoper == OPmin)
 511:         {   // negate retregs
 512:             c = gen2(c,0xF7,modregrm(3,3,mreg));        // NEG mreg
 513:             gen2(c,0xF7,modregrm(3,3,lreg));            // NEG lreg
 514:             code_orflag(c,CFpsw);
 515:             genc2(c,0x81,modregrm(3,3,mreg),0);         // SBB mreg,0
 516:         }
 517:         lrreg = findreglsw(rretregs);
 518:         c = genregs(c,0x03,lreg,lrreg);         // ADD lreg,lrreg
 519:         code_orflag(c,CFpsw);
 520:         genmovreg(c,lrreg,CX);                  // MOV lrreg,CX
 521:         genc2(c,0x81,modregrm(3,2,mreg),0);     // ADC mreg,0
 522:         genshift(c);                            // MOV CX,offset __AHSHIFT
 523:         gen2(c,0xD3,modregrm(3,4,mreg));        // SHL mreg,CL
 524:         genregs(c,0x03,mreg,lrreg);             // ADD mreg,MSREG(h)
 525:         goto L5;
 526:   }
 527:   else
 528:   {     regm_t regm;
 529: 
 530:         /* if (tyword + TYfptr) */
 531:         if (tysize[ty1] == REGSIZE && tysize[ty2] > REGSIZE)
 532:         {   retregs = ~*pretregs & ALLREGS;
 533: 
 534:             /* if retregs doesn't have any regs in it that aren't reg vars */
 535:             if ((retregs & ~regcon.mvar) == 0)
 536:                 retregs |= mAX;
 537:         }
 538:         else if (numwords == 2 && retregs & mES)
 539:             retregs = (retregs | mMSW) & ALLREGS;
 540: 
 541:         // Determine if we should swap operands, because
 542:         //      mov     EAX,x
 543:         //      add     EAX,reg
 544:         // is faster than:
 545:         //      mov     EAX,reg
 546:         //      add     EAX,x
 547:         else if (e2oper == OPvar &&
 548:                  e1->Eoper == OPvar &&
 549:                  e->Eoper != OPmin &&
 550:                  isregvar(e1,®m,NULL) &&
 551:                  regm != retregs &&
 552:                  tysize[ty1] == tysize[ty2])
 553:         {
 554:             elem *es = e1;
 555:             e1 = e2;
 556:             e2 = es;
 557:         }
 558:         cl = codelem(e1,&retregs,test);         /* eval left leaf       */
warning C4800: 'unsigned int' : forcing value to bool 'true' or 'false' (performance warning)
 559:         reg = findreg(retregs);
 560:   }
 561:   switch (e2oper)
 562:   {
 563:     case OPind:                                 /* if addressing mode   */
 564:         if (!e2->Ecount)                        /* if not CSE           */
 565:                 goto L1;                        /* try OP reg,EA        */
 566:         /* FALL-THROUGH */
 567:     default:                                    /* operator node        */
 568:     L2:
 569:         rretregs = ALLREGS & ~retregs;
 570:         /* Be careful not to do arithmetic on ES        */
 571:         if (tysize[ty1] == REGSIZE && tysize[ty2] > REGSIZE && *pretregs != mPSW)
 572:             rretregs = *pretregs & (mES | ALLREGS | mBP) & ~retregs;
 573:         else if (byte)
 574:             rretregs &= BYTEREGS;
 575: 
 576:         cr = scodelem(e2,&rretregs,retregs,TRUE);       /* get rvalue   */
 577:         rreg = (tysize[ty2] > REGSIZE) ? findreglsw(rretregs) : findreg(rretregs);
 578:         c = CNIL;
 579:         if (numwords == 1)                              /* ADD reg,rreg */
 580:         {
 581:                 /* reverse operands to avoid moving around the segment value */
 582:                 if (tysize[ty2] > REGSIZE)
 583:                 {       c = cat(c,getregs(rretregs));
 584:                         c = genregs(c,op1,rreg,reg);
 585:                         retregs = rretregs;     /* reverse operands     */
 586:                 }
 587:                 else
 588:                 {   c = genregs(c,op1,reg,rreg);
 589:                     if (!I16 && *pretregs & mPSW)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 590:                         c->Iflags |= word;
 591:                 }
 592:                 if (I64 && sz == 8)
 593:                     code_orrex(c, REX_W);
 594:                 if (I64 && byte && (reg >= 4 || rreg >= 4))
 595:                     code_orrex(c, REX);
 596:         }
 597:         else /* numwords == 2 */                /* ADD lsreg,lsrreg     */
 598:         {
 599:             reg = findreglsw(retregs);
 600:             rreg = findreglsw(rretregs);
 601:             c = genregs(c,op1,reg,rreg);
 602:             if (e->Eoper == OPadd || e->Eoper == OPmin)
 603:                 code_orflag(c,CFpsw);
 604:             reg = findregmsw(retregs);
 605:             rreg = findregmsw(rretregs);
 606:             if (!(e2oper == OPu16_32 && // if second operand is 0
 607:                   (op2 == 0x0B || op2 == 0x33)) // and OR or XOR
 608:                )
 609:                 genregs(c,op2,reg,rreg);        // ADC msreg,msrreg
 610:         }
 611:         break;
 612: 
 613:     case OPrelconst:
 614:         if (sz != REGSIZE)
 615:                 goto L2;
 616:         if (segfl[el_fl(e2)] != 3)              /* if not in data segment */
 617:                 goto L2;
 618:         if (evalinregister(e2))
 619:                 goto L2;
 620:         cs.IEVoffset2 = e2->EV.sp.Voffset;
 621:         cs.IEVsym2 = e2->EV.sp.Vsym;
 622:         cs.Iflags |= CFoff;
 623:         i = 0;                          /* no INC or DEC opcode         */
 624:         rval = 0;
 625:         goto L3;
 626: 
 627:     case OPconst:
 628:         if (tyfv(ty2))
 629:             goto L2;
 630:         if (numwords == 1)
 631:         {
 632:                 if (!el_signx32(e2))
 633:                     goto L2;
 634:                 i = e2->EV.Vpointer;
 635:                 if (word)
 636:                 {
 637:                     if (!(*pretregs & mPSW) &&
 638:                         config.flags4 & CFG4speed &&
 639:                         (e->Eoper == OPor || e->Eoper == OPxor || test ||
 640:                          (e1->Eoper != OPvar && e1->Eoper != OPind)))
 641:                     {   word = 0;
 642:                         i &= 0xFFFF;
 643:                     }
 644:                 }
 645:                 rval = reghasvalue(byte ? BYTEREGS : ALLREGS,i,&rreg);
 646:                 cs.IEV2.Vint = i;
 647:         L3:
 648:                 op1 ^= byte;
 649:                 cs.Iflags |= word;
 650:                 if (rval)
 651:                 {   cs.Iop = op1 ^ 2;
 652:                     mode = rreg;
 653:                 }
 654:                 else
 655:                     cs.Iop = 0x81;
 656:                 cs.Irm = modregrm(3,mode&7,reg&7);
 657:                 if (mode & 8)
 658:                     cs.Irex |= REX_R;
 659:                 if (reg & 8)
 660:                     cs.Irex |= REX_B;
 661:                 if (I64 && sz == 8)
 662:                     cs.Irex |= REX_W;
 663:                 if (I64 && byte && (reg >= 4 || (rval && rreg >= 4)))
 664:                     cs.Irex |= REX;
 665:                 cs.IFL2 = (e2->Eoper == OPconst) ? FLconst : el_fl(e2);
 666:                 /* Modify instruction for special cases */
 667:                 switch (e->Eoper)
 668:                 {   case OPadd:
 669:                     {   int iop;
 670: 
 671:                         if (i == 1)
 672:                             iop = 0;                    /* INC reg      */
 673:                         else if (i == -1)
 674:                             iop = 8;                    /* DEC reg      */
 675:                         else
 676:                             break;
 677:                         cs.Iop = (0x40 | iop | reg) ^ byte;
 678:                         if ((byte && *pretregs & mPSW) || I64)
 679:                         {   cs.Irm = modregrm(3,0,reg & 7) | iop;
 680:                             cs.Iop = 0xFF;
 681:                         }
 682:                         break;
 683:                     }
 684:                     case OPand:
 685:                         if (test)
 686:                             cs.Iop = rval ? op1 : 0xF7; // TEST
 687:                         break;
 688:                 }
 689:                 if (*pretregs & mPSW)
 690:                         cs.Iflags |= CFpsw;
 691:                 cs.Iop ^= byte;
 692:                 c = gen(CNIL,&cs);
 693:                 cs.Iflags &= ~CFpsw;
 694:         }
 695:         else if (numwords == 2)
 696:         {       unsigned lsreg;
 697:                 targ_int msw;
 698: 
 699:                 c = getregs(retregs);
 700:                 reg = findregmsw(retregs);
 701:                 lsreg = findreglsw(retregs);
 702:                 cs.Iop = 0x81;
 703:                 cs.Irm = modregrm(3,mode,lsreg);
 704:                 cs.IFL2 = FLconst;
 705:                 msw = MSREG(e2->EV.Vllong);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_int', possible loss of data
 706:                 cs.IEV2.Vint = e2->EV.Vlong;
 707:                 switch (e->Eoper)
 708:                 {   case OPadd:
 709:                     case OPmin:
 710:                         cs.Iflags |= CFpsw;
 711:                         break;
 712:                 }
 713:                 c = gen(c,&cs);
 714:                 cs.Iflags &= ~CFpsw;
 715: 
 716:                 cs.Irm = (cs.Irm & modregrm(3,7,0)) | reg;
 717:                 cs.IEV2.Vint = msw;
 718:                 if (e->Eoper == OPadd)
 719:                         cs.Irm |= modregrm(0,2,0);      /* ADC          */
 720:                 c = gen(c,&cs);
 721:         }
 722:         else
 723:                 assert(0);
 724:         freenode(e2);
 725:         break;
 726: 
 727:     case OPvar:
 728:     L1:
 729:         if (tyfv(ty2))
 730:                 goto L2;
 731:         c = loadea(e2,&cs,op1,
 732:                 ((numwords == 2) ? findreglsw(retregs) : reg),
 733:                 0,retregs,retregs);
 734:         if (!I16 && word)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 735:         {   if (*pretregs & mPSW)
 736:                 code_orflag(c,word);
 737:             else
 738:             {
 739:                 code *ce = code_last(c);
 740:                 ce->Iflags &= ~word;
 741:             }
 742:         }
 743:         else if (numwords == 2)
 744:         {
 745:             if (e->Eoper == OPadd || e->Eoper == OPmin)
 746:                 code_orflag(c,CFpsw);
 747:             reg = findregmsw(retregs);
 748:             if (EOP(e2))
 749:             {   getlvalue_msw(&cs);
 750:                 cs.Iop = op2;
 751:                 NEWREG(cs.Irm,reg);
 752:                 c = gen(c,&cs);                 /* ADC reg,data+2 */
 753:             }
 754:             else
 755:                 c = cat(c,loadea(e2,&cs,op2,reg,REGSIZE,retregs,0));
 756:         }
 757:         else if (I64 && sz == 8)
 758:             code_orrex(c, REX_W);
 759:         freenode(e2);
 760:         break;
 761:   }
 762:   if (sz <= REGSIZE && *pretregs & mPSW)
warning C4018: '<=' : signed/unsigned mismatch
 763:   {
 764:         /* If the expression is (_tls_array + ...), then the flags are not set
 765:          * since the linker may rewrite these instructions into something else.
 766:          */
 767:         if (I64 && e->Eoper == OPadd && e1->Eoper == OPvar)
 768:         {
 769:             symbol *s = e1->EV.sp.Vsym;
 770:             if (s->Sident[0] == '_' && memcmp(s->Sident + 1,"tls_array",10) == 0)
 771:             {
 772:                 goto L7;                        // don't assume flags are set
 773:             }
 774:         }
 775:         code_orflag(c,CFpsw);
 776:         *pretregs &= ~mPSW;                     /* flags already set    */
 777:     L7: ;
 778:   }
 779:   if (test)
 780:         cg = NULL;                      /* didn't destroy any           */
 781:   else
 782:         cg = getregs(retregs);          /* we will trash these regs     */
 783: L5:
 784:   c = cat(c,fixresult(e,retregs,pretregs));
 785:   return cat4(cl,cr,cg,c);
 786: }
 787: 
 788: 
 789: /*****************************
 790:  * Handle multiply, divide, modulo and remquo.
 791:  * Note that modulo isn't defined for doubles.
 792:  */
 793: 
 794: code *cdmul(elem *e,regm_t *pretregs)
 795: {   unsigned rreg,op,oper,lib,byte;
 796:     regm_t resreg,retregs,rretregs;
 797:     regm_t keepregs;
 798:     tym_t uns;                          // 1 if unsigned operation, 0 if not
 799:     tym_t tyml;
 800:     code *c,*cg,*cl,*cr,cs;
 801:     elem *e1,*e2;
 802:     int sz;
 803:     targ_size_t e2factor;
 804:     int opunslng;
 805:     int pow2;
 806: 
 807:     if (*pretregs == 0)                         // if don't want result
 808:     {   c = codelem(e->E1,pretregs,FALSE);      // eval left leaf
 809:         *pretregs = 0;                          // in case they got set
 810:         return cat(c,codelem(e->E2,pretregs,FALSE));
 811:     }
 812: 
 813:     //printf("cdmul(e = %p, *pretregs = %s)\n", e, regm_str(*pretregs));
 814:     keepregs = 0;
 815:     cs.Iflags = 0;
 816:     cs.Irex = 0;
 817:     c = cg = cr = CNIL;                         // initialize
 818:     e2 = e->E2;
 819:     e1 = e->E1;
 820:     tyml = tybasic(e1->Ety);
 821:     sz = tysize[tyml];
 822:     byte = tybyte(e->Ety) != 0;
 823:     uns = tyuns(tyml) || tyuns(e2->Ety);
 824:     oper = e->Eoper;
 825:     unsigned rex = (I64 && sz == 8) ? REX_W : 0;
 826:     unsigned grex = rex << 16;
 827: 
 828:     if (tyfloating(tyml))
 829: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
 830:         return orth87(e,pretregs);
 831: #else
 832:         return opdouble(e,pretregs,(oper == OPmul) ? CLIBdmul : CLIBddiv);
 833: #endif
 834: 
 835:     opunslng = I16 ? OPu16_32 : OPu32_64;
 836:     switch (oper)
 837:     {
 838:         case OPmul:
 839:             resreg = mAX;
 840:             op = 5 - uns;
 841:             lib = CLIBlmul;
 842:             break;
 843: 
 844:         case OPdiv:
 845:             resreg = mAX;
 846:             op = 7 - uns;
 847:             lib = uns ? CLIBuldiv : CLIBldiv;
 848:             if (I32)
 849:                 keepregs |= mSI | mDI;
 850:             break;
 851: 
 852:         case OPmod:
 853:             resreg = mDX;
 854:             op = 7 - uns;
 855:             lib = uns ? CLIBulmod : CLIBlmod;
 856:             if (I32)
 857:                 keepregs |= mSI | mDI;
 858:             break;
 859: 
 860:         case OPremquo:
 861:             resreg = mDX | mAX;
 862:             op = 7 - uns;
 863:             lib = uns ? CLIBuldiv : CLIBldiv;
 864:             if (I32)
 865:                 keepregs |= mSI | mDI;
 866:             break;
 867: 
 868:         default:
 869:             assert(0);
 870:     }
 871: 
 872:     if (sz <= REGSIZE)                  // dedicated regs for mul & div
 873:     {   retregs = mAX;
 874:         /* pick some other regs */
 875:         rretregs = byte ? BYTEREGS & ~mAX
 876:                         : ALLREGS & ~(mAX|mDX);
 877:     }
 878:     else
 879:     {
 880:         assert(sz <= 2 * REGSIZE);
 881:         retregs = mDX | mAX;
 882:         rretregs = mCX | mBX;           // second arg
 883:     }
 884: 
 885:   switch (e2->Eoper)
 886:   {
 887:     case OPu16_32:
 888:     case OPshtlng:
 889:     case OPu32_64:
 890:     case OPlngllng:
 891:         if (sz != 2 * REGSIZE || oper != OPmul || e1->Eoper != e2->Eoper ||
 892:             e1->Ecount || e2->Ecount)
 893:             goto L2;
 894:         op = (e2->Eoper == opunslng) ? 4 : 5;
 895:         retregs = mAX;
 896:         cl = codelem(e1->E1,&retregs,FALSE);    /* eval left leaf       */
 897:         if (e2->E1->Eoper == OPvar ||
 898:             (e2->E1->Eoper == OPind && !e2->E1->Ecount)
 899:            )
 900:         {
 901:             cr = loadea(e2->E1,&cs,0xF7,op,0,mAX,mAX | mDX);
 902:         }
 903:         else
 904:         {
 905:             rretregs = ALLREGS & ~mAX;
 906:             cr = scodelem(e2->E1,&rretregs,retregs,TRUE); // get rvalue
 907:             cg = getregs(mAX | mDX);
 908:             rreg = findreg(rretregs);
 909:             cg = gen2(cg,0xF7,grex | modregrmx(3,op,rreg)); // OP AX,rreg
 910:         }
 911:         freenode(e->E1);
 912:         freenode(e2);
 913:         c = fixresult(e,mAX | mDX,pretregs);
 914:         break;
 915: 
 916:     case OPconst:
 917:         e2factor = el_tolong(e2);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
 918: 
 919:         if (oper == OPmul && I32 && sz == REGSIZE * 2)
 920:         {   targ_int msw,lsw;
 921:             regm_t scratch;
 922:             unsigned reg;
 923:             targ_llong e2factor;
warning C6246: Local declaration of 'e2factor' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '803' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 803
 924: 
 925:             cl = codelem(e1,&retregs,FALSE);    // eval left leaf
 926:             /*  IMUL    EDX,EDX,lsw
 927:                 IMUL    reg,EAX,msw
 928:                 ADD     reg,EDX
 929:                 MOV     EDX,lsw
 930:                 MUL     EDX
 931:                 ADD     EDX,reg
 932: 
 933:                 if (msw == 0)
 934:                 IMUL    reg,EDX,lsw
 935:                 MOV     EDX,lsw
 936:                 MUL     EDX
 937:                 ADD     EDX,reg
 938:              */
 939:             scratch = allregs & ~(mAX | mDX);
 940:             cr = allocreg(&scratch,®,TYint);
 941:             cg = getregs(mDX | mAX);
 942: 
 943:             e2factor = el_tolong(e2);
 944:             lsw = e2factor & ((1LL << (REGSIZE * 8)) - 1);
 945:             msw = e2factor >> (REGSIZE * 8);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_int', possible loss of data
 946: 
 947:             if (msw)
 948:             {   cg = genmulimm(cg,DX,DX,lsw);
 949:                 cg = genmulimm(cg,reg,AX,msw);
 950:                 cg = gen2(cg,0x03,modregrm(3,reg,DX));
 951:             }
 952:             else
 953:                 cg = genmulimm(cg,reg,DX,lsw);
 954: 
 955:             cg = movregconst(cg,DX,lsw,0);              // MOV EDX,lsw
 956:             cg = cat(cg,getregs(mDX));
 957:             cg = gen2(cg,0xF7,modregrm(3,4,DX));        // MUL EDX
 958:             gen2(cg,0x03,modregrm(3,DX,reg));           // ADD EDX,reg
 959: 
 960:             resreg = mDX | mAX;
 961:             freenode(e2);
 962:             goto L3;
 963:         }
 964: 
 965:         if (oper != OPmul && e2factor == 10 &&
 966:             (!I16 && sz == 4) &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
 967:             config.flags4 & CFG4speed && !uns)
 968:         {
 969:             /* R1 / 10
 970:              *
 971:              *  MOV     EAX,0x66666667
 972:              *  IMUL    R1
 973:              *  MOV     EAX,R1
 974:              *  SAR     EAX,31
 975:              *  SAR     EDX,2
 976:              *  SUB     EDX,EAX
 977:              *  IMUL    EAX,EDX,10
 978:              *  SUB     R1,EAX
 979:              *
 980:              * EDX = quotient
 981:              * R1 = remainder
 982:              */
 983:             regm_t regm;
 984:             unsigned reg;
 985: 
 986:             regm = allregs & ~(mAX | mDX);
 987:             cl = codelem(e1,®m,FALSE);       // eval left leaf
 988:             reg = findreg(regm);
 989:             cg = getregs(regm | mDX | mAX);
 990: 
 991:             cg = movregconst(cg, AX, 0x66666667, 0);    // MOV EAX,0x66666667
 992:             cg = gen2(cg,0xF7,modregrmx(3,5,reg));      // IMUL R1
 993:             genmovreg(cg, AX, reg);                     // MOV EAX,R1
 994:             genc2(cg,0xC1,modregrm(3,7,AX),31);         // SAR EAX,31
 995:             genc2(cg,0xC1,modregrm(3,7,DX),2);          // SAR EDX,2
 996:             gen2(cg,0x2B,modregrm(3,DX,AX));            // SUB EDX,EAX
 997: 
 998:             switch (oper)
 999:             {   case OPdiv:
1000:                     resreg = mDX;
1001:                     break;
1002: 
1003:                 case OPmod:
1004:                     genmulimm(cg,AX,DX,10);             // IMUL EAX,EDX,10
1005:                     gen2(cg,0x2B,modregxrm(3,reg,AX));  // SUB R1,EAX
1006:                     resreg = regm;
1007:                     break;
1008: 
1009:                 case OPremquo:
1010:                     genmulimm(cg,AX,DX,10);             // IMUL EAX,EDX,10
1011:                     gen2(cg,0x2B,modregxrm(3,reg,AX));  // SUB R1,EAX
1012:                     genmovreg(cg, AX, DX);              // MOV EAX,EDX
1013:                     genmovreg(cg, DX, reg);             // MOV EDX,R1
1014:                     resreg = mDX | mAX;
1015:                     break;
1016: 
1017:                 default:
1018:                     assert(0);
1019:             }
1020:             freenode(e2);
1021:             goto L3;
1022:         }
1023: 
1024:         if (sz > REGSIZE || !el_signx32(e2))
1025:             goto L2;
1026: 
1027:         if (oper == OPmul && config.target_cpu >= TARGET_80286)
1028:         {   unsigned reg;
1029:             int ss;
1030: 
1031:             freenode(e2);
1032:             retregs = byte ? BYTEREGS : ALLREGS;
1033:             resreg = *pretregs & (ALLREGS | mBP);
1034:             if (!resreg)
1035:                 resreg = retregs;
1036: 
1037:             if (!I16)
1038:             {   // See if we can use an LEA instruction
1039:                 int ss2 = 0;
1040:                 int shift;
1041: 
1042:                 switch (e2factor)
1043:                 {
1044:                     case 12:    ss = 1; ss2 = 2; goto L4;
1045:                     case 24:    ss = 1; ss2 = 3; goto L4;
1046: 
1047:                     case 6:
1048:                     case 3:     ss = 1; goto L4;
1049: 
1050:                     case 20:    ss = 2; ss2 = 2; goto L4;
1051:                     case 40:    ss = 2; ss2 = 3; goto L4;
1052: 
1053:                     case 10:
1054:                     case 5:     ss = 2; goto L4;
1055: 
1056:                     case 36:    ss = 3; ss2 = 2; goto L4;
1057:                     case 72:    ss = 3; ss2 = 3; goto L4;
1058: 
1059:                     case 18:
1060:                     case 9:     ss = 3; goto L4;
1061: 
1062:                     L4:
1063:                     {
1064: #if 1
1065:                         regm_t regm = byte ? BYTEREGS : ALLREGS;
1066:                         regm &= ~(mBP | mR13);                  // don't use EBP
1067:                         cl = codelem(e->E1,®m,TRUE);
1068:                         unsigned r = findreg(regm);
1069: 
1070:                         if (ss2)
1071:                         {   // Don't use EBP
1072:                             resreg &= ~(mBP | mR13);
1073:                             if (!resreg)
1074:                                 resreg = retregs;
1075:                         }
1076:                         cg = allocreg(&resreg,®,tyml);
1077: 
1078:                         c = gen2sib(CNIL,0x8D,grex | modregxrm(0,reg,4),
1079:                                               modregxrmx(ss,r,r));
1080:                         assert((r & 7) != BP);
1081:                         if (ss2)
1082:                         {
1083:                             gen2sib(c,0x8D,grex | modregxrm(0,reg,4),
1084:                                            modregxrm(ss2,reg,5));
1085:                             code_last(c)->IFL1 = FLconst;
1086:                             code_last(c)->IEV1.Vint = 0;
1087:                         }
1088:                         else if (!(e2factor & 1))    // if even factor
1089:                         {   genregs(c,0x03,reg,reg); // ADD reg,reg
1090:                             code_orrex(c,rex);
1091:                         }
1092:                         cg = cat(cg,c);
1093:                         goto L3;
1094: #else
1095: 
1096:                                 // Don't use EBP
1097:                                 resreg &= ~mBP;
1098:                                 if (!resreg)
1099:                                     resreg = retregs;
1100: 
1101:                                 cl = codelem(e->E1,&resreg,FALSE);
1102:                                 reg = findreg(resreg);
1103:                                 cg = getregs(resreg);
1104:                                 c = gen2sib(CNIL,0x8D,modregrm(0,reg,4),
1105:                                                       modregrm(ss,reg,reg));
1106:                                 if (ss2)
1107:                                 {
1108:                                     gen2sib(c,0x8D,modregrm(0,reg,4),
1109:                                                    modregrm(ss2,reg,5));
1110:                                     code_last(c)->IFL1 = FLconst;
1111:                                     code_last(c)->IEV1.Vint = 0;
1112:                                 }
1113:                                 else if (!(e2factor & 1))    // if even factor
1114:                                     genregs(c,0x03,reg,reg); // ADD reg,reg
1115:                                 cg = cat(cg,c);
1116:                                 goto L3;
1117: #endif
1118:                     }
1119:                     case 37:
1120:                     case 74:    shift = 2;
1121:                                 goto L5;
1122:                     case 13:
1123:                     case 26:    shift = 0;
1124:                                 goto L5;
1125:                     L5:
1126:                     {
1127:                                 // Don't use EBP
1128:                                 resreg &= ~(mBP | mR13);
1129:                                 if (!resreg)
1130:                                     resreg = retregs;
1131:                                 cl = allocreg(&resreg,®,TYint);
1132: 
1133:                                 regm_t sregm = (ALLREGS & ~mR13) & ~resreg;
1134:                                 cl = cat(cl,codelem(e->E1,&sregm,FALSE));
1135:                                 unsigned sreg = findreg(sregm);
1136:                                 cg = getregs(resreg | sregm);
1137:                                 // LEA reg,[sreg * 4][sreg]
1138:                                 // SHL sreg,shift
1139:                                 // LEA reg,[sreg * 8][reg]
1140:                                 assert((sreg & 7) != BP);
1141:                                 assert((reg & 7) != BP);
1142:                                 c = gen2sib(CNIL,0x8D,grex | modregxrm(0,reg,4),
1143:                                                       modregxrmx(2,sreg,sreg));
1144:                                 if (shift)
1145:                                     genc2(c,0xC1,grex | modregrmx(3,4,sreg),shift);
1146:                                 gen2sib(c,0x8D,grex | modregxrm(0,reg,4),
1147:                                                       modregxrmx(3,sreg,reg));
1148:                                 if (!(e2factor & 1))         // if even factor
1149:                                 {   genregs(c,0x03,reg,reg); // ADD reg,reg
1150:                                     code_orrex(c,rex);
1151:                                 }
1152:                                 cg = cat(cg,c);
1153:                                 goto L3;
1154:                     }
1155:                 }
1156:             }
1157: 
1158:             cl = scodelem(e->E1,&retregs,0,TRUE);       // eval left leaf
1159:             reg = findreg(retregs);
1160:             cg = allocreg(&resreg,&rreg,e->Ety);
1161: 
1162:             /* IMUL reg,imm16   */
1163:             cg = genc2(cg,0x69,grex | modregxrmx(3,rreg,reg),e2factor);
1164:             goto L3;
1165:         }
1166: 
1167:         // Special code for signed divide or modulo by power of 2
1168:         if ((sz == REGSIZE || (I64 && sz == 4)) &&
1169:             (oper == OPdiv || oper == OPmod) && !uns &&
1170:             (pow2 = ispow2(e2factor)) != -1 &&
1171:             !(config.target_cpu < TARGET_80286 && pow2 != 1 && oper == OPdiv)
1172:            )
1173:         {
1174:             if (pow2 == 1 && oper == OPdiv && config.target_cpu > TARGET_80386)
1175:             {
1176:                 //     test    eax,eax
1177:                 //     jns     L1
1178:                 //     add     eax,1
1179:                 // L1: sar     eax,1
1180: 
1181:                 code *cnop;
1182: 
1183:                 retregs = allregs;
1184:                 cl = codelem(e->E1,&retregs,FALSE);     // eval left leaf
1185:                 unsigned reg = findreg(retregs);
1186:                 freenode(e2);
1187:                 cg = getregs(retregs);
1188:                 cg = gentstreg(cg,reg);                 // TEST reg,reg
1189:                 code_orrex(cg, rex);
1190:                 cnop = gennop(CNIL);
1191:                 genjmp(cg,JNS,FLcode,(block *)cnop);    // JNS cnop
1192:                 if (I64)
1193:                 {
1194:                     gen2(cg,0xFF,modregrmx(3,0,reg));       // INC reg
1195:                     code_orrex(cg,rex);
1196:                 }
1197:                 else
1198:                     gen1(cg,0x40 + reg);                    // INC reg
1199:                 cg = cat(cg,cnop);
1200:                 gen2(cg,0xD1,grex | modregrmx(3,7,reg));        // SAR reg,1
1201:                 resreg = retregs;
1202:                 goto L3;
1203:             }
1204:             cl = codelem(e->E1,&retregs,FALSE); // eval left leaf
1205:             freenode(e2);
1206:             cg = getregs(mAX | mDX);            // trash these regs
1207:             cg = gen1(cg,0x99);                         // CWD
1208:             code_orrex(cg, rex);
1209:             if (pow2 == 1)
1210:             {
1211:                 if (oper == OPdiv)
1212:                 {   gen2(cg,0x2B,grex | modregrm(3,AX,DX));    // SUB AX,DX
1213:                     gen2(cg,0xD1,grex | modregrm(3,7,AX));     // SAR AX,1
1214:                 }
1215:                 else // OPmod
1216:                 {   gen2(cg,0x33,grex | modregrm(3,AX,DX));    // XOR AX,DX
1217:                     genc2(cg,0x81,grex | modregrm(3,4,AX),1);  // AND AX,1
1218:                     gen2(cg,0x03,grex | modregrm(3,DX,AX));    // ADD DX,AX
1219:                 }
1220:             }
1221:             else
1222:             {   targ_ulong m;
1223: 
1224:                 m = (1 << pow2) - 1;
1225:                 if (oper == OPdiv)
1226:                 {   genc2(cg,0x81,grex | modregrm(3,4,DX),m);  // AND DX,m
1227:                     gen2(cg,0x03,grex | modregrm(3,AX,DX));    // ADD AX,DX
1228:                     // Be careful not to generate this for 8088
1229:                     assert(config.target_cpu >= TARGET_80286);
1230:                     genc2(cg,0xC1,grex | modregrm(3,7,AX),pow2); // SAR AX,pow2
1231:                 }
1232:                 else // OPmod
1233:                 {   gen2(cg,0x33,grex | modregrm(3,AX,DX));    // XOR AX,DX
1234:                     gen2(cg,0x2B,grex | modregrm(3,AX,DX));    // SUB AX,DX
1235:                     genc2(cg,0x81,grex | modregrm(3,4,AX),m);  // AND AX,mask
1236:                     gen2(cg,0x33,grex | modregrm(3,AX,DX));    // XOR AX,DX
1237:                     gen2(cg,0x2B,grex | modregrm(3,AX,DX));    // SUB AX,DX
1238:                     resreg = mAX;
1239:                 }
1240:             }
1241:             goto L3;
1242:         }
1243:         goto L2;
1244:     case OPind:
1245:         if (!e2->Ecount)                        /* if not CSE           */
1246:                 goto L1;                        /* try OP reg,EA        */
1247:         goto L2;
1248:     default:                                    /* OPconst and operators */
1249:     L2:
1250:         //printf("test2 %p, retregs = %s rretregs = %s resreg = %s\n", e, regm_str(retregs), regm_str(rretregs), regm_str(resreg));
1251:         cl = codelem(e1,&retregs,FALSE);        /* eval left leaf       */
1252:         cr = scodelem(e2,&rretregs,retregs,TRUE);       /* get rvalue   */
1253:         if (sz <= REGSIZE)
1254:         {   cg = getregs(mAX | mDX);            /* trash these regs     */
1255:             if (op == 7)                        /* signed divide        */
1256:             {   cg = gen1(cg,0x99);             // CWD
1257:                 code_orrex(cg,rex);
1258:             }
1259:             else if (op == 6)                   /* unsigned divide      */
1260:             {
1261:                 cg = movregconst(cg,DX,0,(sz == 8) ? 64 : 0);    // MOV DX,0
1262:                 cg = cat(cg,getregs(mDX));
1263:             }
1264:             rreg = findreg(rretregs);
1265:             cg = gen2(cg,0xF7 ^ byte,grex | modregrmx(3,op,rreg)); // OP AX,rreg
1266:             if (I64 && byte && rreg >= 4)
1267:                 code_orrex(cg, REX);
1268:         L3:
1269:             c = fixresult(e,resreg,pretregs);
1270:         }
1271:         else if (sz == 2 * REGSIZE)
1272:         {
1273:             if (config.target_cpu >= TARGET_PentiumPro && oper == OPmul)
1274:             {
1275:                 /*  IMUL    ECX,EAX
1276:                     IMUL    EDX,EBX
1277:                     ADD     ECX,EDX
1278:                     MUL     EBX
1279:                     ADD     EDX,ECX
1280:                  */
1281:                  cg = getregs(mAX|mDX|mCX);
1282:                  cg = gen2(cg,0x0FAF,modregrm(3,CX,AX));
1283:                  gen2(cg,0x0FAF,modregrm(3,DX,BX));
1284:                  gen2(cg,0x03,modregrm(3,CX,DX));
1285:                  gen2(cg,0xF7,modregrm(3,4,BX));
1286:                  gen2(cg,0x03,modregrm(3,DX,CX));
1287:                  c = fixresult(e,mDX|mAX,pretregs);
1288:             }
1289:             else
1290:                 c = callclib(e,lib,pretregs,keepregs);
1291:         }
1292:         else
1293:                 assert(0);
1294:         break;
1295:     case OPvar:
1296:     L1:
1297:         if (!I16 && sz <= REGSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1298:         {
1299:             if (oper == OPmul && sz > 1)        /* no byte version      */
1300:             {
1301:                 /* Generate IMUL r32,r/m32      */
1302:                 retregs = *pretregs & (ALLREGS | mBP);
1303:                 if (!retregs)
1304:                     retregs = ALLREGS;
1305:                 cl = codelem(e1,&retregs,FALSE);        /* eval left leaf */
1306:                 resreg = retregs;
1307:                 cr = loadea(e2,&cs,0x0FAF,findreg(resreg),0,retregs,retregs);
1308:                 freenode(e2);
1309:                 goto L3;
1310:             }
1311:         }
1312:         else
1313:         {
1314:             if (sz == 2 * REGSIZE)
1315:             {   int reg;
1316: 
1317:                 if (oper != OPmul || e->E1->Eoper != opunslng ||
1318:                     e1->Ecount)
1319:                     goto L2;            // have to handle it with codelem()
1320: 
1321:                 retregs = ALLREGS & ~(mAX | mDX);
1322:                 cl = codelem(e1->E1,&retregs,FALSE);    // eval left leaf
1323:                 reg = findreg(retregs);
1324:                 cl = cat(cl,getregs(mAX));
1325:                 cl = genmovreg(cl,AX,reg);              // MOV AX,reg
1326:                 cr = loadea(e2,&cs,0xF7,4,REGSIZE,mAX | mDX | mskl(reg),mAX | mDX);     // MUL EA+2
1327:                 cg = getregs(retregs);
1328:                 cg = gen1(cg,0x90 + reg);               // XCHG AX,reg
1329:                 cg = cat(cg,getregs(mAX | mDX));
1330:                 if ((cs.Irm & 0xC0) == 0xC0)            // if EA is a register
1331:                     cg = cat(cg,loadea(e2,&cs,0xF7,4,0,mAX | mskl(reg),mAX | mDX)); // MUL EA
1332:                 else
1333:                 {   getlvalue_lsw(&cs);
1334:                     gen(cg,&cs);                        // MUL EA
1335:                 }
1336:                 gen2(cg,0x03,modregrm(3,DX,reg));       // ADD DX,reg
1337: 
1338:                 freenode(e1);
1339:                 c = fixresult(e,mAX | mDX,pretregs);
1340:                 break;
1341:             }
1342:             assert(sz <= REGSIZE);
1343:         }
1344: 
1345:         /* loadea() handles CWD or CLR DX for divides   */
1346:         cl = codelem(e->E1,&retregs,FALSE);     /* eval left leaf       */
1347:         cr = loadea(e2,&cs,0xF7 ^ byte,op,0,
1348:                 (oper == OPmul) ? mAX : mAX | mDX,
1349:                 mAX | mDX);
1350:         freenode(e2);
1351:         goto L3;
1352:   }
1353:   return cat4(cl,cr,cg,c);
1354: }
1355: 
1356: 
1357: /***************************
1358:  * Handle OPnot and OPbool.
1359:  * Generate:
1360:  *      c:      [evaluate e1]
1361:  *      cfalse: [save reg code]
1362:  *              clr     reg
1363:  *              jmp     cnop
1364:  *      ctrue:  [save reg code]
1365:  *              clr     reg
1366:  *              inc     reg
1367:  *      cnop:   nop
1368:  */
1369: 
1370: code *cdnot(elem *e,regm_t *pretregs)
1371: {   unsigned reg;
1372:     tym_t forflags;
1373:     code *c1,*c,*cfalse,*ctrue,*cnop;
1374:     unsigned sz;
1375:     regm_t retregs;
1376:     elem *e1;
1377:     int op;
1378: 
1379:     e1 = e->E1;
1380:     if (*pretregs == 0)
1381:         goto L1;
1382:     if (*pretregs == mPSW)
1383:     {   /*assert(e->Eoper != OPnot && e->Eoper != OPbool);*/ /* should've been optimized */
1384:     L1:
1385:         return codelem(e1,pretregs,FALSE);      /* evaluate e1 for cc   */
1386:     }
1387: 
1388:     op = e->Eoper;
1389:     sz = tysize(e1->Ety);
1390:     unsigned rex = (I64 && sz == 8) ? REX_W : 0;
1391:     unsigned grex = rex << 16;
1392:     if (!tyfloating(e1->Ety))
1393:     {
1394:     if (sz <= REGSIZE && e1->Eoper == OPvar)
warning C4018: '<=' : signed/unsigned mismatch
1395:     {   code cs;
1396: 
1397:         c = getlvalue(&cs,e1,0);
1398:         freenode(e1);
1399:         if (!I16 && sz == 2)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1400:             cs.Iflags |= CFopsize;
1401: 
1402:         retregs = *pretregs & (ALLREGS | mBP);
1403:         if (config.target_cpu >= TARGET_80486 &&
1404:             tysize(e->Ety) == 1)
1405:         {
1406:             if (reghasvalue((sz == 1) ? BYTEREGS : ALLREGS,0,®))
1407:                 cs.Iop = 0x39;
1408:             else
1409:             {   cs.Iop = 0x81;
1410:                 reg = 7;
1411:                 cs.IFL2 = FLconst;
1412:                 cs.IEV2.Vint = 0;
1413:             }
1414:             cs.Iop ^= (sz == 1);
1415:             code_newreg(&cs,reg);
1416:             c = gen(c,&cs);                             // CMP e1,0
1417: 
1418:             retregs &= BYTEREGS;
1419:             if (!retregs)
1420:                 retregs = BYTEREGS;
1421:             c1 = allocreg(&retregs,®,TYint);
1422: 
1423:             int iop;
1424:             if (op == OPbool)
1425:             {
1426:                 iop = 0x0F95;   // SETNZ rm8
1427:             }
1428:             else
1429:             {
1430:                 iop = 0x0F94;   // SETZ rm8
1431:             }
1432:             c1 = gen2(c1,iop,grex | modregrmx(3,0,reg));
1433:             if (reg >= 4)
1434:                 code_orrex(c1, REX);
1435:             if (op == OPbool)
1436:                 *pretregs &= ~mPSW;
1437:             goto L4;
1438:         }
1439: 
1440:         if (reghasvalue((sz == 1) ? BYTEREGS : ALLREGS,1,®))
1441:             cs.Iop = 0x39;
1442:         else
1443:         {   cs.Iop = 0x81;
1444:             reg = 7;
1445:             cs.IFL2 = FLconst;
1446:             cs.IEV2.Vint = 1;
1447:         }
1448:         cs.Iop ^= (sz == 1);
1449:         code_newreg(&cs,reg);
1450:         c = gen(c,&cs);                         // CMP e1,1
1451: 
1452:         c1 = allocreg(&retregs,®,TYint);
1453:         op ^= (OPbool ^ OPnot);                 // switch operators
1454:         goto L2;
1455:     }
1456:     else if (sz <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1457:         // NEG bytereg is too expensive
1458:         (sz != 1 || config.target_cpu < TARGET_PentiumPro))
1459:     {
1460:         retregs = *pretregs & (ALLREGS | mBP);
1461:         if (sz == 1 && !(retregs &= BYTEREGS))
1462:             retregs = BYTEREGS;
1463:         c = codelem(e->E1,&retregs,FALSE);
1464:         reg = findreg(retregs);
1465:         c1 = getregs(retregs);
1466:         c1 = gen2(c1,0xF7 ^ (sz == 1),grex | modregrmx(3,3,reg));   // NEG reg
warning C4806: '^' : unsafe operation: no value of type 'bool' promoted to type 'int' can equal the given constant
1467:         code_orflag(c1,CFpsw);
1468:         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?
1469:             code_orflag(c1,CFopsize);
1470:     L2:
1471:         c1 = genregs(c1,0x19,reg,reg);                  // SBB reg,reg
1472:         code_orrex(c1, rex);
1473:         // At this point, reg==0 if e1==0, reg==-1 if e1!=0
1474:         if (op == OPnot)
1475:         {
1476:             if (I64)
1477:                 gen2(c1,0xFF,grex | modregrmx(3,0,reg));    // INC reg
1478:             else
1479:                 gen1(c1,0x40 + reg);                        // INC reg
1480:         }
1481:         else
1482:             gen2(c1,0xF7,grex | modregrmx(3,3,reg));    // NEG reg
1483:         if (*pretregs & mPSW)
1484:         {   code_orflag(c1,CFpsw);
1485:             *pretregs &= ~mPSW;         // flags are always set anyway
1486:         }
1487:     L4:
1488:         return cat3(c,c1,fixresult(e,retregs,pretregs));
1489:     }
1490:   }
1491:   cnop = gennop(CNIL);
1492:   ctrue = gennop(CNIL);
1493:   c = logexp(e->E1,(op == OPnot) ? FALSE : TRUE,FLcode,ctrue);
1494:   forflags = *pretregs & mPSW;
1495:   if (I64 && sz == 8)
1496:         forflags |= 64;
1497:   assert(tysize(e->Ety) <= REGSIZE);            // result better be int
1498:   cfalse = allocreg(pretregs,®,e->Ety);      // allocate reg for result
1499:   for (c1 = cfalse; c1; c1 = code_next(c1))
1500:         gen(ctrue,c1);                          // duplicate reg save code
1501:   cfalse = movregconst(cfalse,reg,0,forflags);  // mov 0 into reg
1502:   regcon.immed.mval &= ~mask[reg];              // mark reg as unavail
1503:   ctrue = movregconst(ctrue,reg,1,forflags);    // mov 1 into reg
1504:   regcon.immed.mval &= ~mask[reg];              // mark reg as unavail
1505:   genjmp(cfalse,JMP,FLcode,(block *) cnop);     // skip over ctrue
1506:   c = cat4(c,cfalse,ctrue,cnop);
1507:   return c;
1508: }
1509: 
1510: 
1511: /************************
1512:  * Complement operator
1513:  */
1514: 
1515: code *cdcom(elem *e,regm_t *pretregs)
1516: { unsigned reg,op;
1517:   regm_t retregs,possregs;
1518:   code *c,*c1,*cg;
1519:   tym_t tym;
1520:   int sz;
1521: 
1522:   if (*pretregs == 0)
1523:         return codelem(e->E1,pretregs,FALSE);
1524:   tym = tybasic(e->Ety);
1525:   sz = tysize[tym];
1526:   unsigned rex = (I64 && sz == 8) ? REX_W : 0;
1527:   possregs = (sz == 1) ? BYTEREGS : allregs;
1528:   retregs = *pretregs & possregs;
1529:   if (retregs == 0)
1530:         retregs = possregs;
1531:   c1 = codelem(e->E1,&retregs,FALSE);
1532:   cg = getregs(retregs);                /* retregs will be destroyed    */
1533: #if 0
1534:   if (sz == 4 * REGSIZE)
1535:   {
1536:         c = gen2(CNIL,0xF7,modregrm(3,2,AX));   // NOT AX
1537:         gen2(c,0xF7,modregrm(3,2,BX));          // NOT BX
1538:         gen2(c,0xF7,modregrm(3,2,CX));          // NOT CX
1539:         gen2(c,0xF7,modregrm(3,2,DX));          // NOT DX
1540:   }
1541:   else
1542: #endif
1543:   {
1544:         reg = (sz <= REGSIZE) ? findreg(retregs) : findregmsw(retregs);
1545:         op = (sz == 1) ? 0xF6 : 0xF7;
1546:         c = genregs(CNIL,op,2,reg);             // NOT reg
1547:         code_orrex(c, rex);
1548:         if (I64 && sz == 1 && reg >= 4)
1549:             code_orrex(c, REX);
1550:         if (sz == 2 * REGSIZE)
1551:         {   reg = findreglsw(retregs);
1552:             genregs(c,op,2,reg);                // NOT reg+1
1553:         }
1554:   }
1555:   return cat4(c1,cg,c,fixresult(e,retregs,pretregs));
1556: }
1557: 
1558: /************************
1559:  * Bswap operator
1560:  */
1561: 
1562: code *cdbswap(elem *e,regm_t *pretregs)
1563: {   unsigned reg,op;
warning C4101: 'op' : unreferenced local variable
1564:     regm_t retregs;
1565:     code *c,*c1,*cg;
1566:     tym_t tym;
1567:     int sz;
warning C4101: 'sz' : unreferenced local variable
1568: 
1569:     if (*pretregs == 0)
1570:         return codelem(e->E1,pretregs,FALSE);
1571: 
1572:     tym = tybasic(e->Ety);
1573:     assert(tysize[tym] == 4);
1574:     retregs = *pretregs & allregs;
1575:     if (retregs == 0)
1576:         retregs = allregs;
1577:     c1 = codelem(e->E1,&retregs,FALSE);
1578:     cg = getregs(retregs);              // retregs will be destroyed
1579:     reg = findreg(retregs);
1580:     c = gen2(CNIL,0x0FC8 + (reg & 7),0);      // BSWAP reg
1581:     if (reg & 8)
1582:         code_orrex(c, REX_B);
1583:     return cat4(c1,cg,c,fixresult(e,retregs,pretregs));
1584: }
1585: 
1586: /*************************
1587:  * ?: operator
1588:  */
1589: 
1590: code *cdcond(elem *e,regm_t *pretregs)
1591: { regm_t psw;
1592:   code *cc,*c,*c1,*cnop1,*c2,*cnop2;
1593:   con_t regconold,regconsave;
1594:   unsigned stackpushold,stackpushsave;
1595:   int ehindexold,ehindexsave;
warning C4101: 'ehindexsave' : unreferenced local variable
warning C4101: 'ehindexold' : unreferenced local variable
1596:   unsigned jop;
1597:   unsigned op1;
1598:   unsigned sz1;
1599:   unsigned sz2;
1600:   elem *e1;
1601:   elem *e2;
1602:   elem *e21;
1603:   elem *e22;
1604: 
1605:   /* vars to save state of 8087 */
1606:   int stackusedold,stackusedsave;
1607:   NDP _8087old[arraysize(_8087elems)];
1608:   NDP _8087save[arraysize(_8087elems)];
1609: 
1610:   _chkstack();
1611: 
1612:   //printf("cdcond(e = %p, *pretregs = %s)\n",e,regm_str(*pretregs));
1613:   e1 = e->E1;
1614:   e2 = e->E2;
1615:   e21 = e2->E1;
1616:   e22 = e2->E2;
1617:   cc = docommas(&e1);
1618:   cgstate.stackclean++;
1619:   psw = *pretregs & mPSW;               /* save PSW bit                 */
1620:   op1 = e1->Eoper;
1621:   sz1 = tysize(e1->Ety);
1622:   unsigned rex = (I64 && sz1 == 8) ? REX_W : 0;
1623:   unsigned grex = rex << 16;
1624:   jop = jmpopcode(e1);
1625: 
1626:   if (!OTrel(op1) && e1 == e21 &&
1627:       sz1 <= REGSIZE && !tyfloating(e1->Ety))
warning C4018: '<=' : signed/unsigned mismatch
1628:   {     // Recognize (e ? e : f)
1629:         regm_t retregs;
1630: 
1631:         cnop1 = gennop(CNIL);
1632:         retregs = *pretregs | mPSW;
1633:         c = codelem(e1,&retregs,FALSE);
1634: 
1635:         c = cat(c,cse_flush(1));                // flush CSEs to memory
1636:         c = genjmp(c,jop,FLcode,(block *)cnop1);
1637:         freenode(e21);
1638: 
1639:         regconsave = regcon;
1640:         stackpushsave = stackpush;
1641: 
1642:         retregs |= psw;
1643:         if (retregs & (mBP | ALLREGS))
1644:             regimmed_set(findreg(retregs),0);
1645:         c2 = codelem(e22,&retregs,FALSE);
1646: 
1647:         andregcon(®consave);
1648:         assert(stackpushsave == stackpush);
1649: 
1650:         *pretregs = retregs;
1651:         freenode(e2);
1652:         c = cat4(cc,c,c2,cnop1);
1653:         goto Lret;
1654:   }
1655: 
1656:   if (OTrel(op1) && sz1 <= REGSIZE && tysize(e2->Ety) <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1657:         !e1->Ecount &&
1658:         (jop == JC || jop == JNC) &&
1659:         (sz2 = tysize(e2->Ety)) <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1660:         e21->Eoper == OPconst &&
1661:         e22->Eoper == OPconst
1662:      )
1663:   {     regm_t retregs;
1664:         unsigned reg;
1665:         targ_size_t v1,v2;
1666:         int opcode;
1667: 
1668:         retregs = *pretregs & (ALLREGS | mBP);
1669:         if (!retregs)
1670:             retregs = ALLREGS;
1671:         cdcmp_flag = 1;
1672:         c = codelem(e1,&retregs,FALSE);
1673:         reg = findreg(retregs);
1674:         v1 = e21->EV.Vllong;
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1675:         v2 = e22->EV.Vllong;
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1676:         if (jop == JNC)
1677:         {   v1 = v2;
1678:             v2 = e21->EV.Vlong;
1679:         }
1680: 
1681:         opcode = 0x81;
1682:         switch (sz2)
1683:         {   case 1:     opcode--;
1684:                         v1 = (signed char) v1;
1685:                         v2 = (signed char) v2;
1686:                         break;
1687:             case 2:     v1 = (short) v1;
1688:                         v2 = (short) v2;
1689:                         break;
1690:             case 4:     v1 = (int) v1;
1691:                         v2 = (int) v2;
1692:                         break;
1693:         }
1694: 
1695:         if (v1 == 0 && v2 == ~(targ_size_t)0)
1696:             c = gen2(c,0xF6 + (opcode & 1),grex | modregrmx(3,2,reg));  // NOT reg
1697:         else
1698:         {
1699:             v1 -= v2;
1700:             c = genc2(c,opcode,grex | modregrmx(3,4,reg),v1);   // AND reg,v1-v2
1701:             if (v2 == 1 && !I64)
1702:                 gen1(c,0x40 + reg);                     // INC reg
1703:             else if (v2 == -1L && !I64)
1704:                 gen1(c,0x48 + reg);                     // DEC reg
1705:             else
1706:                 genc2(c,opcode,grex | modregrmx(3,0,reg),v2);   // ADD reg,v2
1707:         }
1708: 
1709:         freenode(e21);
1710:         freenode(e22);
1711:         freenode(e2);
1712: 
1713:         c = cat(c,fixresult(e,retregs,pretregs));
1714:         goto Lret;
1715:   }
1716: 
1717:   if (op1 != OPcond && op1 != OPandand && op1 != OPoror &&
1718:       op1 != OPnot && op1 != OPbool &&
1719:       e21->Eoper == OPconst &&
1720:       sz1 <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1721:       *pretregs & (mBP | ALLREGS) &&
1722:       tysize(e21->Ety) <= REGSIZE && !tyfloating(e21->Ety))
1723:   {     // Recognize (e ? c : f)
1724:         unsigned reg;
1725:         regm_t retregs;
1726: 
1727:         cnop1 = gennop(CNIL);
1728:         retregs = mPSW;
1729:         jop = jmpopcode(e1);            // get jmp condition
1730:         c = codelem(e1,&retregs,FALSE);
1731: 
1732:         // Set the register with e21 without affecting the flags
1733:         retregs = *pretregs & (ALLREGS | mBP);
1734:         if (retregs & ~regcon.mvar)
1735:             retregs &= ~regcon.mvar;    // don't disturb register variables
1736:         // NOTE: see my email (sign extension bug? possible fix, some questions
1737:         c = regwithvalue(c,retregs,e21->EV.Vllong,®,tysize(e21->Ety) == 8 ? 64|8 : 8);
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1738:         retregs = mask[reg];
1739: 
1740:         c = cat(c,cse_flush(1));                // flush CSE's to memory
1741:         c = genjmp(c,jop,FLcode,(block *)cnop1);
1742:         freenode(e21);
1743: 
1744:         regconsave = regcon;
1745:         stackpushsave = stackpush;
1746: 
1747:         c2 = codelem(e22,&retregs,FALSE);
1748: 
1749:         andregcon(®consave);
1750:         assert(stackpushsave == stackpush);
1751: 
1752:         freenode(e2);
1753:         c = cat6(cc,c,c2,cnop1,fixresult(e,retregs,pretregs),NULL);
1754:         goto Lret;
1755:   }
1756: 
1757:   cnop1 = gennop(CNIL);
1758:   cnop2 = gennop(CNIL);         /* dummy target addresses       */
1759:   c = logexp(e1,FALSE,FLcode,cnop1);    /* evaluate condition           */
1760:   regconold = regcon;
1761:   stackusedold = stackused;
1762:   stackpushold = stackpush;
1763:   memcpy(_8087old,_8087elems,sizeof(_8087elems));
1764:   c1 = codelem(e21,pretregs,FALSE);
1765: 
1766: #if SCPP
1767:   if (CPP && e2->Eoper == OPcolon2)
1768:   {     code cs;
1769: 
1770:         // This is necessary so that any cleanup code on one branch
1771:         // is redone on the other branch.
1772:         cs.Iop = ESCAPE | ESCmark2;
1773:         cs.Iflags = 0;
1774:         cs.Irex = 0;
1775:         c1 = cat(gen(CNIL,&cs),c1);
1776:         cs.Iop = ESCAPE | ESCrelease2;
1777:         c1 = gen(c1,&cs);
1778:   }
1779: #endif
1780: 
1781:   regconsave = regcon;
1782:   regcon = regconold;
1783: 
1784:   stackpushsave = stackpush;
1785:   stackpush = stackpushold;
1786: 
1787:   stackusedsave = stackused;
1788:   stackused = stackusedold;
1789: 
1790:   memcpy(_8087save,_8087elems,sizeof(_8087elems));
1791:   memcpy(_8087elems,_8087old,sizeof(_8087elems));
1792: 
1793:   *pretregs |= psw;                     /* PSW bit may have been trashed */
1794:   c2 = codelem(e22,pretregs,FALSE); /* use same regs as E1 */
1795:   andregcon(®conold);
1796:   andregcon(®consave);
1797:   assert(stackused == stackusedsave);
1798:   assert(stackpush == stackpushsave);
1799:   memcpy(_8087elems,_8087save,sizeof(_8087elems));
1800:   freenode(e2);
1801:   c = cat(cc,c);
1802:   c = cat6(c,c1,genjmp(CNIL,JMP,FLcode,(block *) cnop2),cnop1,c2,cnop2);
1803:   if (*pretregs & mST0)
1804:         note87(e,0,0);
1805: Lret:
1806:   cgstate.stackclean--;
1807:   return c;
1808: }
1809: 
1810: /*********************
1811:  * Comma operator
1812:  */
1813: 
1814: code *cdcomma(elem *e,regm_t *pretregs)
1815: { regm_t retregs;
1816:   code *cl,*cr;
1817: 
1818:   retregs = 0;
1819:   cl = codelem(e->E1,&retregs,FALSE);   /* ignore value from left leaf  */
1820:   cr = codelem(e->E2,pretregs,FALSE);   /* do right leaf                */
1821:   return cat(cl,cr);
1822: }
1823: 
1824: 
1825: /*********************************
1826:  * Do && and || operators.
1827:  * Generate:
1828:  *              (evaluate e1 and e2, if TRUE goto cnop1)
1829:  *      cnop3:  NOP
1830:  *      cg:     [save reg code]         ;if we must preserve reg
1831:  *              CLR     reg             ;FALSE result (set Z also)
1832:  *              JMP     cnop2
1833:  *
1834:  *      cnop1:  NOP                     ;if e1 evaluates to TRUE
1835:  *              [save reg code]         ;preserve reg
1836:  *
1837:  *              MOV     reg,1           ;TRUE result
1838:  *                  or
1839:  *              CLR     reg             ;if return result in flags
1840:  *              INC     reg
1841:  *
1842:  *      cnop2:  NOP                     ;mark end of code
1843:  */
1844: 
1845: code *cdloglog(elem *e,regm_t *pretregs)
1846: { regm_t retregs;
1847:   unsigned reg;
1848:   code *c;
1849:   code *cl,*cr,*cg,*cnop1,*cnop2,*cnop3;
1850:   code *c1;
1851:   con_t regconsave;
1852:   unsigned stackpushsave;
1853:   elem *e2;
1854:   unsigned sz = tysize(e->Ety);
1855: 
1856:   /* We can trip the assert with the following:                         */
1857:   /*    if ( (b<=a) ? (c<b || a<=c) : c>=a )                            */
1858:   /* We'll generate ugly code for it, but it's too obscure a case       */
1859:   /* to expend much effort on it.                                       */
1860:   /*assert(*pretregs != mPSW);*/
1861: 
1862:   cgstate.stackclean++;
1863:   cnop1 = gennop(CNIL);
1864:   cnop3 = gennop(CNIL);
1865:   e2 = e->E2;
1866:   cl = (e->Eoper == OPoror)
1867:         ? logexp(e->E1,1,FLcode,cnop1)
1868:         : logexp(e->E1,0,FLcode,cnop3);
1869:   regconsave = regcon;
1870:   stackpushsave = stackpush;
1871:   if (*pretregs == 0)                   /* if don't want result         */
1872:   {     int noreturn = el_noreturn(e2);
1873: 
1874:         cr = codelem(e2,pretregs,FALSE);
1875:         if (noreturn)
1876:         {
1877:             regconsave.used |= regcon.used;
1878:             regcon = regconsave;
1879:         }
1880:         else
1881:             andregcon(®consave);
1882:         assert(stackpush == stackpushsave);
1883:         c = cat4(cl,cr,cnop3,cnop1);    // eval code, throw away result
1884:         goto Lret;
1885:   }
1886:   cnop2 = gennop(CNIL);
1887:   if (tybasic(e2->Ety) == TYbool &&
1888:       sz == tysize(e2->Ety) &&
1889:       !(*pretregs & mPSW) &&
1890:       e2->Eoper == OPcall)
1891:   {
1892:         cr = codelem(e2,pretregs,FALSE);
1893: 
1894:         andregcon(®consave);
1895: 
1896:         // stack depth should not change when evaluating E2
1897:         assert(stackpush == stackpushsave);
1898: 
1899:         assert(sz <= 4);                                        // result better be int
1900:         retregs = *pretregs & allregs;
1901:         cnop1 = cat(cnop1,allocreg(&retregs,®,TYint));       // allocate reg for result
1902:         cg = genjmp(NULL,JMP,FLcode,(block *) cnop2);           // JMP cnop2
1903:         cnop1 = movregconst(cnop1,reg,e->Eoper == OPoror,0);    // reg = 1
1904:         regcon.immed.mval &= ~mask[reg];                        // mark reg as unavail
1905:         *pretregs = retregs;
1906:         if (e->Eoper == OPoror)
1907:             c = cat6(cl,cr,cnop3,cg,cnop1,cnop2);
1908:         else
1909:             c = cat6(cl,cr,cg,cnop3,cnop1,cnop2);
1910: 
1911:         goto Lret;
1912:   }
1913:   cr = logexp(e2,1,FLcode,cnop1);
1914:   andregcon(®consave);
1915: 
1916:   /* stack depth should not change when evaluating E2   */
1917:   assert(stackpush == stackpushsave);
1918: 
1919:   assert(sz <= 4);                      // result better be int
1920:   retregs = *pretregs & (ALLREGS | mBP);
1921:   if (!retregs) retregs = ALLREGS;      // if mPSW only
1922:   cg = allocreg(&retregs,®,TYint);   // allocate reg for result
1923:   for (c1 = cg; c1; c1 = code_next(c1)) // for each instruction
1924:         gen(cnop1,c1);                  // duplicate it
1925:   cg = movregconst(cg,reg,0,*pretregs & mPSW);  // MOV reg,0
1926:   regcon.immed.mval &= ~mask[reg];                      // mark reg as unavail
1927:   genjmp(cg,JMP,FLcode,(block *) cnop2);                // JMP cnop2
1928:   cnop1 = movregconst(cnop1,reg,1,*pretregs & mPSW);    // reg = 1
1929:   regcon.immed.mval &= ~mask[reg];                      // mark reg as unavail
1930:   *pretregs = retregs;
1931:   c = cat6(cl,cr,cnop3,cg,cnop1,cnop2);
1932: Lret:
1933:   cgstate.stackclean--;
1934:   return c;
1935: }
1936: 
1937: 
1938: /*********************
1939:  * Generate code for shift left or shift right (OPshl,OPshr,OPashr,OProl,OPror).
1940:  */
1941: 
1942: code *cdshift(elem *e,regm_t *pretregs)
1943: { unsigned resreg,shiftcnt,byte;
1944:   unsigned s1,s2,oper;
1945:   tym_t tyml;
1946:   int sz;
1947:   regm_t retregs,rretregs;
1948:   code *cg,*cl,*cr;
1949:   code *c;
1950:   elem *e1;
1951:   elem *e2;
1952:   regm_t forccs,forregs;
1953:   bool e2isconst;
1954: 
1955:   e1 = e->E1;
1956:   if (*pretregs == 0)                   // if don't want result
1957:   {     c = codelem(e1,pretregs,FALSE); // eval left leaf
1958:         *pretregs = 0;                  // in case they got set
1959:         return cat(c,codelem(e->E2,pretregs,FALSE));
1960:   }
1961: 
1962:   tyml = tybasic(e1->Ety);
1963:   sz = tysize[tyml];
1964:   assert(!tyfloating(tyml));
1965:   oper = e->Eoper;
1966:     unsigned rex = (I64 && sz == 8) ? REX_W : 0;
1967:     unsigned grex = rex << 16;
1968: 
1969: #if SCPP
1970:   // Do this until the rest of the compiler does OPshr/OPashr correctly
1971:   if (oper == OPshr)
1972:         oper = (tyuns(tyml)) ? OPshr : OPashr;
1973: #endif
1974: 
1975:   switch (oper)
1976:   {     case OPshl:
1977:             s1 = 4;                     // SHL
1978:             s2 = 2;                     // RCL
1979:             break;
1980:         case OPshr:
1981:             s1 = 5;                     // SHR
1982:             s2 = 3;                     // RCR
1983:             break;
1984:         case OPashr:
1985:             s1 = 7;                     // SAR
1986:             s2 = 3;                     // RCR
1987:             break;
1988:         case OProl:
1989:             s1 = 0;                     // ROL
1990:             break;
1991:         case OPror:
1992:             s1 = 1;                     // ROR
1993:             break;
1994:         default:
1995:             assert(0);
1996:   }
1997: 
1998:   unsigned sreg = ~0;                   // guard against using value without assigning to sreg
1999:   c = cg = cr = CNIL;                   /* initialize                   */
2000:   e2 = e->E2;
2001:   forccs = *pretregs & mPSW;            /* if return result in CCs      */
2002:   forregs = *pretregs & (ALLREGS | mBP); // mask of possible return regs
2003:   e2isconst = FALSE;                    /* assume for the moment        */
2004:   byte = (sz == 1);
2005:   switch (e2->Eoper)
2006:   {
2007:     case OPconst:
2008:         e2isconst = TRUE;               /* e2 is a constant             */
2009:         shiftcnt = e2->EV.Vint;         /* get shift count              */
2010:         if ((!I16 && sz <= REGSIZE) ||
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2011:             shiftcnt <= 4 ||            /* if sequence of shifts        */
2012:             (sz == 2 &&
2013:                 (shiftcnt == 8 || config.target_cpu >= TARGET_80286)) ||
2014:             (sz == 2 * REGSIZE && shiftcnt == 8 * REGSIZE)
2015:            )
2016:         {       retregs = (forregs) ? forregs
2017:                                     : ALLREGS;
2018:                 if (byte)
2019:                 {   retregs &= BYTEREGS;
2020:                     if (!retregs)
2021:                         retregs = BYTEREGS;
2022:                 }
2023:                 else if (sz > REGSIZE && sz <= 2 * REGSIZE &&
2024:                          !(retregs & mMSW))
2025:                     retregs |= mMSW & ALLREGS;
2026:                 if (s1 == 7)    /* if arithmetic right shift */
2027:                 {
2028:                     if (shiftcnt == 8)
2029:                         retregs = mAX;
2030:                     else if (sz == 2 * REGSIZE && shiftcnt == 8 * REGSIZE)
2031:                         retregs = mDX|mAX;
2032:                 }
2033: 
2034:                 if (sz == 2 * REGSIZE && shiftcnt == 8 * REGSIZE &&
2035:                     oper == OPshl &&
2036:                     !e1->Ecount &&
2037:                     (e1->Eoper == OPshtlng  || e1->Eoper == OPu16_32 ||
2038:                      e1->Eoper == OPlngllng || e1->Eoper == OPu32_64)
2039:                    )
2040:                 {   // Handle (shtlng)s << 16
2041:                     regm_t r;
2042: 
2043:                     r = retregs & mMSW;
2044:                     cl = codelem(e1->E1,&r,FALSE);      // eval left leaf
2045:                     cl = regwithvalue(cl,retregs & mLSW,0,&resreg,0);
2046:                     cg = getregs(r);
2047:                     retregs = r | mask[resreg];
2048:                     if (forccs)
2049:                     {   sreg = findreg(r);
2050:                         cg = gentstreg(cg,sreg);
2051:                         *pretregs &= ~mPSW;             // already set
2052:                     }
2053:                     freenode(e1);
2054:                     freenode(e2);
2055:                     break;
2056:                 }
2057: 
2058:                 // See if we should use LEA reg,xxx instead of shift
2059:                 if (!I16 && shiftcnt >= 1 && shiftcnt <= 3 &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2060:                     (sz == REGSIZE || (I64 && sz == 4)) &&
2061:                     oper == OPshl &&
2062:                     e1->Eoper == OPvar &&
2063:                     !(*pretregs & mPSW) &&
2064:                     config.flags4 & CFG4speed
2065:                    )
2066:                 {
2067:                     unsigned reg;
2068:                     regm_t regm;
2069: 
2070:                     if (isregvar(e1,®m,®) && !(regm & retregs))
2071:                     {   code cs;
2072:                         cl = allocreg(&retregs,&resreg,e->Ety);
2073:                         buildEA(&cs,-1,reg,1 << shiftcnt,0);
2074:                         cs.Iop = 0x8D;
2075:                         code_newreg(&cs,resreg);
2076:                         cs.Iflags = 0;
2077:                         cg = gen(NULL,&cs);             // LEA resreg,[reg * ss]
2078:                         freenode(e1);
2079:                         freenode(e2);
2080:                         break;
2081:                     }
2082:                 }
2083: 
2084:                 cl = codelem(e1,&retregs,FALSE); // eval left leaf
2085:                 //assert((retregs & regcon.mvar) == 0);
2086:                 cg = getregs(retregs);          // trash these regs
2087: 
2088:                 {
2089:                     if (sz == 2 * REGSIZE)
2090:                     {   resreg = findregmsw(retregs);
2091:                         sreg = findreglsw(retregs);
2092:                     }
2093:                     else
2094:                     {   resreg = findreg(retregs);
2095:                         sreg = ~0;              // an invalid value
2096:                     }
2097:                     if (config.target_cpu >= TARGET_80286 &&
2098:                         sz <= REGSIZE)
2099:                     {
2100:                         /* SHL resreg,shiftcnt  */
2101:                         assert(!(sz == 1 && (mask[resreg] & ~BYTEREGS)));
2102:                         c = genc2(CNIL,0xC1 ^ byte,grex | modregxrmx(3,s1,resreg),shiftcnt);
2103:                         if (shiftcnt == 1)
2104:                             c->Iop += 0x10;     /* short form of shift  */
2105:                         if (I64 && sz == 1 && resreg >= 4)
2106:                             c->Irex |= REX;
2107:                         // See if we need operand size prefix
2108:                         if (!I16 && oper != OPshl && sz == 2)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2109:                             c->Iflags |= CFopsize;
2110:                         if (forccs)
2111:                             c->Iflags |= CFpsw;         // need flags result
2112:                     }
2113:                     else if (shiftcnt == 8)
2114:                     {   if (!(retregs & BYTEREGS) || resreg >= 4)
2115:                         {
2116:                             cl = cat(cl,cg);
2117:                             goto L1;
2118:                         }
2119: 
2120:                         if (pass != PASSfinal && (!forregs || forregs & (mSI | mDI)))
2121:                         {
2122:                             // e1 might get into SI or DI in a later pass,
2123:                             // so don't put CX into a register
2124:                             cg = cat(cg, getregs(mCX));
2125:                         }
2126: 
2127:                         assert(sz == 2);
2128:                         switch (oper)
2129:                         {
2130:                             case OPshl:
2131:                                 /* MOV regH,regL        XOR regL,regL   */
2132:                                 assert(resreg < 4 && !rex);
2133:                                 c = genregs(CNIL,0x8A,resreg+4,resreg);
2134:                                 genregs(c,0x32,resreg,resreg);
2135:                                 break;
2136: 
2137:                             case OPshr:
2138:                             case OPashr:
2139:                                 /* MOV regL,regH    */
2140:                                 c = genregs(CNIL,0x8A,resreg,resreg+4);
2141:                                 if (oper == OPashr)
2142:                                     gen1(c,0x98);           /* CBW          */
2143:                                 else
2144:                                     genregs(c,0x32,resreg+4,resreg+4); /* CLR regH */
2145:                                 break;
2146: 
2147:                             case OPror:
2148:                             case OProl:
2149:                                 // XCHG regL,regH
2150:                                 c = genregs(CNIL,0x86,resreg+4,resreg);
2151:                                 break;
2152: 
2153:                             default:
2154:                                 assert(0);
2155:                         }
2156:                         if (forccs)
2157:                                 gentstreg(c,resreg);
2158:                     }
2159:                     else if (shiftcnt == REGSIZE * 8)   // it's an lword
2160:                     {
2161:                         if (oper == OPshl)
2162:                             swap((int *) &resreg,(int *) &sreg);
2163:                         c = genmovreg(CNIL,sreg,resreg);        // MOV sreg,resreg
2164:                         if (oper == OPashr)
2165:                             gen1(c,0x99);                       // CWD
2166:                         else
2167:                             movregconst(c,resreg,0,0);          // MOV resreg,0
2168:                         if (forccs)
2169:                         {       gentstreg(c,sreg);
2170:                                 *pretregs &= mBP | ALLREGS | mES;
2171:                         }
2172:                     }
2173:                     else
2174:                     {   c = CNIL;
2175:                         if (oper == OPshl && sz == 2 * REGSIZE)
2176:                             swap((int *) &resreg,(int *) &sreg);
2177:                         while (shiftcnt--)
2178:                         {   c = gen2(c,0xD1 ^ byte,modregrm(3,s1,resreg));
2179:                             if (sz == 2 * REGSIZE)
2180:                                 gen2(c,0xD1,modregrm(3,s2,sreg));
2181:                         }
2182:                         if (forccs)
2183:                             code_orflag(c,CFpsw);
2184:                     }
2185:                     if (sz <= REGSIZE)
2186:                         *pretregs &= mBP | ALLREGS;     // flags already set
2187:                 }
2188:                 freenode(e2);
2189:                 break;
2190:         }
2191:         /* FALL-THROUGH */
2192:     default:
2193:         retregs = forregs & ~mCX;               /* CX will be shift count */
2194:         if (sz <= REGSIZE)
2195:         {
2196:             if (forregs & ~regcon.mvar && !(retregs & ~regcon.mvar))
2197:                 retregs = ALLREGS & ~mCX;       /* need something       */
2198:             else if (!retregs)
2199:                 retregs = ALLREGS & ~mCX;       /* need something       */
2200:             if (sz == 1)
2201:             {   retregs &= mAX|mBX|mDX;
2202:                 if (!retregs)
2203:                     retregs = mAX|mBX|mDX;
2204:             }
2205:         }
2206:         else
2207:         {
2208:             if (!(retregs & mMSW))
2209:                 retregs = ALLREGS & ~mCX;
2210:         }
2211:         cl = codelem(e->E1,&retregs,FALSE);     /* eval left leaf       */
2212: 
2213:         if (sz <= REGSIZE)
2214:             resreg = findreg(retregs);
2215:         else
2216:         {
2217:             resreg = findregmsw(retregs);
2218:             sreg = findreglsw(retregs);
2219:         }
2220:     L1:
2221:         rretregs = mCX;                 /* CX is shift count    */
2222:         if (sz <= REGSIZE)
2223:         {
2224:             cr = scodelem(e2,&rretregs,retregs,FALSE); /* get rvalue */
2225:             cg = getregs(retregs);      /* trash these regs             */
2226:             c = gen2(CNIL,0xD3 ^ byte,grex | modregrmx(3,s1,resreg)); /* Sxx resreg,CX */
2227: 
2228:             if (!I16 && sz == 2 && (oper == OProl || oper == OPror))
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2229:                 c->Iflags |= CFopsize;
2230: 
2231:             // Note that a shift by CL does not set the flags if
2232:             // CL == 0. If e2 is a constant, we know it isn't 0
2233:             // (it would have been optimized out).
2234:             if (e2isconst)
2235:                 *pretregs &= mBP | ALLREGS; // flags already set with result
2236:         }
2237:         else if (sz == 2 * REGSIZE &&
2238:                  config.target_cpu >= TARGET_80386)
2239:         {
2240:             unsigned hreg = resreg;
2241:             unsigned lreg = sreg;
2242:             unsigned rex = I64 ? (REX_W << 16) : 0;
warning C6246: Local declaration of 'rex' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1966' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 1966
2243:             if (e2isconst)
2244:             {
2245:                 cr = NULL;
2246:                 cg = getregs(retregs);
2247:                 if (shiftcnt & (REGSIZE * 8))
2248:                 {
2249:                     if (oper == OPshr)
2250:                     {   //      SHR hreg,shiftcnt
2251:                         //      MOV lreg,hreg
2252:                         //      XOR hreg,hreg
2253:                         c = genc2(NULL,0xC1,rex | modregrm(3,s1,hreg),shiftcnt - (REGSIZE * 8));
2254:                         c = genmovreg(c,lreg,hreg);
2255:                         c = movregconst(c,hreg,0,0);
2256:                     }
2257:                     else if (oper == OPashr)
2258:                     {   //      MOV     lreg,hreg
2259:                         //      SAR     hreg,31
2260:                         //      SHRD    lreg,hreg,shiftcnt
2261:                         c = genmovreg(NULL,lreg,hreg);
2262:                         c = genc2(c,0xC1,rex | modregrm(3,s1,hreg),(REGSIZE * 8) - 1);
2263:                         c = genc2(c,0x0FAC,rex | modregrm(3,hreg,lreg),shiftcnt - (REGSIZE * 8));
2264:                     }
2265:                     else
2266:                     {   //      SHL lreg,shiftcnt
2267:                         //      MOV hreg,lreg
2268:                         //      XOR lreg,lreg
2269:                         c = genc2(NULL,0xC1,rex | modregrm(3,s1,lreg),shiftcnt - (REGSIZE * 8));
2270:                         c = genmovreg(c,hreg,lreg);
2271:                         c = movregconst(c,lreg,0,0);
2272:                     }
2273:                 }
2274:                 else
2275:                 {
2276:                     if (oper == OPshr || oper == OPashr)
2277:                     {   //      SHRD    lreg,hreg,shiftcnt
2278:                         //      SHR/SAR hreg,shiftcnt
2279:                         c = genc2(NULL,0x0FAC,rex | modregrm(3,hreg,lreg),shiftcnt);
2280:                         c = genc2(c,0xC1,rex | modregrm(3,s1,hreg),shiftcnt);
2281:                     }
2282:                     else
2283:                     {   //      SHLD hreg,lreg,shiftcnt
2284:                         //      SHL  lreg,shiftcnt
2285:                         c = genc2(NULL,0x0FA4,rex | modregrm(3,lreg,hreg),shiftcnt);
2286:                         c = genc2(c,0xC1,rex | modregrm(3,s1,lreg),shiftcnt);
2287:                     }
2288:                 }
2289:                 freenode(e2);
2290:             }
2291:             else if (config.target_cpu >= TARGET_80486 && REGSIZE == 2)
2292:             {
2293:                 cr = scodelem(e2,&rretregs,retregs,FALSE); // get rvalue in CX
2294:                 cg = getregs(retregs);          // modify these regs
2295:                 if (oper == OPshl)
2296:                 {
2297:                     /*
2298:                         SHLD    hreg,lreg,CL
2299:                         SHL     lreg,CL
2300:                      */
2301: 
2302:                     c = gen2(NULL,0x0FA5,modregrm(3,lreg,hreg));
2303:                     gen2(c,0xD3,modregrm(3,4,lreg));
2304:                 }
2305:                 else
2306:                 {
2307:                     /*
2308:                         SHRD    lreg,hreg,CL
2309:                         SAR             hreg,CL
2310: 
2311:                         -- or --
2312: 
2313:                         SHRD    lreg,hreg,CL
2314:                         SHR             hreg,CL
2315:                      */
2316:                     c = gen2(NULL,0x0FAD,modregrm(3,hreg,lreg));
2317:                     gen2(c,0xD3,modregrm(3,s1,hreg));
2318:                 }
2319:             }
2320:             else
2321:             {   code *cl1,*cl2;
2322: 
2323:                 cr = scodelem(e2,&rretregs,retregs,FALSE); // get rvalue in CX
2324:                 cg = getregs(retregs | mCX);            // modify these regs
2325:                                                         // TEST CL,0x20
2326:                 c = genc2(NULL,0xF6,modregrm(3,0,CX),REGSIZE * 8);
2327:                 if (oper == OPshl)
2328:                 {
2329:                     /*  TEST    CL,20H
2330:                         JNE     L1
2331:                         SHLD    hreg,lreg,CL
2332:                         SHL     lreg,CL
2333:                         JMP     L2
2334:                     L1: AND     CL,20H-1
2335:                         SHL     lreg,CL
2336:                         MOV     hreg,lreg
2337:                         XOR     lreg,lreg
2338:                     L2: NOP
2339:                      */
2340: 
2341:                     cl1 = NULL;
2342:                     if (REGSIZE == 2)
2343:                         cl1 = genc2(NULL,0x80,modregrm(3,4,CX),REGSIZE * 8 - 1);
2344:                     cl1 = gen2(cl1,0xD3,modregrm(3,4,lreg));
2345:                     genmovreg(cl1,hreg,lreg);
2346:                     genregs(cl1,0x31,lreg,lreg);
2347: 
2348:                     genjmp(c,JNE,FLcode,(block *)cl1);
2349:                     gen2(c,0x0FA5,modregrm(3,lreg,hreg));
2350:                     gen2(c,0xD3,modregrm(3,4,lreg));
2351:                 }
2352:                 else
2353:                 {   if (oper == OPashr)
2354:                     {
2355:                         /*  TEST        CL,20H
2356:                             JNE         L1
2357:                             SHRD        lreg,hreg,CL
2358:                             SAR         hreg,CL
2359:                             JMP         L2
2360:                         L1: AND         CL,15
2361:                             MOV         lreg,hreg
2362:                             SAR         hreg,31
2363:                             SHRD        lreg,hreg,CL
2364:                         L2: NOP
2365:                          */
2366: 
2367:                         cl1 = NULL;
2368:                         if (REGSIZE == 2)
2369:                             cl1 = genc2(NULL,0x80,modregrm(3,4,CX),REGSIZE * 8 - 1);
2370:                         cl1 = genmovreg(cl1,lreg,hreg);
2371:                         genc2(cl1,0xC1,modregrm(3,s1,hreg),31);
2372:                         gen2(cl1,0x0FAD,modregrm(3,hreg,lreg));
2373:                     }
2374:                     else
2375:                     {
2376:                         /*  TEST        CL,20H
2377:                             JNE         L1
2378:                             SHRD        lreg,hreg,CL
2379:                             SHR         hreg,CL
2380:                             JMP         L2
2381:                         L1: AND         CL,15
2382:                             SHR         hreg,CL
2383:                             MOV         lreg,hreg
2384:                             XOR         hreg,hreg
2385:                         L2: NOP
2386:                          */
2387: 
2388:                         cl1 = NULL;
2389:                         if (REGSIZE == 2)
2390:                             cl1 = genc2(NULL,0x80,modregrm(3,4,CX),REGSIZE * 8 - 1);
2391:                         cl1 = gen2(cl1,0xD3,modregrm(3,5,hreg));
2392:                         genmovreg(cl1,lreg,hreg);
2393:                         genregs(cl1,0x31,hreg,hreg);
2394:                     }
2395:                     genjmp(c,JNE,FLcode,(block *)cl1);
2396:                     gen2(c,0x0FAD,modregrm(3,hreg,lreg));
2397:                     gen2(c,0xD3,modregrm(3,s1,hreg));
2398:                 }
2399:                 cl2 = gennop(NULL);
2400:                 genjmp(c,JMPS,FLcode,(block *)cl2);
2401:                 c = cat3(c,cl1,cl2);
2402:             }
2403:             break;
2404:         }
2405:         else if (sz == 2 * REGSIZE)
2406:         {
2407:             c = CNIL;
2408:             if (!e2isconst)                     // if not sure shift count != 0
2409:                     c = genc2(c,0xE3,0,6);      // JCXZ .+6
2410:             cr = scodelem(e2,&rretregs,retregs,FALSE);
2411:             cg = getregs(retregs | mCX);
2412:             if (oper == OPshl)
2413:                     swap((int *) &resreg,(int *) &sreg);
2414:             c = gen2(c,0xD1,modregrm(3,s1,resreg));
2415:             code_orflag(c,CFtarg2);
2416:             gen2(c,0xD1,modregrm(3,s2,sreg));
2417:             genc2(c,0xE2,0,(targ_uns)-6);               // LOOP .-6
2418:             regimmed_set(CX,0);         // note that now CX == 0
2419:         }
2420:         else
2421:             assert(0);
2422:         break;
2423:   }
2424:   c = cat(c,fixresult(e,retregs,pretregs));
2425:   return cat4(cl,cr,cg,c);
2426: }
2427: 
2428: 
2429: /***************************
2430:  * Perform a 'star' reference (indirection).
2431:  */
2432: 
2433: code *cdind(elem *e,regm_t *pretregs)
2434: { code *c,*ce,cs;
2435:   tym_t tym;
2436:   regm_t idxregs,retregs;
2437:   unsigned reg,nreg,byte;
warning C4101: 'nreg' : unreferenced local variable
2438:   elem *e1;
2439:   unsigned sz;
2440: 
2441:   //printf("cdind(e = %p, *pretregs = %s)\n",e,regm_str(*pretregs));
2442:   tym = tybasic(e->Ety);
2443:   if (tyfloating(tym))
2444:   {
2445:         if (config.inline8087)
2446:         {
2447:             if (*pretregs & mST0)
2448:                 return cdind87(e, pretregs);
2449:             if (tycomplex(tym))
2450:                 return cload87(e, pretregs);
2451:             if (*pretregs & mPSW)
2452:                 return cdind87(e, pretregs);
2453:         }
2454:   }
2455: 
2456:   e1 = e->E1;
2457:   assert(e1);
2458:   switch (tym)
2459:   {     case TYstruct:
2460:         case TYarray:
2461:             // This case should never happen, why is it here?
2462:             tym = TYnptr;               // don't confuse allocreg()
2463: #if !TARGET_FLAT
2464:             if (*pretregs & (mES | mCX) || e->Ety & mTYfar)
2465:                     tym = TYfptr;
2466: #endif
2467: 
2468: #if 0
2469:   c = getlvalue(&cs,e,RMload);          // get addressing mode
2470:   if (*pretregs == 0)
2471:         return c;
2472:   idxregs = idxregm(&cs);               // mask of index regs used
2473:   c = cat(c,fixresult(e,idxregs,pretregs));
2474:   return c;
2475: #endif
2476:             break;
2477:   }
2478:   sz = tysize[tym];
2479:   byte = tybyte(tym) != 0;
2480: 
2481:   c = getlvalue(&cs,e,RMload);          // get addressing mode
2482:   //printf("Irex = %02x, Irm = x%02x, Isib = x%02x\n", cs.Irex, cs.Irm, cs.Isib);
2483:   /*fprintf(stderr,"cd2 :\n"); WRcodlst(c);*/
2484:   if (*pretregs == 0)
2485:         return c;
2486: 
2487:   idxregs = idxregm(&cs);               // mask of index regs used
2488: 
2489:   if (*pretregs == mPSW)
2490:   {
2491:         if (!I16 && tym == TYfloat)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2492:         {       retregs = ALLREGS & ~idxregs;
2493:                 c = cat(c,allocreg(&retregs,®,TYfloat));
2494:                 cs.Iop = 0x8B;
2495:                 code_newreg(&cs,reg);
2496:                 ce = gen(CNIL,&cs);                     // MOV reg,lsw
2497:                 gen2(ce,0xD1,modregrmx(3,4,reg));       // SHL reg,1
2498:         }
2499:         else if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2500:         {
2501:                 cs.Iop = 0x81 ^ byte;
2502:                 cs.Irm |= modregrm(0,7,0);
2503:                 cs.IFL2 = FLconst;
2504:                 cs.IEV2.Vint = 0;
2505:                 ce = gen(CNIL,&cs);             /* CMP [idx],0          */
2506:         }
2507:         else if (!I16 && sz == REGSIZE + 2)      // if far pointer
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2508:         {       retregs = ALLREGS & ~idxregs;
2509:                 c = cat(c,allocreg(&retregs,®,TYint));
2510:                 cs.Iop = 0x0FB7;
2511:                 cs.Irm |= modregrm(0,reg,0);
2512:                 getlvalue_msw(&cs);
2513:                 ce = gen(CNIL,&cs);             /* MOVZX reg,msw        */
2514:                 goto L4;
2515:         }
2516:         else if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2517:         {       retregs = ALLREGS & ~idxregs;
2518:                 c = cat(c,allocreg(&retregs,®,TYint));
2519:                 cs.Iop = 0x8B;
2520:                 code_newreg(&cs,reg);
2521:                 getlvalue_msw(&cs);
2522:                 ce = gen(CNIL,&cs);             /* MOV reg,msw          */
2523:                 if (I32)
2524:                 {   if (tym == TYdouble || tym == TYdouble_alias)
2525:                         gen2(ce,0xD1,modregrm(3,4,reg)); // SHL reg,1
2526:                 }
2527:                 else if (tym == TYfloat)
2528:                     gen2(ce,0xD1,modregrm(3,4,reg));    /* SHL reg,1    */
2529:         L4:     cs.Iop = 0x0B;
2530:                 getlvalue_lsw(&cs);
2531:                 gen(ce,&cs);                    /* OR reg,lsw           */
2532:         }
2533:         else if (!I32 && sz == 8)
2534:         {       *pretregs |= DOUBLEREGS_16;     /* fake it for now      */
2535:                 goto L1;
2536:         }
2537:         else
2538:         {
2539:                 debugx(WRTYxx(tym));
2540:                 assert(0);
2541:         }
2542:         c = cat(c,ce);
2543:   }
2544:   else                                  /* else return result in reg    */
2545:   {
2546:   L1:   retregs = *pretregs;
2547:         if (sz == 8 &&
2548:             (retregs & (mPSW | mSTACK | ALLREGS | mBP)) == mSTACK)
2549:         {   int i;
2550: 
2551:             /* Optimizer should not CSE these, as the result is worse code! */
2552:             assert(!e->Ecount);
2553: 
2554:             cs.Iop = 0xFF;
2555:             cs.Irm |= modregrm(0,6,0);
2556:             cs.IEVoffset1 += 8 - REGSIZE;
2557:             stackchanged = 1;
2558:             i = 8 - REGSIZE;
2559:             do
2560:             {
2561:                 c = gen(c,&cs);                         /* PUSH EA+i    */
2562:                 c = genadjesp(c,REGSIZE);
2563:                 cs.IEVoffset1 -= REGSIZE;
2564:                 stackpush += REGSIZE;
2565:                 i -= REGSIZE;
2566:             }
2567:             while (i >= 0);
2568:             goto L3;
2569:         }
2570:         if (I16 && sz == 8)
2571:             retregs = DOUBLEREGS_16;
2572: 
2573:         /* Watch out for loading an lptr from an lptr! We must have     */
2574:         /* the offset loaded into a different register.                 */
2575:         /*if (retregs & mES && (cs.Iflags & CFSEG) == CFes)
2576:                 retregs = ALLREGS;*/
2577: 
2578:         {
2579:         assert(!byte || retregs & BYTEREGS);
2580:         c = cat(c,allocreg(&retregs,®,tym)); /* alloc registers */
2581:         }
2582:         if (retregs & XMMREGS)
2583:         {
2584:             assert(sz == 4 || sz == 8);         // float or double
2585:             cs.Iop = (sz == 4) ? 0xF30F10 : 0xF20F10;
2586:             reg -= XMM0;
2587:             goto L2;
2588:         }
2589:         else if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2590:         {
2591:                 cs.Iop = 0x8B ^ byte;
2592:         L2:     code_newreg(&cs,reg);
2593:                 ce = gen(CNIL,&cs);     /* MOV reg,[idx]                */
2594:                 if (byte && reg >= 4)
2595:                     code_orrex(ce, REX);
2596:         }
2597:         else if ((tym == TYfptr || tym == TYhptr) && retregs & mES)
2598:         {
2599:                 cs.Iop = 0xC4;          /* LES reg,[idx]                */
2600:                 goto L2;
2601:         }
2602:         else if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2603:         {   unsigned lsreg;
2604: 
2605:             cs.Iop = 0x8B;
2606:             /* Be careful not to interfere with index registers */
2607:             if (!I16)
2608:             {
2609:                 /* Can't handle if both result registers are used in    */
2610:                 /* the addressing mode.                                 */
2611:                 if ((retregs & idxregs) == retregs)
2612:                 {
2613:                     retregs = mMSW & allregs & ~idxregs;
2614:                     if (!retregs)
2615:                         retregs |= mCX;
2616:                     retregs |= mLSW & ~idxregs;
2617: 
2618:                     // We can run out of registers, so if that's possible,
2619:                     // give us *one* of the idxregs
2620:                     if ((retregs & ~regcon.mvar & mLSW) == 0)
2621:                     {
2622:                         regm_t x = idxregs & mLSW;
2623:                         if (x)
2624:                             retregs |= mask[findreg(x)];        // give us one idxreg
2625:                     }
2626:                     else if ((retregs & ~regcon.mvar & mMSW) == 0)
2627:                     {
2628:                         regm_t x = idxregs & mMSW;
2629:                         if (x)
2630:                             retregs |= mask[findreg(x)];        // give us one idxreg
2631:                     }
2632: 
2633:                     c = cat(c,allocreg(&retregs,®,tym));     /* alloc registers */
2634:                     assert((retregs & idxregs) != retregs);
2635:                 }
2636: 
2637:                 lsreg = findreglsw(retregs);
2638:                 if (mask[reg] & idxregs)                /* reg is in addr mode */
2639:                 {
2640:                     code_newreg(&cs,lsreg);
2641:                     ce = gen(CNIL,&cs);                 /* MOV lsreg,lsw */
2642:                     if (sz == REGSIZE + 2)
2643:                         cs.Iflags |= CFopsize;
2644:                     lsreg = reg;
2645:                     getlvalue_msw(&cs);                 // MOV reg,msw
2646:                 }
2647:                 else
2648:                 {
2649:                     code_newreg(&cs,reg);
2650:                     getlvalue_msw(&cs);
2651:                     ce = gen(CNIL,&cs);                 // MOV reg,msw
2652:                     if (sz == REGSIZE + 2)
2653:                         ce->Iflags |= CFopsize;
2654:                     getlvalue_lsw(&cs);                 // MOV lsreg,lsw
2655:                 }
2656:                 NEWREG(cs.Irm,lsreg);
2657:                 gen(ce,&cs);
2658:             }
2659:             else
2660:             {
2661:                 /* Index registers are always the lsw!                  */
2662:                 cs.Irm |= modregrm(0,reg,0);
2663:                 getlvalue_msw(&cs);
2664:                 ce = gen(CNIL,&cs);     /* MOV reg,msw          */
2665:                 lsreg = findreglsw(retregs);
2666:                 NEWREG(cs.Irm,lsreg);
2667:                 getlvalue_lsw(&cs);     /* MOV lsreg,lsw        */
2668:                 gen(ce,&cs);
2669:             }
2670:         }
2671:         else if (I16 && sz == 8)
2672:         {
2673:                 assert(reg == AX);
2674:                 cs.Iop = 0x8B;
2675:                 cs.IEVoffset1 += 6;
2676:                 ce = gen(CNIL,&cs);             /* MOV AX,EA+6          */
2677:                 cs.Irm |= modregrm(0,CX,0);
2678:                 cs.IEVoffset1 -= 4;
2679:                 gen(ce,&cs);                    /* MOV CX,EA+2          */
2680:                 NEWREG(cs.Irm,DX);
2681:                 cs.IEVoffset1 -= 2;
2682:                 gen(ce,&cs);                    /* MOV DX,EA            */
2683:                 cs.IEVoffset1 += 4;
2684:                 NEWREG(cs.Irm,BX);
2685:                 gen(ce,&cs);                    /* MOV BX,EA+4          */
2686:         }
2687:         else
2688:                 assert(0);
2689:         c = cat(c,ce);
2690:     L3:
2691:         c = cat(c,fixresult(e,retregs,pretregs));
2692:   }
2693:   /*fprintf(stderr,"cdafter :\n"); WRcodlst(c);*/
2694:   return c;
2695: }
2696: 
2697: 
2698: 
2699: #if TARGET_FLAT
2700: #define cod2_setES(ty) NULL
2701: #else
2702: /********************************
2703:  * Generate code to load ES with the right segment value,
2704:  * do nothing if e is a far pointer.
2705:  */
2706: 
2707: STATIC code *cod2_setES(tym_t ty)
2708: {   code *c2;
2709:     int push;
2710: 
2711:     c2 = CNIL;
2712:     switch (tybasic(ty))
2713:     {
2714:         case TYnptr:
2715:             if (!(config.flags3 & CFG3eseqds))
2716:             {   push = 0x1E;            /* PUSH DS              */
2717:                 goto L1;
2718:             }
2719:             break;
2720:         case TYcptr:
2721:             push = 0x0E;                /* PUSH CS              */
2722:             goto L1;
2723:         case TYsptr:
2724:             if ((config.wflags & WFssneds) || !(config.flags3 & CFG3eseqds))
2725:             {   push = 0x16;            /* PUSH SS              */
2726:             L1:
2727:                 /* Must load ES */
2728:                 c2 = getregs(mES);
2729:                 c2 = gen1(c2,push);
2730:                 gen1(c2,0x07);          /* POP ES               */
2731:             }
2732:             break;
2733:     }
2734:     return c2;
2735: }
2736: #endif
2737: 
2738: /********************************
2739:  * Generate code for intrinsic strlen().
2740:  */
2741: 
2742: code *cdstrlen( elem *e, regm_t *pretregs)
2743: {   code *c1,*c2,*c3,*c4;
2744: 
2745:     /* Generate strlen in CX:
2746:         LES     DI,e1
2747:         CLR     AX                      ;scan for 0
2748:         MOV     CX,-1                   ;largest possible string
2749:         REPNE   SCASB
2750:         NOT     CX
2751:         DEC     CX
2752:      */
2753: 
2754:     regm_t retregs = mDI;
2755:     tym_t ty1 = e->E1->Ety;
2756:     if (!tyreg(ty1))
2757:         retregs |= mES;
2758:     c1 = codelem(e->E1,&retregs,FALSE);
2759: 
2760:     /* Make sure ES contains proper segment value       */
2761:     c2 = cod2_setES(ty1);
2762: 
2763:     unsigned char rex = I64 ? REX_W : 0;
2764: 
2765:     c3 = getregs_imm(mAX | mCX);
2766:     c3 = movregconst(c3,AX,0,1);                /* MOV AL,0             */
2767:     c3 = movregconst(c3,CX,-1LL,I64 ? 64 : 0);  // MOV CX,-1
2768:     c3 = cat(c3,getregs(mDI|mCX));
2769:     c3 = gen1(c3,0xF2);                         /* REPNE                        */
2770:     gen1(c3,0xAE);                              /* SCASB                */
2771:     genregs(c3,0xF7,2,CX);                      /* NOT CX               */
2772:     code_orrex(c3,rex);
2773:     if (I64)
2774:         c4 = gen2(CNIL,0xFF,(rex << 16) | modregrm(3,1,CX));  // DEC reg
2775:     else
2776:         c4 = gen1(CNIL,0x48 + CX);              // DEC CX
2777: 
2778:     if (*pretregs & mPSW)
2779:     {
2780:         c4->Iflags |= CFpsw;
2781:         *pretregs &= ~mPSW;
2782:     }
2783:     return cat6(c1,c2,c3,c4,fixresult(e,mCX,pretregs),CNIL);
2784: }
2785: 
2786: 
2787: /*********************************
2788:  * Generate code for strcmp(s1,s2) intrinsic.
2789:  */
2790: 
2791: code *cdstrcmp( elem *e, regm_t *pretregs)
2792: {   code *c1,*c1a,*c2,*c3,*c4;
warning C4101: 'c1a' : unreferenced local variable
2793:     char need_DS;
2794:     int segreg;
2795: 
2796:     /*
2797:         MOV     SI,s1                   ;get destination pointer (s1)
2798:         MOV     CX,s1+2
2799:         LES     DI,s2                   ;get source pointer (s2)
2800:         PUSH    DS
2801:         MOV     DS,CX
2802:         CLR     AX                      ;scan for 0
2803:         MOV     CX,-1                   ;largest possible string
2804:         REPNE   SCASB
2805:         NOT     CX                      ;CX = string length of s2
2806:         SUB     DI,CX                   ;point DI back to beginning
2807:         REPE    CMPSB                   ;compare string
2808:         POP     DS
2809:         JE      L1                      ;strings are equal
2810:         SBB     AX,AX
2811:         SBB     AX,-1
2812:     L1:
2813:     */
2814: 
2815:     regm_t retregs1 = mSI;
2816:     tym_t ty1 = e->E1->Ety;
2817:     if (!tyreg(ty1))
2818:         retregs1 |= mCX;
2819:     c1 = codelem(e->E1,&retregs1,FALSE);
2820: 
2821:     regm_t retregs = mDI;
2822:     tym_t ty2 = e->E2->Ety;
2823:     if (!tyreg(ty2))
2824:         retregs |= mES;
2825:     c1 = cat(c1,scodelem(e->E2,&retregs,retregs1,FALSE));
2826: 
2827:     /* Make sure ES contains proper segment value       */
2828:     c2 = cod2_setES(ty2);
2829:     c3 = getregs_imm(mAX | mCX);
2830: 
2831:     unsigned char rex = I64 ? REX_W : 0;
2832: 
2833:     /* Load DS with right value */
2834:     switch (tybasic(ty1))
2835:     {
2836:         case TYnptr:
2837:             need_DS = FALSE;
2838:             break;
2839:         case TYsptr:
2840:             if (config.wflags & WFssneds)       /* if sptr can't use DS segment */
2841:                 segreg = SEG_SS;
2842:             else
2843:                 segreg = SEG_DS;
2844:             goto L1;
2845:         case TYcptr:
2846:             segreg = SEG_CS;
2847:         L1:
2848:             c3 = gen1(c3,0x1E);                         /* PUSH DS      */
2849:             gen1(c3,0x06 + (segreg << 3));              /* PUSH segreg  */
2850:             gen1(c3,0x1F);                              /* POP  DS      */
2851:             need_DS = TRUE;
2852:             break;
2853:         case TYfptr:
2854:         case TYvptr:
2855:         case TYhptr:
2856:             c3 = gen1(c3,0x1E);                         /* PUSH DS      */
2857:             gen2(c3,0x8E,modregrm(3,SEG_DS,CX));        /* MOV DS,CX    */
2858:             need_DS = TRUE;
2859:             break;
2860:         default:
2861:             assert(0);
2862:     }
2863: 
2864:     c3 = movregconst(c3,AX,0,0);                /* MOV AX,0             */
2865:     c3 = movregconst(c3,CX,-1LL,I64 ? 64 : 0);  // MOV CX,-1
2866:     c3 = cat(c3,getregs(mSI|mDI|mCX));
2867:     c3 = gen1(c3,0xF2);                         /* REPNE                        */
2868:     gen1(c3,0xAE);                              /* SCASB                */
2869:     genregs(c3,0xF7,2,CX);                      /* NOT CX               */
2870:     code_orrex(c3,rex);
2871:     genregs(c3,0x2B,DI,CX);                     /* SUB DI,CX            */
2872:     code_orrex(c3,rex);
2873:     gen1(c3,0xF3);                              /* REPE                 */
2874:     gen1(c3,0xA6);                              /* CMPSB                */
2875:     if (need_DS)
2876:         gen1(c3,0x1F);                          /* POP DS               */
2877:     c4 = gennop(CNIL);
2878:     if (*pretregs != mPSW)                      /* if not flags only    */
2879:     {
2880:         genjmp(c3,JE,FLcode,(block *) c4);      /* JE L1                */
2881:         c3 = cat(c3,getregs(mAX));
2882:         genregs(c3,0x1B,AX,AX);                 /* SBB AX,AX            */
2883:         code_orrex(c3,rex);
2884:         genc2(c3,0x81,(rex << 16) | modregrm(3,3,AX),(targ_uns)-1);   // SBB AX,-1
2885:     }
2886: 
2887:     *pretregs &= ~mPSW;
2888:     return cat6(c1,c2,c3,c4,fixresult(e,mAX,pretregs),CNIL);
2889: }
2890: 
2891: /*********************************
2892:  * Generate code for memcmp(s1,s2,n) intrinsic.
2893:  */
2894: 
2895: code *cdmemcmp(elem *e,regm_t *pretregs)
2896: {   code *c1,*c2,*c3,*c4;
2897:     char need_DS;
2898:     int segreg;
2899: 
2900:     /*
2901:         MOV     SI,s1                   ;get destination pointer (s1)
2902:         MOV     DX,s1+2
2903:         LES     DI,s2                   ;get source pointer (s2)
2904:         MOV     CX,n                    ;get number of bytes to compare
2905:         PUSH    DS
2906:         MOV     DS,DX
2907:         XOR     AX,AX
2908:         REPE    CMPSB                   ;compare string
2909:         POP     DS
2910:         JE      L1                      ;strings are equal
2911:         SBB     AX,AX
2912:         SBB     AX,-1
2913:     L1:
2914:     */
2915: 
2916:     elem *e1 = e->E1;
2917:     assert(e1->Eoper == OPparam);
2918: 
2919:     // Get s1 into DX:SI
2920:     regm_t retregs1 = mSI;
2921:     tym_t ty1 = e1->E1->Ety;
2922:     if (!tyreg(ty1))
2923:         retregs1 |= mDX;
2924:     c1 = codelem(e1->E1,&retregs1,FALSE);
2925: 
2926:     // Get s2 into ES:DI
2927:     regm_t retregs = mDI;
2928:     tym_t ty2 = e1->E2->Ety;
2929:     if (!tyreg(ty2))
2930:         retregs |= mES;
2931:     c1 = cat(c1,scodelem(e1->E2,&retregs,retregs1,FALSE));
2932:     freenode(e1);
2933: 
2934:     // Get nbytes into CX
2935:     regm_t retregs3 = mCX;
2936:     c1 = cat(c1,scodelem(e->E2,&retregs3,retregs | retregs1,FALSE));
2937: 
2938:     /* Make sure ES contains proper segment value       */
2939:     c2 = cod2_setES(ty2);
2940: 
2941:     /* Load DS with right value */
2942:     c3 = NULL;
2943:     switch (tybasic(ty1))
2944:     {
2945:         case TYnptr:
2946:             need_DS = FALSE;
2947:             break;
2948:         case TYsptr:
2949:             if (config.wflags & WFssneds)       /* if sptr can't use DS segment */
2950:                 segreg = SEG_SS;
2951:             else
2952:                 segreg = SEG_DS;
2953:             goto L1;
2954:         case TYcptr:
2955:             segreg = SEG_CS;
2956:         L1:
2957:             c3 = gen1(c3,0x1E);                         /* PUSH DS      */
2958:             gen1(c3,0x06 + (segreg << 3));              /* PUSH segreg  */
2959:             gen1(c3,0x1F);                              /* POP  DS      */
2960:             need_DS = TRUE;
2961:             break;
2962:         case TYfptr:
2963:         case TYvptr:
2964:         case TYhptr:
2965:             c3 = gen1(c3,0x1E);                         /* PUSH DS      */
2966:             gen2(c3,0x8E,modregrm(3,SEG_DS,DX));        /* MOV DS,DX    */
2967:             need_DS = TRUE;
2968:             break;
2969:         default:
2970:             assert(0);
2971:     }
2972: 
2973: #if 1
2974:     c3 = cat(c3,getregs(mAX));
2975:     c3 = gen2(c3,0x33,modregrm(3,AX,AX));       // XOR AX,AX
2976: #else
2977:     if (*pretregs != mPSW)                      // if not flags only
2978:         c3 = regwithvalue(c3,mAX,0,NULL,0);     // put 0 in AX
2979: #endif
2980: 
2981:     c3 = cat(c3,getregs(mCX | mSI | mDI));
2982:     c3 = gen1(c3,0xF3);                         /* REPE                 */
2983:     gen1(c3,0xA6);                              /* CMPSB                */
2984:     if (need_DS)
2985:         gen1(c3,0x1F);                          /* POP DS               */
2986:     if (*pretregs != mPSW)                      /* if not flags only    */
2987:     {
2988:         c4 = gennop(CNIL);
2989:         genjmp(c3,JE,FLcode,(block *) c4);      /* JE L1                */
2990:         c3 = cat(c3,getregs(mAX));
2991:         genregs(c3,0x1B,AX,AX);                 /* SBB AX,AX            */
2992:         genc2(c3,0x81,modregrm(3,3,AX),(targ_uns)-1);   /* SBB AX,-1            */
2993:         c3 = cat(c3,c4);
2994:     }
2995: 
2996:     *pretregs &= ~mPSW;
2997:     return cat4(c1,c2,c3,fixresult(e,mAX,pretregs));
2998: }
2999: 
3000: /*********************************
3001:  * Generate code for strcpy(s1,s2) intrinsic.
3002:  */
3003: 
3004: code *cdstrcpy(elem *e,regm_t *pretregs)
3005: {   code *c1,*c2,*c3,*c4;
3006:     regm_t retregs;
3007:     tym_t ty1,ty2;
3008:     char need_DS;
3009:     int segreg;
3010: 
3011:     /*
3012:         LES     DI,s2                   ;ES:DI = s2
3013:         CLR     AX                      ;scan for 0
3014:         MOV     CX,-1                   ;largest possible string
3015:         REPNE   SCASB                   ;find end of s2
3016:         NOT     CX                      ;CX = strlen(s2) + 1 (for EOS)
3017:         SUB     DI,CX
3018:         MOV     SI,DI
3019:         PUSH    DS
3020:         PUSH    ES
3021:         LES     DI,s1
3022:         POP     DS
3023:         MOV     AX,DI                   ;return value is s1
3024:         REP     MOVSB
3025:         POP     DS
3026:     */
3027: 
3028:     stackchanged = 1;
3029:     retregs = mDI;
3030:     ty2 = tybasic(e->E2->Ety);
3031:     if (!tyreg(ty2))
3032:         retregs |= mES;
3033:     unsigned char rex = I64 ? REX_W : 0;
3034:     c1 = codelem(e->E2,&retregs,FALSE);
3035: 
3036:     /* Make sure ES contains proper segment value       */
3037:     c2 = cod2_setES(ty2);
3038:     c3 = getregs_imm(mAX | mCX);
3039:     c3 = movregconst(c3,AX,0,1);                /* MOV AL,0             */
3040:     c3 = movregconst(c3,CX,-1,I64?64:0);        // MOV CX,-1
3041:     c3 = cat(c3,getregs(mAX|mCX|mSI|mDI));
3042:     c3 = gen1(c3,0xF2);                         /* REPNE                        */
3043:     gen1(c3,0xAE);                              /* SCASB                */
3044:     genregs(c3,0xF7,2,CX);                      /* NOT CX               */
3045:     code_orrex(c3,rex);
3046:     genregs(c3,0x2B,DI,CX);                     /* SUB DI,CX            */
3047:     code_orrex(c3,rex);
3048:     genmovreg(c3,SI,DI);                        /* MOV SI,DI            */
3049:     code_orrex(c3,rex);
3050: 
3051:     /* Load DS with right value */
3052:     switch (ty2)
3053:     {
3054:         case TYnptr:
3055:             need_DS = FALSE;
3056:             break;
3057:         case TYsptr:
3058:             if (config.wflags & WFssneds)       /* if sptr can't use DS segment */
3059:                 segreg = SEG_SS;
3060:             else
3061:                 segreg = SEG_DS;
3062:             goto L1;
3063:         case TYcptr:
3064:             segreg = SEG_CS;
3065:         L1:
3066:             c3 = gen1(c3,0x1E);                         /* PUSH DS      */
3067:             gen1(c3,0x06 + (segreg << 3));              /* PUSH segreg  */
3068:             genadjesp(c3,REGSIZE * 2);
3069:             need_DS = TRUE;
3070:             break;
3071:         case TYfptr:
3072:         case TYvptr:
3073:         case TYhptr:
3074:             segreg = SEG_ES;
3075:             goto L1;
3076:             break;
3077:         default:
3078:             assert(0);
3079:     }
3080: 
3081:     retregs = mDI;
3082:     ty1 = tybasic(e->E1->Ety);
3083:     if (!tyreg(ty1))
3084:         retregs |= mES;
3085:     c3 = cat(c3,scodelem(e->E1,&retregs,mCX|mSI,FALSE));
3086:     c3 = cat(c3,getregs(mAX|mCX|mSI|mDI));
3087: 
3088:     /* Make sure ES contains proper segment value       */
3089:     if (ty2 != TYnptr || ty1 != ty2)
3090:         c4 = cod2_setES(ty1);
3091:     else
3092:         c4 = CNIL;                              /* ES is already same as DS */
3093: 
3094:     if (need_DS)
3095:         c4 = gen1(c4,0x1F);                     /* POP DS               */
3096:     if (*pretregs)
3097:     {   c4 = genmovreg(c4,AX,DI);               /* MOV AX,DI            */
3098:         code_orrex(c4,rex);
3099:     }
3100:     c4 = gen1(c4,0xF3);                         /* REP                  */
3101:     gen1(c4,0xA4);                              /* MOVSB                */
3102: 
3103:     if (need_DS)
3104:     {   gen1(c4,0x1F);                          /* POP DS               */
3105:         genadjesp(c4,-(REGSIZE * 2));
3106:     }
3107:     return cat6(c1,c2,c3,c4,fixresult(e,mAX | mES,pretregs),CNIL);
3108: }
3109: 
3110: /*********************************
3111:  * Generate code for memcpy(s1,s2,n) intrinsic.
3112:  *  OPmemcpy
3113:  *   /   \
3114:  * s1   OPparam
3115:  *       /   \
3116:  *      s2    n
3117:  */
3118: 
3119: code *cdmemcpy(elem *e,regm_t *pretregs)
3120: {   code *c1,*c2,*c3,*c4;
warning C4101: 'c4' : unreferenced local variable
3121:     regm_t retregs1;
3122:     regm_t retregs2;
3123:     regm_t retregs3;
3124:     tym_t ty1,ty2;
3125:     char need_DS;
3126:     int segreg;
3127:     elem *e2;
3128: 
3129:     /*
3130:         MOV     SI,s2
3131:         MOV     DX,s2+2
3132:         MOV     CX,n
3133:         LES     DI,s1
3134:         PUSH    DS
3135:         MOV     DS,DX
3136:         MOV     AX,DI                   ;return value is s1
3137:         REP     MOVSB
3138:         POP     DS
3139:     */
3140: 
3141:     e2 = e->E2;
3142:     assert(e2->Eoper == OPparam);
3143: 
3144:     // Get s2 into DX:SI
3145:     retregs2 = mSI;
3146:     ty2 = e2->E1->Ety;
3147:     if (!tyreg(ty2))
3148:         retregs2 |= mDX;
3149:     c1 = codelem(e2->E1,&retregs2,FALSE);
3150: 
3151:     // Get nbytes into CX
3152:     retregs3 = mCX;
3153:     c1 = cat(c1,scodelem(e2->E2,&retregs3,retregs2,FALSE));
3154:     freenode(e2);
3155: 
3156:     // Get s1 into ES:DI
3157:     retregs1 = mDI;
3158:     ty1 = e->E1->Ety;
3159:     if (!tyreg(ty1))
3160:         retregs1 |= mES;
3161:     c1 = cat(c1,scodelem(e->E1,&retregs1,retregs2 | retregs3,FALSE));
3162: 
3163:     unsigned char rex = I64 ? REX_W : 0;
3164: 
3165:     /* Make sure ES contains proper segment value       */
3166:     c2 = cod2_setES(ty1);
3167: 
3168:     /* Load DS with right value */
3169:     c3 = NULL;
3170:     switch (tybasic(ty2))
3171:     {
3172:         case TYnptr:
3173:             need_DS = FALSE;
3174:             break;
3175:         case TYsptr:
3176:             if (config.wflags & WFssneds)       /* if sptr can't use DS segment */
3177:                 segreg = SEG_SS;
3178:             else
3179:                 segreg = SEG_DS;
3180:             goto L1;
3181:         case TYcptr:
3182:             segreg = SEG_CS;
3183:         L1:
3184:             c3 = gen1(c3,0x1E);                         /* PUSH DS      */
3185:             gen1(c3,0x06 + (segreg << 3));              /* PUSH segreg  */
3186:             gen1(c3,0x1F);                              /* POP  DS      */
3187:             need_DS = TRUE;
3188:             break;
3189:         case TYfptr:
3190:         case TYvptr:
3191:         case TYhptr:
3192:             c3 = gen1(c3,0x1E);                         /* PUSH DS      */
3193:             gen2(c3,0x8E,modregrm(3,SEG_DS,DX));        /* MOV DS,DX    */
3194:             need_DS = TRUE;
3195:             break;
3196:         default:
3197:             assert(0);
3198:     }
3199: 
3200:     if (*pretregs)                              // if need return value
3201:     {   c3 = cat(c3,getregs(mAX));
3202:         c3 = genmovreg(c3,AX,DI);
3203:         code_orrex(c3, rex);
3204:     }
3205: 
3206:     if (0 && I32 && config.flags4 & CFG4speed)
3207:     {
3208:         /* This is only faster if the memory is dword aligned, if not
3209:          * it is significantly slower than just a rep movsb.
3210:          */
3211:         /*      mov     EDX,ECX
3212:          *      shr     ECX,2
3213:          *      jz      L1
3214:          *      repe    movsd
3215:          * L1:  and     EDX,3
3216:          *      jz      L2
3217:          *      mov     ECX,EDX
3218:          *      repe    movsb
3219:          * L2:  nop
3220:          */
3221:         c3 = cat(c3,getregs(mSI | mDI | mCX | mDX));
3222:         c3 = genmovreg(c3,DX,CX);               // MOV EDX,ECX
3223:         c3 = genc2(c3,0xC1,modregrm(3,5,CX),2); // SHR ECX,2
3224:         code *cx = genc2(CNIL, 0x81, modregrm(3,4,DX),3);       // AND EDX,3
3225:         genjmp(c3, JE, FLcode, (block *)cx);                    // JZ L1
3226:         gen1(c3,0xF3);                                          // REPE
3227:         gen1(c3,0xA5);                                          // MOVSW
3228:         c3 = cat(c3,cx);
3229: 
3230:         code *cnop = gennop(CNIL);
3231:         genjmp(c3, JE, FLcode, (block *)cnop);  // JZ L2
3232:         genmovreg(c3,CX,DX);                    // MOV ECX,EDX
3233:         gen1(c3,0xF3);                          // REPE
3234:         gen1(c3,0xA4);                          // MOVSB
3235:         c3 = cat(c3, cnop);
3236:     }
3237:     else
3238:     {
3239:         c3 = cat(c3,getregs(mSI | mDI | mCX));
3240:         if (!I32 && config.flags4 & CFG4speed)          // if speed optimization
3241:         {   c3 = gen2(c3,0xD1,(rex << 16) | modregrm(3,5,CX));        // SHR CX,1
3242:             gen1(c3,0xF3);                              // REPE
3243:             gen1(c3,0xA5);                              // MOVSW
3244:             gen2(c3,0x11,(rex << 16) | modregrm(3,CX,CX));            // ADC CX,CX
3245:         }
3246:         c3 = gen1(c3,0xF3);                             // REPE
3247:         gen1(c3,0xA4);                                  // MOVSB
3248:         if (need_DS)
3249:             gen1(c3,0x1F);                              // POP DS
3250:     }
3251:     return cat4(c1,c2,c3,fixresult(e,mES|mAX,pretregs));
3252: }
3253: 
3254: 
3255: /*********************************
3256:  * Generate code for memset(s,val,n) intrinsic.
3257:  *      (s OPmemset (n OPparam val))
3258:  */
3259: 
3260: #if 1
3261: code *cdmemset(elem *e,regm_t *pretregs)
3262: {   code *c1,*c2,*c3 = NULL,*c4;
warning C4101: 'c4' : unreferenced local variable
3263:     regm_t retregs1;
3264:     regm_t retregs2;
3265:     regm_t retregs3;
3266:     unsigned reg,vreg;
3267:     tym_t ty1;
3268:     int segreg;
warning C4101: 'segreg' : unreferenced local variable
3269:     unsigned remainder;
3270:     targ_uns numbytes,numwords;
3271:     int op;
3272:     targ_size_t value;
3273:     unsigned m;
3274: 
3275:     //printf("cdmemset(*pretregs = %s)\n", regm_str(*pretregs));
3276:     elem *e2 = e->E2;
3277:     assert(e2->Eoper == OPparam);
3278: 
3279:     unsigned char rex = I64 ? REX_W : 0;
3280: 
3281:     if (e2->E2->Eoper == OPconst)
3282:     {
3283:         value = el_tolong(e2->E2);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
3284:         value &= 0xFF;
3285:         value |= value << 8;
3286:         value |= value << 16;
3287:         value |= value << 32;
warning C4293: '<<' : shift count negative or too big, undefined behavior
3288:     }
3289:     else
3290:         value = 0xDEADBEEF;     // stop annoying false positives that value is not inited
3291: 
3292:     if (e2->E1->Eoper == OPconst)
3293:     {
3294:         numbytes = el_tolong(e2->E1);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_uns', possible loss of data
3295:         if (numbytes <= REP_THRESHOLD &&
warning C4018: '<=' : signed/unsigned mismatch
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3296:             !I16 &&                     // doesn't work for 16 bits
3297:             e2->E2->Eoper == OPconst)
3298:         {
3299:             targ_uns offset = 0;
3300:             retregs1 = *pretregs;
3301:             if (!retregs1)
3302:                 retregs1 = ALLREGS;
3303:             c1 = codelem(e->E1,&retregs1,FALSE);
3304:             reg = findreg(retregs1);
3305:             if (e2->E2->Eoper == OPconst)
3306:             {
3307:                 unsigned m = buildModregrm(0,0,reg);
warning C6246: Local declaration of 'm' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3273' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 3273
3308:                 switch (numbytes)
3309:                 {
3310:                     case 4:                     // MOV [reg],imm32
3311:                         c3 = genc2(CNIL,0xC7,m,value);
3312:                         goto fixres;
3313:                     case 2:                     // MOV [reg],imm16
3314:                         c3 = genc2(CNIL,0xC7,m,value);
3315:                         c3->Iflags = CFopsize;
3316:                         goto fixres;
3317:                     case 1:                     // MOV [reg],imm8
3318:                         c3 = genc2(CNIL,0xC6,m,value);
3319:                         goto fixres;
3320:                 }
3321:             }
3322: 
3323:             c1 = regwithvalue(c1, BYTEREGS & ~retregs1, value, &vreg, I64 ? 64 : 0);
3324:             freenode(e2->E2);
3325:             freenode(e2);
3326: 
3327:             m = (rex << 16) | buildModregrm(2,vreg,reg);
3328:             while (numbytes >= REGSIZE)
warning C4018: '>=' : signed/unsigned mismatch
3329:             {                           // MOV dword ptr offset[reg],vreg
3330:                 c2 = gen2(CNIL,0x89,m);
3331:                 c2->IEVoffset1 = offset;
3332:                 c2->IFL1 = FLconst;
3333:                 numbytes -= REGSIZE;
3334:                 offset += REGSIZE;
3335:                 c3 = cat(c3,c2);
3336:             }
3337:             m &= ~(rex << 16);
3338:             if (numbytes & 4)
3339:             {                           // MOV dword ptr offset[reg],vreg
3340:                 c2 = gen2(CNIL,0x89,m);
3341:                 c2->IEVoffset1 = offset;
3342:                 c2->IFL1 = FLconst;
3343:                 offset += 4;
3344:                 c3 = cat(c3,c2);
3345:             }
3346:             if (numbytes & 2)
3347:             {                           // MOV word ptr offset[reg],vreg
3348:                 c2 = gen2(CNIL,0x89,m);
3349:                 c2->IEVoffset1 = offset;
3350:                 c2->IFL1 = FLconst;
3351:                 c2->Iflags = CFopsize;
3352:                 offset += 2;
3353:                 c3 = cat(c3,c2);
3354:             }
3355:             if (numbytes & 1)
3356:             {                           // MOV byte ptr offset[reg],vreg
3357:                 c2 = gen2(CNIL,0x88,m);
3358:                 c2->IEVoffset1 = offset;
3359:                 c2->IFL1 = FLconst;
3360:                 if (I64 && vreg >= 4)
3361:                     c2->Irex |= REX;
3362:                 c3 = cat(c3,c2);
3363:             }
3364: fixres:
3365:             return cat3(c1,c3,fixresult(e,retregs1,pretregs));
3366:         }
3367:     }
3368: 
3369:     // Get nbytes into CX
3370:     retregs2 = mCX;
3371:     if (!I16 && e2->E1->Eoper == OPconst && e2->E2->Eoper == OPconst)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3372:     {
3373:         remainder = numbytes & (4 - 1);
3374:         numwords  = numbytes / 4;               // number of words
3375:         op = 0xAB;                              // moving by words
3376:         c1 = getregs(mCX);
3377:         c1 = movregconst(c1,CX,numwords,I64?64:0);     // # of bytes/words
3378:     }
3379:     else
3380:     {
3381:         remainder = 0;
3382:         op = 0xAA;                              // must move by bytes
3383:         c1 = codelem(e2->E1,&retregs2,FALSE);
3384:     }
3385: 
3386:     // Get val into AX
3387: 
3388:     retregs3 = mAX;
3389:     if (!I16 && e2->E2->Eoper == OPconst)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3390:     {
3391:         c1 = regwithvalue(c1, mAX, value, NULL, I64?64:0);
3392:         freenode(e2->E2);
3393:     }
3394:     else
3395:     {
3396:         c1 = cat(c1,scodelem(e2->E2,&retregs3,retregs2,FALSE));
3397: #if 0
3398:         if (I32)
3399:         {
3400:             c1 = gen2(c1,0x8A,modregrm(3,AH,AL));       // MOV AH,AL
3401:             c1 = genc2(c1,0xC1,modregrm(3,4,AX),8);     // SHL EAX,8
3402:             c1 = gen2(c1,0x8A,modregrm(3,AL,AH));       // MOV AL,AH
3403:             c1 = genc2(c1,0xC1,modregrm(3,4,AX),8);     // SHL EAX,8
3404:             c1 = gen2(c1,0x8A,modregrm(3,AL,AH));       // MOV AL,AH
3405:         }
3406: #endif
3407:     }
3408:     freenode(e2);
3409: 
3410:     // Get s into ES:DI
3411:     retregs1 = mDI;
3412:     ty1 = e->E1->Ety;
3413:     if (!tyreg(ty1))
3414:         retregs1 |= mES;
3415:     c1 = cat(c1,scodelem(e->E1,&retregs1,retregs2 | retregs3,FALSE));
3416:     reg = DI; //findreg(retregs1);
3417: 
3418:     // Make sure ES contains proper segment value
3419:     c2 = cod2_setES(ty1);
3420: 
3421:     c3 = NULL;
3422:     if (*pretregs)                              // if need return value
3423:     {   c3 = getregs(mBX);
3424:         c3 = genmovreg(c3,BX,DI);
3425:         code_orrex(c3,rex);
3426:     }
3427: 
3428:     c3 = cat(c3,getregs(mDI | mCX));
3429:     if (I16 && config.flags4 & CFG4speed)      // if speed optimization
3430:     {
3431:         c3 = cat(c3,getregs(mAX));
3432:         c3 = gen2(c3,0x8A,modregrm(3,AH,AL));   // MOV AH,AL
3433:         gen2(c3,0xD1,modregrm(3,5,CX));         // SHR CX,1
3434:         gen1(c3,0xF3);                          // REP
3435:         gen1(c3,0xAB);                          // STOSW
3436:         gen2(c3,0x11,modregrm(3,CX,CX));        // ADC CX,CX
3437:         op = 0xAA;
3438:     }
3439: 
3440:     c3 = gen1(c3,0xF3);                         // REP
3441:     gen1(c3,op);                                // STOSD
3442:     m = buildModregrm(2,AX,reg);
3443:     if (remainder & 4)
3444:     {
3445:         code *ctmp;
3446:         ctmp = gen2(CNIL,0x89,m);
3447:         ctmp->IFL1 = FLconst;
3448:         c3 = cat(c3,ctmp);
3449:     }
3450:     if (remainder & 2)
3451:     {
3452:         code *ctmp;
3453:         ctmp = gen2(CNIL,0x89,m);
3454:         ctmp->Iflags = CFopsize;
3455:         ctmp->IEVoffset1 = remainder & 4;
3456:         ctmp->IFL1 = FLconst;
3457:         c3 = cat(c3,ctmp);
3458:     }
3459:     if (remainder & 1)
3460:     {
3461:         code *ctmp;
3462:         ctmp = gen2(CNIL,0x88,m);
3463:         ctmp->IEVoffset1 = remainder & ~1;
3464:         ctmp->IFL1 = FLconst;
3465:         c3 = cat(c3,ctmp);
3466:     }
3467:     regimmed_set(CX,0);
3468:     return cat4(c1,c2,c3,fixresult(e,mES|mBX,pretregs));
3469: }
3470: #else
3471: // BUG: Pat made many improvements in the linux version, I need
3472: // to verify they work for 16 bits and fold them in. -Walter
3473: 
3474: code *cdmemset(elem *e,regm_t *pretregs)
3475: {   code *c1,*c2,*c3 = NULL,*c4;
3476:     regm_t retregs1;
3477:     regm_t retregs2;
3478:     regm_t retregs3;
3479:     tym_t ty1;
3480:     elem *e2;
3481:     targ_size_t value;
3482: 
3483:     /*
3484:         les     DI,s
3485:         mov     BX,DI           ;Return value.
3486:         mov     CX,n
3487:         mov     AL,val
3488:         mov     AH,AL           ;Set up a 16 bit pattern.
3489:         shr     CX,1
3490:         rep     stosw
3491:         adc     CX,CX
3492:         rep     stosb
3493:     */
3494: 
3495:     e2 = e->E2;
3496:     assert(e2->Eoper == OPparam);
3497: 
3498:     // Get nbytes into CX
3499:     retregs2 = mCX;
3500:     c1 = codelem(e2->E1,&retregs2,FALSE);
3501: 
3502:     // Get val into AX
3503:     retregs3 = mAX;
3504:     c1 = cat(c1,scodelem(e2->E2,&retregs3,retregs2,FALSE));
3505:     freenode(e2);
3506: 
3507:     // Get s into ES:DI
3508:     retregs1 = mDI;
3509:     ty1 = e->E1->Ety;
3510:     if (!tyreg(ty1))
3511:         retregs1 |= mES;
3512:     c1 = cat(c1,scodelem(e->E1,&retregs1,retregs2 | retregs3,FALSE));
3513: 
3514:     /* Make sure ES contains proper segment value       */
3515:     c2 = cod2_setES(ty1);
3516: 
3517:     c3 = NULL;
3518:     if (*pretregs)                              // if need return value
3519:     {   c3 = getregs(mBX);
3520:         c3 = genmovreg(c3,BX,DI);
3521:     }
3522: 
3523:     c3 = cat(c3,getregs(mDI | mCX));
3524:     if (!I32 && config.flags4 & CFG4speed)      // if speed optimization
3525:     {
3526:         c3 = cat(c3,getregs(mAX));
3527:         c3 = gen2(c3,0x8A,modregrm(3,AH,AL));   // MOV AH,AL
3528:         gen2(c3,0xD1,modregrm(3,5,CX));         // SHR CX,1
3529:         gen1(c3,0xF3);                          // REP
3530:         gen1(c3,0xAB);                          // STOSW
3531:         gen2(c3,0x11,modregrm(3,CX,CX));        // ADC CX,CX
3532:     }
3533:     c3 = gen1(c3,0xF3);                         // REP
3534:     gen1(c3,0xAA);                              // STOSB
3535:     regimmed_set(CX,0);
3536:     return cat4(c1,c2,c3,fixresult(e,mES|mBX,pretregs));
3537: }
3538: #endif
3539: 
3540: /**********************
3541:  * Do structure assignments.
3542:  * This should be fixed so that (s1 = s2) is rewritten to (&s1 = &s2).
3543:  * Mebbe call cdstreq() for double assignments???
3544:  */
3545: 
3546: code *cdstreq(elem *e,regm_t *pretregs)
3547: { code *c1,*c2,*c3;
3548:   code *c1a;
3549:   regm_t srcregs,dstregs;               /* source & destination reg masks */
3550:   char need_DS = FALSE;
3551:   elem *e1 = e->E1,*e2 = e->E2;
3552:   int segreg;
3553: 
3554:     unsigned numbytes = type_size(e->ET);              // # of bytes in structure/union
3555:     unsigned char rex = I64 ? REX_W : 0;
3556: 
3557:     //printf("cdstreq(e = %p, *pretregs = x%x)\n", e, *pretregs);
3558: 
3559:     /* First, load pointer to rvalue into SI                            */
3560:     srcregs = mSI;                      /* source is DS:SI              */
3561:     c1 = docommas(&e2);
3562:     if (e2->Eoper == OPind)             /* if (.. = *p)                 */
3563:     {   elem *e21 = e2->E1;
3564: 
3565:         segreg = SEG_DS;
3566:         switch (tybasic(e21->Ety))
3567:         {
3568:             case TYsptr:
3569:                 if (config.wflags & WFssneds)   /* if sptr can't use DS segment */
3570:                     segreg = SEG_SS;
3571:                 break;
3572:             case TYcptr:
3573:                 if (!(config.exe & EX_flat))
3574:                     segreg = SEG_CS;
3575:                 break;
3576:             case TYfptr:
3577:             case TYvptr:
3578:             case TYhptr:
3579:                 srcregs |= mCX;         /* get segment also             */
3580:                 need_DS = TRUE;
3581:                 break;
3582:         }
3583:         c1a = codelem(e21,&srcregs,FALSE);
3584:         freenode(e2);
3585:         if (segreg != SEG_DS)           /* if not DS                    */
3586:         {   c1a = cat(c1a,getregs(mCX));
3587:             c1a = gen2(c1a,0x8C,modregrm(3,segreg,CX)); /* MOV CX,segreg */
3588:             need_DS = TRUE;
3589:         }
3590:     }
3591:     else if (e2->Eoper == OPvar)
3592:     {
3593: #if !TARGET_FLAT
3594:         if (e2->EV.sp.Vsym->ty() & mTYfar) // if e2 is in a far segment
3595:         {   srcregs |= mCX;             /* get segment also             */
3596:             need_DS = TRUE;
3597:             c1a = cdrelconst(e2,&srcregs);
3598:         }
3599:         else
3600: #endif
3601:         {
3602:             c1a = cdrelconst(e2,&srcregs);
3603:             segreg = segfl[el_fl(e2)];
3604:             if ((config.wflags & WFssneds) && segreg == SEG_SS || /* if source is on stack */
3605:                 segreg == SEG_CS)               /* if source is in CS */
3606:             {   code *c;
3607: 
3608:                 need_DS = TRUE;         /* we need to reload DS         */
3609:                 // Load CX with segment
3610:                 srcregs |= mCX;
3611:                 c = getregs(mCX);
3612:                 c = gen2(c,0x8C,                /* MOV CX,[SS|CS]       */
3613:                     modregrm(3,segreg,CX));
3614:                 c1a = cat(c,c1a);
3615:             }
3616:         }
3617:         freenode(e2);
3618:     }
3619:     else
3620:     {
3621:         if (!(config.exe & EX_flat))
3622:         {   need_DS = TRUE;
3623:             srcregs |= mCX;
3624:         }
3625:         c1a = codelem(e2,&srcregs,FALSE);
3626:     }
3627:     c1 = cat(c1,c1a);
3628: 
3629:   /* now get pointer to lvalue (destination) in ES:DI                   */
3630:   dstregs = (config.exe & EX_flat) ? mDI : mES|mDI;
3631:   if (e1->Eoper == OPind)               /* if (*p = ..)                 */
3632:   {
3633:         if (tyreg(e1->E1->Ety))
3634:             dstregs = mDI;
3635:         c2 = cod2_setES(e1->E1->Ety);
3636:         c2 = cat(c2,scodelem(e1->E1,&dstregs,srcregs,FALSE));
3637:   }
3638:   else
3639:         c2 = cdrelconst(e1,&dstregs);
3640:   freenode(e1);
3641: 
3642:   c3 = getregs((srcregs | dstregs) & (mLSW | mDI));
3643:   if (need_DS)
3644:   {     assert(!(config.exe & EX_flat));
3645:         c3 = gen1(c3,0x1E);                     /* PUSH DS              */
3646:         gen2(c3,0x8E,modregrm(3,SEG_DS,CX));    /* MOV DS,CX            */
3647:   }
3648:   if (numbytes <= REGSIZE * (6 + (REGSIZE == 4)))
warning C4018: '<=' : signed/unsigned mismatch
3649:   {     while (numbytes >= REGSIZE)
warning C4018: '>=' : signed/unsigned mismatch
3650:         {
3651:             c3 = gen1(c3,0xA5);         /* MOVSW                        */
3652:             code_orrex(c3, rex);
3653:             numbytes -= REGSIZE;
3654:         }
3655:         //if (numbytes)
3656:         //    printf("cdstreq numbytes %d\n",numbytes);
3657:         while (numbytes--)
3658:             c3 = gen1(c3,0xA4);         /* MOVSB                        */
3659:   }
3660:     else
3661:     {
3662: #if 1
3663:         unsigned remainder;
3664: 
3665:         remainder = numbytes & (REGSIZE - 1);
3666:         numbytes /= REGSIZE;            // number of words
3667:         c3 = cat(c3,getregs_imm(mCX));
3668:         c3 = movregconst(c3,CX,numbytes,0);     // # of bytes/words
3669:         gen1(c3,0xF3);                          // REP
3670:         if (REGSIZE == 8)
3671:             gen1(c3,REX | REX_W);
3672:         gen1(c3,0xA5);                  // REP MOVSD
3673:         regimmed_set(CX,0);             // note that CX == 0
3674:         for (; remainder; remainder--)
3675:         {
3676:             gen1(c3, 0xA4);             // MOVSB
3677:         }
3678: #else
3679:         unsigned movs;
3680: 
3681:         if (numbytes & (REGSIZE - 1))   /* if odd                       */
3682:                 movs = 0xA4;            /* MOVSB                        */
3683:         else
3684:         {       movs = 0xA5;            /* MOVSW                        */
3685:                 numbytes /= REGSIZE;    /* # of words                   */
3686:         }
3687:         c3 = cat(c3,getregs_imm(mCX));
3688:         c3 = movregconst(c3,CX,numbytes,0);     /* # of bytes/words     */
3689:         gen1(c3,0xF3);                          /* REP                  */
3690:         gen1(c3,movs);
3691:         regimmed_set(CX,0);             /* note that CX == 0            */
3692: #endif
3693:     }
3694:     if (need_DS)
3695:         gen1(c3,0x1F);                          // POP  DS
3696:     assert(!(*pretregs & mPSW));
3697:     if (*pretregs)
3698:     {   /* ES:DI points past what we want       */
3699:         regm_t retregs;
3700: 
3701:         genc2(c3,0x81,(rex << 16) | modregrm(3,5,DI), type_size(e->ET));   // SUB DI,numbytes
3702:         retregs = mDI;
3703:         if (*pretregs & mMSW && !(config.exe & EX_flat))
3704:             retregs |= mES;
3705:         c3 = cat(c3,fixresult(e,retregs,pretregs));
3706:     }
3707:     return cat3(c1,c2,c3);
3708: }
3709: 
3710: 
3711: /**********************
3712:  * Get the address of.
3713:  * Is also called by cdstreq() to set up pointer to a structure.
3714:  */
3715: 
3716: code *cdrelconst(elem *e,regm_t *pretregs)
3717: { code *c,*c1;
3718:   enum SC sclass;
3719:   unsigned mreg,                /* segment of the address (TYfptrs only) */
3720:         lreg;                   /* offset of the address                */
3721:   tym_t tym;
3722: 
3723:   //printf("cdrelconst(e = %p)\n", e);
3724: 
3725:   c = CNIL;
3726: 
3727:   /* The following should not happen, but cgelem.c is a little stupid.  */
3728:   /* Assertion can be tripped by func("string" == 0); and similar       */
3729:   /* things. Need to add goals to optelem() to fix this completely.     */
3730:   /*assert((*pretregs & mPSW) == 0);*/
3731:   if (*pretregs & mPSW)
3732:   {     *pretregs &= ~mPSW;
3733:         c = gentstreg(c,SP);            // SP is never 0
3734:         if (I64)
3735:             code_orrex(c, REX_W);
3736:   }
3737:   if (!*pretregs)
3738:         return c;
3739: 
3740:   assert(e);
3741:   tym = tybasic(e->Ety);
3742:   switch (tym)
3743:   {     case TYstruct:
3744:         case TYarray:
3745:         case TYldouble:
3746:         case TYildouble:
3747:         case TYcldouble:
3748:             tym = TYnptr;               // don't confuse allocreg()
3749: #if !TARGET_FLAT
3750:             if (*pretregs & (mES | mCX) || e->Ety & mTYfar)
3751:             {
3752:                     tym = TYfptr;
3753:             }
3754: #endif
3755:             break;
3756:         case TYifunc:
3757:             tym = TYfptr;
3758:             break;
3759:         default:
3760:             if (tyfunc(tym))
3761:                 tym = tyfarfunc(tym) ? TYfptr : TYnptr;
3762:             break;
3763:   }
3764:   /*assert(tym & typtr);*/              /* don't fail on (int)&a        */
3765: 
3766:   c = cat(c,allocreg(pretregs,&lreg,tym));
3767:   if (tysize[tym] > REGSIZE)            /* fptr could've been cast to long */
3768:   {     tym_t ety;
3769:         symbol *s;
3770: 
3771:         //elem_print(e);
3772:         assert(!TARGET_FLAT);
3773: 
3774:         if (*pretregs & mES)
3775:         {       regm_t scratch = (mAX|mBX|mDX|mDI) & ~mask[lreg];
3776:                 /* Do not allocate CX or SI here, as cdstreq() needs    */
3777:                 /* them preserved. cdstreq() should use scodelem()...   */
3778: 
3779:                 c = cat(c,allocreg(&scratch,&mreg,TYint));
3780:         }
3781:         else
3782:         {       mreg = lreg;
3783:                 lreg = findreglsw(*pretregs);
3784:         }
3785: 
3786:         /* if (get segment of function that isn't necessarily in the    */
3787:         /* current segment (i.e. CS doesn't have the right value in it) */
3788:         s = e->EV.sp.Vsym;
3789:         if (s->Sfl == FLdatseg)
3790:         {   assert(0);
3791:             goto loadreg;
3792:         }
3793:         sclass = (enum SC) s->Sclass;
3794:         ety = tybasic(s->ty());
3795:         if ((tyfarfunc(ety) || ety == TYifunc) &&
3796:             (sclass == SCextern || ClassInline(sclass) || config.wflags & WFthunk)
3797:             || s->Sfl == FLfardata
3798:             || (s->ty() & mTYcs && s->Sseg != cseg && (LARGECODE || s->Sclass == SCcomdat))
3799: //          || (s->Sfl == FLextern && s->ty() & mTYcs)
3800: //          || (LARGECODE && s->Sclass == SCcomdat)
3801:            )
3802:         {       /* MOV mreg,seg of symbol       */
3803:                 c1 = gencs(CNIL,0xB8 + mreg,0,FLextern,s);
3804:                 c1->Iflags = CFseg;
3805:                 c = cat(c,c1);
3806:                 assert(!TARGET_FLAT);
3807:         }
3808:         else
3809:         {   int fl;
3810: 
3811:         loadreg:
3812:             fl = s->Sfl;
3813:             if (s->ty() & mTYcs)
3814:                 fl = FLcsdata;
3815:             c = gen2(c,0x8C,            /* MOV mreg,SEG REGISTER        */
3816:                 modregrm(3,segfl[fl],mreg));
3817:         }
3818:         if (*pretregs & mES)
3819:                 gen2(c,0x8E,modregrm(3,0,mreg));        /* MOV ES,mreg  */
3820:   }
3821:   return cat(c,getoffset(e,lreg));
3822: }
3823: 
3824: /*********************************
3825:  * Load the offset portion of the address represented by e into
3826:  * reg.
3827:  */
3828: 
3829: code *getoffset(elem *e,unsigned reg)
3830: { code cs;
3831:   code *c;
3832: 
3833:   //printf("getoffset(e = %p, reg = %d)\n", e, reg);
3834:   cs.Iflags = 0;
3835:   unsigned char rex = 0;
3836:   cs.Irex = rex;
3837:   assert(e->Eoper == OPvar || e->Eoper == OPrelconst);
3838:   enum FL fl = el_fl(e);
3839:   switch (fl)
3840:   {
3841:     case FLdatseg:
3842:         cs.IEV2._EP.Vpointer = e->EV.Vpointer;
3843:         goto L3;
3844: 
3845:     case FLfardata:
3846:         assert(!TARGET_FLAT);
3847:         goto L4;
3848: 
3849:     case FLtlsdata:
3850: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
3851:     {
3852:       L5:
3853:         if (I64 && config.flags3 & CFG3pic)
3854:         {
3855:             /* Generate:
3856:              *   LEA DI,s@TLSGD[RIP]
3857:              */
3858:             assert(reg == DI);
3859:             code css;
3860:             css.Irex = REX | REX_W;
3861:             css.Iop = 0x8D;             // LEA
3862:             css.Irm = modregrm(0,DI,5);
3863:             css.Iflags = CFopsize;
3864:             css.IFL1 = fl;
3865:             css.IEVsym1 = e->EV.sp.Vsym;
3866:             css.IEVoffset1 = e->EV.sp.Voffset;
3867:             c = gen(NULL, &css);
3868:             return c;
3869:         }
3870:         /* Generate:
3871:          *      MOV reg,GS:[00000000]
3872:          *      ADD reg, offset s@TLS_LE
3873:          * for locals, and for globals:
3874:          *      MOV reg,GS:[00000000]
3875:          *      ADD reg, s@TLS_IE
3876:          * note different fixup
3877:          */
3878:         int stack = 0;
3879:         c = NULL;
3880:         if (reg == STACK)
3881:         {   regm_t retregs = ALLREGS;
3882: 
3883:             c = allocreg(&retregs,®,TYoffset);
3884:             reg = findreg(retregs);
3885:             stack = 1;
3886:         }
3887: 
3888:         code css;
3889:         css.Irex = rex;
3890:         css.Iop = 0x8B;
3891:         css.Irm = modregrm(0, 0, BPRM);
3892:         code_newreg(&css, reg);
3893:         css.Iflags = CFgs;
3894:         css.IFL1 = FLconst;
3895:         css.IEV1.Vuns = 0;
3896:         c = gen(c, &css);               // MOV reg,GS:[00000000]
3897: 
3898:         if (e->EV.sp.Vsym->Sclass == SCstatic || e->EV.sp.Vsym->Sclass == SClocstat)
3899:         {   // ADD reg, offset s
3900:             cs.Irex = rex;
3901:             cs.Iop = 0x81;
3902:             cs.Irm = modregrm(3,0,reg & 7);
3903:             if (reg & 8)
3904:                 cs.Irex |= REX_B;
3905:             cs.Iflags = CFoff;
3906:             cs.IFL2 = fl;
3907:             cs.IEVsym2 = e->EV.sp.Vsym;
3908:             cs.IEVoffset2 = e->EV.sp.Voffset;
3909:         }
3910:         else
3911:         {   // ADD reg, s
3912:             cs.Irex = rex;
3913:             cs.Iop = 0x03;
3914:             cs.Irm = modregrm(0,0,BPRM);
3915:             code_newreg(&cs, reg);
3916:             cs.Iflags = CFoff;
3917:             cs.IFL1 = fl;
3918:             cs.IEVsym1 = e->EV.sp.Vsym;
3919:             cs.IEVoffset1 = e->EV.sp.Voffset;
3920:         }
3921:         c = gen(c, &cs);                // ADD reg, xxxx
3922: 
3923:         if (stack)
3924:         {
3925:             c = gen1(c,0x50 + (reg & 7));      // PUSH reg
3926:             if (reg & 8)
3927:                 code_orrex(c, REX_B);
3928:             c = genadjesp(c,REGSIZE);
3929:             stackchanged = 1;
3930:         }
3931:         break;
3932:     }
3933: #else
3934:         goto L4;
3935: #endif
3936: 
3937:     case FLfunc:
3938:         fl = FLextern;                  /* don't want PC relative addresses */
3939:         goto L4;
3940: 
3941:     case FLextern:
3942: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
3943:         if (e->EV.sp.Vsym->ty() & mTYthread)
3944:             goto L5;
3945: #endif
3946:     case FLdata:
3947:     case FLudata:
3948: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
3949:     case FLgot:
3950:     case FLgotoff:
3951: #endif
3952:     case FLcsdata:
3953:     L4:
3954:         cs.IEVsym2 = e->EV.sp.Vsym;
3955:         cs.IEVoffset2 = e->EV.sp.Voffset;
3956:     L3:
3957:         if (reg == STACK)
3958:         {   stackchanged = 1;
3959:             cs.Iop = 0x68;              /* PUSH immed16                 */
3960:             c = genadjesp(NULL,REGSIZE);
3961:         }
3962:         else
3963:         {   cs.Iop = 0xB8 + (reg & 7);  // MOV reg,immed16
3964:             if (reg & 8)
3965:                 cs.Irex |= REX_B;
3966:             if (I64)
3967:             {   cs.Irex |= REX_W;
3968:                 if (config.flags3 & CFG3pic)
3969:                 {   // LEA reg,immed32[RIP]
3970:                     cs.Iop = 0x8D;
3971:                     cs.Irm = modregrm(0,reg & 7,5);
3972:                     if (reg & 8)
3973:                         cs.Irex = (cs.Irex & ~REX_B) | REX_R;
3974:                     cs.IFL1 = fl;
3975:                     cs.IEVsym1 = cs.IEVsym2;
3976:                     cs.IEVoffset1 = cs.IEVoffset2;
3977:                 }
3978:             }
3979:             c = NULL;
3980:         }
3981:         cs.Iflags = CFoff;              /* want offset only             */
3982:         cs.IFL2 = fl;
3983:         c = gen(c,&cs);
3984:         break;
3985: 
3986: #if 0 && TARGET_LINUX
3987:     case FLgot:
3988:     case FLgotoff:
3989:         {
3990:         gotref = 1;
3991:         symbol *s = e->EV.sp.Vsym;
3992:         // When using 8B (MOV), indicating that rm is used
3993:         // rm operands are always placed in IEV1 not IEV2
3994:         cs.IEVsym1 = s;
3995:         cs.IEVoffset1 = e->EV.sp.Voffset;
3996:         cs.Irm = modregrm(2,reg,BX);    // reg,disp32[EBX]
3997:         cs.IFL1 = fl;
3998:         cs.Iop = (fl == FLgotoff)
3999:                 ? 0x8D                  // LEA reg, s[EBX]
4000:                 : 0x8B;                 // MOV reg, s[EBX]
4001:         cs.Iflags = CFoff;              // want offset only
4002:         c = gen(NULL,&cs);
4003:         break;
4004:         }
4005: #endif
4006: 
4007:     case FLreg:
4008:         /* Allow this since the tree optimizer puts & in front of       */
4009:         /* register doubles.                                            */
4010:         goto L2;
4011:     case FLauto:
4012:     case FLtmp:
4013:     case FLbprel:
4014:     case FLfltreg:
4015:         reflocal = TRUE;
4016:         goto L2;
4017:     case FLpara:
4018:         refparam = TRUE;
4019:     L2:
4020:         if (reg == STACK)
4021:         {   regm_t retregs = ALLREGS;
4022: 
4023:             c = allocreg(&retregs,®,TYoffset);
4024:             reg = findreg(retregs);
4025:             c = cat(c,loadea(e,&cs,0x8D,reg,0,0,0));    /* LEA reg,EA   */
4026:             if (I64)
4027:                 code_orrex(c, REX_W);
4028:             c = gen1(c,0x50 + (reg & 7));               // PUSH reg
4029:             if (reg & 8)
4030:                 code_orrex(c, REX_B);
4031:             c = genadjesp(c,REGSIZE);
4032:             stackchanged = 1;
4033:         }
4034:         else
4035:         {   c = loadea(e,&cs,0x8D,reg,0,0,0);   /* LEA reg,EA           */
4036:             if (I64)
4037:                 code_orrex(c, REX_W);
4038:         }
4039:         break;
4040:     default:
4041: #ifdef DEBUG
4042:         elem_print(e);
4043:         debugx(WRFL(fl));
4044: #endif
4045:         assert(0);
4046:   }
4047:   return c;
4048: }
4049: 
4050: 
4051: /******************
4052:  * Negate, sqrt operator
4053:  */
4054: 
4055: code *cdneg(elem *e,regm_t *pretregs)
4056: { unsigned byte;
4057:   regm_t retregs,possregs;
4058:   int reg;
4059:   int sz;
4060:   tym_t tyml;
4061:   code *c,*c1,*cg;
4062: 
4063:   //printf("cdneg()\n");
4064:   //elem_print(e);
4065:   if (*pretregs == 0)
4066:         return codelem(e->E1,pretregs,FALSE);
4067:   tyml = tybasic(e->E1->Ety);
4068:   sz = tysize[tyml];
4069:   if (tyfloating(tyml))
4070:   {     if (tycomplex(tyml))
4071:             return neg_complex87(e, pretregs);
4072:         if (config.inline8087 &&
4073:             ((*pretregs & (ALLREGS | mBP)) == 0 || e->Eoper == OPsqrt || I64))
4074:                 return neg87(e,pretregs);
4075:         retregs = (I16 && sz == 8) ? DOUBLEREGS_16 : ALLREGS;
4076:         c1 = codelem(e->E1,&retregs,FALSE);
4077:         c1 = cat(c1,getregs(retregs));
4078:         if (I32)
4079:         {   reg = (sz == 8) ? findregmsw(retregs) : findreg(retregs);
4080:             c1 = genc2(c1,0x81,modregrm(3,6,reg),0x80000000); /* XOR EDX,sign bit */
4081:         }
4082:         else
4083:         {   reg = (sz == 8) ? AX : findregmsw(retregs);
4084:             c1 = genc2(c1,0x81,modregrm(3,6,reg),0x8000);     /* XOR AX,0x8000 */
4085:         }
4086:         return cat(c1,fixresult(e,retregs,pretregs));
4087:   }
4088: 
4089:   byte = sz == 1;
4090:   possregs = (byte) ? BYTEREGS : allregs;
4091:   retregs = *pretregs & possregs;
4092:   if (retregs == 0)
4093:         retregs = possregs;
4094:   c1 = codelem(e->E1,&retregs,FALSE);
4095:   cg = getregs(retregs);                /* retregs will be destroyed    */
4096:   if (sz <= REGSIZE)
4097:   {
4098:         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 '4058' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 4058
4099:         unsigned rex = (I64 && sz == 8) ? REX_W : 0;
4100:         if (I64 && sz == 1 && reg >= 4)
4101:             rex |= REX;
4102:         c = gen2(CNIL,0xF7 ^ byte,(rex << 16) | modregrmx(3,3,reg));   // NEG reg
4103:         if (!I16 && tysize[tyml] == SHORTSIZE && *pretregs & mPSW)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4104:             c->Iflags |= CFopsize | CFpsw;
4105:         *pretregs &= mBP | ALLREGS;             // flags already set
4106:   }
4107:   else if (sz == 2 * REGSIZE)
4108:   {     unsigned msreg,lsreg;
4109: 
4110:         msreg = findregmsw(retregs);
4111:         c = gen2(CNIL,0xF7,modregrm(3,3,msreg)); /* NEG msreg           */
4112:         lsreg = findreglsw(retregs);
4113:         gen2(c,0xF7,modregrm(3,3,lsreg));       /* NEG lsreg            */
4114:         genc2(c,0x81,modregrm(3,3,msreg),0);    /* SBB msreg,0          */
4115:   }
4116:   else
4117:         assert(0);
4118:   return cat4(c1,cg,c,fixresult(e,retregs,pretregs));
4119: }
4120: 
4121: 
4122: /******************
4123:  * Absolute value operator
4124:  */
4125: 
4126: code *cdabs( elem *e, regm_t *pretregs)
4127: { unsigned byte;
4128:   regm_t retregs,possregs;
4129:   int reg;
4130:   tym_t tyml;
4131:   code *c,*c1,*cg;
4132: 
4133:   if (*pretregs == 0)
4134:         return codelem(e->E1,pretregs,FALSE);
4135:   tyml = tybasic(e->E1->Ety);
4136:   int sz = tysize[tyml];
4137:   unsigned rex = (I64 && sz == 8) ? REX_W : 0;
4138:   if (tyfloating(tyml))
4139:   {     if (config.inline8087 && ((*pretregs & (ALLREGS | mBP)) == 0 || I64))
4140:                 return neg87(e,pretregs);
4141:         retregs = (!I32 && sz == 8) ? DOUBLEREGS_16 : ALLREGS;
4142:         c1 = codelem(e->E1,&retregs,FALSE);
4143:         /*cg = callclib(e,CLIBdneg,pretregs,0);*/
4144:         c1 = cat(c1,getregs(retregs));
4145:         if (I32)
4146:         {   reg = (sz == 8) ? findregmsw(retregs) : findreg(retregs);
4147:             c1 = genc2(c1,0x81,modregrm(3,4,reg),0x7FFFFFFF); /* AND EDX,~sign bit */
4148:         }
4149:         else
4150:         {   reg = (sz == 8) ? AX : findregmsw(retregs);
4151:             c1 = genc2(c1,0x81,modregrm(3,4,reg),0x7FFF);     /* AND AX,0x7FFF */
4152:         }
4153:         return cat(c1,fixresult(e,retregs,pretregs));
4154:   }
4155: 
4156:   byte = sz == 1;
4157:   assert(byte == 0);
4158:   byte = 0;
4159:   possregs = (sz <= REGSIZE) ? mAX : allregs;
4160:   if (!I16 && sz == REGSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4161:         possregs = allregs;
4162:   retregs = *pretregs & possregs;
4163:   if (retregs == 0)
4164:         retregs = possregs;
4165:   c1 = codelem(e->E1,&retregs,FALSE);
4166:   cg = getregs(retregs);                /* retregs will be destroyed    */
4167:   if (sz <= REGSIZE)
4168:   {
4169:         /*      CWD
4170:                 XOR     AX,DX
4171:                 SUB     AX,DX
4172:            or:
4173:                 MOV     r,reg
4174:                 SAR     r,63
4175:                 XOR     reg,r
4176:                 SUB     reg,r
4177:          */
4178:         unsigned reg;
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '4129' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 4129
4179:         unsigned r;
4180: 
4181:         if (!I16 && sz == REGSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4182:         {   regm_t scratch = allregs & ~retregs;
4183:             reg = findreg(retregs);
4184:             cg = allocreg(&scratch,&r,TYint);
4185:             cg = cat(cg,getregs(retregs));
4186:             cg = genmovreg(cg,r,reg);                                   // MOV r,reg
4187:             cg = genc2(cg,0xC1,modregrmx(3,7,r),REGSIZE * 8 - 1);       // SAR r,31/63
4188:             code_orrex(cg, rex);
4189:         }
4190:         else
4191:         {
4192:             reg = AX;
4193:             r = DX;
4194:             cg = cat(cg,getregs(mDX));
4195:             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?
4196:                 cg = gen1(cg,0x98);                         // CWDE
4197:             cg = gen1(cg,0x99);                             // CWD
4198:             code_orrex(cg, rex);
4199:         }
4200:         gen2(cg,0x33 ^ byte,(rex << 16) | modregrm(3,reg,r));         // XOR reg,r
4201:         c = gen2(CNIL,0x2B ^ byte,(rex << 16) | modregrm(3,reg,r));   // SUB reg,r
4202:         if (!I16 && sz == SHORTSIZE && *pretregs & mPSW)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4203:             c->Iflags |= CFopsize | CFpsw;
4204:         if (*pretregs & mPSW)
4205:             c->Iflags |= CFpsw;
4206:         *pretregs &= ~mPSW;                     // flags already set
4207:   }
4208:   else if (sz == 2 * REGSIZE)
4209:   {     unsigned msreg,lsreg;
4210:         code *cnop;
4211: 
4212:         /*      tst     DX
4213:                 jns     L2
4214:                 neg     DX
4215:                 neg     AX
4216:                 sbb     DX,0
4217:             L2:
4218:          */
4219: 
4220:         cnop = gennop(CNIL);
4221:         msreg = findregmsw(retregs);
4222:         lsreg = findreglsw(retregs);
4223:         c = genorreg(CNIL,msreg,msreg);
4224:         c = genjmp(c,JNS,FLcode,(block *)cnop);
4225:         c = gen2(c,0xF7,modregrm(3,3,msreg));   // NEG msreg
4226:         gen2(c,0xF7,modregrm(3,3,lsreg));       // NEG lsreg+1
4227:         genc2(c,0x81,modregrm(3,3,msreg),0);    // SBB msreg,0
4228:         c = cat(c,cnop);
4229:   }
4230:   else
4231:         assert(0);
4232:   return cat4(c1,cg,c,fixresult(e,retregs,pretregs));
4233: }
4234: 
4235: /**************************
4236:  * Post increment and post decrement.
4237:  */
4238: 
4239: code *cdpost(elem *e,regm_t *pretregs)
4240: { code cs,*c1,*c2,*c3,*c5,*c6;
4241:   unsigned reg,op,byte;
4242:   tym_t tyml;
4243:   regm_t retregs,possregs,idxregs;
4244:   targ_int n;
4245:   elem *e2;
4246:   int sz;
4247:   int stackpushsave;
4248: 
4249:   //printf("cdpost(pretregs = %s)\n", regm_str(*pretregs));
4250:   retregs = *pretregs;
4251:   op = e->Eoper;                                /* OPxxxx               */
4252:   if (retregs == 0)                             /* if nothing to return */
4253:         return cdaddass(e,pretregs);
4254:   c5 = CNIL;
4255:   tyml = tybasic(e->E1->Ety);
4256:   sz = tysize[tyml];
4257:   e2 = e->E2;
4258:   unsigned rex = (I64 && sz == 8) ? REX_W : 0;
4259: 
4260:   if (tyfloating(tyml))
4261:   {
4262: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
4263:         return post87(e,pretregs);
4264: #else
4265:         if (config.inline8087)
4266:                 return post87(e,pretregs);
4267:         assert(sz <= 8);
4268:         c1 = getlvalue(&cs,e->E1,DOUBLEREGS);
4269:         freenode(e->E1);
4270:         idxregs = idxregm(&cs);         // mask of index regs used
4271:         cs.Iop = 0x8B;                  /* MOV DOUBLEREGS,EA            */
4272:         c2 = fltregs(&cs,tyml);
4273:         stackchanged = 1;
4274:         stackpushsave = stackpush;
4275:         if (sz == 8)
4276:         {
4277:             if (I32)
4278:             {
4279:                 gen1(c2,0x50 + DX);             /* PUSH DOUBLEREGS      */
4280:                 gen1(c2,0x50 + AX);
4281:                 stackpush += DOUBLESIZE;
4282:                 retregs = DOUBLEREGS2_32;
4283:             }
4284:             else
4285:             {
4286:                 gen1(c2,0x50 + AX);
4287:                 gen1(c2,0x50 + BX);
4288:                 gen1(c2,0x50 + CX);
4289:                 gen1(c2,0x50 + DX);             /* PUSH DOUBLEREGS      */
4290:                 stackpush += DOUBLESIZE + DOUBLESIZE;
4291: 
4292:                 gen1(c2,0x50 + AX);
4293:                 gen1(c2,0x50 + BX);
4294:                 gen1(c2,0x50 + CX);
4295:                 gen1(c2,0x50 + DX);             /* PUSH DOUBLEREGS      */
4296:                 retregs = DOUBLEREGS_16;
4297:             }
4298:         }
4299:         else
4300:         {
4301:             stackpush += FLOATSIZE;     /* so we know something is on   */
4302:             if (!I32)
4303:                 gen1(c2,0x50 + DX);
4304:             gen1(c2,0x50 + AX);
4305:             retregs = FLOATREGS2;
4306:         }
4307:         c2 = genadjesp(c2,stackpush - stackpushsave);
4308: 
4309:         cgstate.stackclean++;
4310:         c3 = scodelem(e2,&retregs,idxregs,FALSE);
4311:         cgstate.stackclean--;
4312: 
4313:         code *c4;
4314:         if (tyml == TYdouble || tyml == TYdouble_alias)
4315:         {
4316:             retregs = DOUBLEREGS;
4317:             c4 = callclib(e,(op == OPpostinc) ? CLIBdadd : CLIBdsub,
4318:                     &retregs,idxregs);
4319:         }
4320:         else /* tyml == TYfloat */
4321:         {
4322:             retregs = FLOATREGS;
4323:             c4 = callclib(e,(op == OPpostinc) ? CLIBfadd : CLIBfsub,
4324:                     &retregs,idxregs);
4325:         }
4326:         cs.Iop = 0x89;                  /* MOV EA,DOUBLEREGS            */
4327:         c5 = fltregs(&cs,tyml);
4328:         stackpushsave = stackpush;
4329:         if (tyml == TYdouble || tyml == TYdouble_alias)
4330:         {   if (*pretregs == mSTACK)
4331:                 retregs = mSTACK;       /* leave result on stack        */
4332:             else
4333:             {
4334:                 if (I32)
4335:                 {   gen1(c5,0x58 + AX);
4336:                     gen1(c5,0x58 + DX);
4337:                 }
4338:                 else
4339:                 {   gen1(c5,0x58 + DX);
4340:                     gen1(c5,0x58 + CX);
4341:                     gen1(c5,0x58 + BX);
4342:                     gen1(c5,0x58 + AX);
4343:                 }
4344:                 stackpush -= DOUBLESIZE;
4345:                 retregs = DOUBLEREGS;
4346:             }
4347:         }
4348:         else
4349:         {   gen1(c5,0x58 + AX);
4350:             if (!I32)
4351:                 gen1(c5,0x58 + DX);
4352:             stackpush -= FLOATSIZE;
4353:             retregs = FLOATREGS;
4354:         }
4355:         c5 = genadjesp(c5,stackpush - stackpushsave);
4356:         c6 = fixresult(e,retregs,pretregs);
4357:         return cat6(c1,c2,c3,c4,c5,c6);
4358: #endif
4359:   }
4360: 
4361:   assert(e2->Eoper == OPconst);
4362:   byte = (sz == 1);
4363:   possregs = byte ? BYTEREGS : allregs;
4364:   c1 = getlvalue(&cs,e->E1,0);
4365:   freenode(e->E1);
4366:   idxregs = idxregm(&cs);       // mask of index regs used
4367:   if (sz <= REGSIZE && *pretregs == mPSW && (cs.Irm & 0xC0) == 0xC0 &&
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4368:       (!I16 || (idxregs & (mBX | mSI | mDI | mBP))))
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
4369:   {     // Generate:
4370:         //      TEST    reg,reg
4371:         //      LEA     reg,n[reg]      // don't affect flags
4372:         int rm;
4373: 
4374:         reg = cs.Irm & 7;
4375:         if (cs.Irex & REX_B)
4376:             reg |= 8;
4377:         cs.Iop = 0x85 ^ byte;
4378:         code_newreg(&cs, reg);
4379:         cs.Iflags |= CFpsw;
4380:         c2 = gen(NULL,&cs);             // TEST reg,reg
4381: 
4382:         // If lvalue is a register variable, we must mark it as modified
4383:         c3 = modEA(&cs);
4384: 
4385:         n = e2->EV.Vint;
4386:         if (op == OPpostdec)
4387:             n = -n;
4388:         rm = reg;
4389:         if (I16)
4390:             rm = regtorm[reg];
4391:         code *c4 = genc1(NULL,0x8D,(rex << 16) | buildModregrm(2,reg,rm),FLconst,n); // LEA reg,n[reg]
4392:         return cat4(c1,c2,c3,c4);
4393:   }
4394:   else if (sz <= REGSIZE || tyfv(tyml))
4395:   {     code cs2;
4396: 
4397:         cs.Iop = 0x8B ^ byte;
4398:         retregs = possregs & ~idxregs & *pretregs;
4399:         if (!tyfv(tyml))
4400:         {       if (retregs == 0)
4401:                         retregs = possregs & ~idxregs;
4402:         }
4403:         else /* tyfv(tyml) */
4404:         {       if ((retregs &= mLSW) == 0)
4405:                         retregs = mLSW & ~idxregs;
4406:                 /* Can't use LES if the EA uses ES as a seg override    */
4407:                 if (*pretregs & mES && (cs.Iflags & CFSEG) != CFes)
4408:                 {   cs.Iop = 0xC4;                      /* LES          */
4409:                     c1 = cat(c1,getregs(mES));          /* allocate ES  */
4410:                 }
4411:         }
4412:         c2 = allocreg(&retregs,®,TYint);
4413:         code_newreg(&cs, reg);
4414:         c3 = gen(CNIL,&cs);                     /* MOV reg,EA   */
4415:         cs2 = cs;
4416: 
4417:         /* If lvalue is a register variable, we must mark it as modified */
4418:         c3 = cat(c3,modEA(&cs));
4419: 
4420:         cs.Iop = 0x81 ^ byte;
4421:         cs.Irm &= ~modregrm(0,7,0);             /* reg field = 0        */
4422:         cs.Irex &= ~REX_R;
4423:         if (op == OPpostdec)
4424:                 cs.Irm |= modregrm(0,5,0);      /* SUB                  */
4425:         cs.IFL2 = FLconst;
4426:         n = e2->EV.Vint;
4427:         cs.IEV2.Vint = n;
4428:         if (n == 1)                     /* can use INC or DEC           */
4429:         {       cs.Iop |= 0xFE;         /* xFE is dec byte, xFF is word */
4430:                 if (op == OPpostdec)
4431:                         NEWREG(cs.Irm,1);       // DEC EA
4432:                 else
4433:                         NEWREG(cs.Irm,0);       // INC EA
4434:         }
4435:         else if (n == -1)               // can use INC or DEC
4436:         {       cs.Iop |= 0xFE;         // xFE is dec byte, xFF is word
4437:                 if (op == OPpostinc)
4438:                         NEWREG(cs.Irm,1);       // DEC EA
4439:                 else
4440:                         NEWREG(cs.Irm,0);       // INC EA
4441:         }
4442: 
4443:         // For scheduling purposes, we wish to replace:
4444:         //      MOV     reg,EA
4445:         //      OP      EA
4446:         // with:
4447:         //      MOV     reg,EA
4448:         //      OP      reg
4449:         //      MOV     EA,reg
4450:         //      ~OP     reg
4451:         if (sz <= REGSIZE && (cs.Irm & 0xC0) != 0xC0 &&
4452:             config.target_cpu >= TARGET_Pentium &&
4453:             config.flags4 & CFG4speed)
4454:         {
4455:             // Replace EA in cs with reg
4456:             cs.Irm = (cs.Irm & ~modregrm(3,0,7)) | modregrm(3,0,reg & 7);
4457:             if (reg & 8)
4458:             {   cs.Irex &= ~REX_R;
4459:                 cs.Irex |= REX_B;
4460:             }
4461:             else
4462:                 cs.Irex &= ~REX_B;
4463:             if (I64 && sz == 1 && reg >= 4)
4464:                 cs.Irex |= REX;
4465:             gen(c3,&cs);                        // ADD/SUB reg,const
4466: 
4467:             // Reverse MOV direction
4468:             cs2.Iop ^= 2;
4469:             gen(c3,&cs2);                       // MOV EA,reg
4470: 
4471:             // Toggle INC <-> DEC, ADD <-> SUB
4472:             cs.Irm ^= (n == 1 || n == -1) ? modregrm(0,1,0) : modregrm(0,5,0);
4473:             gen(c3,&cs);
4474: 
4475:             if (*pretregs & mPSW)
4476:             {   *pretregs &= ~mPSW;             // flags already set
4477:                 code_orflag(c3,CFpsw);
4478:             }
4479:         }
4480:         else
4481:             gen(c3,&cs);                        // ADD/SUB EA,const
4482: 
4483:         freenode(e2);
4484:         if (tyfv(tyml))
4485:         {       unsigned preg;
4486: 
4487:                 getlvalue_msw(&cs);
4488:                 if (*pretregs & mES)
4489:                 {       preg = ES;
4490:                         /* ES is already loaded if CFes is 0            */
4491:                         cs.Iop = ((cs.Iflags & CFSEG) == CFes) ? 0x8E : NOP;
4492:                         NEWREG(cs.Irm,0);       /* MOV ES,EA+2          */
4493:                 }
4494:                 else
4495:                 {
4496:                         retregs = *pretregs & mMSW;
4497:                         if (!retregs)
4498:                             retregs = mMSW;
4499:                         c3 = cat(c3,allocreg(&retregs,&preg,TYint));
4500:                         cs.Iop = 0x8B;
4501:                         if (I32)
4502:                             cs.Iflags |= CFopsize;
4503:                         NEWREG(cs.Irm,preg);    /* MOV preg,EA+2        */
4504:                 }
4505:                 c3 = cat(c3,getregs(mask[preg]));
4506:                 gen(c3,&cs);
4507:                 retregs = mask[reg] | mask[preg];
4508:         }
4509:         return cat4(c1,c2,c3,fixresult(e,retregs,pretregs));
4510:   }
4511:   else if (tyml == TYhptr)
4512:   {
4513:         unsigned long rvalue;
4514:         unsigned lreg;
4515:         unsigned rtmp;
4516:         regm_t mtmp;
4517: 
4518:         rvalue = e2->EV.Vlong;
4519:         freenode(e2);
4520: 
4521:         // If h--, convert to h++
4522:         if (e->Eoper == OPpostdec)
4523:             rvalue = -rvalue;
warning C4146: unary minus operator applied to unsigned type, result still unsigned
4524: 
4525:         retregs = mLSW & ~idxregs & *pretregs;
4526:         if (!retregs)
4527:             retregs = mLSW & ~idxregs;
4528:         c1 = cat(c1,allocreg(&retregs,&lreg,TYint));
4529: 
4530:         // Can't use LES if the EA uses ES as a seg override
4531:         if (*pretregs & mES && (cs.Iflags & CFSEG) != CFes)
4532:         {   cs.Iop = 0xC4;
4533:             retregs |= mES;
4534:             c1 = cat(c1,getregs(mES|mCX));      // allocate ES
4535:             cs.Irm |= modregrm(0,lreg,0);
4536:             c2 = gen(CNIL,&cs);                 // LES lreg,EA
4537:         }
4538:         else
4539:         {   cs.Iop = 0x8B;
4540:             retregs |= mDX;
4541:             c1 = cat(c1,getregs(mDX|mCX));
4542:             cs.Irm |= modregrm(0,lreg,0);
4543:             c2 = gen(CNIL,&cs);                 // MOV lreg,EA
4544:             NEWREG(cs.Irm,DX);
4545:             getlvalue_msw(&cs);
4546:             gen(c2,&cs);                        // MOV DX,EA+2
4547:             getlvalue_lsw(&cs);
4548:         }
4549: 
4550:         // Allocate temporary register, rtmp
4551:         mtmp = ALLREGS & ~mCX & ~idxregs & ~retregs;
4552:         c2 = cat(c2,allocreg(&mtmp,&rtmp,TYint));
4553: 
4554:         movregconst(c2,rtmp,rvalue >> 16,0);    // MOV rtmp,e2+2
4555:         c3 = getregs(mtmp);
4556:         cs.Iop = 0x81;
4557:         NEWREG(cs.Irm,0);
4558:         cs.IFL2 = FLconst;
4559:         cs.IEV2.Vint = rvalue;
4560:         c3 = gen(c3,&cs);                       // ADD EA,e2
4561:         code_orflag(c3,CFpsw);
4562:         genc2(c3,0x81,modregrm(3,2,rtmp),0);    // ADC rtmp,0
4563:         genshift(c3);                           // MOV CX,offset __AHSHIFT
4564:         gen2(c3,0xD3,modregrm(3,4,rtmp));       // SHL rtmp,CL
4565:         cs.Iop = 0x01;
4566:         NEWREG(cs.Irm,rtmp);                    // ADD EA+2,rtmp
4567:         getlvalue_msw(&cs);
4568:         gen(c3,&cs);
4569:         return cat4(c1,c2,c3,fixresult(e,retregs,pretregs));
4570:   }
4571:   else if (sz == 2 * REGSIZE)
4572:   {     unsigned sreg;
4573: 
4574:         retregs = allregs & ~idxregs & *pretregs;
4575:         if ((retregs & mLSW) == 0)
4576:                 retregs |= mLSW & ~idxregs;
4577:         if ((retregs & mMSW) == 0)
4578:                 retregs |= ALLREGS & mMSW;
4579:         assert(retregs & mMSW && retregs & mLSW);
4580:         c2 = allocreg(&retregs,®,tyml);
4581:         sreg = findreglsw(retregs);
4582:         cs.Iop = 0x8B;
4583:         cs.Irm |= modregrm(0,sreg,0);
4584:         c3 = gen(CNIL,&cs);             /* MOV sreg,EA                  */
4585:         NEWREG(cs.Irm,reg);
4586:         getlvalue_msw(&cs);
4587:         gen(c3,&cs);                    /* MOV reg,EA+2                 */
4588:         cs.Iop = 0x81;
4589:         cs.Irm &= ~modregrm(0,7,0);     /* reg field = 0 for ADD        */
4590:         if (op == OPpostdec)
4591:             cs.Irm |= modregrm(0,5,0);  /* SUB                          */
4592:         getlvalue_lsw(&cs);
4593:         cs.IFL2 = FLconst;
4594:         cs.IEV2.Vlong = e2->EV.Vlong;
4595:         gen(c3,&cs);                    /* ADD/SUB EA,const             */
4596:         code_orflag(c3,CFpsw);
4597:         getlvalue_msw(&cs);
4598:         cs.IEV2.Vlong = 0;
4599:         if (op == OPpostinc)
4600:             cs.Irm ^= modregrm(0,2,0);  /* ADC                          */
4601:         else
4602:             cs.Irm ^= modregrm(0,6,0);  /* SBB                          */
4603:         cs.IEV2.Vlong = e2->EV.Vullong >> (REGSIZE * 8);
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_long', possible loss of data
4604:         gen(c3,&cs);                    /* ADC/SBB EA,0                 */
4605:         freenode(e2);
4606:         return cat4(c1,c2,c3,fixresult(e,retregs,pretregs));
4607:   }
4608:   else
4609:   {     assert(0);
4610:         /* NOTREACHED */
4611:         return 0;
4612:   }
4613: }
4614: 
4615: 
4616: code *cderr(elem *e,regm_t *pretregs)
4617: {
4618: #if DEBUG
4619:         elem_print(e);
4620: #endif
4621: //printf("op = %d, %d\n", e->Eoper, OPstring);
4622: //printf("string = %p, len = %d\n", e->EV.ss.Vstring, e->EV.ss.Vstrlen);
4623: //printf("string = '%.*s'\n", e->EV.ss.Vstrlen, e->EV.ss.Vstring);
4624:         assert(0);
4625:         return 0;
4626: }
4627: 
4628: code *cdinfo(elem *e,regm_t *pretregs)
4629: {
4630:     code cs;
4631:     code *c;
4632:     regm_t retregs;
4633: 
4634:     switch (e->E1->Eoper)
4635:     {
4636: #if MARS
4637:         case OPdctor:
4638:             c = codelem(e->E2,pretregs,FALSE);
4639:             retregs = 0;
4640:             c = cat(c,codelem(e->E1,&retregs,FALSE));
4641:             break;
4642: #endif
4643: #if SCPP
4644:         case OPdtor:
4645:             c = cdcomma(e,pretregs);
4646:             break;
4647:         case OPctor:
4648:             c = codelem(e->E2,pretregs,FALSE);
4649:             retregs = 0;
4650:             c = cat(c,codelem(e->E1,&retregs,FALSE));
4651:             break;
4652:         case OPmark:
4653:             if (0 && config.exe == EX_NT)
4654:             {   unsigned idx;
4655: 
4656:                 idx = except_index_get();
4657:                 except_mark();
4658:                 c = codelem(e->E2,pretregs,FALSE);
4659:                 if (config.exe == EX_NT && idx != except_index_get())
4660:                 {   usednteh |= NTEHcleanup;
4661:                     c = cat(c,nteh_gensindex(idx - 1));
4662:                 }
4663:                 except_release();
4664:                 assert(idx == except_index_get());
4665:             }
4666:             else
4667:             {
4668: #if 0
4669:                 usednteh |= EHcleanup;
4670:                 if (config.exe == EX_NT)
4671:                     usednteh |= NTEHcleanup;
4672: #endif
4673:                 cs.Iop = ESCAPE | ESCmark;
4674:                 cs.Iflags = 0;
4675:                 cs.Irex = 0;
4676:                 c = gen(CNIL,&cs);
4677:                 c = cat(c,codelem(e->E2,pretregs,FALSE));
4678:                 cs.Iop = ESCAPE | ESCrelease;
4679:                 gen(c,&cs);
4680:             }
4681:             freenode(e->E1);
4682:             break;
4683: #endif
4684:         default:
4685:             assert(0);
4686:     }
4687:     return c;
4688: }
4689: 
4690: /*******************************************
4691:  * D constructor.
4692:  */
4693: 
4694: code *cddctor(elem *e,regm_t *pretregs)
4695: {
4696: #if MARS
4697:     /* Generate:
4698:         ESCAPE | ESCdctor
4699:         MOV     sindex[BP],index
4700:      */
4701:     usednteh |= EHcleanup;
4702:     if (config.exe == EX_NT)
4703:         usednteh |= NTEHcleanup;
4704:     assert(*pretregs == 0);
4705:     code cs;
4706:     cs.Iop = ESCAPE | ESCdctor;
4707:     cs.Iflags = 0;
4708:     cs.Irex = 0;
4709:     cs.IFL1 = FLctor;
4710:     cs.IEV1.Vtor = e;
4711:     code *c = gen(CNIL,&cs);
4712:     c = cat(c, nteh_gensindex(0));      // the actual index will be patched in later
4713:                                         // by except_fillInEHTable()
4714:     return c;
4715: #else
4716:     return NULL;
4717: #endif
4718: }
4719: 
4720: /*******************************************
4721:  * D destructor.
4722:  */
4723: 
4724: code *cdddtor(elem *e,regm_t *pretregs)
4725: {
4726: #if MARS
4727:     /* Generate:
4728:         ESCAPE | ESCddtor
4729:         MOV     sindex[BP],index
4730:         CALL    dtor
4731:         JMP     L1
4732:     Ldtor:
4733:         ... e->E1 ...
4734:         RET
4735:     L1: NOP
4736:     */
4737:     usednteh |= EHcleanup;
4738:     if (config.exe == EX_NT)
4739:         usednteh |= NTEHcleanup;
4740: 
4741:     code cs;
4742:     cs.Iop = ESCAPE | ESCddtor;
4743:     cs.Iflags = 0;
4744:     cs.Irex = 0;
4745:     cs.IFL1 = FLdtor;
4746:     cs.IEV1.Vtor = e;
4747:     code *cd = gen(CNIL,&cs);
4748: 
4749:     cd = cat(cd, nteh_gensindex(0));    // the actual index will be patched in later
4750:                                         // by except_fillInEHTable()
4751: 
4752:     assert(*pretregs == 0);
4753:     code *c = codelem(e->E1,pretregs,FALSE);
4754:     gen1(c,0xC3);               // RET
4755: 
4756: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
4757:     if (config.flags3 & CFG3pic)
4758:     {
4759:         int nalign = 0;
4760:         if (STACKALIGN == 16)
4761:         {   nalign = STACKALIGN - REGSIZE;
4762:             cd = genc2(cd,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign
4763:             if (I64)
4764:                 code_orrex(cd, REX_W);
4765:         }
4766:         calledafunc = 1;
4767:         genjmp(cd,0xE8,FLcode,(block *)c);                  // CALL Ldtor
4768:         if (nalign)
4769:         {   cd = genc2(cd,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign
4770:             if (I64)
4771:                 code_orrex(cd, REX_W);
4772:         }
4773:     }
4774:     else
4775: #endif
4776:         genjmp(cd,0xE8,FLcode,(block *)c);                  // CALL Ldtor
4777: 
4778:     code *cnop = gennop(CNIL);
4779: 
4780:     genjmp(cd,JMP,FLcode,(block *)cnop);
4781: 
4782:     return cat4(cd, c, cnop, NULL);
4783: #else
4784:     return NULL;
4785: #endif
4786: }
4787: 
4788: 
4789: /*******************************************
4790:  * C++ constructor.
4791:  */
4792: 
4793: code *cdctor(elem *e,regm_t *pretregs)
4794: {
4795: #if SCPP
4796:     code cs;
4797:     code *c;
4798: 
4799: #if 0
4800:     if (config.exe == EX_NT)
4801:     {   usednteh |= NTEHcleanup;
4802:         except_push(NULL,e,NULL);
4803:         return nteh_gensindex(except_index_get() - 1);
4804:     }
4805: #else
4806:     usednteh |= EHcleanup;
4807:     if (config.exe == EX_NT)
4808:         usednteh |= NTEHcleanup;
4809: #endif
4810:     assert(*pretregs == 0);
4811:     cs.Iop = ESCAPE | ESCctor;
4812:     cs.Iflags = 0;
4813:     cs.Irex = 0;
4814:     cs.IFL1 = FLctor;
4815:     cs.IEV1.Vtor = e;
4816:     c = gen(CNIL,&cs);
4817:     //except_push(c,e,NULL);
4818:     return c;
4819: #else
4820:     return NULL;
4821: #endif
4822: }
4823: 
4824: code *cddtor(elem *e,regm_t *pretregs)
4825: {
4826: #if SCPP
4827:     code cs;
4828:     code *c;
4829: 
4830: #if 0
4831:     if (config.exe == EX_NT)
4832:     {   usednteh |= NTEHcleanup;
4833:         except_pop(NULL,e,NULL);
4834:         return nteh_gensindex(except_index_get() - 1);
4835:     }
4836: #else
4837:     usednteh |= EHcleanup;
4838:     if (config.exe == EX_NT)
4839:         usednteh |= NTEHcleanup;
4840: #endif
4841:     assert(*pretregs == 0);
4842:     cs.Iop = ESCAPE | ESCdtor;
4843:     cs.Iflags = 0;
4844:     cs.Irex = 0;
4845:     cs.IFL1 = FLdtor;
4846:     cs.IEV1.Vtor = e;
4847:     c = gen(CNIL,&cs);
4848:     //except_pop(c,e,NULL);
4849:     return c;
4850: #else
4851:     return NULL;
4852: #endif
4853: }
4854: 
4855: code *cdmark(elem *e,regm_t *pretregs)
4856: {
4857:     return NULL;
4858: }
4859: 
4860: #if !NTEXCEPTIONS
4861: code *cdsetjmp(elem *e,regm_t *pretregs)
4862: {
4863:     assert(0);
4864:     return NULL;
4865: }
4866: #endif
4867: 
4868: /*****************************************
4869:  */
4870: 
4871: code *cdvoid(elem *e,regm_t *pretregs)
4872: {
4873:     assert(*pretregs == 0);
4874:     return codelem(e->E1,pretregs,FALSE);
4875: }
4876: 
4877: /*****************************************
4878:  */
4879: 
4880: code *cdhalt(elem *e,regm_t *pretregs)
4881: {
4882:     assert(*pretregs == 0);
4883:     return gen1(NULL, 0xF4);            // HLT
4884: }
4885: 
4886: /****************************************
4887:  * Check to see if pointer is NULL.
4888:  */
4889: 
4890: code *cdnullcheck(elem *e,regm_t *pretregs)
4891: {   regm_t retregs;
4892:     regm_t scratch;
4893:     unsigned reg;
4894:     code *c;
4895:     code *cs;
4896: 
4897:     assert(!I16);
4898:     retregs = *pretregs;
4899:     if ((retregs & allregs) == 0)
4900:         retregs |= allregs;
4901:     c = codelem(e->E1,&retregs,FALSE);
4902:     scratch = allregs & ~retregs;
4903:     cs = allocreg(&scratch,®,TYint);
4904:     unsigned rex = I64 ? REX_W : 0;
4905:     cs = genc1(cs,0x8B,(rex << 16) | buildModregrm(2,reg,findreg(retregs)),FLconst,0); // MOV reg,0[e]
4906:     return cat3(c,cs,fixresult(e,retregs,pretregs));
4907: }
4908: 
4909: #endif // !SPP
4910: