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,®) &&
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 = ®
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(®m,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: