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        <string.h>
 17: #include        <time.h>
 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: /*************************************
 29:  * Handy function to answer the question: who the heck is generating this piece of code?
 30:  */
 31: inline void ccheck(code *cs)
 32: {
 33: //    if (cs->Iop == LEA && (cs->Irm & 0x3F) == 0x34 && cs->Isib == 7) *(char*)0=0;
 34: //    if (cs->Iop == 0x31) *(char*)0=0;
 35: //    if (cs->Iop == 0x8A && cs->Irm == 0xF6) *(char*)0=0;
 36: }
 37: 
 38: /*****************************
 39:  * Find last code in list.
 40:  */
 41: 
 42: code *code_last(code *c)
 43: {
 44:     if (c)
 45:     {   while (c->next)
 46:             c = c->next;
 47:     }
 48:     return c;
 49: }
 50: 
 51: /*****************************
 52:  * Set flag bits on last code in list.
 53:  */
 54: 
 55: void code_orflag(code *c,unsigned flag)
 56: {
 57:     if (flag && c)
 58:     {   while (c->next)
 59:             c = c->next;
 60:         c->Iflags |= flag;
 61:     }
 62: }
 63: 
 64: /*****************************
 65:  * Set rex bits on last code in list.
 66:  */
 67: 
 68: void code_orrex(code *c,unsigned rex)
 69: {
 70:     if (rex && c)
 71:     {   while (c->next)
 72:             c = c->next;
 73:         c->Irex |= rex;
 74:     }
 75: }
 76: 
 77: /**************************************
 78:  * Set the opcode fields in cs.
 79:  */
 80: code *setOpcode(code *c, code *cs, unsigned op)
 81: {
 82:     cs->Iop = op;
 83:     return c;
 84: }
 85: 
 86: /*****************************
 87:  * Concatenate two code lists together. Return pointer to result.
 88:  */
 89: 
 90: #if TX86 && __INTSIZE == 4 && __SC__
 91: __declspec(naked) code * __pascal cat(code *c1,code *c2)
 92: {
 93:     _asm
 94:     {
 95:         mov     EAX,c1-4[ESP]
 96:         mov     ECX,c2-4[ESP]
 97:         test    EAX,EAX
 98:         jne     L6D
 99:         mov     EAX,ECX
100:         ret     8
101: 
102: L6D:    mov     EDX,EAX
103:         cmp     dword ptr [EAX],0
104:         je      L7B
105: L74:    mov     EDX,[EDX]
106:         cmp     dword ptr [EDX],0
107:         jne     L74
108: L7B:    mov     [EDX],ECX
109:         ret     8
110:     }
111: }
112: #else
113: code * __pascal cat(code *c1,code *c2)
114: {   code **pc;
115: 
116:     if (!c1)
117:         return c2;
118:     for (pc = &code_next(c1); *pc; pc = &code_next(*pc))
119:         ;
120:     *pc = c2;
121:     return c1;
122: }
123: #endif
124: 
125: code * cat3(code *c1,code *c2,code *c3)
126: {   code **pc;
127: 
128:     for (pc = &c1; *pc; pc = &code_next(*pc))
129:         ;
130:     for (*pc = c2; *pc; pc = &code_next(*pc))
131:         ;
132:     *pc = c3;
133:     return c1;
134: }
135: 
136: code * cat4(code *c1,code *c2,code *c3,code *c4)
137: {   code **pc;
138: 
139:     for (pc = &c1; *pc; pc = &code_next(*pc))
140:         ;
141:     for (*pc = c2; *pc; pc = &code_next(*pc))
142:         ;
143:     for (*pc = c3; *pc; pc = &code_next(*pc))
144:         ;
145:     *pc = c4;
146:     return c1;
147: }
148: 
149: code * cat6(code *c1,code *c2,code *c3,code *c4,code *c5,code *c6)
150: { return cat(cat4(c1,c2,c3,c4),cat(c5,c6)); }
151: 
152: /*****************************
153:  * Add code to end of linked list.
154:  * Note that unused operands are garbage.
155:  * gen1() and gen2() are shortcut routines.
156:  * Input:
157:  *      c ->    linked list that code is to be added to end of
158:  *      cs ->   data for the code
159:  * Returns:
160:  *      pointer to start of code list
161:  */
162: 
163: code *gen(code *c,code *cs)
164: {   code *ce,*cstart;
165:     unsigned reg;
166: 
167: #ifdef DEBUG                            /* this is a high usage routine */
168:     assert(cs);
169: #endif
170:     assert(I64 || cs->Irex == 0);
171:     ce = code_calloc();
172:     *ce = *cs;
173:     //printf("ce = %p %02x\n", ce, ce->Iop);
174:     ccheck(ce);
175:     if (config.flags4 & CFG4optimized &&
176:         (ce->Iop == 0x81 || ce->Iop == 0x80) &&
177:         ce->IFL2 == FLconst &&
178:         reghasvalue((ce->Iop == 0x80) ? BYTEREGS : ALLREGS,I64 ? ce->IEV2.Vsize_t : ce->IEV2.Vlong,&reg) &&
179:         !(ce->Iflags & CFopsize && I16)
180:        )
181:     {   // See if we can replace immediate instruction with register instruction
182:         static unsigned char regop[8] =
183:                 { 0x00,0x08,0x10,0x18,0x20,0x28,0x30,0x38 };
184: 
185:         //printf("replacing 0x%02x, val = x%lx\n",ce->Iop,ce->IEV2.Vlong);
186:         ce->Iop = regop[(ce->Irm & modregrm(0,7,0)) >> 3] | (ce->Iop & 1);
187:         code_newreg(ce, reg);
188:     }
189:     code_next(ce) = CNIL;
190:     if (c)
191:     {   cstart = c;
192:         while (code_next(c)) c = code_next(c);  /* find end of list     */
193:         code_next(c) = ce;                      /* link into list       */
194:         return cstart;
195:     }
196:     return ce;
197: }
198: 
199: code *gen1(code *c,unsigned op)
200: { code *ce,*cstart;
201: 
202:   ce = code_calloc();
203:   ce->Iop = op;
204:   assert(op != LEA);
205:   if (c)
206:   {     cstart = c;
207:         while (code_next(c)) c = code_next(c);  /* find end of list     */
208:         code_next(c) = ce;                      /* link into list       */
209:         return cstart;
210:   }
211:   return ce;
212: }
213: 
214: code *gen2(code *c,unsigned op,unsigned rm)
215: { code *ce,*cstart;
216: 
217:   cstart = ce = code_calloc();
218:   /*cxcalloc++;*/
219:   ce->Iop = op;
220:   ce->Iea = rm;
221:   ccheck(ce);
222:   if (c)
223:   {     cstart = c;
224:         while (code_next(c)) c = code_next(c);  /* find end of list     */
225:         code_next(c) = ce;                      /* link into list       */
226:   }
227:   return cstart;
228: }
229: 
230: code *gen2sib(code *c,unsigned op,unsigned rm,unsigned sib)
231: { code *ce,*cstart;
232: 
233:   cstart = ce = code_calloc();
234:   /*cxcalloc++;*/
235:   ce->Iop = op;
236:   ce->Irm = rm;
237:   ce->Isib = sib;
238:   ce->Irex = (rm | (sib & (REX_B << 16))) >> 16;
239:   if (sib & (REX_R << 16))
240:         ce->Irex |= REX_X;
241:   ccheck(ce);
242:   if (c)
243:   {     cstart = c;
244:         while (code_next(c)) c = code_next(c);  /* find end of list     */
245:         code_next(c) = ce;                      /* link into list       */
246:   }
247:   return cstart;
248: }
249: 
250: code *genregs(code *c,unsigned op,unsigned dstreg,unsigned srcreg)
251: { return gen2(c,op,modregxrmx(3,dstreg,srcreg)); }
252: 
253: code *gentstreg(code *c,unsigned t)
254: {
255:     c = gen2(c,0x85,modregxrmx(3,t,t));   // TEST t,t
256:     code_orflag(c,CFpsw);
257:     return c;
258: }
259: 
260: code *genpush(code *c, unsigned reg)
261: {
262:     c = gen1(c, 0x50 + (reg & 7));
263:     if (reg & 8)
264:         code_orrex(c, REX_B);
265:     return c;
266: }
267: 
268: code *genpop(code *c, unsigned reg)
269: {
270:     c = gen1(c, 0x58 + (reg & 7));
271:     if (reg & 8)
272:         code_orrex(c, REX_B);
273:     return c;
274: }
275: 
276: /********************************
277:  * Generate an ASM sequence.
278:  */
279: 
280: code *genasm(code *c,char *s,unsigned slen)
281: {   code *ce;
282: 
283:     ce = code_calloc();
284:     ce->Iop = ASM;
285:     ce->IFL1 = FLasm;
286:     ce->IEV1.as.len = slen;
287:     ce->IEV1.as.bytes = (char *) mem_malloc(slen);
288:     memcpy(ce->IEV1.as.bytes,s,slen);
289:     return cat(c,ce);
290: }
291: 
292: /**************************
293:  * Generate a MOV to,from register instruction.
294:  * Smart enough to dump redundant register moves, and segment
295:  * register moves.
296:  */
297: 
298: code *genmovreg(code *c,unsigned to,unsigned from)
299: {
300: #if DEBUG
301:         if (to > ES || from > ES)
302:                 printf("genmovreg(c = %p, to = %d, from = %d)\n",c,to,from);
303: #endif
304:         assert(to <= ES && from <= ES);
305:         if (to != from)
306:         {
307:                 if (to == ES)
308:                         c = genregs(c,0x8E,0,from);
309:                 else if (from == ES)
310:                         c = genregs(c,0x8C,0,to);
311:                 else
312:                         c = genregs(c,0x89,from,to);
313:                 if (I64)
314:                         code_orrex(c, REX_W);
315:         }
316:         return c;
317: }
318: 
319: /**************************
320:  * Generate a jump instruction.
321:  */
322: 
323: code *genjmp(code *c,unsigned op,unsigned fltarg,block *targ)
324: {   code cs;
325:     code *cj;
326:     code *cnop;
327: 
328:     cs.Iop = op & 0xFF;
329:     cs.Iflags = 0;
330:     cs.Irex = 0;
331:     if (op != JMP && op != 0xE8)        // if not already long branch
332:           cs.Iflags = CFjmp16;          /* assume long branch for op = 0x7x */
333:     cs.IFL2 = fltarg;                   /* FLblock (or FLcode)          */
334:     cs.IEV2.Vblock = targ;              /* target block (or code)       */
335:     if (fltarg == FLcode)
336:         ((code *)targ)->Iflags |= CFtarg;
337: 
338:     if (config.flags4 & CFG4fastfloat)  // if fast floating point
339:         return gen(c,&cs);
340: 
341:     cj = gen(CNIL,&cs);
342:     switch (op & 0xFF00)                /* look at second jump opcode   */
343:     {
344:         /* The JP and JNP come from floating point comparisons          */
345:         case JP << 8:
346:             cs.Iop = JP;
347:             gen(cj,&cs);
348:             break;
349:         case JNP << 8:
350:             /* Do a JP around the jump instruction      */
351:             cnop = gennop(CNIL);
352:             c = genjmp(c,JP,FLcode,(block *) cnop);
353:             cat(cj,cnop);
354:             break;
355:         case 1 << 8:                    /* toggled no jump              */
356:         case 0 << 8:
357:             break;
358:         default:
359: #ifdef DEBUG
360:             printf("jop = x%x\n",op);
361: #endif
362:             assert(0);
363:     }
364:     return cat(c,cj);
365: }
366: 
367: code *gencs(code *c,unsigned op,unsigned ea,unsigned FL2,symbol *s)
368: {   code cs;
369: 
370:     cs.Iop = op;
371:     cs.Iea = ea;
372:     ccheck(&cs);
373:     cs.Iflags = 0;
374:     cs.IFL2 = FL2;
375:     cs.IEVsym2 = s;
376:     cs.IEVoffset2 = 0;
377: 
378:     return gen(c,&cs);
379: }
380: 
381: code *genc2(code *c,unsigned op,unsigned ea,targ_size_t EV2)
382: {   code cs;
383: 
384:     cs.Iop = op;
385:     cs.Iea = ea;
386:     ccheck(&cs);
387:     cs.Iflags = CFoff;
388:     cs.IFL2 = FLconst;
389:     cs.IEV2.Vsize_t = EV2;
390:     return gen(c,&cs);
391: }
392: 
393: /*****************
394:  * Generate code.
395:  */
396: 
397: code *genc1(code *c,unsigned op,unsigned ea,unsigned FL1,targ_size_t EV1)
398: {   code cs;
399: 
400:     assert(FL1 < FLMAX);
401:     cs.Iop = op;
402:     cs.Iflags = CFoff;
403:     cs.Iea = ea;
404:     ccheck(&cs);
405:     cs.IFL1 = FL1;
406:     cs.IEV1.Vsize_t = EV1;
407:     return gen(c,&cs);
408: }
409: 
410: /*****************
411:  * Generate code.
412:  */
413: 
414: code *genc(code *c,unsigned op,unsigned ea,unsigned FL1,targ_size_t EV1,unsigned FL2,targ_size_t EV2)
415: {   code cs;
416: 
417:     assert(FL1 < FLMAX);
418:     cs.Iop = op;
419:     cs.Iea = ea;
420:     ccheck(&cs);
421:     cs.Iflags = CFoff;
422:     cs.IFL1 = FL1;
423:     cs.IEV1.Vsize_t = EV1;
424:     assert(FL2 < FLMAX);
425:     cs.IFL2 = FL2;
426:     cs.IEV2.Vsize_t = EV2;
427:     return gen(c,&cs);
428: }
429: 
430: /***************************************
431:  * Generate immediate multiply instruction for r1=r2*imm.
432:  * Optimize it into LEA's if we can.
433:  */
434: 
435: code *genmulimm(code *c,unsigned r1,unsigned r2,targ_int imm)
436: {   code cs;
437: 
438:     // These optimizations should probably be put into pinholeopt()
439:     switch (imm)
440:     {   case 1:
441:             c = genmovreg(c,r1,r2);
442:             break;
443:         case 5:
444:             cs.Iop = LEA;
445:             cs.Iflags = 0;
446:             cs.Irex = 0;
447:             buildEA(&cs,r2,r2,4,0);
448:             cs.orReg(r1);
449:             c = gen(c,&cs);
450:             break;
451:         default:
452:             c = genc2(c,0x69,modregxrmx(3,r1,r2),imm);    // IMUL r1,r2,imm
453:             break;
454:     }
455:     return c;
456: }
457: 
458: /********************************
459:  * Generate 'instruction' which is actually a line number.
460:  */
461: 
462: code *genlinnum(code *c,Srcpos srcpos)
463: {   code cs;
464: 
465: #if 0
466:     srcpos.print("genlinnum");
467: #endif
468:     cs.Iop = ESCAPE | ESClinnum;
469:     cs.Iflags = 0;
470:     cs.Irex = 0;
471:     cs.IFL1 = 0;
472:     cs.IFL2 = 0;
473:     cs.IEV2.Vsrcpos = srcpos;
474:     return gen(c,&cs);
475: }
476: 
477: /******************************
478:  * Append line number to existing code.
479:  */
480: 
481: void cgen_linnum(code **pc,Srcpos srcpos)
482: {
483:     *pc = genlinnum(*pc,srcpos);
484: }
485: 
486: /*****************************
487:  * Prepend line number to existing code.
488:  */
489: 
490: void cgen_prelinnum(code **pc,Srcpos srcpos)
491: {
492:     *pc = cat(genlinnum(NULL,srcpos),*pc);
493: }
494: 
495: /********************************
496:  * Generate 'instruction' which tells the address resolver that the stack has
497:  * changed.
498:  */
499: 
500: code *genadjesp(code *c, int offset)
501: {   code cs;
502: 
503:     if (!I16 && offset)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
504: { 505: cs.Iop = ESCAPE | ESCadjesp; 506: cs.Iflags = 0; 507: cs.Irex = 0; 508: cs.IEV2.Vint = offset; 509: return gen(c,&cs); 510: } 511: else 512: return c; 513: } 514: 515: /******************************** 516: * Generate 'nop' 517: */ 518: 519: code *gennop(code *c) 520: { 521: return gen1(c,NOP); 522: } 523: 524: /****************************** 525: * Load CX with the value of _AHSHIFT. 526: */ 527: 528: code *genshift(code *c) 529: { 530: #if SCPP && TX86 531: code *c1; 532: 533: // Set up ahshift to trick ourselves into giving the right fixup, 534: // which must be seg-relative, external frame, external target. 535: c1 = gencs(CNIL,0xC7,modregrm(3,0,CX),FLfunc,rtlsym[RTLSYM_AHSHIFT]); 536: c1->Iflags |= CFoff; 537: return cat(c,c1); 538: #else 539: assert(0); 540: return 0; 541: #endif 542: } 543: 544: /****************************** 545: * Move constant value into reg. 546: * Take advantage of existing values in registers. 547: * If flags & mPSW 548: * set flags based on result 549: * Else if flags & 8 550: * do not disturb flags 551: * Else 552: * don't care about flags 553: * If flags & 1 then byte move 554: * If flags & 2 then short move (for I32 and I64) 555: * If flags & 4 then don't disturb unused portion of register 556: * If flags & 16 then reg is a byte register AL..BH 557: * If flags & 64 (0x40) then 64 bit move (I64 only) 558: * Returns: 559: * code (if any) generated 560: */ 561: 562: code *movregconst(code *c,unsigned reg,targ_size_t value,regm_t flags) 563: { unsigned r; 564: regm_t mreg; 565: 566: //printf("movregconst(reg=%s, value= %lld (%llx), flags=%x)\n", regm_str(mask[reg]), value, value, flags); 567: #define genclrreg(a,r) genregs(a,0x31,r,r) 568: 569: regm_t regm = regcon.immed.mval & mask[reg]; 570: targ_size_t regv = regcon.immed.value[reg]; 571: 572: if (flags & 1) // 8 bits 573: { 574: value &= 0xFF; 575: regm &= BYTEREGS; 576: 577: // If we already have the right value in the right register 578: if (regm && (regv & 0xFF) == value) 579: goto L2; 580: 581: if (flags & 16 && reg & 4 && // if an H byte register 582: regcon.immed.mval & mask[reg & 3] && 583: (((regv = regcon.immed.value[reg & 3]) >> 8) & 0xFF) == value) 584: goto L2; 585: 586: /* Avoid byte register loads on Pentium Pro and Pentium II 587: * to avoid dependency stalls. 588: */ 589: if (config.flags4 & CFG4speed && 590: config.target_cpu >= TARGET_PentiumPro && !(flags & 4)) 591: goto L3; 592: 593: // See if another register has the right value 594: r = 0; 595: for (mreg = (regcon.immed.mval & BYTEREGS); mreg; mreg >>= 1) 596: { 597: if (mreg & 1) 598: { 599: if ((regcon.immed.value[r] & 0xFF) == value) 600: { c = genregs(c,0x8A,reg,r); // MOV regL,rL 601: if (I64 && reg >= 4 || r >= 4) 602: code_orrex(c, REX); 603: goto L2; 604: } 605: if (!(I64 && reg >= 4) && 606: r < 4 && ((regcon.immed.value[r] >> 8) & 0xFF) == value) 607: { c = genregs(c,0x8A,reg,r | 4); // MOV regL,rH 608: goto L2; 609: } 610: } 611: r++; 612: } 613: 614: if (value == 0 && !(flags & 8)) 615: { 616: if (!(flags & 4) && // if we can set the whole register 617: !(flags & 16 && reg & 4)) // and reg is not an H register 618: { c = genregs(c,0x31,reg,reg); // XOR reg,reg 619: regimmed_set(reg,value); 620: regv = 0; 621: } 622: else 623: c = genregs(c,0x30,reg,reg); // XOR regL,regL 624: flags &= ~mPSW; // flags already set by XOR 625: } 626: else 627: { c = genc2(c,0xC6,modregrmx(3,0,reg),value); /* MOV regL,value */ 628: if (reg >= 4 && I64) 629: { 630: code_orrex(c, REX); 631: } 632: } 633: L2: 634: if (flags & mPSW) 635: genregs(c,0x84,reg,reg); // TEST regL,regL 636: 637: if (regm) 638: // Set just the 'L' part of the register value 639: regimmed_set(reg,(regv & ~(targ_size_t)0xFF) | value); 640: else if (flags & 16 && reg & 4 && regcon.immed.mval & mask[reg & 3]) 641: // Set just the 'H' part of the register value 642: regimmed_set((reg & 3),(regv & ~(targ_size_t)0xFF00) | (value << 8)); 643: return c; 644: } 645: L3: 646: if (I16) 647: value = (targ_short) value; /* sign-extend MSW */ 648: else if (I32) 649: value = (targ_int) value; 650: 651: if (!I16 && flags & 2) // load 16 bit value
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
652: { 653: value &= 0xFFFF; 654: if (value == 0) 655: goto L1; 656: else 657: { 658: if (flags & mPSW) 659: goto L1; 660: code *c1 = genc2(CNIL,0xC7,modregrmx(3,0,reg),value); // MOV reg,value 661: c1->Iflags |= CFopsize; // yes, even for I64 662: c = cat(c,c1); 663: if (regm) 664: // High bits of register are not affected by 16 bit load 665: regimmed_set(reg,(regv & ~(targ_size_t)0xFFFF) | value); 666: } 667: return c; 668: } 669: L1: 670: 671: /* If we already have the right value in the right register */ 672: if (regm && (regv & 0xFFFFFFFF) == (value & 0xFFFFFFFF) && !(flags & 64)) 673: { if (flags & mPSW) 674: c = gentstreg(c,reg); 675: } 676: else if (flags & 64 && regm && regv == value) 677: { // Look at the full 64 bits 678: if (flags & mPSW) 679: { 680: c = gentstreg(c,reg); 681: code_orrex(c, REX_W); 682: } 683: } 684: else 685: { 686: if (flags & mPSW) 687: { 688: switch (value) 689: { case 0: 690: c = genclrreg(c,reg); 691: if (flags & 64) 692: code_orrex(c, REX_W); 693: break; 694: case 1: 695: if (I64) 696: goto L4; 697: c = genclrreg(c,reg); 698: goto inc; 699: case -1: 700: if (I64) 701: goto L4; 702: c = genclrreg(c,reg); 703: goto dec; 704: default: 705: L4: 706: if (flags & 64) 707: { 708: c = genc2(c,0xC7,(REX_W << 16) | modregrmx(3,0,reg),value); // MOV reg,value64 709: gentstreg(c,reg); 710: code_orrex(c, REX_W); 711: } 712: else 713: { c = genc2(c,0xC7,modregrmx(3,0,reg),value); /* MOV reg,value */ 714: gentstreg(c,reg); 715: } 716: break; 717: } 718: } 719: else 720: { 721: /* Look for single byte conversion */ 722: if (regcon.immed.mval & mAX) 723: { 724: if (I32) 725: { if (reg == AX && value == (targ_short) regv) 726: { c = gen1(c,0x98); /* CWDE */ 727: goto done; 728: } 729: if (reg == DX && 730: value == (regcon.immed.value[AX] & 0x80000000 ? 0xFFFFFFFF : 0) && 731: !(config.flags4 & CFG4speed && config.target_cpu >= TARGET_Pentium) 732: ) 733: { c = gen1(c,0x99); /* CDQ */ 734: goto done; 735: } 736: } 737: else if (I16) 738: { 739: if (reg == AX && 740: (targ_short) value == (signed char) regv) 741: { c = gen1(c,0x98); /* CBW */ 742: goto done; 743: } 744: 745: if (reg == DX && 746: (targ_short) value == (regcon.immed.value[AX] & 0x8000 ? (targ_short) 0xFFFF : (targ_short) 0) && 747: !(config.flags4 & CFG4speed && config.target_cpu >= TARGET_Pentium) 748: ) 749: { c = gen1(c,0x99); /* CWD */ 750: goto done; 751: } 752: } 753: } 754: if (value == 0 && !(flags & 8) && config.target_cpu >= TARGET_80486) 755: { c = genclrreg(c,reg); // CLR reg 756: if (flags & 64) 757: code_orrex(c, REX_W); 758: goto done; 759: } 760: 761: if (!I64 && regm && !(flags & 8)) 762: { if (regv + 1 == value || 763: /* Catch case of (0xFFFF+1 == 0) for 16 bit compiles */ 764: (I16 && (targ_short)(regv + 1) == (targ_short)value)) 765: { 766: inc: 767: c = gen1(c,0x40 + reg); /* INC reg */ 768: goto done; 769: } 770: if (regv - 1 == value) 771: { 772: dec: 773: c = gen1(c,0x48 + reg); /* DEC reg */ 774: goto done; 775: } 776: } 777: 778: /* See if another register has the right value */ 779: r = 0; 780: for (mreg = regcon.immed.mval; mreg; mreg >>= 1) 781: { 782: #ifdef DEBUG 783: assert(!I16 || regcon.immed.value[r] == (targ_short)regcon.immed.value[r]); 784: #endif 785: if (mreg & 1 && regcon.immed.value[r] == value) 786: { c = genmovreg(c,reg,r); 787: if (flags & 64) 788: code_orrex(c, REX_W); 789: goto done; 790: } 791: r++; 792: } 793: 794: if (value == 0 && !(flags & 8)) 795: { c = genclrreg(c,reg); // CLR reg 796: if (flags & 64) 797: code_orrex(c, REX_W); 798: } 799: else 800: { /* See if we can just load a byte */ 801: if (regm & BYTEREGS && 802: !(config.flags4 & CFG4speed && config.target_cpu >= TARGET_PentiumPro) 803: ) 804: { 805: if ((regv & ~(targ_size_t)0xFF) == (value & ~(targ_size_t)0xFF)) 806: { c = movregconst(c,reg,value,(flags & 8) |4|1); // load regL 807: return c; 808: } 809: if (regm & (mAX|mBX|mCX|mDX) && 810: (regv & ~(targ_size_t)0xFF00) == (value & ~(targ_size_t)0xFF00) && 811: !I64) 812: { c = movregconst(c,4|reg,value >> 8,(flags & 8) |4|1|16); // load regH 813: return c; 814: } 815: } 816: if (flags & 64) 817: c = genc2(c,0xC7,(REX_W << 16) | modregrmx(3,0,reg),value); // MOV reg,value64 818: else 819: c = genc2(c,0xC7,modregrmx(3,0,reg),value); // MOV reg,value 820: } 821: } 822: done: 823: regimmed_set(reg,value); 824: } 825: return c; 826: } 827: 828: /********************************** 829: * Determine if one of the registers in regm has value in it. 830: * If so, return !=0 and set *preg to which register it is. 831: */ 832: 833: bool reghasvalue(regm_t regm,targ_size_t value,unsigned *preg) 834: { 835: //printf("reghasvalue(%s, %llx)\n", regm_str(regm), (unsigned long long)value); 836: /* See if another register has the right value */ 837: unsigned r = 0; 838: for (regm_t mreg = regcon.immed.mval; mreg; mreg >>= 1) 839: { 840: if (mreg & regm & 1 && regcon.immed.value[r] == value) 841: { *preg = r; 842: return TRUE; 843: } 844: r++; 845: regm >>= 1; 846: } 847: return FALSE; 848: } 849: 850: /************************************** 851: * Load a register from the mask regm with value. 852: * Output: 853: * *preg the register selected 854: */ 855: 856: code *regwithvalue(code *c,regm_t regm,targ_size_t value,unsigned *preg,regm_t flags) 857: { unsigned reg; 858: 859: if (!preg) 860: preg = &reg; 861: 862: /* If we don't already have a register with the right value in it */ 863: if (!reghasvalue(regm,value,preg)) 864: { regm_t save; 865: 866: save = regcon.immed.mval; 867: c = cat(c,allocreg(&regm,preg,TYint)); // allocate register 868: regcon.immed.mval = save; 869: c = movregconst(c,*preg,value,flags); // store value into reg 870: } 871: return c; 872: } 873: 874: /************************************************* 875: * Allocate register temporaries 876: */ 877: 878: void REGSAVE::reset() 879: { 880: off = 0; 881: top = 0; 882: idx = 0; 883: alignment = REGSIZE; 884: } 885: 886: code *REGSAVE::save(code *c, int reg, unsigned *pidx) 887: { 888: unsigned i; 889: if (reg >= XMM0) 890: { 891: alignment = 16; 892: idx = (idx + 15) & ~15; 893: i = idx; 894: idx += 16; 895: // MOVD idx[RBP],xmm 896: c = genc1(c,0xF20F11,modregxrm(2, reg - XMM0, BPRM),FLregsave,(targ_uns) i); 897: } 898: else 899: { 900: if (!alignment) 901: alignment = REGSIZE; 902: i = idx; 903: idx += REGSIZE; 904: // MOV idx[RBP],reg 905: c = genc1(c,0x89,modregxrm(2, reg, BPRM),FLregsave,(targ_uns) i); 906: if (I64) 907: code_orrex(c, REX_W); 908: } 909: reflocal = TRUE; 910: if (idx > top) 911: top = idx; // keep high water mark 912: *pidx = i; 913: return c; 914: } 915: 916: code *REGSAVE::restore(code *c, int reg, unsigned idx) 917: { 918: if (reg >= XMM0) 919: { 920: assert(alignment == 16); 921: // MOVD xmm,idx[RBP] 922: c = genc1(c,0xF20F10,modregxrm(2, reg - XMM0, BPRM),FLregsave,(targ_uns) idx); 923: } 924: else 925: { // MOV reg,idx[RBP] 926: c = genc1(c,0x8B,modregxrm(2, reg, BPRM),FLregsave,(targ_uns) idx); 927: if (I64) 928: code_orrex(c, REX_W); 929: } 930: return c; 931: } 932: 933: 934: #endif // !SPP 935: