1: // Copyright (C) 1984-1998 by Symantec
2: // Copyright (C) 2000-2011 by Digital Mars
3: // All Rights Reserved
4: // http://www.digitalmars.com
5: // Written by Walter Bright
6: /*
7: * This source file is made available for personal use
8: * only. The license is in /dmd/src/dmd/backendlicense.txt
9: * or /dm/src/dmd/backendlicense.txt
10: * For any other uses, please contact Digital Mars.
11: */
12:
13: #if !SPP
14:
15: #include <stdio.h>
16: #include <string.h>
17: #include <time.h>
18: #include "cc.h"
19: #include "oper.h"
20: #include "el.h"
21: #include "code.h"
22: #include "global.h"
23: #include "type.h"
24: #if SCPP
25: #include "exh.h"
26: #endif
27:
28: static char __file__[] = __FILE__; /* for tassert.h */
29: #include "tassert.h"
30:
31: int cdcmp_flag;
32: extern signed char regtorm[8];
33:
34: /********************************
35: * Return mask of index registers used by addressing mode.
36: * Index is rm of modregrm field.
37: */
38:
39: regm_t idxregm(code *c)
40: {
41: static const unsigned char idxsib[8] = { mAX,mCX,mDX,mBX,0,mBP,mSI,mDI };
42: static const unsigned char idxrm[8] = {mBX|mSI,mBX|mDI,mSI,mDI,mSI,mDI,0,mBX};
43:
44: unsigned rm = c->Irm;
45: regm_t idxm = 0;
46: if ((rm & 0xC0) != 0xC0) /* if register is not the destination */
47: {
48: if (I16)
49: idxm = idxrm[rm & 7];
50: else
51: {
52: if ((rm & 7) == 4) /* if sib byte */
53: {
54: unsigned sib = c->Isib;
55: unsigned idxreg = (sib >> 3) & 7;
56: if (c->Irex & REX_X)
57: { idxreg |= 8;
58: idxm = mask[idxreg]; // scaled index reg
59: }
60: else
61: idxm = idxsib[idxreg]; // scaled index reg
62: if ((sib & 7) == 5 && (rm & 0xC0) == 0)
63: ;
64: else
65: { unsigned base = sib & 7;
66: if (c->Irex & REX_B)
67: idxm |= mask[base | 8];
68: else
69: idxm |= idxsib[base];
70: }
71: }
72: else
73: { unsigned base = rm & 7;
74: if (c->Irex & REX_B)
75: idxm |= mask[base | 8];
76: else
77: idxm |= idxsib[base];
78: }
79: }
80: }
81: return idxm;
82: }
83:
84:
85: #if TARGET_WINDOS
86: /***************************
87: * Gen code for call to floating point routine.
88: */
89:
90: code *opdouble(elem *e,regm_t *pretregs,unsigned clib)
91: {
92: regm_t retregs1,retregs2;
93: code *cl, *cr, *c;
94:
95: if (config.inline8087)
96: return orth87(e,pretregs);
97:
98: if (tybasic(e->E1->Ety) == TYfloat)
99: {
100: clib += CLIBfadd - CLIBdadd; /* convert to float operation */
101: retregs1 = FLOATREGS;
102: retregs2 = FLOATREGS2;
103: }
104: else
105: {
106: if (I32)
107: { retregs1 = DOUBLEREGS_32;
108: retregs2 = DOUBLEREGS2_32;
109: }
110: else
111: { retregs1 = mSTACK;
112: retregs2 = DOUBLEREGS_16;
113: }
114: }
115: cl = codelem(e->E1, &retregs1,FALSE);
116: if (retregs1 & mSTACK)
117: cgstate.stackclean++;
118: cr = scodelem(e->E2, &retregs2, retregs1 & ~mSTACK, FALSE);
119: if (retregs1 & mSTACK)
120: cgstate.stackclean--;
121: c = callclib(e, clib, pretregs, 0);
122: return cat3(cl, cr, c);
123: }
124: #endif
125:
126:
127: /*****************************
128: * Handle operators which are more or less orthogonal
129: * ( + - & | ^ )
130: */
131:
132: code *cdorth(elem *e,regm_t *pretregs)
133: { tym_t ty1;
134: regm_t retregs,rretregs,posregs;
135: unsigned reg,rreg,op1,op2,mode;
136: int rval;
137: code *c,*cg,*cl;
138: targ_size_t i;
139: elem *e1,*e2;
140: int numwords; /* # of words to be operated on */
141: static int nest;
142:
143: //printf("cdorth(e = %p, *pretregs = %s)\n",e,regm_str(*pretregs));
144: e1 = e->E1;
145: e2 = e->E2;
146: if (*pretregs == 0) /* if don't want result */
147: { c = codelem(e1,pretregs,FALSE); /* eval left leaf */
148: *pretregs = 0; /* in case they got set */
149: return cat(c,codelem(e2,pretregs,FALSE));
150: }
151:
152: ty1 = tybasic(e1->Ety);
153: if (tyfloating(ty1))
154: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
155: return orth87(e,pretregs);
156: #else
157: return opdouble(e,pretregs,(e->Eoper == OPadd) ? CLIBdadd
158: : CLIBdsub);
159: #endif
160: tym_t ty2 = tybasic(e2->Ety);
161: int e2oper = e2->Eoper;
162: tym_t ty = tybasic(e->Ety);
163: unsigned sz = tysize[ty];
164: unsigned byte = (sz == 1);
165: unsigned char word = (!I16 && sz == SHORTSIZE) ? CFopsize : 0;
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
166: unsigned test = FALSE; // assume we destroyed lvalue
167: code cs;
168: cs.Iflags = 0;
169: cs.Irex = 0;
170: code *cr = CNIL;
171:
172: switch (e->Eoper)
173: { case OPadd: mode = 0;
174: op1 = 0x03; op2 = 0x13; break; /* ADD, ADC */
175: case OPmin: mode = 5;
176: op1 = 0x2B; op2 = 0x1B; break; /* SUB, SBB */
177: case OPor: mode = 1;
178: op1 = 0x0B; op2 = 0x0B; break; /* OR , OR */
179: case OPxor: mode = 6;
180: op1 = 0x33; op2 = 0x33; break; /* XOR, XOR */
181: case OPand: mode = 4;
182: op1 = 0x23; op2 = 0x23; /* AND, AND */
183: if (tyreg(ty1) &&
184: *pretregs == mPSW) /* if flags only */
185: { test = TRUE;
186: op1 = 0x85; /* TEST */
187: mode = 0;
188: }
189: break;
190: default:
191: assert(0);
192: }
193: op1 ^= byte; /* if byte operation */
194:
195: /* Compute number of words to operate on. */
196: numwords = 1;
197: if (!I16)
198: { /* Cannot operate on longs and then do a 'paint' to a far */
199: /* pointer, because far pointers are 48 bits and longs are 32. */
200: /* Therefore, numwords can never be 2. */
201: assert(!(tyfv(ty1) && tyfv(ty2)));
202: if (sz == 2 * REGSIZE)
203: {
204: numwords++;
205: }
206: }
207: else
208: { /* If ty is a TYfptr, but both operands are long, treat the */
209: /* operation as a long. */
210: if ((tylong(ty1) || ty1 == TYhptr) &&
211: (tylong(ty2) || ty2 == TYhptr))
212: numwords++;
213: }
214:
215: // Special cases where only flags are set
216: if (test && tysize[ty1] <= REGSIZE &&
217: (e1->Eoper == OPvar || (e1->Eoper == OPind && !e1->Ecount)))
218: {
219: // Handle the case of (var & const)
220: if (e2->Eoper == OPconst && el_signx32(e2))
221: {
222: c = getlvalue(&cs,e1,0);
223: targ_size_t value = e2->EV.Vpointer;
224: if (sz == 2)
225: value &= 0xFFFF;
226: else if (sz == 4)
227: value &= 0xFFFFFFFF;
228: if (reghasvalue(byte ? BYTEREGS : ALLREGS,value,®))
229: goto L11;
230: if (sz == 8 && !I64)
231: {
232: assert(value == (int)value); // sign extend imm32
233: }
234: op1 = 0xF7;
235: cs.IEV2.Vint = value;
236: cs.IFL2 = FLconst;
237: goto L10;
238: }
239:
240: // Handle (exp & reg)
241: if (isregvar(e2,&retregs,®))
242: {
243: c = getlvalue(&cs,e1,0);
244: L11:
245: code_newreg(&cs, reg);
246: if (I64 && byte && reg >= 4)
247: cs.Irex |= REX;
248: L10:
249: cs.Iop = op1 ^ byte;
250: cs.Iflags |= word | CFpsw;
251: freenode(e1);
252: freenode(e2);
253: return gen(c,&cs);
254: }
255: }
256:
257: // Look for possible uses of LEA
258: if (e->Eoper == OPadd &&
259: !(*pretregs & mPSW) && /* flags aren't set by LEA */
260: !nest && // could cause infinite recursion if e->Ecount
261: (sz == REGSIZE || (I64 && sz == 4))) // far pointers aren't handled
262: {
263: unsigned rex = (sz == 8) ? REX_W : 0;
264:
265: // Handle the case of (e + &var)
266: int e1oper = e1->Eoper;
267: if ((e2oper == OPrelconst && (config.target_cpu >= TARGET_Pentium || (!e2->Ecount && stackfl[el_fl(e2)])))
268: || // LEA costs too much for simple EAs on older CPUs
269: (e2oper == OPconst && (e1->Eoper == OPcall || e1->Eoper == OPcallns) && !(*pretregs & mAX)) ||
270: (!I16 && (isscaledindex(e1) || isscaledindex(e2))) ||
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
271: (!I16 && e1oper == OPvar && e1->EV.sp.Vsym->Sfl == FLreg && (e2oper == OPconst || (e2oper == OPvar && e2->EV.sp.Vsym->Sfl == FLreg))) ||
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
272: (e2oper == OPconst && e1oper == OPeq && e1->E1->Eoper == OPvar) ||
273: (!I16 && (e2oper == OPrelconst || e2oper == OPconst) && !e1->Ecount &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
274: (e1oper == OPmul || e1oper == OPshl) &&
275: e1->E2->Eoper == OPconst &&
276: ssindex(e1oper,e1->E2->EV.Vuns)
277: ) ||
278: (!I16 && e1->Ecount)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
279: )
280: {
281: int inc = e->Ecount != 0;
282: nest += inc;
283: c = getlvalue(&cs,e,0);
284: nest -= inc;
285: unsigned reg;
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '135' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 135
286: c = cat(c,allocreg(pretregs,®,ty));
287: cs.Iop = 0x8D;
288: code_newreg(&cs, reg);
289: c = gen(c,&cs); // LEA reg,EA
290: if (rex)
291: code_orrex(c, rex);
292: return c;
293: }
294:
295: // Handle the case of ((e + c) + e2)
296: if (!I16 &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
297: e1oper == OPadd &&
298: (e1->E2->Eoper == OPconst && el_signx32(e1->E2) ||
299: e2oper == OPconst && el_signx32(e2)) &&
300: !e1->Ecount
301: )
302: { elem *e11;
303: elem *ebase;
304: elem *edisp;
305: int ss;
306: int ss2;
307: unsigned reg1,reg2;
308: code *c1,*c2,*c3;
309:
310: if (e2oper == OPconst && el_signx32(e2))
311: { edisp = e2;
312: ebase = e1->E2;
313: }
314: else
315: { edisp = e1->E2;
316: ebase = e2;
317: }
318:
319: e11 = e1->E1;
320: retregs = *pretregs & ALLREGS;
321: if (!retregs)
322: retregs = ALLREGS;
323: ss = 0;
324: ss2 = 0;
325:
326: // Handle the case of (((e * c1) + c2) + e2)
327: // Handle the case of (((e << c1) + c2) + e2)
328: if ((e11->Eoper == OPmul || e11->Eoper == OPshl) &&
329: e11->E2->Eoper == OPconst &&
330: !e11->Ecount
331: )
332: {
333: targ_size_t co1 = el_tolong(e11->E2);
warning C4244: 'initializing' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
334: if (e11->Eoper == OPshl)
335: {
336: if (co1 > 3)
337: goto L13;
338: ss = co1;
339: }
340: else
341: {
342: ss2 = 1;
343: switch (co1)
344: {
345: case 6: ss = 1; break;
346: case 12: ss = 1; ss2 = 2; break;
347: case 24: ss = 1; ss2 = 3; break;
348: case 10: ss = 2; break;
349: case 20: ss = 2; ss2 = 2; break;
350: case 40: ss = 2; ss2 = 3; break;
351: case 18: ss = 3; break;
352: case 36: ss = 3; ss2 = 2; break;
353: case 72: ss = 3; ss2 = 3; break;
354: default:
355: ss2 = 0;
356: goto L13;
357: }
358: }
359: freenode(e11->E2);
360: freenode(e11);
361: e11 = e11->E1;
362: goto L13;
363: }
364: else
365: {
366: L13:
367: regm_t regm;
368: if (e11->Eoper == OPvar && isregvar(e11,®m,®1))
369: {
370: if (tysize[tybasic(e11->Ety)]<= REGSIZE)
371: retregs = mask[reg1]; // only want the LSW
372: else
373: retregs = regm;
374: c1 = NULL;
375: freenode(e11);
376: }
377: else
378: c1 = codelem(e11,&retregs,FALSE);
379: }
380: rretregs = ALLREGS & ~retregs;
381: c2 = scodelem(ebase,&rretregs,retregs,TRUE);
382: {
383: regm_t sregs = *pretregs & ~rretregs;
384: if (!sregs)
385: sregs = ALLREGS & ~rretregs;
386: c3 = allocreg(&sregs,®,ty);
387: }
388:
389: assert((retregs & (retregs - 1)) == 0); // must be only one register
390: assert((rretregs & (rretregs - 1)) == 0); // must be only one register
391:
392: reg1 = findreg(retregs);
393: reg2 = findreg(rretregs);
394:
395: if (ss2)
396: {
397: assert(reg != reg2);
398: if ((reg1 & 7) == BP)
399: { static unsigned imm32[4] = {1+1,2+1,4+1,8+1};
400:
401: // IMUL reg,imm32
402: c = genc2(CNIL,0x69,modregxrmx(3,reg,reg1),imm32[ss]);
403: }
404: else
405: { // LEA reg,[reg1*ss][reg1]
406: c = gen2sib(CNIL,0x8D,modregxrm(0,reg,4),modregrm(ss,reg1 & 7,reg1 & 7));
407: if (reg1 & 8)
408: code_orrex(c, REX_X | REX_B);
409: }
410: if (rex)
411: code_orrex(c, rex);
412: reg1 = reg;
413: ss = ss2; // use *2 for scale
414: }
415: else
416: c = NULL;
417: c = cat4(c1,c2,c3,c);
418:
419: cs.Iop = 0x8D; // LEA reg,c[reg1*ss][reg2]
420: cs.Irm = modregrm(2,reg & 7,4);
421: cs.Isib = modregrm(ss,reg1 & 7,reg2 & 7);
422: assert(reg2 != BP);
423: cs.Iflags = CFoff;
424: cs.Irex = rex;
425: if (reg & 8)
426: cs.Irex |= REX_R;
427: if (reg1 & 8)
428: cs.Irex |= REX_X;
429: if (reg2 & 8)
430: cs.Irex |= REX_B;
431: cs.IFL1 = FLconst;
432: cs.IEV1.Vsize_t = edisp->EV.Vuns;
433:
434: freenode(edisp);
435: freenode(e1);
436: c = gen(c,&cs);
437: return cat(c,fixresult(e,mask[reg],pretregs));
438: }
439: }
440:
441: posregs = (byte) ? BYTEREGS : (mES | ALLREGS | mBP);
442: retregs = *pretregs & posregs;
443: if (retregs == 0) /* if no return regs speced */
444: /* (like if wanted flags only) */
445: retregs = ALLREGS & posregs; // give us some
446:
447: if (tysize[ty1] > REGSIZE && numwords == 1)
448: { /* The only possibilities are (TYfptr + tyword) or (TYfptr - tyword) */
449: #if DEBUG
450: if (tysize[ty2] != REGSIZE)
451: { printf("e = %p, e->Eoper = ",e);
452: WROP(e->Eoper);
453: printf(" e1->Ety = ");
454: WRTYxx(ty1);
455: printf(" e2->Ety = ");
456: WRTYxx(ty2);
457: printf("\n");
458: elem_print(e);
459: }
460: #endif
461: assert(tysize[ty2] == REGSIZE);
462:
463: /* Watch out for the case here where you are going to OP reg,EA */
464: /* and both the reg and EA use ES! Prevent this by forcing */
465: /* reg into the regular registers. */
466: if ((e2oper == OPind ||
467: (e2oper == OPvar && el_fl(e2) == FLfardata)) &&
468: !e2->Ecount)
469: {
470: retregs = ALLREGS;
471: assert(!TARGET_FLAT);
472: }
473:
474: cl = codelem(e1,&retregs,test);
warning C4800: 'unsigned int' : forcing value to bool 'true' or 'false' (performance warning)
475: reg = findreglsw(retregs); /* reg is the register with the offset*/
476: }
477: else if (ty1 == TYhptr || ty2 == TYhptr)
478: { /* Generate code for add/subtract of huge pointers.
479: No attempt is made to generate very good code.
480: */
481: unsigned mreg,lreg;
482: unsigned lrreg;
483:
484: retregs = (retregs & mLSW) | mDX;
485: if (ty1 == TYhptr)
486: { // hptr +- long
487: rretregs = mLSW & ~(retregs | regcon.mvar);
488: if (!rretregs)
489: rretregs = mLSW;
490: rretregs |= mCX;
491: cl = codelem(e1,&rretregs,0);
492: retregs &= ~rretregs;
493: if (!(retregs & mLSW))
494: retregs |= mLSW & ~rretregs;
495:
496: cr = scodelem(e2,&retregs,rretregs,TRUE);
497: }
498: else
499: { // long + hptr
500: cl = codelem(e1,&retregs,0);
501: rretregs = (mLSW | mCX) & ~retregs;
502: if (!(rretregs & mLSW))
503: rretregs |= mLSW;
504: cr = scodelem(e2,&rretregs,retregs,TRUE);
505: }
506: cg = getregs(rretregs | retregs);
507: mreg = DX;
508: lreg = findreglsw(retregs);
509: c = CNIL;
510: if (e->Eoper == OPmin)
511: { // negate retregs
512: c = gen2(c,0xF7,modregrm(3,3,mreg)); // NEG mreg
513: gen2(c,0xF7,modregrm(3,3,lreg)); // NEG lreg
514: code_orflag(c,CFpsw);
515: genc2(c,0x81,modregrm(3,3,mreg),0); // SBB mreg,0
516: }
517: lrreg = findreglsw(rretregs);
518: c = genregs(c,0x03,lreg,lrreg); // ADD lreg,lrreg
519: code_orflag(c,CFpsw);
520: genmovreg(c,lrreg,CX); // MOV lrreg,CX
521: genc2(c,0x81,modregrm(3,2,mreg),0); // ADC mreg,0
522: genshift(c); // MOV CX,offset __AHSHIFT
523: gen2(c,0xD3,modregrm(3,4,mreg)); // SHL mreg,CL
524: genregs(c,0x03,mreg,lrreg); // ADD mreg,MSREG(h)
525: goto L5;
526: }
527: else
528: { regm_t regm;
529:
530: /* if (tyword + TYfptr) */
531: if (tysize[ty1] == REGSIZE && tysize[ty2] > REGSIZE)
532: { retregs = ~*pretregs & ALLREGS;
533:
534: /* if retregs doesn't have any regs in it that aren't reg vars */
535: if ((retregs & ~regcon.mvar) == 0)
536: retregs |= mAX;
537: }
538: else if (numwords == 2 && retregs & mES)
539: retregs = (retregs | mMSW) & ALLREGS;
540:
541: // Determine if we should swap operands, because
542: // mov EAX,x
543: // add EAX,reg
544: // is faster than:
545: // mov EAX,reg
546: // add EAX,x
547: else if (e2oper == OPvar &&
548: e1->Eoper == OPvar &&
549: e->Eoper != OPmin &&
550: isregvar(e1,®m,NULL) &&
551: regm != retregs &&
552: tysize[ty1] == tysize[ty2])
553: {
554: elem *es = e1;
555: e1 = e2;
556: e2 = es;
557: }
558: cl = codelem(e1,&retregs,test); /* eval left leaf */
warning C4800: 'unsigned int' : forcing value to bool 'true' or 'false' (performance warning)
559: reg = findreg(retregs);
560: }
561: switch (e2oper)
562: {
563: case OPind: /* if addressing mode */
564: if (!e2->Ecount) /* if not CSE */
565: goto L1; /* try OP reg,EA */
566: /* FALL-THROUGH */
567: default: /* operator node */
568: L2:
569: rretregs = ALLREGS & ~retregs;
570: /* Be careful not to do arithmetic on ES */
571: if (tysize[ty1] == REGSIZE && tysize[ty2] > REGSIZE && *pretregs != mPSW)
572: rretregs = *pretregs & (mES | ALLREGS | mBP) & ~retregs;
573: else if (byte)
574: rretregs &= BYTEREGS;
575:
576: cr = scodelem(e2,&rretregs,retregs,TRUE); /* get rvalue */
577: rreg = (tysize[ty2] > REGSIZE) ? findreglsw(rretregs) : findreg(rretregs);
578: c = CNIL;
579: if (numwords == 1) /* ADD reg,rreg */
580: {
581: /* reverse operands to avoid moving around the segment value */
582: if (tysize[ty2] > REGSIZE)
583: { c = cat(c,getregs(rretregs));
584: c = genregs(c,op1,rreg,reg);
585: retregs = rretregs; /* reverse operands */
586: }
587: else
588: { c = genregs(c,op1,reg,rreg);
589: if (!I16 && *pretregs & mPSW)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
590: c->Iflags |= word;
591: }
592: if (I64 && sz == 8)
593: code_orrex(c, REX_W);
594: if (I64 && byte && (reg >= 4 || rreg >= 4))
595: code_orrex(c, REX);
596: }
597: else /* numwords == 2 */ /* ADD lsreg,lsrreg */
598: {
599: reg = findreglsw(retregs);
600: rreg = findreglsw(rretregs);
601: c = genregs(c,op1,reg,rreg);
602: if (e->Eoper == OPadd || e->Eoper == OPmin)
603: code_orflag(c,CFpsw);
604: reg = findregmsw(retregs);
605: rreg = findregmsw(rretregs);
606: if (!(e2oper == OPu16_32 && // if second operand is 0
607: (op2 == 0x0B || op2 == 0x33)) // and OR or XOR
608: )
609: genregs(c,op2,reg,rreg); // ADC msreg,msrreg
610: }
611: break;
612:
613: case OPrelconst:
614: if (sz != REGSIZE)
615: goto L2;
616: if (segfl[el_fl(e2)] != 3) /* if not in data segment */
617: goto L2;
618: if (evalinregister(e2))
619: goto L2;
620: cs.IEVoffset2 = e2->EV.sp.Voffset;
621: cs.IEVsym2 = e2->EV.sp.Vsym;
622: cs.Iflags |= CFoff;
623: i = 0; /* no INC or DEC opcode */
624: rval = 0;
625: goto L3;
626:
627: case OPconst:
628: if (tyfv(ty2))
629: goto L2;
630: if (numwords == 1)
631: {
632: if (!el_signx32(e2))
633: goto L2;
634: i = e2->EV.Vpointer;
635: if (word)
636: {
637: if (!(*pretregs & mPSW) &&
638: config.flags4 & CFG4speed &&
639: (e->Eoper == OPor || e->Eoper == OPxor || test ||
640: (e1->Eoper != OPvar && e1->Eoper != OPind)))
641: { word = 0;
642: i &= 0xFFFF;
643: }
644: }
645: rval = reghasvalue(byte ? BYTEREGS : ALLREGS,i,&rreg);
646: cs.IEV2.Vint = i;
647: L3:
648: op1 ^= byte;
649: cs.Iflags |= word;
650: if (rval)
651: { cs.Iop = op1 ^ 2;
652: mode = rreg;
653: }
654: else
655: cs.Iop = 0x81;
656: cs.Irm = modregrm(3,mode&7,reg&7);
657: if (mode & 8)
658: cs.Irex |= REX_R;
659: if (reg & 8)
660: cs.Irex |= REX_B;
661: if (I64 && sz == 8)
662: cs.Irex |= REX_W;
663: if (I64 && byte && (reg >= 4 || (rval && rreg >= 4)))
664: cs.Irex |= REX;
665: cs.IFL2 = (e2->Eoper == OPconst) ? FLconst : el_fl(e2);
666: /* Modify instruction for special cases */
667: switch (e->Eoper)
668: { case OPadd:
669: { int iop;
670:
671: if (i == 1)
672: iop = 0; /* INC reg */
673: else if (i == -1)
674: iop = 8; /* DEC reg */
675: else
676: break;
677: cs.Iop = (0x40 | iop | reg) ^ byte;
678: if ((byte && *pretregs & mPSW) || I64)
679: { cs.Irm = modregrm(3,0,reg & 7) | iop;
680: cs.Iop = 0xFF;
681: }
682: break;
683: }
684: case OPand:
685: if (test)
686: cs.Iop = rval ? op1 : 0xF7; // TEST
687: break;
688: }
689: if (*pretregs & mPSW)
690: cs.Iflags |= CFpsw;
691: cs.Iop ^= byte;
692: c = gen(CNIL,&cs);
693: cs.Iflags &= ~CFpsw;
694: }
695: else if (numwords == 2)
696: { unsigned lsreg;
697: targ_int msw;
698:
699: c = getregs(retregs);
700: reg = findregmsw(retregs);
701: lsreg = findreglsw(retregs);
702: cs.Iop = 0x81;
703: cs.Irm = modregrm(3,mode,lsreg);
704: cs.IFL2 = FLconst;
705: msw = MSREG(e2->EV.Vllong);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_int', possible loss of data
706: cs.IEV2.Vint = e2->EV.Vlong;
707: switch (e->Eoper)
708: { case OPadd:
709: case OPmin:
710: cs.Iflags |= CFpsw;
711: break;
712: }
713: c = gen(c,&cs);
714: cs.Iflags &= ~CFpsw;
715:
716: cs.Irm = (cs.Irm & modregrm(3,7,0)) | reg;
717: cs.IEV2.Vint = msw;
718: if (e->Eoper == OPadd)
719: cs.Irm |= modregrm(0,2,0); /* ADC */
720: c = gen(c,&cs);
721: }
722: else
723: assert(0);
724: freenode(e2);
725: break;
726:
727: case OPvar:
728: L1:
729: if (tyfv(ty2))
730: goto L2;
731: c = loadea(e2,&cs,op1,
732: ((numwords == 2) ? findreglsw(retregs) : reg),
733: 0,retregs,retregs);
734: if (!I16 && word)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
735: { if (*pretregs & mPSW)
736: code_orflag(c,word);
737: else
738: {
739: code *ce = code_last(c);
740: ce->Iflags &= ~word;
741: }
742: }
743: else if (numwords == 2)
744: {
745: if (e->Eoper == OPadd || e->Eoper == OPmin)
746: code_orflag(c,CFpsw);
747: reg = findregmsw(retregs);
748: if (EOP(e2))
749: { getlvalue_msw(&cs);
750: cs.Iop = op2;
751: NEWREG(cs.Irm,reg);
752: c = gen(c,&cs); /* ADC reg,data+2 */
753: }
754: else
755: c = cat(c,loadea(e2,&cs,op2,reg,REGSIZE,retregs,0));
756: }
757: else if (I64 && sz == 8)
758: code_orrex(c, REX_W);
759: freenode(e2);
760: break;
761: }
762: if (sz <= REGSIZE && *pretregs & mPSW)
warning C4018: '<=' : signed/unsigned mismatch
763: {
764: /* If the expression is (_tls_array + ...), then the flags are not set
765: * since the linker may rewrite these instructions into something else.
766: */
767: if (I64 && e->Eoper == OPadd && e1->Eoper == OPvar)
768: {
769: symbol *s = e1->EV.sp.Vsym;
770: if (s->Sident[0] == '_' && memcmp(s->Sident + 1,"tls_array",10) == 0)
771: {
772: goto L7; // don't assume flags are set
773: }
774: }
775: code_orflag(c,CFpsw);
776: *pretregs &= ~mPSW; /* flags already set */
777: L7: ;
778: }
779: if (test)
780: cg = NULL; /* didn't destroy any */
781: else
782: cg = getregs(retregs); /* we will trash these regs */
783: L5:
784: c = cat(c,fixresult(e,retregs,pretregs));
785: return cat4(cl,cr,cg,c);
786: }
787:
788:
789: /*****************************
790: * Handle multiply, divide, modulo and remquo.
791: * Note that modulo isn't defined for doubles.
792: */
793:
794: code *cdmul(elem *e,regm_t *pretregs)
795: { unsigned rreg,op,oper,lib,byte;
796: regm_t resreg,retregs,rretregs;
797: regm_t keepregs;
798: tym_t uns; // 1 if unsigned operation, 0 if not
799: tym_t tyml;
800: code *c,*cg,*cl,*cr,cs;
801: elem *e1,*e2;
802: int sz;
803: targ_size_t e2factor;
804: int opunslng;
805: int pow2;
806:
807: if (*pretregs == 0) // if don't want result
808: { c = codelem(e->E1,pretregs,FALSE); // eval left leaf
809: *pretregs = 0; // in case they got set
810: return cat(c,codelem(e->E2,pretregs,FALSE));
811: }
812:
813: //printf("cdmul(e = %p, *pretregs = %s)\n", e, regm_str(*pretregs));
814: keepregs = 0;
815: cs.Iflags = 0;
816: cs.Irex = 0;
817: c = cg = cr = CNIL; // initialize
818: e2 = e->E2;
819: e1 = e->E1;
820: tyml = tybasic(e1->Ety);
821: sz = tysize[tyml];
822: byte = tybyte(e->Ety) != 0;
823: uns = tyuns(tyml) || tyuns(e2->Ety);
824: oper = e->Eoper;
825: unsigned rex = (I64 && sz == 8) ? REX_W : 0;
826: unsigned grex = rex << 16;
827:
828: if (tyfloating(tyml))
829: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
830: return orth87(e,pretregs);
831: #else
832: return opdouble(e,pretregs,(oper == OPmul) ? CLIBdmul : CLIBddiv);
833: #endif
834:
835: opunslng = I16 ? OPu16_32 : OPu32_64;
836: switch (oper)
837: {
838: case OPmul:
839: resreg = mAX;
840: op = 5 - uns;
841: lib = CLIBlmul;
842: break;
843:
844: case OPdiv:
845: resreg = mAX;
846: op = 7 - uns;
847: lib = uns ? CLIBuldiv : CLIBldiv;
848: if (I32)
849: keepregs |= mSI | mDI;
850: break;
851:
852: case OPmod:
853: resreg = mDX;
854: op = 7 - uns;
855: lib = uns ? CLIBulmod : CLIBlmod;
856: if (I32)
857: keepregs |= mSI | mDI;
858: break;
859:
860: case OPremquo:
861: resreg = mDX | mAX;
862: op = 7 - uns;
863: lib = uns ? CLIBuldiv : CLIBldiv;
864: if (I32)
865: keepregs |= mSI | mDI;
866: break;
867:
868: default:
869: assert(0);
870: }
871:
872: if (sz <= REGSIZE) // dedicated regs for mul & div
873: { retregs = mAX;
874: /* pick some other regs */
875: rretregs = byte ? BYTEREGS & ~mAX
876: : ALLREGS & ~(mAX|mDX);
877: }
878: else
879: {
880: assert(sz <= 2 * REGSIZE);
881: retregs = mDX | mAX;
882: rretregs = mCX | mBX; // second arg
883: }
884:
885: switch (e2->Eoper)
886: {
887: case OPu16_32:
888: case OPshtlng:
889: case OPu32_64:
890: case OPlngllng:
891: if (sz != 2 * REGSIZE || oper != OPmul || e1->Eoper != e2->Eoper ||
892: e1->Ecount || e2->Ecount)
893: goto L2;
894: op = (e2->Eoper == opunslng) ? 4 : 5;
895: retregs = mAX;
896: cl = codelem(e1->E1,&retregs,FALSE); /* eval left leaf */
897: if (e2->E1->Eoper == OPvar ||
898: (e2->E1->Eoper == OPind && !e2->E1->Ecount)
899: )
900: {
901: cr = loadea(e2->E1,&cs,0xF7,op,0,mAX,mAX | mDX);
902: }
903: else
904: {
905: rretregs = ALLREGS & ~mAX;
906: cr = scodelem(e2->E1,&rretregs,retregs,TRUE); // get rvalue
907: cg = getregs(mAX | mDX);
908: rreg = findreg(rretregs);
909: cg = gen2(cg,0xF7,grex | modregrmx(3,op,rreg)); // OP AX,rreg
910: }
911: freenode(e->E1);
912: freenode(e2);
913: c = fixresult(e,mAX | mDX,pretregs);
914: break;
915:
916: case OPconst:
917: e2factor = el_tolong(e2);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
918:
919: if (oper == OPmul && I32 && sz == REGSIZE * 2)
920: { targ_int msw,lsw;
921: regm_t scratch;
922: unsigned reg;
923: targ_llong e2factor;
warning C6246: Local declaration of 'e2factor' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '803' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 803
924:
925: cl = codelem(e1,&retregs,FALSE); // eval left leaf
926: /* IMUL EDX,EDX,lsw
927: IMUL reg,EAX,msw
928: ADD reg,EDX
929: MOV EDX,lsw
930: MUL EDX
931: ADD EDX,reg
932:
933: if (msw == 0)
934: IMUL reg,EDX,lsw
935: MOV EDX,lsw
936: MUL EDX
937: ADD EDX,reg
938: */
939: scratch = allregs & ~(mAX | mDX);
940: cr = allocreg(&scratch,®,TYint);
941: cg = getregs(mDX | mAX);
942:
943: e2factor = el_tolong(e2);
944: lsw = e2factor & ((1LL << (REGSIZE * 8)) - 1);
945: msw = e2factor >> (REGSIZE * 8);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_int', possible loss of data
946:
947: if (msw)
948: { cg = genmulimm(cg,DX,DX,lsw);
949: cg = genmulimm(cg,reg,AX,msw);
950: cg = gen2(cg,0x03,modregrm(3,reg,DX));
951: }
952: else
953: cg = genmulimm(cg,reg,DX,lsw);
954:
955: cg = movregconst(cg,DX,lsw,0); // MOV EDX,lsw
956: cg = cat(cg,getregs(mDX));
957: cg = gen2(cg,0xF7,modregrm(3,4,DX)); // MUL EDX
958: gen2(cg,0x03,modregrm(3,DX,reg)); // ADD EDX,reg
959:
960: resreg = mDX | mAX;
961: freenode(e2);
962: goto L3;
963: }
964:
965: if (oper != OPmul && e2factor == 10 &&
966: (!I16 && sz == 4) &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
967: config.flags4 & CFG4speed && !uns)
968: {
969: /* R1 / 10
970: *
971: * MOV EAX,0x66666667
972: * IMUL R1
973: * MOV EAX,R1
974: * SAR EAX,31
975: * SAR EDX,2
976: * SUB EDX,EAX
977: * IMUL EAX,EDX,10
978: * SUB R1,EAX
979: *
980: * EDX = quotient
981: * R1 = remainder
982: */
983: regm_t regm;
984: unsigned reg;
985:
986: regm = allregs & ~(mAX | mDX);
987: cl = codelem(e1,®m,FALSE); // eval left leaf
988: reg = findreg(regm);
989: cg = getregs(regm | mDX | mAX);
990:
991: cg = movregconst(cg, AX, 0x66666667, 0); // MOV EAX,0x66666667
992: cg = gen2(cg,0xF7,modregrmx(3,5,reg)); // IMUL R1
993: genmovreg(cg, AX, reg); // MOV EAX,R1
994: genc2(cg,0xC1,modregrm(3,7,AX),31); // SAR EAX,31
995: genc2(cg,0xC1,modregrm(3,7,DX),2); // SAR EDX,2
996: gen2(cg,0x2B,modregrm(3,DX,AX)); // SUB EDX,EAX
997:
998: switch (oper)
999: { case OPdiv:
1000: resreg = mDX;
1001: break;
1002:
1003: case OPmod:
1004: genmulimm(cg,AX,DX,10); // IMUL EAX,EDX,10
1005: gen2(cg,0x2B,modregxrm(3,reg,AX)); // SUB R1,EAX
1006: resreg = regm;
1007: break;
1008:
1009: case OPremquo:
1010: genmulimm(cg,AX,DX,10); // IMUL EAX,EDX,10
1011: gen2(cg,0x2B,modregxrm(3,reg,AX)); // SUB R1,EAX
1012: genmovreg(cg, AX, DX); // MOV EAX,EDX
1013: genmovreg(cg, DX, reg); // MOV EDX,R1
1014: resreg = mDX | mAX;
1015: break;
1016:
1017: default:
1018: assert(0);
1019: }
1020: freenode(e2);
1021: goto L3;
1022: }
1023:
1024: if (sz > REGSIZE || !el_signx32(e2))
1025: goto L2;
1026:
1027: if (oper == OPmul && config.target_cpu >= TARGET_80286)
1028: { unsigned reg;
1029: int ss;
1030:
1031: freenode(e2);
1032: retregs = byte ? BYTEREGS : ALLREGS;
1033: resreg = *pretregs & (ALLREGS | mBP);
1034: if (!resreg)
1035: resreg = retregs;
1036:
1037: if (!I16)
1038: { // See if we can use an LEA instruction
1039: int ss2 = 0;
1040: int shift;
1041:
1042: switch (e2factor)
1043: {
1044: case 12: ss = 1; ss2 = 2; goto L4;
1045: case 24: ss = 1; ss2 = 3; goto L4;
1046:
1047: case 6:
1048: case 3: ss = 1; goto L4;
1049:
1050: case 20: ss = 2; ss2 = 2; goto L4;
1051: case 40: ss = 2; ss2 = 3; goto L4;
1052:
1053: case 10:
1054: case 5: ss = 2; goto L4;
1055:
1056: case 36: ss = 3; ss2 = 2; goto L4;
1057: case 72: ss = 3; ss2 = 3; goto L4;
1058:
1059: case 18:
1060: case 9: ss = 3; goto L4;
1061:
1062: L4:
1063: {
1064: #if 1
1065: regm_t regm = byte ? BYTEREGS : ALLREGS;
1066: regm &= ~(mBP | mR13); // don't use EBP
1067: cl = codelem(e->E1,®m,TRUE);
1068: unsigned r = findreg(regm);
1069:
1070: if (ss2)
1071: { // Don't use EBP
1072: resreg &= ~(mBP | mR13);
1073: if (!resreg)
1074: resreg = retregs;
1075: }
1076: cg = allocreg(&resreg,®,tyml);
1077:
1078: c = gen2sib(CNIL,0x8D,grex | modregxrm(0,reg,4),
1079: modregxrmx(ss,r,r));
1080: assert((r & 7) != BP);
1081: if (ss2)
1082: {
1083: gen2sib(c,0x8D,grex | modregxrm(0,reg,4),
1084: modregxrm(ss2,reg,5));
1085: code_last(c)->IFL1 = FLconst;
1086: code_last(c)->IEV1.Vint = 0;
1087: }
1088: else if (!(e2factor & 1)) // if even factor
1089: { genregs(c,0x03,reg,reg); // ADD reg,reg
1090: code_orrex(c,rex);
1091: }
1092: cg = cat(cg,c);
1093: goto L3;
1094: #else
1095:
1096: // Don't use EBP
1097: resreg &= ~mBP;
1098: if (!resreg)
1099: resreg = retregs;
1100:
1101: cl = codelem(e->E1,&resreg,FALSE);
1102: reg = findreg(resreg);
1103: cg = getregs(resreg);
1104: c = gen2sib(CNIL,0x8D,modregrm(0,reg,4),
1105: modregrm(ss,reg,reg));
1106: if (ss2)
1107: {
1108: gen2sib(c,0x8D,modregrm(0,reg,4),
1109: modregrm(ss2,reg,5));
1110: code_last(c)->IFL1 = FLconst;
1111: code_last(c)->IEV1.Vint = 0;
1112: }
1113: else if (!(e2factor & 1)) // if even factor
1114: genregs(c,0x03,reg,reg); // ADD reg,reg
1115: cg = cat(cg,c);
1116: goto L3;
1117: #endif
1118: }
1119: case 37:
1120: case 74: shift = 2;
1121: goto L5;
1122: case 13:
1123: case 26: shift = 0;
1124: goto L5;
1125: L5:
1126: {
1127: // Don't use EBP
1128: resreg &= ~(mBP | mR13);
1129: if (!resreg)
1130: resreg = retregs;
1131: cl = allocreg(&resreg,®,TYint);
1132:
1133: regm_t sregm = (ALLREGS & ~mR13) & ~resreg;
1134: cl = cat(cl,codelem(e->E1,&sregm,FALSE));
1135: unsigned sreg = findreg(sregm);
1136: cg = getregs(resreg | sregm);
1137: // LEA reg,[sreg * 4][sreg]
1138: // SHL sreg,shift
1139: // LEA reg,[sreg * 8][reg]
1140: assert((sreg & 7) != BP);
1141: assert((reg & 7) != BP);
1142: c = gen2sib(CNIL,0x8D,grex | modregxrm(0,reg,4),
1143: modregxrmx(2,sreg,sreg));
1144: if (shift)
1145: genc2(c,0xC1,grex | modregrmx(3,4,sreg),shift);
1146: gen2sib(c,0x8D,grex | modregxrm(0,reg,4),
1147: modregxrmx(3,sreg,reg));
1148: if (!(e2factor & 1)) // if even factor
1149: { genregs(c,0x03,reg,reg); // ADD reg,reg
1150: code_orrex(c,rex);
1151: }
1152: cg = cat(cg,c);
1153: goto L3;
1154: }
1155: }
1156: }
1157:
1158: cl = scodelem(e->E1,&retregs,0,TRUE); // eval left leaf
1159: reg = findreg(retregs);
1160: cg = allocreg(&resreg,&rreg,e->Ety);
1161:
1162: /* IMUL reg,imm16 */
1163: cg = genc2(cg,0x69,grex | modregxrmx(3,rreg,reg),e2factor);
1164: goto L3;
1165: }
1166:
1167: // Special code for signed divide or modulo by power of 2
1168: if ((sz == REGSIZE || (I64 && sz == 4)) &&
1169: (oper == OPdiv || oper == OPmod) && !uns &&
1170: (pow2 = ispow2(e2factor)) != -1 &&
1171: !(config.target_cpu < TARGET_80286 && pow2 != 1 && oper == OPdiv)
1172: )
1173: {
1174: if (pow2 == 1 && oper == OPdiv && config.target_cpu > TARGET_80386)
1175: {
1176: // test eax,eax
1177: // jns L1
1178: // add eax,1
1179: // L1: sar eax,1
1180:
1181: code *cnop;
1182:
1183: retregs = allregs;
1184: cl = codelem(e->E1,&retregs,FALSE); // eval left leaf
1185: unsigned reg = findreg(retregs);
1186: freenode(e2);
1187: cg = getregs(retregs);
1188: cg = gentstreg(cg,reg); // TEST reg,reg
1189: code_orrex(cg, rex);
1190: cnop = gennop(CNIL);
1191: genjmp(cg,JNS,FLcode,(block *)cnop); // JNS cnop
1192: if (I64)
1193: {
1194: gen2(cg,0xFF,modregrmx(3,0,reg)); // INC reg
1195: code_orrex(cg,rex);
1196: }
1197: else
1198: gen1(cg,0x40 + reg); // INC reg
1199: cg = cat(cg,cnop);
1200: gen2(cg,0xD1,grex | modregrmx(3,7,reg)); // SAR reg,1
1201: resreg = retregs;
1202: goto L3;
1203: }
1204: cl = codelem(e->E1,&retregs,FALSE); // eval left leaf
1205: freenode(e2);
1206: cg = getregs(mAX | mDX); // trash these regs
1207: cg = gen1(cg,0x99); // CWD
1208: code_orrex(cg, rex);
1209: if (pow2 == 1)
1210: {
1211: if (oper == OPdiv)
1212: { gen2(cg,0x2B,grex | modregrm(3,AX,DX)); // SUB AX,DX
1213: gen2(cg,0xD1,grex | modregrm(3,7,AX)); // SAR AX,1
1214: }
1215: else // OPmod
1216: { gen2(cg,0x33,grex | modregrm(3,AX,DX)); // XOR AX,DX
1217: genc2(cg,0x81,grex | modregrm(3,4,AX),1); // AND AX,1
1218: gen2(cg,0x03,grex | modregrm(3,DX,AX)); // ADD DX,AX
1219: }
1220: }
1221: else
1222: { targ_ulong m;
1223:
1224: m = (1 << pow2) - 1;
1225: if (oper == OPdiv)
1226: { genc2(cg,0x81,grex | modregrm(3,4,DX),m); // AND DX,m
1227: gen2(cg,0x03,grex | modregrm(3,AX,DX)); // ADD AX,DX
1228: // Be careful not to generate this for 8088
1229: assert(config.target_cpu >= TARGET_80286);
1230: genc2(cg,0xC1,grex | modregrm(3,7,AX),pow2); // SAR AX,pow2
1231: }
1232: else // OPmod
1233: { gen2(cg,0x33,grex | modregrm(3,AX,DX)); // XOR AX,DX
1234: gen2(cg,0x2B,grex | modregrm(3,AX,DX)); // SUB AX,DX
1235: genc2(cg,0x81,grex | modregrm(3,4,AX),m); // AND AX,mask
1236: gen2(cg,0x33,grex | modregrm(3,AX,DX)); // XOR AX,DX
1237: gen2(cg,0x2B,grex | modregrm(3,AX,DX)); // SUB AX,DX
1238: resreg = mAX;
1239: }
1240: }
1241: goto L3;
1242: }
1243: goto L2;
1244: case OPind:
1245: if (!e2->Ecount) /* if not CSE */
1246: goto L1; /* try OP reg,EA */
1247: goto L2;
1248: default: /* OPconst and operators */
1249: L2:
1250: //printf("test2 %p, retregs = %s rretregs = %s resreg = %s\n", e, regm_str(retregs), regm_str(rretregs), regm_str(resreg));
1251: cl = codelem(e1,&retregs,FALSE); /* eval left leaf */
1252: cr = scodelem(e2,&rretregs,retregs,TRUE); /* get rvalue */
1253: if (sz <= REGSIZE)
1254: { cg = getregs(mAX | mDX); /* trash these regs */
1255: if (op == 7) /* signed divide */
1256: { cg = gen1(cg,0x99); // CWD
1257: code_orrex(cg,rex);
1258: }
1259: else if (op == 6) /* unsigned divide */
1260: {
1261: cg = movregconst(cg,DX,0,(sz == 8) ? 64 : 0); // MOV DX,0
1262: cg = cat(cg,getregs(mDX));
1263: }
1264: rreg = findreg(rretregs);
1265: cg = gen2(cg,0xF7 ^ byte,grex | modregrmx(3,op,rreg)); // OP AX,rreg
1266: if (I64 && byte && rreg >= 4)
1267: code_orrex(cg, REX);
1268: L3:
1269: c = fixresult(e,resreg,pretregs);
1270: }
1271: else if (sz == 2 * REGSIZE)
1272: {
1273: if (config.target_cpu >= TARGET_PentiumPro && oper == OPmul)
1274: {
1275: /* IMUL ECX,EAX
1276: IMUL EDX,EBX
1277: ADD ECX,EDX
1278: MUL EBX
1279: ADD EDX,ECX
1280: */
1281: cg = getregs(mAX|mDX|mCX);
1282: cg = gen2(cg,0x0FAF,modregrm(3,CX,AX));
1283: gen2(cg,0x0FAF,modregrm(3,DX,BX));
1284: gen2(cg,0x03,modregrm(3,CX,DX));
1285: gen2(cg,0xF7,modregrm(3,4,BX));
1286: gen2(cg,0x03,modregrm(3,DX,CX));
1287: c = fixresult(e,mDX|mAX,pretregs);
1288: }
1289: else
1290: c = callclib(e,lib,pretregs,keepregs);
1291: }
1292: else
1293: assert(0);
1294: break;
1295: case OPvar:
1296: L1:
1297: if (!I16 && sz <= REGSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1298: {
1299: if (oper == OPmul && sz > 1) /* no byte version */
1300: {
1301: /* Generate IMUL r32,r/m32 */
1302: retregs = *pretregs & (ALLREGS | mBP);
1303: if (!retregs)
1304: retregs = ALLREGS;
1305: cl = codelem(e1,&retregs,FALSE); /* eval left leaf */
1306: resreg = retregs;
1307: cr = loadea(e2,&cs,0x0FAF,findreg(resreg),0,retregs,retregs);
1308: freenode(e2);
1309: goto L3;
1310: }
1311: }
1312: else
1313: {
1314: if (sz == 2 * REGSIZE)
1315: { int reg;
1316:
1317: if (oper != OPmul || e->E1->Eoper != opunslng ||
1318: e1->Ecount)
1319: goto L2; // have to handle it with codelem()
1320:
1321: retregs = ALLREGS & ~(mAX | mDX);
1322: cl = codelem(e1->E1,&retregs,FALSE); // eval left leaf
1323: reg = findreg(retregs);
1324: cl = cat(cl,getregs(mAX));
1325: cl = genmovreg(cl,AX,reg); // MOV AX,reg
1326: cr = loadea(e2,&cs,0xF7,4,REGSIZE,mAX | mDX | mskl(reg),mAX | mDX); // MUL EA+2
1327: cg = getregs(retregs);
1328: cg = gen1(cg,0x90 + reg); // XCHG AX,reg
1329: cg = cat(cg,getregs(mAX | mDX));
1330: if ((cs.Irm & 0xC0) == 0xC0) // if EA is a register
1331: cg = cat(cg,loadea(e2,&cs,0xF7,4,0,mAX | mskl(reg),mAX | mDX)); // MUL EA
1332: else
1333: { getlvalue_lsw(&cs);
1334: gen(cg,&cs); // MUL EA
1335: }
1336: gen2(cg,0x03,modregrm(3,DX,reg)); // ADD DX,reg
1337:
1338: freenode(e1);
1339: c = fixresult(e,mAX | mDX,pretregs);
1340: break;
1341: }
1342: assert(sz <= REGSIZE);
1343: }
1344:
1345: /* loadea() handles CWD or CLR DX for divides */
1346: cl = codelem(e->E1,&retregs,FALSE); /* eval left leaf */
1347: cr = loadea(e2,&cs,0xF7 ^ byte,op,0,
1348: (oper == OPmul) ? mAX : mAX | mDX,
1349: mAX | mDX);
1350: freenode(e2);
1351: goto L3;
1352: }
1353: return cat4(cl,cr,cg,c);
1354: }
1355:
1356:
1357: /***************************
1358: * Handle OPnot and OPbool.
1359: * Generate:
1360: * c: [evaluate e1]
1361: * cfalse: [save reg code]
1362: * clr reg
1363: * jmp cnop
1364: * ctrue: [save reg code]
1365: * clr reg
1366: * inc reg
1367: * cnop: nop
1368: */
1369:
1370: code *cdnot(elem *e,regm_t *pretregs)
1371: { unsigned reg;
1372: tym_t forflags;
1373: code *c1,*c,*cfalse,*ctrue,*cnop;
1374: unsigned sz;
1375: regm_t retregs;
1376: elem *e1;
1377: int op;
1378:
1379: e1 = e->E1;
1380: if (*pretregs == 0)
1381: goto L1;
1382: if (*pretregs == mPSW)
1383: { /*assert(e->Eoper != OPnot && e->Eoper != OPbool);*/ /* should've been optimized */
1384: L1:
1385: return codelem(e1,pretregs,FALSE); /* evaluate e1 for cc */
1386: }
1387:
1388: op = e->Eoper;
1389: sz = tysize(e1->Ety);
1390: unsigned rex = (I64 && sz == 8) ? REX_W : 0;
1391: unsigned grex = rex << 16;
1392: if (!tyfloating(e1->Ety))
1393: {
1394: if (sz <= REGSIZE && e1->Eoper == OPvar)
warning C4018: '<=' : signed/unsigned mismatch
1395: { code cs;
1396:
1397: c = getlvalue(&cs,e1,0);
1398: freenode(e1);
1399: if (!I16 && sz == 2)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1400: cs.Iflags |= CFopsize;
1401:
1402: retregs = *pretregs & (ALLREGS | mBP);
1403: if (config.target_cpu >= TARGET_80486 &&
1404: tysize(e->Ety) == 1)
1405: {
1406: if (reghasvalue((sz == 1) ? BYTEREGS : ALLREGS,0,®))
1407: cs.Iop = 0x39;
1408: else
1409: { cs.Iop = 0x81;
1410: reg = 7;
1411: cs.IFL2 = FLconst;
1412: cs.IEV2.Vint = 0;
1413: }
1414: cs.Iop ^= (sz == 1);
1415: code_newreg(&cs,reg);
1416: c = gen(c,&cs); // CMP e1,0
1417:
1418: retregs &= BYTEREGS;
1419: if (!retregs)
1420: retregs = BYTEREGS;
1421: c1 = allocreg(&retregs,®,TYint);
1422:
1423: int iop;
1424: if (op == OPbool)
1425: {
1426: iop = 0x0F95; // SETNZ rm8
1427: }
1428: else
1429: {
1430: iop = 0x0F94; // SETZ rm8
1431: }
1432: c1 = gen2(c1,iop,grex | modregrmx(3,0,reg));
1433: if (reg >= 4)
1434: code_orrex(c1, REX);
1435: if (op == OPbool)
1436: *pretregs &= ~mPSW;
1437: goto L4;
1438: }
1439:
1440: if (reghasvalue((sz == 1) ? BYTEREGS : ALLREGS,1,®))
1441: cs.Iop = 0x39;
1442: else
1443: { cs.Iop = 0x81;
1444: reg = 7;
1445: cs.IFL2 = FLconst;
1446: cs.IEV2.Vint = 1;
1447: }
1448: cs.Iop ^= (sz == 1);
1449: code_newreg(&cs,reg);
1450: c = gen(c,&cs); // CMP e1,1
1451:
1452: c1 = allocreg(&retregs,®,TYint);
1453: op ^= (OPbool ^ OPnot); // switch operators
1454: goto L2;
1455: }
1456: else if (sz <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1457: // NEG bytereg is too expensive
1458: (sz != 1 || config.target_cpu < TARGET_PentiumPro))
1459: {
1460: retregs = *pretregs & (ALLREGS | mBP);
1461: if (sz == 1 && !(retregs &= BYTEREGS))
1462: retregs = BYTEREGS;
1463: c = codelem(e->E1,&retregs,FALSE);
1464: reg = findreg(retregs);
1465: c1 = getregs(retregs);
1466: c1 = gen2(c1,0xF7 ^ (sz == 1),grex | modregrmx(3,3,reg)); // NEG reg
warning C4806: '^' : unsafe operation: no value of type 'bool' promoted to type 'int' can equal the given constant
1467: code_orflag(c1,CFpsw);
1468: if (!I16 && sz == SHORTSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
1469: code_orflag(c1,CFopsize);
1470: L2:
1471: c1 = genregs(c1,0x19,reg,reg); // SBB reg,reg
1472: code_orrex(c1, rex);
1473: // At this point, reg==0 if e1==0, reg==-1 if e1!=0
1474: if (op == OPnot)
1475: {
1476: if (I64)
1477: gen2(c1,0xFF,grex | modregrmx(3,0,reg)); // INC reg
1478: else
1479: gen1(c1,0x40 + reg); // INC reg
1480: }
1481: else
1482: gen2(c1,0xF7,grex | modregrmx(3,3,reg)); // NEG reg
1483: if (*pretregs & mPSW)
1484: { code_orflag(c1,CFpsw);
1485: *pretregs &= ~mPSW; // flags are always set anyway
1486: }
1487: L4:
1488: return cat3(c,c1,fixresult(e,retregs,pretregs));
1489: }
1490: }
1491: cnop = gennop(CNIL);
1492: ctrue = gennop(CNIL);
1493: c = logexp(e->E1,(op == OPnot) ? FALSE : TRUE,FLcode,ctrue);
1494: forflags = *pretregs & mPSW;
1495: if (I64 && sz == 8)
1496: forflags |= 64;
1497: assert(tysize(e->Ety) <= REGSIZE); // result better be int
1498: cfalse = allocreg(pretregs,®,e->Ety); // allocate reg for result
1499: for (c1 = cfalse; c1; c1 = code_next(c1))
1500: gen(ctrue,c1); // duplicate reg save code
1501: cfalse = movregconst(cfalse,reg,0,forflags); // mov 0 into reg
1502: regcon.immed.mval &= ~mask[reg]; // mark reg as unavail
1503: ctrue = movregconst(ctrue,reg,1,forflags); // mov 1 into reg
1504: regcon.immed.mval &= ~mask[reg]; // mark reg as unavail
1505: genjmp(cfalse,JMP,FLcode,(block *) cnop); // skip over ctrue
1506: c = cat4(c,cfalse,ctrue,cnop);
1507: return c;
1508: }
1509:
1510:
1511: /************************
1512: * Complement operator
1513: */
1514:
1515: code *cdcom(elem *e,regm_t *pretregs)
1516: { unsigned reg,op;
1517: regm_t retregs,possregs;
1518: code *c,*c1,*cg;
1519: tym_t tym;
1520: int sz;
1521:
1522: if (*pretregs == 0)
1523: return codelem(e->E1,pretregs,FALSE);
1524: tym = tybasic(e->Ety);
1525: sz = tysize[tym];
1526: unsigned rex = (I64 && sz == 8) ? REX_W : 0;
1527: possregs = (sz == 1) ? BYTEREGS : allregs;
1528: retregs = *pretregs & possregs;
1529: if (retregs == 0)
1530: retregs = possregs;
1531: c1 = codelem(e->E1,&retregs,FALSE);
1532: cg = getregs(retregs); /* retregs will be destroyed */
1533: #if 0
1534: if (sz == 4 * REGSIZE)
1535: {
1536: c = gen2(CNIL,0xF7,modregrm(3,2,AX)); // NOT AX
1537: gen2(c,0xF7,modregrm(3,2,BX)); // NOT BX
1538: gen2(c,0xF7,modregrm(3,2,CX)); // NOT CX
1539: gen2(c,0xF7,modregrm(3,2,DX)); // NOT DX
1540: }
1541: else
1542: #endif
1543: {
1544: reg = (sz <= REGSIZE) ? findreg(retregs) : findregmsw(retregs);
1545: op = (sz == 1) ? 0xF6 : 0xF7;
1546: c = genregs(CNIL,op,2,reg); // NOT reg
1547: code_orrex(c, rex);
1548: if (I64 && sz == 1 && reg >= 4)
1549: code_orrex(c, REX);
1550: if (sz == 2 * REGSIZE)
1551: { reg = findreglsw(retregs);
1552: genregs(c,op,2,reg); // NOT reg+1
1553: }
1554: }
1555: return cat4(c1,cg,c,fixresult(e,retregs,pretregs));
1556: }
1557:
1558: /************************
1559: * Bswap operator
1560: */
1561:
1562: code *cdbswap(elem *e,regm_t *pretregs)
1563: { unsigned reg,op;
warning C4101: 'op' : unreferenced local variable
1564: regm_t retregs;
1565: code *c,*c1,*cg;
1566: tym_t tym;
1567: int sz;
warning C4101: 'sz' : unreferenced local variable
1568:
1569: if (*pretregs == 0)
1570: return codelem(e->E1,pretregs,FALSE);
1571:
1572: tym = tybasic(e->Ety);
1573: assert(tysize[tym] == 4);
1574: retregs = *pretregs & allregs;
1575: if (retregs == 0)
1576: retregs = allregs;
1577: c1 = codelem(e->E1,&retregs,FALSE);
1578: cg = getregs(retregs); // retregs will be destroyed
1579: reg = findreg(retregs);
1580: c = gen2(CNIL,0x0FC8 + (reg & 7),0); // BSWAP reg
1581: if (reg & 8)
1582: code_orrex(c, REX_B);
1583: return cat4(c1,cg,c,fixresult(e,retregs,pretregs));
1584: }
1585:
1586: /*************************
1587: * ?: operator
1588: */
1589:
1590: code *cdcond(elem *e,regm_t *pretregs)
1591: { regm_t psw;
1592: code *cc,*c,*c1,*cnop1,*c2,*cnop2;
1593: con_t regconold,regconsave;
1594: unsigned stackpushold,stackpushsave;
1595: int ehindexold,ehindexsave;
warning C4101: 'ehindexsave' : unreferenced local variable
warning C4101: 'ehindexold' : unreferenced local variable
1596: unsigned jop;
1597: unsigned op1;
1598: unsigned sz1;
1599: unsigned sz2;
1600: elem *e1;
1601: elem *e2;
1602: elem *e21;
1603: elem *e22;
1604:
1605: /* vars to save state of 8087 */
1606: int stackusedold,stackusedsave;
1607: NDP _8087old[arraysize(_8087elems)];
1608: NDP _8087save[arraysize(_8087elems)];
1609:
1610: _chkstack();
1611:
1612: //printf("cdcond(e = %p, *pretregs = %s)\n",e,regm_str(*pretregs));
1613: e1 = e->E1;
1614: e2 = e->E2;
1615: e21 = e2->E1;
1616: e22 = e2->E2;
1617: cc = docommas(&e1);
1618: cgstate.stackclean++;
1619: psw = *pretregs & mPSW; /* save PSW bit */
1620: op1 = e1->Eoper;
1621: sz1 = tysize(e1->Ety);
1622: unsigned rex = (I64 && sz1 == 8) ? REX_W : 0;
1623: unsigned grex = rex << 16;
1624: jop = jmpopcode(e1);
1625:
1626: if (!OTrel(op1) && e1 == e21 &&
1627: sz1 <= REGSIZE && !tyfloating(e1->Ety))
warning C4018: '<=' : signed/unsigned mismatch
1628: { // Recognize (e ? e : f)
1629: regm_t retregs;
1630:
1631: cnop1 = gennop(CNIL);
1632: retregs = *pretregs | mPSW;
1633: c = codelem(e1,&retregs,FALSE);
1634:
1635: c = cat(c,cse_flush(1)); // flush CSEs to memory
1636: c = genjmp(c,jop,FLcode,(block *)cnop1);
1637: freenode(e21);
1638:
1639: regconsave = regcon;
1640: stackpushsave = stackpush;
1641:
1642: retregs |= psw;
1643: if (retregs & (mBP | ALLREGS))
1644: regimmed_set(findreg(retregs),0);
1645: c2 = codelem(e22,&retregs,FALSE);
1646:
1647: andregcon(®consave);
1648: assert(stackpushsave == stackpush);
1649:
1650: *pretregs = retregs;
1651: freenode(e2);
1652: c = cat4(cc,c,c2,cnop1);
1653: goto Lret;
1654: }
1655:
1656: if (OTrel(op1) && sz1 <= REGSIZE && tysize(e2->Ety) <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1657: !e1->Ecount &&
1658: (jop == JC || jop == JNC) &&
1659: (sz2 = tysize(e2->Ety)) <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1660: e21->Eoper == OPconst &&
1661: e22->Eoper == OPconst
1662: )
1663: { regm_t retregs;
1664: unsigned reg;
1665: targ_size_t v1,v2;
1666: int opcode;
1667:
1668: retregs = *pretregs & (ALLREGS | mBP);
1669: if (!retregs)
1670: retregs = ALLREGS;
1671: cdcmp_flag = 1;
1672: c = codelem(e1,&retregs,FALSE);
1673: reg = findreg(retregs);
1674: v1 = e21->EV.Vllong;
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1675: v2 = e22->EV.Vllong;
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1676: if (jop == JNC)
1677: { v1 = v2;
1678: v2 = e21->EV.Vlong;
1679: }
1680:
1681: opcode = 0x81;
1682: switch (sz2)
1683: { case 1: opcode--;
1684: v1 = (signed char) v1;
1685: v2 = (signed char) v2;
1686: break;
1687: case 2: v1 = (short) v1;
1688: v2 = (short) v2;
1689: break;
1690: case 4: v1 = (int) v1;
1691: v2 = (int) v2;
1692: break;
1693: }
1694:
1695: if (v1 == 0 && v2 == ~(targ_size_t)0)
1696: c = gen2(c,0xF6 + (opcode & 1),grex | modregrmx(3,2,reg)); // NOT reg
1697: else
1698: {
1699: v1 -= v2;
1700: c = genc2(c,opcode,grex | modregrmx(3,4,reg),v1); // AND reg,v1-v2
1701: if (v2 == 1 && !I64)
1702: gen1(c,0x40 + reg); // INC reg
1703: else if (v2 == -1L && !I64)
1704: gen1(c,0x48 + reg); // DEC reg
1705: else
1706: genc2(c,opcode,grex | modregrmx(3,0,reg),v2); // ADD reg,v2
1707: }
1708:
1709: freenode(e21);
1710: freenode(e22);
1711: freenode(e2);
1712:
1713: c = cat(c,fixresult(e,retregs,pretregs));
1714: goto Lret;
1715: }
1716:
1717: if (op1 != OPcond && op1 != OPandand && op1 != OPoror &&
1718: op1 != OPnot && op1 != OPbool &&
1719: e21->Eoper == OPconst &&
1720: sz1 <= REGSIZE &&
warning C4018: '<=' : signed/unsigned mismatch
1721: *pretregs & (mBP | ALLREGS) &&
1722: tysize(e21->Ety) <= REGSIZE && !tyfloating(e21->Ety))
1723: { // Recognize (e ? c : f)
1724: unsigned reg;
1725: regm_t retregs;
1726:
1727: cnop1 = gennop(CNIL);
1728: retregs = mPSW;
1729: jop = jmpopcode(e1); // get jmp condition
1730: c = codelem(e1,&retregs,FALSE);
1731:
1732: // Set the register with e21 without affecting the flags
1733: retregs = *pretregs & (ALLREGS | mBP);
1734: if (retregs & ~regcon.mvar)
1735: retregs &= ~regcon.mvar; // don't disturb register variables
1736: // NOTE: see my email (sign extension bug? possible fix, some questions
1737: c = regwithvalue(c,retregs,e21->EV.Vllong,®,tysize(e21->Ety) == 8 ? 64|8 : 8);
warning C4244: 'argument' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
1738: retregs = mask[reg];
1739:
1740: c = cat(c,cse_flush(1)); // flush CSE's to memory
1741: c = genjmp(c,jop,FLcode,(block *)cnop1);
1742: freenode(e21);
1743:
1744: regconsave = regcon;
1745: stackpushsave = stackpush;
1746:
1747: c2 = codelem(e22,&retregs,FALSE);
1748:
1749: andregcon(®consave);
1750: assert(stackpushsave == stackpush);
1751:
1752: freenode(e2);
1753: c = cat6(cc,c,c2,cnop1,fixresult(e,retregs,pretregs),NULL);
1754: goto Lret;
1755: }
1756:
1757: cnop1 = gennop(CNIL);
1758: cnop2 = gennop(CNIL); /* dummy target addresses */
1759: c = logexp(e1,FALSE,FLcode,cnop1); /* evaluate condition */
1760: regconold = regcon;
1761: stackusedold = stackused;
1762: stackpushold = stackpush;
1763: memcpy(_8087old,_8087elems,sizeof(_8087elems));
1764: c1 = codelem(e21,pretregs,FALSE);
1765:
1766: #if SCPP
1767: if (CPP && e2->Eoper == OPcolon2)
1768: { code cs;
1769:
1770: // This is necessary so that any cleanup code on one branch
1771: // is redone on the other branch.
1772: cs.Iop = ESCAPE | ESCmark2;
1773: cs.Iflags = 0;
1774: cs.Irex = 0;
1775: c1 = cat(gen(CNIL,&cs),c1);
1776: cs.Iop = ESCAPE | ESCrelease2;
1777: c1 = gen(c1,&cs);
1778: }
1779: #endif
1780:
1781: regconsave = regcon;
1782: regcon = regconold;
1783:
1784: stackpushsave = stackpush;
1785: stackpush = stackpushold;
1786:
1787: stackusedsave = stackused;
1788: stackused = stackusedold;
1789:
1790: memcpy(_8087save,_8087elems,sizeof(_8087elems));
1791: memcpy(_8087elems,_8087old,sizeof(_8087elems));
1792:
1793: *pretregs |= psw; /* PSW bit may have been trashed */
1794: c2 = codelem(e22,pretregs,FALSE); /* use same regs as E1 */
1795: andregcon(®conold);
1796: andregcon(®consave);
1797: assert(stackused == stackusedsave);
1798: assert(stackpush == stackpushsave);
1799: memcpy(_8087elems,_8087save,sizeof(_8087elems));
1800: freenode(e2);
1801: c = cat(cc,c);
1802: c = cat6(c,c1,genjmp(CNIL,JMP,FLcode,(block *) cnop2),cnop1,c2,cnop2);
1803: if (*pretregs & mST0)
1804: note87(e,0,0);
1805: Lret:
1806: cgstate.stackclean--;
1807: return c;
1808: }
1809:
1810: /*********************
1811: * Comma operator
1812: */
1813:
1814: code *cdcomma(elem *e,regm_t *pretregs)
1815: { regm_t retregs;
1816: code *cl,*cr;
1817:
1818: retregs = 0;
1819: cl = codelem(e->E1,&retregs,FALSE); /* ignore value from left leaf */
1820: cr = codelem(e->E2,pretregs,FALSE); /* do right leaf */
1821: return cat(cl,cr);
1822: }
1823:
1824:
1825: /*********************************
1826: * Do && and || operators.
1827: * Generate:
1828: * (evaluate e1 and e2, if TRUE goto cnop1)
1829: * cnop3: NOP
1830: * cg: [save reg code] ;if we must preserve reg
1831: * CLR reg ;FALSE result (set Z also)
1832: * JMP cnop2
1833: *
1834: * cnop1: NOP ;if e1 evaluates to TRUE
1835: * [save reg code] ;preserve reg
1836: *
1837: * MOV reg,1 ;TRUE result
1838: * or
1839: * CLR reg ;if return result in flags
1840: * INC reg
1841: *
1842: * cnop2: NOP ;mark end of code
1843: */
1844:
1845: code *cdloglog(elem *e,regm_t *pretregs)
1846: { regm_t retregs;
1847: unsigned reg;
1848: code *c;
1849: code *cl,*cr,*cg,*cnop1,*cnop2,*cnop3;
1850: code *c1;
1851: con_t regconsave;
1852: unsigned stackpushsave;
1853: elem *e2;
1854: unsigned sz = tysize(e->Ety);
1855:
1856: /* We can trip the assert with the following: */
1857: /* if ( (b<=a) ? (c<b || a<=c) : c>=a ) */
1858: /* We'll generate ugly code for it, but it's too obscure a case */
1859: /* to expend much effort on it. */
1860: /*assert(*pretregs != mPSW);*/
1861:
1862: cgstate.stackclean++;
1863: cnop1 = gennop(CNIL);
1864: cnop3 = gennop(CNIL);
1865: e2 = e->E2;
1866: cl = (e->Eoper == OPoror)
1867: ? logexp(e->E1,1,FLcode,cnop1)
1868: : logexp(e->E1,0,FLcode,cnop3);
1869: regconsave = regcon;
1870: stackpushsave = stackpush;
1871: if (*pretregs == 0) /* if don't want result */
1872: { int noreturn = el_noreturn(e2);
1873:
1874: cr = codelem(e2,pretregs,FALSE);
1875: if (noreturn)
1876: {
1877: regconsave.used |= regcon.used;
1878: regcon = regconsave;
1879: }
1880: else
1881: andregcon(®consave);
1882: assert(stackpush == stackpushsave);
1883: c = cat4(cl,cr,cnop3,cnop1); // eval code, throw away result
1884: goto Lret;
1885: }
1886: cnop2 = gennop(CNIL);
1887: if (tybasic(e2->Ety) == TYbool &&
1888: sz == tysize(e2->Ety) &&
1889: !(*pretregs & mPSW) &&
1890: e2->Eoper == OPcall)
1891: {
1892: cr = codelem(e2,pretregs,FALSE);
1893:
1894: andregcon(®consave);
1895:
1896: // stack depth should not change when evaluating E2
1897: assert(stackpush == stackpushsave);
1898:
1899: assert(sz <= 4); // result better be int
1900: retregs = *pretregs & allregs;
1901: cnop1 = cat(cnop1,allocreg(&retregs,®,TYint)); // allocate reg for result
1902: cg = genjmp(NULL,JMP,FLcode,(block *) cnop2); // JMP cnop2
1903: cnop1 = movregconst(cnop1,reg,e->Eoper == OPoror,0); // reg = 1
1904: regcon.immed.mval &= ~mask[reg]; // mark reg as unavail
1905: *pretregs = retregs;
1906: if (e->Eoper == OPoror)
1907: c = cat6(cl,cr,cnop3,cg,cnop1,cnop2);
1908: else
1909: c = cat6(cl,cr,cg,cnop3,cnop1,cnop2);
1910:
1911: goto Lret;
1912: }
1913: cr = logexp(e2,1,FLcode,cnop1);
1914: andregcon(®consave);
1915:
1916: /* stack depth should not change when evaluating E2 */
1917: assert(stackpush == stackpushsave);
1918:
1919: assert(sz <= 4); // result better be int
1920: retregs = *pretregs & (ALLREGS | mBP);
1921: if (!retregs) retregs = ALLREGS; // if mPSW only
1922: cg = allocreg(&retregs,®,TYint); // allocate reg for result
1923: for (c1 = cg; c1; c1 = code_next(c1)) // for each instruction
1924: gen(cnop1,c1); // duplicate it
1925: cg = movregconst(cg,reg,0,*pretregs & mPSW); // MOV reg,0
1926: regcon.immed.mval &= ~mask[reg]; // mark reg as unavail
1927: genjmp(cg,JMP,FLcode,(block *) cnop2); // JMP cnop2
1928: cnop1 = movregconst(cnop1,reg,1,*pretregs & mPSW); // reg = 1
1929: regcon.immed.mval &= ~mask[reg]; // mark reg as unavail
1930: *pretregs = retregs;
1931: c = cat6(cl,cr,cnop3,cg,cnop1,cnop2);
1932: Lret:
1933: cgstate.stackclean--;
1934: return c;
1935: }
1936:
1937:
1938: /*********************
1939: * Generate code for shift left or shift right (OPshl,OPshr,OPashr,OProl,OPror).
1940: */
1941:
1942: code *cdshift(elem *e,regm_t *pretregs)
1943: { unsigned resreg,shiftcnt,byte;
1944: unsigned s1,s2,oper;
1945: tym_t tyml;
1946: int sz;
1947: regm_t retregs,rretregs;
1948: code *cg,*cl,*cr;
1949: code *c;
1950: elem *e1;
1951: elem *e2;
1952: regm_t forccs,forregs;
1953: bool e2isconst;
1954:
1955: e1 = e->E1;
1956: if (*pretregs == 0) // if don't want result
1957: { c = codelem(e1,pretregs,FALSE); // eval left leaf
1958: *pretregs = 0; // in case they got set
1959: return cat(c,codelem(e->E2,pretregs,FALSE));
1960: }
1961:
1962: tyml = tybasic(e1->Ety);
1963: sz = tysize[tyml];
1964: assert(!tyfloating(tyml));
1965: oper = e->Eoper;
1966: unsigned rex = (I64 && sz == 8) ? REX_W : 0;
1967: unsigned grex = rex << 16;
1968:
1969: #if SCPP
1970: // Do this until the rest of the compiler does OPshr/OPashr correctly
1971: if (oper == OPshr)
1972: oper = (tyuns(tyml)) ? OPshr : OPashr;
1973: #endif
1974:
1975: switch (oper)
1976: { case OPshl:
1977: s1 = 4; // SHL
1978: s2 = 2; // RCL
1979: break;
1980: case OPshr:
1981: s1 = 5; // SHR
1982: s2 = 3; // RCR
1983: break;
1984: case OPashr:
1985: s1 = 7; // SAR
1986: s2 = 3; // RCR
1987: break;
1988: case OProl:
1989: s1 = 0; // ROL
1990: break;
1991: case OPror:
1992: s1 = 1; // ROR
1993: break;
1994: default:
1995: assert(0);
1996: }
1997:
1998: unsigned sreg = ~0; // guard against using value without assigning to sreg
1999: c = cg = cr = CNIL; /* initialize */
2000: e2 = e->E2;
2001: forccs = *pretregs & mPSW; /* if return result in CCs */
2002: forregs = *pretregs & (ALLREGS | mBP); // mask of possible return regs
2003: e2isconst = FALSE; /* assume for the moment */
2004: byte = (sz == 1);
2005: switch (e2->Eoper)
2006: {
2007: case OPconst:
2008: e2isconst = TRUE; /* e2 is a constant */
2009: shiftcnt = e2->EV.Vint; /* get shift count */
2010: if ((!I16 && sz <= REGSIZE) ||
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2011: shiftcnt <= 4 || /* if sequence of shifts */
2012: (sz == 2 &&
2013: (shiftcnt == 8 || config.target_cpu >= TARGET_80286)) ||
2014: (sz == 2 * REGSIZE && shiftcnt == 8 * REGSIZE)
2015: )
2016: { retregs = (forregs) ? forregs
2017: : ALLREGS;
2018: if (byte)
2019: { retregs &= BYTEREGS;
2020: if (!retregs)
2021: retregs = BYTEREGS;
2022: }
2023: else if (sz > REGSIZE && sz <= 2 * REGSIZE &&
2024: !(retregs & mMSW))
2025: retregs |= mMSW & ALLREGS;
2026: if (s1 == 7) /* if arithmetic right shift */
2027: {
2028: if (shiftcnt == 8)
2029: retregs = mAX;
2030: else if (sz == 2 * REGSIZE && shiftcnt == 8 * REGSIZE)
2031: retregs = mDX|mAX;
2032: }
2033:
2034: if (sz == 2 * REGSIZE && shiftcnt == 8 * REGSIZE &&
2035: oper == OPshl &&
2036: !e1->Ecount &&
2037: (e1->Eoper == OPshtlng || e1->Eoper == OPu16_32 ||
2038: e1->Eoper == OPlngllng || e1->Eoper == OPu32_64)
2039: )
2040: { // Handle (shtlng)s << 16
2041: regm_t r;
2042:
2043: r = retregs & mMSW;
2044: cl = codelem(e1->E1,&r,FALSE); // eval left leaf
2045: cl = regwithvalue(cl,retregs & mLSW,0,&resreg,0);
2046: cg = getregs(r);
2047: retregs = r | mask[resreg];
2048: if (forccs)
2049: { sreg = findreg(r);
2050: cg = gentstreg(cg,sreg);
2051: *pretregs &= ~mPSW; // already set
2052: }
2053: freenode(e1);
2054: freenode(e2);
2055: break;
2056: }
2057:
2058: // See if we should use LEA reg,xxx instead of shift
2059: if (!I16 && shiftcnt >= 1 && shiftcnt <= 3 &&
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2060: (sz == REGSIZE || (I64 && sz == 4)) &&
2061: oper == OPshl &&
2062: e1->Eoper == OPvar &&
2063: !(*pretregs & mPSW) &&
2064: config.flags4 & CFG4speed
2065: )
2066: {
2067: unsigned reg;
2068: regm_t regm;
2069:
2070: if (isregvar(e1,®m,®) && !(regm & retregs))
2071: { code cs;
2072: cl = allocreg(&retregs,&resreg,e->Ety);
2073: buildEA(&cs,-1,reg,1 << shiftcnt,0);
2074: cs.Iop = 0x8D;
2075: code_newreg(&cs,resreg);
2076: cs.Iflags = 0;
2077: cg = gen(NULL,&cs); // LEA resreg,[reg * ss]
2078: freenode(e1);
2079: freenode(e2);
2080: break;
2081: }
2082: }
2083:
2084: cl = codelem(e1,&retregs,FALSE); // eval left leaf
2085: //assert((retregs & regcon.mvar) == 0);
2086: cg = getregs(retregs); // trash these regs
2087:
2088: {
2089: if (sz == 2 * REGSIZE)
2090: { resreg = findregmsw(retregs);
2091: sreg = findreglsw(retregs);
2092: }
2093: else
2094: { resreg = findreg(retregs);
2095: sreg = ~0; // an invalid value
2096: }
2097: if (config.target_cpu >= TARGET_80286 &&
2098: sz <= REGSIZE)
2099: {
2100: /* SHL resreg,shiftcnt */
2101: assert(!(sz == 1 && (mask[resreg] & ~BYTEREGS)));
2102: c = genc2(CNIL,0xC1 ^ byte,grex | modregxrmx(3,s1,resreg),shiftcnt);
2103: if (shiftcnt == 1)
2104: c->Iop += 0x10; /* short form of shift */
2105: if (I64 && sz == 1 && resreg >= 4)
2106: c->Irex |= REX;
2107: // See if we need operand size prefix
2108: if (!I16 && oper != OPshl && sz == 2)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2109: c->Iflags |= CFopsize;
2110: if (forccs)
2111: c->Iflags |= CFpsw; // need flags result
2112: }
2113: else if (shiftcnt == 8)
2114: { if (!(retregs & BYTEREGS) || resreg >= 4)
2115: {
2116: cl = cat(cl,cg);
2117: goto L1;
2118: }
2119:
2120: if (pass != PASSfinal && (!forregs || forregs & (mSI | mDI)))
2121: {
2122: // e1 might get into SI or DI in a later pass,
2123: // so don't put CX into a register
2124: cg = cat(cg, getregs(mCX));
2125: }
2126:
2127: assert(sz == 2);
2128: switch (oper)
2129: {
2130: case OPshl:
2131: /* MOV regH,regL XOR regL,regL */
2132: assert(resreg < 4 && !rex);
2133: c = genregs(CNIL,0x8A,resreg+4,resreg);
2134: genregs(c,0x32,resreg,resreg);
2135: break;
2136:
2137: case OPshr:
2138: case OPashr:
2139: /* MOV regL,regH */
2140: c = genregs(CNIL,0x8A,resreg,resreg+4);
2141: if (oper == OPashr)
2142: gen1(c,0x98); /* CBW */
2143: else
2144: genregs(c,0x32,resreg+4,resreg+4); /* CLR regH */
2145: break;
2146:
2147: case OPror:
2148: case OProl:
2149: // XCHG regL,regH
2150: c = genregs(CNIL,0x86,resreg+4,resreg);
2151: break;
2152:
2153: default:
2154: assert(0);
2155: }
2156: if (forccs)
2157: gentstreg(c,resreg);
2158: }
2159: else if (shiftcnt == REGSIZE * 8) // it's an lword
2160: {
2161: if (oper == OPshl)
2162: swap((int *) &resreg,(int *) &sreg);
2163: c = genmovreg(CNIL,sreg,resreg); // MOV sreg,resreg
2164: if (oper == OPashr)
2165: gen1(c,0x99); // CWD
2166: else
2167: movregconst(c,resreg,0,0); // MOV resreg,0
2168: if (forccs)
2169: { gentstreg(c,sreg);
2170: *pretregs &= mBP | ALLREGS | mES;
2171: }
2172: }
2173: else
2174: { c = CNIL;
2175: if (oper == OPshl && sz == 2 * REGSIZE)
2176: swap((int *) &resreg,(int *) &sreg);
2177: while (shiftcnt--)
2178: { c = gen2(c,0xD1 ^ byte,modregrm(3,s1,resreg));
2179: if (sz == 2 * REGSIZE)
2180: gen2(c,0xD1,modregrm(3,s2,sreg));
2181: }
2182: if (forccs)
2183: code_orflag(c,CFpsw);
2184: }
2185: if (sz <= REGSIZE)
2186: *pretregs &= mBP | ALLREGS; // flags already set
2187: }
2188: freenode(e2);
2189: break;
2190: }
2191: /* FALL-THROUGH */
2192: default:
2193: retregs = forregs & ~mCX; /* CX will be shift count */
2194: if (sz <= REGSIZE)
2195: {
2196: if (forregs & ~regcon.mvar && !(retregs & ~regcon.mvar))
2197: retregs = ALLREGS & ~mCX; /* need something */
2198: else if (!retregs)
2199: retregs = ALLREGS & ~mCX; /* need something */
2200: if (sz == 1)
2201: { retregs &= mAX|mBX|mDX;
2202: if (!retregs)
2203: retregs = mAX|mBX|mDX;
2204: }
2205: }
2206: else
2207: {
2208: if (!(retregs & mMSW))
2209: retregs = ALLREGS & ~mCX;
2210: }
2211: cl = codelem(e->E1,&retregs,FALSE); /* eval left leaf */
2212:
2213: if (sz <= REGSIZE)
2214: resreg = findreg(retregs);
2215: else
2216: {
2217: resreg = findregmsw(retregs);
2218: sreg = findreglsw(retregs);
2219: }
2220: L1:
2221: rretregs = mCX; /* CX is shift count */
2222: if (sz <= REGSIZE)
2223: {
2224: cr = scodelem(e2,&rretregs,retregs,FALSE); /* get rvalue */
2225: cg = getregs(retregs); /* trash these regs */
2226: c = gen2(CNIL,0xD3 ^ byte,grex | modregrmx(3,s1,resreg)); /* Sxx resreg,CX */
2227:
2228: if (!I16 && sz == 2 && (oper == OProl || oper == OPror))
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2229: c->Iflags |= CFopsize;
2230:
2231: // Note that a shift by CL does not set the flags if
2232: // CL == 0. If e2 is a constant, we know it isn't 0
2233: // (it would have been optimized out).
2234: if (e2isconst)
2235: *pretregs &= mBP | ALLREGS; // flags already set with result
2236: }
2237: else if (sz == 2 * REGSIZE &&
2238: config.target_cpu >= TARGET_80386)
2239: {
2240: unsigned hreg = resreg;
2241: unsigned lreg = sreg;
2242: unsigned rex = I64 ? (REX_W << 16) : 0;
warning C6246: Local declaration of 'rex' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1966' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 1966
2243: if (e2isconst)
2244: {
2245: cr = NULL;
2246: cg = getregs(retregs);
2247: if (shiftcnt & (REGSIZE * 8))
2248: {
2249: if (oper == OPshr)
2250: { // SHR hreg,shiftcnt
2251: // MOV lreg,hreg
2252: // XOR hreg,hreg
2253: c = genc2(NULL,0xC1,rex | modregrm(3,s1,hreg),shiftcnt - (REGSIZE * 8));
2254: c = genmovreg(c,lreg,hreg);
2255: c = movregconst(c,hreg,0,0);
2256: }
2257: else if (oper == OPashr)
2258: { // MOV lreg,hreg
2259: // SAR hreg,31
2260: // SHRD lreg,hreg,shiftcnt
2261: c = genmovreg(NULL,lreg,hreg);
2262: c = genc2(c,0xC1,rex | modregrm(3,s1,hreg),(REGSIZE * 8) - 1);
2263: c = genc2(c,0x0FAC,rex | modregrm(3,hreg,lreg),shiftcnt - (REGSIZE * 8));
2264: }
2265: else
2266: { // SHL lreg,shiftcnt
2267: // MOV hreg,lreg
2268: // XOR lreg,lreg
2269: c = genc2(NULL,0xC1,rex | modregrm(3,s1,lreg),shiftcnt - (REGSIZE * 8));
2270: c = genmovreg(c,hreg,lreg);
2271: c = movregconst(c,lreg,0,0);
2272: }
2273: }
2274: else
2275: {
2276: if (oper == OPshr || oper == OPashr)
2277: { // SHRD lreg,hreg,shiftcnt
2278: // SHR/SAR hreg,shiftcnt
2279: c = genc2(NULL,0x0FAC,rex | modregrm(3,hreg,lreg),shiftcnt);
2280: c = genc2(c,0xC1,rex | modregrm(3,s1,hreg),shiftcnt);
2281: }
2282: else
2283: { // SHLD hreg,lreg,shiftcnt
2284: // SHL lreg,shiftcnt
2285: c = genc2(NULL,0x0FA4,rex | modregrm(3,lreg,hreg),shiftcnt);
2286: c = genc2(c,0xC1,rex | modregrm(3,s1,lreg),shiftcnt);
2287: }
2288: }
2289: freenode(e2);
2290: }
2291: else if (config.target_cpu >= TARGET_80486 && REGSIZE == 2)
2292: {
2293: cr = scodelem(e2,&rretregs,retregs,FALSE); // get rvalue in CX
2294: cg = getregs(retregs); // modify these regs
2295: if (oper == OPshl)
2296: {
2297: /*
2298: SHLD hreg,lreg,CL
2299: SHL lreg,CL
2300: */
2301:
2302: c = gen2(NULL,0x0FA5,modregrm(3,lreg,hreg));
2303: gen2(c,0xD3,modregrm(3,4,lreg));
2304: }
2305: else
2306: {
2307: /*
2308: SHRD lreg,hreg,CL
2309: SAR hreg,CL
2310:
2311: -- or --
2312:
2313: SHRD lreg,hreg,CL
2314: SHR hreg,CL
2315: */
2316: c = gen2(NULL,0x0FAD,modregrm(3,hreg,lreg));
2317: gen2(c,0xD3,modregrm(3,s1,hreg));
2318: }
2319: }
2320: else
2321: { code *cl1,*cl2;
2322:
2323: cr = scodelem(e2,&rretregs,retregs,FALSE); // get rvalue in CX
2324: cg = getregs(retregs | mCX); // modify these regs
2325: // TEST CL,0x20
2326: c = genc2(NULL,0xF6,modregrm(3,0,CX),REGSIZE * 8);
2327: if (oper == OPshl)
2328: {
2329: /* TEST CL,20H
2330: JNE L1
2331: SHLD hreg,lreg,CL
2332: SHL lreg,CL
2333: JMP L2
2334: L1: AND CL,20H-1
2335: SHL lreg,CL
2336: MOV hreg,lreg
2337: XOR lreg,lreg
2338: L2: NOP
2339: */
2340:
2341: cl1 = NULL;
2342: if (REGSIZE == 2)
2343: cl1 = genc2(NULL,0x80,modregrm(3,4,CX),REGSIZE * 8 - 1);
2344: cl1 = gen2(cl1,0xD3,modregrm(3,4,lreg));
2345: genmovreg(cl1,hreg,lreg);
2346: genregs(cl1,0x31,lreg,lreg);
2347:
2348: genjmp(c,JNE,FLcode,(block *)cl1);
2349: gen2(c,0x0FA5,modregrm(3,lreg,hreg));
2350: gen2(c,0xD3,modregrm(3,4,lreg));
2351: }
2352: else
2353: { if (oper == OPashr)
2354: {
2355: /* TEST CL,20H
2356: JNE L1
2357: SHRD lreg,hreg,CL
2358: SAR hreg,CL
2359: JMP L2
2360: L1: AND CL,15
2361: MOV lreg,hreg
2362: SAR hreg,31
2363: SHRD lreg,hreg,CL
2364: L2: NOP
2365: */
2366:
2367: cl1 = NULL;
2368: if (REGSIZE == 2)
2369: cl1 = genc2(NULL,0x80,modregrm(3,4,CX),REGSIZE * 8 - 1);
2370: cl1 = genmovreg(cl1,lreg,hreg);
2371: genc2(cl1,0xC1,modregrm(3,s1,hreg),31);
2372: gen2(cl1,0x0FAD,modregrm(3,hreg,lreg));
2373: }
2374: else
2375: {
2376: /* TEST CL,20H
2377: JNE L1
2378: SHRD lreg,hreg,CL
2379: SHR hreg,CL
2380: JMP L2
2381: L1: AND CL,15
2382: SHR hreg,CL
2383: MOV lreg,hreg
2384: XOR hreg,hreg
2385: L2: NOP
2386: */
2387:
2388: cl1 = NULL;
2389: if (REGSIZE == 2)
2390: cl1 = genc2(NULL,0x80,modregrm(3,4,CX),REGSIZE * 8 - 1);
2391: cl1 = gen2(cl1,0xD3,modregrm(3,5,hreg));
2392: genmovreg(cl1,lreg,hreg);
2393: genregs(cl1,0x31,hreg,hreg);
2394: }
2395: genjmp(c,JNE,FLcode,(block *)cl1);
2396: gen2(c,0x0FAD,modregrm(3,hreg,lreg));
2397: gen2(c,0xD3,modregrm(3,s1,hreg));
2398: }
2399: cl2 = gennop(NULL);
2400: genjmp(c,JMPS,FLcode,(block *)cl2);
2401: c = cat3(c,cl1,cl2);
2402: }
2403: break;
2404: }
2405: else if (sz == 2 * REGSIZE)
2406: {
2407: c = CNIL;
2408: if (!e2isconst) // if not sure shift count != 0
2409: c = genc2(c,0xE3,0,6); // JCXZ .+6
2410: cr = scodelem(e2,&rretregs,retregs,FALSE);
2411: cg = getregs(retregs | mCX);
2412: if (oper == OPshl)
2413: swap((int *) &resreg,(int *) &sreg);
2414: c = gen2(c,0xD1,modregrm(3,s1,resreg));
2415: code_orflag(c,CFtarg2);
2416: gen2(c,0xD1,modregrm(3,s2,sreg));
2417: genc2(c,0xE2,0,(targ_uns)-6); // LOOP .-6
2418: regimmed_set(CX,0); // note that now CX == 0
2419: }
2420: else
2421: assert(0);
2422: break;
2423: }
2424: c = cat(c,fixresult(e,retregs,pretregs));
2425: return cat4(cl,cr,cg,c);
2426: }
2427:
2428:
2429: /***************************
2430: * Perform a 'star' reference (indirection).
2431: */
2432:
2433: code *cdind(elem *e,regm_t *pretregs)
2434: { code *c,*ce,cs;
2435: tym_t tym;
2436: regm_t idxregs,retregs;
2437: unsigned reg,nreg,byte;
warning C4101: 'nreg' : unreferenced local variable
2438: elem *e1;
2439: unsigned sz;
2440:
2441: //printf("cdind(e = %p, *pretregs = %s)\n",e,regm_str(*pretregs));
2442: tym = tybasic(e->Ety);
2443: if (tyfloating(tym))
2444: {
2445: if (config.inline8087)
2446: {
2447: if (*pretregs & mST0)
2448: return cdind87(e, pretregs);
2449: if (tycomplex(tym))
2450: return cload87(e, pretregs);
2451: if (*pretregs & mPSW)
2452: return cdind87(e, pretregs);
2453: }
2454: }
2455:
2456: e1 = e->E1;
2457: assert(e1);
2458: switch (tym)
2459: { case TYstruct:
2460: case TYarray:
2461: // This case should never happen, why is it here?
2462: tym = TYnptr; // don't confuse allocreg()
2463: #if !TARGET_FLAT
2464: if (*pretregs & (mES | mCX) || e->Ety & mTYfar)
2465: tym = TYfptr;
2466: #endif
2467:
2468: #if 0
2469: c = getlvalue(&cs,e,RMload); // get addressing mode
2470: if (*pretregs == 0)
2471: return c;
2472: idxregs = idxregm(&cs); // mask of index regs used
2473: c = cat(c,fixresult(e,idxregs,pretregs));
2474: return c;
2475: #endif
2476: break;
2477: }
2478: sz = tysize[tym];
2479: byte = tybyte(tym) != 0;
2480:
2481: c = getlvalue(&cs,e,RMload); // get addressing mode
2482: //printf("Irex = %02x, Irm = x%02x, Isib = x%02x\n", cs.Irex, cs.Irm, cs.Isib);
2483: /*fprintf(stderr,"cd2 :\n"); WRcodlst(c);*/
2484: if (*pretregs == 0)
2485: return c;
2486:
2487: idxregs = idxregm(&cs); // mask of index regs used
2488:
2489: if (*pretregs == mPSW)
2490: {
2491: if (!I16 && tym == TYfloat)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2492: { retregs = ALLREGS & ~idxregs;
2493: c = cat(c,allocreg(&retregs,®,TYfloat));
2494: cs.Iop = 0x8B;
2495: code_newreg(&cs,reg);
2496: ce = gen(CNIL,&cs); // MOV reg,lsw
2497: gen2(ce,0xD1,modregrmx(3,4,reg)); // SHL reg,1
2498: }
2499: else if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2500: {
2501: cs.Iop = 0x81 ^ byte;
2502: cs.Irm |= modregrm(0,7,0);
2503: cs.IFL2 = FLconst;
2504: cs.IEV2.Vint = 0;
2505: ce = gen(CNIL,&cs); /* CMP [idx],0 */
2506: }
2507: else if (!I16 && sz == REGSIZE + 2) // if far pointer
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
2508: { retregs = ALLREGS & ~idxregs;
2509: c = cat(c,allocreg(&retregs,®,TYint));
2510: cs.Iop = 0x0FB7;
2511: cs.Irm |= modregrm(0,reg,0);
2512: getlvalue_msw(&cs);
2513: ce = gen(CNIL,&cs); /* MOVZX reg,msw */
2514: goto L4;
2515: }
2516: else if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2517: { retregs = ALLREGS & ~idxregs;
2518: c = cat(c,allocreg(&retregs,®,TYint));
2519: cs.Iop = 0x8B;
2520: code_newreg(&cs,reg);
2521: getlvalue_msw(&cs);
2522: ce = gen(CNIL,&cs); /* MOV reg,msw */
2523: if (I32)
2524: { if (tym == TYdouble || tym == TYdouble_alias)
2525: gen2(ce,0xD1,modregrm(3,4,reg)); // SHL reg,1
2526: }
2527: else if (tym == TYfloat)
2528: gen2(ce,0xD1,modregrm(3,4,reg)); /* SHL reg,1 */
2529: L4: cs.Iop = 0x0B;
2530: getlvalue_lsw(&cs);
2531: gen(ce,&cs); /* OR reg,lsw */
2532: }
2533: else if (!I32 && sz == 8)
2534: { *pretregs |= DOUBLEREGS_16; /* fake it for now */
2535: goto L1;
2536: }
2537: else
2538: {
2539: debugx(WRTYxx(tym));
2540: assert(0);
2541: }
2542: c = cat(c,ce);
2543: }
2544: else /* else return result in reg */
2545: {
2546: L1: retregs = *pretregs;
2547: if (sz == 8 &&
2548: (retregs & (mPSW | mSTACK | ALLREGS | mBP)) == mSTACK)
2549: { int i;
2550:
2551: /* Optimizer should not CSE these, as the result is worse code! */
2552: assert(!e->Ecount);
2553:
2554: cs.Iop = 0xFF;
2555: cs.Irm |= modregrm(0,6,0);
2556: cs.IEVoffset1 += 8 - REGSIZE;
2557: stackchanged = 1;
2558: i = 8 - REGSIZE;
2559: do
2560: {
2561: c = gen(c,&cs); /* PUSH EA+i */
2562: c = genadjesp(c,REGSIZE);
2563: cs.IEVoffset1 -= REGSIZE;
2564: stackpush += REGSIZE;
2565: i -= REGSIZE;
2566: }
2567: while (i >= 0);
2568: goto L3;
2569: }
2570: if (I16 && sz == 8)
2571: retregs = DOUBLEREGS_16;
2572:
2573: /* Watch out for loading an lptr from an lptr! We must have */
2574: /* the offset loaded into a different register. */
2575: /*if (retregs & mES && (cs.Iflags & CFSEG) == CFes)
2576: retregs = ALLREGS;*/
2577:
2578: {
2579: assert(!byte || retregs & BYTEREGS);
2580: c = cat(c,allocreg(&retregs,®,tym)); /* alloc registers */
2581: }
2582: if (retregs & XMMREGS)
2583: {
2584: assert(sz == 4 || sz == 8); // float or double
2585: cs.Iop = (sz == 4) ? 0xF30F10 : 0xF20F10;
2586: reg -= XMM0;
2587: goto L2;
2588: }
2589: else if (sz <= REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2590: {
2591: cs.Iop = 0x8B ^ byte;
2592: L2: code_newreg(&cs,reg);
2593: ce = gen(CNIL,&cs); /* MOV reg,[idx] */
2594: if (byte && reg >= 4)
2595: code_orrex(ce, REX);
2596: }
2597: else if ((tym == TYfptr || tym == TYhptr) && retregs & mES)
2598: {
2599: cs.Iop = 0xC4; /* LES reg,[idx] */
2600: goto L2;
2601: }
2602: else if (sz <= 2 * REGSIZE)
warning C4018: '<=' : signed/unsigned mismatch
2603: { unsigned lsreg;
2604:
2605: cs.Iop = 0x8B;
2606: /* Be careful not to interfere with index registers */
2607: if (!I16)
2608: {
2609: /* Can't handle if both result registers are used in */
2610: /* the addressing mode. */
2611: if ((retregs & idxregs) == retregs)
2612: {
2613: retregs = mMSW & allregs & ~idxregs;
2614: if (!retregs)
2615: retregs |= mCX;
2616: retregs |= mLSW & ~idxregs;
2617:
2618: // We can run out of registers, so if that's possible,
2619: // give us *one* of the idxregs
2620: if ((retregs & ~regcon.mvar & mLSW) == 0)
2621: {
2622: regm_t x = idxregs & mLSW;
2623: if (x)
2624: retregs |= mask[findreg(x)]; // give us one idxreg
2625: }
2626: else if ((retregs & ~regcon.mvar & mMSW) == 0)
2627: {
2628: regm_t x = idxregs & mMSW;
2629: if (x)
2630: retregs |= mask[findreg(x)]; // give us one idxreg
2631: }
2632:
2633: c = cat(c,allocreg(&retregs,®,tym)); /* alloc registers */
2634: assert((retregs & idxregs) != retregs);
2635: }
2636:
2637: lsreg = findreglsw(retregs);
2638: if (mask[reg] & idxregs) /* reg is in addr mode */
2639: {
2640: code_newreg(&cs,lsreg);
2641: ce = gen(CNIL,&cs); /* MOV lsreg,lsw */
2642: if (sz == REGSIZE + 2)
2643: cs.Iflags |= CFopsize;
2644: lsreg = reg;
2645: getlvalue_msw(&cs); // MOV reg,msw
2646: }
2647: else
2648: {
2649: code_newreg(&cs,reg);
2650: getlvalue_msw(&cs);
2651: ce = gen(CNIL,&cs); // MOV reg,msw
2652: if (sz == REGSIZE + 2)
2653: ce->Iflags |= CFopsize;
2654: getlvalue_lsw(&cs); // MOV lsreg,lsw
2655: }
2656: NEWREG(cs.Irm,lsreg);
2657: gen(ce,&cs);
2658: }
2659: else
2660: {
2661: /* Index registers are always the lsw! */
2662: cs.Irm |= modregrm(0,reg,0);
2663: getlvalue_msw(&cs);
2664: ce = gen(CNIL,&cs); /* MOV reg,msw */
2665: lsreg = findreglsw(retregs);
2666: NEWREG(cs.Irm,lsreg);
2667: getlvalue_lsw(&cs); /* MOV lsreg,lsw */
2668: gen(ce,&cs);
2669: }
2670: }
2671: else if (I16 && sz == 8)
2672: {
2673: assert(reg == AX);
2674: cs.Iop = 0x8B;
2675: cs.IEVoffset1 += 6;
2676: ce = gen(CNIL,&cs); /* MOV AX,EA+6 */
2677: cs.Irm |= modregrm(0,CX,0);
2678: cs.IEVoffset1 -= 4;
2679: gen(ce,&cs); /* MOV CX,EA+2 */
2680: NEWREG(cs.Irm,DX);
2681: cs.IEVoffset1 -= 2;
2682: gen(ce,&cs); /* MOV DX,EA */
2683: cs.IEVoffset1 += 4;
2684: NEWREG(cs.Irm,BX);
2685: gen(ce,&cs); /* MOV BX,EA+4 */
2686: }
2687: else
2688: assert(0);
2689: c = cat(c,ce);
2690: L3:
2691: c = cat(c,fixresult(e,retregs,pretregs));
2692: }
2693: /*fprintf(stderr,"cdafter :\n"); WRcodlst(c);*/
2694: return c;
2695: }
2696:
2697:
2698:
2699: #if TARGET_FLAT
2700: #define cod2_setES(ty) NULL
2701: #else
2702: /********************************
2703: * Generate code to load ES with the right segment value,
2704: * do nothing if e is a far pointer.
2705: */
2706:
2707: STATIC code *cod2_setES(tym_t ty)
2708: { code *c2;
2709: int push;
2710:
2711: c2 = CNIL;
2712: switch (tybasic(ty))
2713: {
2714: case TYnptr:
2715: if (!(config.flags3 & CFG3eseqds))
2716: { push = 0x1E; /* PUSH DS */
2717: goto L1;
2718: }
2719: break;
2720: case TYcptr:
2721: push = 0x0E; /* PUSH CS */
2722: goto L1;
2723: case TYsptr:
2724: if ((config.wflags & WFssneds) || !(config.flags3 & CFG3eseqds))
2725: { push = 0x16; /* PUSH SS */
2726: L1:
2727: /* Must load ES */
2728: c2 = getregs(mES);
2729: c2 = gen1(c2,push);
2730: gen1(c2,0x07); /* POP ES */
2731: }
2732: break;
2733: }
2734: return c2;
2735: }
2736: #endif
2737:
2738: /********************************
2739: * Generate code for intrinsic strlen().
2740: */
2741:
2742: code *cdstrlen( elem *e, regm_t *pretregs)
2743: { code *c1,*c2,*c3,*c4;
2744:
2745: /* Generate strlen in CX:
2746: LES DI,e1
2747: CLR AX ;scan for 0
2748: MOV CX,-1 ;largest possible string
2749: REPNE SCASB
2750: NOT CX
2751: DEC CX
2752: */
2753:
2754: regm_t retregs = mDI;
2755: tym_t ty1 = e->E1->Ety;
2756: if (!tyreg(ty1))
2757: retregs |= mES;
2758: c1 = codelem(e->E1,&retregs,FALSE);
2759:
2760: /* Make sure ES contains proper segment value */
2761: c2 = cod2_setES(ty1);
2762:
2763: unsigned char rex = I64 ? REX_W : 0;
2764:
2765: c3 = getregs_imm(mAX | mCX);
2766: c3 = movregconst(c3,AX,0,1); /* MOV AL,0 */
2767: c3 = movregconst(c3,CX,-1LL,I64 ? 64 : 0); // MOV CX,-1
2768: c3 = cat(c3,getregs(mDI|mCX));
2769: c3 = gen1(c3,0xF2); /* REPNE */
2770: gen1(c3,0xAE); /* SCASB */
2771: genregs(c3,0xF7,2,CX); /* NOT CX */
2772: code_orrex(c3,rex);
2773: if (I64)
2774: c4 = gen2(CNIL,0xFF,(rex << 16) | modregrm(3,1,CX)); // DEC reg
2775: else
2776: c4 = gen1(CNIL,0x48 + CX); // DEC CX
2777:
2778: if (*pretregs & mPSW)
2779: {
2780: c4->Iflags |= CFpsw;
2781: *pretregs &= ~mPSW;
2782: }
2783: return cat6(c1,c2,c3,c4,fixresult(e,mCX,pretregs),CNIL);
2784: }
2785:
2786:
2787: /*********************************
2788: * Generate code for strcmp(s1,s2) intrinsic.
2789: */
2790:
2791: code *cdstrcmp( elem *e, regm_t *pretregs)
2792: { code *c1,*c1a,*c2,*c3,*c4;
warning C4101: 'c1a' : unreferenced local variable
2793: char need_DS;
2794: int segreg;
2795:
2796: /*
2797: MOV SI,s1 ;get destination pointer (s1)
2798: MOV CX,s1+2
2799: LES DI,s2 ;get source pointer (s2)
2800: PUSH DS
2801: MOV DS,CX
2802: CLR AX ;scan for 0
2803: MOV CX,-1 ;largest possible string
2804: REPNE SCASB
2805: NOT CX ;CX = string length of s2
2806: SUB DI,CX ;point DI back to beginning
2807: REPE CMPSB ;compare string
2808: POP DS
2809: JE L1 ;strings are equal
2810: SBB AX,AX
2811: SBB AX,-1
2812: L1:
2813: */
2814:
2815: regm_t retregs1 = mSI;
2816: tym_t ty1 = e->E1->Ety;
2817: if (!tyreg(ty1))
2818: retregs1 |= mCX;
2819: c1 = codelem(e->E1,&retregs1,FALSE);
2820:
2821: regm_t retregs = mDI;
2822: tym_t ty2 = e->E2->Ety;
2823: if (!tyreg(ty2))
2824: retregs |= mES;
2825: c1 = cat(c1,scodelem(e->E2,&retregs,retregs1,FALSE));
2826:
2827: /* Make sure ES contains proper segment value */
2828: c2 = cod2_setES(ty2);
2829: c3 = getregs_imm(mAX | mCX);
2830:
2831: unsigned char rex = I64 ? REX_W : 0;
2832:
2833: /* Load DS with right value */
2834: switch (tybasic(ty1))
2835: {
2836: case TYnptr:
2837: need_DS = FALSE;
2838: break;
2839: case TYsptr:
2840: if (config.wflags & WFssneds) /* if sptr can't use DS segment */
2841: segreg = SEG_SS;
2842: else
2843: segreg = SEG_DS;
2844: goto L1;
2845: case TYcptr:
2846: segreg = SEG_CS;
2847: L1:
2848: c3 = gen1(c3,0x1E); /* PUSH DS */
2849: gen1(c3,0x06 + (segreg << 3)); /* PUSH segreg */
2850: gen1(c3,0x1F); /* POP DS */
2851: need_DS = TRUE;
2852: break;
2853: case TYfptr:
2854: case TYvptr:
2855: case TYhptr:
2856: c3 = gen1(c3,0x1E); /* PUSH DS */
2857: gen2(c3,0x8E,modregrm(3,SEG_DS,CX)); /* MOV DS,CX */
2858: need_DS = TRUE;
2859: break;
2860: default:
2861: assert(0);
2862: }
2863:
2864: c3 = movregconst(c3,AX,0,0); /* MOV AX,0 */
2865: c3 = movregconst(c3,CX,-1LL,I64 ? 64 : 0); // MOV CX,-1
2866: c3 = cat(c3,getregs(mSI|mDI|mCX));
2867: c3 = gen1(c3,0xF2); /* REPNE */
2868: gen1(c3,0xAE); /* SCASB */
2869: genregs(c3,0xF7,2,CX); /* NOT CX */
2870: code_orrex(c3,rex);
2871: genregs(c3,0x2B,DI,CX); /* SUB DI,CX */
2872: code_orrex(c3,rex);
2873: gen1(c3,0xF3); /* REPE */
2874: gen1(c3,0xA6); /* CMPSB */
2875: if (need_DS)
2876: gen1(c3,0x1F); /* POP DS */
2877: c4 = gennop(CNIL);
2878: if (*pretregs != mPSW) /* if not flags only */
2879: {
2880: genjmp(c3,JE,FLcode,(block *) c4); /* JE L1 */
2881: c3 = cat(c3,getregs(mAX));
2882: genregs(c3,0x1B,AX,AX); /* SBB AX,AX */
2883: code_orrex(c3,rex);
2884: genc2(c3,0x81,(rex << 16) | modregrm(3,3,AX),(targ_uns)-1); // SBB AX,-1
2885: }
2886:
2887: *pretregs &= ~mPSW;
2888: return cat6(c1,c2,c3,c4,fixresult(e,mAX,pretregs),CNIL);
2889: }
2890:
2891: /*********************************
2892: * Generate code for memcmp(s1,s2,n) intrinsic.
2893: */
2894:
2895: code *cdmemcmp(elem *e,regm_t *pretregs)
2896: { code *c1,*c2,*c3,*c4;
2897: char need_DS;
2898: int segreg;
2899:
2900: /*
2901: MOV SI,s1 ;get destination pointer (s1)
2902: MOV DX,s1+2
2903: LES DI,s2 ;get source pointer (s2)
2904: MOV CX,n ;get number of bytes to compare
2905: PUSH DS
2906: MOV DS,DX
2907: XOR AX,AX
2908: REPE CMPSB ;compare string
2909: POP DS
2910: JE L1 ;strings are equal
2911: SBB AX,AX
2912: SBB AX,-1
2913: L1:
2914: */
2915:
2916: elem *e1 = e->E1;
2917: assert(e1->Eoper == OPparam);
2918:
2919: // Get s1 into DX:SI
2920: regm_t retregs1 = mSI;
2921: tym_t ty1 = e1->E1->Ety;
2922: if (!tyreg(ty1))
2923: retregs1 |= mDX;
2924: c1 = codelem(e1->E1,&retregs1,FALSE);
2925:
2926: // Get s2 into ES:DI
2927: regm_t retregs = mDI;
2928: tym_t ty2 = e1->E2->Ety;
2929: if (!tyreg(ty2))
2930: retregs |= mES;
2931: c1 = cat(c1,scodelem(e1->E2,&retregs,retregs1,FALSE));
2932: freenode(e1);
2933:
2934: // Get nbytes into CX
2935: regm_t retregs3 = mCX;
2936: c1 = cat(c1,scodelem(e->E2,&retregs3,retregs | retregs1,FALSE));
2937:
2938: /* Make sure ES contains proper segment value */
2939: c2 = cod2_setES(ty2);
2940:
2941: /* Load DS with right value */
2942: c3 = NULL;
2943: switch (tybasic(ty1))
2944: {
2945: case TYnptr:
2946: need_DS = FALSE;
2947: break;
2948: case TYsptr:
2949: if (config.wflags & WFssneds) /* if sptr can't use DS segment */
2950: segreg = SEG_SS;
2951: else
2952: segreg = SEG_DS;
2953: goto L1;
2954: case TYcptr:
2955: segreg = SEG_CS;
2956: L1:
2957: c3 = gen1(c3,0x1E); /* PUSH DS */
2958: gen1(c3,0x06 + (segreg << 3)); /* PUSH segreg */
2959: gen1(c3,0x1F); /* POP DS */
2960: need_DS = TRUE;
2961: break;
2962: case TYfptr:
2963: case TYvptr:
2964: case TYhptr:
2965: c3 = gen1(c3,0x1E); /* PUSH DS */
2966: gen2(c3,0x8E,modregrm(3,SEG_DS,DX)); /* MOV DS,DX */
2967: need_DS = TRUE;
2968: break;
2969: default:
2970: assert(0);
2971: }
2972:
2973: #if 1
2974: c3 = cat(c3,getregs(mAX));
2975: c3 = gen2(c3,0x33,modregrm(3,AX,AX)); // XOR AX,AX
2976: #else
2977: if (*pretregs != mPSW) // if not flags only
2978: c3 = regwithvalue(c3,mAX,0,NULL,0); // put 0 in AX
2979: #endif
2980:
2981: c3 = cat(c3,getregs(mCX | mSI | mDI));
2982: c3 = gen1(c3,0xF3); /* REPE */
2983: gen1(c3,0xA6); /* CMPSB */
2984: if (need_DS)
2985: gen1(c3,0x1F); /* POP DS */
2986: if (*pretregs != mPSW) /* if not flags only */
2987: {
2988: c4 = gennop(CNIL);
2989: genjmp(c3,JE,FLcode,(block *) c4); /* JE L1 */
2990: c3 = cat(c3,getregs(mAX));
2991: genregs(c3,0x1B,AX,AX); /* SBB AX,AX */
2992: genc2(c3,0x81,modregrm(3,3,AX),(targ_uns)-1); /* SBB AX,-1 */
2993: c3 = cat(c3,c4);
2994: }
2995:
2996: *pretregs &= ~mPSW;
2997: return cat4(c1,c2,c3,fixresult(e,mAX,pretregs));
2998: }
2999:
3000: /*********************************
3001: * Generate code for strcpy(s1,s2) intrinsic.
3002: */
3003:
3004: code *cdstrcpy(elem *e,regm_t *pretregs)
3005: { code *c1,*c2,*c3,*c4;
3006: regm_t retregs;
3007: tym_t ty1,ty2;
3008: char need_DS;
3009: int segreg;
3010:
3011: /*
3012: LES DI,s2 ;ES:DI = s2
3013: CLR AX ;scan for 0
3014: MOV CX,-1 ;largest possible string
3015: REPNE SCASB ;find end of s2
3016: NOT CX ;CX = strlen(s2) + 1 (for EOS)
3017: SUB DI,CX
3018: MOV SI,DI
3019: PUSH DS
3020: PUSH ES
3021: LES DI,s1
3022: POP DS
3023: MOV AX,DI ;return value is s1
3024: REP MOVSB
3025: POP DS
3026: */
3027:
3028: stackchanged = 1;
3029: retregs = mDI;
3030: ty2 = tybasic(e->E2->Ety);
3031: if (!tyreg(ty2))
3032: retregs |= mES;
3033: unsigned char rex = I64 ? REX_W : 0;
3034: c1 = codelem(e->E2,&retregs,FALSE);
3035:
3036: /* Make sure ES contains proper segment value */
3037: c2 = cod2_setES(ty2);
3038: c3 = getregs_imm(mAX | mCX);
3039: c3 = movregconst(c3,AX,0,1); /* MOV AL,0 */
3040: c3 = movregconst(c3,CX,-1,I64?64:0); // MOV CX,-1
3041: c3 = cat(c3,getregs(mAX|mCX|mSI|mDI));
3042: c3 = gen1(c3,0xF2); /* REPNE */
3043: gen1(c3,0xAE); /* SCASB */
3044: genregs(c3,0xF7,2,CX); /* NOT CX */
3045: code_orrex(c3,rex);
3046: genregs(c3,0x2B,DI,CX); /* SUB DI,CX */
3047: code_orrex(c3,rex);
3048: genmovreg(c3,SI,DI); /* MOV SI,DI */
3049: code_orrex(c3,rex);
3050:
3051: /* Load DS with right value */
3052: switch (ty2)
3053: {
3054: case TYnptr:
3055: need_DS = FALSE;
3056: break;
3057: case TYsptr:
3058: if (config.wflags & WFssneds) /* if sptr can't use DS segment */
3059: segreg = SEG_SS;
3060: else
3061: segreg = SEG_DS;
3062: goto L1;
3063: case TYcptr:
3064: segreg = SEG_CS;
3065: L1:
3066: c3 = gen1(c3,0x1E); /* PUSH DS */
3067: gen1(c3,0x06 + (segreg << 3)); /* PUSH segreg */
3068: genadjesp(c3,REGSIZE * 2);
3069: need_DS = TRUE;
3070: break;
3071: case TYfptr:
3072: case TYvptr:
3073: case TYhptr:
3074: segreg = SEG_ES;
3075: goto L1;
3076: break;
3077: default:
3078: assert(0);
3079: }
3080:
3081: retregs = mDI;
3082: ty1 = tybasic(e->E1->Ety);
3083: if (!tyreg(ty1))
3084: retregs |= mES;
3085: c3 = cat(c3,scodelem(e->E1,&retregs,mCX|mSI,FALSE));
3086: c3 = cat(c3,getregs(mAX|mCX|mSI|mDI));
3087:
3088: /* Make sure ES contains proper segment value */
3089: if (ty2 != TYnptr || ty1 != ty2)
3090: c4 = cod2_setES(ty1);
3091: else
3092: c4 = CNIL; /* ES is already same as DS */
3093:
3094: if (need_DS)
3095: c4 = gen1(c4,0x1F); /* POP DS */
3096: if (*pretregs)
3097: { c4 = genmovreg(c4,AX,DI); /* MOV AX,DI */
3098: code_orrex(c4,rex);
3099: }
3100: c4 = gen1(c4,0xF3); /* REP */
3101: gen1(c4,0xA4); /* MOVSB */
3102:
3103: if (need_DS)
3104: { gen1(c4,0x1F); /* POP DS */
3105: genadjesp(c4,-(REGSIZE * 2));
3106: }
3107: return cat6(c1,c2,c3,c4,fixresult(e,mAX | mES,pretregs),CNIL);
3108: }
3109:
3110: /*********************************
3111: * Generate code for memcpy(s1,s2,n) intrinsic.
3112: * OPmemcpy
3113: * / \
3114: * s1 OPparam
3115: * / \
3116: * s2 n
3117: */
3118:
3119: code *cdmemcpy(elem *e,regm_t *pretregs)
3120: { code *c1,*c2,*c3,*c4;
warning C4101: 'c4' : unreferenced local variable
3121: regm_t retregs1;
3122: regm_t retregs2;
3123: regm_t retregs3;
3124: tym_t ty1,ty2;
3125: char need_DS;
3126: int segreg;
3127: elem *e2;
3128:
3129: /*
3130: MOV SI,s2
3131: MOV DX,s2+2
3132: MOV CX,n
3133: LES DI,s1
3134: PUSH DS
3135: MOV DS,DX
3136: MOV AX,DI ;return value is s1
3137: REP MOVSB
3138: POP DS
3139: */
3140:
3141: e2 = e->E2;
3142: assert(e2->Eoper == OPparam);
3143:
3144: // Get s2 into DX:SI
3145: retregs2 = mSI;
3146: ty2 = e2->E1->Ety;
3147: if (!tyreg(ty2))
3148: retregs2 |= mDX;
3149: c1 = codelem(e2->E1,&retregs2,FALSE);
3150:
3151: // Get nbytes into CX
3152: retregs3 = mCX;
3153: c1 = cat(c1,scodelem(e2->E2,&retregs3,retregs2,FALSE));
3154: freenode(e2);
3155:
3156: // Get s1 into ES:DI
3157: retregs1 = mDI;
3158: ty1 = e->E1->Ety;
3159: if (!tyreg(ty1))
3160: retregs1 |= mES;
3161: c1 = cat(c1,scodelem(e->E1,&retregs1,retregs2 | retregs3,FALSE));
3162:
3163: unsigned char rex = I64 ? REX_W : 0;
3164:
3165: /* Make sure ES contains proper segment value */
3166: c2 = cod2_setES(ty1);
3167:
3168: /* Load DS with right value */
3169: c3 = NULL;
3170: switch (tybasic(ty2))
3171: {
3172: case TYnptr:
3173: need_DS = FALSE;
3174: break;
3175: case TYsptr:
3176: if (config.wflags & WFssneds) /* if sptr can't use DS segment */
3177: segreg = SEG_SS;
3178: else
3179: segreg = SEG_DS;
3180: goto L1;
3181: case TYcptr:
3182: segreg = SEG_CS;
3183: L1:
3184: c3 = gen1(c3,0x1E); /* PUSH DS */
3185: gen1(c3,0x06 + (segreg << 3)); /* PUSH segreg */
3186: gen1(c3,0x1F); /* POP DS */
3187: need_DS = TRUE;
3188: break;
3189: case TYfptr:
3190: case TYvptr:
3191: case TYhptr:
3192: c3 = gen1(c3,0x1E); /* PUSH DS */
3193: gen2(c3,0x8E,modregrm(3,SEG_DS,DX)); /* MOV DS,DX */
3194: need_DS = TRUE;
3195: break;
3196: default:
3197: assert(0);
3198: }
3199:
3200: if (*pretregs) // if need return value
3201: { c3 = cat(c3,getregs(mAX));
3202: c3 = genmovreg(c3,AX,DI);
3203: code_orrex(c3, rex);
3204: }
3205:
3206: if (0 && I32 && config.flags4 & CFG4speed)
3207: {
3208: /* This is only faster if the memory is dword aligned, if not
3209: * it is significantly slower than just a rep movsb.
3210: */
3211: /* mov EDX,ECX
3212: * shr ECX,2
3213: * jz L1
3214: * repe movsd
3215: * L1: and EDX,3
3216: * jz L2
3217: * mov ECX,EDX
3218: * repe movsb
3219: * L2: nop
3220: */
3221: c3 = cat(c3,getregs(mSI | mDI | mCX | mDX));
3222: c3 = genmovreg(c3,DX,CX); // MOV EDX,ECX
3223: c3 = genc2(c3,0xC1,modregrm(3,5,CX),2); // SHR ECX,2
3224: code *cx = genc2(CNIL, 0x81, modregrm(3,4,DX),3); // AND EDX,3
3225: genjmp(c3, JE, FLcode, (block *)cx); // JZ L1
3226: gen1(c3,0xF3); // REPE
3227: gen1(c3,0xA5); // MOVSW
3228: c3 = cat(c3,cx);
3229:
3230: code *cnop = gennop(CNIL);
3231: genjmp(c3, JE, FLcode, (block *)cnop); // JZ L2
3232: genmovreg(c3,CX,DX); // MOV ECX,EDX
3233: gen1(c3,0xF3); // REPE
3234: gen1(c3,0xA4); // MOVSB
3235: c3 = cat(c3, cnop);
3236: }
3237: else
3238: {
3239: c3 = cat(c3,getregs(mSI | mDI | mCX));
3240: if (!I32 && config.flags4 & CFG4speed) // if speed optimization
3241: { c3 = gen2(c3,0xD1,(rex << 16) | modregrm(3,5,CX)); // SHR CX,1
3242: gen1(c3,0xF3); // REPE
3243: gen1(c3,0xA5); // MOVSW
3244: gen2(c3,0x11,(rex << 16) | modregrm(3,CX,CX)); // ADC CX,CX
3245: }
3246: c3 = gen1(c3,0xF3); // REPE
3247: gen1(c3,0xA4); // MOVSB
3248: if (need_DS)
3249: gen1(c3,0x1F); // POP DS
3250: }
3251: return cat4(c1,c2,c3,fixresult(e,mES|mAX,pretregs));
3252: }
3253:
3254:
3255: /*********************************
3256: * Generate code for memset(s,val,n) intrinsic.
3257: * (s OPmemset (n OPparam val))
3258: */
3259:
3260: #if 1
3261: code *cdmemset(elem *e,regm_t *pretregs)
3262: { code *c1,*c2,*c3 = NULL,*c4;
warning C4101: 'c4' : unreferenced local variable
3263: regm_t retregs1;
3264: regm_t retregs2;
3265: regm_t retregs3;
3266: unsigned reg,vreg;
3267: tym_t ty1;
3268: int segreg;
warning C4101: 'segreg' : unreferenced local variable
3269: unsigned remainder;
3270: targ_uns numbytes,numwords;
3271: int op;
3272: targ_size_t value;
3273: unsigned m;
3274:
3275: //printf("cdmemset(*pretregs = %s)\n", regm_str(*pretregs));
3276: elem *e2 = e->E2;
3277: assert(e2->Eoper == OPparam);
3278:
3279: unsigned char rex = I64 ? REX_W : 0;
3280:
3281: if (e2->E2->Eoper == OPconst)
3282: {
3283: value = el_tolong(e2->E2);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_size_t', possible loss of data
3284: value &= 0xFF;
3285: value |= value << 8;
3286: value |= value << 16;
3287: value |= value << 32;
warning C4293: '<<' : shift count negative or too big, undefined behavior
3288: }
3289: else
3290: value = 0xDEADBEEF; // stop annoying false positives that value is not inited
3291:
3292: if (e2->E1->Eoper == OPconst)
3293: {
3294: numbytes = el_tolong(e2->E1);
warning C4244: '=' : conversion from 'targ_llong' to 'targ_uns', possible loss of data
3295: if (numbytes <= REP_THRESHOLD &&
warning C4018: '<=' : signed/unsigned mismatch
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3296: !I16 && // doesn't work for 16 bits
3297: e2->E2->Eoper == OPconst)
3298: {
3299: targ_uns offset = 0;
3300: retregs1 = *pretregs;
3301: if (!retregs1)
3302: retregs1 = ALLREGS;
3303: c1 = codelem(e->E1,&retregs1,FALSE);
3304: reg = findreg(retregs1);
3305: if (e2->E2->Eoper == OPconst)
3306: {
3307: unsigned m = buildModregrm(0,0,reg);
warning C6246: Local declaration of 'm' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '3273' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 3273
3308: switch (numbytes)
3309: {
3310: case 4: // MOV [reg],imm32
3311: c3 = genc2(CNIL,0xC7,m,value);
3312: goto fixres;
3313: case 2: // MOV [reg],imm16
3314: c3 = genc2(CNIL,0xC7,m,value);
3315: c3->Iflags = CFopsize;
3316: goto fixres;
3317: case 1: // MOV [reg],imm8
3318: c3 = genc2(CNIL,0xC6,m,value);
3319: goto fixres;
3320: }
3321: }
3322:
3323: c1 = regwithvalue(c1, BYTEREGS & ~retregs1, value, &vreg, I64 ? 64 : 0);
3324: freenode(e2->E2);
3325: freenode(e2);
3326:
3327: m = (rex << 16) | buildModregrm(2,vreg,reg);
3328: while (numbytes >= REGSIZE)
warning C4018: '>=' : signed/unsigned mismatch
3329: { // MOV dword ptr offset[reg],vreg
3330: c2 = gen2(CNIL,0x89,m);
3331: c2->IEVoffset1 = offset;
3332: c2->IFL1 = FLconst;
3333: numbytes -= REGSIZE;
3334: offset += REGSIZE;
3335: c3 = cat(c3,c2);
3336: }
3337: m &= ~(rex << 16);
3338: if (numbytes & 4)
3339: { // MOV dword ptr offset[reg],vreg
3340: c2 = gen2(CNIL,0x89,m);
3341: c2->IEVoffset1 = offset;
3342: c2->IFL1 = FLconst;
3343: offset += 4;
3344: c3 = cat(c3,c2);
3345: }
3346: if (numbytes & 2)
3347: { // MOV word ptr offset[reg],vreg
3348: c2 = gen2(CNIL,0x89,m);
3349: c2->IEVoffset1 = offset;
3350: c2->IFL1 = FLconst;
3351: c2->Iflags = CFopsize;
3352: offset += 2;
3353: c3 = cat(c3,c2);
3354: }
3355: if (numbytes & 1)
3356: { // MOV byte ptr offset[reg],vreg
3357: c2 = gen2(CNIL,0x88,m);
3358: c2->IEVoffset1 = offset;
3359: c2->IFL1 = FLconst;
3360: if (I64 && vreg >= 4)
3361: c2->Irex |= REX;
3362: c3 = cat(c3,c2);
3363: }
3364: fixres:
3365: return cat3(c1,c3,fixresult(e,retregs1,pretregs));
3366: }
3367: }
3368:
3369: // Get nbytes into CX
3370: retregs2 = mCX;
3371: if (!I16 && e2->E1->Eoper == OPconst && e2->E2->Eoper == OPconst)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3372: {
3373: remainder = numbytes & (4 - 1);
3374: numwords = numbytes / 4; // number of words
3375: op = 0xAB; // moving by words
3376: c1 = getregs(mCX);
3377: c1 = movregconst(c1,CX,numwords,I64?64:0); // # of bytes/words
3378: }
3379: else
3380: {
3381: remainder = 0;
3382: op = 0xAA; // must move by bytes
3383: c1 = codelem(e2->E1,&retregs2,FALSE);
3384: }
3385:
3386: // Get val into AX
3387:
3388: retregs3 = mAX;
3389: if (!I16 && e2->E2->Eoper == OPconst)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
3390: {
3391: c1 = regwithvalue(c1, mAX, value, NULL, I64?64:0);
3392: freenode(e2->E2);
3393: }
3394: else
3395: {
3396: c1 = cat(c1,scodelem(e2->E2,&retregs3,retregs2,FALSE));
3397: #if 0
3398: if (I32)
3399: {
3400: c1 = gen2(c1,0x8A,modregrm(3,AH,AL)); // MOV AH,AL
3401: c1 = genc2(c1,0xC1,modregrm(3,4,AX),8); // SHL EAX,8
3402: c1 = gen2(c1,0x8A,modregrm(3,AL,AH)); // MOV AL,AH
3403: c1 = genc2(c1,0xC1,modregrm(3,4,AX),8); // SHL EAX,8
3404: c1 = gen2(c1,0x8A,modregrm(3,AL,AH)); // MOV AL,AH
3405: }
3406: #endif
3407: }
3408: freenode(e2);
3409:
3410: // Get s into ES:DI
3411: retregs1 = mDI;
3412: ty1 = e->E1->Ety;
3413: if (!tyreg(ty1))
3414: retregs1 |= mES;
3415: c1 = cat(c1,scodelem(e->E1,&retregs1,retregs2 | retregs3,FALSE));
3416: reg = DI; //findreg(retregs1);
3417:
3418: // Make sure ES contains proper segment value
3419: c2 = cod2_setES(ty1);
3420:
3421: c3 = NULL;
3422: if (*pretregs) // if need return value
3423: { c3 = getregs(mBX);
3424: c3 = genmovreg(c3,BX,DI);
3425: code_orrex(c3,rex);
3426: }
3427:
3428: c3 = cat(c3,getregs(mDI | mCX));
3429: if (I16 && config.flags4 & CFG4speed) // if speed optimization
3430: {
3431: c3 = cat(c3,getregs(mAX));
3432: c3 = gen2(c3,0x8A,modregrm(3,AH,AL)); // MOV AH,AL
3433: gen2(c3,0xD1,modregrm(3,5,CX)); // SHR CX,1
3434: gen1(c3,0xF3); // REP
3435: gen1(c3,0xAB); // STOSW
3436: gen2(c3,0x11,modregrm(3,CX,CX)); // ADC CX,CX
3437: op = 0xAA;
3438: }
3439:
3440: c3 = gen1(c3,0xF3); // REP
3441: gen1(c3,op); // STOSD
3442: m = buildModregrm(2,AX,reg);
3443: if (remainder & 4)
3444: {
3445: code *ctmp;
3446: ctmp = gen2(CNIL,0x89,m);
3447: ctmp->IFL1 = FLconst;
3448: c3 = cat(c3,ctmp);
3449: }
3450: if (remainder & 2)
3451: {
3452: code *ctmp;
3453: ctmp = gen2(CNIL,0x89,m);
3454: ctmp->Iflags = CFopsize;
3455: ctmp->IEVoffset1 = remainder & 4;
3456: ctmp->IFL1 = FLconst;
3457: c3 = cat(c3,ctmp);
3458: }
3459: if (remainder & 1)
3460: {
3461: code *ctmp;
3462: ctmp = gen2(CNIL,0x88,m);
3463: ctmp->IEVoffset1 = remainder & ~1;
3464: ctmp->IFL1 = FLconst;
3465: c3 = cat(c3,ctmp);
3466: }
3467: regimmed_set(CX,0);
3468: return cat4(c1,c2,c3,fixresult(e,mES|mBX,pretregs));
3469: }
3470: #else
3471: // BUG: Pat made many improvements in the linux version, I need
3472: // to verify they work for 16 bits and fold them in. -Walter
3473:
3474: code *cdmemset(elem *e,regm_t *pretregs)
3475: { code *c1,*c2,*c3 = NULL,*c4;
3476: regm_t retregs1;
3477: regm_t retregs2;
3478: regm_t retregs3;
3479: tym_t ty1;
3480: elem *e2;
3481: targ_size_t value;
3482:
3483: /*
3484: les DI,s
3485: mov BX,DI ;Return value.
3486: mov CX,n
3487: mov AL,val
3488: mov AH,AL ;Set up a 16 bit pattern.
3489: shr CX,1
3490: rep stosw
3491: adc CX,CX
3492: rep stosb
3493: */
3494:
3495: e2 = e->E2;
3496: assert(e2->Eoper == OPparam);
3497:
3498: // Get nbytes into CX
3499: retregs2 = mCX;
3500: c1 = codelem(e2->E1,&retregs2,FALSE);
3501:
3502: // Get val into AX
3503: retregs3 = mAX;
3504: c1 = cat(c1,scodelem(e2->E2,&retregs3,retregs2,FALSE));
3505: freenode(e2);
3506:
3507: // Get s into ES:DI
3508: retregs1 = mDI;
3509: ty1 = e->E1->Ety;
3510: if (!tyreg(ty1))
3511: retregs1 |= mES;
3512: c1 = cat(c1,scodelem(e->E1,&retregs1,retregs2 | retregs3,FALSE));
3513:
3514: /* Make sure ES contains proper segment value */
3515: c2 = cod2_setES(ty1);
3516:
3517: c3 = NULL;
3518: if (*pretregs) // if need return value
3519: { c3 = getregs(mBX);
3520: c3 = genmovreg(c3,BX,DI);
3521: }
3522:
3523: c3 = cat(c3,getregs(mDI | mCX));
3524: if (!I32 && config.flags4 & CFG4speed) // if speed optimization
3525: {
3526: c3 = cat(c3,getregs(mAX));
3527: c3 = gen2(c3,0x8A,modregrm(3,AH,AL)); // MOV AH,AL
3528: gen2(c3,0xD1,modregrm(3,5,CX)); // SHR CX,1
3529: gen1(c3,0xF3); // REP
3530: gen1(c3,0xAB); // STOSW
3531: gen2(c3,0x11,modregrm(3,CX,CX)); // ADC CX,CX
3532: }
3533: c3 = gen1(c3,0xF3); // REP
3534: gen1(c3,0xAA); // STOSB
3535: regimmed_set(CX,0);
3536: return cat4(c1,c2,c3,fixresult(e,mES|mBX,pretregs));
3537: }
3538: #endif
3539:
3540: /**********************
3541: * Do structure assignments.
3542: * This should be fixed so that (s1 = s2) is rewritten to (&s1 = &s2).
3543: * Mebbe call cdstreq() for double assignments???
3544: */
3545:
3546: code *cdstreq(elem *e,regm_t *pretregs)
3547: { code *c1,*c2,*c3;
3548: code *c1a;
3549: regm_t srcregs,dstregs; /* source & destination reg masks */
3550: char need_DS = FALSE;
3551: elem *e1 = e->E1,*e2 = e->E2;
3552: int segreg;
3553:
3554: unsigned numbytes = type_size(e->ET); // # of bytes in structure/union
3555: unsigned char rex = I64 ? REX_W : 0;
3556:
3557: //printf("cdstreq(e = %p, *pretregs = x%x)\n", e, *pretregs);
3558:
3559: /* First, load pointer to rvalue into SI */
3560: srcregs = mSI; /* source is DS:SI */
3561: c1 = docommas(&e2);
3562: if (e2->Eoper == OPind) /* if (.. = *p) */
3563: { elem *e21 = e2->E1;
3564:
3565: segreg = SEG_DS;
3566: switch (tybasic(e21->Ety))
3567: {
3568: case TYsptr:
3569: if (config.wflags & WFssneds) /* if sptr can't use DS segment */
3570: segreg = SEG_SS;
3571: break;
3572: case TYcptr:
3573: if (!(config.exe & EX_flat))
3574: segreg = SEG_CS;
3575: break;
3576: case TYfptr:
3577: case TYvptr:
3578: case TYhptr:
3579: srcregs |= mCX; /* get segment also */
3580: need_DS = TRUE;
3581: break;
3582: }
3583: c1a = codelem(e21,&srcregs,FALSE);
3584: freenode(e2);
3585: if (segreg != SEG_DS) /* if not DS */
3586: { c1a = cat(c1a,getregs(mCX));
3587: c1a = gen2(c1a,0x8C,modregrm(3,segreg,CX)); /* MOV CX,segreg */
3588: need_DS = TRUE;
3589: }
3590: }
3591: else if (e2->Eoper == OPvar)
3592: {
3593: #if !TARGET_FLAT
3594: if (e2->EV.sp.Vsym->ty() & mTYfar) // if e2 is in a far segment
3595: { srcregs |= mCX; /* get segment also */
3596: need_DS = TRUE;
3597: c1a = cdrelconst(e2,&srcregs);
3598: }
3599: else
3600: #endif
3601: {
3602: c1a = cdrelconst(e2,&srcregs);
3603: segreg = segfl[el_fl(e2)];
3604: if ((config.wflags & WFssneds) && segreg == SEG_SS || /* if source is on stack */
3605: segreg == SEG_CS) /* if source is in CS */
3606: { code *c;
3607:
3608: need_DS = TRUE; /* we need to reload DS */
3609: // Load CX with segment
3610: srcregs |= mCX;
3611: c = getregs(mCX);
3612: c = gen2(c,0x8C, /* MOV CX,[SS|CS] */
3613: modregrm(3,segreg,CX));
3614: c1a = cat(c,c1a);
3615: }
3616: }
3617: freenode(e2);
3618: }
3619: else
3620: {
3621: if (!(config.exe & EX_flat))
3622: { need_DS = TRUE;
3623: srcregs |= mCX;
3624: }
3625: c1a = codelem(e2,&srcregs,FALSE);
3626: }
3627: c1 = cat(c1,c1a);
3628:
3629: /* now get pointer to lvalue (destination) in ES:DI */
3630: dstregs = (config.exe & EX_flat) ? mDI : mES|mDI;
3631: if (e1->Eoper == OPind) /* if (*p = ..) */
3632: {
3633: if (tyreg(e1->E1->Ety))
3634: dstregs = mDI;
3635: c2 = cod2_setES(e1->E1->Ety);
3636: c2 = cat(c2,scodelem(e1->E1,&dstregs,srcregs,FALSE));
3637: }
3638: else
3639: c2 = cdrelconst(e1,&dstregs);
3640: freenode(e1);
3641:
3642: c3 = getregs((srcregs | dstregs) & (mLSW | mDI));
3643: if (need_DS)
3644: { assert(!(config.exe & EX_flat));
3645: c3 = gen1(c3,0x1E); /* PUSH DS */
3646: gen2(c3,0x8E,modregrm(3,SEG_DS,CX)); /* MOV DS,CX */
3647: }
3648: if (numbytes <= REGSIZE * (6 + (REGSIZE == 4)))
warning C4018: '<=' : signed/unsigned mismatch
3649: { while (numbytes >= REGSIZE)
warning C4018: '>=' : signed/unsigned mismatch
3650: {
3651: c3 = gen1(c3,0xA5); /* MOVSW */
3652: code_orrex(c3, rex);
3653: numbytes -= REGSIZE;
3654: }
3655: //if (numbytes)
3656: // printf("cdstreq numbytes %d\n",numbytes);
3657: while (numbytes--)
3658: c3 = gen1(c3,0xA4); /* MOVSB */
3659: }
3660: else
3661: {
3662: #if 1
3663: unsigned remainder;
3664:
3665: remainder = numbytes & (REGSIZE - 1);
3666: numbytes /= REGSIZE; // number of words
3667: c3 = cat(c3,getregs_imm(mCX));
3668: c3 = movregconst(c3,CX,numbytes,0); // # of bytes/words
3669: gen1(c3,0xF3); // REP
3670: if (REGSIZE == 8)
3671: gen1(c3,REX | REX_W);
3672: gen1(c3,0xA5); // REP MOVSD
3673: regimmed_set(CX,0); // note that CX == 0
3674: for (; remainder; remainder--)
3675: {
3676: gen1(c3, 0xA4); // MOVSB
3677: }
3678: #else
3679: unsigned movs;
3680:
3681: if (numbytes & (REGSIZE - 1)) /* if odd */
3682: movs = 0xA4; /* MOVSB */
3683: else
3684: { movs = 0xA5; /* MOVSW */
3685: numbytes /= REGSIZE; /* # of words */
3686: }
3687: c3 = cat(c3,getregs_imm(mCX));
3688: c3 = movregconst(c3,CX,numbytes,0); /* # of bytes/words */
3689: gen1(c3,0xF3); /* REP */
3690: gen1(c3,movs);
3691: regimmed_set(CX,0); /* note that CX == 0 */
3692: #endif
3693: }
3694: if (need_DS)
3695: gen1(c3,0x1F); // POP DS
3696: assert(!(*pretregs & mPSW));
3697: if (*pretregs)
3698: { /* ES:DI points past what we want */
3699: regm_t retregs;
3700:
3701: genc2(c3,0x81,(rex << 16) | modregrm(3,5,DI), type_size(e->ET)); // SUB DI,numbytes
3702: retregs = mDI;
3703: if (*pretregs & mMSW && !(config.exe & EX_flat))
3704: retregs |= mES;
3705: c3 = cat(c3,fixresult(e,retregs,pretregs));
3706: }
3707: return cat3(c1,c2,c3);
3708: }
3709:
3710:
3711: /**********************
3712: * Get the address of.
3713: * Is also called by cdstreq() to set up pointer to a structure.
3714: */
3715:
3716: code *cdrelconst(elem *e,regm_t *pretregs)
3717: { code *c,*c1;
3718: enum SC sclass;
3719: unsigned mreg, /* segment of the address (TYfptrs only) */
3720: lreg; /* offset of the address */
3721: tym_t tym;
3722:
3723: //printf("cdrelconst(e = %p)\n", e);
3724:
3725: c = CNIL;
3726:
3727: /* The following should not happen, but cgelem.c is a little stupid. */
3728: /* Assertion can be tripped by func("string" == 0); and similar */
3729: /* things. Need to add goals to optelem() to fix this completely. */
3730: /*assert((*pretregs & mPSW) == 0);*/
3731: if (*pretregs & mPSW)
3732: { *pretregs &= ~mPSW;
3733: c = gentstreg(c,SP); // SP is never 0
3734: if (I64)
3735: code_orrex(c, REX_W);
3736: }
3737: if (!*pretregs)
3738: return c;
3739:
3740: assert(e);
3741: tym = tybasic(e->Ety);
3742: switch (tym)
3743: { case TYstruct:
3744: case TYarray:
3745: case TYldouble:
3746: case TYildouble:
3747: case TYcldouble:
3748: tym = TYnptr; // don't confuse allocreg()
3749: #if !TARGET_FLAT
3750: if (*pretregs & (mES | mCX) || e->Ety & mTYfar)
3751: {
3752: tym = TYfptr;
3753: }
3754: #endif
3755: break;
3756: case TYifunc:
3757: tym = TYfptr;
3758: break;
3759: default:
3760: if (tyfunc(tym))
3761: tym = tyfarfunc(tym) ? TYfptr : TYnptr;
3762: break;
3763: }
3764: /*assert(tym & typtr);*/ /* don't fail on (int)&a */
3765:
3766: c = cat(c,allocreg(pretregs,&lreg,tym));
3767: if (tysize[tym] > REGSIZE) /* fptr could've been cast to long */
3768: { tym_t ety;
3769: symbol *s;
3770:
3771: //elem_print(e);
3772: assert(!TARGET_FLAT);
3773:
3774: if (*pretregs & mES)
3775: { regm_t scratch = (mAX|mBX|mDX|mDI) & ~mask[lreg];
3776: /* Do not allocate CX or SI here, as cdstreq() needs */
3777: /* them preserved. cdstreq() should use scodelem()... */
3778:
3779: c = cat(c,allocreg(&scratch,&mreg,TYint));
3780: }
3781: else
3782: { mreg = lreg;
3783: lreg = findreglsw(*pretregs);
3784: }
3785:
3786: /* if (get segment of function that isn't necessarily in the */
3787: /* current segment (i.e. CS doesn't have the right value in it) */
3788: s = e->EV.sp.Vsym;
3789: if (s->Sfl == FLdatseg)
3790: { assert(0);
3791: goto loadreg;
3792: }
3793: sclass = (enum SC) s->Sclass;
3794: ety = tybasic(s->ty());
3795: if ((tyfarfunc(ety) || ety == TYifunc) &&
3796: (sclass == SCextern || ClassInline(sclass) || config.wflags & WFthunk)
3797: || s->Sfl == FLfardata
3798: || (s->ty() & mTYcs && s->Sseg != cseg && (LARGECODE || s->Sclass == SCcomdat))
3799: // || (s->Sfl == FLextern && s->ty() & mTYcs)
3800: // || (LARGECODE && s->Sclass == SCcomdat)
3801: )
3802: { /* MOV mreg,seg of symbol */
3803: c1 = gencs(CNIL,0xB8 + mreg,0,FLextern,s);
3804: c1->Iflags = CFseg;
3805: c = cat(c,c1);
3806: assert(!TARGET_FLAT);
3807: }
3808: else
3809: { int fl;
3810:
3811: loadreg:
3812: fl = s->Sfl;
3813: if (s->ty() & mTYcs)
3814: fl = FLcsdata;
3815: c = gen2(c,0x8C, /* MOV mreg,SEG REGISTER */
3816: modregrm(3,segfl[fl],mreg));
3817: }
3818: if (*pretregs & mES)
3819: gen2(c,0x8E,modregrm(3,0,mreg)); /* MOV ES,mreg */
3820: }
3821: return cat(c,getoffset(e,lreg));
3822: }
3823:
3824: /*********************************
3825: * Load the offset portion of the address represented by e into
3826: * reg.
3827: */
3828:
3829: code *getoffset(elem *e,unsigned reg)
3830: { code cs;
3831: code *c;
3832:
3833: //printf("getoffset(e = %p, reg = %d)\n", e, reg);
3834: cs.Iflags = 0;
3835: unsigned char rex = 0;
3836: cs.Irex = rex;
3837: assert(e->Eoper == OPvar || e->Eoper == OPrelconst);
3838: enum FL fl = el_fl(e);
3839: switch (fl)
3840: {
3841: case FLdatseg:
3842: cs.IEV2._EP.Vpointer = e->EV.Vpointer;
3843: goto L3;
3844:
3845: case FLfardata:
3846: assert(!TARGET_FLAT);
3847: goto L4;
3848:
3849: case FLtlsdata:
3850: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
3851: {
3852: L5:
3853: if (I64 && config.flags3 & CFG3pic)
3854: {
3855: /* Generate:
3856: * LEA DI,s@TLSGD[RIP]
3857: */
3858: assert(reg == DI);
3859: code css;
3860: css.Irex = REX | REX_W;
3861: css.Iop = 0x8D; // LEA
3862: css.Irm = modregrm(0,DI,5);
3863: css.Iflags = CFopsize;
3864: css.IFL1 = fl;
3865: css.IEVsym1 = e->EV.sp.Vsym;
3866: css.IEVoffset1 = e->EV.sp.Voffset;
3867: c = gen(NULL, &css);
3868: return c;
3869: }
3870: /* Generate:
3871: * MOV reg,GS:[00000000]
3872: * ADD reg, offset s@TLS_LE
3873: * for locals, and for globals:
3874: * MOV reg,GS:[00000000]
3875: * ADD reg, s@TLS_IE
3876: * note different fixup
3877: */
3878: int stack = 0;
3879: c = NULL;
3880: if (reg == STACK)
3881: { regm_t retregs = ALLREGS;
3882:
3883: c = allocreg(&retregs,®,TYoffset);
3884: reg = findreg(retregs);
3885: stack = 1;
3886: }
3887:
3888: code css;
3889: css.Irex = rex;
3890: css.Iop = 0x8B;
3891: css.Irm = modregrm(0, 0, BPRM);
3892: code_newreg(&css, reg);
3893: css.Iflags = CFgs;
3894: css.IFL1 = FLconst;
3895: css.IEV1.Vuns = 0;
3896: c = gen(c, &css); // MOV reg,GS:[00000000]
3897:
3898: if (e->EV.sp.Vsym->Sclass == SCstatic || e->EV.sp.Vsym->Sclass == SClocstat)
3899: { // ADD reg, offset s
3900: cs.Irex = rex;
3901: cs.Iop = 0x81;
3902: cs.Irm = modregrm(3,0,reg & 7);
3903: if (reg & 8)
3904: cs.Irex |= REX_B;
3905: cs.Iflags = CFoff;
3906: cs.IFL2 = fl;
3907: cs.IEVsym2 = e->EV.sp.Vsym;
3908: cs.IEVoffset2 = e->EV.sp.Voffset;
3909: }
3910: else
3911: { // ADD reg, s
3912: cs.Irex = rex;
3913: cs.Iop = 0x03;
3914: cs.Irm = modregrm(0,0,BPRM);
3915: code_newreg(&cs, reg);
3916: cs.Iflags = CFoff;
3917: cs.IFL1 = fl;
3918: cs.IEVsym1 = e->EV.sp.Vsym;
3919: cs.IEVoffset1 = e->EV.sp.Voffset;
3920: }
3921: c = gen(c, &cs); // ADD reg, xxxx
3922:
3923: if (stack)
3924: {
3925: c = gen1(c,0x50 + (reg & 7)); // PUSH reg
3926: if (reg & 8)
3927: code_orrex(c, REX_B);
3928: c = genadjesp(c,REGSIZE);
3929: stackchanged = 1;
3930: }
3931: break;
3932: }
3933: #else
3934: goto L4;
3935: #endif
3936:
3937: case FLfunc:
3938: fl = FLextern; /* don't want PC relative addresses */
3939: goto L4;
3940:
3941: case FLextern:
3942: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
3943: if (e->EV.sp.Vsym->ty() & mTYthread)
3944: goto L5;
3945: #endif
3946: case FLdata:
3947: case FLudata:
3948: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
3949: case FLgot:
3950: case FLgotoff:
3951: #endif
3952: case FLcsdata:
3953: L4:
3954: cs.IEVsym2 = e->EV.sp.Vsym;
3955: cs.IEVoffset2 = e->EV.sp.Voffset;
3956: L3:
3957: if (reg == STACK)
3958: { stackchanged = 1;
3959: cs.Iop = 0x68; /* PUSH immed16 */
3960: c = genadjesp(NULL,REGSIZE);
3961: }
3962: else
3963: { cs.Iop = 0xB8 + (reg & 7); // MOV reg,immed16
3964: if (reg & 8)
3965: cs.Irex |= REX_B;
3966: if (I64)
3967: { cs.Irex |= REX_W;
3968: if (config.flags3 & CFG3pic)
3969: { // LEA reg,immed32[RIP]
3970: cs.Iop = 0x8D;
3971: cs.Irm = modregrm(0,reg & 7,5);
3972: if (reg & 8)
3973: cs.Irex = (cs.Irex & ~REX_B) | REX_R;
3974: cs.IFL1 = fl;
3975: cs.IEVsym1 = cs.IEVsym2;
3976: cs.IEVoffset1 = cs.IEVoffset2;
3977: }
3978: }
3979: c = NULL;
3980: }
3981: cs.Iflags = CFoff; /* want offset only */
3982: cs.IFL2 = fl;
3983: c = gen(c,&cs);
3984: break;
3985:
3986: #if 0 && TARGET_LINUX
3987: case FLgot:
3988: case FLgotoff:
3989: {
3990: gotref = 1;
3991: symbol *s = e->EV.sp.Vsym;
3992: // When using 8B (MOV), indicating that rm is used
3993: // rm operands are always placed in IEV1 not IEV2
3994: cs.IEVsym1 = s;
3995: cs.IEVoffset1 = e->EV.sp.Voffset;
3996: cs.Irm = modregrm(2,reg,BX); // reg,disp32[EBX]
3997: cs.IFL1 = fl;
3998: cs.Iop = (fl == FLgotoff)
3999: ? 0x8D // LEA reg, s[EBX]
4000: : 0x8B; // MOV reg, s[EBX]
4001: cs.Iflags = CFoff; // want offset only
4002: c = gen(NULL,&cs);
4003: break;
4004: }
4005: #endif
4006:
4007: case FLreg:
4008: /* Allow this since the tree optimizer puts & in front of */
4009: /* register doubles. */
4010: goto L2;
4011: case FLauto:
4012: case FLtmp:
4013: case FLbprel:
4014: case FLfltreg:
4015: reflocal = TRUE;
4016: goto L2;
4017: case FLpara:
4018: refparam = TRUE;
4019: L2:
4020: if (reg == STACK)
4021: { regm_t retregs = ALLREGS;
4022:
4023: c = allocreg(&retregs,®,TYoffset);
4024: reg = findreg(retregs);
4025: c = cat(c,loadea(e,&cs,0x8D,reg,0,0,0)); /* LEA reg,EA */
4026: if (I64)
4027: code_orrex(c, REX_W);
4028: c = gen1(c,0x50 + (reg & 7)); // PUSH reg
4029: if (reg & 8)
4030: code_orrex(c, REX_B);
4031: c = genadjesp(c,REGSIZE);
4032: stackchanged = 1;
4033: }
4034: else
4035: { c = loadea(e,&cs,0x8D,reg,0,0,0); /* LEA reg,EA */
4036: if (I64)
4037: code_orrex(c, REX_W);
4038: }
4039: break;
4040: default:
4041: #ifdef DEBUG
4042: elem_print(e);
4043: debugx(WRFL(fl));
4044: #endif
4045: assert(0);
4046: }
4047: return c;
4048: }
4049:
4050:
4051: /******************
4052: * Negate, sqrt operator
4053: */
4054:
4055: code *cdneg(elem *e,regm_t *pretregs)
4056: { unsigned byte;
4057: regm_t retregs,possregs;
4058: int reg;
4059: int sz;
4060: tym_t tyml;
4061: code *c,*c1,*cg;
4062:
4063: //printf("cdneg()\n");
4064: //elem_print(e);
4065: if (*pretregs == 0)
4066: return codelem(e->E1,pretregs,FALSE);
4067: tyml = tybasic(e->E1->Ety);
4068: sz = tysize[tyml];
4069: if (tyfloating(tyml))
4070: { if (tycomplex(tyml))
4071: return neg_complex87(e, pretregs);
4072: if (config.inline8087 &&
4073: ((*pretregs & (ALLREGS | mBP)) == 0 || e->Eoper == OPsqrt || I64))
4074: return neg87(e,pretregs);
4075: retregs = (I16 && sz == 8) ? DOUBLEREGS_16 : ALLREGS;
4076: c1 = codelem(e->E1,&retregs,FALSE);
4077: c1 = cat(c1,getregs(retregs));
4078: if (I32)
4079: { reg = (sz == 8) ? findregmsw(retregs) : findreg(retregs);
4080: c1 = genc2(c1,0x81,modregrm(3,6,reg),0x80000000); /* XOR EDX,sign bit */
4081: }
4082: else
4083: { reg = (sz == 8) ? AX : findregmsw(retregs);
4084: c1 = genc2(c1,0x81,modregrm(3,6,reg),0x8000); /* XOR AX,0x8000 */
4085: }
4086: return cat(c1,fixresult(e,retregs,pretregs));
4087: }
4088:
4089: byte = sz == 1;
4090: possregs = (byte) ? BYTEREGS : allregs;
4091: retregs = *pretregs & possregs;
4092: if (retregs == 0)
4093: retregs = possregs;
4094: c1 = codelem(e->E1,&retregs,FALSE);
4095: cg = getregs(retregs); /* retregs will be destroyed */
4096: if (sz <= REGSIZE)
4097: {
4098: unsigned reg = findreg(retregs);
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '4058' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 4058
4099: unsigned rex = (I64 && sz == 8) ? REX_W : 0;
4100: if (I64 && sz == 1 && reg >= 4)
4101: rex |= REX;
4102: c = gen2(CNIL,0xF7 ^ byte,(rex << 16) | modregrmx(3,3,reg)); // NEG reg
4103: if (!I16 && tysize[tyml] == SHORTSIZE && *pretregs & mPSW)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4104: c->Iflags |= CFopsize | CFpsw;
4105: *pretregs &= mBP | ALLREGS; // flags already set
4106: }
4107: else if (sz == 2 * REGSIZE)
4108: { unsigned msreg,lsreg;
4109:
4110: msreg = findregmsw(retregs);
4111: c = gen2(CNIL,0xF7,modregrm(3,3,msreg)); /* NEG msreg */
4112: lsreg = findreglsw(retregs);
4113: gen2(c,0xF7,modregrm(3,3,lsreg)); /* NEG lsreg */
4114: genc2(c,0x81,modregrm(3,3,msreg),0); /* SBB msreg,0 */
4115: }
4116: else
4117: assert(0);
4118: return cat4(c1,cg,c,fixresult(e,retregs,pretregs));
4119: }
4120:
4121:
4122: /******************
4123: * Absolute value operator
4124: */
4125:
4126: code *cdabs( elem *e, regm_t *pretregs)
4127: { unsigned byte;
4128: regm_t retregs,possregs;
4129: int reg;
4130: tym_t tyml;
4131: code *c,*c1,*cg;
4132:
4133: if (*pretregs == 0)
4134: return codelem(e->E1,pretregs,FALSE);
4135: tyml = tybasic(e->E1->Ety);
4136: int sz = tysize[tyml];
4137: unsigned rex = (I64 && sz == 8) ? REX_W : 0;
4138: if (tyfloating(tyml))
4139: { if (config.inline8087 && ((*pretregs & (ALLREGS | mBP)) == 0 || I64))
4140: return neg87(e,pretregs);
4141: retregs = (!I32 && sz == 8) ? DOUBLEREGS_16 : ALLREGS;
4142: c1 = codelem(e->E1,&retregs,FALSE);
4143: /*cg = callclib(e,CLIBdneg,pretregs,0);*/
4144: c1 = cat(c1,getregs(retregs));
4145: if (I32)
4146: { reg = (sz == 8) ? findregmsw(retregs) : findreg(retregs);
4147: c1 = genc2(c1,0x81,modregrm(3,4,reg),0x7FFFFFFF); /* AND EDX,~sign bit */
4148: }
4149: else
4150: { reg = (sz == 8) ? AX : findregmsw(retregs);
4151: c1 = genc2(c1,0x81,modregrm(3,4,reg),0x7FFF); /* AND AX,0x7FFF */
4152: }
4153: return cat(c1,fixresult(e,retregs,pretregs));
4154: }
4155:
4156: byte = sz == 1;
4157: assert(byte == 0);
4158: byte = 0;
4159: possregs = (sz <= REGSIZE) ? mAX : allregs;
4160: if (!I16 && sz == REGSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4161: possregs = allregs;
4162: retregs = *pretregs & possregs;
4163: if (retregs == 0)
4164: retregs = possregs;
4165: c1 = codelem(e->E1,&retregs,FALSE);
4166: cg = getregs(retregs); /* retregs will be destroyed */
4167: if (sz <= REGSIZE)
4168: {
4169: /* CWD
4170: XOR AX,DX
4171: SUB AX,DX
4172: or:
4173: MOV r,reg
4174: SAR r,63
4175: XOR reg,r
4176: SUB reg,r
4177: */
4178: unsigned reg;
warning C6246: Local declaration of 'reg' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '4129' of 'c:\projects\extern\d\dmd\src\backend\cod2.c': Lines: 4129
4179: unsigned r;
4180:
4181: if (!I16 && sz == REGSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4182: { regm_t scratch = allregs & ~retregs;
4183: reg = findreg(retregs);
4184: cg = allocreg(&scratch,&r,TYint);
4185: cg = cat(cg,getregs(retregs));
4186: cg = genmovreg(cg,r,reg); // MOV r,reg
4187: cg = genc2(cg,0xC1,modregrmx(3,7,r),REGSIZE * 8 - 1); // SAR r,31/63
4188: code_orrex(cg, rex);
4189: }
4190: else
4191: {
4192: reg = AX;
4193: r = DX;
4194: cg = cat(cg,getregs(mDX));
4195: if (!I16 && sz == SHORTSIZE)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4196: cg = gen1(cg,0x98); // CWDE
4197: cg = gen1(cg,0x99); // CWD
4198: code_orrex(cg, rex);
4199: }
4200: gen2(cg,0x33 ^ byte,(rex << 16) | modregrm(3,reg,r)); // XOR reg,r
4201: c = gen2(CNIL,0x2B ^ byte,(rex << 16) | modregrm(3,reg,r)); // SUB reg,r
4202: if (!I16 && sz == SHORTSIZE && *pretregs & mPSW)
warning C6239: (<non-zero constant> && <expression>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4203: c->Iflags |= CFopsize | CFpsw;
4204: if (*pretregs & mPSW)
4205: c->Iflags |= CFpsw;
4206: *pretregs &= ~mPSW; // flags already set
4207: }
4208: else if (sz == 2 * REGSIZE)
4209: { unsigned msreg,lsreg;
4210: code *cnop;
4211:
4212: /* tst DX
4213: jns L2
4214: neg DX
4215: neg AX
4216: sbb DX,0
4217: L2:
4218: */
4219:
4220: cnop = gennop(CNIL);
4221: msreg = findregmsw(retregs);
4222: lsreg = findreglsw(retregs);
4223: c = genorreg(CNIL,msreg,msreg);
4224: c = genjmp(c,JNS,FLcode,(block *)cnop);
4225: c = gen2(c,0xF7,modregrm(3,3,msreg)); // NEG msreg
4226: gen2(c,0xF7,modregrm(3,3,lsreg)); // NEG lsreg+1
4227: genc2(c,0x81,modregrm(3,3,msreg),0); // SBB msreg,0
4228: c = cat(c,cnop);
4229: }
4230: else
4231: assert(0);
4232: return cat4(c1,cg,c,fixresult(e,retregs,pretregs));
4233: }
4234:
4235: /**************************
4236: * Post increment and post decrement.
4237: */
4238:
4239: code *cdpost(elem *e,regm_t *pretregs)
4240: { code cs,*c1,*c2,*c3,*c5,*c6;
4241: unsigned reg,op,byte;
4242: tym_t tyml;
4243: regm_t retregs,possregs,idxregs;
4244: targ_int n;
4245: elem *e2;
4246: int sz;
4247: int stackpushsave;
4248:
4249: //printf("cdpost(pretregs = %s)\n", regm_str(*pretregs));
4250: retregs = *pretregs;
4251: op = e->Eoper; /* OPxxxx */
4252: if (retregs == 0) /* if nothing to return */
4253: return cdaddass(e,pretregs);
4254: c5 = CNIL;
4255: tyml = tybasic(e->E1->Ety);
4256: sz = tysize[tyml];
4257: e2 = e->E2;
4258: unsigned rex = (I64 && sz == 8) ? REX_W : 0;
4259:
4260: if (tyfloating(tyml))
4261: {
4262: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
4263: return post87(e,pretregs);
4264: #else
4265: if (config.inline8087)
4266: return post87(e,pretregs);
4267: assert(sz <= 8);
4268: c1 = getlvalue(&cs,e->E1,DOUBLEREGS);
4269: freenode(e->E1);
4270: idxregs = idxregm(&cs); // mask of index regs used
4271: cs.Iop = 0x8B; /* MOV DOUBLEREGS,EA */
4272: c2 = fltregs(&cs,tyml);
4273: stackchanged = 1;
4274: stackpushsave = stackpush;
4275: if (sz == 8)
4276: {
4277: if (I32)
4278: {
4279: gen1(c2,0x50 + DX); /* PUSH DOUBLEREGS */
4280: gen1(c2,0x50 + AX);
4281: stackpush += DOUBLESIZE;
4282: retregs = DOUBLEREGS2_32;
4283: }
4284: else
4285: {
4286: gen1(c2,0x50 + AX);
4287: gen1(c2,0x50 + BX);
4288: gen1(c2,0x50 + CX);
4289: gen1(c2,0x50 + DX); /* PUSH DOUBLEREGS */
4290: stackpush += DOUBLESIZE + DOUBLESIZE;
4291:
4292: gen1(c2,0x50 + AX);
4293: gen1(c2,0x50 + BX);
4294: gen1(c2,0x50 + CX);
4295: gen1(c2,0x50 + DX); /* PUSH DOUBLEREGS */
4296: retregs = DOUBLEREGS_16;
4297: }
4298: }
4299: else
4300: {
4301: stackpush += FLOATSIZE; /* so we know something is on */
4302: if (!I32)
4303: gen1(c2,0x50 + DX);
4304: gen1(c2,0x50 + AX);
4305: retregs = FLOATREGS2;
4306: }
4307: c2 = genadjesp(c2,stackpush - stackpushsave);
4308:
4309: cgstate.stackclean++;
4310: c3 = scodelem(e2,&retregs,idxregs,FALSE);
4311: cgstate.stackclean--;
4312:
4313: code *c4;
4314: if (tyml == TYdouble || tyml == TYdouble_alias)
4315: {
4316: retregs = DOUBLEREGS;
4317: c4 = callclib(e,(op == OPpostinc) ? CLIBdadd : CLIBdsub,
4318: &retregs,idxregs);
4319: }
4320: else /* tyml == TYfloat */
4321: {
4322: retregs = FLOATREGS;
4323: c4 = callclib(e,(op == OPpostinc) ? CLIBfadd : CLIBfsub,
4324: &retregs,idxregs);
4325: }
4326: cs.Iop = 0x89; /* MOV EA,DOUBLEREGS */
4327: c5 = fltregs(&cs,tyml);
4328: stackpushsave = stackpush;
4329: if (tyml == TYdouble || tyml == TYdouble_alias)
4330: { if (*pretregs == mSTACK)
4331: retregs = mSTACK; /* leave result on stack */
4332: else
4333: {
4334: if (I32)
4335: { gen1(c5,0x58 + AX);
4336: gen1(c5,0x58 + DX);
4337: }
4338: else
4339: { gen1(c5,0x58 + DX);
4340: gen1(c5,0x58 + CX);
4341: gen1(c5,0x58 + BX);
4342: gen1(c5,0x58 + AX);
4343: }
4344: stackpush -= DOUBLESIZE;
4345: retregs = DOUBLEREGS;
4346: }
4347: }
4348: else
4349: { gen1(c5,0x58 + AX);
4350: if (!I32)
4351: gen1(c5,0x58 + DX);
4352: stackpush -= FLOATSIZE;
4353: retregs = FLOATREGS;
4354: }
4355: c5 = genadjesp(c5,stackpush - stackpushsave);
4356: c6 = fixresult(e,retregs,pretregs);
4357: return cat6(c1,c2,c3,c4,c5,c6);
4358: #endif
4359: }
4360:
4361: assert(e2->Eoper == OPconst);
4362: byte = (sz == 1);
4363: possregs = byte ? BYTEREGS : allregs;
4364: c1 = getlvalue(&cs,e->E1,0);
4365: freenode(e->E1);
4366: idxregs = idxregm(&cs); // mask of index regs used
4367: if (sz <= REGSIZE && *pretregs == mPSW && (cs.Irm & 0xC0) == 0xC0 &&
warning C6240: (<expression> && <non-zero constant>) always evaluates to the result of <expression>. Did you intend to use the bitwise-and operator?
4368: (!I16 || (idxregs & (mBX | mSI | mDI | mBP))))
warning C6235: (<non-zero constant> || <expression>) is always a non-zero constant
4369: { // Generate:
4370: // TEST reg,reg
4371: // LEA reg,n[reg] // don't affect flags
4372: int rm;
4373:
4374: reg = cs.Irm & 7;
4375: if (cs.Irex & REX_B)
4376: reg |= 8;
4377: cs.Iop = 0x85 ^ byte;
4378: code_newreg(&cs, reg);
4379: cs.Iflags |= CFpsw;
4380: c2 = gen(NULL,&cs); // TEST reg,reg
4381:
4382: // If lvalue is a register variable, we must mark it as modified
4383: c3 = modEA(&cs);
4384:
4385: n = e2->EV.Vint;
4386: if (op == OPpostdec)
4387: n = -n;
4388: rm = reg;
4389: if (I16)
4390: rm = regtorm[reg];
4391: code *c4 = genc1(NULL,0x8D,(rex << 16) | buildModregrm(2,reg,rm),FLconst,n); // LEA reg,n[reg]
4392: return cat4(c1,c2,c3,c4);
4393: }
4394: else if (sz <= REGSIZE || tyfv(tyml))
4395: { code cs2;
4396:
4397: cs.Iop = 0x8B ^ byte;
4398: retregs = possregs & ~idxregs & *pretregs;
4399: if (!tyfv(tyml))
4400: { if (retregs == 0)
4401: retregs = possregs & ~idxregs;
4402: }
4403: else /* tyfv(tyml) */
4404: { if ((retregs &= mLSW) == 0)
4405: retregs = mLSW & ~idxregs;
4406: /* Can't use LES if the EA uses ES as a seg override */
4407: if (*pretregs & mES && (cs.Iflags & CFSEG) != CFes)
4408: { cs.Iop = 0xC4; /* LES */
4409: c1 = cat(c1,getregs(mES)); /* allocate ES */
4410: }
4411: }
4412: c2 = allocreg(&retregs,®,TYint);
4413: code_newreg(&cs, reg);
4414: c3 = gen(CNIL,&cs); /* MOV reg,EA */
4415: cs2 = cs;
4416:
4417: /* If lvalue is a register variable, we must mark it as modified */
4418: c3 = cat(c3,modEA(&cs));
4419:
4420: cs.Iop = 0x81 ^ byte;
4421: cs.Irm &= ~modregrm(0,7,0); /* reg field = 0 */
4422: cs.Irex &= ~REX_R;
4423: if (op == OPpostdec)
4424: cs.Irm |= modregrm(0,5,0); /* SUB */
4425: cs.IFL2 = FLconst;
4426: n = e2->EV.Vint;
4427: cs.IEV2.Vint = n;
4428: if (n == 1) /* can use INC or DEC */
4429: { cs.Iop |= 0xFE; /* xFE is dec byte, xFF is word */
4430: if (op == OPpostdec)
4431: NEWREG(cs.Irm,1); // DEC EA
4432: else
4433: NEWREG(cs.Irm,0); // INC EA
4434: }
4435: else if (n == -1) // can use INC or DEC
4436: { cs.Iop |= 0xFE; // xFE is dec byte, xFF is word
4437: if (op == OPpostinc)
4438: NEWREG(cs.Irm,1); // DEC EA
4439: else
4440: NEWREG(cs.Irm,0); // INC EA
4441: }
4442:
4443: // For scheduling purposes, we wish to replace:
4444: // MOV reg,EA
4445: // OP EA
4446: // with:
4447: // MOV reg,EA
4448: // OP reg
4449: // MOV EA,reg
4450: // ~OP reg
4451: if (sz <= REGSIZE && (cs.Irm & 0xC0) != 0xC0 &&
4452: config.target_cpu >= TARGET_Pentium &&
4453: config.flags4 & CFG4speed)
4454: {
4455: // Replace EA in cs with reg
4456: cs.Irm = (cs.Irm & ~modregrm(3,0,7)) | modregrm(3,0,reg & 7);
4457: if (reg & 8)
4458: { cs.Irex &= ~REX_R;
4459: cs.Irex |= REX_B;
4460: }
4461: else
4462: cs.Irex &= ~REX_B;
4463: if (I64 && sz == 1 && reg >= 4)
4464: cs.Irex |= REX;
4465: gen(c3,&cs); // ADD/SUB reg,const
4466:
4467: // Reverse MOV direction
4468: cs2.Iop ^= 2;
4469: gen(c3,&cs2); // MOV EA,reg
4470:
4471: // Toggle INC <-> DEC, ADD <-> SUB
4472: cs.Irm ^= (n == 1 || n == -1) ? modregrm(0,1,0) : modregrm(0,5,0);
4473: gen(c3,&cs);
4474:
4475: if (*pretregs & mPSW)
4476: { *pretregs &= ~mPSW; // flags already set
4477: code_orflag(c3,CFpsw);
4478: }
4479: }
4480: else
4481: gen(c3,&cs); // ADD/SUB EA,const
4482:
4483: freenode(e2);
4484: if (tyfv(tyml))
4485: { unsigned preg;
4486:
4487: getlvalue_msw(&cs);
4488: if (*pretregs & mES)
4489: { preg = ES;
4490: /* ES is already loaded if CFes is 0 */
4491: cs.Iop = ((cs.Iflags & CFSEG) == CFes) ? 0x8E : NOP;
4492: NEWREG(cs.Irm,0); /* MOV ES,EA+2 */
4493: }
4494: else
4495: {
4496: retregs = *pretregs & mMSW;
4497: if (!retregs)
4498: retregs = mMSW;
4499: c3 = cat(c3,allocreg(&retregs,&preg,TYint));
4500: cs.Iop = 0x8B;
4501: if (I32)
4502: cs.Iflags |= CFopsize;
4503: NEWREG(cs.Irm,preg); /* MOV preg,EA+2 */
4504: }
4505: c3 = cat(c3,getregs(mask[preg]));
4506: gen(c3,&cs);
4507: retregs = mask[reg] | mask[preg];
4508: }
4509: return cat4(c1,c2,c3,fixresult(e,retregs,pretregs));
4510: }
4511: else if (tyml == TYhptr)
4512: {
4513: unsigned long rvalue;
4514: unsigned lreg;
4515: unsigned rtmp;
4516: regm_t mtmp;
4517:
4518: rvalue = e2->EV.Vlong;
4519: freenode(e2);
4520:
4521: // If h--, convert to h++
4522: if (e->Eoper == OPpostdec)
4523: rvalue = -rvalue;
warning C4146: unary minus operator applied to unsigned type, result still unsigned
4524:
4525: retregs = mLSW & ~idxregs & *pretregs;
4526: if (!retregs)
4527: retregs = mLSW & ~idxregs;
4528: c1 = cat(c1,allocreg(&retregs,&lreg,TYint));
4529:
4530: // Can't use LES if the EA uses ES as a seg override
4531: if (*pretregs & mES && (cs.Iflags & CFSEG) != CFes)
4532: { cs.Iop = 0xC4;
4533: retregs |= mES;
4534: c1 = cat(c1,getregs(mES|mCX)); // allocate ES
4535: cs.Irm |= modregrm(0,lreg,0);
4536: c2 = gen(CNIL,&cs); // LES lreg,EA
4537: }
4538: else
4539: { cs.Iop = 0x8B;
4540: retregs |= mDX;
4541: c1 = cat(c1,getregs(mDX|mCX));
4542: cs.Irm |= modregrm(0,lreg,0);
4543: c2 = gen(CNIL,&cs); // MOV lreg,EA
4544: NEWREG(cs.Irm,DX);
4545: getlvalue_msw(&cs);
4546: gen(c2,&cs); // MOV DX,EA+2
4547: getlvalue_lsw(&cs);
4548: }
4549:
4550: // Allocate temporary register, rtmp
4551: mtmp = ALLREGS & ~mCX & ~idxregs & ~retregs;
4552: c2 = cat(c2,allocreg(&mtmp,&rtmp,TYint));
4553:
4554: movregconst(c2,rtmp,rvalue >> 16,0); // MOV rtmp,e2+2
4555: c3 = getregs(mtmp);
4556: cs.Iop = 0x81;
4557: NEWREG(cs.Irm,0);
4558: cs.IFL2 = FLconst;
4559: cs.IEV2.Vint = rvalue;
4560: c3 = gen(c3,&cs); // ADD EA,e2
4561: code_orflag(c3,CFpsw);
4562: genc2(c3,0x81,modregrm(3,2,rtmp),0); // ADC rtmp,0
4563: genshift(c3); // MOV CX,offset __AHSHIFT
4564: gen2(c3,0xD3,modregrm(3,4,rtmp)); // SHL rtmp,CL
4565: cs.Iop = 0x01;
4566: NEWREG(cs.Irm,rtmp); // ADD EA+2,rtmp
4567: getlvalue_msw(&cs);
4568: gen(c3,&cs);
4569: return cat4(c1,c2,c3,fixresult(e,retregs,pretregs));
4570: }
4571: else if (sz == 2 * REGSIZE)
4572: { unsigned sreg;
4573:
4574: retregs = allregs & ~idxregs & *pretregs;
4575: if ((retregs & mLSW) == 0)
4576: retregs |= mLSW & ~idxregs;
4577: if ((retregs & mMSW) == 0)
4578: retregs |= ALLREGS & mMSW;
4579: assert(retregs & mMSW && retregs & mLSW);
4580: c2 = allocreg(&retregs,®,tyml);
4581: sreg = findreglsw(retregs);
4582: cs.Iop = 0x8B;
4583: cs.Irm |= modregrm(0,sreg,0);
4584: c3 = gen(CNIL,&cs); /* MOV sreg,EA */
4585: NEWREG(cs.Irm,reg);
4586: getlvalue_msw(&cs);
4587: gen(c3,&cs); /* MOV reg,EA+2 */
4588: cs.Iop = 0x81;
4589: cs.Irm &= ~modregrm(0,7,0); /* reg field = 0 for ADD */
4590: if (op == OPpostdec)
4591: cs.Irm |= modregrm(0,5,0); /* SUB */
4592: getlvalue_lsw(&cs);
4593: cs.IFL2 = FLconst;
4594: cs.IEV2.Vlong = e2->EV.Vlong;
4595: gen(c3,&cs); /* ADD/SUB EA,const */
4596: code_orflag(c3,CFpsw);
4597: getlvalue_msw(&cs);
4598: cs.IEV2.Vlong = 0;
4599: if (op == OPpostinc)
4600: cs.Irm ^= modregrm(0,2,0); /* ADC */
4601: else
4602: cs.Irm ^= modregrm(0,6,0); /* SBB */
4603: cs.IEV2.Vlong = e2->EV.Vullong >> (REGSIZE * 8);
warning C4244: '=' : conversion from 'targ_ullong' to 'targ_long', possible loss of data
4604: gen(c3,&cs); /* ADC/SBB EA,0 */
4605: freenode(e2);
4606: return cat4(c1,c2,c3,fixresult(e,retregs,pretregs));
4607: }
4608: else
4609: { assert(0);
4610: /* NOTREACHED */
4611: return 0;
4612: }
4613: }
4614:
4615:
4616: code *cderr(elem *e,regm_t *pretregs)
4617: {
4618: #if DEBUG
4619: elem_print(e);
4620: #endif
4621: //printf("op = %d, %d\n", e->Eoper, OPstring);
4622: //printf("string = %p, len = %d\n", e->EV.ss.Vstring, e->EV.ss.Vstrlen);
4623: //printf("string = '%.*s'\n", e->EV.ss.Vstrlen, e->EV.ss.Vstring);
4624: assert(0);
4625: return 0;
4626: }
4627:
4628: code *cdinfo(elem *e,regm_t *pretregs)
4629: {
4630: code cs;
4631: code *c;
4632: regm_t retregs;
4633:
4634: switch (e->E1->Eoper)
4635: {
4636: #if MARS
4637: case OPdctor:
4638: c = codelem(e->E2,pretregs,FALSE);
4639: retregs = 0;
4640: c = cat(c,codelem(e->E1,&retregs,FALSE));
4641: break;
4642: #endif
4643: #if SCPP
4644: case OPdtor:
4645: c = cdcomma(e,pretregs);
4646: break;
4647: case OPctor:
4648: c = codelem(e->E2,pretregs,FALSE);
4649: retregs = 0;
4650: c = cat(c,codelem(e->E1,&retregs,FALSE));
4651: break;
4652: case OPmark:
4653: if (0 && config.exe == EX_NT)
4654: { unsigned idx;
4655:
4656: idx = except_index_get();
4657: except_mark();
4658: c = codelem(e->E2,pretregs,FALSE);
4659: if (config.exe == EX_NT && idx != except_index_get())
4660: { usednteh |= NTEHcleanup;
4661: c = cat(c,nteh_gensindex(idx - 1));
4662: }
4663: except_release();
4664: assert(idx == except_index_get());
4665: }
4666: else
4667: {
4668: #if 0
4669: usednteh |= EHcleanup;
4670: if (config.exe == EX_NT)
4671: usednteh |= NTEHcleanup;
4672: #endif
4673: cs.Iop = ESCAPE | ESCmark;
4674: cs.Iflags = 0;
4675: cs.Irex = 0;
4676: c = gen(CNIL,&cs);
4677: c = cat(c,codelem(e->E2,pretregs,FALSE));
4678: cs.Iop = ESCAPE | ESCrelease;
4679: gen(c,&cs);
4680: }
4681: freenode(e->E1);
4682: break;
4683: #endif
4684: default:
4685: assert(0);
4686: }
4687: return c;
4688: }
4689:
4690: /*******************************************
4691: * D constructor.
4692: */
4693:
4694: code *cddctor(elem *e,regm_t *pretregs)
4695: {
4696: #if MARS
4697: /* Generate:
4698: ESCAPE | ESCdctor
4699: MOV sindex[BP],index
4700: */
4701: usednteh |= EHcleanup;
4702: if (config.exe == EX_NT)
4703: usednteh |= NTEHcleanup;
4704: assert(*pretregs == 0);
4705: code cs;
4706: cs.Iop = ESCAPE | ESCdctor;
4707: cs.Iflags = 0;
4708: cs.Irex = 0;
4709: cs.IFL1 = FLctor;
4710: cs.IEV1.Vtor = e;
4711: code *c = gen(CNIL,&cs);
4712: c = cat(c, nteh_gensindex(0)); // the actual index will be patched in later
4713: // by except_fillInEHTable()
4714: return c;
4715: #else
4716: return NULL;
4717: #endif
4718: }
4719:
4720: /*******************************************
4721: * D destructor.
4722: */
4723:
4724: code *cdddtor(elem *e,regm_t *pretregs)
4725: {
4726: #if MARS
4727: /* Generate:
4728: ESCAPE | ESCddtor
4729: MOV sindex[BP],index
4730: CALL dtor
4731: JMP L1
4732: Ldtor:
4733: ... e->E1 ...
4734: RET
4735: L1: NOP
4736: */
4737: usednteh |= EHcleanup;
4738: if (config.exe == EX_NT)
4739: usednteh |= NTEHcleanup;
4740:
4741: code cs;
4742: cs.Iop = ESCAPE | ESCddtor;
4743: cs.Iflags = 0;
4744: cs.Irex = 0;
4745: cs.IFL1 = FLdtor;
4746: cs.IEV1.Vtor = e;
4747: code *cd = gen(CNIL,&cs);
4748:
4749: cd = cat(cd, nteh_gensindex(0)); // the actual index will be patched in later
4750: // by except_fillInEHTable()
4751:
4752: assert(*pretregs == 0);
4753: code *c = codelem(e->E1,pretregs,FALSE);
4754: gen1(c,0xC3); // RET
4755:
4756: #if TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS
4757: if (config.flags3 & CFG3pic)
4758: {
4759: int nalign = 0;
4760: if (STACKALIGN == 16)
4761: { nalign = STACKALIGN - REGSIZE;
4762: cd = genc2(cd,0x81,modregrm(3,5,SP),nalign); // SUB ESP,nalign
4763: if (I64)
4764: code_orrex(cd, REX_W);
4765: }
4766: calledafunc = 1;
4767: genjmp(cd,0xE8,FLcode,(block *)c); // CALL Ldtor
4768: if (nalign)
4769: { cd = genc2(cd,0x81,modregrm(3,0,SP),nalign); // ADD ESP,nalign
4770: if (I64)
4771: code_orrex(cd, REX_W);
4772: }
4773: }
4774: else
4775: #endif
4776: genjmp(cd,0xE8,FLcode,(block *)c); // CALL Ldtor
4777:
4778: code *cnop = gennop(CNIL);
4779:
4780: genjmp(cd,JMP,FLcode,(block *)cnop);
4781:
4782: return cat4(cd, c, cnop, NULL);
4783: #else
4784: return NULL;
4785: #endif
4786: }
4787:
4788:
4789: /*******************************************
4790: * C++ constructor.
4791: */
4792:
4793: code *cdctor(elem *e,regm_t *pretregs)
4794: {
4795: #if SCPP
4796: code cs;
4797: code *c;
4798:
4799: #if 0
4800: if (config.exe == EX_NT)
4801: { usednteh |= NTEHcleanup;
4802: except_push(NULL,e,NULL);
4803: return nteh_gensindex(except_index_get() - 1);
4804: }
4805: #else
4806: usednteh |= EHcleanup;
4807: if (config.exe == EX_NT)
4808: usednteh |= NTEHcleanup;
4809: #endif
4810: assert(*pretregs == 0);
4811: cs.Iop = ESCAPE | ESCctor;
4812: cs.Iflags = 0;
4813: cs.Irex = 0;
4814: cs.IFL1 = FLctor;
4815: cs.IEV1.Vtor = e;
4816: c = gen(CNIL,&cs);
4817: //except_push(c,e,NULL);
4818: return c;
4819: #else
4820: return NULL;
4821: #endif
4822: }
4823:
4824: code *cddtor(elem *e,regm_t *pretregs)
4825: {
4826: #if SCPP
4827: code cs;
4828: code *c;
4829:
4830: #if 0
4831: if (config.exe == EX_NT)
4832: { usednteh |= NTEHcleanup;
4833: except_pop(NULL,e,NULL);
4834: return nteh_gensindex(except_index_get() - 1);
4835: }
4836: #else
4837: usednteh |= EHcleanup;
4838: if (config.exe == EX_NT)
4839: usednteh |= NTEHcleanup;
4840: #endif
4841: assert(*pretregs == 0);
4842: cs.Iop = ESCAPE | ESCdtor;
4843: cs.Iflags = 0;
4844: cs.Irex = 0;
4845: cs.IFL1 = FLdtor;
4846: cs.IEV1.Vtor = e;
4847: c = gen(CNIL,&cs);
4848: //except_pop(c,e,NULL);
4849: return c;
4850: #else
4851: return NULL;
4852: #endif
4853: }
4854:
4855: code *cdmark(elem *e,regm_t *pretregs)
4856: {
4857: return NULL;
4858: }
4859:
4860: #if !NTEXCEPTIONS
4861: code *cdsetjmp(elem *e,regm_t *pretregs)
4862: {
4863: assert(0);
4864: return NULL;
4865: }
4866: #endif
4867:
4868: /*****************************************
4869: */
4870:
4871: code *cdvoid(elem *e,regm_t *pretregs)
4872: {
4873: assert(*pretregs == 0);
4874: return codelem(e->E1,pretregs,FALSE);
4875: }
4876:
4877: /*****************************************
4878: */
4879:
4880: code *cdhalt(elem *e,regm_t *pretregs)
4881: {
4882: assert(*pretregs == 0);
4883: return gen1(NULL, 0xF4); // HLT
4884: }
4885:
4886: /****************************************
4887: * Check to see if pointer is NULL.
4888: */
4889:
4890: code *cdnullcheck(elem *e,regm_t *pretregs)
4891: { regm_t retregs;
4892: regm_t scratch;
4893: unsigned reg;
4894: code *c;
4895: code *cs;
4896:
4897: assert(!I16);
4898: retregs = *pretregs;
4899: if ((retregs & allregs) == 0)
4900: retregs |= allregs;
4901: c = codelem(e->E1,&retregs,FALSE);
4902: scratch = allregs & ~retregs;
4903: cs = allocreg(&scratch,®,TYint);
4904: unsigned rex = I64 ? REX_W : 0;
4905: cs = genc1(cs,0x8B,(rex << 16) | buildModregrm(2,reg,findreg(retregs)),FLconst,0); // MOV reg,0[e]
4906: return cat3(c,cs,fixresult(e,retregs,pretregs));
4907: }
4908:
4909: #endif // !SPP
4910: