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,&reg)) 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,&reg)) 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,&reg,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,&regm,&reg1)) 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,&reg,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,&regm,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,&reg,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,&regm,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,&regm,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,&reg,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,&reg,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,&reg)) 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,&reg,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,&reg)) 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,&reg,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,&reg,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(&regconsave); 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,&reg,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(&regconsave); 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(&regconold); 1796: andregcon(&regconsave); 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(&regconsave); 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(&regconsave); 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,&reg,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(&regconsave); 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,&reg,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,&regm,&reg) && !(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,&reg,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,&reg,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,&reg,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,&reg,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,&reg,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,&reg,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,&reg,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,&reg,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,&reg,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,&reg,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: