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