1: // Copyright (C) 1985-1998 by Symantec
   2: // Copyright (C) 2000-2009 by Digital Mars
   3: // All Rights Reserved
   4: // http://www.digitalmars.com
   5: // Written by Walter Bright
   6: /*
   7:  * This source file is made available for personal use
   8:  * only. The license is in /dmd/src/dmd/backendlicense.txt
   9:  * or /dm/src/dmd/backendlicense.txt.
  10:  * For any other uses, please contact Digital Mars.
  11:  */
  12: 
  13: #if !SPP
  14: 
  15: #include        <stdio.h>
  16: #include        <string.h>
  17: #include        <stdlib.h>
  18: #include        <time.h>
  19: 
  20: #if __sun&&__SVR4
  21: #include        <alloca.h>
  22: #elif _MSC_VER
  23: #include        <malloc.h>
  24: #endif
  25: 
  26: #include        "cc.h"
  27: #include        "el.h"
  28: #include        "oper.h"
  29: #include        "code.h"
  30: #include        "global.h"
  31: #include        "type.h"
  32: #include        "exh.h"
  33: 
  34: static char __file__[] = __FILE__;      /* for tassert.h                */
  35: #include        "tassert.h"
  36: 
  37: STATIC void resetEcomsub(elem *e);
  38: STATIC code * loadcse(elem *,unsigned,regm_t);
  39: STATIC void blcodgen(block *);
  40: STATIC void cgcod_eh();
  41: STATIC code * cse_save(regm_t ms);
  42: STATIC int cse_simple(elem *e,int i);
  43: STATIC code * comsub(elem *,regm_t *);
  44: 
  45: bool floatreg;                  // !=0 if floating register is required
  46: 
  47: targ_size_t Aoffset;            // offset of automatics and registers
  48: targ_size_t Toffset;            // offset of temporaries
  49: targ_size_t EEoffset;           // offset of SCstack variables from ESP
  50: int Aalign;                     // alignment for Aoffset
  51: 
  52: REGSAVE regsave;
  53: 
  54: CGstate cgstate;                // state of code generator
  55: 
  56: /************************************
  57:  * # of bytes that SP is beyond BP.
  58:  */
  59: 
  60: unsigned stackpush;
  61: 
  62: int stackchanged;               /* set to !=0 if any use of the stack
  63:                                    other than accessing parameters. Used
  64:                                    to see if we can address parameters
  65:                                    with ESP rather than EBP.
  66:                                  */
  67: int refparam;           // !=0 if we referenced any parameters
  68: int reflocal;           // !=0 if we referenced any locals
  69: char anyiasm;           // !=0 if any inline assembler
  70: char calledafunc;       // !=0 if we called a function
  71: char needframe;         // if TRUE, then we will need the frame
  72:                         // pointer (BP for the 8088)
  73: char usedalloca;        // if TRUE, then alloca() was called
  74: char gotref;            // !=0 if the GOTsym was referenced
  75: unsigned usednteh;              // if !=0, then used NT exception handling
  76: 
  77: /* Register contents    */
  78: con_t regcon;
  79: 
  80: int pass;                       // PASSxxxx
  81: 
  82: static symbol *retsym;          // set to symbol that should be placed in
  83:                                 // register AX
  84: 
  85: /****************************
  86:  * Register masks.
  87:  */
  88: 
  89: regm_t msavereg;        // Mask of registers that we would like to save.
  90:                         // they are temporaries (set by scodelem())
  91: regm_t mfuncreg;        // Mask of registers preserved by a function
  92: regm_t allregs;         // ALLREGS optionally including mBP
  93: 
  94: int dfoidx;                     /* which block we are in                */
  95: struct CSE *csextab = NULL;     /* CSE table (allocated for each function) */
  96: unsigned cstop;                 /* # of entries in CSE table (csextab[])   */
  97: unsigned csmax;                 /* amount of space in csextab[]         */
  98: 
  99: targ_size_t     funcoffset;     // offset of start of function
 100: targ_size_t     startoffset;    // size of function entry code
 101: targ_size_t     retoffset;      /* offset from start of func to ret code */
 102: targ_size_t     retsize;        /* size of function return              */
 103: 
 104: static regm_t lastretregs,last2retregs,last3retregs,last4retregs,last5retregs;
 105: 
 106: /*********************************
 107:  * Generate code for a function.
 108:  * Note at the end of this routine mfuncreg will contain the mask
 109:  * of registers not affected by the function. Some minor optimization
 110:  * possibilities are here...
 111:  */
 112: 
 113: void codgen()
 114: {   block *b,*bn;
 115:     bool flag;
 116:     int i;
 117:     targ_size_t swoffset,coffset;
 118:     tym_t functy;
 119:     unsigned nretblocks;                // number of return blocks
 120:     code *cprolog;
 121:     regm_t noparams;
 122: #if SCPP
 123:     block *btry;
 124: #endif
 125:     // Register usage. If a bit is on, the corresponding register is live
 126:     // in that basic block.
 127: 
 128:     //printf("codgen('%s')\n",funcsym_p->Sident);
 129: 
 130:     cgreg_init();
 131:     csmax = 64;
 132:     csextab = (struct CSE *) util_calloc(sizeof(struct CSE),csmax);
 133:     functy = tybasic(funcsym_p->ty());
 134: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
 135:     if (0 && config.flags3 & CFG3pic)
 136:     {
 137:         ALLREGS = ALLREGS_INIT_PIC;
 138:         BYTEREGS = BYTEREGS_INIT_PIC;
 139:     }
 140:     else
 141:     {
 142:         regm_t value = BYTEREGS_INIT;
 143:         ALLREGS = ALLREGS_INIT;
 144:         BYTEREGS = value;
 145:     }
 146:     if (I64)
 147:     {   ALLREGS = mAX|mBX|mCX|mDX|mSI|mDI| mR8|mR9|mR10|mR11|mR12|mR13|mR14|mR15;
 148:         BYTEREGS = ALLREGS;
 149:     }
 150: #endif
 151:     allregs = ALLREGS;
 152:     if (0 && config.flags3 & CFG3pic)
 153:         allregs &= ~mBX;
 154:     pass = PASSinit;
 155: 
 156: tryagain:
 157:     #ifdef DEBUG
 158:     if (debugr)
 159:         printf("------------------ PASS%s -----------------\n",
 160:             (pass == PASSinit) ? "init" : ((pass == PASSreg) ? "reg" : "final"));
 161:     #endif
 162:     lastretregs = last2retregs = last3retregs = last4retregs = last5retregs = 0;
 163: 
 164:     // if no parameters, assume we don't need a stack frame
 165:     needframe = 0;
 166:     usedalloca = 0;
 167:     gotref = 0;
 168:     stackchanged = 0;
 169:     stackpush = 0;
 170:     refparam = 0;
 171:     anyiasm = 0;
 172:     calledafunc = 0;
 173:     cgstate.stackclean = 1;
 174:     retsym = NULL;
 175: 
 176:     regsave.reset();
 177:     memset(_8087elems,0,sizeof(_8087elems));
 178: 
 179:     usednteh = 0;
 180: #if (MARS) && TARGET_WINDOS
 181:     if (funcsym_p->Sfunc->Fflags3 & Fjmonitor)
 182:         usednteh |= NTEHjmonitor;
 183: #else
 184:     if (CPP)
 185:     {
 186:         if (config.flags2 & CFG2seh &&
 187:             (funcsym_p->Stype->Tflags & TFemptyexc || funcsym_p->Stype->Texcspec))
 188:             usednteh |= NTEHexcspec;
 189:         except_reset();
 190:     }
 191: #endif
 192: 
 193:     floatreg = FALSE;
 194:     assert(stackused == 0);             /* nobody in 8087 stack         */
 195:     cstop = 0;                          /* no entries in table yet      */
 196:     memset(&regcon,0,sizeof(regcon));
 197:     regcon.cse.mval = regcon.cse.mops = 0;      // no common subs yet
 198: #if 0 && TARGET_LINUX
 199:     if (!(allregs & mBX))
 200:         msavereg = mBX;
 201:     else
 202: #endif
 203:         msavereg = 0;
 204:     nretblocks = 0;
 205:     mfuncreg = fregsaved;               // so we can see which are used
 206:                                         // (bit is cleared each time
 207:                                         //  we use one)
 208:     for (b = startblock; b; b = b->Bnext)
 209:     {   memset(&b->Bregcon,0,sizeof(b->Bregcon));       // Clear out values in registers
 210:         if (b->Belem)
 211:             resetEcomsub(b->Belem);     // reset all the Ecomsubs
 212:         if (b->BC == BCasm)
 213:             anyiasm = 1;                // we have inline assembler
 214:         if (b->BC == BCret || b->BC == BCretexp)
 215:             nretblocks++;
 216:     }
 217: 
 218:     if (!config.fulltypes || (config.flags4 & CFG4optimized))
 219:     {
 220:         noparams = 0;
 221:         for (i = 0; i < globsym.top; i++)
 222:         {
 223:             Symbol *s = globsym.tab[i];
 224:             s->Sflags &= ~SFLread;
 225:             switch (s->Sclass)
 226:             {   case SCfastpar:
 227:                     regcon.params |= mask[s->Spreg];
 228:                 case SCparameter:
 229:                     if (s->Sfl == FLreg)
 230:                         noparams |= s->Sregm;
 231:                     break;
 232:             }
 233:         }
 234:         regcon.params &= ~noparams;
 235:     }
 236: 
 237:     if (config.flags4 & CFG4optimized)
 238:     {
 239:         if (nretblocks == 0 &&                  // if no return blocks in function
 240:             !(funcsym_p->ty() & mTYnaked))      // naked functions may have hidden veys of returning
 241:             funcsym_p->Sflags |= SFLexit;       // mark function as never returning
 242: 
 243:         assert(dfo);
 244: 
 245:         cgreg_reset();
 246:         for (dfoidx = 0; dfoidx < dfotop; dfoidx++)
warning C4018: '<' : signed/unsigned mismatch
247: { regcon.used = msavereg | regcon.cse.mval; // registers already in use 248: b = dfo[dfoidx]; 249: blcodgen(b); // gen code in depth-first order 250: //printf("b->Bregcon.used = x%x\n", b->Bregcon.used); 251: cgreg_used(dfoidx,b->Bregcon.used); // gather register used information 252: } 253: } 254: else 255: { pass = PASSfinal; 256: for (b = startblock; b; b = b->Bnext) 257: blcodgen(b); // generate the code for each block 258: } 259: regcon.immed.mval = 0; 260: assert(!regcon.cse.mops); // should have all been used 261: 262: // See which variables we can put into registers 263: if (pass != PASSfinal && 264: !anyiasm) // possible LEA or LES opcodes 265: { 266: allregs |= cod3_useBP(); // see if we can use EBP 267: 268: // If pic code, but EBX was never needed 269: if (!(allregs & mBX) && !gotref) 270: { allregs |= mBX; // EBX can now be used 271: cgreg_assign(retsym); 272: pass = PASSreg; 273: } 274: else if (cgreg_assign(retsym)) // if we found some registers 275: pass = PASSreg; 276: else 277: pass = PASSfinal; 278: for (b = startblock; b; b = b->Bnext) 279: { code_free(b->Bcode); 280: b->Bcode = NULL; 281: } 282: goto tryagain; 283: } 284: cgreg_term(); 285: 286: #if SCPP 287: if (CPP) 288: cgcod_eh(); 289: #endif 290: 291: stackoffsets(1); // compute addresses of stack variables 292: cod5_prol_epi(); // see where to place prolog/epilog 293: 294: // Get rid of unused cse temporaries 295: while (cstop != 0 && (csextab[cstop - 1].flags & CSEload) == 0) 296: cstop--; 297: 298: if (configv.addlinenumbers) 299: objlinnum(funcsym_p->Sfunc->Fstartline,Coffset); 300: 301: // Otherwise, jmp's to startblock will execute the prolog again 302: assert(!startblock->Bpred);
warning C6011: Dereferencing NULL pointer 'struct block * startblock': Lines: 114, 115, 116, 117, 118, 119, 120, 121, 130, 131, 132, 133, 151, 152, 154, 156, 162, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 177, 179, 181, 182, 193, 194, 195, 196, 197, 203, 204, 205, 208, 218, 220, 221, 234, 237, 239, 241, 243, 245, 246, 259, 260, 263,266, 269, 270, 271, 272, 278, 282, 156, 162, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 177, 179, 181, 182, 193, 194, 195, 196, 197, 203, 204, 205, 208, 218, 220, 221, 234, 237, 239, 241, 243, 245, 246, 259, 260, 263, 266, 269, 270, 271, 272, 278, 282, 156, 162, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 176, 177, 179, 181, 182, 193, 194, 195, 196, 197, 203, 204, 205, 208, 218, 220, 221, 234, 237, 255, 256, 259, 260, 263, 284, 291, 292, 295, 298, 299, 302
303: 304: cprolog = prolog(); // gen function start code 305: if (cprolog) 306: pinholeopt(cprolog,NULL); // optimize 307: 308: funcoffset = Coffset; 309: coffset = Coffset; 310: 311: if (eecontext.EEelem) 312: { regm_t retregs; 313: code *c; 314: 315: eecontext.EEin++; 316: regcon.immed.mval = 0; 317: retregs = 0; //regmask(eecontext.EEelem->Ety); 318: assert(EEoffset >= REGSIZE);
warning C4018: '>=' : signed/unsigned mismatch
319: c = genc2(NULL,0x81,modregrm(3,5,SP),EEoffset - REGSIZE); // SUB ESP,EEoffset 320: gen1(c,0x50 + SI); // PUSH ESI 321: genadjesp(c,EEoffset); 322: c = gencodelem(c,eecontext.EEelem,&retregs, FALSE); 323: assignaddrc(c); 324: pinholeopt(c,NULL); 325: jmpaddr(c); 326: eecontext.EEcode = gen1(c,0xCC); // INT 3 327: eecontext.EEin--; 328: } 329: 330: for (b = startblock; b; b = b->Bnext) 331: { 332: // We couldn't do this before because localsize was unknown 333: switch (b->BC) 334: { case BCret: 335: if (configv.addlinenumbers && b->Bsrcpos.Slinnum && !(funcsym_p->ty() & mTYnaked)) 336: cgen_linnum(&b->Bcode,b->Bsrcpos); 337: case BCretexp: 338: epilog(b); 339: break; 340: default: 341: if (b->Bflags & BFLepilog) 342: epilog(b); 343: break; 344: } 345: assignaddr(b); // assign addresses 346: pinholeopt(b->Bcode,b); // do pinhole optimization 347: if (b->Bflags & BFLprolog) // do function prolog 348: { 349: startoffset = coffset + calcblksize(cprolog) - funcoffset; 350: b->Bcode = cat(cprolog,b->Bcode); 351: } 352: if (config.flags4 & CFG4speed && 353: config.target_cpu >= TARGET_Pentium && 354: b->BC != BCasm 355: ) 356: { regm_t scratch; 357: 358: scratch = allregs & ~(b->Bregcon.used | b->Bregcon.params | mfuncreg); 359: scratch &= ~(b->Bregcon.immed.mval | b->Bregcon.cse.mval); 360: cgsched_pentium(&b->Bcode,scratch); 361: //printf("after schedule:\n"); WRcodlst(b->Bcode); 362: } 363: b->Bsize = calcblksize(b->Bcode); // calculate block size 364: if (b->Balign) 365: { targ_size_t u = b->Balign - 1; 366: 367: coffset = (coffset + u) & ~u; 368: } 369: b->Boffset = coffset; /* offset of this block */ 370: coffset += b->Bsize; /* offset of following block */ 371: } 372: #ifdef DEBUG 373: debugw && printf("code addr complete\n"); 374: #endif 375: 376: // Do jump optimization 377: do 378: { flag = FALSE; 379: for (b = startblock; b; b = b->Bnext) 380: { if (b->Bflags & BFLjmpoptdone) /* if no more jmp opts for this blk */ 381: continue; 382: i = branch(b,0); // see if jmp => jmp short 383: if (i) /* if any bytes saved */ 384: { targ_size_t offset; 385: 386: b->Bsize -= i; 387: offset = b->Boffset + b->Bsize; 388: for (bn = b->Bnext; bn; bn = bn->Bnext) 389: { 390: if (bn->Balign) 391: { targ_size_t u = bn->Balign - 1; 392: 393: offset = (offset + u) & ~u; 394: } 395: bn->Boffset = offset; 396: offset += bn->Bsize; 397: } 398: coffset = offset; 399: flag = TRUE; 400: } 401: } 402: if (!I16 && !(config.flags4 & CFG4optimized))
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
403: break; // use the long conditional jmps 404: } while (flag); // loop till no more bytes saved 405: #ifdef DEBUG 406: debugw && printf("code jump optimization complete\n"); 407: #endif 408: 409: #if MARS 410: if (usednteh & NTEH_try) 411: { 412: // Do this before code is emitted because we patch some instructions 413: nteh_filltables(); 414: } 415: #endif 416: 417: // Compute starting offset for switch tables 418: #if ELFOBJ || MACHOBJ 419: swoffset = (config.flags & CFGromable) ? coffset : CDoffset; 420: #else 421: swoffset = (config.flags & CFGromable) ? coffset : Doffset; 422: #endif 423: swoffset = align(0,swoffset); 424: 425: // Emit the generated code 426: if (eecontext.EEcompile == 1) 427: { 428: codout(eecontext.EEcode); 429: code_free(eecontext.EEcode); 430: #if SCPP 431: el_free(eecontext.EEelem); 432: #endif 433: } 434: else 435: { 436: for (b = startblock; b; b = b->Bnext) 437: { 438: if (b->BC == BCjmptab || b->BC == BCswitch) 439: { b->Btableoffset = swoffset; /* offset of sw tab */ 440: swoffset += b->Btablesize; 441: } 442: jmpaddr(b->Bcode); /* assign jump addresses */ 443: #ifdef DEBUG 444: if (debugc) 445: { printf("Boffset = x%lx, Bsize = x%lx, Coffset = x%lx\n", 446: (long)b->Boffset,(long)b->Bsize,(long)Coffset); 447: if (b->Bcode) 448: printf( "First opcode of block is: %0x\n", b->Bcode->Iop ); 449: } 450: #endif 451: if (b->Balign) 452: { unsigned u = b->Balign; 453: unsigned nalign = (u - (unsigned)Coffset) & (u - 1); 454: 455: while (nalign--) 456: obj_byte(cseg,Coffset++,0x90); // XCHG AX,AX 457: } 458: assert(b->Boffset == Coffset); 459: 460: #if SCPP 461: if (CPP && 462: !(config.flags2 & CFG2seh)) 463: { 464: //printf("b = %p, index = %d\n",b,b->Bindex); 465: //except_index_set(b->Bindex); 466: 467: if (btry != b->Btry) 468: { 469: btry = b->Btry; 470: except_pair_setoffset(b,Coffset - funcoffset); 471: } 472: if (b->BC == BCtry) 473: { 474: btry = b; 475: except_pair_setoffset(b,Coffset - funcoffset); 476: } 477: } 478: #endif 479: codout(b->Bcode); // output code 480: } 481: if (coffset != Coffset) 482: { 483: #ifdef DEBUG 484: printf("coffset = %ld, Coffset = %ld\n",(long)coffset,(long)Coffset); 485: #endif 486: assert(0); 487: } 488: funcsym_p->Ssize = Coffset - funcoffset; // size of function 489: 490: #if NTEXCEPTIONS || MARS 491: #if (SCPP && NTEXCEPTIONS) 492: if (usednteh & NTEHcpp) 493: #elif MARS 494: if (usednteh & NTEH_try) 495: #endif 496: { assert(!(config.flags & CFGromable)); 497: //printf("framehandleroffset = x%x, coffset = x%x\n",framehandleroffset,coffset); 498: reftocodseg(cseg,framehandleroffset,coffset); 499: } 500: #endif 501: 502: 503: // Write out switch tables 504: flag = FALSE; // TRUE if last active block was a ret 505: for (b = startblock; b; b = b->Bnext) 506: { 507: switch (b->BC) 508: { case BCjmptab: /* if jump table */ 509: outjmptab(b); /* write out jump table */ 510: break; 511: case BCswitch: 512: outswitab(b); /* write out switch table */ 513: break; 514: case BCret: 515: case BCretexp: 516: /* Compute offset to return code from start of function */ 517: retoffset = b->Boffset + b->Bsize - retsize - funcoffset; 518: #if MARS 519: /* Add 3 bytes to retoffset in case we have an exception 520: * handler. THIS PROBABLY NEEDS TO BE IN ANOTHER SPOT BUT 521: * IT FIXES THE PROBLEM HERE AS WELL. 522: */ 523: if (usednteh & NTEH_try) 524: retoffset += 3; 525: #endif 526: flag = TRUE; 527: break; 528: case BCexit: 529: // Fake it to keep debugger happy 530: retoffset = b->Boffset + b->Bsize - funcoffset; 531: break; 532: } 533: } 534: if (flag && configv.addlinenumbers && !(funcsym_p->ty() & mTYnaked)) 535: /* put line number at end of function on the 536: start of the last instruction 537: */ 538: /* Instead, try offset to cleanup code */ 539: objlinnum(funcsym_p->Sfunc->Fendline,funcoffset + retoffset); 540: 541: #if MARS 542: if (usednteh & NTEH_try) 543: { 544: // Do this before code is emitted because we patch some instructions 545: nteh_gentables(); 546: } 547: if (usednteh & EHtry) 548: { 549: except_gentables(); 550: } 551: #endif 552: 553: #if SCPP 554: #if NTEXCEPTIONS 555: // Write out frame handler 556: if (usednteh & NTEHcpp) 557: nteh_framehandler(except_gentables()); 558: else 559: #endif 560: { 561: #if NTEXCEPTIONS 562: if (usednteh & NTEH_try) 563: nteh_gentables(); 564: else 565: #endif 566: { 567: if (CPP) 568: except_gentables(); 569: } 570: ; 571: } 572: #endif 573: for (b = startblock; b; b = b->Bnext) 574: { 575: code_free(b->Bcode); 576: b->Bcode = NULL; 577: } 578: 579: } 580: 581: // Mask of regs saved 582: // BUG: do interrupt functions save BP? 583: funcsym_p->Sregsaved = (functy == TYifunc) ? mBP : (mfuncreg | fregsaved); 584: 585: util_free(csextab); 586: csextab = NULL; 587: #ifdef DEBUG 588: if (stackused != 0) 589: printf("stackused = %d\n",stackused); 590: #endif 591: assert(stackused == 0); /* nobody in 8087 stack */ 592: 593: /* Clean up ndp save array */ 594: mem_free(NDP::save); 595: NDP::save = NULL; 596: NDP::savetop = 0; 597: NDP::savemax = 0; 598: } 599: 600: 601: /****************************** 602: * Compute offsets for remaining tmp, automatic and register variables 603: * that did not make it into registers. 604: */ 605: 606: void stackoffsets(int flags) 607: { 608: symbol *s; 609: targ_size_t Amax,sz; 610: unsigned alignsize; 611: int offi;
warning C4101: 'offi' : unreferenced local variable
612: #if AUTONEST 613: targ_size_t offstack[20]; 614: int offi = 0; // index into offstack[] 615: #endif 616: vec_t tbl = NULL; 617: 618: 619: //printf("stackoffsets()\n"); 620: if (config.flags4 & CFG4optimized) 621: { 622: tbl = vec_calloc(globsym.top); 623: } 624: Aoffset = 0; // automatic & register offset 625: Toffset = 0; // temporary offset 626: Poffset = 0; // parameter offset 627: EEoffset = 0; // for SCstack's 628: Amax = 0; 629: Aalign = REGSIZE; 630: for (int pass = 0; pass < 2; pass++)
warning C6244: Local declaration of 'pass' hides previous declaration at line '604' of 'c:\projects\extern\d\dmd\src\backend\code.h'
631: { 632: for (int si = 0; si < globsym.top; si++) 633: { s = globsym.tab[si]; 634: if (s->Sflags & SFLdead || 635: (!anyiasm && !(s->Sflags & SFLread) && s->Sflags & SFLunambig && 636: #if MARS 637: /* mTYvolatile was set if s has been reference by a nested function 638: * meaning we'd better allocate space for it 639: */ 640: !(s->Stype->Tty & mTYvolatile) && 641: #endif 642: (config.flags4 & CFG4optimized || !config.fulltypes)) 643: ) 644: sz = 0; 645: else 646: { sz = type_size(s->Stype); 647: if (sz == 0) 648: sz++; // can't handle 0 length structs 649: } 650: alignsize = type_alignsize(s->Stype); 651: 652: //printf("symbol '%s', size = x%lx, align = %d, read = %x\n",s->Sident,(long)sz, (int)type_alignsize(s->Stype), s->Sflags & SFLread); 653: assert((int)sz >= 0); 654: 655: if (pass == 1) 656: { 657: if (s->Sclass == SCfastpar) // if parameter s is passed in a register 658: { 659: /* Allocate in second pass in order to get these 660: * right next to the stack frame pointer, EBP. 661: * Needed so we can call nested contract functions 662: * frequire and fensure. 663: */ 664: if (s->Sfl == FLreg) // if allocated in register 665: continue; 666: /* Needed because storing fastpar's on the stack in prolog() 667: * does the entire register 668: */ 669: if (sz < REGSIZE)
warning C4018: '<' : signed/unsigned mismatch
670: sz = REGSIZE; 671: 672: Aoffset = align(sz,Aoffset); 673: s->Soffset = Aoffset; 674: Aoffset += sz; 675: if (Aoffset > Amax) 676: Amax = Aoffset; 677: //printf("fastpar '%s' sz = %d, auto offset = x%lx\n",s->Sident,sz,(long)s->Soffset); 678: 679: // Align doubles to 8 byte boundary 680: if (!I16 && alignsize > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
681: Aalign = alignsize; 682: } 683: continue; 684: } 685: 686: /* Can't do this for CPP because the inline function expander 687: adds new symbols on the end. 688: */ 689: #if AUTONEST 690: /*printf("symbol '%s', push = %d, pop = %d\n", 691: s->Sident,s->Spush,s->Spop);*/ 692: 693: /* Can't do this for optimizer if any code motion occurred. 694: Code motion changes the live range, so variables that 695: occupy the same space could have live ranges that overlap! 696: */ 697: if (config.flags4 & CFG4optimized) 698: s->Spop = 0; 699: else 700: while (s->Spush != 0) 701: { s->Spush--; 702: assert(offi < arraysize(offstack)); 703: /*printf("Pushing offset x%x\n",Aoffset);*/ 704: offstack[offi++] = Aoffset; 705: } 706: #endif 707: 708: switch (s->Sclass) 709: { 710: case SCfastpar: 711: break; // ignore on pass 0 712: case SCregister: 713: case SCauto: 714: if (s->Sfl == FLreg) // if allocated in register 715: break; 716: // See if we can share storage with another variable 717: if (config.flags4 & CFG4optimized && 718: // Don't share because could stomp on variables 719: // used in finally blocks 720: !(usednteh & ~NTEHjmonitor) && 721: s->Srange && sz && flags && !(s->Sflags & SFLspill)) 722: { 723: for (int i = 0; i < si; i++) 724: { 725: if (!vec_testbit(i,tbl)) 726: continue; 727: symbol *sp = globsym.tab[i]; 728: //printf("auto s = '%s', sp = '%s', %d, %d, %d\n",s->Sident,sp->Sident,dfotop,vec_numbits(s->Srange),vec_numbits(sp->Srange)); 729: if (vec_disjoint(s->Srange,sp->Srange) && 730: sz <= type_size(sp->Stype)) 731: { 732: vec_or(sp->Srange,sp->Srange,s->Srange); 733: //printf("sharing space - '%s' onto '%s'\n",s->Sident,sp->Sident); 734: s->Soffset = sp->Soffset; 735: goto L2; 736: } 737: } 738: } 739: Aoffset = align(sz,Aoffset); 740: s->Soffset = Aoffset; 741: //printf("auto '%s' sz = %d, auto offset = x%lx\n",s->Sident,sz,(long)s->Soffset); 742: Aoffset += sz; 743: if (Aoffset > Amax) 744: Amax = Aoffset; 745: if (s->Srange && sz && !(s->Sflags & SFLspill)) 746: vec_setbit(si,tbl); 747: 748: // Align doubles to 8 byte boundary 749: if (!I16 && type_alignsize(s->Stype) > REGSIZE)
warning C4018: '>' : signed/unsigned mismatch
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
750: Aalign = type_alignsize(s->Stype); 751: L2: 752: break; 753: 754: case SCtmp: 755: // Allocated separately from SCauto to avoid storage 756: // overlapping problems. 757: Toffset = align(sz,Toffset); 758: s->Soffset = Toffset; 759: //printf("tmp offset = x%lx\n",(long)s->Soffset); 760: Toffset += sz; 761: break; 762: 763: case SCstack: 764: EEoffset = align(sz,EEoffset); 765: s->Soffset = EEoffset; 766: //printf("EEoffset = x%lx\n",(long)s->Soffset); 767: EEoffset += sz; 768: break; 769: 770: case SCparameter: 771: Poffset = align(REGSIZE,Poffset); /* align on word stack boundary */ 772: if (I64 && alignsize == 16 && Poffset & 8) 773: Poffset += 8; 774: s->Soffset = Poffset; 775: //printf("%s param offset = x%lx, alignsize = %d\n",s->Sident,(long)s->Soffset, (int)alignsize); 776: Poffset += (s->Sflags & SFLdouble) 777: ? type_size(tsdouble) // float passed as double 778: : type_size(s->Stype); 779: break; 780: case SCpseudo: 781: case SCstatic: 782: case SCbprel: 783: break; 784: default: 785: #ifdef DEBUG 786: symbol_print(s); 787: #endif 788: assert(0); 789: } 790: 791: #if AUTONEST 792: while (s->Spop != 0) 793: { s->Spop--; 794: assert(offi > 0); 795: Aoffset = offstack[--offi]; 796: /*printf("Popping offset x%x\n",Aoffset);*/ 797: } 798: #endif 799: } 800: } 801: Aoffset = Amax; 802: Aoffset = align(0,Aoffset); 803: if (Aalign > REGSIZE) 804: Aoffset = (Aoffset + Aalign - 1) & ~(Aalign - 1); 805: //printf("Aligned Aoffset = x%lx, Toffset = x%lx\n", (long)Aoffset,(long)Toffset); 806: Toffset = align(0,Toffset); 807: 808: if (config.flags4 & CFG4optimized) 809: { 810: vec_free(tbl); 811: } 812: } 813: 814: /**************************** 815: * Generate code for a block. 816: */ 817: 818: STATIC void blcodgen(block *bl) 819: { regm_t retregs; 820: bool jcond; 821: elem *e; 822: code *c; 823: block *nextb; 824: block *bs1,*bs2; 825: list_t bpl; 826: int refparamsave; 827: regm_t mfuncregsave = mfuncreg; 828: char *sflsave = NULL; 829: int anyspill; 830: 831: //dbg_printf("blcodgen(%p)\n",bl); 832: 833: /* Determine existing immediate values in registers by ANDing 834: together the values from all the predecessors of b. 835: */ 836: assert(bl->Bregcon.immed.mval == 0); 837: regcon.immed.mval = 0; // assume no previous contents in registers 838: // regcon.cse.mval = 0; 839: for (bpl = bl->Bpred; bpl; bpl = list_next(bpl)) 840: { block *bp = list_block(bpl); 841: 842: if (bpl == bl->Bpred) 843: { regcon.immed = bp->Bregcon.immed; 844: regcon.params = bp->Bregcon.params; 845: // regcon.cse = bp->Bregcon.cse; 846: } 847: else 848: { int i; 849: 850: regcon.params &= bp->Bregcon.params; 851: if ((regcon.immed.mval &= bp->Bregcon.immed.mval) != 0) 852: // Actual values must match, too 853: for (i = 0; i < REGMAX; i++) 854: { 855: if (regcon.immed.value[i] != bp->Bregcon.immed.value[i]) 856: regcon.immed.mval &= ~mask[i]; 857: } 858: #if 0 859: if ((regcon.cse.mval &= bp->Bregcon.cse.mval) != 0) 860: // Actual values must match, too 861: for (i = 0; i < REGMAX; i++) 862: { 863: if (regcon.cse.value[i] != bp->Bregcon.cse.value[i]) 864: regcon.cse.mval &= ~mask[i]; 865: } 866: #endif 867: } 868: } 869: regcon.cse.mops &= regcon.cse.mval; 870: 871: // Set regcon.mvar according to what variables are in registers for this block 872: c = NULL; 873: regcon.mvar = 0; 874: regcon.mpvar = 0; 875: regcon.indexregs = 1; 876: anyspill = 0; 877: if (config.flags4 & CFG4optimized) 878: { SYMIDX i; 879: code *cload = NULL; 880: code *cstore = NULL; 881: 882: sflsave = (char *) alloca(globsym.top * sizeof(char));
warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead
883: for (i = 0; i < globsym.top; i++) 884: { symbol *s = globsym.tab[i]; 885: 886: sflsave[i] = s->Sfl; 887: if (s->Sclass & SCfastpar && 888: regcon.params & mask[s->Spreg] && 889: vec_testbit(dfoidx,s->Srange)) 890: { 891: regcon.used |= mask[s->Spreg]; 892: } 893: 894: if (s->Sfl == FLreg) 895: { if (vec_testbit(dfoidx,s->Srange)) 896: { regcon.mvar |= s->Sregm; 897: if (s->Sclass == SCfastpar) 898: regcon.mpvar |= s->Sregm; 899: } 900: } 901: else if (s->Sflags & SFLspill) 902: { if (vec_testbit(dfoidx,s->Srange)) 903: { 904: anyspill = i + 1; 905: cgreg_spillreg_prolog(bl,s,&cstore,&cload); 906: if (vec_testbit(dfoidx,s->Slvreg)) 907: { s->Sfl = FLreg; 908: regcon.mvar |= s->Sregm; 909: regcon.cse.mval &= ~s->Sregm; 910: regcon.immed.mval &= ~s->Sregm; 911: if (s->Sclass == SCfastpar) 912: regcon.mpvar |= s->Sregm; 913: } 914: } 915: } 916: } 917: if ((regcon.cse.mops & regcon.cse.mval) != regcon.cse.mops) 918: { code *cx; 919: 920: cx = cse_save(regcon.cse.mops & ~regcon.cse.mval); 921: cstore = cat(cx, cstore); 922: } 923: c = cat(cstore,cload); 924: mfuncreg &= ~regcon.mvar; // use these registers 925: regcon.used |= regcon.mvar; 926: 927: // Determine if we have more than 1 uncommitted index register 928: regcon.indexregs = IDXREGS & ~regcon.mvar; 929: regcon.indexregs &= regcon.indexregs - 1; 930: } 931: 932: e = bl->Belem; 933: regsave.idx = 0; 934: retregs = 0; 935: reflocal = 0; 936: refparamsave = refparam; 937: refparam = 0; 938: assert((regcon.cse.mops & regcon.cse.mval) == regcon.cse.mops); 939: switch (bl->BC) /* block exit condition */ 940: { 941: case BCiftrue: 942: jcond = TRUE; 943: bs1 = list_block(bl->Bsucc); 944: bs2 = list_block(list_next(bl->Bsucc)); 945: if (bs1 == bl->Bnext) 946: { // Swap bs1 and bs2 947: block *btmp; 948: 949: jcond ^= 1; 950: btmp = bs1; 951: bs1 = bs2; 952: bs2 = btmp; 953: } 954: c = cat(c,logexp(e,jcond,FLblock,(code *) bs1)); 955: nextb = bs2; 956: bl->Bcode = NULL; 957: L2: 958: if (nextb != bl->Bnext) 959: { if (configv.addlinenumbers && bl->Bsrcpos.Slinnum && 960: !(funcsym_p->ty() & mTYnaked)) 961: cgen_linnum(&c,bl->Bsrcpos); 962: assert(!(bl->Bflags & BFLepilog)); 963: c = cat(c,genjmp(CNIL,JMP,FLblock,nextb)); 964: } 965: bl->Bcode = cat(bl->Bcode,c); 966: break; 967: case BCjmptab: 968: case BCifthen: 969: case BCswitch: 970: assert(!(bl->Bflags & BFLepilog)); 971: doswitch(bl); /* hide messy details */ 972: bl->Bcode = cat(c,bl->Bcode); 973: break; 974: #if MARS 975: case BCjcatch: 976: // Mark all registers as destroyed. This will prevent 977: // register assignments to variables used in catch blocks. 978: c = cat(c,getregs((I32 | I64) ? allregs : (ALLREGS | mES))); 979: #if 0 && TARGET_LINUX 980: if (config.flags3 & CFG3pic && !(allregs & mBX)) 981: { 982: c = cat(c, cod3_load_got()); 983: } 984: #endif 985: goto case_goto; 986: #endif 987: #if SCPP 988: case BCcatch: 989: // Mark all registers as destroyed. This will prevent 990: // register assignments to variables used in catch blocks. 991: c = cat(c,getregs(allregs | mES)); 992: #if 0 && TARGET_LINUX 993: if (config.flags3 & CFG3pic && !(allregs & mBX)) 994: { 995: c = cat(c, cod3_load_got()); 996: } 997: #endif 998: goto case_goto; 999: 1000: case BCtry: 1001: usednteh |= EHtry; 1002: if (config.flags2 & CFG2seh) 1003: usednteh |= NTEHtry; 1004: goto case_goto; 1005: #endif 1006: case BCgoto: 1007: nextb = list_block(bl->Bsucc); 1008: if ((funcsym_p->Sfunc->Fflags3 & Fnteh || 1009: (MARS /*&& config.flags2 & CFG2seh*/)) && 1010: bl->Btry != nextb->Btry && 1011: nextb->BC != BC_finally) 1012: { int toindex; 1013: int fromindex; 1014: 1015: bl->Bcode = NULL; 1016: c = gencodelem(c,e,&retregs,TRUE); 1017: toindex = nextb->Btry ? nextb->Btry->Bscope_index : -1; 1018: assert(bl->Btry); 1019: fromindex = bl->Btry->Bscope_index; 1020: #if MARS 1021: if (toindex + 1 == fromindex) 1022: { // Simply call __finally 1023: if (bl->Btry && 1024: list_block(list_next(bl->Btry->Bsucc))->BC == BCjcatch) 1025: { 1026: goto L2; 1027: } 1028: } 1029: #endif 1030: if (config.flags2 & CFG2seh) 1031: c = cat(c,nteh_unwind(0,toindex)); 1032: #if MARS && (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS) 1033: else if (toindex + 1 <= fromindex) 1034: { 1035: //c = cat(c, linux_unwind(0, toindex)); 1036: block *bt; 1037: 1038: //printf("B%d: fromindex = %d, toindex = %d\n", bl->Bdfoidx, fromindex, toindex); 1039: bt = bl; 1040: while ((bt = bt->Btry) != NULL && bt->Bscope_index != toindex) 1041: { block *bf; 1042: 1043: //printf("\tbt->Bscope_index = %d, bt->Blast_index = %d\n", bt->Bscope_index, bt->Blast_index); 1044: bf = list_block(list_next(bt->Bsucc)); 1045: // Only look at try-finally blocks 1046: if (bf->BC == BCjcatch) 1047: continue; 1048: 1049: if (bf == nextb) 1050: continue; 1051: //printf("\tbf = B%d, nextb = B%d\n", bf->Bdfoidx, nextb->Bdfoidx); 1052: if (nextb->BC == BCgoto && 1053: !nextb->Belem && 1054: bf == list_block(nextb->Bsucc)) 1055: continue; 1056: 1057: // call __finally 1058: code *cs; 1059: code *cr; 1060: int nalign = 0; 1061: 1062: gensaverestore(retregs,&cs,&cr); 1063: if (STACKALIGN == 16) 1064: { int npush = (numbitsset(retregs) + 1) * REGSIZE; 1065: if (npush & (STACKALIGN - 1)) 1066: { nalign = STACKALIGN - (npush & (STACKALIGN - 1)); 1067: cs = genc2(cs,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign 1068: if (I64) 1069: code_orrex(cs, REX_W); 1070: } 1071: } 1072: cs = genc(cs,0xE8,0,0,0,FLblock,(long)list_block(bf->Bsucc)); 1073: if (nalign) 1074: { cs = genc2(cs,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign 1075: if (I64) 1076: code_orrex(cs, REX_W); 1077: } 1078: c = cat3(c,cs,cr); 1079: } 1080: } 1081: #endif 1082: goto L2; 1083: } 1084: case_goto: 1085: c = gencodelem(c,e,&retregs,TRUE); 1086: if (anyspill) 1087: { // Add in the epilog code 1088: code *cstore = NULL; 1089: code *cload = NULL; 1090: 1091: for (int i = 0; i < anyspill; i++) 1092: { symbol *s = globsym.tab[i]; 1093: 1094: if (s->Sflags & SFLspill && 1095: vec_testbit(dfoidx,s->Srange)) 1096: { 1097: s->Sfl = sflsave[i]; // undo block register assignments 1098: cgreg_spillreg_epilog(bl,s,&cstore,&cload); 1099: } 1100: } 1101: c = cat3(c,cstore,cload); 1102: } 1103: 1104: L3: 1105: bl->Bcode = NULL; 1106: nextb = list_block(bl->Bsucc); 1107: goto L2; 1108: 1109: case BC_try: 1110: if (config.flags2 & CFG2seh) 1111: { usednteh |= NTEH_try; 1112: nteh_usevars(); 1113: } 1114: else 1115: usednteh |= EHtry; 1116: goto case_goto; 1117: 1118: case BC_finally: 1119: // Mark all registers as destroyed. This will prevent 1120: // register assignments to variables used in finally blocks. 1121: assert(!getregs(allregs)); 1122: assert(!e); 1123: assert(!bl->Bcode); 1124: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1125: if (config.flags3 & CFG3pic) 1126: { 1127: int nalign = 0; 1128: if (STACKALIGN == 16) 1129: { nalign = STACKALIGN - REGSIZE; 1130: c = genc2(c,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign 1131: if (I64) 1132: code_orrex(c, REX_W); 1133: } 1134: // CALL bl->Bsucc 1135: c = genc(c,0xE8,0,0,0,FLblock,(long)list_block(bl->Bsucc)); 1136: if (nalign) 1137: { c = genc2(c,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign 1138: if (I64) 1139: code_orrex(c, REX_W); 1140: } 1141: // JMP list_next(bl->Bsucc) 1142: nextb = list_block(list_next(bl->Bsucc)); 1143: goto L2; 1144: } 1145: else 1146: #endif 1147: { 1148: // Generate a PUSH of the address of the successor to the 1149: // corresponding BC_ret 1150: //assert(list_block(list_next(bl->Bsucc))->BC == BC_ret); 1151: // PUSH &succ 1152: c = genc(c,0x68,0,0,0,FLblock,(long)list_block(list_next(bl->Bsucc))); 1153: nextb = list_block(bl->Bsucc); 1154: goto L2; 1155: } 1156: 1157: case BC_ret: 1158: c = gencodelem(c,e,&retregs,TRUE); 1159: bl->Bcode = gen1(c,0xC3); // RET 1160: break; 1161: 1162: #if NTEXCEPTIONS 1163: case BC_except: 1164: assert(!e); 1165: usednteh |= NTEH_except; 1166: c = cat(c,nteh_setsp(0x8B)); 1167: getregs(allregs); 1168: goto L3; 1169: 1170: case BC_filter: 1171: c = cat(c,nteh_filter(bl)); 1172: // Mark all registers as destroyed. This will prevent 1173: // register assignments to variables used in filter blocks. 1174: getregs(allregs); 1175: retregs = regmask(e->Ety, TYnfunc); 1176: c = gencodelem(c,e,&retregs,TRUE); 1177: bl->Bcode = gen1(c,0xC3); // RET 1178: break; 1179: #endif 1180: 1181: case BCretexp: 1182: retregs = regmask(e->Ety, funcsym_p->ty()); 1183: 1184: // For the final load into the return regs, don't set regcon.used, 1185: // so that the optimizer can potentially use retregs for register 1186: // variable assignments. 1187: 1188: if (config.flags4 & CFG4optimized) 1189: { regm_t usedsave; 1190: 1191: c = cat(c,docommas(&e)); 1192: usedsave = regcon.used; 1193: if (EOP(e)) 1194: c = gencodelem(c,e,&retregs,TRUE); 1195: else 1196: { 1197: if (e->Eoper == OPconst) 1198: regcon.mvar = 0; 1199: c = gencodelem(c,e,&retregs,TRUE); 1200: regcon.used = usedsave; 1201: if (e->Eoper == OPvar) 1202: { symbol *s = e->EV.sp.Vsym; 1203: 1204: if (s->Sfl == FLreg && s->Sregm != mAX) 1205: retsym = s; 1206: } 1207: } 1208: } 1209: else 1210: { 1211: case BCret: 1212: case BCexit: 1213: c = gencodelem(c,e,&retregs,TRUE); 1214: } 1215: bl->Bcode = c; 1216: if (retregs == mST0) 1217: { assert(stackused == 1); 1218: pop87(); // account for return value 1219: } 1220: else if (retregs == mST01) 1221: { assert(stackused == 2); 1222: pop87(); 1223: pop87(); // account for return value 1224: } 1225: if (bl->BC == BCexit && config.flags4 & CFG4optimized) 1226: mfuncreg = mfuncregsave; 1227: if (MARS || usednteh & NTEH_try) 1228: { block *bt; 1229: 1230: bt = bl; 1231: while ((bt = bt->Btry) != NULL) 1232: { block *bf; 1233: 1234: bf = list_block(list_next(bt->Bsucc)); 1235: #if MARS 1236: // Only look at try-finally blocks 1237: if (bf->BC == BCjcatch) 1238: { 1239: continue; 1240: } 1241: #endif 1242: if (config.flags2 & CFG2seh) 1243: { 1244: if (bt->Bscope_index == 0) 1245: { 1246: // call __finally 1247: code *cs; 1248: code *cr; 1249: 1250: c = cat(c,nteh_gensindex(-1)); 1251: gensaverestore(retregs,&cs,&cr); 1252: cs = genc(cs,0xE8,0,0,0,FLblock,(long)list_block(bf->Bsucc)); 1253: bl->Bcode = cat3(c,cs,cr); 1254: } 1255: else 1256: bl->Bcode = cat(c,nteh_unwind(retregs,~0)); 1257: break; 1258: } 1259: else 1260: { 1261: // call __finally 1262: code *cs; 1263: code *cr; 1264: int nalign = 0; 1265: 1266: gensaverestore(retregs,&cs,&cr); 1267: if (STACKALIGN == 16) 1268: { int npush = (numbitsset(retregs) + 1) * REGSIZE; 1269: if (npush & (STACKALIGN - 1)) 1270: { nalign = STACKALIGN - (npush & (STACKALIGN - 1)); 1271: cs = genc2(cs,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign 1272: if (I64) 1273: code_orrex(cs, REX_W); 1274: } 1275: } 1276: // CALL bf->Bsucc 1277: cs = genc(cs,0xE8,0,0,0,FLblock,(long)list_block(bf->Bsucc)); 1278: if (nalign) 1279: { cs = genc2(cs,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign 1280: if (I64) 1281: code_orrex(cs, REX_W); 1282: } 1283: bl->Bcode = c = cat3(c,cs,cr); 1284: } 1285: } 1286: } 1287: break; 1288: 1289: #if SCPP || MARS 1290: case BCasm: 1291: assert(!e); 1292: // Mark destroyed registers 1293: assert(!c); 1294: c = cat(c,getregs(iasm_regs(bl))); 1295: if (bl->Bsucc) 1296: { nextb = list_block(bl->Bsucc); 1297: if (!bl->Bnext) 1298: goto L2; 1299: if (nextb != bl->Bnext && 1300: bl->Bnext && 1301: !(bl->Bnext->BC == BCgoto && 1302: !bl->Bnext->Belem && 1303: nextb == list_block(bl->Bnext->Bsucc))) 1304: { code *cl; 1305: 1306: // See if already have JMP at end of block 1307: cl = code_last(bl->Bcode); 1308: if (!cl || cl->Iop != JMP) 1309: goto L2; // add JMP at end of block 1310: } 1311: } 1312: break; 1313: #endif 1314: default: 1315: #ifdef DEBUG 1316: printf("bl->BC = %d\n",bl->BC); 1317: #endif 1318: assert(0); 1319: } 1320: 1321: for (int i = 0; i < anyspill; i++) 1322: { symbol *s = globsym.tab[i]; 1323: 1324: s->Sfl = sflsave[i]; // undo block register assignments 1325: } 1326: 1327: if (reflocal) 1328: bl->Bflags |= BFLreflocal; 1329: if (refparam) 1330: bl->Bflags |= BFLrefparam; 1331: refparam |= refparamsave; 1332: bl->Bregcon.immed = regcon.immed; 1333: bl->Bregcon.cse = regcon.cse; 1334: bl->Bregcon.used = regcon.used; 1335: bl->Bregcon.params = regcon.params; 1336: #ifdef DEBUG 1337: debugw && printf("code gen complete\n"); 1338: #endif 1339: } 1340: 1341: /***************************************** 1342: * Add in exception handling code. 1343: */ 1344: 1345: #if SCPP 1346: 1347: STATIC void cgcod_eh() 1348: { block *btry; 1349: code *c; 1350: code *c1; 1351: list_t stack; 1352: list_t list; 1353: block *b; 1354: int idx; 1355: int lastidx; 1356: int tryidx; 1357: int i; 1358: 1359: if (!(usednteh & (EHtry | EHcleanup))) 1360: return; 1361: 1362: // Compute Bindex for each block 1363: for (b = startblock; b; b = b->Bnext) 1364: { b->Bindex = -1; 1365: b->Bflags &= ~BFLvisited; /* mark as unvisited */ 1366: } 1367: btry = NULL; 1368: lastidx = 0; 1369: startblock->Bindex = 0; 1370: for (b = startblock; b; b = b->Bnext) 1371: { 1372: if (btry == b->Btry && b->BC == BCcatch) // if don't need to pop try block 1373: { block *br; 1374: 1375: br = list_block(b->Bpred); // find corresponding try block 1376: assert(br->BC == BCtry); 1377: b->Bindex = br->Bindex; 1378: } 1379: else if (btry != b->Btry && b->BC != BCcatch || 1380: !(b->Bflags & BFLvisited)) 1381: b->Bindex = lastidx; 1382: b->Bflags |= BFLvisited; 1383: #ifdef DEBUG 1384: if (debuge) 1385: { 1386: WRBC(b->BC); 1387: dbg_printf(" block (%p) Btry=%p Bindex=%d\n",b,b->Btry,b->Bindex); 1388: } 1389: #endif 1390: except_index_set(b->Bindex); 1391: if (btry != b->Btry) // exited previous try block 1392: { 1393: except_pop(b,NULL,btry); 1394: btry = b->Btry; 1395: } 1396: if (b->BC == BCtry) 1397: { 1398: except_push(b,NULL,b); 1399: btry = b; 1400: tryidx = except_index_get(); 1401: b->Bcode = cat(nteh_gensindex(tryidx - 1),b->Bcode); 1402: } 1403: 1404: stack = NULL; 1405: for (c = b->Bcode; c; c = code_next(c)) 1406: { 1407: if ((c->Iop & 0xFF) == ESCAPE) 1408: { 1409: c1 = NULL; 1410: switch (c->Iop & 0xFFFF00) 1411: { 1412: case ESCctor: 1413: //printf("ESCctor\n"); 1414: except_push(c,c->IEV1.Vtor,NULL); 1415: goto L1; 1416: 1417: case ESCdtor: 1418: //printf("ESCdtor\n"); 1419: except_pop(c,c->IEV1.Vtor,NULL); 1420: L1: if (config.flags2 & CFG2seh) 1421: { 1422: c1 = nteh_gensindex(except_index_get() - 1); 1423: code_next(c1) = code_next(c); 1424: code_next(c) = c1; 1425: } 1426: break; 1427: case ESCmark: 1428: //printf("ESCmark\n"); 1429: idx = except_index_get(); 1430: list_prependdata(&stack,idx); 1431: except_mark(); 1432: break; 1433: case ESCrelease: 1434: //printf("ESCrelease\n"); 1435: idx = list_data(stack); 1436: list_pop(&stack); 1437: if (idx != except_index_get()) 1438: { 1439: if (config.flags2 & CFG2seh) 1440: { c1 = nteh_gensindex(idx - 1); 1441: code_next(c1) = code_next(c); 1442: code_next(c) = c1; 1443: } 1444: else 1445: { except_pair_append(c,idx - 1); 1446: c->Iop = ESCAPE | ESCoffset; 1447: } 1448: } 1449: except_release(); 1450: break; 1451: case ESCmark2: 1452: //printf("ESCmark2\n"); 1453: except_mark(); 1454: break; 1455: case ESCrelease2: 1456: //printf("ESCrelease2\n"); 1457: except_release(); 1458: break; 1459: } 1460: } 1461: } 1462: assert(stack == NULL); 1463: b->Bendindex = except_index_get(); 1464: 1465: if (b->BC != BCret && b->BC != BCretexp) 1466: lastidx = b->Bendindex; 1467: 1468: // Set starting index for each of the successors 1469: i = 0; 1470: for (list = b->Bsucc; list; list = list_next(list)) 1471: { block *bs = list_block(list); 1472: 1473: if (b->BC == BCtry) 1474: { switch (i) 1475: { case 0: // block after catches 1476: bs->Bindex = b->Bendindex; 1477: break; 1478: case 1: // 1st catch block 1479: bs->Bindex = tryidx; 1480: break; 1481: default: // subsequent catch blocks 1482: bs->Bindex = b->Bindex; 1483: break; 1484: } 1485: #ifdef DEBUG 1486: if (debuge) 1487: { 1488: dbg_printf(" 1setting %p to %d\n",bs,bs->Bindex); 1489: } 1490: #endif 1491: } 1492: else if (!(bs->Bflags & BFLvisited)) 1493: { 1494: bs->Bindex = b->Bendindex; 1495: #ifdef DEBUG 1496: if (debuge) 1497: { 1498: dbg_printf(" 2setting %p to %d\n",bs,bs->Bindex); 1499: } 1500: #endif 1501: } 1502: bs->Bflags |= BFLvisited; 1503: i++; 1504: } 1505: } 1506: 1507: if (config.flags2 & CFG2seh) 1508: for (b = startblock; b; b = b->Bnext) 1509: { 1510: if (/*!b->Bcount ||*/ b->BC == BCtry) 1511: continue; 1512: for (list = b->Bpred; list; list = list_next(list)) 1513: { int pi; 1514: 1515: pi = list_block(list)->Bendindex; 1516: if (b->Bindex != pi) 1517: { 1518: b->Bcode = cat(nteh_gensindex(b->Bindex - 1),b->Bcode); 1519: break; 1520: } 1521: } 1522: } 1523: } 1524: 1525: #endif 1526: 1527: /***************************** 1528: * Given a type, return a mask of 1529: * registers to hold that type. 1530: * Input: 1531: * tyf function type 1532: */ 1533: 1534: regm_t regmask(tym_t tym, tym_t tyf) 1535: { 1536: switch (tybasic(tym)) 1537: { 1538: case TYvoid: 1539: case TYstruct: 1540: return 0; 1541: case TYbool: 1542: case TYwchar_t: 1543: case TYchar16: 1544: case TYchar: 1545: case TYschar: 1546: case TYuchar: 1547: case TYshort: 1548: case TYushort: 1549: case TYint: 1550: case TYuint: 1551: #if JHANDLE 1552: case TYjhandle: 1553: #endif 1554: case TYnullptr: 1555: case TYnptr: 1556: case TYsptr: 1557: case TYcptr: 1558: return mAX; 1559: 1560: case TYfloat: 1561: case TYifloat: 1562: if (I64) 1563: return mXMM0; 1564: if (config.exe & EX_flat) 1565: return mST0; 1566: case TYlong: 1567: case TYulong: 1568: case TYdchar: 1569: if (!I16) 1570: return mAX; 1571: case TYfptr: 1572: case TYhptr: 1573: return mDX | mAX; 1574: 1575: case TYcent: 1576: case TYucent: 1577: assert(I64); 1578: return mDX | mAX; 1579: 1580: case TYvptr: 1581: return mDX | mBX; 1582: 1583: case TYdouble: 1584: case TYdouble_alias: 1585: case TYidouble: 1586: if (I64) 1587: return mXMM0; 1588: if (config.exe & EX_flat) 1589: return mST0; 1590: return DOUBLEREGS; 1591: 1592: case TYllong: 1593: case TYullong: 1594: return I64 ? mAX : (I32 ? mDX | mAX : DOUBLEREGS); 1595: 1596: case TYldouble: 1597: case TYildouble: 1598: return mST0; 1599: 1600: case TYcfloat: 1601: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 1602: if (I32 && tybasic(tyf) == TYnfunc) 1603: return mDX | mAX; 1604: #endif 1605: case TYcdouble: 1606: if (I64) 1607: return mXMM0 | mXMM1; 1608: case TYcldouble: 1609: return mST01; 1610: 1611: default: 1612: #if DEBUG 1613: WRTYxx(tym); 1614: #endif 1615: assert(0); 1616: return 0; 1617: } 1618: } 1619: 1620: /****************************** 1621: * Count the number of bits set in a register mask. 1622: */ 1623: 1624: int numbitsset(regm_t regm) 1625: { int n; 1626: 1627: n = 0; 1628: if (regm) 1629: do 1630: n++; 1631: while ((regm &= regm - 1) != 0); 1632: return n; 1633: } 1634: 1635: /****************************** 1636: * Given a register mask, find and return the number 1637: * of the first register that fits. 1638: */ 1639: 1640: #undef findreg 1641: 1642: unsigned findreg(regm_t regm 1643: #ifdef DEBUG 1644: ,int line,const char *file 1645: #endif 1646: ) 1647: #ifdef DEBUG 1648: #define findreg(regm) findreg((regm),__LINE__,__FILE__) 1649: #endif 1650: { 1651: #ifdef DEBUG 1652: regm_t regmsave = regm; 1653: #endif 1654: int i = 0; 1655: while (1) 1656: { 1657: if (!(regm & 0xF)) 1658: { 1659: regm >>= 4; 1660: i += 4; 1661: if (!regm) 1662: break; 1663: } 1664: if (regm & 1) 1665: return i; 1666: regm >>= 1; 1667: i++; 1668: } 1669: #ifdef DEBUG 1670: printf("findreg(x%x, line=%d, file='%s')\n",regmsave,line,file); 1671: fflush(stdout); 1672: #endif 1673: //*(char*)0=0; 1674: assert(0); 1675: return 0; 1676: } 1677: 1678: /*************** 1679: * Free element (but not it's leaves! (assume they are already freed)) 1680: * Don't decrement Ecount! This is so we can detect if the common subexp 1681: * has already been evaluated. 1682: * If common subexpression is not required anymore, eliminate 1683: * references to it. 1684: */ 1685: 1686: void freenode(elem *e) 1687: { unsigned i; 1688: 1689: elem_debug(e); 1690: //dbg_printf("freenode(%p) : comsub = %d, count = %d\n",e,e->Ecomsub,e->Ecount); 1691: if (e->Ecomsub--) return; /* usage count */ 1692: if (e->Ecount) /* if it was a CSE */ 1693: { for (i = 0; i < arraysize(regcon.cse.value); i++) 1694: { if (regcon.cse.value[i] == e) /* if a register is holding it */ 1695: { regcon.cse.mval &= ~mask[i]; 1696: regcon.cse.mops &= ~mask[i]; /* free masks */ 1697: } 1698: } 1699: for (i = 0; i < cstop; i++) 1700: { if (csextab[i].e == e) 1701: csextab[i].e = NULL; 1702: } 1703: } 1704: } 1705: 1706: /********************************* 1707: * Reset Ecomsub for all elem nodes, i.e. reverse the effects of freenode(). 1708: */ 1709: 1710: STATIC void resetEcomsub(elem *e) 1711: { unsigned op; 1712: 1713: while (1) 1714: { 1715: elem_debug(e); 1716: e->Ecomsub = e->Ecount; 1717: op = e->Eoper; 1718: if (!OTleaf(op)) 1719: { if (OTbinary(op)) 1720: resetEcomsub(e->E2); 1721: e = e->E1; 1722: } 1723: else 1724: break; 1725: } 1726: } 1727: 1728: /********************************* 1729: * Determine if elem e is a register variable. 1730: * If so: 1731: * *pregm = mask of registers that make up the variable 1732: * *preg = the least significant register 1733: * returns TRUE 1734: * Else 1735: * returns FALSE 1736: */ 1737: 1738: int isregvar(elem *e,regm_t *pregm,unsigned *preg) 1739: { symbol *s; 1740: unsigned u;
warning C4101: 'u' : unreferenced local variable
1741: regm_t m;
warning C4101: 'm' : unreferenced local variable
1742: regm_t regm; 1743: unsigned reg; 1744: 1745: elem_debug(e); 1746: if (e->Eoper == OPvar || e->Eoper == OPrelconst) 1747: { 1748: s = e->EV.sp.Vsym; 1749: switch (s->Sfl) 1750: { case FLreg: 1751: if (s->Sclass == SCparameter) 1752: { refparam = TRUE; 1753: reflocal = TRUE; 1754: } 1755: reg = s->Sreglsw; 1756: regm = s->Sregm; 1757: //assert(tyreg(s->ty())); 1758: #if 0 1759: // Let's just see if there is a CSE in a reg we can use 1760: // instead. This helps avoid AGI's. 1761: if (e->Ecount && e->Ecount != e->Ecomsub) 1762: { int i; 1763: 1764: for (i = 0; i < arraysize(regcon.cse.value); i++) 1765: { 1766: if (regcon.cse.value[i] == e) 1767: { reg = i; 1768: break; 1769: } 1770: } 1771: } 1772: #endif 1773: assert(regm & regcon.mvar && !(regm & ~regcon.mvar)); 1774: goto Lreg; 1775: 1776: case FLpseudo: 1777: #if MARS 1778: assert(0); 1779: #else 1780: u = s->Sreglsw; 1781: m = pseudomask[u]; 1782: if (m & ALLREGS && (u & ~3) != 4) // if not BP,SP,EBP,ESP,or ?H 1783: { reg = pseudoreg[u] & 7; 1784: regm = m; 1785: goto Lreg; 1786: } 1787: #endif 1788: break; 1789: } 1790: } 1791: return FALSE; 1792: 1793: Lreg: 1794: if (preg) 1795: *preg = reg; 1796: if (pregm) 1797: *pregm = regm; 1798: return TRUE; 1799: } 1800: 1801: /********************************* 1802: * Allocate some registers. 1803: * Input: 1804: * pretregs Pointer to mask of registers to make selection from. 1805: * tym Mask of type we will store in registers. 1806: * Output: 1807: * *pretregs Mask of allocated registers. 1808: * *preg Register number of first allocated register. 1809: * msavereg,mfuncreg retregs bits are cleared. 1810: * regcon.cse.mval,regcon.cse.mops updated 1811: * Returns: 1812: * pointer to code generated if necessary to save any regcon.cse.mops on the 1813: * stack. 1814: */ 1815: 1816: #undef allocreg 1817: 1818: code *allocreg(regm_t *pretregs,unsigned *preg,tym_t tym 1819: #ifdef DEBUG 1820: ,int line,const char *file 1821: #endif 1822: ) 1823: #ifdef DEBUG 1824: #define allocreg(a,b,c) allocreg((a),(b),(c),__LINE__,__FILE__) 1825: #endif 1826: { regm_t r; 1827: regm_t retregs; 1828: unsigned reg; 1829: unsigned msreg,lsreg; 1830: int count; 1831: unsigned size; 1832: 1833: #if 0 1834: if (pass == PASSfinal) 1835: { dbg_printf("allocreg %s,%d: regcon.mvar %s regcon.cse.mval %s msavereg %s *pretregs %s tym ", 1836: file,line,regm_str(regcon.mvar),regm_str(regcon.cse.mval), 1837: regm_str(msavereg),regm_str(*pretregs)); 1838: WRTYxx(tym); 1839: dbg_printf("\n"); 1840: } 1841: #endif 1842: tym = tybasic(tym); 1843: size = tysize[tym]; 1844: *pretregs &= mES | allregs | XMMREGS; 1845: retregs = *pretregs; 1846: if ((retregs & regcon.mvar) == retregs) // if exactly in reg vars 1847: { 1848: if (size <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1849: { *preg = findreg(retregs); 1850: assert(retregs == mask[*preg]); /* no more bits are set */ 1851: } 1852: else if (size <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1853: { *preg = findregmsw(retregs); 1854: assert(retregs & mLSW); 1855: } 1856: else 1857: assert(0); 1858: return getregs(retregs); 1859: } 1860: count = 0; 1861: L1: 1862: //printf("L1: allregs = x%x, *pretregs = x%x\n", allregs, *pretregs); 1863: assert(++count < 20); /* fail instead of hanging if blocked */ 1864: assert(retregs); 1865: msreg = lsreg = (unsigned)-1; /* no value assigned yet */ 1866: L3: 1867: //printf("L2: allregs = x%x, *pretregs = x%x\n", allregs, *pretregs); 1868: r = retregs & ~(msavereg | regcon.cse.mval | regcon.params); 1869: if (!r) 1870: { 1871: r = retregs & ~(msavereg | regcon.cse.mval); 1872: if (!r) 1873: { 1874: r = retregs & ~(msavereg | regcon.cse.mops); 1875: if (!r) 1876: { r = retregs & ~msavereg; 1877: if (!r) 1878: r = retregs; 1879: } 1880: } 1881: } 1882: if (0 && r & ~fregsaved) 1883: r &= ~fregsaved; 1884: 1885: if (size <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1886: { 1887: if (r & ~mBP) 1888: r &= ~mBP; 1889: 1890: // If only one index register, prefer to not use LSW registers 1891: if (!regcon.indexregs && r & ~mLSW) 1892: r &= ~mLSW; 1893: 1894: if (pass == PASSfinal && r & ~lastretregs && !I16)
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1895: { // Try not to always allocate the same register, 1896: // to schedule better 1897: 1898: r &= ~lastretregs; 1899: if (r & ~last2retregs) 1900: { r &= ~last2retregs; 1901: if (r & ~last3retregs) 1902: { r &= ~last3retregs; 1903: if (r & ~last4retregs) 1904: { r &= ~last4retregs; 1905: // if (r & ~last5retregs) 1906: // r &= ~last5retregs; 1907: } 1908: } 1909: } 1910: if (r & ~mfuncreg) 1911: r &= ~mfuncreg; 1912: } 1913: reg = findreg(r); 1914: retregs = mask[reg]; 1915: } 1916: else if (size <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
1917: { 1918: /* Select pair with both regs free. Failing */ 1919: /* that, select pair with one reg free. */ 1920: 1921: if (r & mBP) 1922: { retregs &= ~mBP; 1923: goto L3; 1924: } 1925: 1926: if (r & mMSW) 1927: { 1928: if (r & mDX) 1929: msreg = DX; /* prefer to use DX over CX */ 1930: else 1931: msreg = findregmsw(r); 1932: r &= mLSW; /* see if there's an LSW also */ 1933: if (r) 1934: lsreg = findreg(r); 1935: else if (lsreg == -1) /* if don't have LSW yet */ 1936: { retregs &= mLSW; 1937: goto L3; 1938: } 1939: } 1940: else 1941: { 1942: if (I64 && !(r & mLSW)) 1943: { retregs = *pretregs & (mMSW | mLSW); 1944: assert(retregs); 1945: goto L1; 1946: } 1947: lsreg = findreglsw(r); 1948: if (msreg == -1) 1949: { retregs &= mMSW; 1950: assert(retregs); 1951: goto L3; 1952: } 1953: } 1954: reg = (msreg == ES) ? lsreg : msreg; 1955: retregs = mask[msreg] | mask[lsreg]; 1956: } 1957: else if (I16 && (tym == TYdouble || tym == TYdouble_alias)) 1958: { 1959: #ifdef DEBUG 1960: if (retregs != DOUBLEREGS) 1961: printf("retregs = x%x, *pretregs = x%x\n",retregs,*pretregs); 1962: #endif 1963: assert(retregs == DOUBLEREGS); 1964: reg = AX; 1965: } 1966: else 1967: { 1968: #ifdef DEBUG 1969: WRTYxx(tym); 1970: printf("\nallocreg: fil %s lin %d, regcon.mvar x%x msavereg x%x *pretregs x%x, reg %d, tym x%x\n", 1971: file,line,regcon.mvar,msavereg,*pretregs,*preg,tym); 1972: #endif 1973: assert(0); 1974: } 1975: if (retregs & regcon.mvar) // if conflict with reg vars 1976: { 1977: if (!(size > REGSIZE && *pretregs == (mAX | mDX)))
warning C4018: '>' : signed/unsigned mismatch
1978: { 1979: retregs = (*pretregs &= ~(retregs & regcon.mvar)); 1980: goto L1; // try other registers 1981: } 1982: } 1983: *preg = reg; 1984: *pretregs = retregs; 1985: 1986: //printf("Allocating %s\n",regm_str(retregs)); 1987: last5retregs = last4retregs; 1988: last4retregs = last3retregs; 1989: last3retregs = last2retregs; 1990: last2retregs = lastretregs; 1991: lastretregs = retregs; 1992: return getregs(retregs); 1993: } 1994: 1995: /************************* 1996: * Mark registers as used. 1997: */ 1998: 1999: void useregs(regm_t regm) 2000: { 2001: //printf("useregs(x%x) %s\n", regm, regm_str(regm)); 2002: mfuncreg &= ~regm; 2003: regcon.used |= regm; // registers used in this block 2004: regcon.params &= ~regm; 2005: if (regm & regcon.mpvar) // if modified a fastpar register variable 2006: regcon.params = 0; // toss them all out 2007: } 2008: 2009: /************************* 2010: * We are going to use the registers in mask r. 2011: * Generate any code necessary to save any regs. 2012: */ 2013: 2014: code *getregs(regm_t r) 2015: { regm_t ms; 2016: 2017: //printf("getregs(x%x)\n",r); 2018: ms = r & regcon.cse.mops; // mask of common subs we must save 2019: useregs(r); 2020: regcon.cse.mval &= ~r; 2021: msavereg &= ~r; // regs that are destroyed 2022: regcon.immed.mval &= ~r; 2023: return ms ? cse_save(ms) : NULL; 2024: } 2025: 2026: /***************************************** 2027: * Copy registers in cse.mops into memory. 2028: */ 2029: 2030: STATIC code * cse_save(regm_t ms) 2031: { unsigned reg,i,op; 2032: code *c = NULL; 2033: regm_t regm; 2034: 2035: assert((ms & regcon.cse.mops) == ms); 2036: regcon.cse.mops &= ~ms; 2037: 2038: /* Skip CSEs that are already saved */ 2039: for (regm = 1; regm <= mES; regm <<= 1) 2040: { 2041: if (regm & ms) 2042: { elem *e; 2043: 2044: e = regcon.cse.value[findreg(regm)]; 2045: for (i = 0; i < csmax; i++) 2046: { 2047: if (csextab[i].e == e) 2048: { 2049: tym_t tym; 2050: unsigned sz; 2051: 2052: tym = e->Ety; 2053: sz = tysize(tym); 2054: if (sz <= REGSIZE ||
warning C4018: '<=' : signed/unsigned mismatch
2055: sz <= 2 * REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
2056: (regm & mMSW && csextab[i].regm & mMSW || 2057: regm & mLSW && csextab[i].regm & mLSW) || 2058: sz == 4 * REGSIZE && regm == csextab[i].regm 2059: ) 2060: { 2061: ms &= ~regm; 2062: if (!ms) 2063: goto Lret; 2064: break; 2065: } 2066: } 2067: } 2068: } 2069: } 2070: 2071: for (i = cstop; ms; i++) 2072: { 2073: if (i >= csmax) /* array overflow */ 2074: { unsigned cseinc; 2075: 2076: #ifdef DEBUG 2077: cseinc = 8; /* flush out reallocation bugs */ 2078: #else 2079: cseinc = csmax + 32; 2080: #endif 2081: csextab = (struct CSE *) util_realloc(csextab, 2082: (csmax + cseinc), sizeof(csextab[0])); 2083: memset(&csextab[csmax],0,cseinc * sizeof(csextab[0])); 2084: csmax += cseinc; 2085: goto L1; 2086: } 2087: if (i >= cstop) 2088: { 2089: memset(&csextab[cstop],0,sizeof(csextab[0])); 2090: goto L1; 2091: } 2092: if (csextab[i].e == NULL || i >= cstop) 2093: { 2094: L1: 2095: reg = findreg(ms); /* the register to save */ 2096: csextab[i].e = regcon.cse.value[reg]; 2097: csextab[i].regm = mask[reg]; 2098: csextab[i].flags &= CSEload; 2099: if (i >= cstop) 2100: cstop = i + 1; 2101: 2102: ms &= ~mask[reg]; /* turn off reg bit in ms */ 2103: 2104: // If we can simply reload the CSE, we don't need to save it 2105: if (!cse_simple(csextab[i].e,i)) 2106: { 2107: // MOV i[BP],reg 2108: op = 0x89; // normal mov 2109: if (reg == ES) 2110: { reg = 0; // the real reg number 2111: op = 0x8C; // segment reg mov 2112: } 2113: c = genc1(c,op,modregxrm(2, reg, BPRM),FLcs,(targ_uns) i); 2114: if (I64) 2115: code_orrex(c, REX_W); 2116: reflocal = TRUE; 2117: } 2118: } 2119: } 2120: Lret: 2121: return c; 2122: } 2123: 2124: /****************************************** 2125: * Getregs without marking immediate register values as gone. 2126: */ 2127: 2128: code *getregs_imm(regm_t r) 2129: { code *c; 2130: regm_t save; 2131: 2132: save = regcon.immed.mval; 2133: c = getregs(r); 2134: regcon.immed.mval = save; 2135: return c; 2136: } 2137: 2138: /****************************************** 2139: * Flush all CSE's out of registers and into memory. 2140: * Input: 2141: * do87 !=0 means save 87 registers too 2142: */ 2143: 2144: code *cse_flush(int do87) 2145: { code *c; 2146: 2147: //dbg_printf("cse_flush()\n"); 2148: c = cse_save(regcon.cse.mops); // save any CSEs to memory 2149: if (do87) 2150: c = cat(c,save87()); // save any 8087 temporaries 2151: return c; 2152: } 2153: 2154: /************************************************* 2155: */ 2156: 2157: STATIC int cse_simple(elem *e,int i) 2158: { regm_t regm; 2159: unsigned reg; 2160: code *c; 2161: int sz; 2162: 2163: sz = tysize[tybasic(e->Ety)]; 2164: if (!I16 && // don't bother with 16 bit code
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2165: e->Eoper == OPadd && 2166: sz == REGSIZE && 2167: e->E2->Eoper == OPconst && 2168: e->E1->Eoper == OPvar && 2169: isregvar(e->E1,&regm,&reg) && 2170: sz <= REGSIZE && 2171: !(e->E1->EV.sp.Vsym->Sflags & SFLspill) 2172: ) 2173: { 2174: c = &csextab[i].csimple; 2175: memset(c,0,sizeof(*c)); 2176: 2177: // Make this an LEA instruction 2178: c->Iop = 0x8D; // LEA 2179: buildEA(c,reg,-1,1,e->E2->EV.Vuns); 2180: if (I64) 2181: { if (sz == 8) 2182: c->Irex |= REX_W; 2183: else if (sz == 1 && reg >= 4) 2184: c->Irex |= REX; 2185: } 2186: 2187: csextab[i].flags |= CSEsimple; 2188: return 1; 2189: } 2190: else if (e->Eoper == OPind && 2191: sz <= REGSIZE && 2192: e->E1->Eoper == OPvar && 2193: isregvar(e->E1,&regm,&reg) && 2194: (I32 || I64 || regm & IDXREGS) && 2195: !(e->E1->EV.sp.Vsym->Sflags & SFLspill) 2196: ) 2197: { 2198: c = &csextab[i].csimple; 2199: memset(c,0,sizeof(*c)); 2200: 2201: // Make this a MOV instruction 2202: c->Iop = (sz == 1) ? 0x8A : 0x8B; // MOV reg,EA 2203: buildEA(c,reg,-1,1,0); 2204: if (sz == 2 && I32) 2205: c->Iflags |= CFopsize; 2206: else if (I64) 2207: { if (sz == 8) 2208: c->Irex |= REX_W; 2209: else if (sz == 1 && reg >= 4) 2210: c->Irex |= REX; 2211: } 2212: 2213: csextab[i].flags |= CSEsimple; 2214: return 1; 2215: } 2216: return 0; 2217: } 2218: 2219: /************************* 2220: * Common subexpressions exist in registers. Note this in regcon.cse.mval. 2221: * Input: 2222: * e the subexpression 2223: * regm mask of registers holding it 2224: * opsflag if != 0 then regcon.cse.mops gets set too 2225: */ 2226: 2227: void cssave(elem *e,regm_t regm,unsigned opsflag) 2228: { unsigned i; 2229: 2230: /*if (e->Ecount && e->Ecount == e->Ecomsub)*/ 2231: if (e->Ecount && e->Ecomsub) 2232: { 2233: //printf("cssave(e = %p, regm = x%x, opsflag = %d)\n", e, regm, opsflag); 2234: if (!opsflag && pass != PASSfinal && (I32 || I64)) 2235: return; 2236: 2237: //printf("cssave(e = %p, regm = x%x, opsflag = x%x)\n", e, regm, opsflag); 2238: regm &= mBP | ALLREGS | mES; /* just to be sure */ 2239: 2240: #if 0 2241: /* Do not register CSEs if they are register variables and */ 2242: /* are not operator nodes. This forces the register allocation */ 2243: /* to go through allocreg(), which will prevent using register */ 2244: /* variables for scratch. */ 2245: if (opsflag || !(regm & regcon.mvar)) 2246: #endif 2247: for (i = 0; regm; i++) 2248: { regm_t mi; 2249: 2250: mi = mask[i]; 2251: if (regm & mi) 2252: { 2253: regm &= ~mi; 2254: 2255: // If we don't need this CSE, and the register already 2256: // holds a CSE that we do need, don't mark the new one 2257: if (regcon.cse.mval & mi && regcon.cse.value[i] != e && 2258: !opsflag && regcon.cse.mops & mi) 2259: continue; 2260: 2261: regcon.cse.mval |= mi; 2262: if (opsflag) 2263: regcon.cse.mops |= mi; 2264: //printf("cssave set: regcon.cse.value[%s] = %p\n",regstring[i],e); 2265: regcon.cse.value[i] = e; 2266: } 2267: } 2268: } 2269: } 2270: 2271: /************************************* 2272: * Determine if a computation should be done into a register. 2273: */ 2274: 2275: bool evalinregister(elem *e) 2276: { regm_t emask; 2277: unsigned i; 2278: unsigned sz; 2279: 2280: if (e->Ecount == 0) /* elem is not a CSE, therefore */ 2281: /* we don't need to evaluate it */ 2282: /* in a register */ 2283: return FALSE; 2284: if (EOP(e)) /* operators are always in register */ 2285: return TRUE; 2286: sz = tysize(e->Ety); 2287: if (e->Ecount == e->Ecomsub) /* elem is a CSE that needs */ 2288: /* to be generated */ 2289: { 2290: if ((I32 || I64) && pass == PASSfinal && sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2291: { 2292: // Do it only if at least 2 registers are available 2293: regm_t m; 2294: 2295: m = allregs & ~regcon.mvar; 2296: if (sz == 1) 2297: m &= BYTEREGS; 2298: if (m & (m - 1)) // if more than one register 2299: { // Need to be at least 3 registers available, as 2300: // addressing modes can use up 2. 2301: while (!(m & 1)) 2302: m >>= 1; 2303: m >>= 1; 2304: if (m & (m - 1)) 2305: return TRUE; 2306: } 2307: } 2308: return FALSE; 2309: } 2310: 2311: /* Elem is now a CSE that might have been generated. If so, and */ 2312: /* it's in a register already, the computation should be done */ 2313: /* using that register. */ 2314: emask = 0; 2315: for (i = 0; i < arraysize(regcon.cse.value); i++) 2316: if (regcon.cse.value[i] == e) 2317: emask |= mask[i]; 2318: emask &= regcon.cse.mval; // mask of available CSEs 2319: if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2320: return emask != 0; /* the CSE is in a register */ 2321: else if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2322: return (emask & mMSW) && (emask & mLSW); 2323: return TRUE; /* cop-out for now */ 2324: } 2325: 2326: /******************************************************* 2327: * Return mask of scratch registers. 2328: */ 2329: 2330: regm_t getscratch() 2331: { regm_t scratch; 2332: 2333: scratch = 0; 2334: if (pass == PASSfinal) 2335: { 2336: scratch = allregs & ~(regcon.mvar | regcon.mpvar | regcon.cse.mval | 2337: regcon.immed.mval | regcon.params | mfuncreg); 2338: } 2339: return scratch; 2340: } 2341: 2342: /****************************** 2343: * Evaluate an elem that is a common subexp that has been encountered 2344: * before. 2345: * Look first to see if it is already in a register. 2346: */ 2347: 2348: STATIC code * comsub(elem *e,regm_t *pretregs) 2349: { tym_t tym; 2350: regm_t regm,emask,csemask; 2351: unsigned reg,i,byte,sz; 2352: code *c; 2353: 2354: //printf("comsub(e = %p, *pretregs = %s)\n",e,regm_str(*pretregs)); 2355: elem_debug(e); 2356: #ifdef DEBUG 2357: if (e->Ecomsub > e->Ecount) 2358: elem_print(e); 2359: #endif 2360: assert(e->Ecomsub <= e->Ecount); 2361: 2362: c = CNIL; 2363: if (*pretregs == 0) goto done; /* no possible side effects anyway */ 2364: 2365: if (tyfloating(e->Ety) && config.inline8087) 2366: return comsub87(e,pretregs); 2367: 2368: /* First construct a mask, emask, of all the registers that */ 2369: /* have the right contents. */ 2370: 2371: emask = 0; 2372: for (i = 0; i < arraysize(regcon.cse.value); i++) 2373: { 2374: //dbg_printf("regcon.cse.value[%d] = %p\n",i,regcon.cse.value[i]); 2375: if (regcon.cse.value[i] == e) /* if contents are right */ 2376: emask |= mask[i]; /* turn on bit for reg */ 2377: } 2378: emask &= regcon.cse.mval; /* make sure all bits are valid */ 2379: 2380: /* create mask of what's in csextab[] */ 2381: csemask = 0; 2382: for (i = 0; i < cstop; i++) 2383: { if (csextab[i].e) 2384: elem_debug(csextab[i].e); 2385: if (csextab[i].e == e)
warning C4390: ';' : empty controlled statement found; is this the intent?
2386: csemask |= csextab[i].regm; 2387: } 2388: csemask &= ~emask; /* stuff already in registers */ 2389: 2390: #ifdef DEBUG 2391: if (debugw) 2392: { 2393: printf("comsub(e=%p): *pretregs=%x, emask=%x, csemask=%x, regcon.cse.mval=%x, regcon.mvar=%x\n", 2394: e,*pretregs,emask,csemask,regcon.cse.mval,regcon.mvar); 2395: if (regcon.cse.mval & 1) elem_print(regcon.cse.value[i]); 2396: } 2397: #endif 2398: 2399: tym = tybasic(e->Ety); 2400: sz = tysize[tym]; 2401: byte = sz == 1; 2402: 2403: if (sz <= REGSIZE) // if data will fit in one register
warning C4018: '<=' : signed/unsigned mismatch
2404: { 2405: /* First see if it is already in a correct register */ 2406: 2407: regm = emask & *pretregs; 2408: if (regm == 0) 2409: regm = emask; /* try any other register */ 2410: if (regm) /* if it's in a register */ 2411: { 2412: if (EOP(e) || !(regm & regcon.mvar) || (*pretregs & regcon.mvar) == *pretregs) 2413: { 2414: regm = mask[findreg(regm)]; 2415: goto fix; 2416: } 2417: } 2418: 2419: if (!EOP(e)) /* if not op or func */ 2420: goto reload; /* reload data */ 2421: for (i = cstop; i--;) /* look through saved comsubs */ 2422: if (csextab[i].e == e) /* found it */ 2423: { regm_t retregs; 2424: 2425: if (csextab[i].flags & CSEsimple) 2426: { code *cr; 2427: 2428: retregs = *pretregs; 2429: if (byte && !(retregs & BYTEREGS)) 2430: retregs = BYTEREGS; 2431: else if (!(retregs & allregs)) 2432: retregs = allregs; 2433: c = allocreg(&retregs,&reg,tym); 2434: cr = &csextab[i].csimple; 2435: cr->setReg(reg); 2436: c = gen(c,cr); 2437: goto L10; 2438: } 2439: else 2440: { 2441: reflocal = TRUE; 2442: csextab[i].flags |= CSEload; 2443: if (*pretregs == mPSW) /* if result in CCs only */ 2444: { // CMP cs[BP],0 2445: c = genc(NULL,0x81 ^ byte,modregrm(2,7,BPRM), 2446: FLcs,i, FLconst,(targ_uns) 0); 2447: if (I32 && sz == 2) 2448: c->Iflags |= CFopsize; 2449: } 2450: else 2451: { 2452: retregs = *pretregs; 2453: if (byte && !(retregs & BYTEREGS)) 2454: retregs = BYTEREGS; 2455: c = allocreg(&retregs,&reg,tym); 2456: // MOV reg,cs[BP] 2457: c = genc1(c,0x8B,modregxrm(2,reg,BPRM),FLcs,(targ_uns) i); 2458: if (I64) 2459: code_orrex(c, REX_W); 2460: L10: 2461: regcon.cse.mval |= mask[reg]; // cs is in a reg 2462: regcon.cse.value[reg] = e; 2463: c = cat(c,fixresult(e,retregs,pretregs)); 2464: } 2465: } 2466: freenode(e); 2467: return c; 2468: } 2469: #ifdef DEBUG 2470: printf("couldn't find cse e = %p, pass = %d\n",e,pass); 2471: elem_print(e); 2472: #endif 2473: assert(0); /* should have found it */ 2474: } 2475: else /* reg pair is req'd */ 2476: if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2477: { unsigned msreg,lsreg; 2478: 2479: /* see if we have both */ 2480: if (!((emask | csemask) & mMSW && (emask | csemask) & (mLSW | mBP))) 2481: { /* we don't have both */ 2482: #if DEBUG 2483: if (EOP(e)) 2484: { 2485: printf("e = %p, op = x%x, emask = x%x, csemask = x%x\n", 2486: e,e->Eoper,emask,csemask); 2487: //printf("mMSW = x%x, mLSW = x%x\n", mMSW, mLSW); 2488: elem_print(e); 2489: } 2490: #endif 2491: assert(!EOP(e)); /* must have both for operators */ 2492: goto reload; 2493: } 2494: 2495: /* Look for right vals in any regs */ 2496: 2497: regm = *pretregs & mMSW; 2498: if (emask & regm) 2499: msreg = findreg(emask & regm); 2500: else if (emask & mMSW) 2501: msreg = findregmsw(emask); 2502: else /* reload from cse array */ 2503: { 2504: if (!regm) 2505: regm = mMSW & ALLREGS; 2506: c = allocreg(&regm,&msreg,TYint); 2507: c = cat(c,loadcse(e,msreg,mMSW)); 2508: } 2509: 2510: regm = *pretregs & (mLSW | mBP); 2511: if (emask & regm) 2512: lsreg = findreg(emask & regm); 2513: else if (emask & (mLSW | mBP)) 2514: lsreg = findreglsw(emask); 2515: else 2516: { 2517: if (!regm) 2518: regm = mLSW; 2519: c = cat(c,allocreg(&regm,&lsreg,TYint)); 2520: c = cat(c,loadcse(e,lsreg,mLSW | mBP)); 2521: } 2522: 2523: regm = mask[msreg] | mask[lsreg]; /* mask of result */ 2524: goto fix; 2525: } 2526: else if (tym == TYdouble || tym == TYdouble_alias) // double 2527: { 2528: assert(I16); 2529: if (((csemask | emask) & DOUBLEREGS_16) == DOUBLEREGS_16) 2530: { 2531: for (reg = AX; reg != -1; reg = dblreg[reg]) 2532: { assert((int) reg >= 0 && reg <= 7); 2533: if (mask[reg] & csemask) 2534: c = cat(c,loadcse(e,reg,mask[reg])); 2535: } 2536: regm = DOUBLEREGS_16; 2537: goto fix; 2538: } 2539: if (!EOP(e)) goto reload; 2540: #if DEBUG 2541: printf("e = %p, csemask = x%x, emask = x%x\n",e,csemask,emask); 2542: #endif 2543: assert(0); 2544: } 2545: else 2546: { 2547: #if DEBUG 2548: printf("e = %p, tym = x%x\n",e,tym); 2549: #endif 2550: assert(0); 2551: } 2552: 2553: reload: /* reload result from memory */ 2554: switch (e->Eoper) 2555: { 2556: case OPrelconst: 2557: c = cdrelconst(e,pretregs); 2558: break; 2559: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS 2560: case OPgot: 2561: c = cdgot(e,pretregs); 2562: break; 2563: #endif 2564: default: 2565: c = loaddata(e,pretregs); 2566: break; 2567: } 2568: cssave(e,*pretregs,FALSE); 2569: freenode(e); 2570: return c; 2571: 2572: fix: /* we got result in regm, fix */ 2573: c = cat(c,fixresult(e,regm,pretregs)); 2574: done: 2575: freenode(e); 2576: return c; 2577: } 2578: 2579: 2580: /***************************** 2581: * Load reg from cse stack. 2582: * Returns: 2583: * pointer to the MOV instruction 2584: */ 2585: 2586: STATIC code * loadcse(elem *e,unsigned reg,regm_t regm) 2587: { unsigned i,op; 2588: code *c; 2589: 2590: for (i = cstop; i--;) 2591: { 2592: //printf("csextab[%d] = %p, regm = x%x\n", i, csextab[i].e, csextab[i].regm); 2593: if (csextab[i].e == e && csextab[i].regm & regm) 2594: { 2595: reflocal = TRUE; 2596: csextab[i].flags |= CSEload; /* it was loaded */ 2597: c = getregs(mask[reg]); 2598: regcon.cse.value[reg] = e; 2599: regcon.cse.mval |= mask[reg]; 2600: op = 0x8B; 2601: if (reg == ES) 2602: { op = 0x8E; 2603: reg = 0; 2604: } 2605: c = genc1(c,op,modregxrm(2,reg,BPRM),FLcs,(targ_uns) i); 2606: if (I64) 2607: code_orrex(c, REX_W); 2608: return c; 2609: } 2610: } 2611: #if DEBUG 2612: printf("loadcse(e = %p, reg = %d, regm = x%x)\n",e,reg,regm); 2613: elem_print(e); 2614: #endif 2615: assert(0); 2616: /* NOTREACHED */ 2617: return 0; 2618: } 2619: 2620: /*************************** 2621: * Generate code sequence for an elem. 2622: * Input: 2623: * pretregs mask of possible registers to return result in 2624: * Note: longs are in AX,BX or CX,DX or SI,DI 2625: * doubles are AX,BX,CX,DX only 2626: * constflag TRUE if user of result will not modify the 2627: * registers returned in *pretregs. 2628: * Output: 2629: * *pretregs mask of registers result is returned in 2630: * Returns: 2631: * pointer to code sequence generated 2632: */ 2633: 2634: #include "cdxxx.c" /* jump table */ 2635: 2636: code *codelem(elem *e,regm_t *pretregs,bool constflag) 2637: { code *c; 2638: Symbol *s; 2639: unsigned op; 2640: 2641: #ifdef DEBUG 2642: if (debugw) 2643: { printf("+codelem(e=%p,*pretregs=%s) ",e,regm_str(*pretregs)); 2644: WROP(e->Eoper); 2645: printf("msavereg=x%x regcon.cse.mval=x%x regcon.cse.mops=x%x\n", 2646: msavereg,regcon.cse.mval,regcon.cse.mops); 2647: printf("Ecount = %d, Ecomsub = %d\n", e->Ecount, e->Ecomsub); 2648: } 2649: #endif 2650: assert(e); 2651: elem_debug(e); 2652: if ((regcon.cse.mops & regcon.cse.mval) != regcon.cse.mops) 2653: { 2654: #ifdef DEBUG 2655: printf("+codelem(e=%p,*pretregs=x%x) ",e,*pretregs); 2656: elem_print(e); 2657: printf("msavereg=x%x regcon.cse.mval=x%x regcon.cse.mops=x%x\n", 2658: msavereg,regcon.cse.mval,regcon.cse.mops); 2659: printf("Ecount = %d, Ecomsub = %d\n", e->Ecount, e->Ecomsub); 2660: #endif 2661: assert(0); 2662: } 2663: 2664: if (!constflag && *pretregs & (mES | ALLREGS | mBP) & ~regcon.mvar) 2665: *pretregs &= ~regcon.mvar; /* can't use register vars */ 2666: op = e->Eoper; 2667: if (e->Ecount && e->Ecount != e->Ecomsub) /* if common subexp */ 2668: { c = comsub(e,pretregs); 2669: goto L1; 2670: } 2671: 2672: switch (op) 2673: { 2674: default: 2675: if (e->Ecount) /* if common subexp */ 2676: { 2677: /* if no return value */ 2678: if ((*pretregs & (mSTACK | mES | ALLREGS | mBP)) == 0) 2679: { if (tysize(e->Ety) == 1) 2680: *pretregs |= BYTEREGS; 2681: else if (tybasic(e->Ety) == TYdouble || tybasic(e->Ety) == TYdouble_alias) 2682: *pretregs |= DOUBLEREGS; 2683: else 2684: *pretregs |= ALLREGS; /* make one */ 2685: } 2686: 2687: /* BUG: For CSEs, make sure we have both an MSW */ 2688: /* and an LSW specified in *pretregs */ 2689: } 2690: assert(op <= OPMAX); 2691: c = (*cdxxx[op])(e,pretregs); 2692: break; 2693: case OPrelconst: 2694: c = cdrelconst(e,pretregs); 2695: break; 2696: case OPvar: 2697: if (constflag && (s = e->EV.sp.Vsym)->Sfl == FLreg && 2698: (s->Sregm & *pretregs) == s->Sregm) 2699: { 2700: if (tysize(e->Ety) <= REGSIZE && tysize(s->Stype->Tty) == 2 * REGSIZE) 2701: *pretregs &= mPSW | (s->Sregm & mLSW); 2702: else 2703: *pretregs &= mPSW | s->Sregm; 2704: } 2705: case OPconst: 2706: if (*pretregs == 0 && (e->Ecount >= 3 || e->Ety & mTYvolatile)) 2707: { 2708: switch (tybasic(e->Ety)) 2709: { 2710: case TYbool: 2711: case TYchar: 2712: case TYschar: 2713: case TYuchar: 2714: *pretregs |= BYTEREGS; 2715: break; 2716: #if JHANDLE 2717: case TYjhandle: 2718: #endif 2719: case TYnptr: 2720: case TYsptr: 2721: case TYcptr: 2722: *pretregs |= IDXREGS; 2723: break; 2724: case TYshort: 2725: case TYushort: 2726: case TYint: 2727: case TYuint: 2728: case TYlong: 2729: case TYulong: 2730: case TYllong: 2731: case TYullong: 2732: case TYcent: 2733: case TYucent: 2734: #if !TARGET_FLAT 2735: case TYfptr: 2736: case TYhptr: 2737: #endif 2738: case TYvptr: 2739: *pretregs |= ALLREGS; 2740: break; 2741: } 2742: } 2743: c = loaddata(e,pretregs); 2744: break; 2745: } 2746: cssave(e,*pretregs,!OTleaf(op)); 2747: freenode(e); 2748: L1: 2749: #ifdef DEBUG 2750: if (debugw) 2751: { printf("-codelem(e=%p,*pretregs=x%x) ",e,*pretregs); 2752: WROP(op); 2753: printf("msavereg=x%x regcon.cse.mval=x%x regcon.cse.mops=x%x\n", 2754: msavereg,regcon.cse.mval,regcon.cse.mops); 2755: } 2756: #endif 2757: if (configv.addlinenumbers && e->Esrcpos.Slinnum) 2758: cgen_prelinnum(&c,e->Esrcpos); 2759: return c; 2760: } 2761: 2762: /********************************************* 2763: * Turn register mask into a string suitable for printing. 2764: */ 2765: 2766: #ifdef DEBUG 2767: 2768: const char *regm_str(regm_t rm) 2769: { 2770: #define NUM 4 2771: #define SMAX 64 2772: static char str[NUM][SMAX + 1]; 2773: static int i; 2774: char *p; 2775: int j; 2776: 2777: if (rm == 0) 2778: return "0"; 2779: if (rm == ALLREGS) 2780: return "ALLREGS"; 2781: if (rm == BYTEREGS) 2782: return "BYTEREGS"; 2783: if (rm == allregs) 2784: return "allregs"; 2785: p = str[i]; 2786: if (++i == NUM) 2787: i = 0; 2788: *p = 0; 2789: for (j = 0; j < 32; j++) 2790: { 2791: if (mask[j] & rm) 2792: { 2793: strcat(p,regstring[j]); 2794: rm &= ~mask[j]; 2795: if (rm) 2796: strcat(p,"|"); 2797: } 2798: } 2799: if (rm) 2800: { char *s = p + strlen(p); 2801: sprintf(s,"x%02x",rm); 2802: } 2803: assert(strlen(p) <= SMAX); 2804: return strdup(p); 2805: } 2806: 2807: #endif 2808: 2809: #endif // !SPP 2810: