1: // Copyright (C) 1985-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        <time.h>
  17: 
  18: #include        "cc.h"
  19: #include        "el.h"
  20: #include        "oper.h"
  21: #include        "code.h"
  22: #include        "type.h"
  23: #include        "global.h"
  24: 
  25: static char __file__[] = __FILE__;      /* for tassert.h                */
  26: #include        "tassert.h"
  27: 
  28:                         /*   AX,CX,DX,BX                */
  29: const unsigned dblreg[4] = { BX,DX,(unsigned)-1,CX };
  30: 
  31: 
  32: /*******************************
  33:  * Return number of times symbol s appears in tree e.
  34:  */
  35: 
  36: STATIC int intree(symbol *s,elem *e)
  37: {
  38:         if (EOP(e))
  39:             return intree(s,e->E1) + (EBIN(e) ? intree(s,e->E2) : 0);
  40:         return e->Eoper == OPvar && e->EV.sp.Vsym == s;
  41: }
  42: 
  43: /***********************************
  44:  * Determine if expression e can be evaluated directly into register
  45:  * variable s.
  46:  * Have to be careful about things like x=x+x+x, and x=a+x.
  47:  * Returns:
  48:  *      !=0     can
  49:  *      0       can't
  50:  */
  51: 
  52: STATIC int doinreg(symbol *s, elem *e)
  53: {   int in = 0;
  54:     int op;
  55: 
  56:  L1:
  57:     op = e->Eoper;
  58:     if (op == OPind ||
  59:         OTcall(op)  ||
  60:         OTleaf(op) ||
  61:         (in = intree(s,e)) == 0 ||
  62:         (OTunary(op) && !EOP(e->E1))
  63:        )
  64:         return 1;
  65:     if (in == 1)
  66:     {
  67:         switch (op)
  68:         {
  69:             case OPadd:
  70:             case OPmin:
  71:             case OPand:
  72:             case OPor:
  73:             case OPxor:
  74:             case OPshl:
  75:             case OPmul:
  76:                 if (!intree(s,e->E2))
  77:                 {
  78:                     e = e->E1;
  79:                     goto L1;
  80:                 }
  81:         }
  82:     }
  83:     return 0;
  84: }
  85: 
  86: /****************************
  87:  * Return code for saving common subexpressions if EA
  88:  * turns out to be a register.
  89:  * This is called just before modifying an EA.
  90:  */
  91: 
  92: code *modEA(code *c)
  93: {
  94:     if ((c->Irm & 0xC0) == 0xC0)        // addressing mode refers to a register
  95:     {
  96:         unsigned reg = c->Irm & 7;
  97:         if (c->Irex & REX_B)
  98:         {   reg |= 8;
  99:             assert(I64);
 100:         }
 101:         return getregs(mask[reg]);
 102:     }
 103:     return CNIL;
 104: }
 105: 
 106: #if TARGET_WINDOS
 107: // This code is for CPUs that do not support the 8087
 108: 
 109: /****************************
 110:  * Gen code for op= for doubles.
 111:  */
 112: 
 113: STATIC code * opassdbl(elem *e,regm_t *pretregs,unsigned op)
 114: { code *c1,*c2,*c3,*c4,*c5,*c6,cs;
warning C4101: 'c2' : unreferenced local variable
115: unsigned clib; 116: regm_t retregs2,retregs,idxregs; 117: tym_t tym; 118: elem *e1; 119: 120: static unsigned clibtab[OPdivass - OPpostinc + 1] = 121: /* OPpostinc,OPpostdec,OPeq,OPaddass,OPminass,OPmulass,OPdivass */ 122: { CLIBdadd, CLIBdsub, (unsigned)-1, CLIBdadd,CLIBdsub,CLIBdmul,CLIBddiv }; 123: 124: if (config.inline8087) 125: return opass87(e,pretregs); 126: clib = clibtab[op - OPpostinc]; 127: e1 = e->E1; 128: tym = tybasic(e1->Ety); 129: c1 = getlvalue(&cs,e1,DOUBLEREGS | mBX | mCX); 130: 131: if (tym == TYfloat) 132: { 133: clib += CLIBfadd - CLIBdadd; /* convert to float operation */ 134: 135: /* Load EA into FLOATREGS */ 136: c1 = cat(c1,getregs(FLOATREGS)); 137: cs.Iop = 0x8B; 138: cs.Irm |= modregrm(0,AX,0); 139: c1 = gen(c1,&cs); 140: 141: if (!I32) 142: { 143: cs.Irm |= modregrm(0,DX,0); 144: getlvalue_msw(&cs); 145: c1 = gen(c1,&cs); 146: getlvalue_lsw(&cs); 147: 148: } 149: retregs2 = FLOATREGS2; 150: idxregs = FLOATREGS | idxregm(&cs); 151: retregs = FLOATREGS; 152: } 153: else 154: { 155: if (I32) 156: { 157: /* Load EA into DOUBLEREGS */ 158: c1 = cat(c1,getregs(DOUBLEREGS_32)); 159: cs.Iop = 0x8B; 160: cs.Irm |= modregrm(0,AX,0); 161: c1 = gen(c1,&cs); 162: cs.Irm |= modregrm(0,DX,0); 163: getlvalue_msw(&cs); 164: c1 = gen(c1,&cs); 165: getlvalue_lsw(&cs); 166: 167: retregs2 = DOUBLEREGS2_32; 168: idxregs = DOUBLEREGS_32 | idxregm(&cs); 169: } 170: else 171: { 172: /* Push EA onto stack */ 173: cs.Iop = 0xFF; 174: cs.Irm |= modregrm(0,6,0); 175: cs.IEVoffset1 += DOUBLESIZE - REGSIZE; 176: c1 = gen(c1,&cs); 177: getlvalue_lsw(&cs); 178: gen(c1,&cs); 179: getlvalue_lsw(&cs); 180: gen(c1,&cs); 181: getlvalue_lsw(&cs); 182: gen(c1,&cs); 183: stackpush += DOUBLESIZE; 184: 185: retregs2 = DOUBLEREGS_16; 186: idxregs = idxregm(&cs); 187: } 188: retregs = DOUBLEREGS; 189: } 190: 191: if ((cs.Iflags & CFSEG) == CFes) 192: idxregs |= mES; 193: cgstate.stackclean++; 194: c3 = scodelem(e->E2,&retregs2,idxregs,FALSE); 195: cgstate.stackclean--; 196: c4 = callclib(e,clib,&retregs,0); 197: if (e1->Ecount) 198: cssave(e1,retregs,EOP(e1)); /* if lvalue is a CSE */ 199: freenode(e1); 200: cs.Iop = 0x89; /* MOV EA,DOUBLEREGS */ 201: c5 = fltregs(&cs,tym); 202: c6 = fixresult(e,retregs,pretregs); 203: return cat6(c1,CNIL,c3,c4,c5,c6); 204: } 205: 206: /**************************** 207: * Gen code for OPnegass for doubles. 208: */ 209: 210: STATIC code * opnegassdbl(elem *e,regm_t *pretregs) 211: { code *c1,*c2,*c3,*c,*cl,*cr,cs;
warning C4101: 'c2' : unreferenced local variable
212: unsigned clib;
warning C4101: 'clib' : unreferenced local variable
213: regm_t retregs2,retregs,idxregs;
warning C4101: 'idxregs' : unreferenced local variable
warning C4101: 'retregs2' : unreferenced local variable
214: tym_t tym; 215: elem *e1; 216: int sz; 217: 218: if (config.inline8087) 219: return cdnegass87(e,pretregs); 220: e1 = e->E1; 221: tym = tybasic(e1->Ety); 222: sz = tysize[tym]; 223: 224: cl = getlvalue(&cs,e1,*pretregs ? DOUBLEREGS | mBX | mCX : 0); 225: cr = modEA(&cs); 226: cs.Irm |= modregrm(0,6,0); 227: cs.Iop = 0x80; 228: cs.IEVoffset1 += sz - 1; 229: cs.IFL2 = FLconst; 230: cs.IEV2.Vuns = 0x80; 231: c = gen(NULL,&cs); // XOR 7[EA],0x80 232: if (tycomplex(tym)) 233: { 234: cs.IEVoffset1 -= sz / 2; 235: gen(c,&cs); // XOR 7[EA],0x80 236: } 237: c = cat3(cl,cr,c); 238: 239: if (*pretregs || e1->Ecount) 240: { 241: cs.IEVoffset1 -= sz - 1; 242: 243: if (tym == TYfloat) 244: { 245: // Load EA into FLOATREGS 246: c1 = getregs(FLOATREGS); 247: cs.Iop = 0x8B; 248: NEWREG(cs.Irm, AX); 249: c1 = gen(c1,&cs); 250: 251: if (!I32) 252: { 253: NEWREG(cs.Irm, DX); 254: getlvalue_msw(&cs); 255: c1 = gen(c1,&cs); 256: getlvalue_lsw(&cs); 257: 258: } 259: retregs = FLOATREGS; 260: } 261: else 262: { 263: if (I32) 264: { 265: // Load EA into DOUBLEREGS 266: c1 = getregs(DOUBLEREGS_32); 267: cs.Iop = 0x8B; 268: cs.Irm &= ~modregrm(0,7,0); 269: cs.Irm |= modregrm(0,AX,0); 270: c1 = gen(c1,&cs); 271: cs.Irm |= modregrm(0,DX,0); 272: getlvalue_msw(&cs); 273: c1 = gen(c1,&cs); 274: getlvalue_lsw(&cs); 275: } 276: else 277: { 278: #if 1 279: cs.Iop = 0x8B; 280: c1 = fltregs(&cs,TYdouble); // MOV DOUBLEREGS, EA 281: #else 282: // Push EA onto stack 283: cs.Iop = 0xFF; 284: cs.Irm |= modregrm(0,6,0); 285: cs.IEVoffset1 += DOUBLESIZE - REGSIZE; 286: c1 = gen(NULL,&cs); 287: cs.IEVoffset1 -= REGSIZE; 288: gen(c1,&cs); 289: cs.IEVoffset1 -= REGSIZE; 290: gen(c1,&cs); 291: cs.IEVoffset1 -= REGSIZE; 292: gen(c1,&cs); 293: stackpush += DOUBLESIZE; 294: #endif 295: } 296: retregs = DOUBLEREGS; 297: } 298: if (e1->Ecount) 299: cssave(e1,retregs,EOP(e1)); /* if lvalue is a CSE */ 300: } 301: else 302: { retregs = 0; 303: assert(e1->Ecount == 0); 304: c1 = NULL; 305: } 306: 307: freenode(e1); 308: c3 = fixresult(e,retregs,pretregs); 309: return cat3(c,c1,c3); 310: } 311: #endif 312: 313: 314: 315: /************************ 316: * Generate code for an assignment. 317: */ 318: 319: code *cdeq(elem *e,regm_t *pretregs) 320: { 321: tym_t tymll; 322: unsigned reg; 323: int i; 324: code *cl,*cr,*c,cs; 325: elem *e11; 326: bool regvar; /* TRUE means evaluate into register variable */ 327: regm_t varregm; 328: unsigned varreg; 329: targ_int postinc; 330: 331: //printf("cdeq(e = %p, *pretregs = %s)\n", e, regm_str(*pretregs)); 332: elem *e1 = e->E1; 333: elem *e2 = e->E2; 334: int e2oper = e2->Eoper; 335: tym_t tyml = tybasic(e1->Ety); /* type of lvalue */ 336: regm_t retregs = *pretregs; 337: 338: if (tyfloating(tyml) && config.inline8087) 339: { 340: if (tycomplex(tyml)) 341: return complex_eq87(e, pretregs); 342: 343: if (!(retregs == 0 && 344: (e2oper == OPconst || e2oper == OPvar || e2oper == OPind)) 345: ) 346: return eq87(e,pretregs); 347: if (config.target_cpu >= TARGET_PentiumPro && 348: (e2oper == OPvar || e2oper == OPind) 349: ) 350: return eq87(e,pretregs); 351: if (tyml == TYldouble || tyml == TYildouble) 352: return eq87(e,pretregs); 353: } 354: 355: unsigned sz = tysize[tyml]; // # of bytes to transfer 356: assert((int)sz > 0); 357: 358: if (retregs == 0) /* if no return value */ 359: { int fl; 360: 361: if ((e2oper == OPconst || /* if rvalue is a constant */ 362: e2oper == OPrelconst && 363: !(I64 && config.flags3 & CFG3pic) && 364: ((fl = el_fl(e2)) == FLdata || 365: fl==FLudata || fl == FLextern) && 366: !(e2->EV.sp.Vsym->ty() & mTYcs) 367: ) && 368: !evalinregister(e2) && 369: !e1->Ecount) /* and no CSE headaches */ 370: { 371: // Look for special case of (*p++ = ...), where p is a register variable 372: if (e1->Eoper == OPind && 373: ((e11 = e1->E1)->Eoper == OPpostinc || e11->Eoper == OPpostdec) && 374: e11->E1->Eoper == OPvar && 375: e11->E1->EV.sp.Vsym->Sfl == FLreg &&
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
376: (!I16 || e11->E1->EV.sp.Vsym->Sregm & IDXREGS)
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
377: ) 378: { 379: postinc = e11->E2->EV.Vint; 380: if (e11->Eoper == OPpostdec) 381: postinc = -postinc; 382: cl = getlvalue(&cs,e11,RMstore); 383: freenode(e11->E2); 384: } 385: else 386: { postinc = 0; 387: cl = getlvalue(&cs,e1,RMstore); 388: 389: if (e2oper == OPconst && 390: config.flags4 & CFG4speed && 391: (config.target_cpu == TARGET_Pentium || 392: config.target_cpu == TARGET_PentiumMMX) && 393: (cs.Irm & 0xC0) == 0x80 394: ) 395: { 396: if (I64 && sz == 8 && e2->EV.Vpointer) 397: { 398: // MOV reg,imm64 399: // MOV EA,reg 400: regm_t rregm = allregs & ~idxregm(&cs); 401: 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 '322' of 'c:\projects\extern\d\dmd\src\backend\cod4.c': Lines: 322
402: cl = regwithvalue(cl,rregm,e2->EV.Vpointer,&reg,64); 403: cs.Iop = 0x89; 404: cs.Irm |= modregrm(0,reg & 7,0); 405: if (reg & 8) 406: cs.Irex |= REX_R; 407: c = gen(cl,&cs); 408: freenode(e2); 409: goto Lp; 410: } 411: if ((sz == REGSIZE || (I64 && sz == 4)) && e2->EV.Vint) 412: { 413: // MOV reg,imm 414: // MOV EA,reg 415: regm_t rregm = allregs & ~idxregm(&cs); 416: 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 '322' of 'c:\projects\extern\d\dmd\src\backend\cod4.c': Lines: 322
417: cl = regwithvalue(cl,rregm,e2->EV.Vint,&reg,0); 418: cs.Iop = 0x89; 419: cs.Irm |= modregrm(0,reg & 7,0); 420: if (reg & 8) 421: cs.Irex |= REX_R; 422: c = gen(cl,&cs); 423: freenode(e2); 424: goto Lp; 425: } 426: if (sz == 2 * REGSIZE && e2->EV.Vllong == 0) 427: { regm_t rregm; 428: 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 '322' of 'c:\projects\extern\d\dmd\src\backend\cod4.c': Lines: 322
429: 430: // MOV reg,imm 431: // MOV EA,reg 432: // MOV EA+2,reg 433: rregm = getscratch() & ~idxregm(&cs); 434: if (rregm) 435: { cl = regwithvalue(cl,rregm,e2->EV.Vint,&reg,0); 436: cs.Iop = 0x89; 437: cs.Irm |= modregrm(0,reg,0); 438: c = gen(cl,&cs); 439: getlvalue_msw(&cs); 440: c = gen(c,&cs); 441: freenode(e2); 442: goto Lp; 443: } 444: } 445: } 446: } 447: 448: /* If loading result into a register */ 449: if ((cs.Irm & 0xC0) == 0xC0) 450: { cl = cat(cl,modEA(&cs)); 451: if (sz == 2 * REGSIZE && cs.IFL1 == FLreg) 452: cl = cat(cl,getregs(cs.IEVsym1->Sregm)); 453: } 454: cs.Iop = (sz == 1) ? 0xC6 : 0xC7; 455: 456: if (e2oper == OPrelconst) 457: { 458: cs.IEVoffset2 = e2->EV.sp.Voffset; 459: cs.IFL2 = fl; 460: cs.IEVsym2 = e2->EV.sp.Vsym; 461: cs.Iflags |= CFoff; 462: cl = gen(cl,&cs); /* MOV EA,&variable */ 463: if (I64 && sz == 8) 464: code_orrex(cl, REX_W); 465: if (sz > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
466: { 467: cs.Iop = 0x8C; 468: getlvalue_msw(&cs); 469: cs.Irm |= modregrm(0,3,0); 470: cl = gen(cl,&cs); /* MOV EA+2,DS */ 471: } 472: } 473: else 474: { 475: assert(e2oper == OPconst); 476: cs.IFL2 = FLconst; 477: targ_size_t *p = (targ_size_t *) &(e2->EV); 478: cs.IEV2.Vsize_t = *p; 479: // Look for loading a register variable 480: if ((cs.Irm & 0xC0) == 0xC0) 481: { unsigned reg = cs.Irm & 7;
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '322' of 'c:\projects\extern\d\dmd\src\backend\cod4.c': Lines: 322
482: 483: if (cs.Irex & REX_B) 484: reg |= 8; 485: if (I64 && sz == 8) 486: cl = movregconst(cl,reg,*p,64); 487: else 488: cl = movregconst(cl,reg,*p,1 ^ (cs.Iop & 1)); 489: if (sz == 2 * REGSIZE) 490: { getlvalue_msw(&cs); 491: cl = movregconst(cl,cs.Irm & 7,p[1],0); 492: } 493: } 494: else if (I64 && sz == 8 && *p >= 0x80000000) 495: { // Use 64 bit MOV, as the 32 bit one gets sign extended 496: // MOV reg,imm64 497: // MOV EA,reg 498: regm_t rregm = allregs & ~idxregm(&cs); 499: 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 '322' of 'c:\projects\extern\d\dmd\src\backend\cod4.c': Lines: 322
500: cl = regwithvalue(cl,rregm,e2->EV.Vpointer,&reg,64); 501: cs.Iop = 0x89; 502: cs.Irm |= modregrm(0,reg & 7,0); 503: if (reg & 8) 504: cs.Irex |= REX_R; 505: c = gen(cl,&cs); 506: freenode(e2); 507: goto Lp; 508: } 509: else 510: { int regsize; 511: 512: i = sz; 513: do 514: { regsize = REGSIZE; 515: retregs = (sz == 1) ? BYTEREGS : allregs; 516: if (i >= 4 && I16 && I386) 517: { 518: regsize = 4; 519: cs.Iflags |= CFopsize; // use opsize to do 32 bit operation 520: } 521: else 522: { 523: if (reghasvalue(retregs,*p,&reg)) 524: { 525: cs.Iop = (cs.Iop & 1) | 0x88; 526: cs.Irm |= modregrm(0,reg & 7,0); // MOV EA,reg 527: if (reg & 8) 528: cs.Irex |= REX_R; 529: if (I64 && sz == 1 && reg >= 4) 530: cs.Irex |= REX; 531: } 532: if (!I16 && i == 2) // if 16 bit operand
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
533: cs.Iflags |= CFopsize; 534: if (I64 && sz == 8) 535: cs.Irex |= REX_W; 536: } 537: cl = gen(cl,&cs); /* MOV EA,const */ 538: 539: p = (targ_size_t *)((char *) p + regsize); 540: cs.Iop = (cs.Iop & 1) | 0xC6; 541: cs.Irm &= ~modregrm(0,7,0); 542: cs.Irex &= ~REX_R; 543: cs.IEVoffset1 += regsize; 544: cs.IEV2.Vint = *p; 545: i -= regsize; 546: } while (i > 0); 547: } 548: } 549: freenode(e2); 550: c = cl; 551: goto Lp; 552: } 553: retregs = allregs; /* pick a reg, any reg */ 554: if (sz == 2 * REGSIZE) 555: retregs &= ~mBP; // BP cannot be used for register pair 556: } 557: if (retregs == mPSW) 558: { retregs = allregs; 559: if (sz == 2 * REGSIZE) 560: retregs &= ~mBP; // BP cannot be used for register pair 561: } 562: cs.Iop = 0x89; 563: if (sz == 1) // must have byte regs 564: { cs.Iop = 0x88; 565: retregs &= BYTEREGS; 566: if (!retregs) 567: retregs = BYTEREGS; 568: } 569: else if (retregs & mES && 570: ((e1->Eoper == OPind && 571: ((tymll = tybasic(e1->E1->Ety)) == TYfptr || tymll == TYhptr)) 572: || 573: (e1->Eoper == OPvar && e1->EV.sp.Vsym->Sfl == FLfardata) 574: ) 575: ) 576: // getlvalue() needs ES, so we can't return it 577: retregs = allregs; /* no conflicts with ES */ 578: else if (tyml == TYdouble || tyml == TYdouble_alias || retregs & mST0) 579: retregs = DOUBLEREGS; 580: regvar = FALSE; 581: varregm = 0; 582: if (config.flags4 & CFG4optimized) 583: { 584: // Be careful of cases like (x = x+x+x). We cannot evaluate in 585: // x if x is in a register. 586: if (isregvar(e1,&varregm,&varreg) && // if lvalue is register variable 587: doinreg(e1->EV.sp.Vsym,e2) && // and we can compute directly into it 588: !(sz == 1 && e1->EV.sp.Voffset == 1) 589: ) 590: { regvar = TRUE; 591: retregs = varregm; 592: reg = varreg; /* evaluate directly in target register */ 593: if (tysize(e1->Ety) == REGSIZE && 594: tysize(e1->EV.sp.Vsym->Stype->Tty) == 2 * REGSIZE) 595: { 596: if (e1->EV.sp.Voffset) 597: retregs &= mMSW; 598: else 599: retregs &= mLSW; 600: reg = findreg(retregs); 601: } 602: } 603: } 604: if (*pretregs & mPSW && !EOP(e1)) /* if evaluating e1 couldn't change flags */ 605: { /* Be careful that this lines up with jmpopcode() */ 606: retregs |= mPSW; 607: *pretregs &= ~mPSW; 608: } 609: cr = scodelem(e2,&retregs,0,TRUE); /* get rvalue */ 610: 611: // Look for special case of (*p++ = ...), where p is a register variable 612: if (e1->Eoper == OPind && 613: ((e11 = e1->E1)->Eoper == OPpostinc || e11->Eoper == OPpostdec) && 614: e11->E1->Eoper == OPvar && 615: e11->E1->EV.sp.Vsym->Sfl == FLreg &&
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
616: (!I16 || e11->E1->EV.sp.Vsym->Sregm & IDXREGS)
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
617: ) 618: { 619: postinc = e11->E2->EV.Vint; 620: if (e11->Eoper == OPpostdec) 621: postinc = -postinc; 622: cl = getlvalue(&cs,e11,RMstore | retregs); 623: freenode(e11->E2); 624: if (I64 && sz < 8) 625: cs.Irex &= ~REX_W; // incorrectly set by getlvalue() 626: } 627: else 628: { postinc = 0; 629: cl = getlvalue(&cs,e1,RMstore | retregs); // get lvalue (cl == CNIL if regvar) 630: } 631: 632: c = getregs_imm(varregm); 633: 634: assert(!(retregs & mES && (cs.Iflags & CFSEG) == CFes)); 635: if ((tyml == TYfptr || tyml == TYhptr) && retregs & mES) 636: { 637: reg = findreglsw(retregs); 638: cs.Irm |= modregrm(0,reg,0); 639: c = gen(c,&cs); /* MOV EA,reg */ 640: getlvalue_msw(&cs); // point to where segment goes 641: cs.Iop = 0x8C; 642: NEWREG(cs.Irm,0); 643: gen(c,&cs); /* MOV EA+2,ES */ 644: } 645: else 646: { 647: if (!I16) 648: { 649: reg = findreg(retregs & 650: ((sz > REGSIZE) ? mBP | mLSW : mBP | ALLREGS));
warning C4018: '>' : signed/unsigned mismatch
651: cs.Irm |= modregrm(0,reg & 7,0); 652: if (reg & 8) 653: cs.Irex |= REX_R; 654: for (; TRUE; sz -= REGSIZE) 655: { 656: // Do not generate mov from register onto itself 657: if (regvar && reg == ((cs.Irm & 7) | (cs.Irex & REX_B ? 8 : 0))) 658: break; 659: if (sz == 2) // if 16 bit operand 660: cs.Iflags |= CFopsize; 661: else if (sz == 1 && reg >= 4) 662: cs.Irex |= REX; 663: c = gen(c,&cs); // MOV EA+offset,reg 664: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
665: break; 666: getlvalue_msw(&cs); 667: reg = findregmsw(retregs); 668: code_newreg(&cs, reg); 669: } 670: } 671: else 672: { 673: if (sz > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
674: cs.IEVoffset1 += sz - REGSIZE; /* 0,2,6 */ 675: reg = findreg(retregs & 676: (sz > REGSIZE ? mMSW : ALLREGS));
warning C4018: '>' : signed/unsigned mismatch
677: if (tyml == TYdouble || tyml == TYdouble_alias) 678: reg = AX; 679: cs.Irm |= modregrm(0,reg,0); 680: /* Do not generate mov from register onto itself */ 681: if (!regvar || reg != (cs.Irm & 7)) 682: for (; TRUE; sz -= REGSIZE) /* 1,2,4 */ 683: { 684: c = gen(c,&cs); /* MOV EA+offset,reg */ 685: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
686: break; 687: cs.IEVoffset1 -= REGSIZE; 688: if (tyml == TYdouble || tyml == TYdouble_alias) 689: reg = dblreg[reg]; 690: else 691: reg = findreglsw(retregs); 692: NEWREG(cs.Irm,reg); 693: } 694: } 695: } 696: if (e1->Ecount || /* if lvalue is a CSE or */ 697: regvar) /* rvalue can't be a CSE */ 698: { 699: c = cat(c,getregs_imm(retregs)); // necessary if both lvalue and 700: // rvalue are CSEs (since a reg 701: // can hold only one e at a time) 702: cssave(e1,retregs,EOP(e1)); /* if lvalue is a CSE */ 703: } 704: 705: c = cat4(cr,cl,c,fixresult(e,retregs,pretregs)); 706: Lp: 707: if (postinc) 708: { 709: int reg = findreg(idxregm(&cs));
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '322' of 'c:\projects\extern\d\dmd\src\backend\cod4.c': Lines: 322
710: if (*pretregs & mPSW) 711: { // Use LEA to avoid touching the flags 712: unsigned rm = cs.Irm & 7; 713: if (cs.Irex & REX_B) 714: rm |= 8; 715: c = genc1(c,0x8D,buildModregrm(2,reg,rm),FLconst,postinc); 716: if (sz == 8) 717: code_orrex(c, REX_W); 718: } 719: else if (I64) 720: { 721: c = genc2(c,0x81,modregrmx(3,0,reg),postinc); 722: if (tysize(e11->E1->Ety) == 8) 723: code_orrex(c, REX_W); 724: } 725: else 726: { 727: if (postinc == 1) 728: c = gen1(c,0x40 + reg); // INC reg 729: else if (postinc == -(targ_int)1) 730: c = gen1(c,0x48 + reg); // DEC reg 731: else 732: { 733: c = genc2(c,0x81,modregrm(3,0,reg),postinc); 734: } 735: } 736: } 737: freenode(e1); 738: return c; 739: } 740: 741: 742: /************************ 743: * Generate code for += -= &= |= ^= negass 744: */ 745: 746: code *cdaddass(elem *e,regm_t *pretregs) 747: { regm_t retregs,forccs,forregs; 748: tym_t tyml; 749: unsigned reg,op,op1,op2,mode,wantres; 750: int byte; 751: code *cl,*cr,*c,*ce,cs; 752: elem *e1; 753: elem *e2; 754: unsigned opsize; 755: unsigned reverse; 756: int sz; 757: regm_t varregm; 758: unsigned varreg; 759: unsigned cflags; 760: 761: //printf("cdaddass(e=%p, *pretregs = x%x)\n",e,*pretregs); 762: op = e->Eoper; 763: retregs = 0; 764: reverse = 0; 765: e1 = e->E1; 766: tyml = tybasic(e1->Ety); // type of lvalue 767: sz = tysize[tyml]; 768: byte = (sz == 1); // 1 for byte operation, else 0 769: if (tyfloating(tyml)) 770: { 771: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 772: if (op == OPnegass) 773: c = cdnegass87(e,pretregs); 774: else 775: c = opass87(e,pretregs); 776: #else 777: if (op == OPnegass) 778: c = opnegassdbl(e,pretregs); 779: else 780: c = opassdbl(e,pretregs,op); 781: #endif 782: return c; 783: } 784: opsize = (I16 && tylong(tyml) && config.target_cpu >= TARGET_80386) 785: ? CFopsize : 0; 786: cflags = 0; 787: forccs = *pretregs & mPSW; // return result in flags 788: forregs = *pretregs & ~mPSW; // return result in regs 789: /* TRUE if we want the result in a register */ 790: wantres = forregs || (e1->Ecount && EOP(e1)); 791: 792: switch (op) /* select instruction opcodes */ 793: { case OPpostinc: op = OPaddass; /* i++ => += */ 794: case OPaddass: op1 = 0x01; op2 = 0x11; 795: cflags = CFpsw; 796: mode = 0; break; /* ADD, ADC */ 797: case OPpostdec: op = OPminass; /* i-- => -= */ 798: case OPminass: op1 = 0x29; op2 = 0x19; 799: cflags = CFpsw; 800: mode = 5; break; /* SUB, SBC */ 801: case OPandass: op1 = op2 = 0x21; 802: mode = 4; break; /* AND, AND */ 803: case OPorass: op1 = op2 = 0x09; 804: mode = 1; break; /* OR , OR */ 805: case OPxorass: op1 = op2 = 0x31; 806: mode = 6; break; /* XOR, XOR */ 807: case OPnegass: op1 = 0xF7; // NEG 808: break; 809: default: 810: assert(0); 811: } 812: op1 ^= byte; /* bit 0 is 0 for byte operation */ 813: 814: if (op == OPnegass) 815: { 816: cl = getlvalue(&cs,e1,0); 817: cr = modEA(&cs); 818: cs.Irm |= modregrm(0,3,0); 819: cs.Iop = op1; 820: switch (tysize[tyml]) 821: { case CHARSIZE: 822: c = gen(CNIL,&cs); 823: break; 824: 825: case SHORTSIZE: 826: c = gen(CNIL,&cs); 827: 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?
828: c->Iflags |= CFopsize | CFpsw; 829: break; 830: 831: case LONGSIZE: 832: if (!I16 || opsize)
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
833: { c = gen(CNIL,&cs); 834: c->Iflags |= opsize; 835: break; 836: } 837: neg_2reg: 838: getlvalue_msw(&cs); 839: c = gen(CNIL,&cs); // NEG EA+2 840: getlvalue_lsw(&cs); 841: gen(c,&cs); // NEG EA 842: code_orflag(c,CFpsw); 843: cs.Iop = 0x81; 844: getlvalue_msw(&cs); 845: cs.IFL2 = FLconst; 846: cs.IEV2.Vuns = 0; 847: gen(c,&cs); // SBB EA+2,0 848: break; 849: 850: case LLONGSIZE: 851: if (I16) 852: assert(0); // not implemented yet 853: goto neg_2reg; 854: 855: default: 856: assert(0); 857: } 858: c = cat3(cl,cr,c); 859: forccs = 0; // flags already set by NEG 860: *pretregs &= ~mPSW; 861: } 862: else if ((e2 = e->E2)->Eoper == OPconst && // if rvalue is a const 863: el_signx32(e2) && 864: // Don't evaluate e2 in register if we can use an INC or DEC 865: (((sz <= REGSIZE || tyfv(tyml)) && 866: (op == OPaddass || op == OPminass) && 867: (el_allbits(e2, 1) || el_allbits(e2, -1)) 868: ) || 869: (!evalinregister(e2) && tyml != TYhptr) 870: ) 871: ) 872: { 873: cl = getlvalue(&cs,e1,0); 874: cl = cat(cl,modEA(&cs)); 875: cs.IFL2 = FLconst; 876: cs.IEV2.Vint = e2->EV.Vint; 877: if (sz <= REGSIZE || tyfv(tyml) || opsize) 878: { 879: targ_int i = cs.IEV2.Vint; 880: 881: /* Handle shortcuts. Watch out for if result has */ 882: /* to be in flags. */ 883: 884: if (reghasvalue(ALLREGS,i,&reg) && i != 1 && i != -1 && 885: !opsize) 886: { 887: cs.Iop = op1; 888: cs.Irm |= modregrm(0,reg,0); 889: } 890: else 891: { 892: cs.Iop = 0x81; 893: cs.Irm |= modregrm(0,mode,0); 894: switch (op) 895: { case OPminass: /* convert to += */ 896: cs.Irm ^= modregrm(0,5,0); 897: i = -i; 898: cs.IEV2.Vsize_t = i; 899: /* FALL-THROUGH */ 900: case OPaddass: 901: if (i == 1) /* INC EA */ 902: goto L1; 903: else if (i == -1) /* DEC EA */ 904: { cs.Irm |= modregrm(0,1,0); 905: L1: cs.Iop = 0xFF; 906: } 907: break; 908: } 909: } 910: cs.Iop ^= byte; /* for byte operations */ 911: cs.Iflags |= opsize; 912: if (forccs) 913: cs.Iflags |= CFpsw; 914: else if (!I16 && cs.Iflags & CFopsize)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
915: { 916: switch (op) 917: { case OPorass: 918: case OPxorass: 919: cs.IEV2.Vsize_t &= 0xFFFF; 920: cs.Iflags &= ~CFopsize; // don't worry about MSW 921: break; 922: case OPandass: 923: cs.IEV2.Vsize_t |= ~0xFFFFLL; 924: cs.Iflags &= ~CFopsize; // don't worry about MSW 925: break; 926: case OPminass: 927: case OPaddass: 928: #if 1 929: if ((cs.Irm & 0xC0) == 0xC0) // EA is register 930: cs.Iflags &= ~CFopsize; 931: #else 932: if ((cs.Irm & 0xC0) == 0xC0 && // EA is register and 933: e1->Eoper == OPind) // not a register var 934: cs.Iflags &= ~CFopsize; 935: #endif 936: break; 937: default: 938: assert(0); 939: break; 940: } 941: } 942: 943: // For scheduling purposes, we wish to replace: 944: // OP EA 945: // with: 946: // MOV reg,EA 947: // OP reg 948: // MOV EA,reg 949: if (forregs && sz <= REGSIZE && (cs.Irm & 0xC0) != 0xC0 && 950: (config.target_cpu == TARGET_Pentium || 951: config.target_cpu == TARGET_PentiumMMX) && 952: config.flags4 & CFG4speed) 953: { regm_t sregm; 954: code cs2; 955: 956: // Determine which registers to use 957: sregm = allregs & ~idxregm(&cs); 958: if (byte) 959: sregm &= BYTEREGS; 960: if (sregm & forregs) 961: sregm &= forregs; 962: 963: cr = allocreg(&sregm,&reg,tyml); // allocate register 964: 965: cs2 = cs; 966: cs2.Iflags &= ~CFpsw; 967: cs2.Iop = 0x8B ^ byte; 968: code_newreg(&cs2, reg); 969: cr = gen(cr,&cs2); // MOV reg,EA 970: 971: cs.Irm = (cs.Irm & modregrm(0,7,0)) | modregrm(3,0,reg & 7); 972: if (reg & 8) 973: cs.Irex |= REX_B; 974: gen(cr,&cs); // OP reg 975: 976: cs2.Iop ^= 2; 977: gen(cr,&cs2); // MOV EA,reg 978: 979: c = cat(cl,cr); 980: retregs = sregm; 981: wantres = 0; 982: if (e1->Ecount) 983: cssave(e1,retregs,EOP(e1)); 984: } 985: else 986: { 987: c = gen(cl,&cs); 988: cs.Iflags &= ~opsize; 989: cs.Iflags &= ~CFpsw; 990: if (I16 && opsize) // if DWORD operand 991: cs.IEVoffset1 += 2; // compensate for wantres code 992: } 993: } 994: else if (sz == 2 * REGSIZE) 995: { targ_uns msw; 996: 997: cs.Iop = 0x81; 998: cs.Irm |= modregrm(0,mode,0); 999: c = cl; 1000: cs.Iflags |= cflags; 1001: c = gen(c,&cs); 1002: cs.Iflags &= ~CFpsw; 1003: 1004: getlvalue_msw(&cs); // point to msw 1005: msw = MSREG(e->E2->EV.Vllong);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_uns', possible loss of data
1006: cs.IEV2.Vuns = msw; /* msw of constant */ 1007: switch (op) 1008: { case OPminass: 1009: cs.Irm ^= modregrm(0,6,0); /* SUB => SBB */ 1010: break; 1011: case OPaddass: 1012: cs.Irm |= modregrm(0,2,0); /* ADD => ADC */ 1013: break; 1014: } 1015: c = gen(c,&cs); 1016: } 1017: else 1018: assert(0); 1019: freenode(e->E2); /* don't need it anymore */ 1020: } 1021: else if (isregvar(e1,&varregm,&varreg) && 1022: (e2->Eoper == OPvar || e2->Eoper == OPind) && 1023: !evalinregister(e2) && 1024: sz <= REGSIZE) // deal with later 1025: { 1026: cr = getlvalue(&cs,e2,0); 1027: freenode(e2); 1028: cl = getregs(varregm); 1029: code_newreg(&cs, varreg); 1030: if (I64 && sz == 1 && varreg >= 4) 1031: cs.Irex |= REX; 1032: cs.Iop = op1 ^ 2; // toggle direction bit 1033: if (forccs) 1034: cs.Iflags |= CFpsw; 1035: reverse = 2; // remember we toggled it 1036: cl = gen(cl,&cs); 1037: c = cat(cr,cl); 1038: retregs = 0; /* to trigger a bug if we attempt to use it */ 1039: } 1040: else // evaluate e2 into register 1041: { 1042: retregs = (byte) ? BYTEREGS : ALLREGS; // pick working reg 1043: if (tyml == TYhptr) 1044: retregs &= ~mCX; // need CX for shift count 1045: cr = scodelem(e->E2,&retregs,0,TRUE); // get rvalue 1046: cl = getlvalue(&cs,e1,retregs); // get lvalue 1047: cl = cat(cl,modEA(&cs)); 1048: cs.Iop = op1; 1049: if (sz <= REGSIZE || tyfv(tyml)) 1050: { reg = findreg(retregs); 1051: code_newreg(&cs, reg); // OP1 EA,reg 1052: if (sz == 1 && reg >= 4 && I64) 1053: cs.Irex |= REX; 1054: } 1055: else if (tyml == TYhptr) 1056: { unsigned mreg,lreg; 1057: 1058: mreg = findregmsw(retregs); 1059: lreg = findreglsw(retregs); 1060: cl = cat(cl,getregs(retregs | mCX)); 1061: 1062: // If h -= l, convert to h += -l 1063: if (e->Eoper == OPminass) 1064: { 1065: cl = gen2(cl,0xF7,modregrm(3,3,mreg)); // NEG mreg 1066: gen2(cl,0xF7,modregrm(3,3,lreg)); // NEG lreg 1067: code_orflag(cl,CFpsw); 1068: genc2(cl,0x81,modregrm(3,3,mreg),0); // SBB mreg,0 1069: } 1070: cs.Iop = 0x01; 1071: cs.Irm |= modregrm(0,lreg,0); 1072: cl = gen(cl,&cs); // ADD EA,lreg 1073: code_orflag(cl,CFpsw); 1074: genc2(cl,0x81,modregrm(3,2,mreg),0); // ADC mreg,0 1075: genshift(cl); // MOV CX,offset __AHSHIFT 1076: gen2(cl,0xD3,modregrm(3,4,mreg)); // SHL mreg,CL 1077: NEWREG(cs.Irm,mreg); // ADD EA+2,mreg 1078: getlvalue_msw(&cs); 1079: } 1080: else if (sz == 2 * REGSIZE) 1081: { 1082: cs.Irm |= modregrm(0,findreglsw(retregs),0); 1083: cl = gen(cl,&cs); /* OP1 EA,reg+1 */ 1084: code_orflag(cl,cflags); 1085: cs.Iop = op2; 1086: NEWREG(cs.Irm,findregmsw(retregs)); /* OP2 EA+1,reg */ 1087: getlvalue_msw(&cs); 1088: } 1089: else 1090: assert(0); 1091: cl = gen(cl,&cs); 1092: c = cat(cr,cl); 1093: retregs = 0; /* to trigger a bug if we attempt to use it */ 1094: } 1095: 1096: /* See if we need to reload result into a register. */ 1097: /* Need result in registers in case we have a 32 bit */ 1098: /* result and we want the flags as a result. */ 1099: if (wantres || (sz > REGSIZE && forccs)) 1100: { 1101: if (sz <= REGSIZE) 1102: { regm_t possregs; 1103: 1104: possregs = ALLREGS; 1105: if (byte) 1106: possregs = BYTEREGS; 1107: retregs = forregs & possregs; 1108: if (!retregs) 1109: retregs = possregs; 1110: 1111: // If reg field is destination 1112: if (cs.Iop & 2 && cs.Iop < 0x40 && (cs.Iop & 7) <= 5) 1113: { 1114: reg = (cs.Irm >> 3) & 7; 1115: if (cs.Irex & REX_R) 1116: reg |= 8; 1117: retregs = mask[reg]; 1118: ce = allocreg(&retregs,&reg,tyml); 1119: } 1120: // If lvalue is a register, just use that register 1121: else if ((cs.Irm & 0xC0) == 0xC0) 1122: { 1123: reg = cs.Irm & 7; 1124: if (cs.Irex & REX_B) 1125: reg |= 8; 1126: retregs = mask[reg]; 1127: ce = allocreg(&retregs,&reg,tyml); 1128: } 1129: else 1130: { 1131: ce = allocreg(&retregs,&reg,tyml); 1132: cs.Iop = 0x8B ^ byte ^ reverse; 1133: code_newreg(&cs, reg); 1134: if (I64 && byte && reg >= 4) 1135: cs.Irex |= REX_W; 1136: ce = gen(ce,&cs); // MOV reg,EA 1137: } 1138: } 1139: else if (tyfv(tyml) || tyml == TYhptr) 1140: { regm_t idxregs; 1141: 1142: if (tyml == TYhptr) 1143: getlvalue_lsw(&cs); 1144: idxregs = idxregm(&cs); 1145: retregs = forregs & ~idxregs; 1146: if (!(retregs & IDXREGS)) 1147: retregs |= IDXREGS & ~idxregs; 1148: if (!(retregs & mMSW)) 1149: retregs |= mMSW & ALLREGS; 1150: ce = allocreg(&retregs,&reg,tyml); 1151: NEWREG(cs.Irm,findreglsw(retregs)); 1152: if (retregs & mES) /* if want ES loaded */ 1153: { cs.Iop = 0xC4; 1154: ce = gen(ce,&cs); /* LES lreg,EA */ 1155: } 1156: else 1157: { cs.Iop = 0x8B; 1158: ce = gen(ce,&cs); /* MOV lreg,EA */ 1159: getlvalue_msw(&cs); 1160: if (I32) 1161: cs.Iflags |= CFopsize; 1162: NEWREG(cs.Irm,reg); 1163: gen(ce,&cs); /* MOV mreg,EA+2 */ 1164: } 1165: } 1166: else if (sz == 2 * REGSIZE) 1167: { regm_t idx; 1168: code *cm,*cl;
warning C6246: Local declaration of 'cl' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '751' of 'c:\projects\extern\d\dmd\src\backend\cod4.c': Lines: 751
1169: 1170: idx = idxregm(&cs); 1171: retregs = forregs; 1172: if (!retregs) 1173: retregs = ALLREGS; 1174: ce = allocreg(&retregs,&reg,tyml); 1175: cs.Iop = 0x8B; 1176: NEWREG(cs.Irm,reg); 1177: cm = gen(NULL,&cs); // MOV reg,EA+2 1178: NEWREG(cs.Irm,findreglsw(retregs)); 1179: getlvalue_lsw(&cs); 1180: cl = gen(NULL,&cs); // MOV reg+1,EA 1181: if (mask[reg] & idx) 1182: ce = cat3(ce,cl,cm); 1183: else 1184: ce = cat3(ce,cm,cl); 1185: } 1186: else 1187: assert(0); 1188: c = cat(c,ce); 1189: if (e1->Ecount) /* if we gen a CSE */ 1190: cssave(e1,retregs,EOP(e1)); 1191: } 1192: freenode(e1); 1193: if (sz <= REGSIZE) 1194: *pretregs &= ~mPSW; // flags are already set 1195: return cat(c,fixresult(e,retregs,pretregs)); 1196: } 1197: 1198: /******************************** 1199: * Generate code for *= /= %= 1200: */ 1201: 1202: code *cdmulass(elem *e,regm_t *pretregs) 1203: { 1204: code *cr,*cl,*cg,*c,cs; 1205: regm_t retregs; 1206: unsigned resreg,reg,opr,lib,byte; 1207: 1208: //printf("cdmulass(e=%p, *pretregs = %s)\n",e,regm_str(*pretregs)); 1209: elem *e1 = e->E1; 1210: elem *e2 = e->E2; 1211: unsigned op = e->Eoper; // OPxxxx 1212: 1213: tym_t tyml = tybasic(e1->Ety); // type of lvalue 1214: char uns = tyuns(tyml) || tyuns(e2->Ety); 1215: unsigned sz = tysize[tyml]; 1216: 1217: unsigned rex = (I64 && sz == 8) ? REX_W : 0; 1218: unsigned grex = rex << 16; // 64 bit operands 1219: 1220: 1221: if (tyfloating(tyml)) 1222: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1223: return opass87(e,pretregs); 1224: #else 1225: return opassdbl(e,pretregs,op); 1226: #endif 1227: 1228: if (sz <= REGSIZE) /* if word or byte */
warning C4018: '<=' : signed/unsigned mismatch
1229: { byte = (sz == 1); /* 1 for byte operation */ 1230: resreg = AX; /* result register for * or / */ 1231: if (uns) /* if unsigned operation */ 1232: opr = 4; /* MUL */ 1233: else /* else signed */ 1234: opr = 5; /* IMUL */ 1235: if (op != OPmulass) /* if /= or %= */ 1236: { opr += 2; /* MUL => DIV, IMUL => IDIV */ 1237: if (op == OPmodass) 1238: resreg = DX; /* remainder is in DX */ 1239: } 1240: if (op == OPmulass) /* if multiply */ 1241: { 1242: if (config.target_cpu >= TARGET_80286 && 1243: e2->Eoper == OPconst && !byte) 1244: { 1245: targ_size_t e2factor = el_tolong(e2);
warning C4244: 'initializing' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1246: if (I64 && sz == 8 && e2factor != (int)e2factor) 1247: goto L1; 1248: freenode(e2); 1249: cr = CNIL; 1250: cl = getlvalue(&cs,e1,0); /* get EA */ 1251: regm_t idxregs = idxregm(&cs); 1252: retregs = *pretregs & (ALLREGS | mBP) & ~idxregs; 1253: if (!retregs) 1254: retregs = ALLREGS & ~idxregs; 1255: cg = allocreg(&retregs,&resreg,tyml); 1256: cs.Iop = 0x69; /* IMUL reg,EA,e2value */ 1257: cs.IFL2 = FLconst; 1258: cs.IEV2.Vint = e2factor; 1259: opr = resreg; 1260: } 1261: else if (!I16 && !byte)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1262: { 1263: L1: 1264: retregs = *pretregs & (ALLREGS | mBP); 1265: if (!retregs) 1266: retregs = ALLREGS; 1267: cr = codelem(e2,&retregs,FALSE); /* load rvalue in reg */ 1268: cl = getlvalue(&cs,e1,retregs); /* get EA */ 1269: cg = getregs(retregs); /* destroy these regs */ 1270: cs.Iop = 0x0FAF; // IMUL resreg,EA 1271: resreg = findreg(retregs); 1272: opr = resreg; 1273: } 1274: else 1275: { 1276: retregs = mAX; 1277: cr = codelem(e2,&retregs,FALSE); // load rvalue in AX 1278: cl = getlvalue(&cs,e1,mAX); // get EA 1279: cg = getregs(byte ? mAX : mAX | mDX); // destroy these regs 1280: cs.Iop = 0xF7 ^ byte; // [I]MUL EA 1281: } 1282: code_newreg(&cs,opr); 1283: c = gen(CNIL,&cs); 1284: } 1285: else // /= or %= 1286: { targ_size_t e2factor; 1287: int pow2; 1288: 1289: assert(!byte); // should never happen 1290: assert(I16 || sz != SHORTSIZE); 1291: if (config.flags4 & CFG4speed && 1292: e2->Eoper == OPconst && !uns && 1293: (sz == REGSIZE || (I64 && sz == 4)) && 1294: (pow2 = ispow2(e2factor = el_tolong(e2))) != -1 &&
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1295: e2factor == (int)e2factor && 1296: !(config.target_cpu < TARGET_80286 && pow2 != 1 && op == OPdivass) 1297: ) 1298: { 1299: // Signed divide or modulo by power of 2 1300: cr = NULL; 1301: c = NULL; 1302: cl = getlvalue(&cs,e1,mAX | mDX); 1303: cs.Iop = 0x8B; 1304: code_newreg(&cs, AX); 1305: cl = gen(cl,&cs); // MOV AX,EA 1306: freenode(e2); 1307: cg = getregs(mAX | mDX); // trash these regs 1308: cg = gen1(cg,0x99); // CWD 1309: code_orrex(cg, rex); 1310: if (pow2 == 1) 1311: { 1312: if (op == OPdivass) 1313: { gen2(cg,0x2B,grex | modregrm(3,AX,DX)); // SUB AX,DX 1314: gen2(cg,0xD1,grex | modregrm(3,7,AX)); // SAR AX,1 1315: resreg = AX; 1316: } 1317: else // OPmod 1318: { gen2(cg,0x33,grex | modregrm(3,AX,DX)); // XOR AX,DX 1319: genc2(cg,0x81,grex | modregrm(3,4,AX),1); // AND AX,1 1320: gen2(cg,0x03,grex | modregrm(3,DX,AX)); // ADD DX,AX 1321: resreg = DX; 1322: } 1323: } 1324: else 1325: { 1326: assert(pow2 < 32); 1327: targ_ulong m = (1 << pow2) - 1; 1328: if (op == OPdivass) 1329: { genc2(cg,0x81,grex | modregrm(3,4,DX),m); // AND DX,m 1330: gen2(cg,0x03,grex | modregrm(3,AX,DX)); // ADD AX,DX 1331: // Be careful not to generate this for 8088 1332: assert(config.target_cpu >= TARGET_80286); 1333: genc2(cg,0xC1,grex | modregrm(3,7,AX),pow2); // SAR AX,pow2 1334: resreg = AX; 1335: } 1336: else // OPmodass 1337: { gen2(cg,0x33,grex | modregrm(3,AX,DX)); // XOR AX,DX 1338: gen2(cg,0x2B,grex | modregrm(3,AX,DX)); // SUB AX,DX 1339: genc2(cg,0x81,grex | modregrm(3,4,AX),m); // AND AX,m 1340: gen2(cg,0x33,grex | modregrm(3,AX,DX)); // XOR AX,DX 1341: gen2(cg,0x2B,grex | modregrm(3,AX,DX)); // SUB AX,DX 1342: resreg = AX; 1343: } 1344: } 1345: } 1346: else 1347: { 1348: retregs = ALLREGS & ~(mAX|mDX); // DX gets sign extension 1349: cr = codelem(e2,&retregs,FALSE); // load rvalue in retregs 1350: reg = findreg(retregs); 1351: cl = getlvalue(&cs,e1,mAX | mDX | retregs); // get EA 1352: cg = getregs(mAX | mDX); // destroy these regs 1353: cs.Irm |= modregrm(0,AX,0); 1354: cs.Iop = 0x8B; 1355: c = gen(CNIL,&cs); // MOV AX,EA 1356: if (uns) // if unsigned 1357: movregconst(c,DX,0,0); // CLR DX 1358: else // else signed 1359: { gen1(c,0x99); // CWD 1360: code_orrex(c,rex); 1361: } 1362: c = cat(c,getregs(mDX | mAX)); // DX and AX will be destroyed 1363: genregs(c,0xF7,opr,reg); // OPR reg 1364: code_orrex(c,rex); 1365: } 1366: } 1367: cs.Iop = 0x89 ^ byte; 1368: code_newreg(&cs,resreg); 1369: c = gen(c,&cs); // MOV EA,resreg 1370: if (e1->Ecount) // if we gen a CSE 1371: cssave(e1,mask[resreg],EOP(e1)); 1372: freenode(e1); 1373: c = cat(c,fixresult(e,mask[resreg],pretregs)); 1374: return cat4(cr,cl,cg,c); 1375: } 1376: else if (sz == 2 * REGSIZE) 1377: { 1378: lib = CLIBlmul; 1379: if (op == OPdivass || op == OPmodass) 1380: { lib = (uns) ? CLIBuldiv : CLIBldiv; 1381: if (op == OPmodass) 1382: lib++; 1383: } 1384: retregs = mCX | mBX; 1385: cr = codelem(e2,&retregs,FALSE); 1386: cl = getlvalue(&cs,e1,mDX|mAX | mCX|mBX); 1387: cl = cat(cl,getregs(mDX | mAX)); 1388: cs.Iop = 0x8B; 1389: cl = gen(cl,&cs); /* MOV AX,EA */ 1390: getlvalue_msw(&cs); 1391: cs.Irm |= modregrm(0,DX,0); 1392: gen(cl,&cs); /* MOV DX,EA+2 */ 1393: getlvalue_lsw(&cs); 1394: retregs = 0; 1395: if (config.target_cpu >= TARGET_PentiumPro && op == OPmulass) 1396: { 1397: /* IMUL ECX,EAX 1398: IMUL EDX,EBX 1399: ADD ECX,EDX 1400: MUL EBX 1401: ADD EDX,ECX 1402: */ 1403: c = getregs(mAX|mDX|mCX); 1404: c = gen2(c,0x0FAF,modregrm(3,CX,AX)); 1405: gen2(c,0x0FAF,modregrm(3,DX,BX)); 1406: gen2(c,0x03,modregrm(3,CX,DX)); 1407: gen2(c,0xF7,modregrm(3,4,BX)); 1408: gen2(c,0x03,modregrm(3,DX,CX)); 1409: retregs = mDX | mAX; 1410: } 1411: else 1412: c = callclib(e,lib,&retregs,idxregm(&cs)); 1413: reg = (op == OPmodass) ? BX : AX; 1414: retregs = mask[reg]; 1415: cs.Iop = 0x89; 1416: NEWREG(cs.Irm,reg); 1417: gen(c,&cs); /* MOV EA,lsreg */ 1418: reg = (op == OPmodass) ? CX : DX; 1419: retregs |= mask[reg]; 1420: NEWREG(cs.Irm,reg); 1421: getlvalue_msw(&cs); 1422: gen(c,&cs); /* MOV EA+2,msreg */ 1423: if (e1->Ecount) /* if we gen a CSE */ 1424: cssave(e1,retregs,EOP(e1)); 1425: freenode(e1); 1426: cg = fixresult(e,retregs,pretregs); 1427: return cat4(cr,cl,c,cg); 1428: } 1429: else 1430: { assert(0); 1431: /* NOTREACHED */ 1432: return 0; 1433: } 1434: } 1435: 1436: 1437: /******************************** 1438: * Generate code for <<= and >>= 1439: */ 1440: 1441: code *cdshass(elem *e,regm_t *pretregs) 1442: { elem *e1,*e2; 1443: code *cr,*cl,*cg,*c,cs,*ce; 1444: tym_t tym,tyml; 1445: regm_t retregs; 1446: unsigned shiftcnt,op1,op2,reg,v,oper,byte,conste2; 1447: unsigned loopcnt; 1448: unsigned sz; 1449: 1450: e1 = e->E1; 1451: e2 = e->E2; 1452: 1453: tyml = tybasic(e1->Ety); /* type of lvalue */ 1454: sz = tysize[tyml]; 1455: byte = tybyte(e->Ety) != 0; /* 1 for byte operations */ 1456: tym = tybasic(e->Ety); /* type of result */ 1457: oper = e->Eoper; 1458: assert(tysize(e2->Ety) <= REGSIZE); 1459: 1460: unsigned rex = (I64 && sz == 8) ? REX_W : 0; 1461: 1462: // if our lvalue is a cse, make sure we evaluate for result in register 1463: if (e1->Ecount && !(*pretregs & (ALLREGS | mBP)) && !isregvar(e1,&retregs,&reg)) 1464: *pretregs |= ALLREGS; 1465: 1466: #if SCPP 1467: // Do this until the rest of the compiler does OPshr/OPashr correctly 1468: if (oper == OPshrass) 1469: oper = tyuns(tyml) ? OPshrass : OPashrass; 1470: #endif 1471: 1472: // Select opcodes. op2 is used for msw for long shifts. 1473: 1474: switch (oper) 1475: { case OPshlass: 1476: op1 = 4; // SHL 1477: op2 = 2; // RCL 1478: break; 1479: case OPshrass: 1480: op1 = 5; // SHR 1481: op2 = 3; // RCR 1482: break; 1483: case OPashrass: 1484: op1 = 7; // SAR 1485: op2 = 3; // RCR 1486: break; 1487: default: 1488: assert(0); 1489: } 1490: 1491: 1492: v = 0xD3; /* for SHIFT xx,CL cases */ 1493: loopcnt = 1; 1494: conste2 = FALSE; 1495: cr = CNIL; 1496: shiftcnt = 0; // avoid "use before initialized" warnings 1497: if (cnst(e2)) 1498: { 1499: conste2 = TRUE; /* e2 is a constant */ 1500: shiftcnt = e2->EV.Vint; /* byte ordering of host */ 1501: if (config.target_cpu >= TARGET_80286 && 1502: sz <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1503: shiftcnt != 1) 1504: v = 0xC1; // SHIFT xx,shiftcnt 1505: else if (shiftcnt <= 3) 1506: { loopcnt = shiftcnt; 1507: v = 0xD1; // SHIFT xx,1 1508: } 1509: } 1510: if (v == 0xD3) /* if COUNT == CL */ 1511: { retregs = mCX; 1512: cr = codelem(e2,&retregs,FALSE); 1513: } 1514: else 1515: freenode(e2); 1516: cl = getlvalue(&cs,e1,mCX); /* get lvalue, preserve CX */ 1517: cl = cat(cl,modEA(&cs)); // check for modifying register 1518: 1519: if (*pretregs == 0 || /* if don't return result */ 1520: (*pretregs == mPSW && conste2 && tysize[tym] <= REGSIZE) || 1521: sz > REGSIZE 1522: )
warning C4018: '>' : signed/unsigned mismatch
1523: { retregs = 0; // value not returned in a register 1524: cs.Iop = v ^ byte; 1525: c = CNIL; 1526: while (loopcnt--) 1527: { 1528: NEWREG(cs.Irm,op1); /* make sure op1 is first */ 1529: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1530: { 1531: if (conste2) 1532: { cs.IFL2 = FLconst; 1533: cs.IEV2.Vint = shiftcnt; 1534: } 1535: c = gen(c,&cs); /* SHIFT EA,[CL|1] */ 1536: if (*pretregs & mPSW && !loopcnt && conste2) 1537: code_orflag(c,CFpsw); 1538: } 1539: else /* TYlong */ 1540: { cs.Iop = 0xD1; /* plain shift */ 1541: ce = gennop(CNIL); /* ce: NOP */ 1542: if (v == 0xD3) 1543: { c = getregs(mCX); 1544: if (!conste2) 1545: { assert(loopcnt == 0); 1546: c = genjmp(c,JCXZ,FLcode,(block *) ce); /* JCXZ ce */ 1547: } 1548: } 1549: if (oper == OPshlass) 1550: { cg = gen(CNIL,&cs); // cg: SHIFT EA 1551: c = cat(c,cg); 1552: getlvalue_msw(&cs); 1553: NEWREG(cs.Irm,op2); 1554: gen(c,&cs); /* SHIFT EA */ 1555: getlvalue_lsw(&cs); 1556: } 1557: else 1558: { getlvalue_msw(&cs); 1559: cg = gen(CNIL,&cs); 1560: c = cat(c,cg); 1561: NEWREG(cs.Irm,op2); 1562: getlvalue_lsw(&cs); 1563: gen(c,&cs); 1564: } 1565: if (v == 0xD3) /* if building a loop */ 1566: { genjmp(c,LOOP,FLcode,(block *) cg); /* LOOP cg */ 1567: regimmed_set(CX,0); /* note that now CX == 0 */ 1568: } 1569: c = cat(c,ce); 1570: } 1571: } 1572: 1573: /* If we want the result, we must load it from the EA */ 1574: /* into a register. */ 1575: 1576: if (sz == 2 * REGSIZE && *pretregs) 1577: { retregs = *pretregs & (ALLREGS | mBP); 1578: if (retregs) 1579: { ce = allocreg(&retregs,&reg,tym); 1580: cs.Iop = 0x8B; 1581: 1582: /* be careful not to trash any index regs */ 1583: /* do MSW first (which can't be an index reg) */ 1584: getlvalue_msw(&cs); 1585: NEWREG(cs.Irm,reg); 1586: cg = gen(CNIL,&cs); 1587: getlvalue_lsw(&cs); 1588: reg = findreglsw(retregs); 1589: NEWREG(cs.Irm,reg); 1590: gen(cg,&cs); 1591: if (*pretregs & mPSW) 1592: cg = cat(cg,tstresult(retregs,tyml,TRUE)); 1593: } 1594: else /* flags only */ 1595: { retregs = ALLREGS & ~idxregm(&cs); 1596: ce = allocreg(&retregs,&reg,TYint); 1597: cs.Iop = 0x8B; 1598: NEWREG(cs.Irm,reg); 1599: cg = gen(CNIL,&cs); /* MOV reg,EA */ 1600: cs.Iop = 0x0B; /* OR reg,EA+2 */ 1601: cs.Iflags |= CFpsw; 1602: getlvalue_msw(&cs); 1603: gen(cg,&cs); 1604: } 1605: c = cat3(c,ce,cg); 1606: } 1607: cg = CNIL; 1608: } 1609: else /* else must evaluate in register */ 1610: { 1611: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1612: { 1613: regm_t possregs = ALLREGS & ~mCX & ~idxregm(&cs); 1614: if (byte) 1615: possregs &= BYTEREGS; 1616: retregs = *pretregs & possregs; 1617: if (retregs == 0) 1618: retregs = possregs; 1619: cg = allocreg(&retregs,&reg,tym); 1620: cs.Iop = 0x8B ^ byte; 1621: code_newreg(&cs, reg); 1622: c = ce = gen(CNIL,&cs); /* MOV reg,EA */ 1623: if (!I16) 1624: { 1625: assert(!byte || (mask[reg] & BYTEREGS)); 1626: ce = genc2(CNIL,v ^ byte,modregrmx(3,op1,reg),shiftcnt); 1627: code_orrex(ce, rex); 1628: /* We can do a 32 bit shift on a 16 bit operand if */ 1629: /* it's a left shift and we're not concerned about */ 1630: /* the flags. Remember that flags are not set if */ 1631: /* a shift of 0 occurs. */ 1632: if (tysize[tym] == SHORTSIZE && 1633: (oper == OPshrass || oper == OPashrass || 1634: (*pretregs & mPSW && conste2))) 1635: ce->Iflags |= CFopsize; /* 16 bit operand */ 1636: cat(c,ce); 1637: } 1638: else 1639: { 1640: while (loopcnt--) 1641: { /* Generate shift instructions. */ 1642: genc2(ce,v ^ byte,modregrm(3,op1,reg),shiftcnt); 1643: } 1644: } 1645: if (*pretregs & mPSW && conste2) 1646: { assert(shiftcnt); 1647: *pretregs &= ~mPSW; // result is already in flags 1648: code_orflag(ce,CFpsw); 1649: } 1650: 1651: cs.Iop = 0x89 ^ byte; 1652: gen(ce,&cs); /* MOV EA,reg */ 1653: 1654: // If result is not in correct register 1655: cat(ce,fixresult(e,retregs,pretregs)); 1656: retregs = *pretregs; 1657: } 1658: else 1659: assert(0); 1660: } 1661: if (e1->Ecount && !(retregs & regcon.mvar)) // if lvalue is a CSE 1662: cssave(e1,retregs,EOP(e1)); 1663: freenode(e1); 1664: *pretregs = retregs; 1665: return cat4(cr,cl,cg,c); 1666: } 1667: 1668: 1669: /********************************** 1670: * Generate code for compares. 1671: * Handles lt,gt,le,ge,eqeq,ne for all data types. 1672: */ 1673: 1674: code *cdcmp(elem *e,regm_t *pretregs) 1675: { regm_t retregs,rretregs; 1676: unsigned reg,rreg,op,jop,byte; 1677: tym_t tym; 1678: code *cl,*cr,*c,cs,*ce,*cg; 1679: elem *e1,*e2; 1680: bool eqorne; 1681: unsigned reverse; 1682: unsigned sz; 1683: int fl; 1684: int flag; 1685: 1686: //printf("cdcmp(e = %p, retregs = %s)\n",e,regm_str(*pretregs)); 1687: // Collect extra parameter. This is pretty ugly... 1688: flag = cdcmp_flag; 1689: cdcmp_flag = 0; 1690: 1691: e1 = e->E1; 1692: e2 = e->E2; 1693: if (*pretregs == 0) /* if don't want result */ 1694: { cl = codelem(e1,pretregs,FALSE); 1695: *pretregs = 0; /* in case e1 changed it */ 1696: cr = codelem(e2,pretregs,FALSE); 1697: return cat(cl,cr); 1698: } 1699: 1700: jop = jmpopcode(e); // must be computed before 1701: // leaves are free'd 1702: reverse = 0; 1703: cl = cr = CNIL; 1704: op = e->Eoper; 1705: assert(OTrel(op)); 1706: eqorne = (op == OPeqeq) || (op == OPne); 1707: 1708: tym = tybasic(e1->Ety); 1709: sz = tysize[tym]; 1710: byte = sz == 1; 1711: 1712: unsigned rex = (I64 && sz == 8) ? REX_W : 0; 1713: unsigned grex = rex << 16; // 64 bit operands 1714: 1715: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1716: if (tyfloating(tym)) /* if floating operation */ 1717: { 1718: retregs = mPSW; 1719: c = orth87(e,&retregs); 1720: goto L3; 1721: } 1722: #else 1723: if (tyfloating(tym)) /* if floating operation */ 1724: { 1725: if (config.inline8087) 1726: { retregs = mPSW; 1727: c = orth87(e,&retregs); 1728: } 1729: else 1730: { int clib; 1731: 1732: retregs = 0; /* skip result for now */ 1733: if (iffalse(e2)) /* second operand is constant 0 */ 1734: { assert(!eqorne); /* should be OPbool or OPnot */ 1735: if (tym == TYfloat) 1736: { retregs = FLOATREGS; 1737: clib = CLIBftst0; 1738: } 1739: else 1740: { retregs = DOUBLEREGS; 1741: clib = CLIBdtst0; 1742: } 1743: if (rel_exception(op)) 1744: clib += CLIBdtst0exc - CLIBdtst0; 1745: cl = codelem(e1,&retregs,FALSE); 1746: retregs = 0; 1747: c = callclib(e,clib,&retregs,0); 1748: freenode(e2); 1749: } 1750: else 1751: { clib = CLIBdcmp; 1752: if (rel_exception(op)) 1753: clib += CLIBdcmpexc - CLIBdcmp; 1754: c = opdouble(e,&retregs,clib); 1755: } 1756: } 1757: goto L3; 1758: } 1759: #endif 1760: 1761: /* If it's a signed comparison of longs, we have to call a library */ 1762: /* routine, because we don't know the target of the signed branch */ 1763: /* (have to set up flags so that jmpopcode() will do it right) */ 1764: if (!eqorne && 1765: (I16 && tym == TYlong && tybasic(e2->Ety) == TYlong || 1766: I32 && tym == TYllong && tybasic(e2->Ety) == TYllong) 1767: ) 1768: { retregs = mDX | mAX; 1769: cl = codelem(e1,&retregs,FALSE); 1770: retregs = mCX | mBX; 1771: cr = scodelem(e2,&retregs,mDX | mAX,FALSE); 1772: 1773: if (I16) 1774: { 1775: retregs = 0; 1776: c = callclib(e,CLIBlcmp,&retregs,0); /* gross, but it works */ 1777: } 1778: else 1779: { 1780: /* Generate: 1781: * CMP EDX,ECX 1782: * JNE C1 1783: * XOR EDX,EDX 1784: * CMP EAX,EBX 1785: * JZ C1 1786: * JA C3 1787: * DEC EDX 1788: * JMP C1 1789: * C3: INC EDX 1790: * C1: 1791: */ 1792: c = getregs(mDX); 1793: c = genregs(c,0x39,CX,DX); // CMP EDX,ECX 1794: code *c1 = gennop(CNIL); 1795: genjmp(c,JNE,FLcode,(block *)c1); // JNE C1 1796: movregconst(c,DX,0,0); // XOR EDX,EDX 1797: genregs(c,0x39,BX,AX); // CMP EAX,EBX 1798: genjmp(c,JE,FLcode,(block *)c1); // JZ C1 1799: code *c3 = gen1(CNIL,0x40 + DX); // INC EDX 1800: genjmp(c,JA,FLcode,(block *)c3); // JA C3 1801: gen1(c,0x48 + DX); // DEC EDX 1802: genjmp(c,JMPS,FLcode,(block *)c1); // JMP C1 1803: c = cat4(c,c3,c1,getregs(mDX)); 1804: retregs = mPSW; 1805: } 1806: goto L3; 1807: } 1808: 1809: /* See if we should swap operands */ 1810: if (e1->Eoper == OPvar && e2->Eoper == OPvar && evalinregister(e2)) 1811: { e1 = e->E2; 1812: e2 = e->E1; 1813: reverse = 2; 1814: } 1815: 1816: retregs = allregs; 1817: if (byte) 1818: retregs = BYTEREGS; 1819: 1820: c = CNIL; 1821: ce = CNIL; 1822: cs.Iflags = (!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?
1823: cs.Irex = rex; 1824: if (sz > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
1825: ce = gennop(ce); 1826: 1827: switch (e2->Eoper) 1828: { 1829: default: 1830: L2: 1831: cl = scodelem(e1,&retregs,0,TRUE); /* compute left leaf */ 1832: L1:
warning C4102: 'L1' : unreferenced label
1833: rretregs = allregs & ~retregs; 1834: if (byte) 1835: rretregs &= BYTEREGS; 1836: cr = scodelem(e2,&rretregs,retregs,TRUE); /* get right leaf */ 1837: if (sz <= REGSIZE) /* CMP reg,rreg */
warning C4018: '<=' : signed/unsigned mismatch
1838: { reg = findreg(retregs); /* get reg that e1 is in */ 1839: rreg = findreg(rretregs); 1840: c = genregs(CNIL,0x3B ^ byte ^ reverse,reg,rreg); 1841: code_orrex(c, rex); 1842: 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?
1843: c->Iflags |= CFopsize; /* compare only 16 bits */ 1844: if (I64 && byte && (reg >= 4 || rreg >= 4)) 1845: c->Irex |= REX; // address byte registers 1846: } 1847: else 1848: { assert(sz <= 2 * REGSIZE);
warning C4018: '<=' : signed/unsigned mismatch
1849: 1850: /* Compare MSW, if they're equal then compare the LSW */ 1851: reg = findregmsw(retregs); 1852: rreg = findregmsw(rretregs); 1853: c = genregs(CNIL,0x3B ^ reverse,reg,rreg); /* CMP reg,rreg */ 1854: if (I32 && sz == 6) 1855: c->Iflags |= CFopsize; /* seg is only 16 bits */ 1856: else if (I64) 1857: code_orrex(c, REX_W); 1858: genjmp(c,JNE,FLcode,(block *) ce); /* JNE nop */ 1859: 1860: reg = findreglsw(retregs); 1861: rreg = findreglsw(rretregs); 1862: genregs(c,0x3B ^ reverse,reg,rreg); /* CMP reg,rreg */ 1863: if (I64) 1864: code_orrex(c, REX_W); 1865: } 1866: break; 1867: case OPrelconst: 1868: if (I64 && config.flags3 & CFG3pic) 1869: goto L2; 1870: fl = el_fl(e2); 1871: switch (fl) 1872: { case FLfunc: 1873: fl = FLextern; // so it won't be self-relative 1874: break; 1875: case FLdata: 1876: case FLudata: 1877: case FLextern: 1878: if (sz > REGSIZE) // compare against DS, not DGROUP
warning C4018: '>' : signed/unsigned mismatch
1879: goto L2; 1880: break; 1881: case FLfardata: 1882: break; 1883: default: 1884: goto L2; 1885: } 1886: cs.IFL2 = fl; 1887: cs.IEVsym2 = e2->EV.sp.Vsym; 1888: if (sz > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
1889: { cs.Iflags |= CFseg; 1890: cs.IEVoffset2 = 0; 1891: } 1892: else 1893: { cs.Iflags |= CFoff; 1894: cs.IEVoffset2 = e2->EV.sp.Voffset; 1895: } 1896: goto L4; 1897: 1898: case OPconst: 1899: // If compare against 0 1900: if (sz <= REGSIZE && *pretregs == mPSW && !boolres(e2) &&
warning C4018: '<=' : signed/unsigned mismatch
1901: isregvar(e1,&retregs,&reg) 1902: ) 1903: { // Just do a TEST instruction 1904: c = genregs(NULL,0x85 ^ byte,reg,reg); // TEST reg,reg 1905: c->Iflags |= (cs.Iflags & CFopsize) | CFpsw; 1906: code_orrex(c, rex); 1907: if (I64 && byte && reg >= 4) 1908: c->Irex |= REX; // address byte registers 1909: retregs = mPSW; 1910: break; 1911: } 1912: 1913: if (!tyuns(tym) && !tyuns(e2->Ety) && 1914: !boolres(e2) && !(*pretregs & mPSW) && 1915: (sz == REGSIZE || (I64 && sz == 4)) &&
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1916: (!I16 || op == OPlt || op == OPge))
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
1917: { 1918: assert(*pretregs & (allregs)); 1919: cl = codelem(e1,pretregs,FALSE); 1920: reg = findreg(*pretregs); 1921: c = getregs(mask[reg]); 1922: switch (op) 1923: { case OPle: 1924: c = genc2(c,0x81,grex | modregrmx(3,0,reg & 7),(unsigned)-1); // ADD reg,-1 1925: genc2(c,0x81,grex | modregrmx(3,2,reg & 7),0); // ADC reg,0 1926: goto oplt; 1927: case OPgt: 1928: c = gen2(c,0xF7,grex | modregrmx(3,3,reg & 7)); // NEG reg 1929: #if TARGET_WINDOS 1930: // What does the Windows platform do? 1931: // lower INT_MIN by 1? See test exe9.c 1932: // BUG: fix later 1933: genc2(c,0x81,grex | modregrmx(3,3,reg),0); // SBB reg,0 1934: #endif 1935: goto oplt; 1936: case OPlt: 1937: oplt: 1938: if (!I16) 1939: c = genc2(c,0xC1,grex | modregrmx(3,5,reg),sz * 8 - 1); // SHR reg,31 1940: else 1941: { /* 8088-286 do not have a barrel shifter, so use this 1942: faster sequence 1943: */ 1944: c = genregs(c,0xD1,0,reg); /* ROL reg,1 */ 1945: unsigned regi; 1946: if (reghasvalue(allregs,1,&regi)) 1947: c = genregs(c,0x23,reg,regi); /* AND reg,regi */ 1948: else 1949: c = genc2(c,0x81,modregrm(3,4,reg),1); /* AND reg,1 */ 1950: } 1951: break; 1952: case OPge: 1953: c = genregs(c,0xD1,4,reg); /* SHL reg,1 */ 1954: code_orrex(c,rex); 1955: genregs(c,0x19,reg,reg); /* SBB reg,reg */ 1956: code_orrex(c,rex); 1957: if (I64) 1958: { 1959: c = gen2(c,0xFF,modregrmx(3,0,reg)); // INC reg 1960: code_orrex(c, rex); 1961: } 1962: else 1963: c = gen1(c,0x40 + reg); // INC reg 1964: break; 1965: 1966: default: 1967: assert(0); 1968: } 1969: freenode(e2); 1970: goto ret; 1971: } 1972: 1973: cs.IFL2 = FLconst; 1974: if (sz == 16) 1975: cs.IEV2.Vsize_t = e2->EV.Vcent.msw;
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_size_t', possible loss of data
1976: else if (sz > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
1977: cs.IEV2.Vint = MSREG(e2->EV.Vllong);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_int', possible loss of data
1978: else 1979: cs.IEV2.Vsize_t = e2->EV.Vllong;
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1980: 1981: // The cmp immediate relies on sign extension of the 32 bit immediate value 1982: if (I64 && sz >= REGSIZE && cs.IEV2.Vsize_t != (int)cs.IEV2.Vint)
warning C4018: '>=' : signed/unsigned mismatch
1983: goto L2; 1984: L4: 1985: cs.Iop = 0x81 ^ byte; 1986: 1987: /* if ((e1 is data or a '*' reference) and it's not a 1988: * common subexpression 1989: */ 1990: 1991: if ((e1->Eoper == OPvar && datafl[el_fl(e1)] || 1992: e1->Eoper == OPind) && 1993: !evalinregister(e1)) 1994: { cl = getlvalue(&cs,e1,RMload); 1995: freenode(e1); 1996: if (evalinregister(e2)) 1997: { 1998: retregs = idxregm(&cs); 1999: if ((cs.Iflags & CFSEG) == CFes) 2000: retregs |= mES; /* take no chances */ 2001: rretregs = allregs & ~retregs; 2002: if (byte) 2003: rretregs &= BYTEREGS; 2004: cr = scodelem(e2,&rretregs,retregs,TRUE); 2005: cs.Iop = 0x39 ^ byte ^ reverse; 2006: if (sz > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
2007: { 2008: rreg = findregmsw(rretregs); 2009: cs.Irm |= modregrm(0,rreg,0); 2010: getlvalue_msw(&cs); 2011: c = gen(CNIL,&cs); /* CMP EA+2,rreg */ 2012: if (I32 && sz == 6) 2013: c->Iflags |= CFopsize; /* seg is only 16 bits */ 2014: if (I64 && byte && rreg >= 4) 2015: c->Irex |= REX; 2016: genjmp(c,JNE,FLcode,(block *) ce); /* JNE nop */ 2017: rreg = findreglsw(rretregs); 2018: NEWREG(cs.Irm,rreg); 2019: getlvalue_lsw(&cs); 2020: } 2021: else 2022: { 2023: rreg = findreg(rretregs); 2024: code_newreg(&cs, rreg); 2025: if (I64 && byte && rreg >= 4) 2026: cs.Irex |= REX; 2027: } 2028: } 2029: else 2030: { 2031: cs.Irm |= modregrm(0,7,0); 2032: if (sz > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
2033: { 2034: #if TARGET_FLAT 2035: if (sz == 6) 2036: assert(0); 2037: #endif 2038: if (e2->Eoper == OPrelconst) 2039: { cs.Iflags = (cs.Iflags & ~(CFoff | CFseg)) | CFseg; 2040: cs.IEVoffset2 = 0; 2041: } 2042: getlvalue_msw(&cs); 2043: c = gen(CNIL,&cs); /* CMP EA+2,const */ 2044: if (!I16 && sz == 6)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2045: c->Iflags |= CFopsize; /* seg is only 16 bits */ 2046: genjmp(c,JNE,FLcode,(block *) ce); /* JNE nop */ 2047: if (e2->Eoper == OPconst) 2048: cs.IEV2.Vint = e2->EV.Vllong;
warning C4244: '=' : conversion from 'targ_llong' to 'targ_int', possible loss of data
2049: else if (e2->Eoper == OPrelconst) 2050: { /* Turn off CFseg, on CFoff */ 2051: cs.Iflags ^= CFseg | CFoff; 2052: cs.IEVoffset2 = e2->EV.sp.Voffset; 2053: } 2054: else 2055: assert(0); 2056: getlvalue_lsw(&cs); 2057: } 2058: freenode(e2); 2059: } 2060: c = gen(c,&cs); 2061: break; 2062: } 2063: 2064: if (evalinregister(e2) && !OTassign(e1->Eoper) && 2065: !isregvar(e1,NULL,NULL)) 2066: { regm_t m; 2067: 2068: m = allregs & ~regcon.mvar; 2069: if (byte) 2070: m &= BYTEREGS; 2071: if (m & (m - 1)) // if more than one free register 2072: goto L2; 2073: } 2074: if ((e1->Eoper == OPstrcmp || (OTassign(e1->Eoper) && sz <= REGSIZE)) &&
warning C4018: '<=' : signed/unsigned mismatch
2075: !boolres(e2) && !evalinregister(e1)) 2076: { 2077: retregs = mPSW; 2078: cl = scodelem(e1,&retregs,0,FALSE); 2079: freenode(e2); 2080: break; 2081: } 2082: if (sz <= REGSIZE && !boolres(e2) && e1->Eoper == OPadd && *pretregs == mPSW)
warning C4018: '<=' : signed/unsigned mismatch
2083: { 2084: retregs |= mPSW; 2085: cl = scodelem(e1,&retregs,0,FALSE); 2086: freenode(e2); 2087: break; 2088: } 2089: cl = scodelem(e1,&retregs,0,TRUE); /* compute left leaf */ 2090: if (sz == 1) 2091: { 2092: reg = findreg(retregs & allregs); // get reg that e1 is in 2093: cs.Irm = modregrm(3,7,reg & 7); 2094: if (reg & 8) 2095: cs.Irex |= REX_B; 2096: if (e1->Eoper == OPvar && e1->EV.sp.Voffset == 1 && e1->EV.sp.Vsym->Sfl == FLreg) 2097: { assert(reg < 4); 2098: cs.Irm |= 4; // use upper register half 2099: } 2100: if (I64 && reg >= 4) 2101: cs.Irex |= REX; // address byte registers 2102: } 2103: else if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2104: { /* CMP reg,const */ 2105: reg = findreg(retregs & allregs); // get reg that e1 is in 2106: rretregs = allregs & ~retregs; 2107: if (cs.IFL2 == FLconst && reghasvalue(rretregs,cs.IEV2.Vint,&rreg)) 2108: { 2109: code *cc = genregs(CNIL,0x3B,reg,rreg); 2110: code_orrex(cc, rex); 2111: if (!I16) 2112: cc->Iflags |= cs.Iflags & CFopsize; 2113: c = cat(c,cc); 2114: freenode(e2); 2115: break; 2116: } 2117: cs.Irm = modregrm(3,7,reg & 7); 2118: if (reg & 8) 2119: cs.Irex |= REX_B; 2120: } 2121: else if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2122: { 2123: reg = findregmsw(retregs); // get reg that e1 is in 2124: cs.Irm = modregrm(3,7,reg); 2125: c = gen(CNIL,&cs); /* CMP reg,MSW */ 2126: if (I32 && sz == 6) 2127: c->Iflags |= CFopsize; /* seg is only 16 bits */ 2128: genjmp(c,JNE,FLcode,(block *) ce); /* JNE ce */ 2129: 2130: reg = findreglsw(retregs); 2131: cs.Irm = modregrm(3,7,reg); 2132: if (e2->Eoper == OPconst) 2133: cs.IEV2.Vint = e2->EV.Vlong; 2134: else if (e2->Eoper == OPrelconst) 2135: { /* Turn off CFseg, on CFoff */ 2136: cs.Iflags ^= CFseg | CFoff; 2137: cs.IEVoffset2 = e2->EV.sp.Voffset; 2138: } 2139: else 2140: assert(0); 2141: } 2142: else 2143: assert(0); 2144: c = gen(c,&cs); /* CMP sucreg,LSW */ 2145: freenode(e2); 2146: break; 2147: 2148: case OPind: 2149: if (e2->Ecount) 2150: goto L2; 2151: goto L5; 2152: 2153: case OPvar: 2154: if ((e1->Eoper == OPvar && 2155: isregvar(e2,&rretregs,&reg) && 2156: sz <= REGSIZE 2157: ) ||
warning C4018: '<=' : signed/unsigned mismatch
2158: (e1->Eoper == OPind && 2159: isregvar(e2,&rretregs,&reg) && 2160: !evalinregister(e1) && 2161: sz <= REGSIZE 2162: )
warning C4018: '<=' : signed/unsigned mismatch
2163: ) 2164: { 2165: // CMP EA,e2 2166: cl = getlvalue(&cs,e1,RMload); 2167: freenode(e1); 2168: cs.Iop = 0x39 ^ byte ^ reverse; 2169: code_newreg(&cs,reg); 2170: if (I64 && byte && reg >= 4) 2171: cs.Irex |= REX; // address byte registers 2172: c = gen(c,&cs); 2173: freenode(e2); 2174: break; 2175: } 2176: L5: 2177: cl = scodelem(e1,&retregs,0,TRUE); /* compute left leaf */ 2178: if (sz <= REGSIZE) /* CMP reg,EA */
warning C4018: '<=' : signed/unsigned mismatch
2179: { 2180: reg = findreg(retregs & allregs); // get reg that e1 is in 2181: unsigned opsize = cs.Iflags & CFopsize; 2182: c = cat(c,loadea(e2,&cs,0x3B ^ byte ^ reverse,reg,0,RMload | retregs,0)); 2183: code_orflag(c,opsize); 2184: } 2185: else if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2186: { 2187: reg = findregmsw(retregs); /* get reg that e1 is in */ 2188: // CMP reg,EA 2189: c = loadea(e2,&cs,0x3B ^ reverse,reg,REGSIZE,RMload | retregs,0); 2190: if (I32 && sz == 6) 2191: c->Iflags |= CFopsize; /* seg is only 16 bits */ 2192: genjmp(c,JNE,FLcode,(block *) ce); /* JNE ce */ 2193: reg = findreglsw(retregs); 2194: if (e2->Eoper == OPind) 2195: { 2196: NEWREG(cs.Irm,reg); 2197: getlvalue_lsw(&cs); 2198: c = gen(c,&cs); 2199: } 2200: else 2201: c = cat(c,loadea(e2,&cs,0x3B ^ reverse,reg,0,RMload | retregs,0)); 2202: } 2203: else 2204: assert(0); 2205: freenode(e2); 2206: break; 2207: } 2208: c = cat(c,ce); 2209: 2210: L3: 2211: if ((retregs = (*pretregs & (ALLREGS | mBP))) != 0) // if return result in register 2212: { code *nop = CNIL; 2213: regm_t save = regcon.immed.mval; 2214: cg = allocreg(&retregs,&reg,TYint); 2215: regcon.immed.mval = save; 2216: if ((*pretregs & mPSW) == 0 && 2217: (jop == JC || jop == JNC)) 2218: { 2219: cg = cat(cg,getregs(retregs)); 2220: cg = genregs(cg,0x19,reg,reg); /* SBB reg,reg */ 2221: if (rex) 2222: code_orrex(cg, rex); 2223: if (flag) 2224: ; // cdcond() will handle it 2225: else if (jop == JNC) 2226: { 2227: if (I64) 2228: { 2229: cg = gen2(cg,0xFF,modregrmx(3,0,reg)); // INC reg 2230: code_orrex(cg, rex); 2231: } 2232: else 2233: gen1(cg,0x40 + reg); // INC reg 2234: } 2235: else 2236: { gen2(cg,0xF7,modregrmx(3,3,reg)); /* NEG reg */ 2237: code_orrex(cg, rex); 2238: } 2239: } 2240: else if (I64 && sz == 8) 2241: { 2242: assert(!flag); 2243: cg = movregconst(cg,reg,1,64|8); // MOV reg,1 2244: nop = gennop(nop); 2245: cg = genjmp(cg,jop,FLcode,(block *) nop); // Jtrue nop 2246: // MOV reg,0 2247: movregconst(cg,reg,0,(*pretregs & mPSW) ? 64|8 : 64); 2248: regcon.immed.mval &= ~mask[reg]; 2249: } 2250: else 2251: { 2252: assert(!flag); 2253: cg = movregconst(cg,reg,1,8); // MOV reg,1 2254: nop = gennop(nop); 2255: cg = genjmp(cg,jop,FLcode,(block *) nop); // Jtrue nop 2256: // MOV reg,0 2257: movregconst(cg,reg,0,(*pretregs & mPSW) ? 8 : 0); 2258: regcon.immed.mval &= ~mask[reg]; 2259: } 2260: *pretregs = retregs; 2261: c = cat3(c,cg,nop); 2262: } 2263: ret: 2264: return cat3(cl,cr,c); 2265: } 2266: 2267: 2268: /********************************** 2269: * Generate code for signed compare of longs. 2270: * Input: 2271: * targ block* or code* 2272: */ 2273: 2274: code *longcmp(elem *e,bool jcond,unsigned fltarg,code *targ) 2275: { regm_t retregs,rretregs; 2276: unsigned reg,rreg,op,jop; 2277: code *cl,*cr,*c,cs,*ce; 2278: code *cmsw,*clsw; 2279: elem *e1,*e2; 2280: /* <= > < >= */ 2281: static const unsigned char jopmsw[4] = {JL, JG, JL, JG }; 2282: static const unsigned char joplsw[4] = {JBE, JA, JB, JAE }; 2283: 2284: cr = CNIL; 2285: e1 = e->E1; 2286: e2 = e->E2; 2287: op = e->Eoper; 2288: 2289: /* See if we should swap operands */ 2290: if (e1->Eoper == OPvar && e2->Eoper == OPvar && evalinregister(e2)) 2291: { e1 = e->E2; 2292: e2 = e->E1; 2293: op = swaprel(op); 2294: } 2295: 2296: cs.Iflags = 0; 2297: cs.Irex = 0; 2298: 2299: ce = gennop(CNIL); 2300: retregs = ALLREGS; 2301: 2302: switch (e2->Eoper) 2303: { 2304: default: 2305: L2: 2306: cl = scodelem(e1,&retregs,0,TRUE); /* compute left leaf */ 2307: rretregs = ALLREGS & ~retregs; 2308: cr = scodelem(e2,&rretregs,retregs,TRUE); /* get right leaf */ 2309: /* Compare MSW, if they're equal then compare the LSW */ 2310: reg = findregmsw(retregs); 2311: rreg = findregmsw(rretregs); 2312: cmsw = genregs(CNIL,0x3B,reg,rreg); /* CMP reg,rreg */ 2313: 2314: reg = findreglsw(retregs); 2315: rreg = findreglsw(rretregs); 2316: clsw = genregs(CNIL,0x3B,reg,rreg); /* CMP reg,rreg */ 2317: break; 2318: case OPconst: 2319: cs.IEV2.Vint = MSREG(e2->EV.Vllong); // MSW first
warning C4244: '=' : conversion from 'targ_llong' to 'targ_int', possible loss of data
2320: cs.IFL2 = FLconst; 2321: cs.Iop = 0x81; 2322: 2323: /* if ((e1 is data or a '*' reference) and it's not a 2324: * common subexpression 2325: */ 2326: 2327: if ((e1->Eoper == OPvar && datafl[el_fl(e1)] || 2328: e1->Eoper == OPind) && 2329: !evalinregister(e1)) 2330: { cl = getlvalue(&cs,e1,0); 2331: freenode(e1); 2332: if (evalinregister(e2)) 2333: { 2334: retregs = idxregm(&cs); 2335: if ((cs.Iflags & CFSEG) == CFes) 2336: retregs |= mES; /* take no chances */ 2337: rretregs = ALLREGS & ~retregs; 2338: cr = scodelem(e2,&rretregs,retregs,TRUE); 2339: rreg = findregmsw(rretregs); 2340: cs.Iop = 0x39; 2341: cs.Irm |= modregrm(0,rreg,0); 2342: getlvalue_msw(&cs); 2343: cmsw = gen(CNIL,&cs); /* CMP EA+2,rreg */ 2344: rreg = findreglsw(rretregs); 2345: NEWREG(cs.Irm,rreg); 2346: } 2347: else 2348: { cs.Irm |= modregrm(0,7,0); 2349: getlvalue_msw(&cs); 2350: cmsw = gen(CNIL,&cs); /* CMP EA+2,const */ 2351: cs.IEV2.Vint = e2->EV.Vlong; 2352: freenode(e2); 2353: } 2354: getlvalue_lsw(&cs); 2355: clsw = gen(CNIL,&cs); /* CMP EA,rreg/const */ 2356: break; 2357: } 2358: if (evalinregister(e2)) 2359: goto L2; 2360: 2361: cl = scodelem(e1,&retregs,0,TRUE); /* compute left leaf */ 2362: reg = findregmsw(retregs); /* get reg that e1 is in */ 2363: cs.Irm = modregrm(3,7,reg); 2364: 2365: cmsw = gen(CNIL,&cs); /* CMP reg,MSW */ 2366: reg = findreglsw(retregs); 2367: cs.Irm = modregrm(3,7,reg); 2368: cs.IEV2.Vint = e2->EV.Vlong; 2369: clsw = gen(CNIL,&cs); /* CMP sucreg,LSW */ 2370: freenode(e2); 2371: break; 2372: case OPvar: 2373: if (!e1->Ecount && e1->Eoper == OPs32_64) 2374: { unsigned msreg; 2375: 2376: retregs = allregs; 2377: cl = scodelem(e1->E1,&retregs,0,TRUE); 2378: freenode(e1); 2379: reg = findreg(retregs); 2380: retregs = allregs & ~retregs; 2381: cr = allocreg(&retregs,&msreg,TYint); 2382: cr = genmovreg(cr,msreg,reg); // MOV msreg,reg 2383: cr = genc2(cr,0xC1,modregrm(3,7,msreg),REGSIZE * 8 - 1); // SAR msreg,31 2384: cmsw = loadea(e2,&cs,0x3B,msreg,REGSIZE,mask[reg],0); 2385: clsw = loadea(e2,&cs,0x3B,reg,0,mask[reg],0); 2386: freenode(e2); 2387: } 2388: else 2389: { 2390: cl = scodelem(e1,&retregs,0,TRUE); // compute left leaf 2391: reg = findregmsw(retregs); // get reg that e1 is in 2392: cmsw = loadea(e2,&cs,0x3B,reg,REGSIZE,retregs,0); 2393: reg = findreglsw(retregs); 2394: clsw = loadea(e2,&cs,0x3B,reg,0,retregs,0); 2395: freenode(e2); 2396: } 2397: break; 2398: } 2399: 2400: jop = jopmsw[op - OPle]; 2401: if (!(jcond & 1)) jop ^= (JL ^ JG); // toggle jump condition 2402: genjmp(cmsw,jop,fltarg,(block *) targ); /* Jx targ */ 2403: genjmp(cmsw,jop ^ (JL ^ JG),FLcode,(block *) ce); /* Jy nop */ 2404: 2405: jop = joplsw[op - OPle]; 2406: if (!(jcond & 1)) jop ^= 1; // toggle jump condition 2407: genjmp(clsw,jop,fltarg,(block *) targ); /* Jcond targ */ 2408: 2409: c = cse_flush(1); // flush CSE's to memory 2410: freenode(e); 2411: return cat6(cl,cr,c,cmsw,clsw,ce); 2412: } 2413: 2414: /***************************** 2415: * Do conversions. 2416: * Depends on OPd_s32 and CLIBdbllng being in sequence. 2417: */ 2418: 2419: code *cdcnvt(elem *e, regm_t *pretregs) 2420: { regm_t retregs; 2421: code *c1,*c2; 2422: int i; 2423: static unsigned char clib[][2] = 2424: { OPd_s32, CLIBdbllng, 2425: OPs32_d, CLIBlngdbl, 2426: OPdblint, CLIBdblint, 2427: OPs16_d, CLIBintdbl, 2428: OPdbluns, CLIBdbluns, 2429: OPu16_d, CLIBunsdbl, 2430: OPd_u32, CLIBdblulng, 2431: #if TARGET_WINDOS 2432: OPu32_d, CLIBulngdbl, 2433: #endif 2434: OPd_s64, CLIBdblllng, 2435: OPs64_d, CLIBllngdbl, 2436: OPd_u64, CLIBdblullng, 2437: OPu64_d, CLIBullngdbl, 2438: OPd_f, CLIBdblflt, 2439: OPf_d, CLIBfltdbl, 2440: OPvptrfptr, CLIBvptrfptr, 2441: OPcvptrfptr, CLIBcvptrfptr, 2442: }; 2443: 2444: //printf("cdcnvt: *pretregs = %s\n", regm_str(*pretregs)); 2445: //elem_print(e); 2446: 2447: if (!*pretregs) 2448: return codelem(e->E1,pretregs,FALSE); 2449: if (config.inline8087) 2450: { switch (e->Eoper) 2451: { 2452: case OPld_d: 2453: case OPd_ld: 2454: if (tycomplex(e->E1->Ety)) 2455: { 2456: Lcomplex: 2457: retregs = mST01 | (*pretregs & mPSW); 2458: c1 = codelem(e->E1, &retregs, FALSE); 2459: c2 = fixresult_complex87(e, retregs, pretregs); 2460: return cat(c1, c2); 2461: } 2462: retregs = mST0 | (*pretregs & mPSW); 2463: c1 = codelem(e->E1, &retregs, FALSE); 2464: c2 = fixresult87(e, retregs, pretregs); 2465: return cat(c1, c2); 2466: 2467: case OPf_d: 2468: case OPd_f: 2469: if (I64 && *pretregs & XMMREGS) 2470: { 2471: c1 = codelem(e->E1,pretregs,FALSE); 2472: unsigned reg = findreg(*pretregs) - XMM0; 2473: if (e->Eoper == OPf_d) 2474: { /* 0F 14 C0 UNPCKLPS XMM0,XMM0 2475: * 0F 5A C0 CVTPS2PD XMM0,XMM0 2476: */ 2477: c1 = gen2(c1, 0x0F14, modregrm(3,reg,reg)); 2478: c1 = gen2(c1, 0x0F5A, modregrm(3,reg,reg)); 2479: } 2480: else // OPd_f 2481: { /* 66 0F 14 C0 UPPCKLPD XMM0,XMM0 2482: * 66 0F 5A C0 CVTPD2PS XMM0,XMM0 2483: */ 2484: c1 = gen2(c1, 0x660F14, modregrm(3,reg,reg)); 2485: c1 = gen2(c1, 0x660F5A, modregrm(3,reg,reg)); 2486: } 2487: return c1; 2488: } 2489: /* if won't do us much good to transfer back and */ 2490: /* forth between 8088 registers and 8087 registers */ 2491: if (OTcall(e->E1->Eoper) && !(*pretregs & allregs)) 2492: { 2493: retregs = regmask(e->E1->Ety, e->E1->E1->Ety); 2494: if (retregs & (mXMM1 | mXMM0 |mST01 | mST0)) // if return in ST0 2495: { 2496: c1 = codelem(e->E1,pretregs,FALSE); 2497: if (*pretregs & mST0) 2498: note87(e, 0, 0); 2499: return c1; 2500: } 2501: else 2502: break; 2503: } 2504: if (tycomplex(e->E1->Ety)) 2505: goto Lcomplex; 2506: /* FALL-THROUGH */ 2507: case OPs64_d: 2508: case OPs32_d: 2509: case OPs16_d: 2510: case OPu16_d: 2511: return load87(e,0,pretregs,NULL,-1); 2512: case OPu32_d: 2513: if (!I16) 2514: { 2515: unsigned retregs = ALLREGS;
warning C6246: Local declaration of 'retregs' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '2420' of 'c:\projects\extern\d\dmd\src\backend\cod4.c': Lines: 2420
2516: c1 = codelem(e->E1, &retregs, FALSE); 2517: unsigned reg = findreg(retregs); 2518: c1 = genfltreg(c1, 0x89, reg, 0); 2519: regwithvalue(c1,ALLREGS,0,&reg,0); 2520: genfltreg(c1, 0x89, reg, 4); 2521: 2522: cat(c1, push87()); 2523: genfltreg(c1,0xDF,5,0); // FILD m64int 2524: 2525: retregs = mST0 /*| (*pretregs & mPSW)*/; 2526: c2 = fixresult87(e, retregs, pretregs); 2527: return cat(c1, c2); 2528: } 2529: break; 2530: case OPd_s16: 2531: case OPd_s32: 2532: case OPd_u16: 2533: case OPd_s64: 2534: return cnvt87(e,pretregs); 2535: case OPd_u32: // use subroutine, not 8087 2536: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 2537: retregs = mST0; 2538: #else 2539: retregs = DOUBLEREGS; 2540: #endif 2541: goto L1; 2542: 2543: case OPd_u64: 2544: retregs = DOUBLEREGS; 2545: goto L1; 2546: case OPu64_d: 2547: if (*pretregs & mST0) 2548: { 2549: retregs = I64 ? mAX : mAX|mDX; 2550: c1 = codelem(e->E1,&retregs,FALSE); 2551: c2 = callclib(e,CLIBu64_ldbl,pretregs,0); 2552: return cat(c1,c2); 2553: } 2554: break; 2555: case OPld_u64: 2556: retregs = mST0; 2557: c1 = codelem(e->E1,&retregs,FALSE); 2558: c2 = callclib(e,CLIBld_u64,pretregs,0); 2559: return cat(c1,c2); 2560: } 2561: } 2562: retregs = regmask(e->E1->Ety, TYnfunc); 2563: L1: 2564: c1 = codelem(e->E1,&retregs,FALSE); 2565: for (i = 0; 1; i++) 2566: { assert(i < arraysize(clib)); 2567: if (clib[i][0] == e->Eoper) 2568: { c2 = callclib(e,clib[i][1],pretregs,0); 2569: break; 2570: } 2571: } 2572: return cat(c1,c2); 2573: } 2574: 2575: 2576: /*************************** 2577: * Convert short to long. 2578: * For OPs16_32, OPu16_32, OPptrlptr, OPu32_64, OPs32_64 2579: */ 2580: 2581: code *cdshtlng(elem *e,regm_t *pretregs) 2582: { code *c,*ce,*c1,*c2,*c3,*c4; 2583: unsigned reg; 2584: unsigned char op; 2585: regm_t retregs; 2586: 2587: //printf("cdshtlng(e = %p, *pretregs = %s)\n", e, regm_str(*pretregs)); 2588: int e1comsub = e->E1->Ecount; 2589: if ((*pretregs & (ALLREGS | mBP)) == 0) // if don't need result in regs 2590: c = codelem(e->E1,pretregs,FALSE); /* then conversion isn't necessary */ 2591: 2592: else if ((op = e->Eoper) == OPptrlptr || 2593: (I16 && op == OPu16_32) || 2594: (I32 && op == OPu32_64) 2595: ) 2596: { 2597: regm_t regm; 2598: tym_t tym1; 2599: 2600: retregs = *pretregs & mLSW; 2601: assert(retregs); 2602: tym1 = tybasic(e->E1->Ety); 2603: c = codelem(e->E1,&retregs,FALSE); 2604: 2605: regm = *pretregs & (mMSW & ALLREGS); 2606: if (regm == 0) /* *pretregs could be mES */ 2607: regm = mMSW & ALLREGS; 2608: ce = allocreg(&regm,&reg,TYint); 2609: if (e1comsub) 2610: ce = cat(ce,getregs(retregs)); 2611: if (op == OPptrlptr) 2612: { int segreg; 2613: 2614: /* BUG: what about pointers to functions? */ 2615: switch (tym1) 2616: { 2617: case TYnptr: segreg = SEG_DS; break; 2618: case TYcptr: segreg = SEG_CS; break; 2619: case TYsptr: segreg = SEG_SS; break; 2620: default: assert(0); 2621: } 2622: ce = gen2(ce,0x8C,modregrm(3,segreg,reg)); /* MOV reg,segreg */ 2623: } 2624: else 2625: ce = movregconst(ce,reg,0,0); /* 0 extend */ 2626: 2627: c = cat3(c,ce,fixresult(e,retregs | regm,pretregs)); 2628: } 2629: else if (I64 && op == OPu32_64) 2630: { 2631: elem *e1 = e->E1; 2632: retregs = *pretregs; 2633: if (e1->Eoper == OPvar || (e1->Eoper == OPind && !e1->Ecount)) 2634: { code cs; 2635: 2636: c1 = allocreg(&retregs,&reg,TYint); 2637: c2 = NULL; 2638: c3 = loadea(e1,&cs,0x8B,reg,0,retregs,retregs); // MOV Ereg,EA 2639: freenode(e1); 2640: } 2641: else 2642: { 2643: *pretregs &= ~mPSW; // flags are set by eval of e1 2644: c1 = codelem(e1,&retregs,FALSE); 2645: c2 = getregs(retregs); 2646: reg = findreg(retregs); 2647: c3 = genregs(NULL,0x89,reg,reg); // MOV Ereg,Ereg 2648: } 2649: c4 = fixresult(e,retregs,pretregs); 2650: c = cat4(c1,c2,c3,c4); 2651: } 2652: else if (!I16 && (op == OPs16_32 || op == OPu16_32) ||
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2653: I64 && op == OPs32_64) 2654: { 2655: elem *e11; 2656: 2657: elem *e1 = e->E1; 2658: 2659: if (e1->Eoper == OPu8_16 && !e1->Ecount && 2660: ((e11 = e1->E1)->Eoper == OPvar || (e11->Eoper == OPind && !e11->Ecount)) 2661: ) 2662: { code cs; 2663: 2664: retregs = *pretregs & BYTEREGS; 2665: if (!retregs) 2666: retregs = BYTEREGS; 2667: c1 = allocreg(&retregs,&reg,TYint); 2668: c2 = movregconst(NULL,reg,0,0); // XOR reg,reg 2669: c3 = loadea(e11,&cs,0x8A,reg,0,retregs,retregs); // MOV regL,EA 2670: freenode(e11); 2671: freenode(e1); 2672: } 2673: else if (e1->Eoper == OPvar || 2674: (e1->Eoper == OPind && !e1->Ecount)) 2675: { code cs; 2676: unsigned opcode; 2677: 2678: if (op == OPu16_32 && config.flags4 & CFG4speed) 2679: goto L2; 2680: retregs = *pretregs; 2681: c1 = allocreg(&retregs,&reg,TYint); 2682: opcode = (op == OPu16_32) ? 0x0FB7 : 0x0FBF; /* MOVZX/MOVSX reg,EA */ 2683: if (op == OPs32_64) 2684: { 2685: assert(I64); 2686: // MOVSXD reg,e1 2687: c2 = loadea(e1,&cs,0x63,reg,0,0,retregs); 2688: code_orrex(c2, REX_W); 2689: } 2690: else 2691: c2 = loadea(e1,&cs,opcode,reg,0,0,retregs); 2692: c3 = CNIL; 2693: freenode(e1); 2694: } 2695: else 2696: { 2697: L2: 2698: retregs = *pretregs; 2699: if (op == OPs32_64) 2700: retregs = mAX | (*pretregs & mPSW); 2701: *pretregs &= ~mPSW; /* flags are already set */ 2702: c1 = codelem(e1,&retregs,FALSE); 2703: c2 = getregs(retregs); 2704: if (op == OPu16_32 && c1) 2705: { 2706: code *cx = code_last(c1); 2707: if (cx->Iop == 0x81 && (cx->Irm & modregrm(3,7,0)) == modregrm(3,4,0)) 2708: { 2709: // Convert AND of a word to AND of a dword, zeroing upper word 2710: retregs = mask[cx->Irm & 7]; 2711: if (cx->Irex & REX_B) 2712: retregs = mask[8 | (cx->Irm & 7)]; 2713: cx->Iflags &= ~CFopsize; 2714: cx->IEV2.Vint &= 0xFFFF; 2715: goto L1; 2716: } 2717: } 2718: if (op == OPs16_32 && retregs == mAX) 2719: c2 = gen1(c2,0x98); /* CWDE */ 2720: else if (op == OPs32_64 && retregs == mAX) 2721: { c2 = gen1(c2,0x98); /* CDQE */ 2722: code_orrex(c2, REX_W); 2723: } 2724: else 2725: { 2726: reg = findreg(retregs); 2727: if (config.flags4 & CFG4speed && op == OPu16_32) 2728: { // AND reg,0xFFFF 2729: c3 = genc2(NULL,0x81,modregrmx(3,4,reg),0xFFFFu); 2730: } 2731: else 2732: { 2733: unsigned iop = (op == OPu16_32) ? 0x0FB7 : 0x0FBF; /* MOVZX/MOVSX reg,reg */ 2734: c3 = genregs(CNIL,iop,reg,reg); 2735: } 2736: c2 = cat(c2,c3); 2737: } 2738: L1: 2739: c3 = e1comsub ? getregs(retregs) : CNIL; 2740: } 2741: c4 = fixresult(e,retregs,pretregs); 2742: c = cat4(c1,c2,c3,c4); 2743: } 2744: else if (*pretregs & mPSW || config.target_cpu < TARGET_80286) 2745: { 2746: // OPs16_32, OPs32_64 2747: // CWD doesn't affect flags, so we can depend on the integer 2748: // math to provide the flags. 2749: retregs = mAX | mPSW; // want integer result in AX 2750: *pretregs &= ~mPSW; // flags are already set 2751: c1 = codelem(e->E1,&retregs,FALSE); 2752: c2 = getregs(mDX); // sign extend into DX 2753: c2 = gen1(c2,0x99); // CWD/CDQ 2754: c3 = e1comsub ? getregs(retregs) : CNIL; 2755: c4 = fixresult(e,mDX | retregs,pretregs); 2756: c = cat4(c1,c2,c3,c4); 2757: } 2758: else 2759: { 2760: // OPs16_32, OPs32_64 2761: unsigned msreg,lsreg; 2762: 2763: retregs = *pretregs & mLSW; 2764: assert(retregs); 2765: c1 = codelem(e->E1,&retregs,FALSE); 2766: retregs |= *pretregs & mMSW; 2767: c2 = allocreg(&retregs,&reg,e->Ety); 2768: msreg = findregmsw(retregs); 2769: lsreg = findreglsw(retregs); 2770: c3 = genmovreg(NULL,msreg,lsreg); // MOV msreg,lsreg 2771: assert(config.target_cpu >= TARGET_80286); // 8088 can't handle SAR reg,imm8 2772: c3 = genc2(c3,0xC1,modregrm(3,7,msreg),REGSIZE * 8 - 1); // SAR msreg,31 2773: c4 = fixresult(e,retregs,pretregs); 2774: c = cat4(c1,c2,c3,c4); 2775: } 2776: return c; 2777: } 2778: 2779: 2780: /*************************** 2781: * Convert byte to int. 2782: * For OPu8int and OPs8int. 2783: */ 2784: 2785: code *cdbyteint(elem *e,regm_t *pretregs) 2786: { code *c,*c0,*c1,*c2,*c3,*c4; 2787: regm_t retregs; 2788: unsigned reg; 2789: char op; 2790: char size; 2791: elem *e1; 2792: 2793: 2794: if ((*pretregs & (ALLREGS | mBP)) == 0) // if don't need result in regs 2795: return codelem(e->E1,pretregs,FALSE); /* then conversion isn't necessary */ 2796: 2797: //printf("cdbyteint(e = %p, *pretregs = %s\n", e, regm_str(*pretregs)); 2798: op = e->Eoper; 2799: e1 = e->E1; 2800: c0 = NULL; 2801: if (e1->Eoper == OPcomma) 2802: c0 = docommas(&e1); 2803: if (!I16) 2804: { 2805: if (e1->Eoper == OPvar || (e1->Eoper == OPind && !e1->Ecount)) 2806: { code cs; 2807: unsigned opcode; 2808: 2809: retregs = *pretregs; 2810: c1 = allocreg(&retregs,&reg,TYint); 2811: if (config.flags4 & CFG4speed && 2812: op == OPu8int && mask[reg] & BYTEREGS && 2813: config.target_cpu < TARGET_PentiumPro) 2814: { 2815: c2 = movregconst(NULL,reg,0,0); // XOR reg,reg 2816: c3 = loadea(e1,&cs,0x8A,reg,0,retregs,retregs); // MOV regL,EA 2817: } 2818: else 2819: { 2820: opcode = (op == OPu8int) ? 0x0FB6 : 0x0FBE; // MOVZX/MOVSX reg,EA 2821: c2 = loadea(e1,&cs,opcode,reg,0,0,retregs); 2822: c3 = CNIL; 2823: } 2824: freenode(e1); 2825: goto L2; 2826: } 2827: size = tysize(e->Ety); 2828: retregs = *pretregs & BYTEREGS; 2829: if (retregs == 0) 2830: retregs = BYTEREGS; 2831: retregs |= *pretregs & mPSW; 2832: *pretregs &= ~mPSW; 2833: } 2834: else 2835: { 2836: if (op == OPu8int) /* if unsigned conversion */ 2837: { 2838: retregs = *pretregs & BYTEREGS; 2839: if (retregs == 0) 2840: retregs = BYTEREGS; 2841: } 2842: else 2843: { 2844: /* CBW doesn't affect flags, so we can depend on the integer */ 2845: /* math to provide the flags. */ 2846: retregs = mAX | (*pretregs & mPSW); /* want integer result in AX */ 2847: } 2848: } 2849: 2850: c3 = CNIL; 2851: c1 = codelem(e1,&retregs,FALSE); 2852: reg = findreg(retregs); 2853: if (!c1) 2854: goto L1; 2855: 2856: for (c = c1; c->next; c = c->next) 2857: ; /* find previous instruction */ 2858: 2859: /* If previous instruction is an AND bytereg,value */ 2860: if (c->Iop == 0x80 && c->Irm == modregrm(3,4,reg & 7) && 2861: (op == OPu8int || (c->IEV2.Vuns & 0x80) == 0)) 2862: { 2863: if (*pretregs & mPSW) 2864: c->Iflags |= CFpsw; 2865: c->Iop |= 1; /* convert to word operation */ 2866: c->IEV2.Vuns &= 0xFF; /* dump any high order bits */ 2867: *pretregs &= ~mPSW; /* flags already set */ 2868: } 2869: else 2870: { 2871: L1: 2872: if (!I16) 2873: { 2874: if (op == OPs8int && reg == AX && size == 2) 2875: { c3 = gen1(c3,0x98); /* CBW */ 2876: c3->Iflags |= CFopsize; /* don't do a CWDE */ 2877: } 2878: else 2879: { 2880: /* We could do better by not forcing the src and dst */ 2881: /* registers to be the same. */ 2882: 2883: if (config.flags4 & CFG4speed && op == OPu8_16) 2884: { // AND reg,0xFF 2885: c3 = genc2(c3,0x81,modregrmx(3,4,reg),0xFF); 2886: } 2887: else 2888: { 2889: unsigned iop = (op == OPu8int) ? 0x0FB6 : 0x0FBE; // MOVZX/MOVSX reg,reg 2890: c3 = genregs(c3,iop,reg,reg); 2891: if (I64 && reg >= 4) 2892: code_orrex(c3, REX); 2893: } 2894: } 2895: } 2896: else 2897: { 2898: if (op == OPu8int) 2899: c3 = genregs(c3,0x30,reg+4,reg+4); // XOR regH,regH 2900: else 2901: { 2902: c3 = gen1(c3,0x98); /* CBW */ 2903: *pretregs &= ~mPSW; /* flags already set */ 2904: } 2905: } 2906: } 2907: c2 = getregs(retregs); 2908: L2: 2909: c4 = fixresult(e,retregs,pretregs); 2910: return cat6(c0,c1,c2,c3,c4,NULL); 2911: } 2912: 2913: 2914: /*************************** 2915: * Convert long to short (OP32_16). 2916: * Get offset of far pointer (OPoffset). 2917: * Convert int to byte (OP16_8). 2918: * Convert long long to long (OP64_32). 2919: * OP128_64 2920: */ 2921: 2922: code *cdlngsht(elem *e,regm_t *pretregs) 2923: { regm_t retregs; 2924: code *c; 2925: 2926: #ifdef DEBUG 2927: switch (e->Eoper) 2928: { 2929: case OP32_16: 2930: case OPoffset: 2931: case OP16_8: 2932: case OP64_32: 2933: case OP128_64: 2934: break; 2935: 2936: default: 2937: assert(0); 2938: } 2939: #endif 2940: 2941: if (e->Eoper == OP16_8) 2942: { retregs = *pretregs ? BYTEREGS : 0; 2943: c = codelem(e->E1,&retregs,FALSE); 2944: } 2945: else 2946: { if (e->E1->Eoper == OPrelconst) 2947: c = offsetinreg(e->E1,&retregs); 2948: else 2949: { retregs = *pretregs ? ALLREGS : 0; 2950: c = codelem(e->E1,&retregs,FALSE); 2951: if (I16 || 2952: I32 && (e->Eoper == OPoffset || e->Eoper == OP64_32) || 2953: I64 && (e->Eoper == OPoffset || e->Eoper == OP128_64)) 2954: retregs &= mLSW; /* want LSW only */ 2955: } 2956: } 2957: 2958: /* We "destroy" a reg by assigning it the result of a new e, even */ 2959: /* though the values are the same. Weakness of our CSE strategy that */ 2960: /* a register can only hold the contents of one elem at a time. */ 2961: if (e->Ecount) 2962: c = cat(c,getregs(retregs)); 2963: else 2964: useregs(retregs); 2965: 2966: #ifdef DEBUG 2967: if (!(!*pretregs || retregs)) 2968: WROP(e->Eoper), 2969: printf(" *pretregs = x%x, retregs = x%x, e = %p\n",*pretregs,retregs,e); 2970: #endif 2971: assert(!*pretregs || retregs); 2972: return cat(c,fixresult(e,retregs,pretregs)); /* lsw only */ 2973: } 2974: 2975: /********************************************** 2976: * Get top 32 bits of 64 bit value (I32) 2977: * or top 16 bits of 32 bit value (I16) 2978: * or top 64 bits of 128 bit value (I64). 2979: * OPmsw 2980: */ 2981: 2982: code *cdmsw(elem *e,regm_t *pretregs) 2983: { regm_t retregs; 2984: code *c; 2985: 2986: //printf("cdmsw(e->Ecount = %d)\n", e->Ecount); 2987: assert(e->Eoper == OPmsw); 2988: 2989: retregs = *pretregs ? ALLREGS : 0; 2990: c = codelem(e->E1,&retregs,FALSE); 2991: retregs &= mMSW; // want MSW only 2992: 2993: // We "destroy" a reg by assigning it the result of a new e, even 2994: // though the values are the same. Weakness of our CSE strategy that 2995: // a register can only hold the contents of one elem at a time. 2996: if (e->Ecount) 2997: c = cat(c,getregs(retregs)); 2998: else 2999: useregs(retregs); 3000: 3001: #ifdef DEBUG 3002: if (!(!*pretregs || retregs)) 3003: { WROP(e->Eoper); 3004: printf(" *pretregs = %s, retregs = %s\n",regm_str(*pretregs),regm_str(retregs)); 3005: elem_print(e); 3006: } 3007: #endif 3008: assert(!*pretregs || retregs); 3009: return cat(c,fixresult(e,retregs,pretregs)); // msw only 3010: } 3011: 3012: 3013: 3014: /****************************** 3015: * Handle operators OPinp and OPoutp. 3016: */ 3017: 3018: code *cdport(elem *e,regm_t *pretregs) 3019: { regm_t retregs; 3020: code *c1,*c2,*c3; 3021: unsigned char op,port; 3022: unsigned sz; 3023: elem *e1; 3024: 3025: //printf("cdport\n"); 3026: op = 0xE4; /* root of all IN/OUT opcodes */ 3027: e1 = e->E1; 3028: 3029: // See if we can use immediate mode of IN/OUT opcodes 3030: if (e1->Eoper == OPconst && e1->EV.Vuns <= 255 && 3031: (!evalinregister(e1) || regcon.mvar & mDX)) 3032: { port = e1->EV.Vuns; 3033: freenode(e1); 3034: c1 = CNIL; 3035: } 3036: else 3037: { retregs = mDX; /* port number is always DX */ 3038: c1 = codelem(e1,&retregs,FALSE); 3039: op |= 0x08; /* DX version of opcode */ 3040: port = 0; // not logically needed, but 3041: // quiets "uninitialized var" complaints 3042: } 3043: 3044: if (e->Eoper == OPoutp) 3045: { 3046: sz = tysize(e->E2->Ety); 3047: retregs = mAX; /* byte/word to output is in AL/AX */ 3048: c2 = scodelem(e->E2,&retregs,((op & 0x08) ? mDX : (regm_t) 0),TRUE); 3049: op |= 0x02; /* OUT opcode */ 3050: } 3051: else // OPinp 3052: { c2 = getregs(mAX); 3053: sz = tysize(e->Ety); 3054: } 3055: 3056: if (sz != 1) 3057: op |= 1; /* word operation */ 3058: c3 = genc2(CNIL,op,0,port); /* IN/OUT AL/AX,DX/port */ 3059: if (op & 1 && sz != REGSIZE) // if need size override 3060: c3->Iflags |= CFopsize; 3061: retregs = mAX; 3062: return cat4(c1,c2,c3,fixresult(e,retregs,pretregs)); 3063: } 3064: 3065: /************************ 3066: * Generate code for an asm elem. 3067: */ 3068: 3069: code *cdasm(elem *e,regm_t *pretregs) 3070: { code *c; 3071: 3072: #if 1 3073: /* Assume only regs normally destroyed by a function are destroyed */ 3074: c = getregs((ALLREGS | mES) & ~fregsaved); 3075: #else 3076: /* Assume all regs are destroyed */ 3077: c = getregs(ALLREGS | mES); 3078: #endif 3079: c = genasm(c,e->EV.ss.Vstring,e->EV.ss.Vstrlen); 3080: return cat(c,fixresult(e,(I16 ? mDX | mAX : mAX),pretregs)); 3081: } 3082: 3083: /************************ 3084: * Generate code for OPtofar16 and OPfromfar16. 3085: */ 3086: 3087: code *cdfar16( elem *e, regm_t *pretregs) 3088: { code *c; 3089: code *c1; 3090: code *c3; 3091: code *cnop; 3092: code cs; 3093: unsigned reg; 3094: 3095: assert(I32); 3096: c = codelem(e->E1,pretregs,FALSE); 3097: reg = findreg(*pretregs); 3098: c = cat(c,getregs(*pretregs)); /* we will destroy the regs */ 3099: 3100: cs.Iop = 0xC1; 3101: cs.Irm = modregrm(3,0,reg); 3102: cs.Iflags = 0; 3103: cs.Irex = 0; 3104: cs.IFL2 = FLconst; 3105: cs.IEV2.Vuns = 16; 3106: 3107: c3 = gen(CNIL,&cs); /* ROL ereg,16 */ 3108: cs.Irm |= modregrm(0,1,0); 3109: c1 = gen(CNIL,&cs); /* ROR ereg,16 */ 3110: cs.IEV2.Vuns = 3; 3111: cs.Iflags |= CFopsize; 3112: 3113: if (e->Eoper == OPtofar16) 3114: { 3115: /* OR ereg,ereg 3116: JE L1 3117: ROR ereg,16 3118: SHL reg,3 3119: MOV rx,SS 3120: AND rx,3 ;mask off CPL bits 3121: OR rl,4 ;run on LDT bit 3122: OR regl,rl 3123: ROL ereg,16 3124: L1: NOP 3125: */ 3126: int jop; 3127: int byte; 3128: unsigned rx; 3129: regm_t retregs; 3130: 3131: retregs = BYTEREGS & ~*pretregs; 3132: c = cat(c,allocreg(&retregs,&rx,TYint)); 3133: cnop = gennop(CNIL); 3134: jop = JCXZ; 3135: if (reg != CX) 3136: { 3137: c = gentstreg(c,reg); 3138: jop = JE; 3139: } 3140: c = genjmp(c,jop,FLcode,(block *)cnop); /* Jop L1 */ 3141: NEWREG(cs.Irm,4); 3142: gen(c1,&cs); /* SHL reg,3 */ 3143: genregs(c1,0x8C,2,rx); /* MOV rx,SS */ 3144: byte = (mask[reg] & BYTEREGS) == 0; 3145: genc2(c1,0x80 | byte,modregrm(3,4,rx),3); /* AND rl,3 */ 3146: genc2(c1,0x80,modregrm(3,1,rx),4); /* OR rl,4 */ 3147: genregs(c1,0x0A | byte,reg,rx); /* OR regl,rl */ 3148: } 3149: else /* OPfromfar16 */ 3150: { 3151: /* ROR ereg,16 3152: SHR reg,3 3153: ROL ereg,16 3154: */ 3155: 3156: cs.Irm |= modregrm(0,5,0); 3157: gen(c1,&cs); /* SHR reg,3 */ 3158: cnop = NULL; 3159: } 3160: return cat4(c,c1,c3,cnop); 3161: } 3162: 3163: /************************* 3164: * Generate code for OPbt, OPbtc, OPbtr, OPbts 3165: */ 3166: 3167: code *cdbt(elem *e, regm_t *pretregs) 3168: { 3169: elem *e1; 3170: elem *e2; 3171: code *c; 3172: code *c2; 3173: code cs; 3174: regm_t idxregs; 3175: regm_t retregs; 3176: unsigned reg; 3177: unsigned char word; 3178: tym_t ty1; 3179: int op; 3180: int mode; 3181: 3182: switch (e->Eoper) 3183: { 3184: case OPbt: op = 0xA3; mode = 4; break; 3185: case OPbtc: op = 0xBB; mode = 7; break; 3186: case OPbtr: op = 0xB3; mode = 6; break; 3187: case OPbts: op = 0xAB; mode = 5; break; 3188: 3189: default: 3190: assert(0); 3191: } 3192: 3193: e1 = e->E1; 3194: e2 = e->E2; 3195: cs.Iflags = 0; 3196: c = getlvalue(&cs, e, RMload); // get addressing mode 3197: if (e->Eoper == OPbt && *pretregs == 0) 3198: return cat(c, codelem(e2,pretregs,FALSE)); 3199: 3200: ty1 = tybasic(e1->Ety); 3201: word = (!I16 && tysize[ty1] == 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?
3202: idxregs = idxregm(&cs); // mask if index regs used 3203: 3204: // if (e2->Eoper == OPconst && e2->EV.Vuns < 0x100) // should do this instead? 3205: if (e2->Eoper == OPconst) 3206: { 3207: cs.Iop = 0x0FBA; // BT rm,imm8 3208: cs.Irm |= modregrm(0,mode,0); 3209: cs.Iflags |= CFpsw | word; 3210: cs.IFL2 = FLconst; 3211: if (tysize[ty1] == SHORTSIZE) 3212: { 3213: cs.IEVoffset1 += (e2->EV.Vuns & ~15) >> 3; 3214: cs.IEV2.Vint = e2->EV.Vint & 15; 3215: } 3216: else if (tysize[ty1] == 4) 3217: { 3218: cs.IEVoffset1 += (e2->EV.Vuns & ~31) >> 3; 3219: cs.IEV2.Vint = e2->EV.Vint & 31; 3220: } 3221: else 3222: { 3223: cs.IEVoffset1 += (e2->EV.Vuns & ~63) >> 3; 3224: cs.IEV2.Vint = e2->EV.Vint & 63; 3225: if (I64) 3226: cs.Irex |= REX_W; 3227: } 3228: c2 = gen(CNIL,&cs); 3229: } 3230: else 3231: { 3232: retregs = ALLREGS & ~idxregs; 3233: c2 = scodelem(e2,&retregs,idxregs,TRUE); 3234: reg = findreg(retregs); 3235: 3236: cs.Iop = 0x0F00 | op; // BT rm,reg 3237: code_newreg(&cs,reg); 3238: cs.Iflags |= CFpsw | word; 3239: c2 = gen(c2,&cs); 3240: } 3241: 3242: if ((retregs = (*pretregs & (ALLREGS | mBP))) != 0) // if return result in register 3243: { 3244: code *nop = CNIL; 3245: regm_t save = regcon.immed.mval; 3246: code *cg = allocreg(&retregs,&reg,TYint); 3247: regcon.immed.mval = save; 3248: if ((*pretregs & mPSW) == 0) 3249: { 3250: cg = cat(cg,getregs(retregs)); 3251: cg = genregs(cg,0x19,reg,reg); // SBB reg,reg 3252: } 3253: else 3254: { 3255: cg = movregconst(cg,reg,1,8); // MOV reg,1 3256: nop = gennop(nop); 3257: cg = genjmp(cg,JC,FLcode,(block *) nop); // Jtrue nop 3258: // MOV reg,0 3259: movregconst(cg,reg,0,8); 3260: regcon.immed.mval &= ~mask[reg]; 3261: } 3262: *pretregs = retregs; 3263: c2 = cat3(c2,cg,nop); 3264: } 3265: 3266: return cat(c,c2); 3267: } 3268: 3269: /************************************* 3270: * Generate code for OPbsf and OPbsr. 3271: */ 3272: 3273: code *cdbscan(elem *e, regm_t *pretregs) 3274: { 3275: regm_t retregs; 3276: unsigned reg; 3277: int sz; 3278: tym_t tyml; 3279: code *cl,*cg; 3280: code cs; 3281: 3282: //printf("cdbscan()\n"); 3283: //elem_print(e); 3284: if (*pretregs == 0) 3285: return codelem(e->E1,pretregs,FALSE); 3286: tyml = tybasic(e->E1->Ety); 3287: sz = tysize[tyml]; 3288: assert(sz == 2 || sz == 4 || sz == 8); 3289: 3290: if ((e->E1->Eoper == OPind && !e->E1->Ecount) || e->E1->Eoper == OPvar) 3291: { 3292: cl = getlvalue(&cs, e->E1, RMload); // get addressing mode 3293: } 3294: else 3295: { 3296: retregs = allregs; 3297: cl = codelem(e->E1, &retregs, FALSE); 3298: reg = findreg(retregs); 3299: cs.Irm = modregrm(3,0,reg & 7); 3300: cs.Iflags = 0; 3301: cs.Irex = 0; 3302: if (reg & 8) 3303: cs.Irex |= REX_B; 3304: } 3305: 3306: retregs = *pretregs & allregs; 3307: if (!retregs) 3308: retregs = allregs; 3309: cg = allocreg(&retregs, &reg, e->Ety); 3310: 3311: cs.Iop = (e->Eoper == OPbsf) ? 0x0FBC : 0x0FBD; // BSF/BSR reg,EA 3312: code_newreg(&cs, reg); 3313: 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?
3314: cs.Iflags |= CFopsize; 3315: cg = gen(cg,&cs); 3316: if (sz == 8) 3317: code_orrex(cg, REX_W); 3318: 3319: return cat3(cl,cg,fixresult(e,retregs,pretregs)); 3320: } 3321: 3322: /******************************************* 3323: * Generate code for OPpair, OPrpair. 3324: */ 3325: 3326: code *cdpair(elem *e, regm_t *pretregs) 3327: { 3328: regm_t retregs; 3329: regm_t regs1; 3330: regm_t regs2; 3331: code *cg; 3332: code *c1; 3333: code *c2; 3334: 3335: if (*pretregs == 0) // if don't want result 3336: { c1 = codelem(e->E1,pretregs,FALSE); // eval left leaf 3337: *pretregs = 0; // in case they got set 3338: return cat(c1,codelem(e->E2,pretregs,FALSE)); 3339: } 3340: 3341: //printf("\ncdpair(e = %p, *pretregs = x%x)\n", e, *pretregs); 3342: //printf("Ecount = %d\n", e->Ecount); 3343: retregs = *pretregs & allregs; 3344: if (!retregs) 3345: retregs = allregs; 3346: regs1 = retregs & (mLSW | mBP); 3347: regs2 = retregs & mMSW; 3348: if (e->Eoper == OPrpair) 3349: { 3350: regs1 = regs2; 3351: regs2 = retregs & (mLSW | mBP); 3352: } 3353: //printf("1: regs1 = x%x, regs2 = x%x\n", regs1, regs2); 3354: c1 = codelem(e->E1, &regs1, FALSE); 3355: c2 = scodelem(e->E2, &regs2, regs1, FALSE); 3356: 3357: cg = NULL; 3358: if (e->E1->Ecount) 3359: cg = getregs(regs1); 3360: if (e->E2->Ecount) 3361: cg = cat(cg, getregs(regs2)); 3362: 3363: //printf("regs1 = x%x, regs2 = x%x\n", regs1, regs2); 3364: return cat4(c1,c2,cg,fixresult(e,regs1 | regs2,pretregs)); 3365: } 3366: 3367: #endif // !SPP 3368: